feat: add Citations and WatchlistChat components, integrate with API

- Implemented Citations component to display citation data.
- Created WatchlistDrawer and ChatSidebar components for managing watchlists and AI chat functionality.
- Integrated API calls for watchlist management and chat interactions.
- Updated index.tsx to include new components in the main application layout.
- Added API client in lib/api.ts for structured API interactions.
- Developed Alerts, Dashboard, Portfolio, Routines, Screener, and Report pages with relevant data fetching and UI components.
- Introduced styles in tokens.css for consistent theming across the application.
- Configured TypeScript and Vite for project setup and development.
This commit is contained in:
asepharyana
2026-09-15 12:36:48 +07:00
parent 0db2cf28b3
commit 8c184ccae1
111 changed files with 12349 additions and 62 deletions
+74
View File
@@ -0,0 +1,74 @@
// Package model holds shared domain types: citations, snapshots, agent
// results. Every number in user-visible output carries a Citation.
// API response shapes live in internal/sectors; agent inputs in internal/agents.
package model
import "time"
// Citation pins a value to its source endpoint + snapshot timestamp.
// Stale (>1 session old) citations are rendered marked, never hidden.
type Citation struct {
Endpoint string `json:"endpoint"`
SnapshotAt string `json:"snapshot_at"`
Ticker string `json:"ticker,omitempty"`
Stale bool `json:"stale,omitempty"`
}
// Value is a cited number or string shown to users.
type Value struct {
Label string `json:"label"`
Display string `json:"display"`
Citations []Citation `json:"citations"`
}
// Snapshot is one raw Sectors payload row.
type Snapshot struct {
ID int64
Ticker string
Date string
Source string
Payload string
FetchedAt time.Time
}
// AgentResult is the common output contract for A1..A7.
type AgentResult struct {
Agent string `json:"agent"`
Score float64 `json:"score"`
Summary string `json:"summary"`
Values []Value `json:"values"`
Flags []string `json:"flags"`
Citations []Citation `json:"citations"`
Extra map[string]any `json:"extra,omitempty"`
}
// Cite builds a Citation for one endpoint + snapshot date.
func Cite(endpoint, ticker, snapshotAt string) Citation {
return Citation{Endpoint: endpoint, SnapshotAt: snapshotAt, Ticker: ticker}
}
// StaleSession returns the date before which snapshots count as stale:
// anything older than the session containing ref (WIB trading day).
func StaleSession(ref time.Time) time.Time {
y, m, d := ref.Date()
return time.Date(y, m, d, 0, 0, 0, 0, ref.Location()).AddDate(0, 0, -1)
}
// MarkStale flags citations older than cutoff (one session back).
func MarkStale(citations []Citation, cutoff time.Time) []Citation {
out := make([]Citation, len(citations))
for i, c := range citations {
if t, err := time.Parse("2006-01-02", head10(c.SnapshotAt)); err == nil && t.Before(cutoff) {
c.Stale = true
}
out[i] = c
}
return out
}
func head10(s string) string {
if len(s) > 10 {
return s[:10]
}
return s
}