From 7467d3a4cfc16f1bba61b6558329b6baff6c4678 Mon Sep 17 00:00:00 2001 From: whekin Date: Thu, 12 Mar 2026 01:32:05 +0400 Subject: [PATCH] fix(miniapp): make dashboard screens react to initial load --- apps/miniapp/src/screens/balances-screen.tsx | 239 ++--- apps/miniapp/src/screens/home-screen.tsx | 249 ++--- apps/miniapp/src/screens/ledger-screen.tsx | 899 ++++++++++--------- 3 files changed, 700 insertions(+), 687 deletions(-) diff --git a/apps/miniapp/src/screens/balances-screen.tsx b/apps/miniapp/src/screens/balances-screen.tsx index 2a72ff0..6e1935b 100644 --- a/apps/miniapp/src/screens/balances-screen.tsx +++ b/apps/miniapp/src/screens/balances-screen.tsx @@ -39,129 +39,132 @@ type Props = { } 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.emptyDashboard ?? ''}

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

{props.copy.yourBalanceBody ?? ''}

+
+
+ {props.copy.baseDue ?? ''} + + {props.memberBaseDueMajor(member())} {dashboard().currency} + +
+
+ {props.copy.shareOffset ?? ''} + + {member().purchaseOffsetMajor} {dashboard().currency} + +
+
+ {props.copy.finalDue ?? ''} + + {member().netDueMajor} {dashboard().currency} + +
+
+ {props.copy.paidLabel ?? ''} + + {member().paidMajor} {dashboard().currency} + +
+
+ {props.copy.remainingLabel ?? ''} + + {member().remainingMajor} {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.householdBalancesTitle ?? ''}
-

- {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} -

+

{props.copy.householdBalancesBody ?? ''}

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

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

+

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

+

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

+

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

+

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

+

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

