@burdenoff/microfe-brainyrich 2026.705.1 → 2026.706.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/brainyrich/BrainyRichRoot.js +13 -13
  2. package/dist/brainyrich/components/ActorName.js +38 -0
  3. package/dist/brainyrich/components/ActorName.js.map +1 -0
  4. package/dist/brainyrich/components/ConfirmDialog.js +25 -0
  5. package/dist/brainyrich/components/ConfirmDialog.js.map +1 -0
  6. package/dist/brainyrich/components/LoadMore.js +24 -0
  7. package/dist/brainyrich/components/LoadMore.js.map +1 -0
  8. package/dist/brainyrich/components/index.js +5 -0
  9. package/dist/brainyrich/components/notify.js +38 -0
  10. package/dist/brainyrich/components/notify.js.map +1 -0
  11. package/dist/brainyrich/components/pickers.js +232 -0
  12. package/dist/brainyrich/components/pickers.js.map +1 -0
  13. package/dist/brainyrich/components/reuse/CommentThread.js +208 -0
  14. package/dist/brainyrich/components/reuse/CommentThread.js.map +1 -0
  15. package/dist/brainyrich/components/reuse/DocumentsPanel.js +237 -0
  16. package/dist/brainyrich/components/reuse/DocumentsPanel.js.map +1 -0
  17. package/dist/brainyrich/components/reuse/TagField.js +206 -0
  18. package/dist/brainyrich/components/reuse/TagField.js.map +1 -0
  19. package/dist/brainyrich/components/reuse/transport.js +24 -0
  20. package/dist/brainyrich/components/reuse/transport.js.map +1 -0
  21. package/dist/brainyrich/hooks/useBrainyRichApi.js +644 -372
  22. package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
  23. package/dist/brainyrich/pages/AccountsPage.js +346 -293
  24. package/dist/brainyrich/pages/AccountsPage.js.map +1 -1
  25. package/dist/brainyrich/pages/AiAssistantPage.js +339 -320
  26. package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
  27. package/dist/brainyrich/pages/AnalyticsPage.js +178 -164
  28. package/dist/brainyrich/pages/AnalyticsPage.js.map +1 -1
  29. package/dist/brainyrich/pages/DashboardPage.js +195 -169
  30. package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
  31. package/dist/brainyrich/pages/FamilyPage.js +247 -198
  32. package/dist/brainyrich/pages/FamilyPage.js.map +1 -1
  33. package/dist/brainyrich/pages/GoalsPage.js +478 -442
  34. package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
  35. package/dist/brainyrich/pages/InvestmentsPage.js.map +1 -1
  36. package/dist/brainyrich/pages/PortfoliosPage.js +438 -396
  37. package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
  38. package/dist/brainyrich/pages/ReportsPage.js +246 -213
  39. package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
  40. package/dist/brainyrich/pages/RiskPage.js +321 -173
  41. package/dist/brainyrich/pages/RiskPage.js.map +1 -1
  42. package/dist/brainyrich/pages/TaxPage.js +258 -225
  43. package/dist/brainyrich/pages/TaxPage.js.map +1 -1
  44. package/dist/brainyrich/pages/_shared.js.map +1 -1
  45. package/dist/node_modules/sonner/dist/index.js +163 -0
  46. package/dist/node_modules/sonner/dist/index.js.map +1 -0
  47. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"file":"RiskPage.js","names":[],"sources":["../../../src/brainyrich/pages/RiskPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport {\n AlertTriangle,\n ArrowRight,\n Check,\n MoreHorizontal,\n Plus,\n Scale,\n ShieldAlert,\n ShieldCheck,\n X,\n} from 'lucide-react';\nimport {\n useRebalanceProposals,\n usePortfolios,\n useInsights,\n useCreateRebalanceProposal,\n useTransitionRebalanceProposal,\n useAcknowledgeInsight,\n useDismissInsight,\n useResolveInsight,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraPortfolio,\n BraRebalanceProposal,\n BraRebalanceStatus,\n BraInsight,\n BraInsightType,\n} from '../types/bra';\nimport {\n SectionShell,\n KpiGrid,\n EmptyState,\n LoadingState,\n ErrorState,\n formatPct,\n formatDate,\n statusBadgeVariant,\n} from './_shared';\n\n// ============================================================================\n// Domain rules (derived from the SDL enum, not fabricated data)\n// ============================================================================\n\n/** Valid forward/side transitions per current rebalance status. Terminal states map to []. */\nconst NEXT_STATUSES: Record<BraRebalanceStatus, BraRebalanceStatus[]> = {\n DRAFT: ['PROPOSED', 'CANCELLED'],\n PROPOSED: ['APPROVED', 'REJECTED', 'CANCELLED'],\n APPROVED: ['EXECUTED', 'CANCELLED'],\n REJECTED: [],\n EXECUTED: [],\n CANCELLED: [],\n};\n\n/** Insight types that belong on the risk/rebalancing surface. */\nconst RISK_INSIGHT_TYPES: BraInsightType[] = [\n 'DRIFT',\n 'CONCENTRATION_RISK',\n 'REBALANCE_DUE',\n 'CASH_DRAG',\n 'FEE_ANOMALY',\n];\nconst RISK_INSIGHT_TYPE_SET = new Set<BraInsightType>(RISK_INSIGHT_TYPES);\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/** Summarize the opaque `trades` JSON scalar without inventing data. */\nfunction summarizeTrades(trades: unknown): string {\n if (trades == null) return '—';\n if (Array.isArray(trades)) {\n return `${trades.length} trade${trades.length === 1 ? '' : 's'}`;\n }\n if (typeof trades === 'object') {\n const n = Object.keys(trades as Record<string, unknown>).length;\n return `${n} field${n === 1 ? '' : 's'}`;\n }\n return String(trades);\n}\n\n// ============================================================================\n// Create-proposal form\n// ============================================================================\n\ninterface ProposalFormState {\n portfolioId: string;\n driftPct: string;\n rationale: string;\n trades: string;\n}\n\nconst EMPTY_PROPOSAL_FORM: ProposalFormState = {\n portfolioId: '',\n driftPct: '',\n rationale: '',\n trades: '',\n};\n\nfunction parseNum(value: string): number | undefined {\n if (value.trim() === '') return undefined;\n const n = Number(value);\n return Number.isFinite(n) ? n : undefined;\n}\n\nexport function RiskPage() {\n const {\n data: proposals,\n isLoading: proposalsLoading,\n isError: proposalsError,\n refetch: refetchProposals,\n } = useRebalanceProposals();\n\n const { data: portfolios } = usePortfolios();\n\n const {\n data: insights,\n isLoading: insightsLoading,\n isError: insightsError,\n refetch: refetchInsights,\n } = useInsights();\n\n const createProposal = useCreateRebalanceProposal();\n const transitionProposal = useTransitionRebalanceProposal();\n const acknowledgeInsight = useAcknowledgeInsight();\n const dismissInsight = useDismissInsight();\n const resolveInsight = useResolveInsight();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [form, setForm] = useState<ProposalFormState>(EMPTY_PROPOSAL_FORM);\n const [tradesError, setTradesError] = useState<string | null>(null);\n\n // Portfolio lookup for names + drift thresholds (real backend data).\n const portfolioById = useMemo(() => {\n const map = new Map<string, BraPortfolio>();\n for (const p of portfolios) map.set(p.id, p);\n return map;\n }, [portfolios]);\n\n const riskInsights = useMemo(\n () => insights.filter((i) => RISK_INSIGHT_TYPE_SET.has(i.type)),\n [insights]\n );\n\n const activeProposals = proposals.filter(\n (p) => p.status === 'DRAFT' || p.status === 'PROPOSED' || p.status === 'APPROVED'\n );\n const openInsights = riskInsights.filter((i) => i.status === 'OPEN');\n const avgDrift =\n proposals.length > 0\n ? proposals.reduce((sum, p) => sum + (p.driftPct ?? 0), 0) / proposals.length\n : null;\n\n const canCreate = portfolios.length > 0;\n\n function openCreate() {\n setForm(EMPTY_PROPOSAL_FORM);\n setTradesError(null);\n setCreateOpen(true);\n }\n\n function submitCreate() {\n if (!form.portfolioId) return;\n let trades: unknown;\n if (form.trades.trim() !== '') {\n try {\n trades = JSON.parse(form.trades);\n } catch {\n setTradesError('Trades must be valid JSON.');\n return;\n }\n }\n const portfolio = portfolioById.get(form.portfolioId);\n createProposal.mutate(\n {\n portfolioId: form.portfolioId,\n householdId: portfolio?.householdId ?? null,\n driftPct: parseNum(form.driftPct),\n rationale: form.rationale.trim() || null,\n ...(trades !== undefined ? { trades } : {}),\n },\n { onSuccess: () => setCreateOpen(false) }\n );\n }\n\n /** Drift is a breach when it meets/exceeds the portfolio's configured threshold. */\n function driftBreached(p: BraRebalanceProposal): boolean {\n const threshold = portfolioById.get(p.portfolioId)?.driftThresholdPct;\n return threshold != null && Number.isFinite(threshold) && p.driftPct >= threshold;\n }\n\n return (\n <SectionShell\n title=\"Risk & Rebalancing\"\n description=\"Review drift-driven rebalance proposals and act on portfolio risk insights.\"\n badges={[\n `${activeProposals.length} active`,\n `${openInsights.length} open insight${openInsights.length === 1 ? '' : 's'}`,\n ]}\n actionLabel=\"New proposal\"\n onAction={openCreate}\n >\n <KpiGrid\n items={[\n { label: 'Total proposals', value: String(proposals.length) },\n { label: 'Active proposals', value: String(activeProposals.length) },\n {\n label: 'Average drift',\n value: avgDrift === null ? '—' : formatPct(avgDrift),\n },\n { label: 'Open risk insights', value: String(openInsights.length) },\n ]}\n />\n\n {/* Rebalance proposals */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Scale className=\"h-5 w-5\" aria-hidden=\"true\" />\n Rebalance proposals\n </CardTitle>\n <CardDescription>\n Drift against target allocation, with lifecycle actions per proposal.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {proposalsLoading ? (\n <LoadingState />\n ) : proposalsError ? (\n <ErrorState onRetry={() => refetchProposals()} />\n ) : proposals.length === 0 ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No rebalance proposals\"\n description={\n canCreate\n ? 'Create a proposal when a portfolio drifts from its target allocation.'\n : 'Create a portfolio first, then propose a rebalance when it drifts.'\n }\n action={\n canCreate ? (\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n New proposal\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Portfolio</TableHead>\n <TableHead className=\"text-right\">Drift</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Rationale</TableHead>\n <TableHead>Trades</TableHead>\n <TableHead>Created</TableHead>\n <TableHead className=\"w-12 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {proposals.map((p) => {\n const portfolio = portfolioById.get(p.portfolioId);\n const breached = driftBreached(p);\n const nextStatuses = NEXT_STATUSES[p.status];\n return (\n <TableRow key={p.id}>\n <TableCell>\n <p className=\"font-medium text-text-primary\">\n {portfolio?.name ?? 'Unknown portfolio'}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {portfolio?.baseCurrency ?? '—'}\n {portfolio?.driftThresholdPct != null\n ? ` · threshold ${formatPct(portfolio.driftThresholdPct)}`\n : ''}\n </p>\n </TableCell>\n <TableCell className=\"text-right\">\n <span\n className={`inline-flex items-center justify-end gap-1 font-semibold ${\n breached ? 'text-status-error-text' : 'text-text-primary'\n }`}\n >\n {breached ? (\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n ) : null}\n {formatPct(p.driftPct)}\n </span>\n {breached ? (\n <p className=\"text-xs text-status-error-text\">Over threshold</p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant={statusBadgeVariant(p.status)}>{humanize(p.status)}</Badge>\n </TableCell>\n <TableCell className=\"max-w-xs\">\n <p className=\"truncate text-sm text-text-secondary\">\n {p.rationale ?? '—'}\n </p>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {summarizeTrades(p.trades)}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {formatDate(p.createdAt)}\n </TableCell>\n <TableCell className=\"text-right\">\n {nextStatuses.length === 0 ? (\n <span className=\"text-xs text-text-muted\">—</span>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Lifecycle actions for ${portfolio?.name ?? 'proposal'}`}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuLabel>Advance to</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {nextStatuses.map((status) => {\n const destructive =\n status === 'REJECTED' || status === 'CANCELLED';\n return (\n <DropdownMenuItem\n key={status}\n disabled={transitionProposal.isPending}\n className={destructive ? 'text-status-error-text' : undefined}\n onClick={() =>\n transitionProposal.mutate({ id: p.id, status })\n }\n >\n {destructive ? (\n <X className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n )}\n {humanize(status)}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Risk insights */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-5 w-5\" aria-hidden=\"true\" />\n Risk insights\n </CardTitle>\n <CardDescription>\n Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {insightsLoading ? (\n <LoadingState />\n ) : insightsError ? (\n <ErrorState onRetry={() => refetchInsights()} />\n ) : riskInsights.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No risk insights\"\n description=\"No drift, concentration, cash-drag or fee-anomaly signals are open right now.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {riskInsights.map((insight) => (\n <InsightRow\n key={insight.id}\n insight={insight}\n onAcknowledge={() => acknowledgeInsight.mutate(insight.id)}\n onResolve={() => resolveInsight.mutate(insight.id)}\n onDismiss={() => dismissInsight.mutate(insight.id)}\n actionPending={\n acknowledgeInsight.isPending ||\n resolveInsight.isPending ||\n dismissInsight.isPending\n }\n />\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Create proposal dialog */}\n <Dialog open={createOpen} onOpenChange={setCreateOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>New rebalance proposal</DialogTitle>\n <DialogDescription>\n Propose a rebalance for a portfolio that has drifted from its target allocation.\n </DialogDescription>\n </DialogHeader>\n {!canCreate ? (\n <EmptyState\n title=\"No portfolios available\"\n description=\"Create a portfolio before proposing a rebalance.\"\n />\n ) : (\n <div className=\"grid gap-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-portfolio\">Portfolio</Label>\n <Select\n value={form.portfolioId}\n onValueChange={(v) => setForm((f) => ({ ...f, portfolioId: v }))}\n >\n <SelectTrigger id=\"prop-portfolio\">\n <SelectValue placeholder=\"Select a portfolio\" />\n </SelectTrigger>\n <SelectContent>\n {portfolios.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-drift\">Drift %</Label>\n <Input\n id=\"prop-drift\"\n type=\"number\"\n value={form.driftPct}\n onChange={(e) => setForm((f) => ({ ...f, driftPct: e.target.value }))}\n placeholder=\"e.g. 6.5\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-rationale\">Rationale</Label>\n <Textarea\n id=\"prop-rationale\"\n value={form.rationale}\n onChange={(e) => setForm((f) => ({ ...f, rationale: e.target.value }))}\n placeholder=\"Why is this rebalance needed?\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-trades\">Trades (JSON, optional)</Label>\n <Textarea\n id=\"prop-trades\"\n value={form.trades}\n onChange={(e) => {\n setTradesError(null);\n setForm((f) => ({ ...f, trades: e.target.value }));\n }}\n placeholder='e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]'\n />\n {tradesError ? (\n <p className=\"text-xs text-status-error-text\">{tradesError}</p>\n ) : null}\n </div>\n </div>\n )}\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button\n onClick={submitCreate}\n disabled={!form.portfolioId || createProposal.isPending}\n >\n {createProposal.isPending ? 'Creating…' : 'Create proposal'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </SectionShell>\n );\n}\n\n// ============================================================================\n// Insight row\n// ============================================================================\n\nfunction InsightRow({\n insight,\n onAcknowledge,\n onResolve,\n onDismiss,\n actionPending,\n}: {\n insight: BraInsight;\n onAcknowledge: () => void;\n onResolve: () => void;\n onDismiss: () => void;\n actionPending: boolean;\n}) {\n const terminal = insight.status === 'RESOLVED' || insight.status === 'DISMISSED';\n return (\n <div className=\"flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{insight.title}</p>\n <Badge variant={statusBadgeVariant(insight.severity)}>{humanize(insight.severity)}</Badge>\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>{humanize(insight.status)}</Badge>\n </div>\n {insight.detail ? (\n <p className=\"text-sm text-text-secondary\">{insight.detail}</p>\n ) : null}\n <p className=\"text-xs text-text-muted\">Detected {formatDate(insight.createdAt)}</p>\n </div>\n {terminal ? (\n <span className=\"mt-1 text-xs text-text-muted\">Closed</span>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${insight.title}`}\n disabled={actionPending}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {insight.status === 'OPEN' ? (\n <DropdownMenuItem onClick={onAcknowledge}>\n <Check className=\"size-4\" aria-hidden=\"true\" />\n Acknowledge\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem onClick={onResolve}>\n <ShieldCheck className=\"size-4\" aria-hidden=\"true\" />\n Resolve\n </DropdownMenuItem>\n <DropdownMenuItem className=\"text-status-error-text\" onClick={onDismiss}>\n <X className=\"size-4\" aria-hidden=\"true\" />\n Dismiss\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RiskPage.js","names":[],"sources":["../../../src/brainyrich/pages/RiskPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport {\n AlertTriangle,\n ArrowRight,\n Check,\n Eye,\n MoreHorizontal,\n Plus,\n Scale,\n ShieldAlert,\n ShieldCheck,\n X,\n} from 'lucide-react';\nimport {\n useRebalanceProposals,\n usePortfolios,\n usePagedInsights,\n useCreateRebalanceProposal,\n useTransitionRebalanceProposal,\n useAcknowledgeInsight,\n useDismissInsight,\n useResolveInsight,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraPortfolio,\n BraRebalanceProposal,\n BraRebalanceStatus,\n BraInsight,\n BraInsightType,\n} from '../types/bra';\nimport {\n SectionShell,\n KpiGrid,\n EmptyState,\n LoadingState,\n ErrorState,\n formatPct,\n formatDate,\n statusBadgeVariant,\n} from './_shared';\nimport { ConfirmDialog, ActorName, LoadMore } from '../components';\nimport { CommentThread } from '../components/reuse/CommentThread';\n\n// ============================================================================\n// Domain rules (derived from the SDL enum, not fabricated data)\n// ============================================================================\n\n/** Valid forward/side transitions per current rebalance status. Terminal states map to []. */\nconst NEXT_STATUSES: Record<BraRebalanceStatus, BraRebalanceStatus[]> = {\n DRAFT: ['PROPOSED', 'CANCELLED'],\n PROPOSED: ['APPROVED', 'REJECTED', 'CANCELLED'],\n APPROVED: ['EXECUTED', 'CANCELLED'],\n REJECTED: [],\n EXECUTED: [],\n CANCELLED: [],\n};\n\n/** Insight types that belong on the risk/rebalancing surface. */\nconst RISK_INSIGHT_TYPES: BraInsightType[] = [\n 'DRIFT',\n 'CONCENTRATION_RISK',\n 'REBALANCE_DUE',\n 'CASH_DRAG',\n 'FEE_ANOMALY',\n];\nconst RISK_INSIGHT_TYPE_SET = new Set<BraInsightType>(RISK_INSIGHT_TYPES);\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/** Summarize the opaque `trades` JSON scalar without inventing data. */\nfunction summarizeTrades(trades: unknown): string {\n if (trades == null) return '—';\n if (Array.isArray(trades)) {\n return `${trades.length} trade${trades.length === 1 ? '' : 's'}`;\n }\n if (typeof trades === 'object') {\n const n = Object.keys(trades as Record<string, unknown>).length;\n return `${n} field${n === 1 ? '' : 's'}`;\n }\n return String(trades);\n}\n\n// ============================================================================\n// Create-proposal form\n// ============================================================================\n\ninterface ProposalFormState {\n portfolioId: string;\n driftPct: string;\n rationale: string;\n trades: string;\n}\n\nconst EMPTY_PROPOSAL_FORM: ProposalFormState = {\n portfolioId: '',\n driftPct: '',\n rationale: '',\n trades: '',\n};\n\nfunction parseNum(value: string): number | undefined {\n if (value.trim() === '') return undefined;\n const n = Number(value);\n return Number.isFinite(n) ? n : undefined;\n}\n\nexport function RiskPage() {\n const {\n data: proposals,\n isLoading: proposalsLoading,\n isError: proposalsError,\n refetch: refetchProposals,\n } = useRebalanceProposals();\n\n const { data: portfolios } = usePortfolios();\n\n const {\n items: insights,\n hasMore: insightsHasMore,\n loadMore: loadMoreInsights,\n isLoading: insightsLoading,\n isFetchingNextPage: insightsFetchingMore,\n isError: insightsError,\n refetch: refetchInsights,\n } = usePagedInsights();\n\n const createProposal = useCreateRebalanceProposal();\n const transitionProposal = useTransitionRebalanceProposal();\n const acknowledgeInsight = useAcknowledgeInsight();\n const dismissInsight = useDismissInsight();\n const resolveInsight = useResolveInsight();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [form, setForm] = useState<ProposalFormState>(EMPTY_PROPOSAL_FORM);\n const [tradesError, setTradesError] = useState<string | null>(null);\n const [detailProposal, setDetailProposal] = useState<BraRebalanceProposal | null>(null);\n const [confirmTransition, setConfirmTransition] = useState<{\n proposal: BraRebalanceProposal;\n status: BraRebalanceStatus;\n } | null>(null);\n\n // Portfolio lookup for names + drift thresholds (real backend data).\n const portfolioById = useMemo(() => {\n const map = new Map<string, BraPortfolio>();\n for (const p of portfolios) map.set(p.id, p);\n return map;\n }, [portfolios]);\n\n const riskInsights = useMemo(\n () => insights.filter((i) => RISK_INSIGHT_TYPE_SET.has(i.type)),\n [insights]\n );\n\n const activeProposals = proposals.filter(\n (p) => p.status === 'DRAFT' || p.status === 'PROPOSED' || p.status === 'APPROVED'\n );\n const openInsights = riskInsights.filter((i) => i.status === 'OPEN');\n const avgDrift =\n proposals.length > 0\n ? proposals.reduce((sum, p) => sum + (p.driftPct ?? 0), 0) / proposals.length\n : null;\n\n const canCreate = portfolios.length > 0;\n\n function openCreate() {\n setForm(EMPTY_PROPOSAL_FORM);\n setTradesError(null);\n setCreateOpen(true);\n }\n\n function submitCreate() {\n if (!form.portfolioId) return;\n let trades: unknown;\n if (form.trades.trim() !== '') {\n try {\n trades = JSON.parse(form.trades);\n } catch {\n setTradesError('Trades must be valid JSON.');\n return;\n }\n }\n const portfolio = portfolioById.get(form.portfolioId);\n createProposal.mutate(\n {\n portfolioId: form.portfolioId,\n householdId: portfolio?.householdId ?? null,\n driftPct: parseNum(form.driftPct),\n rationale: form.rationale.trim() || null,\n ...(trades !== undefined ? { trades } : {}),\n },\n { onSuccess: () => setCreateOpen(false) }\n );\n }\n\n /** Destructive transitions (reject/cancel) confirm first; forward transitions fire directly. */\n function requestTransition(proposal: BraRebalanceProposal, status: BraRebalanceStatus) {\n if (status === 'REJECTED' || status === 'CANCELLED') {\n setConfirmTransition({ proposal, status });\n return;\n }\n transitionProposal.mutate({ id: proposal.id, status });\n }\n\n /** Drift is a breach when it meets/exceeds the portfolio's configured threshold. */\n function driftBreached(p: BraRebalanceProposal): boolean {\n const threshold = portfolioById.get(p.portfolioId)?.driftThresholdPct;\n return threshold != null && Number.isFinite(threshold) && p.driftPct >= threshold;\n }\n\n return (\n <SectionShell\n title=\"Risk & Rebalancing\"\n description=\"Review drift-driven rebalance proposals and act on portfolio risk insights.\"\n badges={[\n `${activeProposals.length} active`,\n `${openInsights.length} open insight${openInsights.length === 1 ? '' : 's'}`,\n ]}\n actionLabel=\"New proposal\"\n onAction={openCreate}\n >\n <KpiGrid\n items={[\n { label: 'Total proposals', value: String(proposals.length) },\n { label: 'Active proposals', value: String(activeProposals.length) },\n {\n label: 'Average drift',\n value: avgDrift === null ? '—' : formatPct(avgDrift),\n },\n { label: 'Open risk insights', value: String(openInsights.length) },\n ]}\n />\n\n {/* Rebalance proposals */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Scale className=\"h-5 w-5\" aria-hidden=\"true\" />\n Rebalance proposals\n </CardTitle>\n <CardDescription>\n Drift against target allocation, with lifecycle actions per proposal.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {proposalsLoading ? (\n <LoadingState />\n ) : proposalsError ? (\n <ErrorState onRetry={() => refetchProposals()} />\n ) : proposals.length === 0 ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No rebalance proposals\"\n description={\n canCreate\n ? 'Create a proposal when a portfolio drifts from its target allocation.'\n : 'Create a portfolio first, then propose a rebalance when it drifts.'\n }\n action={\n canCreate ? (\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n New proposal\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Portfolio</TableHead>\n <TableHead className=\"text-right\">Drift</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Rationale</TableHead>\n <TableHead>Trades</TableHead>\n <TableHead>Created</TableHead>\n <TableHead className=\"w-12 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {proposals.map((p) => {\n const portfolio = portfolioById.get(p.portfolioId);\n const breached = driftBreached(p);\n const nextStatuses = NEXT_STATUSES[p.status];\n return (\n <TableRow key={p.id}>\n <TableCell>\n <p className=\"font-medium text-text-primary\">\n {portfolio?.name ?? 'Unknown portfolio'}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {portfolio?.baseCurrency ?? '—'}\n {portfolio?.driftThresholdPct != null\n ? ` · threshold ${formatPct(portfolio.driftThresholdPct)}`\n : ''}\n </p>\n </TableCell>\n <TableCell className=\"text-right\">\n <span\n className={`inline-flex items-center justify-end gap-1 font-semibold ${\n breached ? 'text-status-error-text' : 'text-text-primary'\n }`}\n >\n {breached ? (\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n ) : null}\n {formatPct(p.driftPct)}\n </span>\n {breached ? (\n <p className=\"text-xs text-status-error-text\">Over threshold</p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant={statusBadgeVariant(p.status)}>{humanize(p.status)}</Badge>\n </TableCell>\n <TableCell className=\"max-w-xs\">\n <p className=\"truncate text-sm text-text-secondary\">\n {p.rationale ?? '—'}\n </p>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {summarizeTrades(p.trades)}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {formatDate(p.createdAt)}\n </TableCell>\n <TableCell className=\"text-right\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${portfolio?.name ?? 'proposal'}`}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => setDetailProposal(p)}>\n <Eye className=\"size-4\" aria-hidden=\"true\" />\n View details\n </DropdownMenuItem>\n {nextStatuses.length > 0 ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Advance to</DropdownMenuLabel>\n {nextStatuses.map((status) => {\n const destructive =\n status === 'REJECTED' || status === 'CANCELLED';\n return (\n <DropdownMenuItem\n key={status}\n disabled={transitionProposal.isPending}\n className={\n destructive ? 'text-status-error-text' : undefined\n }\n onClick={() => requestTransition(p, status)}\n >\n {destructive ? (\n <X className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n )}\n {humanize(status)}\n </DropdownMenuItem>\n );\n })}\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Risk insights */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-5 w-5\" aria-hidden=\"true\" />\n Risk insights\n </CardTitle>\n <CardDescription>\n Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {insightsLoading ? (\n <LoadingState />\n ) : insightsError ? (\n <ErrorState onRetry={() => refetchInsights()} />\n ) : riskInsights.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No risk insights\"\n description=\"No drift, concentration, cash-drag or fee-anomaly signals are open right now.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {riskInsights.map((insight) => (\n <InsightRow\n key={insight.id}\n insight={insight}\n onAcknowledge={() => acknowledgeInsight.mutate(insight.id)}\n onResolve={() => resolveInsight.mutate(insight.id)}\n onDismiss={() => dismissInsight.mutate(insight.id)}\n actionPending={\n acknowledgeInsight.isPending ||\n resolveInsight.isPending ||\n dismissInsight.isPending\n }\n />\n ))}\n <LoadMore\n hasMore={insightsHasMore}\n onClick={loadMoreInsights}\n loading={insightsFetchingMore}\n label=\"Load more insights\"\n />\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Create proposal dialog */}\n <Dialog open={createOpen} onOpenChange={setCreateOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>New rebalance proposal</DialogTitle>\n <DialogDescription>\n Propose a rebalance for a portfolio that has drifted from its target allocation.\n </DialogDescription>\n </DialogHeader>\n {!canCreate ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Create a portfolio first\"\n description=\"A rebalance proposal targets a portfolio. Add a portfolio on the Portfolios page, then return here to propose a rebalance.\"\n />\n ) : (\n <div className=\"grid gap-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-portfolio\">Portfolio</Label>\n <Select\n value={form.portfolioId}\n onValueChange={(v) => setForm((f) => ({ ...f, portfolioId: v }))}\n >\n <SelectTrigger id=\"prop-portfolio\">\n <SelectValue placeholder=\"Select a portfolio\" />\n </SelectTrigger>\n <SelectContent>\n {portfolios.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-drift\">Drift %</Label>\n <Input\n id=\"prop-drift\"\n type=\"number\"\n value={form.driftPct}\n onChange={(e) => setForm((f) => ({ ...f, driftPct: e.target.value }))}\n placeholder=\"e.g. 6.5\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-rationale\">Rationale</Label>\n <Textarea\n id=\"prop-rationale\"\n value={form.rationale}\n onChange={(e) => setForm((f) => ({ ...f, rationale: e.target.value }))}\n placeholder=\"Why is this rebalance needed?\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-trades\">Trades (JSON, optional)</Label>\n <Textarea\n id=\"prop-trades\"\n value={form.trades}\n onChange={(e) => {\n setTradesError(null);\n setForm((f) => ({ ...f, trades: e.target.value }));\n }}\n placeholder='e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]'\n />\n {tradesError ? (\n <p className=\"text-xs text-status-error-text\">{tradesError}</p>\n ) : null}\n </div>\n </div>\n )}\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button onClick={submitCreate} disabled={!form.portfolioId || createProposal.isPending}>\n {createProposal.isPending ? 'Creating…' : 'Create proposal'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Proposal detail — summary + discussion thread */}\n <ProposalDetailDialog\n proposal={detailProposal}\n portfolio={\n detailProposal ? (portfolioById.get(detailProposal.portfolioId) ?? null) : null\n }\n onOpenChange={(open) => {\n if (!open) setDetailProposal(null);\n }}\n />\n\n {/* Confirm destructive lifecycle transition (reject / cancel) */}\n <ConfirmDialog\n open={confirmTransition !== null}\n onOpenChange={(open) => {\n if (!open) setConfirmTransition(null);\n }}\n title={\n confirmTransition?.status === 'REJECTED'\n ? 'Reject this proposal?'\n : 'Cancel this proposal?'\n }\n description={\n confirmTransition\n ? `This moves the rebalance proposal for ${\n portfolioById.get(confirmTransition.proposal.portfolioId)?.name ??\n 'this portfolio'\n } to ${humanize(confirmTransition.status)}. This cannot be undone.`\n : undefined\n }\n confirmLabel={confirmTransition?.status === 'REJECTED' ? 'Reject' : 'Cancel proposal'}\n cancelLabel=\"Keep\"\n destructive\n pending={transitionProposal.isPending}\n onConfirm={() => {\n if (!confirmTransition) return;\n transitionProposal.mutate(\n { id: confirmTransition.proposal.id, status: confirmTransition.status },\n { onSuccess: () => setConfirmTransition(null) }\n );\n }}\n />\n </SectionShell>\n );\n}\n\n// ============================================================================\n// Proposal detail dialog — rationale summary, actors, and discussion thread\n// ============================================================================\n\nfunction ProposalDetailDialog({\n proposal,\n portfolio,\n onOpenChange,\n}: {\n proposal: BraRebalanceProposal | null;\n portfolio: BraPortfolio | null;\n onOpenChange: (open: boolean) => void;\n}) {\n return (\n <Dialog open={proposal !== null} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[85vh] overflow-y-auto\">\n {proposal ? (\n <>\n <DialogHeader>\n <DialogTitle className=\"flex flex-wrap items-center gap-2\">\n {portfolio?.name ?? 'Rebalance proposal'}\n <Badge variant={statusBadgeVariant(proposal.status)}>\n {humanize(proposal.status)}\n </Badge>\n </DialogTitle>\n <DialogDescription>\n Drift {formatPct(proposal.driftPct)}\n {portfolio?.driftThresholdPct != null\n ? ` · threshold ${formatPct(portfolio.driftThresholdPct)}`\n : ''}\n {' · created '}\n {formatDate(proposal.createdAt)}\n </DialogDescription>\n </DialogHeader>\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm\">\n <div className=\"space-y-1\">\n <dt className=\"text-xs font-medium text-text-muted\">Proposed by</dt>\n <dd className=\"text-text-primary\">\n {proposal.proposedById ? (\n <ActorName id={proposal.proposedById} />\n ) : (\n <span className=\"text-text-muted\">—</span>\n )}\n </dd>\n </div>\n <div className=\"space-y-1\">\n <dt className=\"text-xs font-medium text-text-muted\">Approved by</dt>\n <dd className=\"text-text-primary\">\n {proposal.approvedById ? (\n <ActorName id={proposal.approvedById} />\n ) : (\n <span className=\"text-text-muted\">—</span>\n )}\n </dd>\n </div>\n <div className=\"space-y-1\">\n <dt className=\"text-xs font-medium text-text-muted\">Trades</dt>\n <dd className=\"text-text-primary\">{summarizeTrades(proposal.trades)}</dd>\n </div>\n <div className=\"space-y-1\">\n <dt className=\"text-xs font-medium text-text-muted\">Executed</dt>\n <dd className=\"text-text-primary\">\n {proposal.executedAt ? (\n formatDate(proposal.executedAt)\n ) : (\n <span className=\"text-text-muted\">—</span>\n )}\n </dd>\n </div>\n </dl>\n\n <div className=\"space-y-1\">\n <p className=\"text-xs font-medium text-text-muted\">Rationale (summary)</p>\n <p className=\"text-sm text-text-secondary\">{proposal.rationale ?? '—'}</p>\n </div>\n\n <div className=\"border-t border-border-subtle pt-4\">\n <CommentThread\n entityType=\"brainyrich-rebalance\"\n entityId={proposal.id}\n heading=\"Discussion\"\n />\n </div>\n </>\n ) : null}\n </DialogContent>\n </Dialog>\n );\n}\n\n// ============================================================================\n// Insight row\n// ============================================================================\n\nfunction InsightRow({\n insight,\n onAcknowledge,\n onResolve,\n onDismiss,\n actionPending,\n}: {\n insight: BraInsight;\n onAcknowledge: () => void;\n onResolve: () => void;\n onDismiss: () => void;\n actionPending: boolean;\n}) {\n const terminal = insight.status === 'RESOLVED' || insight.status === 'DISMISSED';\n return (\n <div className=\"flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{insight.title}</p>\n <Badge variant={statusBadgeVariant(insight.severity)}>{humanize(insight.severity)}</Badge>\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>{humanize(insight.status)}</Badge>\n </div>\n {insight.detail ? <p className=\"text-sm text-text-secondary\">{insight.detail}</p> : null}\n <p className=\"text-xs text-text-muted\">Detected {formatDate(insight.createdAt)}</p>\n </div>\n {terminal ? (\n <span className=\"mt-1 text-xs text-text-muted\">Closed</span>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${insight.title}`}\n disabled={actionPending}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {insight.status === 'OPEN' ? (\n <DropdownMenuItem onClick={onAcknowledge}>\n <Check className=\"size-4\" aria-hidden=\"true\" />\n Acknowledge\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem onClick={onResolve}>\n <ShieldCheck className=\"size-4\" aria-hidden=\"true\" />\n Resolve\n </DropdownMenuItem>\n <DropdownMenuItem className=\"text-status-error-text\" onClick={onDismiss}>\n <X className=\"size-4\" aria-hidden=\"true\" />\n Dismiss\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n}\n"],"mappings":"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"}