11import { Ionicons } from "@expo/vector-icons" ;
2- import { useContext , useEffect , useState } from "react" ;
2+ import { useContext , useEffect , useMemo , useState } from "react" ;
33import {
44 Alert ,
55 FlatList ,
@@ -124,56 +124,68 @@ const HomeScreen = ({ navigation }) => {
124124 setIsSettledExpanded ( ! isSettledExpanded ) ;
125125 } ;
126126
127- const renderGroup = ( { item } ) => {
128- const { settlementStatus } = item ;
129-
130- const getSettlementStatusText = ( ) => {
131- if ( settlementStatus . netBalance > 0 ) {
132- return `You are owed ${ formatCurrency ( settlementStatus . netBalance ) } ` ;
133- }
134- return `You owe ${ formatCurrency ( Math . abs ( settlementStatus . netBalance ) ) } ` ;
135- } ;
136-
137- const getStatusColor = ( ) =>
138- settlementStatus . netBalance > 0 ? colors . success : colors . error ;
139-
140- const isImage = item . imageUrl && / ^ ( h t t p s ? : | d a t a : i m a g e ) / . test ( item . imageUrl ) ;
141- const groupIcon = item . imageUrl || item . name ?. charAt ( 0 ) || "?" ;
127+ const activeGroupRows = useMemo ( ( ) => {
128+ const rows = [ ] ;
129+ for ( let i = 0 ; i < activeGroups . length ; i += 2 ) {
130+ rows . push ( activeGroups . slice ( i , i + 2 ) ) ;
131+ }
132+ return rows ;
133+ } , [ activeGroups ] ) ;
142134
143- return (
144- < TouchableOpacity
145- style = { styles . card }
146- onPress = { ( ) =>
147- navigation . navigate ( "GroupDetails" , {
148- groupId : item . _id ,
149- groupName : item . name ,
150- groupIcon,
151- } )
152- }
153- >
154- { isImage ? (
155- < Avatar . Image
156- size = { 60 }
157- source = { { uri : item . imageUrl } }
158- style = { styles . avatar }
159- />
160- ) : (
161- < Avatar . Text
162- size = { 60 }
163- label = { groupIcon }
164- style = { styles . avatar }
165- labelStyle = { { ...typography . h2 , color : colors . white } }
166- />
167- ) }
168- < Text style = { styles . groupName } numberOfLines = { 2 } >
169- { item . name }
170- </ Text >
171- < Text style = { [ styles . settlementStatus , { color : getStatusColor ( ) } ] } >
172- { getSettlementStatusText ( ) }
173- </ Text >
174- </ TouchableOpacity >
175- ) ;
176- } ;
135+ const renderGroupRow = ( { item : row } ) => (
136+ < View style = { styles . row } >
137+ { row . map ( ( item ) => (
138+ < TouchableOpacity
139+ key = { item . _id }
140+ style = { styles . card }
141+ onPress = { ( ) =>
142+ navigation . navigate ( "GroupDetails" , {
143+ groupId : item . _id ,
144+ groupName : item . name ,
145+ groupIcon : item . imageUrl || item . name ?. charAt ( 0 ) || "?" ,
146+ } )
147+ }
148+ >
149+ { / ^ ( h t t p s ? : | d a t a : i m a g e ) / . test ( item . imageUrl ) ? (
150+ < Avatar . Image
151+ size = { 60 }
152+ source = { { uri : item . imageUrl } }
153+ style = { styles . avatar }
154+ />
155+ ) : (
156+ < Avatar . Text
157+ size = { 60 }
158+ label = { item . imageUrl || item . name ?. charAt ( 0 ) || "?" }
159+ style = { styles . avatar }
160+ labelStyle = { { ...typography . h2 , color : colors . white } }
161+ />
162+ ) }
163+ < Text style = { styles . groupName } numberOfLines = { 2 } >
164+ { item . name }
165+ </ Text >
166+ < Text
167+ style = { [
168+ styles . settlementStatus ,
169+ {
170+ color :
171+ item . settlementStatus . netBalance > 0
172+ ? colors . success
173+ : colors . error ,
174+ } ,
175+ ] }
176+ >
177+ { item . settlementStatus . netBalance > 0
178+ ? `You are owed ${ formatCurrency (
179+ item . settlementStatus . netBalance
180+ ) } `
181+ : `You owe ${ formatCurrency (
182+ Math . abs ( item . settlementStatus . netBalance )
183+ ) } `}
184+ </ Text >
185+ </ TouchableOpacity >
186+ ) ) }
187+ </ View >
188+ ) ;
177189
178190 const renderSettledGroup = ( { item } ) => (
179191 < TouchableOpacity
@@ -194,7 +206,7 @@ const HomeScreen = ({ navigation }) => {
194206 if ( settledGroups . length === 0 ) return null ;
195207
196208 return (
197- < View >
209+ < View style = { styles . expanderContainer } >
198210 < TouchableOpacity
199211 style = { styles . expanderHeader }
200212 onPress = { toggleSettledGroups }
@@ -209,11 +221,7 @@ const HomeScreen = ({ navigation }) => {
209221 />
210222 </ TouchableOpacity >
211223 { isSettledExpanded && (
212- < FlatList
213- data = { settledGroups }
214- renderItem = { renderSettledGroup }
215- keyExtractor = { ( item ) => item . _id }
216- />
224+ < View > { settledGroups . map ( ( item ) => renderSettledGroup ( { item } ) ) } </ View >
217225 ) }
218226 </ View >
219227 ) ;
@@ -270,17 +278,18 @@ const HomeScreen = ({ navigation }) => {
270278 </ View >
271279 ) : (
272280 < FlatList
273- data = { activeGroups }
274- renderItem = { renderGroup }
275- keyExtractor = { ( item ) => item . _id }
276- numColumns = { 2 }
281+ data = { activeGroupRows }
282+ renderItem = { renderGroupRow }
283+ keyExtractor = { ( item , index ) => `row-${ index } ` }
277284 contentContainerStyle = { styles . list }
278285 ListEmptyComponent = {
279- < View style = { styles . emptyContainer } >
280- < Text style = { styles . emptyText } >
281- No active groups. Create or join one!
282- </ Text >
283- </ View >
286+ ! isLoading && (
287+ < View style = { styles . emptyContainer } >
288+ < Text style = { styles . emptyText } >
289+ No active groups. Create or join one!
290+ </ Text >
291+ </ View >
292+ )
284293 }
285294 ListFooterComponent = { renderSettledGroupsExpander }
286295 onRefresh = { fetchGroups }
@@ -296,6 +305,10 @@ const styles = StyleSheet.create({
296305 flex : 1 ,
297306 backgroundColor : colors . secondary ,
298307 } ,
308+ row : {
309+ flexDirection : "row" ,
310+ justifyContent : "space-between" ,
311+ } ,
299312 loaderContainer : {
300313 flex : 1 ,
301314 justifyContent : "center" ,
0 commit comments