+
+ )} +
+ + )} + ) } diff --git a/apps/miniapp/src/screens/home-screen.tsx b/apps/miniapp/src/screens/home-screen.tsx index c15b072..3752973 100644 --- a/apps/miniapp/src/screens/home-screen.tsx +++ b/apps/miniapp/src/screens/home-screen.tsx @@ -18,130 +18,133 @@ type Props = { } export function HomeScreen(props: Props) { - if (!props.dashboard) { - return ( -
-
-
- {props.copy.remainingLabel ?? ''} - -
-
- {props.copy.shareRent ?? ''} - -
-
- {props.copy.shareUtilities ?? ''} - -
-
- {props.copy.purchasesTitle ?? ''} - + return ( + +
+
+ {props.copy.remainingLabel ?? ''} + +
+
+ {props.copy.shareRent ?? ''} + +
+
+ {props.copy.shareUtilities ?? ''} + +
+
+ {props.copy.purchasesTitle ?? ''} + +
+
+
+ } + > + {(dashboard) => ( +
+
+ + +
+ {props.copy.pendingRequests ?? ''} + {String(props.pendingMembersCount)} +
+
+
+ + + {(member) => ( +
+
+ {props.copy.yourBalanceTitle ?? ''} + + {member().remainingMajor} {dashboard().currency} + +
+

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

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

{props.copy.latestActivityEmpty ?? ''}

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

{secondary()}

} +
+

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

+
+ )} +
+
+ )}
-
- ) - } - - return ( -
-
- - -
- {props.copy.pendingRequests ?? ''} - {String(props.pendingMembersCount)} -
-
-
- - - {(member) => ( -
-
- {props.copy.yourBalanceTitle ?? ''} - - {member().remainingMajor} {props.dashboard!.currency} - -
-

- {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 ?? ''}

-
- )} -
-
- )} -
-
+ )} + ) } diff --git a/apps/miniapp/src/screens/ledger-screen.tsx b/apps/miniapp/src/screens/ledger-screen.tsx index 2f21dba..fe16c6f 100644 --- a/apps/miniapp/src/screens/ledger-screen.tsx +++ b/apps/miniapp/src/screens/ledger-screen.tsx @@ -118,130 +118,467 @@ type Props = { } export function LedgerScreen(props: Props) { - if (!props.dashboard) { - return ( -
-

{props.copy.emptyDashboard ?? ''}

-
- ) - } - return ( -
-
-
- - {props.readyIsAdmin ? props.copy.purchaseReviewTitle : props.copy.purchasesTitle} - -
- -

{props.copy.purchaseReviewBody ?? ''}

-
- {props.purchaseEntries.length === 0 ? ( -

{props.copy.purchasesEmpty ?? ''}

- ) : ( -
- - {(entry) => ( -
-
-
- {entry.title} - {entry.occurredAt?.slice(0, 10) ?? '—'} -
-

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

-
- {props.ledgerPrimaryAmount(entry)} - - {(secondary) => ( - {secondary()} - )} - - - {props.purchaseParticipantSummary(entry)} - + +

{props.copy.emptyDashboard ?? ''}

+
+ } + > +
+
+
+ + {props.readyIsAdmin ? props.copy.purchaseReviewTitle : props.copy.purchasesTitle} + +
+ +

{props.copy.purchaseReviewBody ?? ''}

+
+ {props.purchaseEntries.length === 0 ? ( +

{props.copy.purchasesEmpty ?? ''}

+ ) : ( +
+ + {(entry) => ( +
+
+
+ {entry.title} + {entry.occurredAt?.slice(0, 10) ?? '—'} +
+

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

+
+ {props.ledgerPrimaryAmount(entry)} + + {(secondary) => ( + {secondary()} + )} + + + {props.purchaseParticipantSummary(entry)} + +
-
- -
- props.onOpenPurchaseEditor(entry.id)} - > - - -
-
-
- )} - -
- )} -
- { - const entry = props.editingPurchaseEntry - - if (!entry) { - return null - } - - return ( -
+ )} +
- ) - })()} - > - {(() => { - const entry = props.editingPurchaseEntry + )} + + { + const entry = props.editingPurchaseEntry - if (!entry) { - return null + if (!entry) { + return null + } + + return ( + + ) + })()} + > + {(() => { + const entry = props.editingPurchaseEntry + + if (!entry) { + return null + } + + const draft = props.purchaseDraftMap[entry.id] ?? props.purchaseDraftForEntry(entry) + const splitPreview = props.purchaseSplitPreview(entry.id) + + return ( + <> +
+ + + props.onPurchaseDescriptionChange( + entry.id, + entry, + event.currentTarget.value + ) + } + /> + + + + props.onPurchaseAmountChange(entry.id, entry, event.currentTarget.value) + } + /> + + + + +
+ +
+
+ {props.copy.purchaseSplitTitle ?? ''} + + {draft.splitMode === 'custom_amounts' + ? props.copy.purchaseSplitCustom + : props.copy.purchaseSplitEqual} + +
+
+ + + +
+
+ + {(member) => { + const included = draft.participants.some( + (participant) => participant.memberId === member.id + ) + const previewAmount = + splitPreview.find((participant) => participant.memberId === member.id) + ?.amountMajor ?? '0.00' + + return ( +
+
+ {member.displayName} + + {previewAmount} {draft.currency} + +
+
+ + + + participant.memberId === member.id + )?.shareAmountMajor ?? '' + } + onInput={(event) => + props.onPurchaseParticipantShareChange( + entry.id, + entry, + member.id, + event.currentTarget.value + ) + } + /> + + +
+
+ ) + }} +
+
+
+ + ) + })()} +
+
+
+ {props.copy.utilityLedgerTitle ?? ''} +
+ {props.utilityEntries.length === 0 ? ( +

{props.copy.utilityLedgerEmpty ?? ''}

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

{secondary()}

} +
+

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

+
+ )} +
+
+ )} +
+
+
+ {props.copy.paymentsAdminTitle ?? ''} +
+ +

{props.copy.paymentsAdminBody ?? ''}

