From 63f31a46db22e5fe104755f2d5b4644953e7e892 Mon Sep 17 00:00:00 2001 From: whekin Date: Wed, 11 Mar 2026 18:48:29 +0400 Subject: [PATCH] refactor(miniapp): split home and balances screens --- apps/miniapp/src/App.tsx | 307 ++----------------- apps/miniapp/src/screens/balances-screen.tsx | 167 ++++++++++ apps/miniapp/src/screens/home-screen.tsx | 197 ++++++++++++ 3 files changed, 393 insertions(+), 278 deletions(-) create mode 100644 apps/miniapp/src/screens/balances-screen.tsx create mode 100644 apps/miniapp/src/screens/home-screen.tsx diff --git a/apps/miniapp/src/App.tsx b/apps/miniapp/src/App.tsx index bd7b1c9..2a9f7ca 100644 --- a/apps/miniapp/src/App.tsx +++ b/apps/miniapp/src/App.tsx @@ -40,11 +40,11 @@ import { HeroBanner } from './components/layout/hero-banner' import { NavigationTabs } from './components/layout/navigation-tabs' import { ProfileCard } from './components/layout/profile-card' import { TopBar } from './components/layout/top-bar' -import { FinanceSummaryCards } from './components/finance/finance-summary-cards' -import { FinanceVisuals } from './components/finance/finance-visuals' import { BlockedState } from './components/session/blocked-state' import { LoadingState } from './components/session/loading-state' import { OnboardingState } from './components/session/onboarding-state' +import { BalancesScreen } from './screens/balances-screen' +import { HomeScreen } from './screens/home-screen' import { demoAdminSettings, demoCycleState, @@ -1854,122 +1854,17 @@ function App() { switch (activeNav()) { case 'balances': return ( -
- {copy().emptyDashboard}

} - render={(data) => ( - <> - {currentMemberLine() ? ( -
-
- {copy().yourBalanceTitle} - - {currentMemberLine()!.netDueMajor} {data.currency} - -
-

{copy().yourBalanceBody}

-
-
- {copy().baseDue} - - {memberBaseDueMajor(currentMemberLine()!)} {data.currency} - -
-
- {copy().shareOffset} - - {currentMemberLine()!.purchaseOffsetMajor} {data.currency} - -
-
- {copy().finalDue} - - {currentMemberLine()!.netDueMajor} {data.currency} - -
-
- {copy().paidLabel} - - {currentMemberLine()!.paidMajor} {data.currency} - -
-
- {copy().remainingLabel} - - {currentMemberLine()!.remainingMajor} {data.currency} - -
-
-
- ) : null} -
- -
- -
-
- {copy().householdBalancesTitle} -
-

{copy().householdBalancesBody}

-
- {data.members.map((member) => ( -
-
- {member.displayName} - - {member.remainingMajor} {data.currency} - -
-

- {copy().baseDue}: {memberBaseDueMajor(member)} {data.currency} -

-

- {copy().shareRent}: {member.rentShareMajor} {data.currency} -

-

- {copy().shareUtilities}: {member.utilityShareMajor} {data.currency} -

-

- {copy().shareOffset}: {member.purchaseOffsetMajor} {data.currency} -

-

- {copy().paidLabel}: {member.paidMajor} {data.currency} -

-

- {copy().remainingLabel}: {member.remainingMajor} {data.currency} -

-
- ))} - - )} - /> -
+ ) case 'ledger': return ( @@ -3583,166 +3478,22 @@ function App() { ) default: return ( -
- -
- {copy().remainingLabel} - -
-
- {copy().shareRent} - -
-
- {copy().shareUtilities} - -
-
- {copy().purchasesTitle} - -
- - } - render={(data) => ( - - )} - /> - {readySession()?.member.isAdmin ? ( -
- {copy().pendingRequests} - {String(pendingMembers().length)} -
- ) : null} - - {currentMemberLine() ? ( -
-
- {copy().yourBalanceTitle} - - {currentMemberLine()!.remainingMajor} {dashboard()?.currency ?? ''} - -
-

{copy().yourBalanceBody}

- ( -

- {copy().shareRent}: {data.rentSourceAmountMajor} {data.rentSourceCurrency} - {data.rentSourceCurrency !== data.currency - ? ` -> ${data.rentDisplayAmountMajor} ${data.currency}` - : ''} -

- )} - /> -
-
- {copy().baseDue} - - {memberBaseDueMajor(currentMemberLine()!)} {dashboard()?.currency ?? ''} - -
-
- {copy().shareOffset} - - {currentMemberLine()!.purchaseOffsetMajor} {dashboard()?.currency ?? ''} - -
-
- {copy().finalDue} - - {currentMemberLine()!.netDueMajor} {dashboard()?.currency ?? ''} - -
-
- {copy().paidLabel} - - {currentMemberLine()!.paidMajor} {dashboard()?.currency ?? ''} - -
-
- {copy().remainingLabel} - - {currentMemberLine()!.remainingMajor} {dashboard()?.currency ?? ''} - -
-
-
- ) : ( -
-
- {copy().overviewTitle} -
-

{copy().overviewBody}

-
- )} - - ( - - )} - /> - -
-
- {copy().latestActivityTitle} -
- {copy().latestActivityEmpty}

} - render={(data) => - data.ledger.length === 0 ? ( -

{copy().latestActivityEmpty}

- ) : ( -
- {data.ledger.slice(0, 3).map((entry) => ( -
-
- {ledgerTitle(entry)} - {ledgerPrimaryAmount(entry)} -
- - {(secondary) =>

{secondary()}

} -
-

{entry.actorDisplayName ?? copy().ledgerActorFallback}

-
- ))} -
- ) - } - /> -
-
+ ) } } diff --git a/apps/miniapp/src/screens/balances-screen.tsx b/apps/miniapp/src/screens/balances-screen.tsx new file mode 100644 index 0000000..6f8048e --- /dev/null +++ b/apps/miniapp/src/screens/balances-screen.tsx @@ -0,0 +1,167 @@ +import { For, Show } from 'solid-js' + +import { FinanceSummaryCards } from '../components/finance/finance-summary-cards' +import { FinanceVisuals } from '../components/finance/finance-visuals' +import type { MiniAppDashboard } from '../miniapp-api' + +type Props = { + copy: Record + dashboard: MiniAppDashboard | null + currentMemberLine: MiniAppDashboard['members'][number] | null + utilityTotalMajor: string + purchaseTotalMajor: string + memberBalanceVisuals: { + member: MiniAppDashboard['members'][number] + totalMinor: bigint + barWidthPercent: number + segments: { + key: string + label: string + amountMajor: string + amountMinor: bigint + widthPercent: number + }[] + }[] + purchaseChart: { + totalMajor: string + slices: { + key: string + label: string + amountMajor: string + color: string + percentage: number + dasharray: string + dashoffset: string + }[] + } + memberBaseDueMajor: (member: MiniAppDashboard['members'][number]) => string + memberRemainingClass: (member: MiniAppDashboard['members'][number]) => string +} + +export function BalancesScreen(props: Props) { + if (!props.dashboard) { + return ( +
+

{props.copy.emptyDashboard ?? ''}

+
+ ) + } + + return ( +
+ + {(member) => ( +
+
+ {props.copy.yourBalanceTitle ?? ''} + + {member().netDueMajor} {props.dashboard!.currency} + +
+

{props.copy.yourBalanceBody ?? ''}

+
+
+ {props.copy.baseDue ?? ''} + + {props.memberBaseDueMajor(member())} {props.dashboard!.currency} + +
+
+ {props.copy.shareOffset ?? ''} + + {member().purchaseOffsetMajor} {props.dashboard!.currency} + +
+
+ {props.copy.finalDue ?? ''} + + {member().netDueMajor} {props.dashboard!.currency} + +
+
+ {props.copy.paidLabel ?? ''} + + {member().paidMajor} {props.dashboard!.currency} + +
+
+ {props.copy.remainingLabel ?? ''} + + {member().remainingMajor} {props.dashboard!.currency} + +
+
+
+ )} +
+
+ +
+ +
+
+ {props.copy.householdBalancesTitle ?? ''} +
+

{props.copy.householdBalancesBody ?? ''}

+
+ + {(member) => ( +
+
+ {member.displayName} + + {member.remainingMajor} {props.dashboard!.currency} + +
+

+ {props.copy.baseDue ?? ''}: {props.memberBaseDueMajor(member)}{' '} + {props.dashboard!.currency} +

+

+ {props.copy.shareRent ?? ''}: {member.rentShareMajor} {props.dashboard!.currency} +

+

+ {props.copy.shareUtilities ?? ''}: {member.utilityShareMajor}{' '} + {props.dashboard!.currency} +

+

+ {props.copy.shareOffset ?? ''}: {member.purchaseOffsetMajor}{' '} + {props.dashboard!.currency} +

+

+ {props.copy.paidLabel ?? ''}: {member.paidMajor} {props.dashboard!.currency} +

+

+ {props.copy.remainingLabel ?? ''}: {member.remainingMajor} {props.dashboard!.currency} +

+
+ )} +
+
+ ) +} diff --git a/apps/miniapp/src/screens/home-screen.tsx b/apps/miniapp/src/screens/home-screen.tsx new file mode 100644 index 0000000..6072dec --- /dev/null +++ b/apps/miniapp/src/screens/home-screen.tsx @@ -0,0 +1,197 @@ +import { For, Show } from 'solid-js' + +import { FinanceSummaryCards } from '../components/finance/finance-summary-cards' +import { FinanceVisuals } from '../components/finance/finance-visuals' +import type { MiniAppDashboard } from '../miniapp-api' + +type Props = { + copy: Record + dashboard: MiniAppDashboard | null + readyIsAdmin: boolean + pendingMembersCount: number + currentMemberLine: MiniAppDashboard['members'][number] | null + utilityTotalMajor: string + purchaseTotalMajor: string + memberBalanceVisuals: { + member: MiniAppDashboard['members'][number] + totalMinor: bigint + barWidthPercent: number + segments: { + key: string + label: string + amountMajor: string + amountMinor: bigint + widthPercent: number + }[] + }[] + purchaseChart: { + totalMajor: string + slices: { + key: string + label: string + amountMajor: string + color: string + percentage: number + dasharray: string + dashoffset: string + }[] + } + memberBaseDueMajor: (member: MiniAppDashboard['members'][number]) => string + memberRemainingClass: (member: MiniAppDashboard['members'][number]) => string + ledgerTitle: (entry: MiniAppDashboard['ledger'][number]) => string + ledgerPrimaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string + ledgerSecondaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string | null +} + +export function HomeScreen(props: Props) { + if (!props.dashboard) { + return ( +
+
+ {props.copy.remainingLabel ?? ''} + +
+
+ {props.copy.shareRent ?? ''} + +
+
+ {props.copy.shareUtilities ?? ''} + +
+
+ {props.copy.purchasesTitle ?? ''} + +
+
+ ) + } + + return ( +
+ + +
+ {props.copy.pendingRequests ?? ''} + {String(props.pendingMembersCount)} +
+
+ + +
+ {props.copy.overviewTitle ?? ''} +
+

{props.copy.overviewBody ?? ''}

+ + } + > + {(member) => ( +
+
+ {props.copy.yourBalanceTitle ?? ''} + + {member().remainingMajor} {props.dashboard!.currency} + +
+

{props.copy.yourBalanceBody ?? ''}

+

+ {props.copy.shareRent ?? ''}: {props.dashboard!.rentSourceAmountMajor}{' '} + {props.dashboard!.rentSourceCurrency} + {props.dashboard!.rentSourceCurrency !== props.dashboard!.currency + ? ` -> ${props.dashboard!.rentDisplayAmountMajor} ${props.dashboard!.currency}` + : ''} +

+
+
+ {props.copy.baseDue ?? ''} + + {props.memberBaseDueMajor(member())} {props.dashboard!.currency} + +
+
+ {props.copy.shareOffset ?? ''} + + {member().purchaseOffsetMajor} {props.dashboard!.currency} + +
+
+ {props.copy.finalDue ?? ''} + + {member().netDueMajor} {props.dashboard!.currency} + +
+
+ {props.copy.paidLabel ?? ''} + + {member().paidMajor} {props.dashboard!.currency} + +
+
+ {props.copy.remainingLabel ?? ''} + + {member().remainingMajor} {props.dashboard!.currency} + +
+
+
+ )} +
+ + + +
+
+ {props.copy.latestActivityTitle ?? ''} +
+ {props.dashboard.ledger.length === 0 ? ( +

{props.copy.latestActivityEmpty ?? ''}

+ ) : ( +
+ + {(entry) => ( +
+
+ {props.ledgerTitle(entry)} + {props.ledgerPrimaryAmount(entry)} +
+ + {(secondary) =>

{secondary()}

} +
+

{entry.actorDisplayName ?? props.copy.ledgerActorFallback ?? ''}

+
+ )} +
+
+ )} +
+
+ ) +}