@burdenoff/microfe-brainyrich 2026.1101.2 → 2026.1101.3
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.
- package/dist/brainyrich/BrainyRichRoot.d.ts.map +1 -1
- package/dist/brainyrich/BrainyRichRoot.js +22 -107
- package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
- package/dist/brainyrich/BrainyRichRoutes.d.ts.map +1 -1
- package/dist/brainyrich/BrainyRichRoutes.js +65 -46
- package/dist/brainyrich/BrainyRichRoutes.js.map +1 -1
- package/dist/brainyrich/components/mobile/MobilePage.d.ts +44 -0
- package/dist/brainyrich/components/mobile/MobilePage.d.ts.map +1 -0
- package/dist/brainyrich/components/mobile/MobilePage.js +45 -0
- package/dist/brainyrich/components/mobile/MobilePage.js.map +1 -0
- package/dist/brainyrich/components/mobile/MobileTabBar.d.ts +20 -0
- package/dist/brainyrich/components/mobile/MobileTabBar.d.ts.map +1 -0
- package/dist/brainyrich/components/mobile/MobileTabBar.js +139 -0
- package/dist/brainyrich/components/mobile/MobileTabBar.js.map +1 -0
- package/dist/brainyrich/components/mobile/index.d.ts +8 -0
- package/dist/brainyrich/components/mobile/index.d.ts.map +1 -0
- package/dist/brainyrich/components/mobile/index.js +2 -0
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts +48 -12
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.js +120 -108
- package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
- package/dist/brainyrich/hooks/useIsMobileViewport.d.ts +14 -0
- package/dist/brainyrich/hooks/useIsMobileViewport.d.ts.map +1 -0
- package/dist/brainyrich/hooks/useIsMobileViewport.js +23 -0
- package/dist/brainyrich/hooks/useIsMobileViewport.js.map +1 -0
- package/dist/brainyrich/navItems.d.ts +36 -0
- package/dist/brainyrich/navItems.d.ts.map +1 -0
- package/dist/brainyrich/navItems.js +54 -0
- package/dist/brainyrich/navItems.js.map +1 -0
- package/dist/brainyrich/pages/AccountsPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/AccountsPage.js +411 -390
- package/dist/brainyrich/pages/AccountsPage.js.map +1 -1
- package/dist/brainyrich/pages/DashboardPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/DashboardPage.js +220 -174
- package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
- package/dist/brainyrich/pages/GoalsPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/GoalsPage.js +560 -551
- package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
- package/dist/brainyrich/pages/mobile/MobileAccountsView.d.ts +28 -0
- package/dist/brainyrich/pages/mobile/MobileAccountsView.d.ts.map +1 -0
- package/dist/brainyrich/pages/mobile/MobileAccountsView.js +139 -0
- package/dist/brainyrich/pages/mobile/MobileAccountsView.js.map +1 -0
- package/dist/brainyrich/pages/mobile/MobileDashboardView.d.ts +24 -0
- package/dist/brainyrich/pages/mobile/MobileDashboardView.d.ts.map +1 -0
- package/dist/brainyrich/pages/mobile/MobileDashboardView.js +245 -0
- package/dist/brainyrich/pages/mobile/MobileDashboardView.js.map +1 -0
- package/dist/brainyrich/pages/mobile/MobileGoalsView.d.ts +30 -0
- package/dist/brainyrich/pages/mobile/MobileGoalsView.d.ts.map +1 -0
- package/dist/brainyrich/pages/mobile/MobileGoalsView.js +180 -0
- package/dist/brainyrich/pages/mobile/MobileGoalsView.js.map +1 -0
- package/dist/brainyrich/pages/mobile/mobileShared.d.ts +24 -0
- package/dist/brainyrich/pages/mobile/mobileShared.d.ts.map +1 -0
- package/dist/brainyrich/pages/mobile/mobileShared.js +25 -0
- package/dist/brainyrich/pages/mobile/mobileShared.js.map +1 -0
- package/dist/brainyrich/utils/cn.js +10 -0
- package/dist/brainyrich/utils/cn.js.map +1 -0
- package/dist/brainyrich/utils/goalMetrics.d.ts +13 -0
- package/dist/brainyrich/utils/goalMetrics.d.ts.map +1 -0
- package/dist/brainyrich/utils/goalMetrics.js +20 -0
- package/dist/brainyrich/utils/goalMetrics.js.map +1 -0
- package/dist/test/brainyrichFixtures.d.ts +7 -0
- package/dist/test/brainyrichFixtures.d.ts.map +1 -0
- package/dist/test/viewport.d.ts +8 -0
- package/dist/test/viewport.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoalsPage.js","names":[],"sources":["../../../src/brainyrich/pages/GoalsPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AlertTriangle,\n CalendarClock,\n Coins,\n Link2,\n LineChart,\n MoreHorizontal,\n PiggyBank,\n Plus,\n RefreshCw,\n Target,\n Trash2,\n TrendingDown,\n TrendingUp,\n Unlink,\n Wallet,\n} from 'lucide-react';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n ConfirmDialog,\n FadeIn,\n GlassCard,\n LoadMore,\n MiniAreaChart,\n ProgressRing,\n StatTile,\n type AreaDatum,\n type VizTone,\n} from '../components';\nimport { TagField } from '../components/reuse/TagField';\nimport { hapticSuccess, showToast } from '../utils/nativeControls';\nimport { useTrackBrainyRichPageView } from '../hooks/useBrainyRichAnalytics';\nimport {\n useAccounts,\n useArchiveGoal,\n useCreateGoal,\n useGoal,\n useGoalFundings,\n useHouseholds,\n useLinkGoalFunding,\n usePagedGoals,\n useRecalcGoalProjection,\n useUnlinkGoalFunding,\n useUpdateGoal,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraCreateGoalInput,\n BraGoal,\n BraGoalFunding,\n BraGoalProjection,\n BraGoalStatus,\n BraGoalType,\n BraUpdateGoalInput,\n} from '../types/bra';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n SectionShell,\n formatCompact,\n formatDate,\n formatMoney,\n formatPct,\n statusBadgeVariant,\n} from './_shared';\n\nconst GOAL_TYPES: BraGoalType[] = [\n 'RETIREMENT',\n 'EDUCATION',\n 'HOME',\n 'EMERGENCY_FUND',\n 'MAJOR_PURCHASE',\n 'WEALTH_GROWTH',\n 'CUSTOM',\n];\n\nconst GOAL_STATUSES: BraGoalStatus[] = ['ACTIVE', 'ACHIEVED', 'ON_HOLD', 'ABANDONED'];\n\ninterface ProjectionMeta {\n icon: typeof TrendingUp;\n tone: string;\n}\n\nfunction projectionMeta(projection: BraGoalProjection): ProjectionMeta {\n switch (projection) {\n case 'AHEAD':\n case 'ON_TRACK':\n return { icon: TrendingUp, tone: 'text-status-success-text' };\n case 'BEHIND':\n return { icon: TrendingDown, tone: 'text-status-warning-text' };\n case 'AT_RISK':\n default:\n return { icon: AlertTriangle, tone: 'text-status-error-text' };\n }\n}\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\n/** Sum of the fixed-amount funding links wired to a goal (real backend value). */\nfunction goalFixedFunded(goal: Pick<BraGoal, 'fundings'>): number {\n // `fundings` is omitted from GOAL_FIELDS, so list-query items arrive without it.\n // Treat absence as zero-funded so the goal card renders instead of crashing.\n return (goal.fundings ?? []).reduce((s, f) => s + (f.fixedAmount ?? 0), 0);\n}\n\n/**\n * Funded-progress percentage for a goal. ACHIEVED goals read 100%; otherwise the\n * sum of fixed funding links over the target — every input is wired backend data,\n * never fabricated.\n */\nfunction fundedPercent(goal: Pick<BraGoal, 'fundings' | 'targetAmount' | 'status'>): number {\n if (goal.status === 'ACHIEVED') return 100;\n if (!(goal.targetAmount > 0)) return 0;\n return Math.max(0, Math.min(100, (goalFixedFunded(goal) / goal.targetAmount) * 100));\n}\n\n/** Ring/accent tone derived from the goal's real status + projection. */\nfunction goalTone(status: BraGoalStatus, projection: BraGoalProjection): VizTone {\n if (status === 'ACHIEVED') return 'success';\n switch (projection) {\n case 'AHEAD':\n case 'ON_TRACK':\n return 'brand';\n case 'BEHIND':\n return 'warning';\n case 'AT_RISK':\n default:\n return 'error';\n }\n}\n\n/**\n * A deterministic contribution trajectory from today to the target date, computed\n * purely from wired fields: starting funded balance + monthly contribution × month.\n * No randomness, no fabricated series — just the arithmetic funding path the user\n * has configured. Returns [] when there is nothing meaningful to chart.\n */\nfunction buildProjectionSeries(\n funded: number,\n monthly: number,\n targetIso?: string | null\n): AreaDatum[] {\n if (!targetIso) return [];\n const target = new Date(targetIso);\n if (Number.isNaN(target.getTime())) return [];\n const now = new Date();\n const totalMonths =\n (target.getFullYear() - now.getFullYear()) * 12 + (target.getMonth() - now.getMonth());\n if (totalMonths <= 0) return [];\n const steps = Math.min(Math.max(totalMonths, 2), 12);\n const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: '2-digit' });\n const points: AreaDatum[] = [];\n for (let i = 0; i <= steps; i += 1) {\n const m = Math.round((totalMonths / steps) * i);\n const at = new Date(now.getFullYear(), now.getMonth() + m, 1);\n points.push({ x: fmt.format(at), y: Math.round(funded + monthly * m) });\n }\n return points;\n}\n\n/** yyyy-mm-dd for a date input, guarded against absent/invalid ISO strings. */\nfunction toDateInput(iso?: string | null): string {\n if (!iso) return '';\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n return d.toISOString().slice(0, 10);\n}\n\ninterface GoalFormState {\n name: string;\n type: BraGoalType;\n status: BraGoalStatus;\n targetAmount: string;\n targetDate: string;\n monthlyContribution: string;\n priority: string;\n currency: string;\n householdId: string;\n notes: string;\n}\n\nfunction emptyForm(): GoalFormState {\n return {\n name: '',\n type: 'CUSTOM',\n status: 'ACTIVE',\n targetAmount: '',\n targetDate: '',\n monthlyContribution: '',\n priority: '1',\n currency: 'USD',\n householdId: '',\n notes: '',\n };\n}\n\nfunction formFromGoal(goal: BraGoal): GoalFormState {\n return {\n name: goal.name,\n type: goal.type,\n status: goal.status,\n targetAmount: String(goal.targetAmount),\n targetDate: toDateInput(goal.targetDate),\n monthlyContribution: String(goal.monthlyContribution),\n priority: String(goal.priority),\n currency: goal.currency,\n householdId: goal.householdId ?? '',\n notes: goal.notes ?? '',\n };\n}\n\nconst HOUSEHOLD_NONE = '__none__';\n\nexport function GoalsPage() {\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.goals.viewed');\n\n const {\n items: goals,\n hasMore,\n loadMore,\n isFetchingNextPage,\n isLoading,\n isError,\n refetch,\n } = usePagedGoals();\n const { data: households } = useHouseholds();\n\n const createGoal = useCreateGoal();\n const updateGoal = useUpdateGoal();\n const archiveGoal = useArchiveGoal();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [editing, setEditing] = useState<BraGoal | null>(null);\n const [detailId, setDetailId] = useState<string | null>(null);\n const [archiving, setArchiving] = useState<BraGoal | null>(null);\n const [form, setForm] = useState<GoalFormState>(emptyForm);\n\n const setField = <K extends keyof GoalFormState>(key: K, value: GoalFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const totals = useMemo(() => {\n const totalTarget = goals.reduce((s, g) => s + g.targetAmount, 0);\n const totalMonthly = goals.reduce((s, g) => s + g.monthlyContribution, 0);\n const atRisk = goals.filter(\n (g) => g.projection === 'AT_RISK' || g.projection === 'BEHIND'\n ).length;\n return { totalTarget, totalMonthly, atRisk };\n }, [goals]);\n\n const currency = goals[0]?.currency ?? 'USD';\n\n const openCreate = () => {\n setForm(emptyForm());\n setCreateOpen(true);\n };\n\n const openEdit = (goal: BraGoal) => {\n setForm(formFromGoal(goal));\n setEditing(goal);\n };\n\n const formValid =\n form.name.trim().length > 0 && Number(form.targetAmount) > 0 && form.targetDate.length > 0;\n\n const handleCreate = () => {\n if (!formValid) return;\n const input: BraCreateGoalInput = {\n name: form.name.trim(),\n type: form.type,\n targetAmount: Number(form.targetAmount),\n targetDate: new Date(form.targetDate).toISOString(),\n monthlyContribution: Number(form.monthlyContribution) || 0,\n priority: Number(form.priority) || 1,\n currency: form.currency.trim() || 'USD',\n notes: form.notes.trim() || null,\n tags: [],\n ...(form.householdId ? { householdId: form.householdId } : {}),\n };\n createGoal.mutate(input, {\n onSuccess: () => {\n hapticSuccess();\n void showToast(translate('brainyrich.goals.created', 'Goal created'));\n setCreateOpen(false);\n },\n });\n };\n\n const handleUpdate = () => {\n if (!editing || !formValid) return;\n const input: BraUpdateGoalInput = {\n name: form.name.trim(),\n type: form.type,\n status: form.status,\n targetAmount: Number(form.targetAmount),\n targetDate: new Date(form.targetDate).toISOString(),\n monthlyContribution: Number(form.monthlyContribution) || 0,\n priority: Number(form.priority) || 1,\n currency: form.currency.trim() || 'USD',\n notes: form.notes.trim() || null,\n // Legacy `tags` scalar preserved as-is; the canonical tag surface is <TagField>.\n tags: editing.tags,\n };\n updateGoal.mutate(\n { id: editing.id, input },\n {\n onSuccess: () => {\n hapticSuccess();\n void showToast(translate('brainyrich.goals.saved', 'Goal saved'));\n setEditing(null);\n },\n }\n );\n };\n\n const body = () => {\n if (isLoading) return <LoadingState rows={4} />;\n if (isError)\n return (\n <ErrorState\n title={translate('brainyrich.goals.error.title', 'Could not load goals')}\n description={translate(\n 'brainyrich.goals.error.description',\n 'We could not reach the goals service. Please try again.'\n )}\n onRetry={() => refetch()}\n />\n );\n if (goals.length === 0)\n return (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.goals.empty.title', 'No financial goals yet')}\n description={translate(\n 'brainyrich.goals.empty.description',\n 'Create your first goal to start tracking progress toward a milestone.'\n )}\n action={\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.createGoal', 'New goal')}\n </Button>\n }\n />\n );\n\n return (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <FadeIn index={0}>\n <StatTile\n glow\n icon={<Target className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.activeGoals', 'Goals')}\n value={String(goals.length)}\n />\n </FadeIn>\n <FadeIn index={1}>\n <StatTile\n icon={<PiggyBank className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.totalTarget', 'Total target')}\n value={formatMoney(totals.totalTarget, currency)}\n />\n </FadeIn>\n <FadeIn index={2}>\n <StatTile\n icon={<Coins className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.monthly', 'Monthly contributions')}\n value={formatMoney(totals.totalMonthly, currency)}\n />\n </FadeIn>\n <FadeIn index={3}>\n <StatTile\n icon={<AlertTriangle className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.atRisk', 'Needs attention')}\n value={String(totals.atRisk)}\n className={totals.atRisk > 0 ? 'ring-1 ring-status-error-text/30' : undefined}\n />\n </FadeIn>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {goals.map((g, i) => {\n const proj = projectionMeta(g.projection);\n const ProjIcon = proj.icon;\n const tone = goalTone(g.status, g.projection);\n const pct = fundedPercent(g);\n const achieved = g.status === 'ACHIEVED';\n return (\n <FadeIn key={g.id} index={i}>\n <Card\n className={`group flex h-full flex-col transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))] ${\n achieved ? 'ring-1 ring-status-success-text/30' : ''\n }`}\n >\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Target\n className=\"size-4 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n <span className=\"truncate\">{g.name}</span>\n </CardTitle>\n <CardDescription className=\"mt-1 flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\">{humanize(g.type)}</Badge>\n <Badge variant={statusBadgeVariant(g.status)}>{humanize(g.status)}</Badge>\n </CardDescription>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={translate('brainyrich.goals.actions.menu', 'Goal actions')}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onSelect={() => setDetailId(g.id)}>\n <Link2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.manageFunding', 'Manage funding')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => openEdit(g)}>\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.editGoal', 'Edit goal')}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"text-status-error-text focus:text-status-error-text\"\n onSelect={() => setArchiving(g)}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.archive', 'Archive goal')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"flex flex-1 flex-col gap-4\">\n <div className=\"flex items-center gap-4\">\n <ProgressRing\n value={pct}\n tone={tone}\n size={92}\n strokeWidth={9}\n label={translate('brainyrich.goals.card.funded', 'funded')}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.target', 'Target amount')}\n </p>\n <p className=\"truncate text-2xl font-semibold text-text-primary\">\n {formatMoney(g.targetAmount, g.currency)}\n </p>\n <span\n className={`mt-1 inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium ${proj.tone}`}\n >\n <ProjIcon className=\"size-3.5\" aria-hidden=\"true\" />\n {humanize(g.projection)}\n </span>\n </div>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-3 rounded-lg bg-bg-sunken p-3 text-sm\">\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.targetDate', 'Target date')}\n </dt>\n <dd className=\"flex items-center gap-1 font-medium text-text-primary\">\n <CalendarClock\n className=\"size-3.5 text-text-secondary\"\n aria-hidden=\"true\"\n />\n {formatDate(g.targetDate)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.monthly', 'Monthly')}\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatMoney(g.monthlyContribution, g.currency)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.priority', 'Priority')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{g.priority}</dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.fundings', 'Funding links')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{g.fundings?.length ?? 0}</dd>\n </div>\n </dl>\n\n <div className=\"mt-auto\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full\"\n onClick={() => setDetailId(g.id)}\n >\n {translate(\n 'brainyrich.goals.actions.viewDetails',\n 'View details & funding'\n )}\n </Button>\n </div>\n </CardContent>\n </Card>\n </FadeIn>\n );\n })}\n </div>\n\n <LoadMore\n hasMore={hasMore}\n loading={isFetchingNextPage}\n onClick={loadMore}\n label={translate('brainyrich.goals.actions.loadMore', 'Load more goals')}\n loadingLabel={translate('brainyrich.goals.actions.loadingMore', 'Loading…')}\n />\n </>\n );\n };\n\n return (\n <div data-tour=\"brainyrich-page-goals\" className=\"contents\">\n <SectionShell\n title={translate('brainyrich.goals.title', 'Financial Goals')}\n description={translate(\n 'brainyrich.goals.description',\n 'Track progress toward your wealth milestones and life objectives'\n )}\n actionLabel={translate('brainyrich.goals.actions.createGoal', 'New goal')}\n onAction={openCreate}\n >\n {body()}\n </SectionShell>\n\n <GoalFormDialog\n open={createOpen}\n mode=\"create\"\n form={form}\n setField={setField}\n households={households.map((h) => ({ id: h.id, name: h.name }))}\n valid={formValid}\n pending={createGoal.isPending}\n onSubmit={handleCreate}\n onOpenChange={(v) => setCreateOpen(v)}\n translate={translate}\n />\n\n <GoalFormDialog\n open={Boolean(editing)}\n mode=\"edit\"\n goalId={editing?.id}\n form={form}\n setField={setField}\n households={households.map((h) => ({ id: h.id, name: h.name }))}\n valid={formValid}\n pending={updateGoal.isPending}\n onSubmit={handleUpdate}\n onOpenChange={(v) => {\n if (!v) setEditing(null);\n }}\n translate={translate}\n />\n\n <GoalDetailSheet goalId={detailId} onClose={() => setDetailId(null)} translate={translate} />\n\n <ConfirmDialog\n open={Boolean(archiving)}\n onOpenChange={(o) => {\n if (!o) setArchiving(null);\n }}\n title={translate('brainyrich.goals.archive.title', 'Archive goal?')}\n description={translate(\n 'brainyrich.goals.archive.description',\n 'This removes “{name}” from your active goals. You can no longer track its progress.',\n { name: archiving?.name ?? '' }\n )}\n confirmLabel={translate('brainyrich.goals.archive.confirm', 'Archive goal')}\n pendingLabel={translate('brainyrich.goals.archive.pending', 'Archiving…')}\n destructive\n pending={archiveGoal.isPending}\n onConfirm={() => {\n if (!archiving) return;\n archiveGoal.mutate(archiving.id, {\n onSuccess: () => {\n hapticSuccess();\n void showToast(\n translate('brainyrich.goals.archived', 'Goal archived', { name: archiving.name })\n );\n setArchiving(null);\n },\n });\n }}\n />\n </div>\n );\n}\n\ntype Translate = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string;\n\ninterface GoalFormDialogProps {\n open: boolean;\n mode: 'create' | 'edit';\n goalId?: string;\n form: GoalFormState;\n setField: <K extends keyof GoalFormState>(key: K, value: GoalFormState[K]) => void;\n households: { id: string; name: string }[];\n valid: boolean;\n pending: boolean;\n onSubmit: () => void;\n onOpenChange: (open: boolean) => void;\n translate: Translate;\n}\n\nfunction GoalFormDialog({\n open,\n mode,\n goalId,\n form,\n setField,\n households,\n valid,\n pending,\n onSubmit,\n onOpenChange,\n translate,\n}: GoalFormDialogProps) {\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[90vh] overflow-y-auto sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {mode === 'create'\n ? translate('brainyrich.goals.form.createTitle', 'New goal')\n : translate('brainyrich.goals.form.editTitle', 'Edit goal')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {translate(\n 'brainyrich.goals.form.subtitle',\n 'Define the milestone, target and contribution plan.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n className=\"space-y-4\"\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit();\n }}\n >\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-name\">{translate('brainyrich.goals.form.name', 'Name')}</Label>\n <Input\n id=\"goal-name\"\n value={form.name}\n onChange={(e) => setField('name', e.target.value)}\n placeholder={translate(\n 'brainyrich.goals.form.namePlaceholder',\n 'e.g. Retirement fund'\n )}\n required\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-type\">{translate('brainyrich.goals.form.type', 'Type')}</Label>\n <Select value={form.type} onValueChange={(v) => setField('type', v as BraGoalType)}>\n <SelectTrigger id=\"goal-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {GOAL_TYPES.map((tpe) => (\n <SelectItem key={tpe} value={tpe}>\n {humanize(tpe)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n {mode === 'edit' ? (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-status\">\n {translate('brainyrich.goals.form.status', 'Status')}\n </Label>\n <Select\n value={form.status}\n onValueChange={(v) => setField('status', v as BraGoalStatus)}\n >\n <SelectTrigger id=\"goal-status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {GOAL_STATUSES.map((st) => (\n <SelectItem key={st} value={st}>\n {humanize(st)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-priority\">\n {translate('brainyrich.goals.form.priority', 'Priority')}\n </Label>\n <Input\n id=\"goal-priority\"\n type=\"number\"\n min={1}\n value={form.priority}\n onChange={(e) => setField('priority', e.target.value)}\n />\n </div>\n )}\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-target\">\n {translate('brainyrich.goals.form.targetAmount', 'Target amount')}\n </Label>\n <Input\n id=\"goal-target\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={form.targetAmount}\n onChange={(e) => setField('targetAmount', e.target.value)}\n required\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-date\">\n {translate('brainyrich.goals.form.targetDate', 'Target date')}\n </Label>\n <Input\n id=\"goal-date\"\n type=\"date\"\n value={form.targetDate}\n onChange={(e) => setField('targetDate', e.target.value)}\n required\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-monthly\">\n {translate('brainyrich.goals.form.monthly', 'Monthly contribution')}\n </Label>\n <Input\n id=\"goal-monthly\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={form.monthlyContribution}\n onChange={(e) => setField('monthlyContribution', e.target.value)}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-currency\">\n {translate('brainyrich.goals.form.currency', 'Currency')}\n </Label>\n <Input\n id=\"goal-currency\"\n value={form.currency}\n onChange={(e) => setField('currency', e.target.value.toUpperCase())}\n maxLength={3}\n />\n </div>\n </div>\n\n {mode === 'edit' ? (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-priority-edit\">\n {translate('brainyrich.goals.form.priority', 'Priority')}\n </Label>\n <Input\n id=\"goal-priority-edit\"\n type=\"number\"\n min={1}\n value={form.priority}\n onChange={(e) => setField('priority', e.target.value)}\n />\n </div>\n ) : null}\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-household\">\n {translate('brainyrich.goals.form.household', 'Household (optional)')}\n </Label>\n <Select\n value={form.householdId || HOUSEHOLD_NONE}\n onValueChange={(v) => setField('householdId', v === HOUSEHOLD_NONE ? '' : v)}\n >\n <SelectTrigger id=\"goal-household\">\n <SelectValue\n placeholder={translate('brainyrich.goals.form.householdNone', 'None')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={HOUSEHOLD_NONE}>\n {translate('brainyrich.goals.form.householdNone', 'None')}\n </SelectItem>\n {households.map((h) => (\n <SelectItem key={h.id} value={h.id}>\n {h.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {mode === 'edit' && goalId ? (\n <TagField\n entityType=\"brainyrich-goal\"\n entityId={goalId}\n label={translate('brainyrich.goals.form.tags', 'Tags')}\n />\n ) : (\n <div className=\"space-y-1.5\">\n <Label>{translate('brainyrich.goals.form.tags', 'Tags')}</Label>\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.goals.form.tagsAfterCreate',\n 'You can add tags after creating the goal.'\n )}\n </p>\n </div>\n )}\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-notes\">{translate('brainyrich.goals.form.notes', 'Notes')}</Label>\n <Textarea\n id=\"goal-notes\"\n value={form.notes}\n onChange={(e) => setField('notes', e.target.value)}\n rows={3}\n />\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={pending}\n >\n {translate('brainyrich.goals.form.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={!valid || pending}>\n {pending\n ? translate('brainyrich.goals.form.saving', 'Saving…')\n : mode === 'create'\n ? translate('brainyrich.goals.form.create', 'Create goal')\n : translate('brainyrich.goals.form.save', 'Save changes')}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\ntype FundingMode = 'PERCENT' | 'FIXED';\n\ninterface GoalDetailSheetProps {\n goalId: string | null;\n onClose: () => void;\n translate: Translate;\n}\n\nfunction GoalDetailSheet({ goalId, onClose, translate }: GoalDetailSheetProps) {\n const { data: goal, isLoading, isError, refetch } = useGoal(goalId ?? undefined);\n const { data: fundings } = useGoalFundings(goalId ?? undefined);\n const { data: accounts } = useAccounts();\n\n const linkFunding = useLinkGoalFunding();\n const unlinkFunding = useUnlinkGoalFunding();\n const recalc = useRecalcGoalProjection();\n\n const [accountId, setAccountId] = useState('');\n const [fundingMode, setFundingMode] = useState<FundingMode>('PERCENT');\n const [fundingValue, setFundingValue] = useState('');\n const [fundedAmount, setFundedAmount] = useState('');\n const [unlinking, setUnlinking] = useState<BraGoalFunding | null>(null);\n\n const fixedFunded = fundings.reduce((s, f) => s + (f.fixedAmount ?? 0), 0);\n const currency = goal?.currency ?? 'USD';\n const fundedPct = goal ? fundedPercent(goal) : 0;\n const tone: VizTone = goal ? goalTone(goal.status, goal.projection) : 'brand';\n const projectionSeries = goal\n ? buildProjectionSeries(fixedFunded, goal.monthlyContribution, goal.targetDate)\n : [];\n\n const accountName = (id: string) => accounts.find((a) => a.id === id)?.name ?? id;\n\n const handleLink = () => {\n if (!goalId || !accountId) return;\n const numeric = Number(fundingValue);\n if (!Number.isFinite(numeric) || numeric <= 0) return;\n linkFunding.mutate(\n {\n goalId,\n accountId,\n ...(fundingMode === 'PERCENT' ? { allocationPct: numeric } : { fixedAmount: numeric }),\n },\n {\n onSuccess: () => {\n setAccountId('');\n setFundingValue('');\n },\n }\n );\n };\n\n const handleRecalc = () => {\n if (!goalId) return;\n const amount = fundedAmount === '' ? fixedFunded : Number(fundedAmount);\n if (!Number.isFinite(amount)) return;\n recalc.mutate({ id: goalId, fundedAmount: amount });\n };\n\n const linkValid = Boolean(accountId) && Number(fundingValue) > 0;\n\n const unlinkingLabel = unlinking\n ? unlinking.fixedAmount != null\n ? formatMoney(unlinking.fixedAmount, currency)\n : accountName(unlinking.accountId)\n : '';\n\n return (\n <>\n <Sheet\n open={Boolean(goalId)}\n onOpenChange={(v) => {\n if (!v) onClose();\n }}\n >\n <SheetContent className=\"flex w-full flex-col gap-0 overflow-y-auto sm:max-w-xl\">\n <SheetHeader>\n <SheetTitle>\n {goal?.name ?? translate('brainyrich.goals.detail.title', 'Goal')}\n </SheetTitle>\n <SheetDescription>\n {translate(\n 'brainyrich.goals.detail.subtitle',\n 'Manage funding links and projection.'\n )}\n </SheetDescription>\n </SheetHeader>\n\n <div className=\"space-y-6 p-4\">\n {isLoading ? (\n <LoadingState rows={3} />\n ) : isError ? (\n <ErrorState\n title={translate('brainyrich.goals.detail.error', 'Could not load goal')}\n onRetry={() => refetch()}\n />\n ) : !goal ? (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.goals.detail.notFound', 'Goal not found')}\n />\n ) : (\n <>\n {/* Hero: funded progress ring + headline */}\n <GlassCard glow className=\"flex items-center gap-5\">\n <ProgressRing\n value={fundedPct}\n tone={tone}\n size={116}\n strokeWidth={11}\n label={translate('brainyrich.goals.detail.funded', 'funded')}\n />\n <div className=\"min-w-0 flex-1 space-y-1\">\n <Badge variant={statusBadgeVariant(goal.projection)}>\n {humanize(goal.projection)}\n </Badge>\n <p className=\"text-2xl font-semibold text-text-primary\">\n {formatMoney(fixedFunded, currency)}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.detail.ofTarget', 'of {target} target', {\n target: formatCompact(goal.targetAmount, currency),\n })}\n </p>\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <StatTile\n icon={<Target className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.target', 'Target')}\n value={formatMoney(goal.targetAmount, currency)}\n />\n <StatTile\n icon={<Wallet className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.funded', 'Funded (fixed)')}\n value={formatMoney(fixedFunded, currency)}\n />\n <StatTile\n icon={<Coins className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.monthly', 'Monthly')}\n value={formatMoney(goal.monthlyContribution, currency)}\n />\n <StatTile\n icon={<CalendarClock className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.targetDate', 'Target date')}\n value={formatDate(goal.targetDate)}\n />\n </div>\n\n {/* Projection trajectory toward the target line */}\n {projectionSeries.length >= 2 ? (\n <section className=\"space-y-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex items-center gap-2\">\n <LineChart className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate(\n 'brainyrich.goals.detail.projectionChart',\n 'Contribution projection'\n )}\n </h3>\n </div>\n <MiniAreaChart\n data={projectionSeries}\n target={goal.targetAmount}\n tone={tone}\n height={180}\n valueFormatter={(v) => formatCompact(v, currency)}\n />\n <p className=\"text-xs text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.projectionHint',\n 'Starting balance plus {monthly}/mo through {date}.',\n {\n monthly: formatMoney(goal.monthlyContribution, currency),\n date: formatDate(goal.targetDate),\n }\n )}\n </p>\n </section>\n ) : null}\n\n {/* Funding sources table */}\n <section className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.goals.detail.fundingLinks', 'Funding sources')}\n </h3>\n {fundings.length === 0 ? (\n <p className=\"rounded-lg border border-dashed border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.noFundings',\n 'No accounts linked to fund this goal yet.'\n )}\n </p>\n ) : (\n <div className=\"overflow-x-auto rounded-lg border border-border-subtle\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>\n {translate('brainyrich.goals.detail.account', 'Account')}\n </TableHead>\n <TableHead className=\"text-right\">\n {translate('brainyrich.goals.detail.allocation', 'Allocation')}\n </TableHead>\n <TableHead className=\"text-right\">\n {translate('brainyrich.goals.detail.fixedAmount', 'Fixed amount')}\n </TableHead>\n <TableHead className=\"w-10\" />\n </TableRow>\n </TableHeader>\n <TableBody>\n {fundings.map((f) => (\n <TableRow key={f.id}>\n <TableCell className=\"font-medium text-text-primary\">\n {accountName(f.accountId)}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {f.fixedAmount == null ? formatPct(f.allocationPct) : '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {f.fixedAmount != null ? formatMoney(f.fixedAmount, currency) : '—'}\n </TableCell>\n <TableCell className=\"text-right\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={translate(\n 'brainyrich.goals.detail.unlink',\n 'Unlink funding'\n )}\n onClick={() => setUnlinking(f)}\n >\n <Unlink className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n </section>\n\n {/* Link a new funding */}\n <section className=\"space-y-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.goals.detail.linkTitle', 'Link an account')}\n </h3>\n {accounts.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.noAccounts',\n 'No accounts available to link.'\n )}\n </p>\n ) : (\n <>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"funding-account\">\n {translate('brainyrich.goals.detail.account', 'Account')}\n </Label>\n <Select value={accountId} onValueChange={setAccountId}>\n <SelectTrigger id=\"funding-account\">\n <SelectValue\n placeholder={translate(\n 'brainyrich.goals.detail.selectAccount',\n 'Select account'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {accounts.map((a) => (\n <SelectItem key={a.id} value={a.id}>\n {a.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"funding-mode\">\n {translate('brainyrich.goals.detail.mode', 'Method')}\n </Label>\n <Select\n value={fundingMode}\n onValueChange={(v) => setFundingMode(v as FundingMode)}\n >\n <SelectTrigger id=\"funding-mode\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"PERCENT\">\n {translate('brainyrich.goals.detail.percent', 'Percentage')}\n </SelectItem>\n <SelectItem value=\"FIXED\">\n {translate('brainyrich.goals.detail.fixed', 'Fixed amount')}\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"funding-value\">\n {fundingMode === 'PERCENT'\n ? translate('brainyrich.goals.detail.pct', 'Percent')\n : translate('brainyrich.goals.detail.amount', 'Amount')}\n </Label>\n <Input\n id=\"funding-value\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={fundingValue}\n onChange={(e) => setFundingValue(e.target.value)}\n />\n </div>\n </div>\n <Button\n size=\"sm\"\n className=\"w-full\"\n disabled={!linkValid || linkFunding.isPending}\n onClick={handleLink}\n >\n <Link2 className=\"size-4\" aria-hidden=\"true\" />\n {linkFunding.isPending\n ? translate('brainyrich.goals.detail.linking', 'Linking…')\n : translate('brainyrich.goals.detail.link', 'Link funding')}\n </Button>\n </>\n )}\n </section>\n\n {/* Tags */}\n <Card>\n <CardContent className=\"p-4\">\n <TagField\n entityType=\"brainyrich-goal\"\n entityId={goal.id}\n label={translate('brainyrich.goals.detail.tags', 'Tags')}\n />\n </CardContent>\n </Card>\n\n {/* Recalc projection */}\n <section className=\"space-y-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.goals.detail.recalcTitle', 'Recalculate projection')}\n </h3>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"recalc-funded\">\n {translate('brainyrich.goals.detail.fundedAmount', 'Funded amount')}\n </Label>\n <Input\n id=\"recalc-funded\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={fundedAmount}\n placeholder={String(fixedFunded)}\n onChange={(e) => setFundedAmount(e.target.value)}\n />\n <p className=\"text-xs text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.recalcHint',\n 'Defaults to the sum of fixed fundings when left blank.'\n )}\n </p>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n disabled={recalc.isPending}\n onClick={handleRecalc}\n >\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n {recalc.isPending\n ? translate('brainyrich.goals.detail.recalculating', 'Recalculating…')\n : translate('brainyrich.goals.detail.recalc', 'Recalculate')}\n </Button>\n </section>\n </>\n )}\n </div>\n </SheetContent>\n </Sheet>\n\n <ConfirmDialog\n open={Boolean(unlinking)}\n onOpenChange={(o) => {\n if (!o) setUnlinking(null);\n }}\n title={translate('brainyrich.goals.detail.unlinkTitle', 'Unlink funding?')}\n description={translate(\n 'brainyrich.goals.detail.unlinkConfirm',\n 'This removes the “{name}” funding link from this goal.',\n { name: unlinkingLabel }\n )}\n confirmLabel={translate('brainyrich.goals.detail.unlink', 'Unlink funding')}\n pendingLabel={translate('brainyrich.goals.detail.unlinking', 'Unlinking…')}\n destructive\n pending={unlinkFunding.isPending}\n onConfirm={() => {\n if (!unlinking) return;\n unlinkFunding.mutate(unlinking.id, { onSuccess: () => setUnlinking(null) });\n }}\n />\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA2GA,IAAM,KAA4B;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;AACF,GAEM,KAAiC;CAAC;CAAU;CAAY;CAAW;AAAW;AAOpF,SAAS,GAAe,GAA+C;CACrE,QAAQ,GAAR;EACE,KAAK;EACL,KAAK,YACH,OAAO;GAAE,MAAM;GAAY,MAAM;EAA2B;EAC9D,KAAK,UACH,OAAO;GAAE,MAAM;GAAc,MAAM;EAA2B;EAEhE,SACE,OAAO;GAAE,MAAM;GAAe,MAAM;EAAyB;CACjE;AACF;AAEA,SAAS,EAAS,GAAuB;CACvC,OAAO,EACJ,YAAY,EACZ,MAAM,GAAG,EACT,KAAK,MAAS,EAAK,OAAO,CAAC,EAAE,YAAY,IAAI,EAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,GAAG;AACb;AAGA,SAAS,GAAgB,GAAyC;CAGhE,QAAQ,EAAK,YAAY,CAAC,GAAG,QAAQ,GAAG,MAAM,KAAK,EAAE,eAAe,IAAI,CAAC;AAC3E;AAOA,SAAS,GAAc,GAAqE;CAG1F,OAFI,EAAK,WAAW,aAAmB,MACjC,EAAK,eAAe,IACnB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAM,GAAgB,CAAI,IAAI,EAAK,eAAgB,GAAG,CAAC,IAD9C;AAEvC;AAGA,SAAS,GAAS,GAAuB,GAAwC;CAC/E,IAAI,MAAW,YAAY,OAAO;CAClC,QAAQ,GAAR;EACE,KAAK;EACL,KAAK,YACH,OAAO;EACT,KAAK,UACH,OAAO;EAET,SACE,OAAO;CACX;AACF;AAQA,SAAS,GACP,GACA,GACA,GACa;CACb,IAAI,CAAC,GAAW,OAAO,CAAC;CACxB,IAAM,IAAS,IAAI,KAAK,CAAS;CACjC,IAAI,OAAO,MAAM,EAAO,QAAQ,CAAC,GAAG,OAAO,CAAC;CAC5C,IAAM,oBAAM,IAAI,KAAK,GACf,KACH,EAAO,YAAY,IAAI,EAAI,YAAY,KAAK,MAAM,EAAO,SAAS,IAAI,EAAI,SAAS;CACtF,IAAI,KAAe,GAAG,OAAO,CAAC;CAC9B,IAAM,IAAQ,KAAK,IAAI,KAAK,IAAI,GAAa,CAAC,GAAG,EAAE,GAC7C,IAAM,IAAI,KAAK,eAAe,SAAS;EAAE,OAAO;EAAS,MAAM;CAAU,CAAC,GAC1E,IAAsB,CAAC;CAC7B,KAAK,IAAI,IAAI,GAAG,KAAK,GAAO,KAAK,GAAG;EAClC,IAAM,IAAI,KAAK,MAAO,IAAc,IAAS,CAAC,GACxC,IAAK,IAAI,KAAK,EAAI,YAAY,GAAG,EAAI,SAAS,IAAI,GAAG,CAAC;EAC5D,EAAO,KAAK;GAAE,GAAG,EAAI,OAAO,CAAE;GAAG,GAAG,KAAK,MAAM,IAAS,IAAU,CAAC;EAAE,CAAC;CACxE;CACA,OAAO;AACT;AAGA,SAAS,GAAY,GAA6B;CAChD,IAAI,CAAC,GAAK,OAAO;CACjB,IAAM,IAAI,IAAI,KAAK,CAAG;CAEtB,OADI,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAU,KAC/B,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACpC;AAeA,SAAS,KAA2B;CAClC,OAAO;EACL,MAAM;EACN,MAAM;EACN,QAAQ;EACR,cAAc;EACd,YAAY;EACZ,qBAAqB;EACrB,UAAU;EACV,UAAU;EACV,aAAa;EACb,OAAO;CACT;AACF;AAEA,SAAS,GAAa,GAA8B;CAClD,OAAO;EACL,MAAM,EAAK;EACX,MAAM,EAAK;EACX,QAAQ,EAAK;EACb,cAAc,OAAO,EAAK,YAAY;EACtC,YAAY,GAAY,EAAK,UAAU;EACvC,qBAAqB,OAAO,EAAK,mBAAmB;EACpD,UAAU,OAAO,EAAK,QAAQ;EAC9B,UAAU,EAAK;EACf,aAAa,EAAK,eAAe;EACjC,OAAO,EAAK,SAAS;CACvB;AACF;AAEA,IAAM,KAAiB;AAEvB,SAAgB,KAAY;CAC1B,IAAM,EAAE,MAAM,EAAQ,GAChB,KAAa,GAAa,GAAkB,MAChD,EAAc,GAAG,GAAK,GAAU,CAAM;CAExC,EAA2B,yBAAyB;CAEpD,IAAM,EACJ,OAAO,GACP,YACA,aACA,uBACA,eACA,aACA,gBACE,EAAc,GACZ,EAAE,MAAM,MAAe,EAAc,GAErC,IAAa,EAAc,GAC3B,KAAa,GAAc,GAC3B,IAAc,EAAe,GAE7B,CAAC,IAAY,KAAiB,EAAS,EAAK,GAC5C,CAAC,GAAS,KAAc,EAAyB,IAAI,GACrD,CAAC,GAAU,KAAe,EAAwB,IAAI,GACtD,CAAC,GAAW,KAAgB,EAAyB,IAAI,GACzD,CAAC,GAAM,KAAW,EAAwB,EAAS,GAEnD,MAA2C,GAAQ,MACvD,GAAS,OAAU;EAAE,GAAG;GAAO,IAAM;CAAM,EAAE,GAEzC,IAAS,SAMN;EAAE,aALW,EAAM,QAAQ,GAAG,MAAM,IAAI,EAAE,cAAc,CAKtD;EAAa,cAJD,EAAM,QAAQ,GAAG,MAAM,IAAI,EAAE,qBAAqB,CAIjD;EAAc,QAHrB,EAAM,QAClB,MAAM,EAAE,eAAe,aAAa,EAAE,eAAe,QACxD,EAAE;CACyC,IAC1C,CAAC,CAAK,CAAC,GAEJ,IAAW,EAAM,IAAI,YAAY,OAEjC,UAAmB;EAEvB,AADA,EAAQ,GAAU,CAAC,GACnB,EAAc,EAAI;CACpB,GAEM,KAAY,MAAkB;EAElC,AADA,EAAQ,GAAa,CAAI,CAAC,GAC1B,EAAW,CAAI;CACjB,GAEM,IACJ,EAAK,KAAK,KAAK,EAAE,SAAS,KAAK,OAAO,EAAK,YAAY,IAAI,KAAK,EAAK,WAAW,SAAS;CA6Q3F,OACE,kBAAC,OAAD;EAAK,aAAU;EAAwB,WAAU;YAAjD;GACE,kBAAC,GAAD;IACE,OAAO,EAAU,0BAA0B,iBAAiB;IAC5D,aAAa,EACX,gCACA,kEACF;IACA,aAAa,EAAU,uCAAuC,UAAU;IACxE,UAAU;cAjOV,KAAkB,kBAAC,IAAD,EAAc,MAAM,EAAI,CAAA,IAC1C,KAEA,kBAAC,IAAD;KACE,OAAO,EAAU,gCAAgC,sBAAsB;KACvE,aAAa,EACX,sCACA,yDACF;KACA,eAAe,GAAQ;IACxB,CAAA,IAED,EAAM,WAAW,IAEjB,kBAAC,IAAD;KACE,MAAM,kBAAC,GAAD;MAAQ,WAAU;MAAS,eAAY;KAAQ,CAAA;KACrD,OAAO,EAAU,gCAAgC,wBAAwB;KACzE,aAAa,EACX,sCACA,uEACF;KACA,QACE,kBAAC,GAAD;MAAQ,MAAK;MAAK,SAAS;gBAA3B,CACE,kBAAC,GAAD;OAAM,WAAU;OAAS,eAAY;MAAQ,CAAA,GAC5C,EAAU,uCAAuC,UAAU,CACtD;;IAEX,CAAA,IAIH,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QAAQ,OAAO;kBACb,kBAAC,GAAD;SACE,MAAA;SACA,MAAM,kBAAC,GAAD;UAAQ,WAAU;UAAS,eAAY;SAAQ,CAAA;SACrD,OAAO,EAAU,wCAAwC,OAAO;SAChE,OAAO,OAAO,EAAM,MAAM;QAC3B,CAAA;OACK,CAAA;OACR,kBAAC,GAAD;QAAQ,OAAO;kBACb,kBAAC,GAAD;SACE,MAAM,kBAAC,IAAD;UAAW,WAAU;UAAS,eAAY;SAAQ,CAAA;SACxD,OAAO,EAAU,wCAAwC,cAAc;SACvE,OAAO,EAAY,EAAO,aAAa,CAAQ;QAChD,CAAA;OACK,CAAA;OACR,kBAAC,GAAD;QAAQ,OAAO;kBACb,kBAAC,GAAD;SACE,MAAM,kBAAC,IAAD;UAAO,WAAU;UAAS,eAAY;SAAQ,CAAA;SACpD,OAAO,EAAU,oCAAoC,uBAAuB;SAC5E,OAAO,EAAY,EAAO,cAAc,CAAQ;QACjD,CAAA;OACK,CAAA;OACR,kBAAC,GAAD;QAAQ,OAAO;kBACb,kBAAC,GAAD;SACE,MAAM,kBAAC,GAAD;UAAe,WAAU;UAAS,eAAY;SAAQ,CAAA;SAC5D,OAAO,EAAU,mCAAmC,iBAAiB;SACrE,OAAO,OAAO,EAAO,MAAM;SAC3B,WAAW,EAAO,SAAS,IAAI,qCAAqC,KAAA;QACrE,CAAA;OACK,CAAA;MACL;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAM,KAAK,GAAG,MAAM;OACnB,IAAM,IAAO,GAAe,EAAE,UAAU,GAClC,IAAW,EAAK,MAChB,IAAO,GAAS,EAAE,QAAQ,EAAE,UAAU,GACtC,IAAM,GAAc,CAAC;OAE3B,OACE,kBAAC,GAAD;QAAmB,OAAO;kBACxB,kBAAC,IAAD;SACE,WAAW,6HAJA,EAAE,WAAW,aAKX,uCAAuC;mBAFtD,CAKE,kBAAC,GAAD;UAAY,WAAU;oBACpB,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,GAAD;aAAW,WAAU;uBAArB,CACE,kBAAC,GAAD;cACE,WAAU;cACV,eAAY;aACb,CAAA,GACD,kBAAC,QAAD;cAAM,WAAU;wBAAY,EAAE;aAAW,CAAA,CAChC;gBACX,kBAAC,GAAD;aAAiB,WAAU;uBAA3B,CACE,kBAAC,GAAD;cAAO,SAAQ;wBAAW,EAAS,EAAE,IAAI;aAAS,CAAA,GAClD,kBAAC,GAAD;cAAO,SAAS,GAAmB,EAAE,MAAM;wBAAI,EAAS,EAAE,MAAM;aAAS,CAAA,CAC1D;cACd;eACL,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD;YAAqB,SAAA;sBACnB,kBAAC,GAAD;aACE,SAAQ;aACR,MAAK;aACL,cAAY,EAAU,iCAAiC,cAAc;uBAErE,kBAAC,GAAD;cAAgB,WAAU;cAAS,eAAY;aAAQ,CAAA;YACjD,CAAA;WACW,CAAA,GACrB,kBAAC,IAAD;YAAqB,OAAM;sBAA3B;aACE,kBAAC,GAAD;cAAkB,gBAAgB,EAAY,EAAE,EAAE;wBAAlD,CACE,kBAAC,IAAD;eAAO,WAAU;eAAS,eAAY;cAAQ,CAAA,GAC7C,EAAU,0CAA0C,gBAAgB,CACrD;;aAClB,kBAAC,GAAD;cAAkB,gBAAgB,EAAS,CAAC;wBAA5C,CACE,kBAAC,IAAD;eAAW,WAAU;eAAS,eAAY;cAAQ,CAAA,GACjD,EAAU,qCAAqC,WAAW,CAC3C;;aAClB,kBAAC,IAAD,CAAwB,CAAA;aACxB,kBAAC,GAAD;cACE,WAAU;cACV,gBAAgB,EAAa,CAAC;wBAFhC,CAIE,kBAAC,IAAD;eAAQ,WAAU;eAAS,eAAY;cAAQ,CAAA,GAC9C,EAAU,oCAAoC,cAAc,CAC7C;;YACC;aACT,EAAA,CAAA,CACX;;SACK,CAAA,GACZ,kBAAC,IAAD;UAAa,WAAU;oBAAvB;WACE,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,IAAD;aACE,OAAO;aACD;aACN,MAAM;aACN,aAAa;aACb,OAAO,EAAU,gCAAgC,QAAQ;YAC1D,CAAA,GACD,kBAAC,OAAD;aAAK,WAAU;uBAAf;cACE,kBAAC,KAAD;eAAG,WAAU;yBACV,EAAU,gCAAgC,eAAe;cACzD,CAAA;cACH,kBAAC,KAAD;eAAG,WAAU;yBACV,EAAY,EAAE,cAAc,EAAE,QAAQ;cACtC,CAAA;cACH,kBAAC,QAAD;eACE,WAAW,iGAAiG,EAAK;yBADnH,CAGE,kBAAC,GAAD;gBAAU,WAAU;gBAAW,eAAY;eAAQ,CAAA,GAClD,EAAS,EAAE,UAAU,CAClB;;aACH;cACF;;WAEL,kBAAC,MAAD;YAAI,WAAU;sBAAd;aACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;cAAI,WAAU;wBACX,EAAU,oCAAoC,aAAa;aAC1D,CAAA,GACJ,kBAAC,MAAD;cAAI,WAAU;wBAAd,CACE,kBAAC,IAAD;eACE,WAAU;eACV,eAAY;cACb,CAAA,GACA,GAAW,EAAE,UAAU,CACtB;eACD,EAAA,CAAA;aACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;cAAI,WAAU;wBACX,EAAU,iCAAiC,SAAS;aACnD,CAAA,GACJ,kBAAC,MAAD;cAAI,WAAU;wBACX,EAAY,EAAE,qBAAqB,EAAE,QAAQ;aAC5C,CAAA,CACD,EAAA,CAAA;aACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;cAAI,WAAU;wBACX,EAAU,kCAAkC,UAAU;aACrD,CAAA,GACJ,kBAAC,MAAD;cAAI,WAAU;wBAAiC,EAAE;aAAa,CAAA,CAC3D,EAAA,CAAA;aACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;cAAI,WAAU;wBACX,EAAU,kCAAkC,eAAe;aAC1D,CAAA,GACJ,kBAAC,MAAD;cAAI,WAAU;wBAAiC,EAAE,UAAU,UAAU;aAAM,CAAA,CACxE,EAAA,CAAA;YACH;;WAEJ,kBAAC,OAAD;YAAK,WAAU;sBACb,kBAAC,GAAD;aACE,SAAQ;aACR,MAAK;aACL,WAAU;aACV,eAAe,EAAY,EAAE,EAAE;uBAE9B,EACC,wCACA,wBACF;YACM,CAAA;WACL,CAAA;UACM;WACT;;OACA,GA/HK,EAAE,EA+HP;MAEZ,CAAC;KACE,CAAA;KAEL,kBAAC,IAAD;MACW;MACT,SAAS;MACT,SAAS;MACT,OAAO,EAAU,qCAAqC,iBAAiB;MACvE,cAAc,EAAU,wCAAwC,UAAU;KAC3E,CAAA;IACD,EAAA,CAAA;GAgBY,CAAA;GAEd,kBAAC,IAAD;IACE,MAAM;IACN,MAAK;IACC;IACI;IACV,YAAY,EAAW,KAAK,OAAO;KAAE,IAAI,EAAE;KAAI,MAAM,EAAE;IAAK,EAAE;IAC9D,OAAO;IACP,SAAS,EAAW;IACpB,gBAjSqB;KACzB,IAAI,CAAC,GAAW;KAChB,IAAM,IAA4B;MAChC,MAAM,EAAK,KAAK,KAAK;MACrB,MAAM,EAAK;MACX,cAAc,OAAO,EAAK,YAAY;MACtC,YAAY,IAAI,KAAK,EAAK,UAAU,EAAE,YAAY;MAClD,qBAAqB,OAAO,EAAK,mBAAmB,KAAK;MACzD,UAAU,OAAO,EAAK,QAAQ,KAAK;MACnC,UAAU,EAAK,SAAS,KAAK,KAAK;MAClC,OAAO,EAAK,MAAM,KAAK,KAAK;MAC5B,MAAM,CAAC;MACP,GAAI,EAAK,cAAc,EAAE,aAAa,EAAK,YAAY,IAAI,CAAC;KAC9D;KACA,EAAW,OAAO,GAAO,EACvB,iBAAiB;MAGf,AAFA,EAAc,GACd,EAAe,EAAU,4BAA4B,cAAc,CAAC,GACpE,EAAc,EAAK;KACrB,EACF,CAAC;IACH;IA6QM,eAAe,MAAM,EAAc,CAAC;IACzB;GACZ,CAAA;GAED,kBAAC,IAAD;IACE,MAAM,EAAQ;IACd,MAAK;IACL,QAAQ,GAAS;IACX;IACI;IACV,YAAY,EAAW,KAAK,OAAO;KAAE,IAAI,EAAE;KAAI,MAAM,EAAE;IAAK,EAAE;IAC9D,OAAO;IACP,SAAS,GAAW;IACpB,gBAxRqB;KACzB,IAAI,CAAC,KAAW,CAAC,GAAW;KAC5B,IAAM,IAA4B;MAChC,MAAM,EAAK,KAAK,KAAK;MACrB,MAAM,EAAK;MACX,QAAQ,EAAK;MACb,cAAc,OAAO,EAAK,YAAY;MACtC,YAAY,IAAI,KAAK,EAAK,UAAU,EAAE,YAAY;MAClD,qBAAqB,OAAO,EAAK,mBAAmB,KAAK;MACzD,UAAU,OAAO,EAAK,QAAQ,KAAK;MACnC,UAAU,EAAK,SAAS,KAAK,KAAK;MAClC,OAAO,EAAK,MAAM,KAAK,KAAK;MAE5B,MAAM,EAAQ;KAChB;KACA,GAAW,OACT;MAAE,IAAI,EAAQ;MAAI;KAAM,GACxB,EACE,iBAAiB;MAGf,AAFA,EAAc,GACd,EAAe,EAAU,0BAA0B,YAAY,CAAC,GAChE,EAAW,IAAI;KACjB,EACF,CACF;IACF;IAgQM,eAAe,MAAM;KACnB,AAAK,KAAG,EAAW,IAAI;IACzB;IACW;GACZ,CAAA;GAED,kBAAC,IAAD;IAAiB,QAAQ;IAAU,eAAe,EAAY,IAAI;IAAc;GAAY,CAAA;GAE5F,kBAAC,IAAD;IACE,MAAM,EAAQ;IACd,eAAe,MAAM;KACnB,AAAK,KAAG,EAAa,IAAI;IAC3B;IACA,OAAO,EAAU,kCAAkC,eAAe;IAClE,aAAa,EACX,wCACA,uFACA,EAAE,MAAM,GAAW,QAAQ,GAAG,CAChC;IACA,cAAc,EAAU,oCAAoC,cAAc;IAC1E,cAAc,EAAU,oCAAoC,YAAY;IACxE,aAAA;IACA,SAAS,EAAY;IACrB,iBAAiB;KACV,KACL,EAAY,OAAO,EAAU,IAAI,EAC/B,iBAAiB;MAKf,AAJA,EAAc,GACd,EACE,EAAU,6BAA6B,iBAAiB,EAAE,MAAM,EAAU,KAAK,CAAC,CAClF,GACA,EAAa,IAAI;KACnB,EACF,CAAC;IACH;GACD,CAAA;EACE;;AAET;AAsBA,SAAS,GAAe,EACtB,SACA,SACA,WACA,SACA,aACA,eACA,UACA,YACA,aACA,iBACA,gBACsB;CACtB,OACE,kBAAC,GAAD;EAAwB;EAAoB;YAC1C,kBAAC,GAAD;GAAyB,WAAU;aAAnC,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UACG,MAAS,WACN,EAAU,qCAAqC,UAAU,IACzD,EAAU,mCAAmC,WAAW,EACvC,CAAA,GACvB,kBAAC,GAAD,EAAA,UACG,EACC,kCACA,qDACF,EAC2B,CAAA,CACP,EAAA,CAAA,GAExB,kBAAC,QAAD;IACE,WAAU;IACV,WAAW,MAAM;KAEf,AADA,EAAE,eAAe,GACjB,EAAS;IACX;cALF;KAOE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBAAa,EAAU,8BAA8B,MAAM;MAAS,CAAA,GACnF,kBAAC,GAAD;OACE,IAAG;OACH,OAAO,EAAK;OACZ,WAAW,MAAM,EAAS,QAAQ,EAAE,OAAO,KAAK;OAChD,aAAa,EACX,yCACA,sBACF;OACA,UAAA;MACD,CAAA,CACE;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBAAa,EAAU,8BAA8B,MAAM;OAAS,CAAA,GACnF,kBAAC,GAAD;QAAQ,OAAO,EAAK;QAAM,gBAAgB,MAAM,EAAS,QAAQ,CAAgB;kBAAjF,CACE,kBAAC,GAAD;SAAe,IAAG;mBAChB,kBAAC,GAAD,CAAc,CAAA;QACD,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,GAAW,KAAK,MACf,kBAAC,GAAD;SAAsB,OAAO;mBAC1B,EAAS,CAAG;QACH,GAFK,CAEL,CACb,EACY,CAAA,CACT;SACL;UACJ,MAAS,SACR,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,gCAAgC,QAAQ;OAC9C,CAAA,GACP,kBAAC,GAAD;QACE,OAAO,EAAK;QACZ,gBAAgB,MAAM,EAAS,UAAU,CAAkB;kBAF7D,CAIE,kBAAC,GAAD;SAAe,IAAG;mBAChB,kBAAC,GAAD,CAAc,CAAA;QACD,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,GAAc,KAAK,MAClB,kBAAC,GAAD;SAAqB,OAAO;mBACzB,EAAS,CAAE;QACF,GAFK,CAEL,CACb,EACY,CAAA,CACT;SACL;WAEL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,kCAAkC,UAAU;OAClD,CAAA,GACP,kBAAC,GAAD;QACE,IAAG;QACH,MAAK;QACL,KAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAS,YAAY,EAAE,OAAO,KAAK;OACrD,CAAA,CACE;QAEJ;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,sCAAsC,eAAe;OAC3D,CAAA,GACP,kBAAC,GAAD;QACE,IAAG;QACH,MAAK;QACL,KAAK;QACL,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAS,gBAAgB,EAAE,OAAO,KAAK;QACxD,UAAA;OACD,CAAA,CACE;UACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,oCAAoC,aAAa;OACvD,CAAA,GACP,kBAAC,GAAD;QACE,IAAG;QACH,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAS,cAAc,EAAE,OAAO,KAAK;QACtD,UAAA;OACD,CAAA,CACE;QACF;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,iCAAiC,sBAAsB;OAC7D,CAAA,GACP,kBAAC,GAAD;QACE,IAAG;QACH,MAAK;QACL,KAAK;QACL,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAS,uBAAuB,EAAE,OAAO,KAAK;OAChE,CAAA,CACE;UACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,kCAAkC,UAAU;OAClD,CAAA,GACP,kBAAC,GAAD;QACE,IAAG;QACH,OAAO,EAAK;QACZ,WAAW,MAAM,EAAS,YAAY,EAAE,OAAO,MAAM,YAAY,CAAC;QAClE,WAAW;OACZ,CAAA,CACE;QACF;;KAEJ,MAAS,SACR,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,kCAAkC,UAAU;MAClD,CAAA,GACP,kBAAC,GAAD;OACE,IAAG;OACH,MAAK;OACL,KAAK;OACL,OAAO,EAAK;OACZ,WAAW,MAAM,EAAS,YAAY,EAAE,OAAO,KAAK;MACrD,CAAA,CACE;UACH;KAEJ,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,mCAAmC,sBAAsB;MAC/D,CAAA,GACP,kBAAC,GAAD;OACE,OAAO,EAAK,eAAe;OAC3B,gBAAgB,MAAM,EAAS,eAAe,MAAM,KAAiB,KAAK,CAAC;iBAF7E,CAIE,kBAAC,GAAD;QAAe,IAAG;kBAChB,kBAAC,GAAD,EACE,aAAa,EAAU,uCAAuC,MAAM,EACrE,CAAA;OACY,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;QAAY,OAAO;kBAChB,EAAU,uCAAuC,MAAM;OAC9C,CAAA,GACX,EAAW,KAAK,MACf,kBAAC,GAAD;QAAuB,OAAO,EAAE;kBAC7B,EAAE;OACO,GAFK,EAAE,EAEP,CACb,CACY,EAAA,CAAA,CACT;QACL;;KAEJ,MAAS,UAAU,IAClB,kBAAC,GAAD;MACE,YAAW;MACX,UAAU;MACV,OAAO,EAAU,8BAA8B,MAAM;KACtD,CAAA,IAED,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAQ,EAAU,8BAA8B,MAAM,EAAS,CAAA,GAC/D,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,yCACA,2CACF;MACC,CAAA,CACA;;KAGP,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBAAc,EAAU,+BAA+B,OAAO;MAAS,CAAA,GACtF,kBAAC,IAAD;OACE,IAAG;OACH,OAAO,EAAK;OACZ,WAAW,MAAM,EAAS,SAAS,EAAE,OAAO,KAAK;OACjD,MAAM;MACP,CAAA,CACE;;KAEL,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,eAAe,EAAa,EAAK;MACjC,UAAU;gBAET,EAAU,gCAAgC,QAAQ;KAC7C,CAAA,GACR,kBAAC,GAAD;MAAQ,MAAK;MAAS,UAAU,CAAC,KAAS;gBACvC,IACG,EAAU,gCAAgC,SAAS,IACnD,MAAS,WACP,EAAU,gCAAgC,aAAa,IACvD,EAAU,8BAA8B,cAAc;KACtD,CAAA,CACc,EAAA,CAAA;IACpB;KACiB;;CACT,CAAA;AAEtB;AAUA,SAAS,GAAgB,EAAE,WAAQ,YAAS,gBAAmC;CAC7E,IAAM,EAAE,MAAM,GAAM,cAAW,aAAS,gBAAY,EAAQ,KAAU,KAAA,CAAS,GACzE,EAAE,MAAM,MAAa,EAAgB,KAAU,KAAA,CAAS,GACxD,EAAE,MAAM,MAAa,EAAY,GAEjC,IAAc,EAAmB,GACjC,IAAgB,EAAqB,GACrC,IAAS,EAAwB,GAEjC,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAa,MAAkB,EAAsB,SAAS,GAC/D,CAAC,GAAc,MAAmB,EAAS,EAAE,GAC7C,CAAC,GAAc,MAAmB,EAAS,EAAE,GAC7C,CAAC,GAAW,KAAgB,EAAgC,IAAI,GAEhE,IAAc,EAAS,QAAQ,GAAG,MAAM,KAAK,EAAE,eAAe,IAAI,CAAC,GACnE,IAAW,GAAM,YAAY,OAC7B,KAAY,IAAO,GAAc,CAAI,IAAI,GACzC,KAAgB,IAAO,GAAS,EAAK,QAAQ,EAAK,UAAU,IAAI,SAChE,IAAmB,IACrB,GAAsB,GAAa,EAAK,qBAAqB,EAAK,UAAU,IAC5E,CAAC,GAEC,MAAe,MAAe,EAAS,MAAM,MAAM,EAAE,OAAO,CAAE,GAAG,QAAQ,GAEzE,WAAmB;EACvB,IAAI,CAAC,KAAU,CAAC,GAAW;EAC3B,IAAM,IAAU,OAAO,CAAY;EAC/B,CAAC,OAAO,SAAS,CAAO,KAAK,KAAW,KAC5C,EAAY,OACV;GACE;GACA;GACA,GAAI,MAAgB,YAAY,EAAE,eAAe,EAAQ,IAAI,EAAE,aAAa,EAAQ;EACtF,GACA,EACE,iBAAiB;GAEf,AADA,EAAa,EAAE,GACf,GAAgB,EAAE;EACpB,EACF,CACF;CACF,GAEM,UAAqB;EACzB,IAAI,CAAC,GAAQ;EACb,IAAM,IAAS,MAAiB,KAAK,IAAc,OAAO,CAAY;EACjE,OAAO,SAAS,CAAM,KAC3B,EAAO,OAAO;GAAE,IAAI;GAAQ,cAAc;EAAO,CAAC;CACpD,GAEM,IAAY,EAAQ,KAAc,OAAO,CAAY,IAAI,GAEzD,IAAiB,IACnB,EAAU,eAAe,OAEvB,GAAY,EAAU,SAAS,IAD/B,EAAY,EAAU,aAAa,CAAQ,IAE7C;CAEJ,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,IAAD;EACE,MAAM,EAAQ;EACd,eAAe,MAAM;GACnB,AAAK,KAAG,EAAQ;EAClB;YAEA,kBAAC,IAAD;GAAc,WAAU;aAAxB,CACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UACG,GAAM,QAAQ,EAAU,iCAAiC,MAAM,EACtD,CAAA,GACZ,kBAAC,IAAD,EAAA,UACG,EACC,oCACA,sCACF,EACgB,CAAA,CACP,EAAA,CAAA,GAEb,kBAAC,OAAD;IAAK,WAAU;cACZ,IACC,kBAAC,IAAD,EAAc,MAAM,EAAI,CAAA,IACtB,KACF,kBAAC,IAAD;KACE,OAAO,EAAU,iCAAiC,qBAAqB;KACvE,eAAe,GAAQ;IACxB,CAAA,IACE,IAMH,kBAAA,GAAA,EAAA,UAAA;KAEE,kBAAC,IAAD;MAAW,MAAA;MAAK,WAAU;gBAA1B,CACE,kBAAC,IAAD;OACE,OAAO;OACD;OACN,MAAM;OACN,aAAa;OACb,OAAO,EAAU,kCAAkC,QAAQ;MAC5D,CAAA,GACD,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD;SAAO,SAAS,GAAmB,EAAK,UAAU;mBAC/C,EAAS,EAAK,UAAU;QACpB,CAAA;QACP,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAY,GAAa,CAAQ;QACjC,CAAA;QACH,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAU,oCAAoC,sBAAsB,EACnE,QAAQ,GAAc,EAAK,cAAc,CAAQ,EACnD,CAAC;QACA,CAAA;OACA;QACI;;KAEX,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QACE,MAAM,kBAAC,GAAD;SAAQ,WAAU;SAAS,eAAY;QAAQ,CAAA;QACrD,OAAO,EAAU,kCAAkC,QAAQ;QAC3D,OAAO,EAAY,EAAK,cAAc,CAAQ;OAC/C,CAAA;OACD,kBAAC,GAAD;QACE,MAAM,kBAAC,GAAD;SAAQ,WAAU;SAAS,eAAY;QAAQ,CAAA;QACrD,OAAO,EAAU,kCAAkC,gBAAgB;QACnE,OAAO,EAAY,GAAa,CAAQ;OACzC,CAAA;OACD,kBAAC,GAAD;QACE,MAAM,kBAAC,IAAD;SAAO,WAAU;SAAS,eAAY;QAAQ,CAAA;QACpD,OAAO,EAAU,mCAAmC,SAAS;QAC7D,OAAO,EAAY,EAAK,qBAAqB,CAAQ;OACtD,CAAA;OACD,kBAAC,GAAD;QACE,MAAM,kBAAC,IAAD;SAAe,WAAU;SAAS,eAAY;QAAQ,CAAA;QAC5D,OAAO,EAAU,sCAAsC,aAAa;QACpE,OAAO,GAAW,EAAK,UAAU;OAClC,CAAA;MACE;;KAGJ,EAAiB,UAAU,IAC1B,kBAAC,WAAD;MAAS,WAAU;gBAAnB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,IAAD;SAAW,WAAU;SAA6B,eAAY;QAAQ,CAAA,GACtE,kBAAC,MAAD;SAAI,WAAU;mBACX,EACC,2CACA,yBACF;QACE,CAAA,CACD;;OACL,kBAAC,IAAD;QACE,MAAM;QACN,QAAQ,EAAK;QACP;QACN,QAAQ;QACR,iBAAiB,MAAM,GAAc,GAAG,CAAQ;OACjD,CAAA;OACD,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,0CACA,sDACA;SACE,SAAS,EAAY,EAAK,qBAAqB,CAAQ;SACvD,MAAM,GAAW,EAAK,UAAU;QAClC,CACF;OACC,CAAA;MACI;UACP;KAGJ,kBAAC,WAAD;MAAS,WAAU;gBAAnB,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAU,wCAAwC,iBAAiB;MAClE,CAAA,GACH,EAAS,WAAW,IACnB,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,sCACA,2CACF;MACC,CAAA,IAEH,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD,EAAA,UAAA;QACE,kBAAC,GAAD,EAAA,UACG,EAAU,mCAAmC,SAAS,EAC9C,CAAA;QACX,kBAAC,GAAD;SAAW,WAAU;mBAClB,EAAU,sCAAsC,YAAY;QACpD,CAAA;QACX,kBAAC,GAAD;SAAW,WAAU;mBAClB,EAAU,uCAAuC,cAAc;QACvD,CAAA;QACX,kBAAC,GAAD,EAAW,WAAU,OAAQ,CAAA;OACrB,EAAA,CAAA,EACC,CAAA,GACb,kBAAC,IAAD,EAAA,UACG,EAAS,KAAK,MACb,kBAAC,IAAD,EAAA,UAAA;QACE,kBAAC,GAAD;SAAW,WAAU;mBAClB,GAAY,EAAE,SAAS;QACf,CAAA;QACX,kBAAC,GAAD;SAAW,WAAU;mBAClB,EAAE,eAAe,OAAO,EAAU,EAAE,aAAa,IAAI;QAC7C,CAAA;QACX,kBAAC,GAAD;SAAW,WAAU;mBAClB,EAAE,eAAe,OAA8C,MAAvC,EAAY,EAAE,aAAa,CAAQ;QACnD,CAAA;QACX,kBAAC,GAAD;SAAW,WAAU;mBACnB,kBAAC,GAAD;UACE,SAAQ;UACR,MAAK;UACL,cAAY,EACV,kCACA,gBACF;UACA,eAAe,EAAa,CAAC;oBAE7B,kBAAC,GAAD;WAAQ,WAAU;WAAS,eAAY;UAAQ,CAAA;SACzC,CAAA;QACC,CAAA;OACH,EAAA,GAvBK,EAAE,EAuBP,CACX,EACQ,CAAA,CACN,EAAA,CAAA;MACJ,CAAA,CAEA;;KAGT,kBAAC,WAAD;MAAS,WAAU;gBAAnB,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAU,qCAAqC,iBAAiB;MAC/D,CAAA,GACH,EAAS,WAAW,IACnB,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,sCACA,gCACF;MACC,CAAA,IAEH,kBAAA,GAAA,EAAA,UAAA;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBACZ,EAAU,mCAAmC,SAAS;QAClD,CAAA,GACP,kBAAC,GAAD;SAAQ,OAAO;SAAW,eAAe;mBAAzC,CACE,kBAAC,GAAD;UAAe,IAAG;oBAChB,kBAAC,GAAD,EACE,aAAa,EACX,yCACA,gBACF,EACD,CAAA;SACY,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAS,KAAK,MACb,kBAAC,GAAD;UAAuB,OAAO,EAAE;oBAC7B,EAAE;SACO,GAFK,EAAE,EAEP,CACb,EACY,CAAA,CACT;UACL;;OACL,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBACZ,EAAU,gCAAgC,QAAQ;SAC9C,CAAA,GACP,kBAAC,GAAD;UACE,OAAO;UACP,gBAAgB,MAAM,GAAe,CAAgB;oBAFvD,CAIE,kBAAC,GAAD;WAAe,IAAG;qBAChB,kBAAC,GAAD,CAAc,CAAA;UACD,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;WAAY,OAAM;qBACf,EAAU,mCAAmC,YAAY;UAChD,CAAA,GACZ,kBAAC,GAAD;WAAY,OAAM;qBACf,EAAU,iCAAiC,cAAc;UAChD,CAAA,CACC,EAAA,CAAA,CACT;WACL;YACL,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBACZ,MAAgB,YACb,EAAU,+BAA+B,SAAS,IAClD,EAAU,kCAAkC,QAAQ;SACnD,CAAA,GACP,kBAAC,GAAD;UACE,IAAG;UACH,MAAK;UACL,KAAK;UACL,MAAK;UACL,OAAO;UACP,WAAW,MAAM,GAAgB,EAAE,OAAO,KAAK;SAChD,CAAA,CACE;UACF;;OACL,kBAAC,GAAD;QACE,MAAK;QACL,WAAU;QACV,UAAU,CAAC,KAAa,EAAY;QACpC,SAAS;kBAJX,CAME,kBAAC,IAAD;SAAO,WAAU;SAAS,eAAY;QAAQ,CAAA,GAC7C,EAAY,YACT,EAAU,mCAAmC,UAAU,IACvD,EAAU,gCAAgC,cAAc,CACtD;;MACR,EAAA,CAAA,CAEG;;KAGT,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD;MAAa,WAAU;gBACrB,kBAAC,GAAD;OACE,YAAW;OACX,UAAU,EAAK;OACf,OAAO,EAAU,gCAAgC,MAAM;MACxD,CAAA;KACU,CAAA,EACT,CAAA;KAGN,kBAAC,WAAD;MAAS,WAAU;gBAAnB;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAU,uCAAuC,wBAAwB;OACxE,CAAA;OACJ,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,GAAD;UAAO,SAAQ;oBACZ,EAAU,wCAAwC,eAAe;SAC7D,CAAA;SACP,kBAAC,GAAD;UACE,IAAG;UACH,MAAK;UACL,KAAK;UACL,MAAK;UACL,OAAO;UACP,aAAa,OAAO,CAAW;UAC/B,WAAW,MAAM,GAAgB,EAAE,OAAO,KAAK;SAChD,CAAA;SACD,kBAAC,KAAD;UAAG,WAAU;oBACV,EACC,sCACA,wDACF;SACC,CAAA;QACA;;OACL,kBAAC,GAAD;QACE,MAAK;QACL,SAAQ;QACR,WAAU;QACV,UAAU,EAAO;QACjB,SAAS;kBALX,CAOE,kBAAC,IAAD;SAAW,WAAU;SAAS,eAAY;QAAQ,CAAA,GACjD,EAAO,YACJ,EAAU,yCAAyC,gBAAgB,IACnE,EAAU,kCAAkC,aAAa,CACvD;;MACD;;IACT,EAAA,CAAA,IA7RF,kBAAC,IAAD;KACE,MAAM,kBAAC,GAAD;MAAQ,WAAU;MAAS,eAAY;KAAQ,CAAA;KACrD,OAAO,EAAU,oCAAoC,gBAAgB;IACtE,CAAA;GA4RA,CAAA,CACO;;CACT,CAAA,GAEP,kBAAC,IAAD;EACE,MAAM,EAAQ;EACd,eAAe,MAAM;GACnB,AAAK,KAAG,EAAa,IAAI;EAC3B;EACA,OAAO,EAAU,uCAAuC,iBAAiB;EACzE,aAAa,EACX,yCACA,0DACA,EAAE,MAAM,EAAe,CACzB;EACA,cAAc,EAAU,kCAAkC,gBAAgB;EAC1E,cAAc,EAAU,qCAAqC,YAAY;EACzE,aAAA;EACA,SAAS,EAAc;EACvB,iBAAiB;GACV,KACL,EAAc,OAAO,EAAU,IAAI,EAAE,iBAAiB,EAAa,IAAI,EAAE,CAAC;EAC5E;CACD,CAAA,CACD,EAAA,CAAA;AAEN"}
|
|
1
|
+
{"version":3,"file":"GoalsPage.js","names":[],"sources":["../../../src/brainyrich/pages/GoalsPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useSearchParams } from 'react-router';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AlertTriangle,\n CalendarClock,\n Coins,\n Link2,\n LineChart,\n MoreHorizontal,\n PiggyBank,\n Plus,\n RefreshCw,\n Target,\n Trash2,\n TrendingDown,\n TrendingUp,\n Unlink,\n Wallet,\n} from 'lucide-react';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n ConfirmDialog,\n FadeIn,\n GlassCard,\n LoadMore,\n MiniAreaChart,\n ProgressRing,\n StatTile,\n type AreaDatum,\n type VizTone,\n} from '../components';\nimport { TagField } from '../components/reuse/TagField';\nimport { hapticSuccess, showToast } from '../utils/nativeControls';\nimport { useTrackBrainyRichPageView } from '../hooks/useBrainyRichAnalytics';\nimport {\n useAccounts,\n useArchiveGoal,\n useCreateGoal,\n useGoal,\n useGoalFundings,\n useHouseholds,\n useLinkGoalFunding,\n usePagedGoals,\n useRecalcGoalProjection,\n useUnlinkGoalFunding,\n useUpdateGoal,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraCreateGoalInput,\n BraGoal,\n BraGoalFunding,\n BraGoalProjection,\n BraGoalStatus,\n BraGoalType,\n BraUpdateGoalInput,\n} from '../types/bra';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n SectionShell,\n formatCompact,\n formatDate,\n formatMoney,\n formatPct,\n statusBadgeVariant,\n} from './_shared';\nimport { fundedPercent, goalTone } from '../utils/goalMetrics';\nimport { useIsMobileViewport } from '../hooks/useIsMobileViewport';\nimport { GOAL_DETAIL_PARAM } from '../navItems';\nimport { MobileGoalsView } from './mobile/MobileGoalsView';\n\nconst GOAL_TYPES: BraGoalType[] = [\n 'RETIREMENT',\n 'EDUCATION',\n 'HOME',\n 'EMERGENCY_FUND',\n 'MAJOR_PURCHASE',\n 'WEALTH_GROWTH',\n 'CUSTOM',\n];\n\nconst GOAL_STATUSES: BraGoalStatus[] = ['ACTIVE', 'ACHIEVED', 'ON_HOLD', 'ABANDONED'];\n\ninterface ProjectionMeta {\n icon: typeof TrendingUp;\n tone: string;\n}\n\nfunction projectionMeta(projection: BraGoalProjection): ProjectionMeta {\n switch (projection) {\n case 'AHEAD':\n case 'ON_TRACK':\n return { icon: TrendingUp, tone: 'text-status-success-text' };\n case 'BEHIND':\n return { icon: TrendingDown, tone: 'text-status-warning-text' };\n case 'AT_RISK':\n default:\n return { icon: AlertTriangle, tone: 'text-status-error-text' };\n }\n}\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\n/**\n * A deterministic contribution trajectory from today to the target date, computed\n * purely from wired fields: starting funded balance + monthly contribution × month.\n * No randomness, no fabricated series — just the arithmetic funding path the user\n * has configured. Returns [] when there is nothing meaningful to chart.\n */\nfunction buildProjectionSeries(\n funded: number,\n monthly: number,\n targetIso?: string | null\n): AreaDatum[] {\n if (!targetIso) return [];\n const target = new Date(targetIso);\n if (Number.isNaN(target.getTime())) return [];\n const now = new Date();\n const totalMonths =\n (target.getFullYear() - now.getFullYear()) * 12 + (target.getMonth() - now.getMonth());\n if (totalMonths <= 0) return [];\n const steps = Math.min(Math.max(totalMonths, 2), 12);\n const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: '2-digit' });\n const points: AreaDatum[] = [];\n for (let i = 0; i <= steps; i += 1) {\n const m = Math.round((totalMonths / steps) * i);\n const at = new Date(now.getFullYear(), now.getMonth() + m, 1);\n points.push({ x: fmt.format(at), y: Math.round(funded + monthly * m) });\n }\n return points;\n}\n\n/** yyyy-mm-dd for a date input, guarded against absent/invalid ISO strings. */\nfunction toDateInput(iso?: string | null): string {\n if (!iso) return '';\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n return d.toISOString().slice(0, 10);\n}\n\ninterface GoalFormState {\n name: string;\n type: BraGoalType;\n status: BraGoalStatus;\n targetAmount: string;\n targetDate: string;\n monthlyContribution: string;\n priority: string;\n currency: string;\n householdId: string;\n notes: string;\n}\n\nfunction emptyForm(): GoalFormState {\n return {\n name: '',\n type: 'CUSTOM',\n status: 'ACTIVE',\n targetAmount: '',\n targetDate: '',\n monthlyContribution: '',\n priority: '1',\n currency: 'USD',\n householdId: '',\n notes: '',\n };\n}\n\nfunction formFromGoal(goal: BraGoal): GoalFormState {\n return {\n name: goal.name,\n type: goal.type,\n status: goal.status,\n targetAmount: String(goal.targetAmount),\n targetDate: toDateInput(goal.targetDate),\n monthlyContribution: String(goal.monthlyContribution),\n priority: String(goal.priority),\n currency: goal.currency,\n householdId: goal.householdId ?? '',\n notes: goal.notes ?? '',\n };\n}\n\nconst HOUSEHOLD_NONE = '__none__';\n\nexport function GoalsPage() {\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.goals.viewed');\n const isMobile = useIsMobileViewport();\n\n const {\n items: goals,\n hasMore,\n loadMore,\n isFetchingNextPage,\n isLoading,\n isError,\n refetch,\n } = usePagedGoals();\n const { data: households } = useHouseholds();\n\n const createGoal = useCreateGoal();\n const updateGoal = useUpdateGoal();\n const archiveGoal = useArchiveGoal();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [editing, setEditing] = useState<BraGoal | null>(null);\n // `?goal=<id>` opens that goal's detail sheet, so other views (the phone\n // dashboard's goal strip) can deep-link to a single goal.\n const [searchParams, setSearchParams] = useSearchParams();\n const [detailId, setDetailId] = useState<string | null>(() =>\n searchParams.get(GOAL_DETAIL_PARAM)\n );\n const closeDetail = () => {\n setDetailId(null);\n if (searchParams.has(GOAL_DETAIL_PARAM)) {\n const next = new URLSearchParams(searchParams);\n next.delete(GOAL_DETAIL_PARAM);\n setSearchParams(next, { replace: true });\n }\n };\n const [archiving, setArchiving] = useState<BraGoal | null>(null);\n const [form, setForm] = useState<GoalFormState>(emptyForm);\n\n const setField = <K extends keyof GoalFormState>(key: K, value: GoalFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const totals = useMemo(() => {\n const totalTarget = goals.reduce((s, g) => s + g.targetAmount, 0);\n const totalMonthly = goals.reduce((s, g) => s + g.monthlyContribution, 0);\n const atRisk = goals.filter(\n (g) => g.projection === 'AT_RISK' || g.projection === 'BEHIND'\n ).length;\n return { totalTarget, totalMonthly, atRisk };\n }, [goals]);\n\n const currency = goals[0]?.currency ?? 'USD';\n\n const openCreate = () => {\n setForm(emptyForm());\n setCreateOpen(true);\n };\n\n const openEdit = (goal: BraGoal) => {\n setForm(formFromGoal(goal));\n setEditing(goal);\n };\n\n const formValid =\n form.name.trim().length > 0 && Number(form.targetAmount) > 0 && form.targetDate.length > 0;\n\n const handleCreate = () => {\n if (!formValid) return;\n const input: BraCreateGoalInput = {\n name: form.name.trim(),\n type: form.type,\n targetAmount: Number(form.targetAmount),\n targetDate: new Date(form.targetDate).toISOString(),\n monthlyContribution: Number(form.monthlyContribution) || 0,\n priority: Number(form.priority) || 1,\n currency: form.currency.trim() || 'USD',\n notes: form.notes.trim() || null,\n tags: [],\n ...(form.householdId ? { householdId: form.householdId } : {}),\n };\n createGoal.mutate(input, {\n onSuccess: () => {\n hapticSuccess();\n void showToast(translate('brainyrich.goals.created', 'Goal created'));\n setCreateOpen(false);\n },\n });\n };\n\n const handleUpdate = () => {\n if (!editing || !formValid) return;\n const input: BraUpdateGoalInput = {\n name: form.name.trim(),\n type: form.type,\n status: form.status,\n targetAmount: Number(form.targetAmount),\n targetDate: new Date(form.targetDate).toISOString(),\n monthlyContribution: Number(form.monthlyContribution) || 0,\n priority: Number(form.priority) || 1,\n currency: form.currency.trim() || 'USD',\n notes: form.notes.trim() || null,\n // Legacy `tags` scalar preserved as-is; the canonical tag surface is <TagField>.\n tags: editing.tags,\n };\n updateGoal.mutate(\n { id: editing.id, input },\n {\n onSuccess: () => {\n hapticSuccess();\n void showToast(translate('brainyrich.goals.saved', 'Goal saved'));\n setEditing(null);\n },\n }\n );\n };\n\n const body = () => {\n if (isLoading) return <LoadingState rows={4} />;\n if (isError)\n return (\n <ErrorState\n title={translate('brainyrich.goals.error.title', 'Could not load goals')}\n description={translate(\n 'brainyrich.goals.error.description',\n 'We could not reach the goals service. Please try again.'\n )}\n onRetry={() => refetch()}\n />\n );\n if (goals.length === 0)\n return (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.goals.empty.title', 'No financial goals yet')}\n description={translate(\n 'brainyrich.goals.empty.description',\n 'Create your first goal to start tracking progress toward a milestone.'\n )}\n action={\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.createGoal', 'New goal')}\n </Button>\n }\n />\n );\n\n return (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <FadeIn index={0}>\n <StatTile\n glow\n icon={<Target className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.activeGoals', 'Goals')}\n value={String(goals.length)}\n />\n </FadeIn>\n <FadeIn index={1}>\n <StatTile\n icon={<PiggyBank className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.totalTarget', 'Total target')}\n value={formatMoney(totals.totalTarget, currency)}\n />\n </FadeIn>\n <FadeIn index={2}>\n <StatTile\n icon={<Coins className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.monthly', 'Monthly contributions')}\n value={formatMoney(totals.totalMonthly, currency)}\n />\n </FadeIn>\n <FadeIn index={3}>\n <StatTile\n icon={<AlertTriangle className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.metrics.atRisk', 'Needs attention')}\n value={String(totals.atRisk)}\n className={totals.atRisk > 0 ? 'ring-1 ring-status-error-text/30' : undefined}\n />\n </FadeIn>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {goals.map((g, i) => {\n const proj = projectionMeta(g.projection);\n const ProjIcon = proj.icon;\n const tone = goalTone(g.status, g.projection);\n const pct = fundedPercent(g);\n const achieved = g.status === 'ACHIEVED';\n return (\n <FadeIn key={g.id} index={i}>\n <Card\n className={`group flex h-full flex-col transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))] ${\n achieved ? 'ring-1 ring-status-success-text/30' : ''\n }`}\n >\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Target\n className=\"size-4 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n <span className=\"truncate\">{g.name}</span>\n </CardTitle>\n <CardDescription className=\"mt-1 flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\">{humanize(g.type)}</Badge>\n <Badge variant={statusBadgeVariant(g.status)}>{humanize(g.status)}</Badge>\n </CardDescription>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={translate('brainyrich.goals.actions.menu', 'Goal actions')}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onSelect={() => setDetailId(g.id)}>\n <Link2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.manageFunding', 'Manage funding')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => openEdit(g)}>\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.editGoal', 'Edit goal')}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"text-status-error-text focus:text-status-error-text\"\n onSelect={() => setArchiving(g)}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.goals.actions.archive', 'Archive goal')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"flex flex-1 flex-col gap-4\">\n <div className=\"flex items-center gap-4\">\n <ProgressRing\n value={pct}\n tone={tone}\n size={92}\n strokeWidth={9}\n label={translate('brainyrich.goals.card.funded', 'funded')}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.target', 'Target amount')}\n </p>\n <p className=\"truncate text-2xl font-semibold text-text-primary\">\n {formatMoney(g.targetAmount, g.currency)}\n </p>\n <span\n className={`mt-1 inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium ${proj.tone}`}\n >\n <ProjIcon className=\"size-3.5\" aria-hidden=\"true\" />\n {humanize(g.projection)}\n </span>\n </div>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-3 rounded-lg bg-bg-sunken p-3 text-sm\">\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.targetDate', 'Target date')}\n </dt>\n <dd className=\"flex items-center gap-1 font-medium text-text-primary\">\n <CalendarClock\n className=\"size-3.5 text-text-secondary\"\n aria-hidden=\"true\"\n />\n {formatDate(g.targetDate)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.monthly', 'Monthly')}\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatMoney(g.monthlyContribution, g.currency)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.priority', 'Priority')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{g.priority}</dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.card.fundings', 'Funding links')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{g.fundings?.length ?? 0}</dd>\n </div>\n </dl>\n\n <div className=\"mt-auto\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full\"\n onClick={() => setDetailId(g.id)}\n >\n {translate(\n 'brainyrich.goals.actions.viewDetails',\n 'View details & funding'\n )}\n </Button>\n </div>\n </CardContent>\n </Card>\n </FadeIn>\n );\n })}\n </div>\n\n <LoadMore\n hasMore={hasMore}\n loading={isFetchingNextPage}\n onClick={loadMore}\n label={translate('brainyrich.goals.actions.loadMore', 'Load more goals')}\n loadingLabel={translate('brainyrich.goals.actions.loadingMore', 'Loading…')}\n />\n </>\n );\n };\n\n // Dialogs and the detail sheet are shared by the desktop and phone layouts.\n const overlays = (\n <>\n <GoalFormDialog\n open={createOpen}\n mode=\"create\"\n form={form}\n setField={setField}\n households={households.map((h) => ({ id: h.id, name: h.name }))}\n valid={formValid}\n pending={createGoal.isPending}\n onSubmit={handleCreate}\n onOpenChange={(v) => setCreateOpen(v)}\n translate={translate}\n />\n\n <GoalFormDialog\n open={Boolean(editing)}\n mode=\"edit\"\n goalId={editing?.id}\n form={form}\n setField={setField}\n households={households.map((h) => ({ id: h.id, name: h.name }))}\n valid={formValid}\n pending={updateGoal.isPending}\n onSubmit={handleUpdate}\n onOpenChange={(v) => {\n if (!v) setEditing(null);\n }}\n translate={translate}\n />\n\n <GoalDetailSheet goalId={detailId} onClose={closeDetail} translate={translate} />\n\n <ConfirmDialog\n open={Boolean(archiving)}\n onOpenChange={(o) => {\n if (!o) setArchiving(null);\n }}\n title={translate('brainyrich.goals.archive.title', 'Archive goal?')}\n description={translate(\n 'brainyrich.goals.archive.description',\n 'This removes “{name}” from your active goals. You can no longer track its progress.',\n { name: archiving?.name ?? '' }\n )}\n confirmLabel={translate('brainyrich.goals.archive.confirm', 'Archive goal')}\n pendingLabel={translate('brainyrich.goals.archive.pending', 'Archiving…')}\n destructive\n pending={archiveGoal.isPending}\n onConfirm={() => {\n if (!archiving) return;\n archiveGoal.mutate(archiving.id, {\n onSuccess: () => {\n hapticSuccess();\n void showToast(\n translate('brainyrich.goals.archived', 'Goal archived', { name: archiving.name })\n );\n setArchiving(null);\n },\n });\n }}\n />\n </>\n );\n\n if (isMobile) {\n return (\n <>\n <MobileGoalsView\n translate={translate}\n goals={goals}\n isLoading={isLoading}\n isError={isError}\n refetch={() => refetch()}\n hasMore={hasMore}\n loadMore={loadMore}\n isFetchingNextPage={isFetchingNextPage}\n totals={totals}\n currency={currency}\n onCreate={openCreate}\n onOpen={(goal) => setDetailId(goal.id)}\n onEdit={openEdit}\n onArchive={setArchiving}\n />\n {overlays}\n </>\n );\n }\n\n return (\n <div data-tour=\"brainyrich-page-goals\" className=\"contents\">\n <SectionShell\n title={translate('brainyrich.goals.title', 'Financial Goals')}\n description={translate(\n 'brainyrich.goals.description',\n 'Track progress toward your wealth milestones and life objectives'\n )}\n actionLabel={translate('brainyrich.goals.actions.createGoal', 'New goal')}\n onAction={openCreate}\n >\n {body()}\n </SectionShell>\n\n {overlays}\n </div>\n );\n}\n\ntype Translate = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string;\n\ninterface GoalFormDialogProps {\n open: boolean;\n mode: 'create' | 'edit';\n goalId?: string;\n form: GoalFormState;\n setField: <K extends keyof GoalFormState>(key: K, value: GoalFormState[K]) => void;\n households: { id: string; name: string }[];\n valid: boolean;\n pending: boolean;\n onSubmit: () => void;\n onOpenChange: (open: boolean) => void;\n translate: Translate;\n}\n\nfunction GoalFormDialog({\n open,\n mode,\n goalId,\n form,\n setField,\n households,\n valid,\n pending,\n onSubmit,\n onOpenChange,\n translate,\n}: GoalFormDialogProps) {\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[90vh] overflow-y-auto sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {mode === 'create'\n ? translate('brainyrich.goals.form.createTitle', 'New goal')\n : translate('brainyrich.goals.form.editTitle', 'Edit goal')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {translate(\n 'brainyrich.goals.form.subtitle',\n 'Define the milestone, target and contribution plan.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n className=\"space-y-4\"\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit();\n }}\n >\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-name\">{translate('brainyrich.goals.form.name', 'Name')}</Label>\n <Input\n id=\"goal-name\"\n value={form.name}\n onChange={(e) => setField('name', e.target.value)}\n placeholder={translate(\n 'brainyrich.goals.form.namePlaceholder',\n 'e.g. Retirement fund'\n )}\n required\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-type\">{translate('brainyrich.goals.form.type', 'Type')}</Label>\n <Select value={form.type} onValueChange={(v) => setField('type', v as BraGoalType)}>\n <SelectTrigger id=\"goal-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {GOAL_TYPES.map((tpe) => (\n <SelectItem key={tpe} value={tpe}>\n {humanize(tpe)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n {mode === 'edit' ? (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-status\">\n {translate('brainyrich.goals.form.status', 'Status')}\n </Label>\n <Select\n value={form.status}\n onValueChange={(v) => setField('status', v as BraGoalStatus)}\n >\n <SelectTrigger id=\"goal-status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {GOAL_STATUSES.map((st) => (\n <SelectItem key={st} value={st}>\n {humanize(st)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-priority\">\n {translate('brainyrich.goals.form.priority', 'Priority')}\n </Label>\n <Input\n id=\"goal-priority\"\n type=\"number\"\n min={1}\n value={form.priority}\n onChange={(e) => setField('priority', e.target.value)}\n />\n </div>\n )}\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-target\">\n {translate('brainyrich.goals.form.targetAmount', 'Target amount')}\n </Label>\n <Input\n id=\"goal-target\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={form.targetAmount}\n onChange={(e) => setField('targetAmount', e.target.value)}\n required\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-date\">\n {translate('brainyrich.goals.form.targetDate', 'Target date')}\n </Label>\n <Input\n id=\"goal-date\"\n type=\"date\"\n value={form.targetDate}\n onChange={(e) => setField('targetDate', e.target.value)}\n required\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-monthly\">\n {translate('brainyrich.goals.form.monthly', 'Monthly contribution')}\n </Label>\n <Input\n id=\"goal-monthly\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={form.monthlyContribution}\n onChange={(e) => setField('monthlyContribution', e.target.value)}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-currency\">\n {translate('brainyrich.goals.form.currency', 'Currency')}\n </Label>\n <Input\n id=\"goal-currency\"\n value={form.currency}\n onChange={(e) => setField('currency', e.target.value.toUpperCase())}\n maxLength={3}\n />\n </div>\n </div>\n\n {mode === 'edit' ? (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-priority-edit\">\n {translate('brainyrich.goals.form.priority', 'Priority')}\n </Label>\n <Input\n id=\"goal-priority-edit\"\n type=\"number\"\n min={1}\n value={form.priority}\n onChange={(e) => setField('priority', e.target.value)}\n />\n </div>\n ) : null}\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-household\">\n {translate('brainyrich.goals.form.household', 'Household (optional)')}\n </Label>\n <Select\n value={form.householdId || HOUSEHOLD_NONE}\n onValueChange={(v) => setField('householdId', v === HOUSEHOLD_NONE ? '' : v)}\n >\n <SelectTrigger id=\"goal-household\">\n <SelectValue\n placeholder={translate('brainyrich.goals.form.householdNone', 'None')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={HOUSEHOLD_NONE}>\n {translate('brainyrich.goals.form.householdNone', 'None')}\n </SelectItem>\n {households.map((h) => (\n <SelectItem key={h.id} value={h.id}>\n {h.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {mode === 'edit' && goalId ? (\n <TagField\n entityType=\"brainyrich-goal\"\n entityId={goalId}\n label={translate('brainyrich.goals.form.tags', 'Tags')}\n />\n ) : (\n <div className=\"space-y-1.5\">\n <Label>{translate('brainyrich.goals.form.tags', 'Tags')}</Label>\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.goals.form.tagsAfterCreate',\n 'You can add tags after creating the goal.'\n )}\n </p>\n </div>\n )}\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"goal-notes\">{translate('brainyrich.goals.form.notes', 'Notes')}</Label>\n <Textarea\n id=\"goal-notes\"\n value={form.notes}\n onChange={(e) => setField('notes', e.target.value)}\n rows={3}\n />\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={pending}\n >\n {translate('brainyrich.goals.form.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={!valid || pending}>\n {pending\n ? translate('brainyrich.goals.form.saving', 'Saving…')\n : mode === 'create'\n ? translate('brainyrich.goals.form.create', 'Create goal')\n : translate('brainyrich.goals.form.save', 'Save changes')}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\ntype FundingMode = 'PERCENT' | 'FIXED';\n\ninterface GoalDetailSheetProps {\n goalId: string | null;\n onClose: () => void;\n translate: Translate;\n}\n\nfunction GoalDetailSheet({ goalId, onClose, translate }: GoalDetailSheetProps) {\n const { data: goal, isLoading, isError, refetch } = useGoal(goalId ?? undefined);\n const { data: fundings } = useGoalFundings(goalId ?? undefined);\n const { data: accounts } = useAccounts();\n\n const linkFunding = useLinkGoalFunding();\n const unlinkFunding = useUnlinkGoalFunding();\n const recalc = useRecalcGoalProjection();\n\n const [accountId, setAccountId] = useState('');\n const [fundingMode, setFundingMode] = useState<FundingMode>('PERCENT');\n const [fundingValue, setFundingValue] = useState('');\n const [fundedAmount, setFundedAmount] = useState('');\n const [unlinking, setUnlinking] = useState<BraGoalFunding | null>(null);\n\n const fixedFunded = fundings.reduce((s, f) => s + (f.fixedAmount ?? 0), 0);\n const currency = goal?.currency ?? 'USD';\n const fundedPct = goal ? fundedPercent(goal) : 0;\n const tone: VizTone = goal ? goalTone(goal.status, goal.projection) : 'brand';\n const projectionSeries = goal\n ? buildProjectionSeries(fixedFunded, goal.monthlyContribution, goal.targetDate)\n : [];\n\n const accountName = (id: string) => accounts.find((a) => a.id === id)?.name ?? id;\n\n const handleLink = () => {\n if (!goalId || !accountId) return;\n const numeric = Number(fundingValue);\n if (!Number.isFinite(numeric) || numeric <= 0) return;\n linkFunding.mutate(\n {\n goalId,\n accountId,\n ...(fundingMode === 'PERCENT' ? { allocationPct: numeric } : { fixedAmount: numeric }),\n },\n {\n onSuccess: () => {\n setAccountId('');\n setFundingValue('');\n },\n }\n );\n };\n\n const handleRecalc = () => {\n if (!goalId) return;\n const amount = fundedAmount === '' ? fixedFunded : Number(fundedAmount);\n if (!Number.isFinite(amount)) return;\n recalc.mutate({ id: goalId, fundedAmount: amount });\n };\n\n const linkValid = Boolean(accountId) && Number(fundingValue) > 0;\n\n const unlinkingLabel = unlinking\n ? unlinking.fixedAmount != null\n ? formatMoney(unlinking.fixedAmount, currency)\n : accountName(unlinking.accountId)\n : '';\n\n return (\n <>\n <Sheet\n open={Boolean(goalId)}\n onOpenChange={(v) => {\n if (!v) onClose();\n }}\n >\n <SheetContent className=\"flex w-full flex-col gap-0 overflow-y-auto sm:max-w-xl\">\n <SheetHeader>\n <SheetTitle>\n {goal?.name ?? translate('brainyrich.goals.detail.title', 'Goal')}\n </SheetTitle>\n <SheetDescription>\n {translate(\n 'brainyrich.goals.detail.subtitle',\n 'Manage funding links and projection.'\n )}\n </SheetDescription>\n </SheetHeader>\n\n <div className=\"space-y-6 p-4\">\n {isLoading ? (\n <LoadingState rows={3} />\n ) : isError ? (\n <ErrorState\n title={translate('brainyrich.goals.detail.error', 'Could not load goal')}\n onRetry={() => refetch()}\n />\n ) : !goal ? (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.goals.detail.notFound', 'Goal not found')}\n />\n ) : (\n <>\n {/* Hero: funded progress ring + headline */}\n <GlassCard glow className=\"flex items-center gap-5\">\n <ProgressRing\n value={fundedPct}\n tone={tone}\n size={116}\n strokeWidth={11}\n label={translate('brainyrich.goals.detail.funded', 'funded')}\n />\n <div className=\"min-w-0 flex-1 space-y-1\">\n <Badge variant={statusBadgeVariant(goal.projection)}>\n {humanize(goal.projection)}\n </Badge>\n <p className=\"text-2xl font-semibold text-text-primary\">\n {formatMoney(fixedFunded, currency)}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {translate('brainyrich.goals.detail.ofTarget', 'of {target} target', {\n target: formatCompact(goal.targetAmount, currency),\n })}\n </p>\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <StatTile\n icon={<Target className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.target', 'Target')}\n value={formatMoney(goal.targetAmount, currency)}\n />\n <StatTile\n icon={<Wallet className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.funded', 'Funded (fixed)')}\n value={formatMoney(fixedFunded, currency)}\n />\n <StatTile\n icon={<Coins className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.monthly', 'Monthly')}\n value={formatMoney(goal.monthlyContribution, currency)}\n />\n <StatTile\n icon={<CalendarClock className=\"size-4\" aria-hidden=\"true\" />}\n label={translate('brainyrich.goals.detail.targetDate', 'Target date')}\n value={formatDate(goal.targetDate)}\n />\n </div>\n\n {/* Projection trajectory toward the target line */}\n {projectionSeries.length >= 2 ? (\n <section className=\"space-y-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex items-center gap-2\">\n <LineChart className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate(\n 'brainyrich.goals.detail.projectionChart',\n 'Contribution projection'\n )}\n </h3>\n </div>\n <MiniAreaChart\n data={projectionSeries}\n target={goal.targetAmount}\n tone={tone}\n height={180}\n valueFormatter={(v) => formatCompact(v, currency)}\n />\n <p className=\"text-xs text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.projectionHint',\n 'Starting balance plus {monthly}/mo through {date}.',\n {\n monthly: formatMoney(goal.monthlyContribution, currency),\n date: formatDate(goal.targetDate),\n }\n )}\n </p>\n </section>\n ) : null}\n\n {/* Funding sources table */}\n <section className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.goals.detail.fundingLinks', 'Funding sources')}\n </h3>\n {fundings.length === 0 ? (\n <p className=\"rounded-lg border border-dashed border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.noFundings',\n 'No accounts linked to fund this goal yet.'\n )}\n </p>\n ) : (\n <div className=\"overflow-x-auto rounded-lg border border-border-subtle\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>\n {translate('brainyrich.goals.detail.account', 'Account')}\n </TableHead>\n <TableHead className=\"text-right\">\n {translate('brainyrich.goals.detail.allocation', 'Allocation')}\n </TableHead>\n <TableHead className=\"text-right\">\n {translate('brainyrich.goals.detail.fixedAmount', 'Fixed amount')}\n </TableHead>\n <TableHead className=\"w-10\" />\n </TableRow>\n </TableHeader>\n <TableBody>\n {fundings.map((f) => (\n <TableRow key={f.id}>\n <TableCell className=\"font-medium text-text-primary\">\n {accountName(f.accountId)}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {f.fixedAmount == null ? formatPct(f.allocationPct) : '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {f.fixedAmount != null ? formatMoney(f.fixedAmount, currency) : '—'}\n </TableCell>\n <TableCell className=\"text-right\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={translate(\n 'brainyrich.goals.detail.unlink',\n 'Unlink funding'\n )}\n onClick={() => setUnlinking(f)}\n >\n <Unlink className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n </section>\n\n {/* Link a new funding */}\n <section className=\"space-y-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.goals.detail.linkTitle', 'Link an account')}\n </h3>\n {accounts.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.noAccounts',\n 'No accounts available to link.'\n )}\n </p>\n ) : (\n <>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"funding-account\">\n {translate('brainyrich.goals.detail.account', 'Account')}\n </Label>\n <Select value={accountId} onValueChange={setAccountId}>\n <SelectTrigger id=\"funding-account\">\n <SelectValue\n placeholder={translate(\n 'brainyrich.goals.detail.selectAccount',\n 'Select account'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {accounts.map((a) => (\n <SelectItem key={a.id} value={a.id}>\n {a.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"funding-mode\">\n {translate('brainyrich.goals.detail.mode', 'Method')}\n </Label>\n <Select\n value={fundingMode}\n onValueChange={(v) => setFundingMode(v as FundingMode)}\n >\n <SelectTrigger id=\"funding-mode\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"PERCENT\">\n {translate('brainyrich.goals.detail.percent', 'Percentage')}\n </SelectItem>\n <SelectItem value=\"FIXED\">\n {translate('brainyrich.goals.detail.fixed', 'Fixed amount')}\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"funding-value\">\n {fundingMode === 'PERCENT'\n ? translate('brainyrich.goals.detail.pct', 'Percent')\n : translate('brainyrich.goals.detail.amount', 'Amount')}\n </Label>\n <Input\n id=\"funding-value\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={fundingValue}\n onChange={(e) => setFundingValue(e.target.value)}\n />\n </div>\n </div>\n <Button\n size=\"sm\"\n className=\"w-full\"\n disabled={!linkValid || linkFunding.isPending}\n onClick={handleLink}\n >\n <Link2 className=\"size-4\" aria-hidden=\"true\" />\n {linkFunding.isPending\n ? translate('brainyrich.goals.detail.linking', 'Linking…')\n : translate('brainyrich.goals.detail.link', 'Link funding')}\n </Button>\n </>\n )}\n </section>\n\n {/* Tags */}\n <Card>\n <CardContent className=\"p-4\">\n <TagField\n entityType=\"brainyrich-goal\"\n entityId={goal.id}\n label={translate('brainyrich.goals.detail.tags', 'Tags')}\n />\n </CardContent>\n </Card>\n\n {/* Recalc projection */}\n <section className=\"space-y-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.goals.detail.recalcTitle', 'Recalculate projection')}\n </h3>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"recalc-funded\">\n {translate('brainyrich.goals.detail.fundedAmount', 'Funded amount')}\n </Label>\n <Input\n id=\"recalc-funded\"\n type=\"number\"\n min={0}\n step=\"0.01\"\n value={fundedAmount}\n placeholder={String(fixedFunded)}\n onChange={(e) => setFundedAmount(e.target.value)}\n />\n <p className=\"text-xs text-text-secondary\">\n {translate(\n 'brainyrich.goals.detail.recalcHint',\n 'Defaults to the sum of fixed fundings when left blank.'\n )}\n </p>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n disabled={recalc.isPending}\n onClick={handleRecalc}\n >\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n {recalc.isPending\n ? translate('brainyrich.goals.detail.recalculating', 'Recalculating…')\n : translate('brainyrich.goals.detail.recalc', 'Recalculate')}\n </Button>\n </section>\n </>\n )}\n </div>\n </SheetContent>\n </Sheet>\n\n <ConfirmDialog\n open={Boolean(unlinking)}\n onOpenChange={(o) => {\n if (!o) setUnlinking(null);\n }}\n title={translate('brainyrich.goals.detail.unlinkTitle', 'Unlink funding?')}\n description={translate(\n 'brainyrich.goals.detail.unlinkConfirm',\n 'This removes the “{name}” funding link from this goal.',\n { name: unlinkingLabel }\n )}\n confirmLabel={translate('brainyrich.goals.detail.unlink', 'Unlink funding')}\n pendingLabel={translate('brainyrich.goals.detail.unlinking', 'Unlinking…')}\n destructive\n pending={unlinkFunding.isPending}\n onConfirm={() => {\n if (!unlinking) return;\n unlinkFunding.mutate(unlinking.id, { onSuccess: () => setUnlinking(null) });\n }}\n />\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { BraAccount } from '../../types/bra';
|
|
3
|
+
export interface MobileAccountsViewProps {
|
|
4
|
+
totalCash: number;
|
|
5
|
+
accountCount: number;
|
|
6
|
+
currency: string;
|
|
7
|
+
/** Paged account list (same connection the desktop table renders). */
|
|
8
|
+
items: BraAccount[];
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
isError: boolean;
|
|
11
|
+
refetch: () => void;
|
|
12
|
+
hasMore: boolean;
|
|
13
|
+
loadMore: () => void;
|
|
14
|
+
isFetchingNextPage: boolean;
|
|
15
|
+
onCreate: () => void;
|
|
16
|
+
onOpen: (account: BraAccount) => void;
|
|
17
|
+
onEdit: (account: BraAccount) => void;
|
|
18
|
+
onArchive: (account: BraAccount) => void;
|
|
19
|
+
/** Institution linking / aggregation panel, shared with desktop. */
|
|
20
|
+
aggregation: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Phone accounts list per `br-48-mobile-accounts`: a total-cash hero, one
|
|
24
|
+
* card per account with a type chip and balance, and a floating "New account"
|
|
25
|
+
* button. Tapping a card opens the same account detail sheet as desktop.
|
|
26
|
+
*/
|
|
27
|
+
export declare function MobileAccountsView({ totalCash, accountCount, currency, items, isLoading, isError, refetch, hasMore, loadMore, isFetchingNextPage, onCreate, onOpen, onEdit, onArchive, aggregation, }: MobileAccountsViewProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
//# sourceMappingURL=MobileAccountsView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MobileAccountsView.d.ts","sourceRoot":"","sources":["../../../../src/brainyrich/pages/mobile/MobileAccountsView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAsBvC,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,iBAAiB,CAAC;AAmBlE,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,oEAAoE;IACpE,WAAW,EAAE,SAAS,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,SAAS,EACT,OAAO,EACP,OAAO,EACP,OAAO,EACP,QAAQ,EACR,kBAAkB,EAClB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACT,WAAW,GACZ,EAAE,uBAAuB,2CAkHzB"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { LoadMore as e } from "../../components/LoadMore.js";
|
|
2
|
+
import { GlassCard as t } from "../../components/viz.js";
|
|
3
|
+
import "../../components/index.js";
|
|
4
|
+
import { EmptyState as n, ErrorState as r, LoadingState as i, formatMoney as a } from "../_shared.js";
|
|
5
|
+
import { cn as o } from "../../utils/cn.js";
|
|
6
|
+
import { MobileFab as s, MobilePage as c } from "../../components/mobile/MobilePage.js";
|
|
7
|
+
import "../../components/mobile/index.js";
|
|
8
|
+
import { MobileCard as l, accountTypeChipClass as u } from "./mobileShared.js";
|
|
9
|
+
import { Archive as d, Banknote as f, Bitcoin as p, Building as m, CreditCard as h, Gem as g, Landmark as _, MoreHorizontal as v, Pencil as y, Plus as b, Receipt as x, Wallet as S } from "lucide-react";
|
|
10
|
+
import { jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
11
|
+
import { Button as T, DropdownMenu as E, DropdownMenuContent as D, DropdownMenuItem as O, DropdownMenuTrigger as k } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
//#region src/brainyrich/pages/mobile/MobileAccountsView.tsx
|
|
13
|
+
var A = {
|
|
14
|
+
BANK: h,
|
|
15
|
+
BROKERAGE: S,
|
|
16
|
+
RETIREMENT: _,
|
|
17
|
+
CASH: f,
|
|
18
|
+
CRYPTO: p,
|
|
19
|
+
REAL_ESTATE: m,
|
|
20
|
+
ALTERNATIVE: g,
|
|
21
|
+
LIABILITY: x
|
|
22
|
+
};
|
|
23
|
+
function j({ totalCash: f, accountCount: p, currency: m, items: h, isLoading: g, isError: x, refetch: j, hasMore: M, loadMore: N, isFetchingNextPage: P, onCreate: F, onOpen: I, onEdit: L, onArchive: R, aggregation: z }) {
|
|
24
|
+
return /* @__PURE__ */ w(c, {
|
|
25
|
+
tourId: "brainyrich-page-accounts",
|
|
26
|
+
title: "Accounts",
|
|
27
|
+
subtitle: `${p} account${p === 1 ? "" : "s"}`,
|
|
28
|
+
fab: /* @__PURE__ */ C(s, {
|
|
29
|
+
label: "New account",
|
|
30
|
+
icon: /* @__PURE__ */ C(b, {
|
|
31
|
+
className: "size-4",
|
|
32
|
+
"aria-hidden": "true"
|
|
33
|
+
}),
|
|
34
|
+
onClick: F
|
|
35
|
+
}),
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ w(t, {
|
|
38
|
+
glow: !0,
|
|
39
|
+
className: "p-5",
|
|
40
|
+
children: [/* @__PURE__ */ C("p", {
|
|
41
|
+
className: "text-sm text-text-secondary",
|
|
42
|
+
children: "Total cash"
|
|
43
|
+
}), /* @__PURE__ */ C("p", {
|
|
44
|
+
className: "mt-1 text-3xl font-semibold tracking-tight text-text-primary",
|
|
45
|
+
"data-testid": "brainyrich-mobile-total-cash",
|
|
46
|
+
children: a(f, m)
|
|
47
|
+
})]
|
|
48
|
+
}),
|
|
49
|
+
g ? /* @__PURE__ */ C(i, {}) : x ? /* @__PURE__ */ C(r, { onRetry: j }) : h.length === 0 ? /* @__PURE__ */ C(n, {
|
|
50
|
+
icon: /* @__PURE__ */ C(_, {
|
|
51
|
+
className: "size-6",
|
|
52
|
+
"aria-hidden": "true"
|
|
53
|
+
}),
|
|
54
|
+
title: "No accounts yet",
|
|
55
|
+
description: "Add your first bank, brokerage or retirement account to start tracking net worth."
|
|
56
|
+
}) : /* @__PURE__ */ C("ul", {
|
|
57
|
+
className: "space-y-3",
|
|
58
|
+
"aria-label": "Accounts",
|
|
59
|
+
children: h.map((e) => {
|
|
60
|
+
let t = A[e.type] ?? S;
|
|
61
|
+
return /* @__PURE__ */ C("li", { children: /* @__PURE__ */ w(l, {
|
|
62
|
+
className: "flex items-center gap-3 p-3",
|
|
63
|
+
children: [/* @__PURE__ */ w("button", {
|
|
64
|
+
type: "button",
|
|
65
|
+
onClick: () => I(e),
|
|
66
|
+
className: "flex min-h-14 min-w-0 flex-1 items-center gap-3 text-left",
|
|
67
|
+
"aria-label": `Open ${e.name}`,
|
|
68
|
+
children: [/* @__PURE__ */ C("span", {
|
|
69
|
+
"aria-hidden": "true",
|
|
70
|
+
className: "flex size-12 shrink-0 items-center justify-center rounded-xl bg-bg-sunken text-text-secondary",
|
|
71
|
+
children: /* @__PURE__ */ C(t, { className: "size-5" })
|
|
72
|
+
}), /* @__PURE__ */ w("span", {
|
|
73
|
+
className: "min-w-0 flex-1",
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ C("span", {
|
|
76
|
+
className: "block truncate text-sm font-medium text-text-primary",
|
|
77
|
+
children: e.name
|
|
78
|
+
}),
|
|
79
|
+
/* @__PURE__ */ w("span", {
|
|
80
|
+
className: "mt-1 flex flex-wrap items-center gap-2",
|
|
81
|
+
children: [/* @__PURE__ */ C("span", {
|
|
82
|
+
className: o("rounded-md px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide", u(e.type)),
|
|
83
|
+
children: e.type.replace(/_/g, " ")
|
|
84
|
+
}), e.status === "ACTIVE" ? null : /* @__PURE__ */ C("span", {
|
|
85
|
+
className: "text-[10px] uppercase tracking-wide text-text-secondary",
|
|
86
|
+
children: e.status
|
|
87
|
+
})]
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ C("span", {
|
|
90
|
+
className: "mt-1 block text-lg font-semibold tabular-nums text-text-primary",
|
|
91
|
+
children: a(e.cashBalance, e.currency)
|
|
92
|
+
})
|
|
93
|
+
]
|
|
94
|
+
})]
|
|
95
|
+
}), /* @__PURE__ */ w(E, { children: [/* @__PURE__ */ C(k, {
|
|
96
|
+
asChild: !0,
|
|
97
|
+
children: /* @__PURE__ */ C(T, {
|
|
98
|
+
variant: "ghost",
|
|
99
|
+
size: "icon",
|
|
100
|
+
className: "size-11 shrink-0",
|
|
101
|
+
"aria-label": `Actions for ${e.name}`,
|
|
102
|
+
children: /* @__PURE__ */ C(v, {
|
|
103
|
+
className: "size-4",
|
|
104
|
+
"aria-hidden": "true"
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
}), /* @__PURE__ */ w(D, {
|
|
108
|
+
align: "end",
|
|
109
|
+
children: [/* @__PURE__ */ w(O, {
|
|
110
|
+
onClick: () => L(e),
|
|
111
|
+
children: [/* @__PURE__ */ C(y, {
|
|
112
|
+
className: "size-4",
|
|
113
|
+
"aria-hidden": "true"
|
|
114
|
+
}), "Edit"]
|
|
115
|
+
}), /* @__PURE__ */ w(O, {
|
|
116
|
+
className: "text-status-error-text",
|
|
117
|
+
onClick: () => R(e),
|
|
118
|
+
children: [/* @__PURE__ */ C(d, {
|
|
119
|
+
className: "size-4",
|
|
120
|
+
"aria-hidden": "true"
|
|
121
|
+
}), "Archive"]
|
|
122
|
+
})]
|
|
123
|
+
})] })]
|
|
124
|
+
}) }, e.id);
|
|
125
|
+
})
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ C(e, {
|
|
128
|
+
hasMore: M,
|
|
129
|
+
onClick: N,
|
|
130
|
+
loading: P
|
|
131
|
+
}),
|
|
132
|
+
z
|
|
133
|
+
]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
export { j as MobileAccountsView };
|
|
138
|
+
|
|
139
|
+
//# sourceMappingURL=MobileAccountsView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MobileAccountsView.js","names":[],"sources":["../../../../src/brainyrich/pages/mobile/MobileAccountsView.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Archive as ArchiveIcon,\n Banknote,\n Bitcoin,\n Building,\n CreditCard,\n Gem,\n Landmark,\n MoreHorizontal,\n Pencil,\n Plus,\n Receipt,\n Wallet,\n} from 'lucide-react';\nimport type { BraAccount, BraAccountType } from '../../types/bra';\nimport { GlassCard } from '../../components/viz';\nimport { LoadMore } from '../../components';\nimport { MobileFab, MobilePage } from '../../components/mobile';\nimport { cn } from '../../utils/cn';\nimport { EmptyState, ErrorState, LoadingState, formatMoney } from '../_shared';\nimport { MobileCard, accountTypeChipClass } from './mobileShared';\n\nconst TYPE_ICON: Record<BraAccountType, typeof Wallet> = {\n BANK: CreditCard,\n BROKERAGE: Wallet,\n RETIREMENT: Landmark,\n CASH: Banknote,\n CRYPTO: Bitcoin,\n REAL_ESTATE: Building,\n ALTERNATIVE: Gem,\n LIABILITY: Receipt,\n};\n\nexport interface MobileAccountsViewProps {\n totalCash: number;\n accountCount: number;\n currency: string;\n /** Paged account list (same connection the desktop table renders). */\n items: BraAccount[];\n isLoading: boolean;\n isError: boolean;\n refetch: () => void;\n hasMore: boolean;\n loadMore: () => void;\n isFetchingNextPage: boolean;\n onCreate: () => void;\n onOpen: (account: BraAccount) => void;\n onEdit: (account: BraAccount) => void;\n onArchive: (account: BraAccount) => void;\n /** Institution linking / aggregation panel, shared with desktop. */\n aggregation: ReactNode;\n}\n\n/**\n * Phone accounts list per `br-48-mobile-accounts`: a total-cash hero, one\n * card per account with a type chip and balance, and a floating \"New account\"\n * button. Tapping a card opens the same account detail sheet as desktop.\n */\nexport function MobileAccountsView({\n totalCash,\n accountCount,\n currency,\n items,\n isLoading,\n isError,\n refetch,\n hasMore,\n loadMore,\n isFetchingNextPage,\n onCreate,\n onOpen,\n onEdit,\n onArchive,\n aggregation,\n}: MobileAccountsViewProps) {\n return (\n <MobilePage\n tourId=\"brainyrich-page-accounts\"\n title=\"Accounts\"\n subtitle={`${accountCount} account${accountCount === 1 ? '' : 's'}`}\n fab={\n <MobileFab\n label=\"New account\"\n icon={<Plus className=\"size-4\" aria-hidden=\"true\" />}\n onClick={onCreate}\n />\n }\n >\n <GlassCard glow className=\"p-5\">\n <p className=\"text-sm text-text-secondary\">Total cash</p>\n <p\n className=\"mt-1 text-3xl font-semibold tracking-tight text-text-primary\"\n data-testid=\"brainyrich-mobile-total-cash\"\n >\n {formatMoney(totalCash, currency)}\n </p>\n </GlassCard>\n\n {isLoading ? (\n <LoadingState />\n ) : isError ? (\n <ErrorState onRetry={refetch} />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<Landmark className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No accounts yet\"\n description=\"Add your first bank, brokerage or retirement account to start tracking net worth.\"\n />\n ) : (\n <ul className=\"space-y-3\" aria-label=\"Accounts\">\n {items.map((account) => {\n const Icon = TYPE_ICON[account.type] ?? Wallet;\n return (\n <li key={account.id}>\n <MobileCard className=\"flex items-center gap-3 p-3\">\n <button\n type=\"button\"\n onClick={() => onOpen(account)}\n className=\"flex min-h-14 min-w-0 flex-1 items-center gap-3 text-left\"\n aria-label={`Open ${account.name}`}\n >\n <span\n aria-hidden=\"true\"\n className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-bg-sunken text-text-secondary\"\n >\n <Icon className=\"size-5\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">\n {account.name}\n </span>\n <span className=\"mt-1 flex flex-wrap items-center gap-2\">\n <span\n className={cn(\n 'rounded-md px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide',\n accountTypeChipClass(account.type)\n )}\n >\n {account.type.replace(/_/g, ' ')}\n </span>\n {account.status !== 'ACTIVE' ? (\n <span className=\"text-[10px] uppercase tracking-wide text-text-secondary\">\n {account.status}\n </span>\n ) : null}\n </span>\n <span className=\"mt-1 block text-lg font-semibold tabular-nums text-text-primary\">\n {formatMoney(account.cashBalance, account.currency)}\n </span>\n </span>\n </button>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-11 shrink-0\"\n aria-label={`Actions for ${account.name}`}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => onEdit(account)}>\n <Pencil className=\"size-4\" aria-hidden=\"true\" />\n Edit\n </DropdownMenuItem>\n <DropdownMenuItem\n className=\"text-status-error-text\"\n onClick={() => onArchive(account)}\n >\n <ArchiveIcon className=\"size-4\" aria-hidden=\"true\" />\n Archive\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </MobileCard>\n </li>\n );\n })}\n </ul>\n )}\n\n <LoadMore hasMore={hasMore} onClick={loadMore} loading={isFetchingNextPage} />\n\n {aggregation}\n </MobilePage>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { BraGoal, BraInsight, BraNetWorthSummary, BraPortfolio } from '../../types/bra';
|
|
3
|
+
import { DonutDatum } from '../../components/viz';
|
|
4
|
+
import { MobileQueryState, Translate } from './mobileShared';
|
|
5
|
+
export interface MobileDashboardViewProps {
|
|
6
|
+
translate: Translate;
|
|
7
|
+
summary: MobileQueryState<BraNetWorthSummary | null | undefined>;
|
|
8
|
+
/** Positive allocation slices, computed by the page so both layouts agree. */
|
|
9
|
+
allocation: DonutDatum[];
|
|
10
|
+
insights: MobileQueryState<BraInsight[]>;
|
|
11
|
+
goals: MobileQueryState<BraGoal[]>;
|
|
12
|
+
portfolios: MobileQueryState<BraPortfolio[]>;
|
|
13
|
+
/** Renders one open insight with its acknowledge / resolve / dismiss actions. */
|
|
14
|
+
renderInsight: (insight: BraInsight) => ReactNode;
|
|
15
|
+
/** App-bar action that opens the new-account dialog. */
|
|
16
|
+
newAccountAction: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Phone dashboard per `br-47-mobile-dashboard`: net-worth hero, condensed
|
|
20
|
+
* invested / cash KPIs, allocation mini-chart, the attention list and a
|
|
21
|
+
* horizontally scrolling strip of goal cards.
|
|
22
|
+
*/
|
|
23
|
+
export declare function MobileDashboardView({ translate, summary, allocation, insights, goals, portfolios, renderInsight, newAccountAction, }: MobileDashboardViewProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
//# sourceMappingURL=MobileDashboardView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MobileDashboardView.d.ts","sourceRoot":"","sources":["../../../../src/brainyrich/pages/mobile/MobileDashboardView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAgB9B,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACjE,8EAA8E;IAC9E,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,KAAK,EAAE,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IACnC,UAAU,EAAE,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC;IAC7C,iFAAiF;IACjF,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,SAAS,CAAC;IAClD,wDAAwD;IACxD,gBAAgB,EAAE,SAAS,CAAC;CAC7B;AAOD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,OAAO,EACP,UAAU,EACV,QAAQ,EACR,KAAK,EACL,UAAU,EACV,aAAa,EACb,gBAAgB,GACjB,EAAE,wBAAwB,2CAqR1B"}
|