@burdenoff/microfe-brainyrich 2026.1101.1 → 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 +223 -177
- 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/ReportsPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/ReportsPage.js +145 -151
- package/dist/brainyrich/pages/ReportsPage.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/pages/reports-csv.d.ts +2 -0
- package/dist/brainyrich/pages/reports-csv.d.ts.map +1 -0
- package/dist/brainyrich/pages/reports-csv.js +14 -0
- package/dist/brainyrich/pages/reports-csv.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
|
@@ -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"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { useBrainyRich as e } from "../../providers/BrainyRichProvider.js";
|
|
2
|
+
import { DonutChart as t, GlassCard as n, ProgressRing as r, useVizColors as i } from "../../components/viz.js";
|
|
3
|
+
import { EmptyState as a, ErrorState as o, LoadingState as s, formatCompact as c, formatDate as l, formatMoney as u, formatPct as d, statusBadgeVariant as f } from "../_shared.js";
|
|
4
|
+
import { cn as p } from "../../utils/cn.js";
|
|
5
|
+
import { goalDetailPath as m, sectionPath as h } from "../../navItems.js";
|
|
6
|
+
import { MobilePage as g } from "../../components/mobile/MobilePage.js";
|
|
7
|
+
import "../../components/mobile/index.js";
|
|
8
|
+
import { fundedPercent as _, goalTone as v } from "../../utils/goalMetrics.js";
|
|
9
|
+
import { MobileCard as y, projectionChipClass as b } from "./mobileShared.js";
|
|
10
|
+
import { ChevronRight as x, CircleCheck as S, Coins as C, Target as w, TrendingUp as T, Wallet as E } from "lucide-react";
|
|
11
|
+
import { useNavigate as D } from "react-router";
|
|
12
|
+
import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
13
|
+
import { Badge as j } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
//#region src/brainyrich/pages/mobile/MobileDashboardView.tsx
|
|
15
|
+
function M(e) {
|
|
16
|
+
let t = e.replace(/_/g, " ").toLowerCase();
|
|
17
|
+
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
18
|
+
}
|
|
19
|
+
function N({ translate: N, summary: P, allocation: F, insights: I, goals: L, portfolios: R, renderInsight: z, newAccountAction: B }) {
|
|
20
|
+
let V = D(), { basePath: H = "/" } = e(), U = i(), W = P.data, G = W?.currency ?? "USD", K = F.reduce((e, t) => e + t.value, 0), q = I.data.slice(0, 3), J = L.data.slice(0, 8), Y = R.data.slice(0, 3), X = (e, t) => /* @__PURE__ */ A("button", {
|
|
21
|
+
type: "button",
|
|
22
|
+
onClick: () => V(t),
|
|
23
|
+
className: "inline-flex min-h-11 items-center gap-0.5 text-xs font-medium text-text-secondary hover:text-text-primary",
|
|
24
|
+
children: [e, /* @__PURE__ */ k(x, {
|
|
25
|
+
className: "size-3.5",
|
|
26
|
+
"aria-hidden": "true"
|
|
27
|
+
})]
|
|
28
|
+
});
|
|
29
|
+
return /* @__PURE__ */ A(g, {
|
|
30
|
+
tourId: "brainyrich-page-dashboard",
|
|
31
|
+
title: N("brainyrich.dashboard.title", "Wealth Dashboard"),
|
|
32
|
+
subtitle: N("brainyrich.mobile.dashboard.subtitle", "Your wealth at a glance"),
|
|
33
|
+
brandMark: !0,
|
|
34
|
+
action: B,
|
|
35
|
+
children: [
|
|
36
|
+
P.isLoading ? /* @__PURE__ */ k(s, { rows: 2 }) : P.isError ? /* @__PURE__ */ k(o, {
|
|
37
|
+
title: N("brainyrich.dashboard.netWorthError", "Could not load net worth"),
|
|
38
|
+
onRetry: P.refetch
|
|
39
|
+
}) : W ? /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ A(n, {
|
|
40
|
+
glow: !0,
|
|
41
|
+
className: "p-5",
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ A("div", {
|
|
44
|
+
className: "flex items-start justify-between gap-2",
|
|
45
|
+
children: [/* @__PURE__ */ k("p", {
|
|
46
|
+
className: "text-sm text-text-secondary",
|
|
47
|
+
children: N("brainyrich.dashboard.metrics.netWorth", "Net Worth")
|
|
48
|
+
}), /* @__PURE__ */ k(E, {
|
|
49
|
+
className: "size-4 text-text-secondary",
|
|
50
|
+
"aria-hidden": "true"
|
|
51
|
+
})]
|
|
52
|
+
}),
|
|
53
|
+
/* @__PURE__ */ k("p", {
|
|
54
|
+
className: "mt-1 text-4xl font-semibold tracking-tight text-text-primary",
|
|
55
|
+
"data-testid": "brainyrich-mobile-networth",
|
|
56
|
+
children: c(W.totalNetWorth, G)
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ k("p", {
|
|
59
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
60
|
+
children: N("brainyrich.mobile.dashboard.accountsLinked", "{{count}} linked accounts", { count: W.accountCount })
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
}), /* @__PURE__ */ A("div", {
|
|
64
|
+
className: "grid grid-cols-2 gap-3",
|
|
65
|
+
children: [/* @__PURE__ */ A(y, { children: [/* @__PURE__ */ A("div", {
|
|
66
|
+
className: "flex items-center gap-1.5 text-xs text-text-secondary",
|
|
67
|
+
children: [/* @__PURE__ */ k(T, {
|
|
68
|
+
className: "size-3.5",
|
|
69
|
+
"aria-hidden": "true"
|
|
70
|
+
}), N("brainyrich.mobile.dashboard.invested", "Invested")]
|
|
71
|
+
}), /* @__PURE__ */ k("p", {
|
|
72
|
+
className: "mt-1 text-xl font-semibold text-text-primary",
|
|
73
|
+
children: c(W.totalMarketValue, G)
|
|
74
|
+
})] }), /* @__PURE__ */ A(y, { children: [/* @__PURE__ */ A("div", {
|
|
75
|
+
className: "flex items-center gap-1.5 text-xs text-text-secondary",
|
|
76
|
+
children: [/* @__PURE__ */ k(C, {
|
|
77
|
+
className: "size-3.5",
|
|
78
|
+
"aria-hidden": "true"
|
|
79
|
+
}), N("brainyrich.mobile.dashboard.cash", "Cash")]
|
|
80
|
+
}), /* @__PURE__ */ k("p", {
|
|
81
|
+
className: "mt-1 text-xl font-semibold text-text-primary",
|
|
82
|
+
children: c(W.totalCash, G)
|
|
83
|
+
})] })]
|
|
84
|
+
})] }) : /* @__PURE__ */ k(a, {
|
|
85
|
+
icon: /* @__PURE__ */ k(E, {
|
|
86
|
+
className: "size-6",
|
|
87
|
+
"aria-hidden": "true"
|
|
88
|
+
}),
|
|
89
|
+
title: N("brainyrich.dashboard.noSummary", "No financial data yet"),
|
|
90
|
+
description: N("brainyrich.dashboard.noSummaryDesc", "Link your first account to see your net worth here.")
|
|
91
|
+
}),
|
|
92
|
+
!P.isLoading && !P.isError && F.length > 0 ? /* @__PURE__ */ A(y, { children: [/* @__PURE__ */ k("h2", {
|
|
93
|
+
className: "text-sm font-semibold text-text-primary",
|
|
94
|
+
children: N("brainyrich.dashboard.sections.positiveAssetAllocation", "Asset allocation")
|
|
95
|
+
}), /* @__PURE__ */ A("div", {
|
|
96
|
+
className: "mt-3 flex items-center gap-4",
|
|
97
|
+
children: [/* @__PURE__ */ k("div", {
|
|
98
|
+
className: "w-28 shrink-0",
|
|
99
|
+
children: /* @__PURE__ */ k(t, {
|
|
100
|
+
data: F,
|
|
101
|
+
legend: !1,
|
|
102
|
+
height: 112,
|
|
103
|
+
valueFormatter: (e) => u(e, G)
|
|
104
|
+
})
|
|
105
|
+
}), /* @__PURE__ */ k("ul", {
|
|
106
|
+
className: "min-w-0 flex-1 space-y-1.5",
|
|
107
|
+
"aria-label": N("brainyrich.dashboard.allocationLegend", "Allocation legend"),
|
|
108
|
+
children: F.map((e, t) => /* @__PURE__ */ A("li", {
|
|
109
|
+
className: "flex items-center gap-2 text-xs",
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ k("span", {
|
|
112
|
+
"aria-hidden": "true",
|
|
113
|
+
className: "size-2 shrink-0 rounded-full",
|
|
114
|
+
style: { background: e.tone ? U.tone(e.tone) : U.palette[t % U.palette.length] }
|
|
115
|
+
}),
|
|
116
|
+
/* @__PURE__ */ k("span", {
|
|
117
|
+
className: "truncate text-text-secondary",
|
|
118
|
+
children: e.label
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ k("span", {
|
|
121
|
+
className: "ml-auto font-medium tabular-nums text-text-primary",
|
|
122
|
+
children: d(K > 0 ? e.value / K * 100 : 0, 0)
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
}, e.label))
|
|
126
|
+
})]
|
|
127
|
+
})] }) : null,
|
|
128
|
+
/* @__PURE__ */ A("section", {
|
|
129
|
+
"aria-labelledby": "br-mobile-attention",
|
|
130
|
+
className: "space-y-2",
|
|
131
|
+
children: [/* @__PURE__ */ k("h2", {
|
|
132
|
+
id: "br-mobile-attention",
|
|
133
|
+
className: "text-sm font-semibold text-text-primary",
|
|
134
|
+
children: N("brainyrich.dashboard.sections.needsAttention", "Needs attention")
|
|
135
|
+
}), I.isLoading ? /* @__PURE__ */ k(s, { rows: 2 }) : I.isError ? /* @__PURE__ */ k(o, { onRetry: I.refetch }) : q.length > 0 ? /* @__PURE__ */ k("div", {
|
|
136
|
+
className: "space-y-2",
|
|
137
|
+
children: q.map((e) => /* @__PURE__ */ k("div", { children: z(e) }, e.id))
|
|
138
|
+
}) : /* @__PURE__ */ A(y, {
|
|
139
|
+
className: "flex items-center gap-3",
|
|
140
|
+
children: [/* @__PURE__ */ k(S, {
|
|
141
|
+
className: "size-5 text-status-success-text",
|
|
142
|
+
"aria-hidden": "true"
|
|
143
|
+
}), /* @__PURE__ */ k("p", {
|
|
144
|
+
className: "text-sm text-text-secondary",
|
|
145
|
+
children: N("brainyrich.dashboard.noInsightsDesc", "There are no open insights that need your attention.")
|
|
146
|
+
})]
|
|
147
|
+
})]
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ A("section", {
|
|
150
|
+
"aria-labelledby": "br-mobile-goals",
|
|
151
|
+
className: "space-y-2",
|
|
152
|
+
children: [/* @__PURE__ */ A("div", {
|
|
153
|
+
className: "flex items-center justify-between",
|
|
154
|
+
children: [/* @__PURE__ */ k("h2", {
|
|
155
|
+
id: "br-mobile-goals",
|
|
156
|
+
className: "text-sm font-semibold text-text-primary",
|
|
157
|
+
children: N("brainyrich.dashboard.sections.goals", "Goals on track")
|
|
158
|
+
}), J.length > 0 ? X(N("brainyrich.mobile.seeAll", "See all"), h(H, "brainyrich-goals")) : null]
|
|
159
|
+
}), L.isLoading ? /* @__PURE__ */ k(s, { rows: 1 }) : L.isError ? /* @__PURE__ */ k(o, { onRetry: L.refetch }) : J.length > 0 ? /* @__PURE__ */ k("ul", {
|
|
160
|
+
className: "-mx-1 flex snap-x snap-mandatory gap-3 overflow-x-auto px-1 pb-1",
|
|
161
|
+
"aria-label": N("brainyrich.dashboard.sections.goals", "Goals on track"),
|
|
162
|
+
children: J.map((e) => /* @__PURE__ */ k("li", {
|
|
163
|
+
className: "w-40 shrink-0 snap-start",
|
|
164
|
+
children: /* @__PURE__ */ A("button", {
|
|
165
|
+
type: "button",
|
|
166
|
+
onClick: () => V(m(H, e.id)),
|
|
167
|
+
className: "flex h-full w-full flex-col items-start gap-2 rounded-2xl border border-border-subtle bg-bg-surface p-3 text-left motion-safe:transition-colors hover:bg-bg-elevated",
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ k(r, {
|
|
170
|
+
value: _(e),
|
|
171
|
+
tone: v(e.status, e.projection),
|
|
172
|
+
size: 52,
|
|
173
|
+
strokeWidth: 6,
|
|
174
|
+
label: N("brainyrich.goals.card.funded", "funded")
|
|
175
|
+
}),
|
|
176
|
+
/* @__PURE__ */ k("p", {
|
|
177
|
+
className: "w-full truncate text-sm font-medium text-text-primary",
|
|
178
|
+
children: e.name
|
|
179
|
+
}),
|
|
180
|
+
/* @__PURE__ */ k("span", {
|
|
181
|
+
className: p("rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide", b(e)),
|
|
182
|
+
children: e.status === "ACHIEVED" ? M(e.status) : M(e.projection)
|
|
183
|
+
}),
|
|
184
|
+
/* @__PURE__ */ A("p", {
|
|
185
|
+
className: "text-xs text-text-secondary",
|
|
186
|
+
children: [
|
|
187
|
+
c(e.targetAmount, e.currency),
|
|
188
|
+
" ·",
|
|
189
|
+
" ",
|
|
190
|
+
l(e.targetDate)
|
|
191
|
+
]
|
|
192
|
+
})
|
|
193
|
+
]
|
|
194
|
+
})
|
|
195
|
+
}, e.id))
|
|
196
|
+
}) : /* @__PURE__ */ k(a, {
|
|
197
|
+
icon: /* @__PURE__ */ k(w, {
|
|
198
|
+
className: "size-6",
|
|
199
|
+
"aria-hidden": "true"
|
|
200
|
+
}),
|
|
201
|
+
title: N("brainyrich.dashboard.noGoals", "No goals yet"),
|
|
202
|
+
description: N("brainyrich.dashboard.noGoalsDesc", "Set a financial goal to start tracking progress.")
|
|
203
|
+
})]
|
|
204
|
+
}),
|
|
205
|
+
!R.isLoading && (R.isError || Y.length > 0) ? /* @__PURE__ */ A("section", {
|
|
206
|
+
"aria-labelledby": "br-mobile-portfolios",
|
|
207
|
+
className: "space-y-2",
|
|
208
|
+
children: [/* @__PURE__ */ A("div", {
|
|
209
|
+
className: "flex items-center justify-between",
|
|
210
|
+
children: [/* @__PURE__ */ k("h2", {
|
|
211
|
+
id: "br-mobile-portfolios",
|
|
212
|
+
className: "text-sm font-semibold text-text-primary",
|
|
213
|
+
children: N("brainyrich.dashboard.sections.portfolios", "Portfolios")
|
|
214
|
+
}), X(N("brainyrich.mobile.seeAll", "See all"), h(H, "brainyrich-portfolios"))]
|
|
215
|
+
}), R.isError ? /* @__PURE__ */ k(o, {
|
|
216
|
+
title: N("brainyrich.dashboard.portfoliosError", "Could not load portfolios"),
|
|
217
|
+
onRetry: R.refetch
|
|
218
|
+
}) : /* @__PURE__ */ k("div", {
|
|
219
|
+
className: "space-y-2",
|
|
220
|
+
children: Y.map((e) => /* @__PURE__ */ A(y, {
|
|
221
|
+
className: "flex items-center justify-between gap-3",
|
|
222
|
+
children: [/* @__PURE__ */ A("div", {
|
|
223
|
+
className: "min-w-0",
|
|
224
|
+
children: [/* @__PURE__ */ k("p", {
|
|
225
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
226
|
+
children: e.name
|
|
227
|
+
}), /* @__PURE__ */ k("p", {
|
|
228
|
+
className: "truncate text-xs text-text-secondary",
|
|
229
|
+
children: e.description ?? e.baseCurrency
|
|
230
|
+
})]
|
|
231
|
+
}), /* @__PURE__ */ k(j, {
|
|
232
|
+
variant: f(e.status),
|
|
233
|
+
className: "shrink-0",
|
|
234
|
+
children: e.status
|
|
235
|
+
})]
|
|
236
|
+
}, e.id))
|
|
237
|
+
})]
|
|
238
|
+
}) : null
|
|
239
|
+
]
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
//#endregion
|
|
243
|
+
export { N as MobileDashboardView };
|
|
244
|
+
|
|
245
|
+
//# sourceMappingURL=MobileDashboardView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MobileDashboardView.js","names":[],"sources":["../../../../src/brainyrich/pages/mobile/MobileDashboardView.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { ChevronRight, CircleCheck, Coins, Target, TrendingUp, Wallet } from 'lucide-react';\nimport type { BraGoal, BraInsight, BraNetWorthSummary, BraPortfolio } from '../../types/bra';\nimport {\n DonutChart,\n GlassCard,\n ProgressRing,\n useVizColors,\n type DonutDatum,\n} from '../../components/viz';\nimport { MobilePage } from '../../components/mobile';\nimport { useBrainyRich } from '../../providers/BrainyRichProvider';\nimport { goalDetailPath, sectionPath } from '../../navItems';\nimport { fundedPercent, goalTone } from '../../utils/goalMetrics';\nimport { cn } from '../../utils/cn';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n formatCompact,\n formatDate,\n formatMoney,\n formatPct,\n statusBadgeVariant,\n} from '../_shared';\nimport {\n MobileCard,\n projectionChipClass,\n type MobileQueryState,\n type Translate,\n} from './mobileShared';\n\nexport interface MobileDashboardViewProps {\n translate: Translate;\n summary: MobileQueryState<BraNetWorthSummary | null | undefined>;\n /** Positive allocation slices, computed by the page so both layouts agree. */\n allocation: DonutDatum[];\n insights: MobileQueryState<BraInsight[]>;\n goals: MobileQueryState<BraGoal[]>;\n portfolios: MobileQueryState<BraPortfolio[]>;\n /** Renders one open insight with its acknowledge / resolve / dismiss actions. */\n renderInsight: (insight: BraInsight) => ReactNode;\n /** App-bar action that opens the new-account dialog. */\n newAccountAction: ReactNode;\n}\n\nfunction prettyLabel(value: string): string {\n const spaced = value.replace(/_/g, ' ').toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/**\n * Phone dashboard per `br-47-mobile-dashboard`: net-worth hero, condensed\n * invested / cash KPIs, allocation mini-chart, the attention list and a\n * horizontally scrolling strip of goal cards.\n */\nexport function MobileDashboardView({\n translate,\n summary,\n allocation,\n insights,\n goals,\n portfolios,\n renderInsight,\n newAccountAction,\n}: MobileDashboardViewProps) {\n const navigate = useNavigate();\n const { basePath = '/' } = useBrainyRich();\n const colors = useVizColors();\n const data = summary.data;\n const currency = data?.currency ?? 'USD';\n const allocationTotal = allocation.reduce((sum, row) => sum + row.value, 0);\n const topInsights = insights.data.slice(0, 3);\n const topGoals = goals.data.slice(0, 8);\n const topPortfolios = portfolios.data.slice(0, 3);\n\n const seeAll = (label: string, target: string) => (\n <button\n type=\"button\"\n onClick={() => navigate(target)}\n className=\"inline-flex min-h-11 items-center gap-0.5 text-xs font-medium text-text-secondary hover:text-text-primary\"\n >\n {label}\n <ChevronRight className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n );\n\n return (\n <MobilePage\n tourId=\"brainyrich-page-dashboard\"\n title={translate('brainyrich.dashboard.title', 'Wealth Dashboard')}\n subtitle={translate('brainyrich.mobile.dashboard.subtitle', 'Your wealth at a glance')}\n brandMark\n action={newAccountAction}\n >\n {/* Net worth hero + condensed KPIs */}\n {summary.isLoading ? (\n <LoadingState rows={2} />\n ) : summary.isError ? (\n <ErrorState\n title={translate('brainyrich.dashboard.netWorthError', 'Could not load net worth')}\n onRetry={summary.refetch}\n />\n ) : data ? (\n <>\n <GlassCard glow className=\"p-5\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm text-text-secondary\">\n {translate('brainyrich.dashboard.metrics.netWorth', 'Net Worth')}\n </p>\n <Wallet className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n </div>\n <p\n className=\"mt-1 text-4xl font-semibold tracking-tight text-text-primary\"\n data-testid=\"brainyrich-mobile-networth\"\n >\n {formatCompact(data.totalNetWorth, currency)}\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {translate(\n 'brainyrich.mobile.dashboard.accountsLinked',\n '{{count}} linked accounts',\n {\n count: data.accountCount,\n }\n )}\n </p>\n </GlassCard>\n <div className=\"grid grid-cols-2 gap-3\">\n <MobileCard>\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <TrendingUp className=\"size-3.5\" aria-hidden=\"true\" />\n {translate('brainyrich.mobile.dashboard.invested', 'Invested')}\n </div>\n <p className=\"mt-1 text-xl font-semibold text-text-primary\">\n {formatCompact(data.totalMarketValue, currency)}\n </p>\n </MobileCard>\n <MobileCard>\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Coins className=\"size-3.5\" aria-hidden=\"true\" />\n {translate('brainyrich.mobile.dashboard.cash', 'Cash')}\n </div>\n <p className=\"mt-1 text-xl font-semibold text-text-primary\">\n {formatCompact(data.totalCash, currency)}\n </p>\n </MobileCard>\n </div>\n </>\n ) : (\n <EmptyState\n icon={<Wallet className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noSummary', 'No financial data yet')}\n description={translate(\n 'brainyrich.dashboard.noSummaryDesc',\n 'Link your first account to see your net worth here.'\n )}\n />\n )}\n\n {/* Allocation mini-chart */}\n {!summary.isLoading && !summary.isError && allocation.length > 0 ? (\n <MobileCard>\n <h2 className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.dashboard.sections.positiveAssetAllocation', 'Asset allocation')}\n </h2>\n <div className=\"mt-3 flex items-center gap-4\">\n <div className=\"w-28 shrink-0\">\n <DonutChart\n data={allocation}\n legend={false}\n height={112}\n valueFormatter={(v) => formatMoney(v, currency)}\n />\n </div>\n <ul\n className=\"min-w-0 flex-1 space-y-1.5\"\n aria-label={translate('brainyrich.dashboard.allocationLegend', 'Allocation legend')}\n >\n {allocation.map((row, i) => (\n <li key={row.label} className=\"flex items-center gap-2 text-xs\">\n <span\n aria-hidden=\"true\"\n className=\"size-2 shrink-0 rounded-full\"\n style={{\n background: row.tone\n ? colors.tone(row.tone)\n : colors.palette[i % colors.palette.length],\n }}\n />\n <span className=\"truncate text-text-secondary\">{row.label}</span>\n <span className=\"ml-auto font-medium tabular-nums text-text-primary\">\n {formatPct(allocationTotal > 0 ? (row.value / allocationTotal) * 100 : 0, 0)}\n </span>\n </li>\n ))}\n </ul>\n </div>\n </MobileCard>\n ) : null}\n\n {/* Needs attention */}\n <section aria-labelledby=\"br-mobile-attention\" className=\"space-y-2\">\n <h2 id=\"br-mobile-attention\" className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.dashboard.sections.needsAttention', 'Needs attention')}\n </h2>\n {insights.isLoading ? (\n <LoadingState rows={2} />\n ) : insights.isError ? (\n <ErrorState onRetry={insights.refetch} />\n ) : topInsights.length > 0 ? (\n <div className=\"space-y-2\">\n {topInsights.map((insight) => (\n <div key={insight.id}>{renderInsight(insight)}</div>\n ))}\n </div>\n ) : (\n <MobileCard className=\"flex items-center gap-3\">\n <CircleCheck className=\"size-5 text-status-success-text\" aria-hidden=\"true\" />\n <p className=\"text-sm text-text-secondary\">\n {translate(\n 'brainyrich.dashboard.noInsightsDesc',\n 'There are no open insights that need your attention.'\n )}\n </p>\n </MobileCard>\n )}\n </section>\n\n {/* Goals strip */}\n <section aria-labelledby=\"br-mobile-goals\" className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <h2 id=\"br-mobile-goals\" className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.dashboard.sections.goals', 'Goals on track')}\n </h2>\n {topGoals.length > 0\n ? seeAll(\n translate('brainyrich.mobile.seeAll', 'See all'),\n sectionPath(basePath, 'brainyrich-goals')\n )\n : null}\n </div>\n {goals.isLoading ? (\n <LoadingState rows={1} />\n ) : goals.isError ? (\n <ErrorState onRetry={goals.refetch} />\n ) : topGoals.length > 0 ? (\n <ul\n className=\"-mx-1 flex snap-x snap-mandatory gap-3 overflow-x-auto px-1 pb-1\"\n aria-label={translate('brainyrich.dashboard.sections.goals', 'Goals on track')}\n >\n {topGoals.map((goal) => {\n const pct = fundedPercent(goal);\n return (\n <li key={goal.id} className=\"w-40 shrink-0 snap-start\">\n <button\n type=\"button\"\n onClick={() => navigate(goalDetailPath(basePath, goal.id))}\n className=\"flex h-full w-full flex-col items-start gap-2 rounded-2xl border border-border-subtle bg-bg-surface p-3 text-left motion-safe:transition-colors hover:bg-bg-elevated\"\n >\n <ProgressRing\n value={pct}\n tone={goalTone(goal.status, goal.projection)}\n size={52}\n strokeWidth={6}\n label={translate('brainyrich.goals.card.funded', 'funded')}\n />\n <p className=\"w-full truncate text-sm font-medium text-text-primary\">\n {goal.name}\n </p>\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide',\n projectionChipClass(goal)\n )}\n >\n {goal.status === 'ACHIEVED'\n ? prettyLabel(goal.status)\n : prettyLabel(goal.projection)}\n </span>\n <p className=\"text-xs text-text-secondary\">\n {formatCompact(goal.targetAmount, goal.currency)} ·{' '}\n {formatDate(goal.targetDate)}\n </p>\n </button>\n </li>\n );\n })}\n </ul>\n ) : (\n <EmptyState\n icon={<Target className=\"size-6\" aria-hidden=\"true\" />}\n title={translate('brainyrich.dashboard.noGoals', 'No goals yet')}\n description={translate(\n 'brainyrich.dashboard.noGoalsDesc',\n 'Set a financial goal to start tracking progress.'\n )}\n />\n )}\n </section>\n\n {/* Portfolios: hidden while loading or when there are none, but a failed\n load stays visible with a retry so the phone never silently drops it. */}\n {!portfolios.isLoading && (portfolios.isError || topPortfolios.length > 0) ? (\n <section aria-labelledby=\"br-mobile-portfolios\" className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <h2 id=\"br-mobile-portfolios\" className=\"text-sm font-semibold text-text-primary\">\n {translate('brainyrich.dashboard.sections.portfolios', 'Portfolios')}\n </h2>\n {seeAll(\n translate('brainyrich.mobile.seeAll', 'See all'),\n sectionPath(basePath, 'brainyrich-portfolios')\n )}\n </div>\n {portfolios.isError ? (\n <ErrorState\n title={translate('brainyrich.dashboard.portfoliosError', 'Could not load portfolios')}\n onRetry={portfolios.refetch}\n />\n ) : (\n <div className=\"space-y-2\">\n {topPortfolios.map((portfolio) => (\n <MobileCard key={portfolio.id} className=\"flex items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {portfolio.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {portfolio.description ?? portfolio.baseCurrency}\n </p>\n </div>\n <Badge variant={statusBadgeVariant(portfolio.status)} className=\"shrink-0\">\n {portfolio.status}\n </Badge>\n </MobileCard>\n ))}\n </div>\n )}\n </section>\n ) : null}\n </MobilePage>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BraGoal } from '../../types/bra';
|
|
2
|
+
import { Translate } from './mobileShared';
|
|
3
|
+
export interface MobileGoalsViewProps {
|
|
4
|
+
translate: Translate;
|
|
5
|
+
goals: BraGoal[];
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
isError: boolean;
|
|
8
|
+
refetch: () => void;
|
|
9
|
+
hasMore: boolean;
|
|
10
|
+
loadMore: () => void;
|
|
11
|
+
isFetchingNextPage: boolean;
|
|
12
|
+
totals: {
|
|
13
|
+
totalTarget: number;
|
|
14
|
+
totalMonthly: number;
|
|
15
|
+
atRisk: number;
|
|
16
|
+
};
|
|
17
|
+
currency: string;
|
|
18
|
+
onCreate: () => void;
|
|
19
|
+
onOpen: (goal: BraGoal) => void;
|
|
20
|
+
onEdit: (goal: BraGoal) => void;
|
|
21
|
+
onArchive: (goal: BraGoal) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Phone goals list per `br-49-mobile-goals`: a simplified funding summary, one
|
|
25
|
+
* card per goal with a progress ring and projection badge, and a floating
|
|
26
|
+
* "New goal" button. Tapping a card opens the same detail and funding sheet
|
|
27
|
+
* as desktop.
|
|
28
|
+
*/
|
|
29
|
+
export declare function MobileGoalsView({ translate, goals, isLoading, isError, refetch, hasMore, loadMore, isFetchingNextPage, totals, currency, onCreate, onOpen, onEdit, onArchive, }: MobileGoalsViewProps): import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=MobileGoalsView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MobileGoalsView.d.ts","sourceRoot":"","sources":["../../../../src/brainyrich/pages/mobile/MobileGoalsView.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAc/C,OAAO,EAAmC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjF,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,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,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAChC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAUD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,KAAK,EACL,SAAS,EACT,OAAO,EACP,OAAO,EACP,OAAO,EACP,QAAQ,EACR,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE,oBAAoB,2CAwKtB"}
|