diff --git a/apps/mobile/api/client.ts b/apps/mobile/api/client.ts index a8b80e9..6392dd6 100644 --- a/apps/mobile/api/client.ts +++ b/apps/mobile/api/client.ts @@ -12,6 +12,7 @@ import type { CreateHouseHelpReview, MaintenanceBill, Payment, + StatementEntry, Notice, SocietyConfig, Ticket, @@ -26,6 +27,15 @@ import type { export const API_URL = process.env.EXPO_PUBLIC_API_URL || 'http://localhost:8787' +// Per-flat statement of account (#96) — read-only running balance for residents. +export type ApartmentStatement = { + apartmentId: string + apartment: string + opening: number + closing: number + entries: StatementEntry[] +} + // House help as returned by the directory list — carries its anonymous rating // summary plus verification/trust signals. export type HouseHelpWithRating = HouseHelp & { @@ -133,6 +143,8 @@ export const apiClient = { checkOutHouseHelpEntry: (entryId: string, userId?: string) => api(`/house-help/entries/${entryId}/checkout`, { method: 'POST', body: JSON.stringify({}) }, userId), listMyApartments: () => api('/apartments/mine'), + getApartmentStatement: (apartmentId: string) => + api(`/apartments/${apartmentId}/statement`), listMyResidents: () => api<{ apartmentId: string; userId: string; name: string; relation: string }[]>('/apartments/mine/residents'), listVehicles: (apartmentId?: string) => diff --git a/apps/mobile/app/bills.tsx b/apps/mobile/app/bills.tsx index 89478b0..e9d7933 100644 --- a/apps/mobile/app/bills.tsx +++ b/apps/mobile/app/bills.tsx @@ -24,6 +24,13 @@ export default function Bills() { const { t } = useT() const bills = useQuery({ queryKey: ['bills'], queryFn: () => apiClient.listBills() }) const payments = useQuery({ queryKey: ['payments'], queryFn: () => apiClient.listPayments() }) + const myApts = useQuery({ queryKey: ['my-apartments'], queryFn: () => apiClient.listMyApartments() }) + const primaryApt = myApts.data?.[0]?.id + const statement = useQuery({ + queryKey: ['my-statement', primaryApt], + queryFn: () => apiClient.getApartmentStatement(primaryApt!), + enabled: !!primaryApt, + }) if (bills.isLoading) return ( @@ -91,6 +98,33 @@ export default function Bills() { {formatPaise(p.amount)} ))} + + {statement.data && statement.data.entries.length > 0 && ( + <> + {t('bills.statement')} + {statement.data.entries.map((e, i) => ( + + + {e.description} + {e.date.slice(0, 10)} + + + + {e.debit ? `+${formatPaise(e.debit)}` : `-${formatPaise(e.credit)}`} + + {formatPaise(e.balance)} + + + ))} + + {t('bills.closingBalance')} + {formatPaise(statement.data.closing)} + + + )} ) } diff --git a/packages/shared/src/i18n.ts b/packages/shared/src/i18n.ts index d23c079..c3673ed 100644 --- a/packages/shared/src/i18n.ts +++ b/packages/shared/src/i18n.ts @@ -1012,6 +1012,8 @@ const mobileEn: Dict = { 'bills.paid': 'Paid', 'bills.paymentHistory': 'Payment history', 'bills.noPayments': 'No payments yet.', + 'bills.statement': 'Statement of account', + 'bills.closingBalance': 'Closing balance', 'common.deny': 'Deny', 'visitors.empty': 'No visitors yet.', 'visitors.denyReason': 'Reason for denial', @@ -1140,6 +1142,8 @@ const mobileHi: Dict = { 'bills.paid': 'भुगतान किया', 'bills.paymentHistory': 'भुगतान इतिहास', 'bills.noPayments': 'अभी कोई भुगतान नहीं।', + 'bills.statement': 'खाता विवरण', + 'bills.closingBalance': 'अंतिम शेष', 'common.deny': 'अस्वीकृत करें', 'visitors.empty': 'अभी कोई आगंतुक नहीं।', 'visitors.denyReason': 'अस्वीकृति का कारण',