Skip to content

Commit e2a8789

Browse files
fix: currency display in activity feed and add stats pages (#80)
* fix activity email hydration Build email map before transforming history so each activity gets resolved author email directly. * fix settlement save payload Stop overriding from_user_id when saving a settlement to let backend assign the current user. * fix: currency display in activity feed and add stats pages - Fix activity feed currency display by handling flat snapshot structure - Add resolveCurrencyCode to prefer diff currency over snapshot - Extract transaction from snapshot correctly for both nested and flat structures - Add GroupStatsScreen for detailed cost and balance breakdowns - Make balance rows clickable to open settlement form - Update My costs page to show only user's transactions - Link all dashboard stat cards to dedicated breakdown pages * chore: auto-sync version with PR title [skip ci] --------- Co-authored-by: share-money-version-bot <[email protected]>
1 parent 3e43508 commit e2a8789

File tree

9 files changed

+1101
-428
lines changed

9 files changed

+1101
-428
lines changed

mobile/App.tsx

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@ import { Session } from "@supabase/supabase-js";
22
import { StatusBar } from "expo-status-bar";
33
import React, { useEffect, useState } from "react";
44
import { ErrorBoundary } from "react-error-boundary";
5-
import {
6-
Text as RNText,
7-
StyleSheet,
8-
useColorScheme,
9-
View
10-
} from "react-native";
5+
import { Text as RNText, StyleSheet, useColorScheme, View } from "react-native";
116
import {
127
ActivityIndicator,
138
Button,
149
Provider as PaperProvider,
15-
useTheme
10+
useTheme,
1611
} from "react-native-paper";
1712
import { SafeAreaProvider } from "react-native-safe-area-context";
1813
import { BottomNavBar } from "./components/BottomNavBar";
@@ -23,11 +18,16 @@ import {
2318
useRemoveMember,
2419
} from "./hooks/useGroupMutations";
2520
import { useGroupDetails } from "./hooks/useGroups";
26-
import { useCreateTransaction, useDeleteTransaction, useUpdateTransaction } from "./hooks/useTransactions";
21+
import {
22+
useCreateTransaction,
23+
useDeleteTransaction,
24+
useUpdateTransaction,
25+
} from "./hooks/useTransactions";
2726
import { AddMemberScreen } from "./screens/AddMemberScreen";
2827
import { AuthScreen } from "./screens/AuthScreen";
2928
import { BalancesScreen } from "./screens/BalancesScreen";
3029
import { GroupDetailsScreen } from "./screens/GroupDetailsScreen";
30+
import { GroupStatsMode, GroupStatsScreen } from "./screens/GroupStatsScreen";
3131
import { GroupsListScreen } from "./screens/GroupsListScreen";
3232
import { TransactionFormScreen } from "./screens/TransactionFormScreen";
3333
import { darkTheme, lightTheme } from "./theme";
@@ -47,6 +47,10 @@ function AppContent() {
4747
useState<number>(0);
4848
const [groupRefreshTrigger, setGroupRefreshTrigger] = useState<number>(0);
4949
const [editingTransaction, setEditingTransaction] = useState<any>(null);
50+
const [statsContext, setStatsContext] = useState<{
51+
groupId: string;
52+
mode: GroupStatsMode;
53+
} | null>(null);
5054
const prevSessionRef = React.useRef<Session | null>(null);
5155
const groupsListRefetchRef = React.useRef<(() => void) | null>(null);
5256

@@ -58,7 +62,7 @@ function AppContent() {
5862
const createGroupMutation = useCreateGroup(refetchSelectedGroup);
5963
const addMemberMutation = useAddMember(refetchSelectedGroup);
6064
const removeMemberMutation = useRemoveMember(refetchSelectedGroup);
61-
65+
6266
// Transaction mutations
6367
const onTransactionSuccess = () => {
6468
setCurrentRoute("group-details");
@@ -131,14 +135,13 @@ function AppContent() {
131135
const handleGroupPress = (group: Group) => {
132136
setSelectedGroup(group);
133137
setCurrentRoute("group-details");
138+
setStatsContext(null);
134139
// Group details will be fetched via useGroupDetails hook
135140
};
136141

137-
const handleSaveTransaction = async (
138-
transactionData: any
139-
) => {
142+
const handleSaveTransaction = async (transactionData: any) => {
140143
if (!selectedGroup) return;
141-
144+
142145
if (editingTransaction) {
143146
await updateTx.mutate({
144147
...transactionData,
@@ -156,7 +159,10 @@ function AppContent() {
156159

157160
const handleDeleteTransaction = async () => {
158161
if (!editingTransaction || !selectedGroup) return;
159-
await deleteTx.mutate({ id: editingTransaction.id, group_id: selectedGroup.id });
162+
await deleteTx.mutate({
163+
id: editingTransaction.id,
164+
group_id: selectedGroup.id,
165+
});
160166
};
161167

162168
if (loading) {
@@ -230,6 +236,22 @@ function AppContent() {
230236
);
231237
}
232238

239+
if (currentRoute === "group-stats" && statsContext) {
240+
return (
241+
<>
242+
<GroupStatsScreen
243+
groupId={statsContext.groupId}
244+
mode={statsContext.mode}
245+
onBack={() => {
246+
setStatsContext(null);
247+
setCurrentRoute(selectedGroup ? "group-details" : "groups");
248+
}}
249+
/>
250+
<StatusBar style={theme.dark ? "light" : "dark"} />
251+
</>
252+
);
253+
}
254+
233255
// Show group details screen (with bottom nav)
234256
// Render as soon as a group is selected - the screen handles loading states internally
235257
if (currentRoute === "group-details" && selectedGroup) {
@@ -250,6 +272,7 @@ function AppContent() {
250272
onBack={() => {
251273
setSelectedGroup(null);
252274
setCurrentRoute("groups");
275+
setStatsContext(null);
253276
}}
254277
onAddMember={() => setShowAddMember(true)}
255278
onRemoveMember={async (userId: string) => {
@@ -258,10 +281,12 @@ function AppContent() {
258281
onLeaveGroup={() => {
259282
setSelectedGroup(null);
260283
setCurrentRoute("groups");
284+
setStatsContext(null);
261285
}}
262286
onDeleteGroup={() => {
263287
setSelectedGroup(null);
264288
setCurrentRoute("groups");
289+
setStatsContext(null);
265290
}}
266291
onAddTransaction={() => {
267292
setEditingTransaction(null);
@@ -271,16 +296,23 @@ function AppContent() {
271296
setEditingTransaction(transaction);
272297
setCurrentRoute("transaction-form");
273298
}}
299+
onStatsPress={(mode) => {
300+
if (!groupToDisplay.id) return;
301+
setStatsContext({ groupId: groupToDisplay.id, mode });
302+
setCurrentRoute("group-stats");
303+
}}
274304
/>
275305
<BottomNavBar
276306
currentRoute={currentRoute}
277307
onGroupsPress={() => {
278308
setSelectedGroup(null);
279309
setCurrentRoute("groups");
310+
setStatsContext(null);
280311
}}
281312
onBalancesPress={() => {
282313
setSelectedGroup(null);
283314
setCurrentRoute("balances");
315+
setStatsContext(null);
284316
}}
285317
onLogoutPress={signOut}
286318
/>

0 commit comments

Comments
 (0)