@burdenoff/microfe-brainyrich 2026.828.1 → 2026.830.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 (39) hide show
  1. package/dist/brainyrich/BrainyRichRoot.d.ts.map +1 -1
  2. package/dist/brainyrich/BrainyRichRoot.js +59 -59
  3. package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
  4. package/dist/brainyrich/components/viz.d.ts.map +1 -1
  5. package/dist/brainyrich/components/viz.js +149 -148
  6. package/dist/brainyrich/components/viz.js.map +1 -1
  7. package/dist/brainyrich/hooks/useTr.d.ts +17 -0
  8. package/dist/brainyrich/hooks/useTr.d.ts.map +1 -0
  9. package/dist/brainyrich/hooks/useTr.js +14 -0
  10. package/dist/brainyrich/hooks/useTr.js.map +1 -0
  11. package/dist/brainyrich/pages/AiAssistantPage.js +192 -192
  12. package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
  13. package/dist/brainyrich/pages/AnalyticsPage.d.ts.map +1 -1
  14. package/dist/brainyrich/pages/AnalyticsPage.js +253 -252
  15. package/dist/brainyrich/pages/AnalyticsPage.js.map +1 -1
  16. package/dist/brainyrich/pages/DashboardPage.js +115 -115
  17. package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
  18. package/dist/brainyrich/pages/FamilyPage.js +59 -59
  19. package/dist/brainyrich/pages/FamilyPage.js.map +1 -1
  20. package/dist/brainyrich/pages/GoalsPage.js +285 -285
  21. package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
  22. package/dist/brainyrich/pages/InvestmentsPage.js +18 -18
  23. package/dist/brainyrich/pages/InvestmentsPage.js.map +1 -1
  24. package/dist/brainyrich/pages/PortfoliosPage.d.ts.map +1 -1
  25. package/dist/brainyrich/pages/PortfoliosPage.js +477 -471
  26. package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
  27. package/dist/brainyrich/pages/ReportsPage.js +52 -52
  28. package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
  29. package/dist/brainyrich/pages/RiskPage.d.ts.map +1 -1
  30. package/dist/brainyrich/pages/RiskPage.js +272 -271
  31. package/dist/brainyrich/pages/RiskPage.js.map +1 -1
  32. package/dist/brainyrich/pages/TaxPage.d.ts.map +1 -1
  33. package/dist/brainyrich/pages/TaxPage.js +198 -197
  34. package/dist/brainyrich/pages/TaxPage.js.map +1 -1
  35. package/dist/brainyrich/pages/_shared.d.ts.map +1 -1
  36. package/dist/brainyrich/pages/_shared.js +84 -82
  37. package/dist/brainyrich/pages/_shared.js.map +1 -1
  38. package/dist/brainyrich/types/bra.d.ts.map +1 -1
  39. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/brainyrich/pages/DashboardPage.tsx"],"sourcesContent":["import { useMemo, useState, type FormEvent, type ReactNode } from 'react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n Button,\n Badge,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Target,\n Bell,\n Briefcase,\n Wallet,\n PlusCircle,\n MoreHorizontal,\n Check,\n X,\n CircleCheck,\n TrendingUp,\n Coins,\n Landmark,\n TriangleAlert,\n Info,\n ShieldAlert,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n useNetWorthSummary,\n usePortfolios,\n useGoals,\n useInsights,\n useCreateAccount,\n useAcknowledgeInsight,\n useDismissInsight,\n useResolveInsight,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraAccountType,\n BraAssetClass,\n BraCreateAccountInput,\n BraInsight,\n BraInsightSeverity,\n} from '../types/bra';\nimport {\n HouseholdPicker,\n ConfirmDialog,\n DonutChart,\n StatTile,\n GlassCard,\n FadeIn,\n type VizTone,\n type DonutDatum,\n} from '../components';\nimport {\n SectionShell,\n EmptyState,\n LoadingState,\n ErrorState,\n formatMoney,\n formatCompact,\n formatDate,\n statusBadgeVariant,\n} from './_shared';\nimport { hapticSuccess, showToast } from '../utils/nativeControls';\nimport { useTrackBrainyRichPageView } from '../hooks/useBrainyRichAnalytics';\n\nconst ACCOUNT_TYPES: BraAccountType[] = [\n 'BANK',\n 'BROKERAGE',\n 'RETIREMENT',\n 'CASH',\n 'CRYPTO',\n 'REAL_ESTATE',\n 'ALTERNATIVE',\n 'LIABILITY',\n];\n\n/** Distinct, semantic tone per asset class so the donut stays legible + on-brand. */\nconst ASSET_TONE: Record<BraAssetClass, VizTone> = {\n EQUITY: 'brand',\n FIXED_INCOME: 'blue',\n CASH: 'teal',\n REAL_ESTATE: 'indigo',\n COMMODITY: 'warning',\n CRYPTO: 'purple',\n ALTERNATIVE: 'info',\n};\n\n/** Title-case an enum member: FIXED_INCOME → \"Fixed income\". */\nfunction prettyLabel(value: string): string {\n const spaced = value.replace(/_/g, ' ').toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nexport function DashboardPage() {\n const { t } = useI18n();\n const translate = (key: string, fallback: string, params?: Record<string, string | number>) =>\n tWithFallback(t, key, fallback, params);\n\n useTrackBrainyRichPageView('brainyrich.dashboard.viewed');\n\n const summaryQuery = useNetWorthSummary();\n const portfoliosQuery = usePortfolios();\n const goalsQuery = useGoals();\n const insightsQuery = useInsights({ status: 'OPEN' });\n\n const summary = summaryQuery.data;\n const currency = summary?.currency ?? 'USD';\n\n const kpis: HeroStat[] = summary\n ? [\n {\n label: translate('brainyrich.dashboard.metrics.netWorth', 'Net Worth'),\n value: formatCompact(summary.totalNetWorth, currency),\n icon: <Wallet className=\"size-4\" aria-hidden=\"true\" />,\n glow: true,\n },\n {\n label: translate('brainyrich.dashboard.metrics.investedAssets', 'Invested Assets'),\n value: formatCompact(summary.totalMarketValue, currency),\n icon: <TrendingUp className=\"size-4\" aria-hidden=\"true\" />,\n },\n {\n label: translate('brainyrich.dashboard.metrics.liquidity', 'Cash & Liquidity'),\n value: formatCompact(summary.totalCash, currency),\n icon: <Coins className=\"size-4\" aria-hidden=\"true\" />,\n },\n {\n label: translate('brainyrich.dashboard.metrics.accounts', 'Linked Accounts'),\n value: String(summary.accountCount),\n icon: <Landmark className=\"size-4\" aria-hidden=\"true\" />,\n },\n ]\n : [];\n\n const donutData: DonutDatum[] = useMemo(() => {\n if (!summary) return [];\n return summary.byAssetClass\n .filter((row) => Number.isFinite(row.marketValue) && row.marketValue > 0)\n .slice()\n .sort((a, b) => b.marketValue - a.marketValue)\n .map((row) => ({\n label: prettyLabel(row.assetClass),\n value: row.marketValue,\n tone: ASSET_TONE[row.assetClass],\n }));\n }, [summary]);\n\n const topPortfolios = portfoliosQuery.data.slice(0, 5);\n const topGoals = goalsQuery.data.slice(0, 5);\n const openInsights = insightsQuery.data.slice(0, 6);\n\n return (\n <div data-tour=\"brainyrich-page-dashboard\" className=\"contents\">\n <SectionShell\n title={translate('brainyrich.dashboard.title', 'Wealth Dashboard')}\n description={translate(\n 'brainyrich.dashboard.description',\n 'Your consolidated financial overview at a glance'\n )}\n actions={<NewAccountDialog translate={translate} />}\n >\n {/* Hero KPI row — net-worth overview */}\n {summaryQuery.isLoading ? (\n <LoadingState rows={1} />\n ) : summaryQuery.isError ? (\n <ErrorState\n title={translate('brainyrich.dashboard.netWorthError', 'Could not load net worth')}\n onRetry={() => summaryQuery.refetch()}\n />\n ) : summary ? (\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n {kpis.map((kpi, i) => (\n <FadeIn key={kpi.label} index={i}>\n <StatTile\n label={kpi.label}\n value={kpi.value}\n icon={kpi.icon}\n glow={kpi.glow}\n className=\"h-full\"\n />\n </FadeIn>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Wallet className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noSummary', 'No financial data yet')}\n description={translate(\n 'brainyrich.dashboard.noSummaryDesc',\n 'Link your first account to see your net worth here.'\n )}\n />\n )}\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Net worth by asset class — donut hero */}\n <FadeIn index={0} className=\"lg:col-span-2\">\n <GlassCard className=\"h-full\">\n <div className=\"mb-4 space-y-1\">\n <h2 className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <Briefcase className=\"size-5\" aria-hidden=\"true\" />\n {translate(\n 'brainyrich.dashboard.sections.assetAllocation',\n 'Net worth by asset class'\n )}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.dashboard.sections.assetAllocationDescription',\n 'Market value distributed across asset classes'\n )}\n </p>\n </div>\n {summaryQuery.isLoading ? (\n <LoadingState rows={3} />\n ) : summaryQuery.isError ? (\n <ErrorState onRetry={() => summaryQuery.refetch()} />\n ) : donutData.length > 0 ? (\n <DonutChart\n data={donutData}\n height={260}\n centerValue={formatCompact(summary?.totalMarketValue ?? 0, currency)}\n centerLabel={translate('brainyrich.dashboard.metrics.investedAssets', 'Invested')}\n valueFormatter={(v) => formatMoney(v, currency)}\n />\n ) : (\n <EmptyState\n icon={<Briefcase className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noAllocation', 'No holdings to allocate')}\n description={translate(\n 'brainyrich.dashboard.noAllocationDesc',\n 'Add holdings to your accounts to see how your wealth is allocated.'\n )}\n />\n )}\n </GlassCard>\n </FadeIn>\n\n {/* Right rail — needs attention + goals */}\n <div className=\"space-y-6\">\n {/* Needs attention — open insights */}\n <FadeIn index={1}>\n <Card className=\"motion-safe:transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]\">\n <CardHeader className=\"pb-3\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Bell className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.sections.needsAttention', 'Needs attention')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2.5\">\n {insightsQuery.isLoading ? (\n <LoadingState rows={2} />\n ) : insightsQuery.isError ? (\n <ErrorState onRetry={() => insightsQuery.refetch()} />\n ) : openInsights.length > 0 ? (\n openInsights.map((insight) => (\n <InsightRow key={insight.id} insight={insight} translate={translate} />\n ))\n ) : (\n <EmptyState\n icon={<CircleCheck className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noInsights', 'All clear')}\n description={translate(\n 'brainyrich.dashboard.noInsightsDesc',\n 'There are no open insights that need your attention.'\n )}\n />\n )}\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* Goals on track */}\n <FadeIn index={2}>\n <Card className=\"motion-safe:transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]\">\n <CardHeader className=\"pb-3\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Target className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.sections.goals', 'Goals on track')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2.5\">\n {goalsQuery.isLoading ? (\n <LoadingState rows={3} />\n ) : goalsQuery.isError ? (\n <ErrorState onRetry={() => goalsQuery.refetch()} />\n ) : topGoals.length > 0 ? (\n topGoals.map((goal) => (\n <div\n key={goal.id}\n className=\"flex items-start justify-between gap-2 rounded-lg border border-border-subtle p-3 motion-safe:transition-colors hover:border-[var(--color-action-primary-border)]/50 hover:bg-bg-elevated\"\n >\n <div className=\"min-w-0 space-y-0.5\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {goal.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {formatMoney(goal.targetAmount, goal.currency)}\n {' · '}\n {formatDate(goal.targetDate)}\n </p>\n </div>\n <Badge variant={statusBadgeVariant(goal.projection)} className=\"shrink-0\">\n {prettyLabel(goal.projection)}\n </Badge>\n </div>\n ))\n ) : (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noGoals', 'No goals yet')}\n description={translate(\n 'brainyrich.dashboard.noGoalsDesc',\n 'Set a financial goal to start tracking progress.'\n )}\n />\n )}\n </CardContent>\n </Card>\n </FadeIn>\n </div>\n </div>\n\n {/* Portfolios mini-list */}\n <FadeIn index={3}>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wallet className=\"size-5\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.sections.portfolios', 'Portfolios')}\n </CardTitle>\n <CardDescription>\n {translate(\n 'brainyrich.dashboard.sections.portfoliosDescription',\n 'Your active investment strategies'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {portfoliosQuery.isLoading ? (\n <LoadingState rows={3} />\n ) : portfoliosQuery.isError ? (\n <ErrorState onRetry={() => portfoliosQuery.refetch()} />\n ) : topPortfolios.length > 0 ? (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {topPortfolios.map((portfolio) => (\n <div\n key={portfolio.id}\n className=\"flex items-start justify-between gap-2 rounded-lg border border-border-subtle p-3 motion-safe:transition-colors hover:border-[var(--color-action-primary-border)]/50 hover:bg-bg-elevated\"\n >\n <div className=\"min-w-0 space-y-0.5\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {portfolio.name}\n </p>\n {portfolio.description ? (\n <p className=\"truncate text-xs text-text-secondary\">\n {portfolio.description}\n </p>\n ) : (\n <p className=\"text-xs text-text-secondary\">{portfolio.baseCurrency}</p>\n )}\n </div>\n <Badge variant={statusBadgeVariant(portfolio.status)} className=\"shrink-0\">\n {portfolio.status}\n </Badge>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Wallet className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noPortfolios', 'No portfolios yet')}\n description={translate(\n 'brainyrich.dashboard.noPortfoliosDesc',\n 'Create a portfolio to organize your investment strategy.'\n )}\n />\n )}\n </CardContent>\n </Card>\n </FadeIn>\n </SectionShell>\n </div>\n );\n}\n\ninterface HeroStat {\n label: string;\n value: string;\n icon: ReactNode;\n glow?: boolean;\n}\n\ntype Translate = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string;\n\n// ============================================================================\n// Severity chip — tinted, icon + label (colour is never the only signal)\n// ============================================================================\n\nconst SEVERITY_STYLE: Record<BraInsightSeverity, { chip: string; rail: string; icon: ReactNode }> =\n {\n CRITICAL: {\n chip: 'text-status-error-text bg-status-error-bg',\n rail: 'bg-status-error',\n icon: <ShieldAlert className=\"size-3\" aria-hidden=\"true\" />,\n },\n HIGH: {\n chip: 'text-status-error-text bg-status-error-bg',\n rail: 'bg-status-error',\n icon: <TriangleAlert className=\"size-3\" aria-hidden=\"true\" />,\n },\n MEDIUM: {\n chip: 'text-status-warning-text bg-status-warning-bg',\n rail: 'bg-status-warning',\n icon: <TriangleAlert className=\"size-3\" aria-hidden=\"true\" />,\n },\n LOW: {\n chip: 'text-status-info-text bg-status-info-bg',\n rail: 'bg-status-info',\n icon: <Info className=\"size-3\" aria-hidden=\"true\" />,\n },\n INFO: {\n chip: 'text-status-info-text bg-status-info-bg',\n rail: 'bg-status-info',\n icon: <Info className=\"size-3\" aria-hidden=\"true\" />,\n },\n };\n\nfunction SeverityChip({ severity }: { severity: BraInsightSeverity }) {\n const style = SEVERITY_STYLE[severity] ?? SEVERITY_STYLE.INFO;\n return (\n <span\n className={`inline-flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide ${style.chip}`}\n >\n {style.icon}\n {severity}\n </span>\n );\n}\n\n// ============================================================================\n// Insight row with acknowledge / dismiss / resolve actions\n// ============================================================================\n\nfunction InsightRow({ insight, translate }: { insight: BraInsight; translate: Translate }) {\n const acknowledge = useAcknowledgeInsight();\n const dismiss = useDismissInsight();\n const resolve = useResolveInsight();\n const [confirmDismiss, setConfirmDismiss] = useState(false);\n const pending = acknowledge.isPending || dismiss.isPending || resolve.isPending;\n const rail = (SEVERITY_STYLE[insight.severity] ?? SEVERITY_STYLE.INFO).rail;\n\n return (\n <div className=\"relative flex items-start justify-between gap-3 overflow-hidden rounded-lg border border-border-subtle p-3 pl-4 motion-safe:transition-colors hover:border-[var(--color-action-primary-border)]/50 hover:bg-bg-elevated\">\n <span aria-hidden=\"true\" className={`absolute inset-y-0 left-0 w-1 ${rail}`} />\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex items-center gap-2\">\n <SeverityChip severity={insight.severity} />\n <span className=\"truncate text-xs text-text-secondary\">{prettyLabel(insight.type)}</span>\n </div>\n <p className=\"text-sm font-medium text-text-primary\">{insight.title}</p>\n {insight.detail ? <p className=\"text-xs text-text-secondary\">{insight.detail}</p> : null}\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"shrink-0\"\n disabled={pending}\n aria-label={translate('brainyrich.dashboard.insightActions', 'Insight actions')}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onSelect={() => acknowledge.mutate(insight.id)}>\n <Check className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.insight.acknowledge', 'Acknowledge')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => resolve.mutate(insight.id)}>\n <CircleCheck className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.insight.resolve', 'Resolve')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => setConfirmDismiss(true)}>\n <X className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.insight.dismiss', 'Dismiss')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n\n <ConfirmDialog\n open={confirmDismiss}\n onOpenChange={setConfirmDismiss}\n title={translate('brainyrich.dashboard.insight.dismissTitle', 'Dismiss this insight?')}\n description={translate(\n 'brainyrich.dashboard.insight.dismissDescription',\n 'It will be removed from Needs Attention. You can still find it in the full insights list.'\n )}\n confirmLabel={translate('brainyrich.dashboard.insight.dismiss', 'Dismiss')}\n pendingLabel={translate('brainyrich.dashboard.insight.dismissing', 'Dismissing…')}\n destructive\n pending={dismiss.isPending}\n onConfirm={() =>\n dismiss.mutate(insight.id, {\n onSuccess: () => setConfirmDismiss(false),\n })\n }\n />\n </div>\n );\n}\n\n// ============================================================================\n// New account dialog — primary create action\n// ============================================================================\n\nfunction NewAccountDialog({ translate }: { translate: Translate }) {\n const [open, setOpen] = useState(false);\n const [name, setName] = useState('');\n const [type, setType] = useState<BraAccountType>('BROKERAGE');\n const [institution, setInstitution] = useState('');\n const [cashBalance, setCashBalance] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [householdId, setHouseholdId] = useState<string | null>(null);\n\n const createAccount = useCreateAccount();\n const trimmedName = name.trim();\n const canSubmit = trimmedName.length > 0 && !createAccount.isPending;\n\n const reset = () => {\n setName('');\n setType('BROKERAGE');\n setInstitution('');\n setCashBalance('');\n setCurrency('USD');\n setHouseholdId(null);\n createAccount.reset();\n };\n\n const handleSubmit = (event: FormEvent) => {\n event.preventDefault();\n if (!canSubmit) return;\n const parsedCash = Number.parseFloat(cashBalance);\n const input: BraCreateAccountInput = {\n name: trimmedName,\n type,\n currency: currency.trim() || 'USD',\n isManual: true,\n ...(institution.trim() ? { institution: institution.trim() } : {}),\n ...(Number.isFinite(parsedCash) ? { cashBalance: parsedCash } : {}),\n ...(householdId ? { householdId } : {}),\n };\n createAccount.mutate(input, {\n onSuccess: () => {\n hapticSuccess();\n void showToast(translate('brainyrich.dashboard.newAccount.success', 'Account created'));\n reset();\n setOpen(false);\n },\n });\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) reset();\n }}\n >\n <Button size=\"sm\" onClick={() => setOpen(true)}>\n <PlusCircle className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.actions.newAccount', 'New Account')}\n </Button>\n <DialogContent>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <DialogHeader>\n <DialogTitle>\n {translate('brainyrich.dashboard.newAccount.title', 'New Account')}\n </DialogTitle>\n <DialogDescription>\n {translate(\n 'brainyrich.dashboard.newAccount.description',\n 'Add a manual account to track alongside your linked institutions.'\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-name\">\n {translate('brainyrich.dashboard.newAccount.name', 'Account name')}\n </Label>\n <Input\n id=\"bra-account-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={translate(\n 'brainyrich.dashboard.newAccount.namePlaceholder',\n 'e.g. Fidelity Brokerage'\n )}\n required\n autoFocus\n />\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-type\">\n {translate('brainyrich.dashboard.newAccount.type', 'Type')}\n </Label>\n <Select value={type} onValueChange={(value) => setType(value as BraAccountType)}>\n <SelectTrigger id=\"bra-account-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ACCOUNT_TYPES.map((accountType) => (\n <SelectItem key={accountType} value={accountType}>\n {accountType.replace(/_/g, ' ')}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-currency\">\n {translate('brainyrich.dashboard.newAccount.currency', 'Currency')}\n </Label>\n <Input\n id=\"bra-account-currency\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value.toUpperCase())}\n maxLength={3}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-institution\">\n {translate('brainyrich.dashboard.newAccount.institution', 'Institution (optional)')}\n </Label>\n <Input\n id=\"bra-account-institution\"\n value={institution}\n onChange={(e) => setInstitution(e.target.value)}\n placeholder={translate(\n 'brainyrich.dashboard.newAccount.institutionPlaceholder',\n 'e.g. Fidelity'\n )}\n />\n </div>\n\n <HouseholdPicker\n id=\"bra-account-household\"\n value={householdId}\n onChange={setHouseholdId}\n label={translate('brainyrich.dashboard.newAccount.household', 'Household (optional)')}\n noneLabel={translate('brainyrich.dashboard.newAccount.noHousehold', 'No household')}\n disabled={createAccount.isPending}\n />\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-cash\">\n {translate('brainyrich.dashboard.newAccount.cash', 'Cash balance (optional)')}\n </Label>\n <Input\n id=\"bra-account-cash\"\n type=\"number\"\n inputMode=\"decimal\"\n step=\"0.01\"\n value={cashBalance}\n onChange={(e) => setCashBalance(e.target.value)}\n placeholder=\"0.00\"\n />\n </div>\n\n {createAccount.isError ? (\n <p className=\"text-sm text-status-error-text\">\n {createAccount.error instanceof Error\n ? createAccount.error.message\n : translate('brainyrich.dashboard.newAccount.error', 'Could not create account.')}\n </p>\n ) : null}\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={createAccount.isPending}\n >\n {translate('brainyrich.common.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={!canSubmit}>\n {createAccount.isPending\n ? translate('brainyrich.dashboard.newAccount.creating', 'Creating…')\n : translate('brainyrich.dashboard.newAccount.create', 'Create account')}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/brainyrich/pages/DashboardPage.tsx"],"sourcesContent":["import { useMemo, useState, type FormEvent, type ReactNode } from 'react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n Button,\n Badge,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Target,\n Bell,\n Briefcase,\n Wallet,\n PlusCircle,\n MoreHorizontal,\n Check,\n X,\n CircleCheck,\n TrendingUp,\n Coins,\n Landmark,\n TriangleAlert,\n Info,\n ShieldAlert,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n useNetWorthSummary,\n usePortfolios,\n useGoals,\n useInsights,\n useCreateAccount,\n useAcknowledgeInsight,\n useDismissInsight,\n useResolveInsight,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraAccountType,\n BraAssetClass,\n BraCreateAccountInput,\n BraInsight,\n BraInsightSeverity,\n} from '../types/bra';\nimport {\n HouseholdPicker,\n ConfirmDialog,\n DonutChart,\n StatTile,\n GlassCard,\n FadeIn,\n type VizTone,\n type DonutDatum,\n} from '../components';\nimport {\n SectionShell,\n EmptyState,\n LoadingState,\n ErrorState,\n formatMoney,\n formatCompact,\n formatDate,\n statusBadgeVariant,\n} from './_shared';\nimport { hapticSuccess, showToast } from '../utils/nativeControls';\nimport { useTrackBrainyRichPageView } from '../hooks/useBrainyRichAnalytics';\n\nconst ACCOUNT_TYPES: BraAccountType[] = [\n 'BANK',\n 'BROKERAGE',\n 'RETIREMENT',\n 'CASH',\n 'CRYPTO',\n 'REAL_ESTATE',\n 'ALTERNATIVE',\n 'LIABILITY',\n];\n\n/** Distinct, semantic tone per asset class so the donut stays legible + on-brand. */\nconst ASSET_TONE: Record<BraAssetClass, VizTone> = {\n EQUITY: 'brand',\n FIXED_INCOME: 'blue',\n CASH: 'teal',\n REAL_ESTATE: 'indigo',\n COMMODITY: 'warning',\n CRYPTO: 'purple',\n ALTERNATIVE: 'info',\n};\n\n/** Title-case an enum member: FIXED_INCOME → \"Fixed income\". */\nfunction prettyLabel(value: string): string {\n const spaced = value.replace(/_/g, ' ').toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nexport function DashboardPage() {\n const { t } = useI18n();\n const translate = (key: string, fallback: string, params?: Record<string, string | number>) =>\n tWithFallback(t, key, fallback, params);\n\n useTrackBrainyRichPageView('brainyrich.dashboard.viewed');\n\n const summaryQuery = useNetWorthSummary();\n const portfoliosQuery = usePortfolios();\n const goalsQuery = useGoals();\n const insightsQuery = useInsights({ status: 'OPEN' });\n\n const summary = summaryQuery.data;\n const currency = summary?.currency ?? 'USD';\n\n const kpis: HeroStat[] = summary\n ? [\n {\n label: translate('brainyrich.dashboard.metrics.netWorth', 'Net Worth'),\n value: formatCompact(summary.totalNetWorth, currency),\n icon: <Wallet className=\"size-4\" aria-hidden=\"true\" />,\n glow: true,\n },\n {\n label: translate('brainyrich.dashboard.metrics.investedAssets', 'Invested Assets'),\n value: formatCompact(summary.totalMarketValue, currency),\n icon: <TrendingUp className=\"size-4\" aria-hidden=\"true\" />,\n },\n {\n label: translate('brainyrich.dashboard.metrics.liquidity', 'Cash & Liquidity'),\n value: formatCompact(summary.totalCash, currency),\n icon: <Coins className=\"size-4\" aria-hidden=\"true\" />,\n },\n {\n label: translate('brainyrich.dashboard.metrics.accounts', 'Linked Accounts'),\n value: String(summary.accountCount),\n icon: <Landmark className=\"size-4\" aria-hidden=\"true\" />,\n },\n ]\n : [];\n\n const donutData: DonutDatum[] = useMemo(() => {\n if (!summary) return [];\n return summary.byAssetClass\n .filter((row) => Number.isFinite(row.marketValue) && row.marketValue > 0)\n .slice()\n .sort((a, b) => b.marketValue - a.marketValue)\n .map((row) => ({\n label: prettyLabel(row.assetClass),\n value: row.marketValue,\n tone: ASSET_TONE[row.assetClass],\n }));\n }, [summary]);\n\n const topPortfolios = portfoliosQuery.data.slice(0, 5);\n const topGoals = goalsQuery.data.slice(0, 5);\n const openInsights = insightsQuery.data.slice(0, 6);\n\n return (\n <div data-tour=\"brainyrich-page-dashboard\" className=\"contents\">\n <SectionShell\n title={translate('brainyrich.dashboard.title', 'Wealth Dashboard')}\n description={translate(\n 'brainyrich.dashboard.description',\n 'Your consolidated financial overview at a glance'\n )}\n actions={<NewAccountDialog translate={translate} />}\n >\n {/* Hero KPI row — net-worth overview */}\n {summaryQuery.isLoading ? (\n <LoadingState rows={1} />\n ) : summaryQuery.isError ? (\n <ErrorState\n title={translate('brainyrich.dashboard.netWorthError', 'Could not load net worth')}\n onRetry={() => summaryQuery.refetch()}\n />\n ) : summary ? (\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n {kpis.map((kpi, i) => (\n <FadeIn key={kpi.label} index={i}>\n <StatTile\n label={kpi.label}\n value={kpi.value}\n icon={kpi.icon}\n glow={kpi.glow}\n className=\"h-full\"\n />\n </FadeIn>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Wallet className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noSummary', 'No financial data yet')}\n description={translate(\n 'brainyrich.dashboard.noSummaryDesc',\n 'Link your first account to see your net worth here.'\n )}\n />\n )}\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Net worth by asset class — donut hero */}\n <FadeIn index={0} className=\"lg:col-span-2\">\n <GlassCard className=\"h-full\">\n <div className=\"mb-4 space-y-1\">\n <h2 className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <Briefcase className=\"size-5\" aria-hidden=\"true\" />\n {translate(\n 'brainyrich.dashboard.sections.assetAllocation',\n 'Net worth by asset class'\n )}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.dashboard.sections.assetAllocationDescription',\n 'Market value distributed across asset classes'\n )}\n </p>\n </div>\n {summaryQuery.isLoading ? (\n <LoadingState rows={3} />\n ) : summaryQuery.isError ? (\n <ErrorState onRetry={() => summaryQuery.refetch()} />\n ) : donutData.length > 0 ? (\n <DonutChart\n data={donutData}\n height={260}\n centerValue={formatCompact(summary?.totalMarketValue ?? 0, currency)}\n centerLabel={translate('brainyrich.dashboard.metrics.investedAssets', 'Invested')}\n valueFormatter={(v) => formatMoney(v, currency)}\n />\n ) : (\n <EmptyState\n icon={<Briefcase className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noAllocation', 'No holdings to allocate')}\n description={translate(\n 'brainyrich.dashboard.noAllocationDesc',\n 'Add holdings to your accounts to see how your wealth is allocated.'\n )}\n />\n )}\n </GlassCard>\n </FadeIn>\n\n {/* Right rail — needs attention + goals */}\n <div className=\"space-y-6\">\n {/* Needs attention — open insights */}\n <FadeIn index={1}>\n <Card className=\"motion-safe:transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]\">\n <CardHeader className=\"pb-3\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Bell className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.sections.needsAttention', 'Needs attention')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2.5\">\n {insightsQuery.isLoading ? (\n <LoadingState rows={2} />\n ) : insightsQuery.isError ? (\n <ErrorState onRetry={() => insightsQuery.refetch()} />\n ) : openInsights.length > 0 ? (\n openInsights.map((insight) => (\n <InsightRow key={insight.id} insight={insight} translate={translate} />\n ))\n ) : (\n <EmptyState\n icon={<CircleCheck className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noInsights', 'All clear')}\n description={translate(\n 'brainyrich.dashboard.noInsightsDesc',\n 'There are no open insights that need your attention.'\n )}\n />\n )}\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* Goals on track */}\n <FadeIn index={2}>\n <Card className=\"motion-safe:transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]\">\n <CardHeader className=\"pb-3\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Target className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.sections.goals', 'Goals on track')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2.5\">\n {goalsQuery.isLoading ? (\n <LoadingState rows={3} />\n ) : goalsQuery.isError ? (\n <ErrorState onRetry={() => goalsQuery.refetch()} />\n ) : topGoals.length > 0 ? (\n topGoals.map((goal) => (\n <div\n key={goal.id}\n className=\"flex items-start justify-between gap-2 rounded-lg border border-border-subtle p-3 motion-safe:transition-colors hover:border-[var(--color-action-primary-border)]/50 hover:bg-bg-elevated\"\n >\n <div className=\"min-w-0 space-y-0.5\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {goal.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {formatMoney(goal.targetAmount, goal.currency)}\n {' · '}\n {formatDate(goal.targetDate)}\n </p>\n </div>\n <Badge variant={statusBadgeVariant(goal.projection)} className=\"shrink-0\">\n {prettyLabel(goal.projection)}\n </Badge>\n </div>\n ))\n ) : (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noGoals', 'No goals yet')}\n description={translate(\n 'brainyrich.dashboard.noGoalsDesc',\n 'Set a financial goal to start tracking progress.'\n )}\n />\n )}\n </CardContent>\n </Card>\n </FadeIn>\n </div>\n </div>\n\n {/* Portfolios mini-list */}\n <FadeIn index={3}>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wallet className=\"size-5\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.sections.portfolios', 'Portfolios')}\n </CardTitle>\n <CardDescription>\n {translate(\n 'brainyrich.dashboard.sections.portfoliosDescription',\n 'Your active investment strategies'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {portfoliosQuery.isLoading ? (\n <LoadingState rows={3} />\n ) : portfoliosQuery.isError ? (\n <ErrorState onRetry={() => portfoliosQuery.refetch()} />\n ) : topPortfolios.length > 0 ? (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {topPortfolios.map((portfolio) => (\n <div\n key={portfolio.id}\n className=\"flex items-start justify-between gap-2 rounded-lg border border-border-subtle p-3 motion-safe:transition-colors hover:border-[var(--color-action-primary-border)]/50 hover:bg-bg-elevated\"\n >\n <div className=\"min-w-0 space-y-0.5\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {portfolio.name}\n </p>\n {portfolio.description ? (\n <p className=\"truncate text-xs text-text-secondary\">\n {portfolio.description}\n </p>\n ) : (\n <p className=\"text-xs text-text-secondary\">{portfolio.baseCurrency}</p>\n )}\n </div>\n <Badge variant={statusBadgeVariant(portfolio.status)} className=\"shrink-0\">\n {portfolio.status}\n </Badge>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Wallet className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noPortfolios', 'No portfolios yet')}\n description={translate(\n 'brainyrich.dashboard.noPortfoliosDesc',\n 'Create a portfolio to organize your investment strategy.'\n )}\n />\n )}\n </CardContent>\n </Card>\n </FadeIn>\n </SectionShell>\n </div>\n );\n}\n\ninterface HeroStat {\n label: string;\n value: string;\n icon: ReactNode;\n glow?: boolean;\n}\n\ntype Translate = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string;\n\n// ============================================================================\n// Severity chip — tinted, icon + label (colour is never the only signal)\n// ============================================================================\n\nconst SEVERITY_STYLE: Record<BraInsightSeverity, { chip: string; rail: string; icon: ReactNode }> =\n {\n CRITICAL: {\n chip: 'text-status-error-text bg-status-error-bg',\n rail: 'bg-status-error',\n icon: <ShieldAlert className=\"size-3\" aria-hidden=\"true\" />,\n },\n HIGH: {\n chip: 'text-status-error-text bg-status-error-bg',\n rail: 'bg-status-error',\n icon: <TriangleAlert className=\"size-3\" aria-hidden=\"true\" />,\n },\n MEDIUM: {\n chip: 'text-status-warning-text bg-status-warning-bg',\n rail: 'bg-status-warning',\n icon: <TriangleAlert className=\"size-3\" aria-hidden=\"true\" />,\n },\n LOW: {\n chip: 'text-status-info-text bg-status-info-bg',\n rail: 'bg-status-info',\n icon: <Info className=\"size-3\" aria-hidden=\"true\" />,\n },\n INFO: {\n chip: 'text-status-info-text bg-status-info-bg',\n rail: 'bg-status-info',\n icon: <Info className=\"size-3\" aria-hidden=\"true\" />,\n },\n };\n\nfunction SeverityChip({ severity }: { severity: BraInsightSeverity }) {\n const style = SEVERITY_STYLE[severity] ?? SEVERITY_STYLE.INFO;\n return (\n <span\n className={`inline-flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide ${style.chip}`}\n >\n {style.icon}\n {severity}\n </span>\n );\n}\n\n// ============================================================================\n// Insight row with acknowledge / dismiss / resolve actions\n// ============================================================================\n\nfunction InsightRow({ insight, translate }: { insight: BraInsight; translate: Translate }) {\n const acknowledge = useAcknowledgeInsight();\n const dismiss = useDismissInsight();\n const resolve = useResolveInsight();\n const [confirmDismiss, setConfirmDismiss] = useState(false);\n const pending = acknowledge.isPending || dismiss.isPending || resolve.isPending;\n const rail = (SEVERITY_STYLE[insight.severity] ?? SEVERITY_STYLE.INFO).rail;\n\n return (\n <div className=\"relative flex items-start justify-between gap-3 overflow-hidden rounded-lg border border-border-subtle p-3 pl-4 motion-safe:transition-colors hover:border-[var(--color-action-primary-border)]/50 hover:bg-bg-elevated\">\n <span aria-hidden=\"true\" className={`absolute inset-y-0 left-0 w-1 ${rail}`} />\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex items-center gap-2\">\n <SeverityChip severity={insight.severity} />\n <span className=\"truncate text-xs text-text-secondary\">{prettyLabel(insight.type)}</span>\n </div>\n <p className=\"text-sm font-medium text-text-primary\">{insight.title}</p>\n {insight.detail ? <p className=\"text-xs text-text-secondary\">{insight.detail}</p> : null}\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"shrink-0\"\n disabled={pending}\n aria-label={translate('brainyrich.dashboard.insightActions', 'Insight actions')}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onSelect={() => acknowledge.mutate(insight.id)}>\n <Check className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.insight.acknowledge', 'Acknowledge')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => resolve.mutate(insight.id)}>\n <CircleCheck className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.insight.resolve', 'Resolve')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => setConfirmDismiss(true)}>\n <X className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.insight.dismiss', 'Dismiss')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n\n <ConfirmDialog\n open={confirmDismiss}\n onOpenChange={setConfirmDismiss}\n title={translate('brainyrich.dashboard.insight.dismissTitle', 'Dismiss this insight?')}\n description={translate(\n 'brainyrich.dashboard.insight.dismissDescription',\n 'It will be removed from Needs Attention. You can still find it in the full insights list.'\n )}\n confirmLabel={translate('brainyrich.dashboard.insight.dismiss', 'Dismiss')}\n pendingLabel={translate('brainyrich.dashboard.insight.dismissing', 'Dismissing…')}\n destructive\n pending={dismiss.isPending}\n onConfirm={() =>\n dismiss.mutate(insight.id, {\n onSuccess: () => setConfirmDismiss(false),\n })\n }\n />\n </div>\n );\n}\n\n// ============================================================================\n// New account dialog — primary create action\n// ============================================================================\n\nfunction NewAccountDialog({ translate }: { translate: Translate }) {\n const [open, setOpen] = useState(false);\n const [name, setName] = useState('');\n const [type, setType] = useState<BraAccountType>('BROKERAGE');\n const [institution, setInstitution] = useState('');\n const [cashBalance, setCashBalance] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [householdId, setHouseholdId] = useState<string | null>(null);\n\n const createAccount = useCreateAccount();\n const trimmedName = name.trim();\n const canSubmit = trimmedName.length > 0 && !createAccount.isPending;\n\n const reset = () => {\n setName('');\n setType('BROKERAGE');\n setInstitution('');\n setCashBalance('');\n setCurrency('USD');\n setHouseholdId(null);\n createAccount.reset();\n };\n\n const handleSubmit = (event: FormEvent) => {\n event.preventDefault();\n if (!canSubmit) return;\n const parsedCash = Number.parseFloat(cashBalance);\n const input: BraCreateAccountInput = {\n name: trimmedName,\n type,\n currency: currency.trim() || 'USD',\n isManual: true,\n ...(institution.trim() ? { institution: institution.trim() } : {}),\n ...(Number.isFinite(parsedCash) ? { cashBalance: parsedCash } : {}),\n ...(householdId ? { householdId } : {}),\n };\n createAccount.mutate(input, {\n onSuccess: () => {\n hapticSuccess();\n void showToast(translate('brainyrich.dashboard.newAccount.success', 'Account created'));\n reset();\n setOpen(false);\n },\n });\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) reset();\n }}\n >\n <Button size=\"sm\" onClick={() => setOpen(true)}>\n <PlusCircle className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.dashboard.actions.newAccount', 'New Account')}\n </Button>\n <ResponsiveDialogContent>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {translate('brainyrich.dashboard.newAccount.title', 'New Account')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {translate(\n 'brainyrich.dashboard.newAccount.description',\n 'Add a manual account to track alongside your linked institutions.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-name\">\n {translate('brainyrich.dashboard.newAccount.name', 'Account name')}\n </Label>\n <Input\n id=\"bra-account-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={translate(\n 'brainyrich.dashboard.newAccount.namePlaceholder',\n 'e.g. Fidelity Brokerage'\n )}\n required\n autoFocus\n />\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-type\">\n {translate('brainyrich.dashboard.newAccount.type', 'Type')}\n </Label>\n <Select value={type} onValueChange={(value) => setType(value as BraAccountType)}>\n <SelectTrigger id=\"bra-account-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ACCOUNT_TYPES.map((accountType) => (\n <SelectItem key={accountType} value={accountType}>\n {accountType.replace(/_/g, ' ')}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-currency\">\n {translate('brainyrich.dashboard.newAccount.currency', 'Currency')}\n </Label>\n <Input\n id=\"bra-account-currency\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value.toUpperCase())}\n maxLength={3}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-institution\">\n {translate('brainyrich.dashboard.newAccount.institution', 'Institution (optional)')}\n </Label>\n <Input\n id=\"bra-account-institution\"\n value={institution}\n onChange={(e) => setInstitution(e.target.value)}\n placeholder={translate(\n 'brainyrich.dashboard.newAccount.institutionPlaceholder',\n 'e.g. Fidelity'\n )}\n />\n </div>\n\n <HouseholdPicker\n id=\"bra-account-household\"\n value={householdId}\n onChange={setHouseholdId}\n label={translate('brainyrich.dashboard.newAccount.household', 'Household (optional)')}\n noneLabel={translate('brainyrich.dashboard.newAccount.noHousehold', 'No household')}\n disabled={createAccount.isPending}\n />\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"bra-account-cash\">\n {translate('brainyrich.dashboard.newAccount.cash', 'Cash balance (optional)')}\n </Label>\n <Input\n id=\"bra-account-cash\"\n type=\"number\"\n inputMode=\"decimal\"\n step=\"0.01\"\n value={cashBalance}\n onChange={(e) => setCashBalance(e.target.value)}\n placeholder=\"0.00\"\n />\n </div>\n\n {createAccount.isError ? (\n <p className=\"text-sm text-status-error-text\">\n {createAccount.error instanceof Error\n ? createAccount.error.message\n : translate('brainyrich.dashboard.newAccount.error', 'Could not create account.')}\n </p>\n ) : null}\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={createAccount.isPending}\n >\n {translate('brainyrich.common.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={!canSubmit}>\n {createAccount.isPending\n ? translate('brainyrich.dashboard.newAccount.creating', 'Creating…')\n : translate('brainyrich.dashboard.newAccount.create', 'Create account')}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -15,7 +15,7 @@ import { useMemo as oe, useState as w } from "react";
15
15
  import { Archive as T, Briefcase as E, Building2 as se, Eye as ce, Mail as le, MoreHorizontal as ue, Pencil as de, Target as D, TrendingUp as O, UserCircle2 as fe, Users as k, Wallet as A } from "lucide-react";
16
16
  import { useI18n as pe } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
17
17
  import { jsx as j, jsxs as M } from "react/jsx-runtime";
18
- import { Badge as N, Button as P, Card as F, CardContent as I, Dialog as L, DialogClose as R, DialogContent as me, DialogDescription as z, DialogFooter as B, DialogHeader as V, DialogTitle as he, DropdownMenu as ge, DropdownMenuContent as _e, DropdownMenuItem as H, DropdownMenuSeparator as ve, DropdownMenuTrigger as ye, Input as U, Label as W, Select as G, SelectContent as K, SelectItem as q, SelectTrigger as J, SelectValue as Y, Separator as be, Sheet as xe, SheetContent as Se, SheetDescription as Ce, SheetHeader as we, SheetTitle as Te, Table as Ee, TableBody as De, TableCell as X, TableHead as Z, TableHeader as Oe, TableRow as ke, Tabs as Ae, TabsContent as Q, TabsList as je, TabsTrigger as $, Textarea as Me } from "@burdenoff/fe-libs/ui";
18
+ import { Badge as N, Button as P, Card as F, CardContent as I, DropdownMenu as me, DropdownMenuContent as he, DropdownMenuItem as L, DropdownMenuSeparator as ge, DropdownMenuTrigger as _e, Input as R, Label as z, ResponsiveDialog as ve, ResponsiveDialogClose as B, ResponsiveDialogContent as V, ResponsiveDialogDescription as H, ResponsiveDialogFooter as ye, ResponsiveDialogHeader as U, ResponsiveDialogTitle as W, Select as G, SelectContent as K, SelectItem as q, SelectTrigger as J, SelectValue as Y, Separator as be, Sheet as xe, SheetContent as Se, SheetDescription as Ce, SheetHeader as we, SheetTitle as Te, Table as Ee, TableBody as De, TableCell as X, TableHead as Z, TableHeader as Oe, TableRow as ke, Tabs as Ae, TabsContent as Q, TabsList as je, TabsTrigger as $, Textarea as Me } from "@burdenoff/fe-libs/ui";
19
19
  //#region src/brainyrich/pages/FamilyPage.tsx
20
20
  var Ne = [
21
21
  "PROSPECT",
@@ -61,13 +61,13 @@ function ze(e) {
61
61
  function Be() {
62
62
  let { t } = pe(), i = (n, r, i) => e(t, n, r, i);
63
63
  x("brainyrich.family.viewed");
64
- let { items: a, hasMore: s, loadMore: u, isLoading: f, isFetchingNextPage: h, isError: g, refetch: ae } = o(), S = r(), C = c(), E = n(), [se, D] = w(!1), [O, A] = w(null), [L, R] = w(Le), [me, z] = w(void 0), [B, V] = w(null), he = (e, t) => R((n) => ({
64
+ let { items: a, hasMore: s, loadMore: u, isLoading: f, isFetchingNextPage: h, isError: g, refetch: ae } = o(), S = r(), C = c(), E = n(), [se, D] = w(!1), [O, A] = w(null), [R, z] = w(Le), [ve, B] = w(void 0), [V, H] = w(null), ye = (e, t) => z((n) => ({
65
65
  ...n,
66
66
  [e]: t
67
67
  })), U = () => {
68
- A(null), R(Le), D(!0);
68
+ A(null), z(Le), D(!0);
69
69
  }, W = (e) => {
70
- A(e), R({
70
+ A(e), z({
71
71
  name: e.name,
72
72
  status: e.status,
73
73
  riskProfile: e.riskProfile,
@@ -104,17 +104,17 @@ function Be() {
104
104
  tone: Ie[e]
105
105
  })).filter((e) => e.value > 0)
106
106
  };
107
- }, [a]), K = S.isPending || C.isPending, q = L.name.trim().length > 0 && !K, J = () => {
107
+ }, [a]), K = S.isPending || C.isPending, q = R.name.trim().length > 0 && !K, J = () => {
108
108
  if (q) if (O) {
109
109
  let e = {
110
- name: L.name.trim(),
111
- status: L.status,
112
- riskProfile: L.riskProfile,
113
- currency: L.currency,
114
- primaryContactName: L.primaryContactName.trim() || null,
115
- primaryContactEmail: L.primaryContactEmail.trim() || null,
116
- notes: L.notes.trim() || null,
117
- tags: Re(L.tags)
110
+ name: R.name.trim(),
111
+ status: R.status,
112
+ riskProfile: R.riskProfile,
113
+ currency: R.currency,
114
+ primaryContactName: R.primaryContactName.trim() || null,
115
+ primaryContactEmail: R.primaryContactEmail.trim() || null,
116
+ notes: R.notes.trim() || null,
117
+ tags: Re(R.tags)
118
118
  };
119
119
  C.mutate({
120
120
  id: O.id,
@@ -124,16 +124,16 @@ function Be() {
124
124
  } });
125
125
  } else {
126
126
  let e = {
127
- name: L.name.trim(),
128
- status: L.status,
129
- riskProfile: L.riskProfile,
130
- currency: L.currency,
131
- primaryContactName: L.primaryContactName.trim() || null,
132
- primaryContactEmail: L.primaryContactEmail.trim() || null,
133
- notes: L.notes.trim() || null,
134
- tags: Re(L.tags)
127
+ name: R.name.trim(),
128
+ status: R.status,
129
+ riskProfile: R.riskProfile,
130
+ currency: R.currency,
131
+ primaryContactName: R.primaryContactName.trim() || null,
132
+ primaryContactEmail: R.primaryContactEmail.trim() || null,
133
+ notes: R.notes.trim() || null,
134
+ tags: Re(R.tags)
135
135
  };
136
- L.advisorId.trim() && (e.advisorId = L.advisorId.trim()), S.mutate(e, { onSuccess: () => {
136
+ R.advisorId.trim() && (e.advisorId = R.advisorId.trim()), S.mutate(e, { onSuccess: () => {
137
137
  y(), b(i("brainyrich.households.created", "Household created")), D(!1);
138
138
  } });
139
139
  }
@@ -229,7 +229,7 @@ function Be() {
229
229
  let t = G.aum > 0 ? Math.min(100, e.aum / G.aum * 100) : 0;
230
230
  return /* @__PURE__ */ M(ke, {
231
231
  className: "group cursor-pointer transition-colors",
232
- onClick: () => z(e.id),
232
+ onClick: () => B(e.id),
233
233
  children: [
234
234
  /* @__PURE__ */ M(X, { children: [/* @__PURE__ */ j("span", {
235
235
  className: "font-medium text-text-primary transition-colors group-hover:text-[var(--color-action-primary-text)]",
@@ -309,7 +309,7 @@ function Be() {
309
309
  /* @__PURE__ */ j(X, {
310
310
  className: "text-right",
311
311
  onClick: (e) => e.stopPropagation(),
312
- children: /* @__PURE__ */ M(ge, { children: [/* @__PURE__ */ j(ye, {
312
+ children: /* @__PURE__ */ M(me, { children: [/* @__PURE__ */ j(_e, {
313
313
  asChild: !0,
314
314
  children: /* @__PURE__ */ j(P, {
315
315
  variant: "ghost",
@@ -320,27 +320,27 @@ function Be() {
320
320
  "aria-hidden": "true"
321
321
  })
322
322
  })
323
- }), /* @__PURE__ */ M(_e, {
323
+ }), /* @__PURE__ */ M(he, {
324
324
  align: "end",
325
325
  children: [
326
- /* @__PURE__ */ M(H, {
327
- onClick: () => z(e.id),
326
+ /* @__PURE__ */ M(L, {
327
+ onClick: () => B(e.id),
328
328
  children: [/* @__PURE__ */ j(ce, {
329
329
  className: "size-4",
330
330
  "aria-hidden": "true"
331
331
  }), i("brainyrich.households.action.view", "View details")]
332
332
  }),
333
- /* @__PURE__ */ M(H, {
333
+ /* @__PURE__ */ M(L, {
334
334
  onClick: () => W(e),
335
335
  children: [/* @__PURE__ */ j(de, {
336
336
  className: "size-4",
337
337
  "aria-hidden": "true"
338
338
  }), i("brainyrich.households.action.edit", "Edit")]
339
339
  }),
340
- /* @__PURE__ */ j(ve, {}),
341
- /* @__PURE__ */ M(H, {
340
+ /* @__PURE__ */ j(ge, {}),
341
+ /* @__PURE__ */ M(L, {
342
342
  className: "text-status-error-text focus:text-status-error-text",
343
- onClick: () => V(e),
343
+ onClick: () => H(e),
344
344
  children: [/* @__PURE__ */ j(T, {
345
345
  className: "size-4",
346
346
  "aria-hidden": "true"
@@ -366,33 +366,33 @@ function Be() {
366
366
  open: se,
367
367
  onOpenChange: D,
368
368
  editing: O,
369
- form: L,
370
- setField: he,
369
+ form: R,
370
+ setField: ye,
371
371
  onSubmit: J,
372
372
  canSubmit: q,
373
373
  submitting: K,
374
374
  tr: i
375
375
  }),
376
376
  /* @__PURE__ */ j(Ue, {
377
- householdId: me,
378
- onClose: () => z(void 0),
377
+ householdId: ve,
378
+ onClose: () => B(void 0),
379
379
  onEdit: (e) => {
380
- z(void 0), W(e);
380
+ B(void 0), W(e);
381
381
  },
382
382
  tr: i
383
383
  }),
384
384
  /* @__PURE__ */ j(te, {
385
- open: !!B,
386
- onOpenChange: (e) => e ? void 0 : V(null),
385
+ open: !!V,
386
+ onOpenChange: (e) => e ? void 0 : H(null),
387
387
  title: i("brainyrich.households.archive.title", "Archive household?"),
388
- description: i("brainyrich.households.archive.description", "Archiving “{name}” removes it from the active list. You can still access its records, but it will no longer appear here.", { name: B?.name ?? "" }),
388
+ description: i("brainyrich.households.archive.description", "Archiving “{name}” removes it from the active list. You can still access its records, but it will no longer appear here.", { name: V?.name ?? "" }),
389
389
  confirmLabel: i("brainyrich.households.action.archive", "Archive"),
390
390
  pendingLabel: i("brainyrich.households.archive.pending", "Archiving…"),
391
391
  destructive: !0,
392
392
  pending: E.isPending,
393
393
  onConfirm: () => {
394
- B && E.mutate(B.id, { onSuccess: () => {
395
- y(), b(i("brainyrich.households.archived", "Household archived", { name: B.name })), V(null);
394
+ V && E.mutate(V.id, { onSuccess: () => {
395
+ y(), b(i("brainyrich.households.archived", "Household archived", { name: V.name })), H(null);
396
396
  } });
397
397
  }
398
398
  })
@@ -512,12 +512,12 @@ function Ve({ firm: e, tr: t }) {
512
512
  });
513
513
  }
514
514
  function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubmit: a, canSubmit: o, submitting: s, tr: c }) {
515
- return /* @__PURE__ */ j(L, {
515
+ return /* @__PURE__ */ j(ve, {
516
516
  open: e,
517
517
  onOpenChange: t,
518
- children: /* @__PURE__ */ M(me, {
518
+ children: /* @__PURE__ */ M(V, {
519
519
  className: "max-h-[90vh] overflow-y-auto sm:max-w-lg",
520
- children: [/* @__PURE__ */ M(V, { children: [/* @__PURE__ */ j(he, { children: n ? c("brainyrich.households.form.editTitle", "Edit household") : c("brainyrich.households.form.createTitle", "New household") }), /* @__PURE__ */ j(z, { children: c("brainyrich.households.form.subtitle", "A household groups a client family’s accounts, portfolios and goals.") })] }), /* @__PURE__ */ M("form", {
520
+ children: [/* @__PURE__ */ M(U, { children: [/* @__PURE__ */ j(W, { children: n ? c("brainyrich.households.form.editTitle", "Edit household") : c("brainyrich.households.form.createTitle", "New household") }), /* @__PURE__ */ j(H, { children: c("brainyrich.households.form.subtitle", "A household groups a client family’s accounts, portfolios and goals.") })] }), /* @__PURE__ */ M("form", {
521
521
  className: "space-y-4",
522
522
  onSubmit: (e) => {
523
523
  e.preventDefault(), a();
@@ -525,10 +525,10 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
525
525
  children: [
526
526
  /* @__PURE__ */ M("div", {
527
527
  className: "space-y-2",
528
- children: [/* @__PURE__ */ M(W, {
528
+ children: [/* @__PURE__ */ M(z, {
529
529
  htmlFor: "hh-name",
530
530
  children: [c("brainyrich.households.form.name", "Name"), " *"]
531
- }), /* @__PURE__ */ j(U, {
531
+ }), /* @__PURE__ */ j(R, {
532
532
  id: "hh-name",
533
533
  value: r.name,
534
534
  onChange: (e) => i("name", e.target.value),
@@ -540,7 +540,7 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
540
540
  className: "grid gap-4 sm:grid-cols-2",
541
541
  children: [/* @__PURE__ */ M("div", {
542
542
  className: "space-y-2",
543
- children: [/* @__PURE__ */ j(W, { children: c("brainyrich.households.form.status", "Status") }), /* @__PURE__ */ M(G, {
543
+ children: [/* @__PURE__ */ j(z, { children: c("brainyrich.households.form.status", "Status") }), /* @__PURE__ */ M(G, {
544
544
  value: r.status,
545
545
  onValueChange: (e) => i("status", e),
546
546
  children: [/* @__PURE__ */ j(J, { children: /* @__PURE__ */ j(Y, {}) }), /* @__PURE__ */ j(K, { children: Ne.map((e) => /* @__PURE__ */ j(q, {
@@ -550,7 +550,7 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
550
550
  })]
551
551
  }), /* @__PURE__ */ M("div", {
552
552
  className: "space-y-2",
553
- children: [/* @__PURE__ */ j(W, { children: c("brainyrich.households.form.risk", "Risk profile") }), /* @__PURE__ */ M(G, {
553
+ children: [/* @__PURE__ */ j(z, { children: c("brainyrich.households.form.risk", "Risk profile") }), /* @__PURE__ */ M(G, {
554
554
  value: r.riskProfile,
555
555
  onValueChange: (e) => i("riskProfile", e),
556
556
  children: [/* @__PURE__ */ j(J, { children: /* @__PURE__ */ j(Y, {}) }), /* @__PURE__ */ j(K, { children: Pe.map((e) => /* @__PURE__ */ j(q, {
@@ -564,10 +564,10 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
564
564
  className: "grid gap-4 sm:grid-cols-2",
565
565
  children: [/* @__PURE__ */ M("div", {
566
566
  className: "space-y-2",
567
- children: [/* @__PURE__ */ j(W, {
567
+ children: [/* @__PURE__ */ j(z, {
568
568
  htmlFor: "hh-contact-name",
569
569
  children: c("brainyrich.households.form.contactName", "Primary contact")
570
- }), /* @__PURE__ */ j(U, {
570
+ }), /* @__PURE__ */ j(R, {
571
571
  id: "hh-contact-name",
572
572
  value: r.primaryContactName,
573
573
  onChange: (e) => i("primaryContactName", e.target.value),
@@ -575,10 +575,10 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
575
575
  })]
576
576
  }), /* @__PURE__ */ M("div", {
577
577
  className: "space-y-2",
578
- children: [/* @__PURE__ */ j(W, {
578
+ children: [/* @__PURE__ */ j(z, {
579
579
  htmlFor: "hh-contact-email",
580
580
  children: c("brainyrich.households.form.contactEmail", "Contact email")
581
- }), /* @__PURE__ */ j(U, {
581
+ }), /* @__PURE__ */ j(R, {
582
582
  id: "hh-contact-email",
583
583
  type: "email",
584
584
  value: r.primaryContactEmail,
@@ -591,7 +591,7 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
591
591
  className: "grid gap-4 sm:grid-cols-2",
592
592
  children: [/* @__PURE__ */ M("div", {
593
593
  className: "space-y-2",
594
- children: [/* @__PURE__ */ j(W, { children: c("brainyrich.households.form.currency", "Currency") }), /* @__PURE__ */ M(G, {
594
+ children: [/* @__PURE__ */ j(z, { children: c("brainyrich.households.form.currency", "Currency") }), /* @__PURE__ */ M(G, {
595
595
  value: r.currency,
596
596
  onValueChange: (e) => i("currency", e),
597
597
  children: [/* @__PURE__ */ j(J, { children: /* @__PURE__ */ j(Y, {}) }), /* @__PURE__ */ j(K, { children: Fe.map((e) => /* @__PURE__ */ j(q, {
@@ -601,10 +601,10 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
601
601
  })]
602
602
  }), n ? null : /* @__PURE__ */ M("div", {
603
603
  className: "space-y-2",
604
- children: [/* @__PURE__ */ j(W, {
604
+ children: [/* @__PURE__ */ j(z, {
605
605
  htmlFor: "hh-advisor",
606
606
  children: c("brainyrich.households.form.advisor", "Advisor ID")
607
- }), /* @__PURE__ */ j(U, {
607
+ }), /* @__PURE__ */ j(R, {
608
608
  id: "hh-advisor",
609
609
  value: r.advisorId,
610
610
  onChange: (e) => i("advisorId", e.target.value),
@@ -618,10 +618,10 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
618
618
  label: c("brainyrich.households.form.tags", "Tags")
619
619
  }) : /* @__PURE__ */ M("div", {
620
620
  className: "space-y-2",
621
- children: [/* @__PURE__ */ j(W, {
621
+ children: [/* @__PURE__ */ j(z, {
622
622
  htmlFor: "hh-tags",
623
623
  children: c("brainyrich.households.form.tags", "Tags")
624
- }), /* @__PURE__ */ j(U, {
624
+ }), /* @__PURE__ */ j(R, {
625
625
  id: "hh-tags",
626
626
  value: r.tags,
627
627
  onChange: (e) => i("tags", e.target.value),
@@ -630,7 +630,7 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
630
630
  }),
631
631
  /* @__PURE__ */ M("div", {
632
632
  className: "space-y-2",
633
- children: [/* @__PURE__ */ j(W, {
633
+ children: [/* @__PURE__ */ j(z, {
634
634
  htmlFor: "hh-notes",
635
635
  children: c("brainyrich.households.form.notes", "Notes")
636
636
  }), /* @__PURE__ */ j(Me, {
@@ -640,7 +640,7 @@ function He({ open: e, onOpenChange: t, editing: n, form: r, setField: i, onSubm
640
640
  rows: 3
641
641
  })]
642
642
  }),
643
- /* @__PURE__ */ M(B, { children: [/* @__PURE__ */ j(R, {
643
+ /* @__PURE__ */ M(ye, { children: [/* @__PURE__ */ j(B, {
644
644
  asChild: !0,
645
645
  children: /* @__PURE__ */ j(P, {
646
646
  type: "button",