+
+ +
+
+ {props.paymentEntries.length === 0 ? ( +

{props.copy.paymentsEmpty ?? ''}

+ ) : ( +
+ + {(entry) => ( +
+
+
+ {props.paymentMemberName(entry)} + {entry.occurredAt?.slice(0, 10) ?? '—'} +
+

{props.ledgerTitle(entry)}

+
+ {props.ledgerPrimaryAmount(entry)} + + {(secondary) => ( + {secondary()} + )} + +
+
+ +
+ props.onOpenPaymentEditor(entry.id)} + > + + +
+
+
+ )} +
+
+ )} +
+ + + + } + > +
+ + + + + + + + props.onPaymentFormAmountChange(event.currentTarget.value)} + /> + + + + +
+
+ { + const entry = props.editingPaymentEntry - const draft = props.purchaseDraftMap[entry.id] ?? props.purchaseDraftForEntry(entry) - const splitPreview = props.purchaseSplitPreview(entry.id) + if (!entry) { + return null + } - return ( - <> + return ( + + ) + })()} + > + {(() => { + const entry = props.editingPaymentEntry + + if (!entry) { + return null + } + + const draft = props.paymentDraftMap[entry.id] ?? props.paymentDraftForEntry(entry) + + return (
- - - props.onPurchaseDescriptionChange(entry.id, entry, event.currentTarget.value) + + + + + - props.onPurchaseAmountChange(entry.id, entry, event.currentTarget.value) + props.onPaymentDraftAmountChange(entry.id, entry, event.currentTarget.value) } /> @@ -249,7 +586,7 @@ export function LedgerScreen(props: Props) {
- -
-
- {props.copy.purchaseSplitTitle ?? ''} - - {draft.splitMode === 'custom_amounts' - ? props.copy.purchaseSplitCustom - : props.copy.purchaseSplitEqual} - -
-
- - - -
-
- - {(member) => { - const included = draft.participants.some( - (participant) => participant.memberId === member.id - ) - const previewAmount = - splitPreview.find((participant) => participant.memberId === member.id) - ?.amountMajor ?? '0.00' - - return ( -
-
- {member.displayName} - - {previewAmount} {draft.currency} - -
-
- - - - participant.memberId === member.id - )?.shareAmountMajor ?? '' - } - onInput={(event) => - props.onPurchaseParticipantShareChange( - entry.id, - entry, - member.id, - event.currentTarget.value - ) - } - /> - - -
-
- ) - }} -
-
-
- - ) - })()} -
-
-
- {props.copy.utilityLedgerTitle ?? ''} -
- {props.utilityEntries.length === 0 ? ( -

{props.copy.utilityLedgerEmpty ?? ''}

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

{secondary()}

} -
-

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

-
- )} -
-
- )} -
-
-
- {props.copy.paymentsAdminTitle ?? ''} -
- -

{props.copy.paymentsAdminBody ?? ''}

-
- -
-
- {props.paymentEntries.length === 0 ? ( -

{props.copy.paymentsEmpty ?? ''}

- ) : ( -
- - {(entry) => ( -
-
-
- {props.paymentMemberName(entry)} - {entry.occurredAt?.slice(0, 10) ?? '—'} -
-

{props.ledgerTitle(entry)}

-
- {props.ledgerPrimaryAmount(entry)} - - {(secondary) => ( - {secondary()} - )} - -
-
- -
- props.onOpenPaymentEditor(entry.id)} - > - - -
-
-
- )} -
-
- )} -
- - - - - } - > -
- - - - - - - - props.onPaymentFormAmountChange(event.currentTarget.value)} - /> - - - - -
-
- { - const entry = props.editingPaymentEntry - - if (!entry) { - return null - } - - return ( - - ) - })()} - > - {(() => { - const entry = props.editingPaymentEntry - - if (!entry) { - return null - } - - const draft = props.paymentDraftMap[entry.id] ?? props.paymentDraftForEntry(entry) - - return ( -
- - - - - - - - - props.onPaymentDraftAmountChange(entry.id, entry, event.currentTarget.value) - } - /> - - - - -
- ) - })()} -
- + ) + })()} + + + ) }