@@ -33,6 +33,30 @@ const CustomCheckbox = ({ label, status, onPress }) => (
3333 </ TouchableOpacity >
3434) ;
3535
36+ const SplitInputRow = ( {
37+ label,
38+ value,
39+ onChangeText,
40+ keyboardType = "numeric" ,
41+ disabled = false ,
42+ isPercentage = false ,
43+ } ) => (
44+ < View style = { styles . splitRow } >
45+ < Text style = { styles . splitLabel } > { label } </ Text >
46+ < View style = { { flexDirection : "row" , alignItems : "center" } } >
47+ < TextInput
48+ style = { styles . splitInput }
49+ value = { value }
50+ onChangeText = { onChangeText }
51+ keyboardType = { keyboardType }
52+ disabled = { disabled }
53+ theme = { { colors : { primary : colors . accent } } }
54+ />
55+ { isPercentage && < Text style = { styles . percentageSymbol } > %</ Text > }
56+ </ View >
57+ </ View >
58+ ) ;
59+
3660const AddExpenseScreen = ( { route, navigation } ) => {
3761 const { groupId } = route . params ;
3862 const { user } = useContext ( AuthContext ) ;
@@ -143,8 +167,37 @@ const AddExpenseScreen = ({ route, navigation }) => {
143167 amount : parseFloat ( value ) ,
144168 type : "unequal" ,
145169 } ) ) ;
170+ } else if ( splitMethod === "percentage" ) {
171+ const totalPercentage = Object . values ( percentages ) . reduce (
172+ ( sum , val ) => sum + parseFloat ( val || "0" ) ,
173+ 0
174+ ) ;
175+ if ( Math . abs ( totalPercentage - 100 ) > 0.01 ) {
176+ throw new Error ( "Percentages must add up to 100." ) ;
177+ }
178+ splits = Object . entries ( percentages )
179+ . filter ( ( [ , value ] ) => parseFloat ( value || "0" ) > 0 )
180+ . map ( ( [ userId , value ] ) => ( {
181+ userId,
182+ amount : ( numericAmount * parseFloat ( value ) ) / 100 ,
183+ type : "percentage" ,
184+ } ) ) ;
185+ } else if ( splitMethod === "shares" ) {
186+ const totalShares = Object . values ( shares ) . reduce (
187+ ( sum , val ) => sum + parseFloat ( val || "0" ) ,
188+ 0
189+ ) ;
190+ if ( totalShares === 0 ) {
191+ throw new Error ( "Total shares cannot be zero." ) ;
192+ }
193+ splits = Object . entries ( shares )
194+ . filter ( ( [ , value ] ) => parseFloat ( value || "0" ) > 0 )
195+ . map ( ( [ userId , value ] ) => ( {
196+ userId,
197+ amount : ( numericAmount * parseFloat ( value ) ) / totalShares ,
198+ type : "shares" ,
199+ } ) ) ;
146200 }
147- // ... other split methods logic
148201 const expenseData = {
149202 description,
150203 amount : numericAmount ,
@@ -177,7 +230,40 @@ const AddExpenseScreen = ({ route, navigation }) => {
177230 onPress = { ( ) => handleMemberSelect ( member . userId ) }
178231 />
179232 ) ) ;
180- // ... other cases
233+ case "exact" :
234+ return members . map ( ( member ) => (
235+ < SplitInputRow
236+ key = { member . userId }
237+ label = { member . user . name }
238+ value = { exactAmounts [ member . userId ] }
239+ onChangeText = { ( text ) =>
240+ setExactAmounts ( { ...exactAmounts , [ member . userId ] : text } )
241+ }
242+ />
243+ ) ) ;
244+ case "percentage" :
245+ return members . map ( ( member ) => (
246+ < SplitInputRow
247+ key = { member . userId }
248+ label = { member . user . name }
249+ value = { percentages [ member . userId ] }
250+ onChangeText = { ( text ) =>
251+ setPercentages ( { ...percentages , [ member . userId ] : text } )
252+ }
253+ isPercentage
254+ />
255+ ) ) ;
256+ case "shares" :
257+ return members . map ( ( member ) => (
258+ < SplitInputRow
259+ key = { member . userId }
260+ label = { member . user . name }
261+ value = { shares [ member . userId ] }
262+ onChangeText = { ( text ) =>
263+ setShares ( { ...shares , [ member . userId ] : text } )
264+ }
265+ />
266+ ) ) ;
181267 default :
182268 return null ;
183269 }
@@ -227,25 +313,25 @@ const AddExpenseScreen = ({ route, navigation }) => {
227313 theme = { { colors : { primary : colors . accent } } }
228314 />
229315
230- < Menu
231- visible = { menuVisible }
232- onDismiss = { ( ) => setMenuVisible ( false ) }
233- anchor = {
234- < TouchableOpacity
235- style = { styles . menuAnchor }
236- onPress = { ( ) => setMenuVisible ( true ) }
237- >
238- < Text style = { styles . menuAnchorText } >
239- Paid by: { selectedPayerName }
240- </ Text >
241- < Ionicons
242- name = "chevron-down-outline"
243- size = { 24 }
244- color = { colors . textSecondary }
245- />
246- </ TouchableOpacity >
247- }
248- >
316+ < View >
317+ < Text style = { styles . label } > Paid by </ Text >
318+ < Menu
319+ visible = { menuVisible }
320+ onDismiss = { ( ) => setMenuVisible ( false ) }
321+ anchor = {
322+ < TouchableOpacity
323+ style = { styles . menuAnchor }
324+ onPress = { ( ) => setMenuVisible ( true ) }
325+ >
326+ < Text style = { styles . menuAnchorText } > { selectedPayerName } </ Text >
327+ < Ionicons
328+ name = "chevron-down-outline"
329+ size = { 24 }
330+ color = { colors . textSecondary }
331+ />
332+ </ TouchableOpacity >
333+ }
334+ >
249335 { members . map ( ( member ) => (
250336 < Menu . Item
251337 key = { member . userId }
@@ -257,6 +343,7 @@ const AddExpenseScreen = ({ route, navigation }) => {
257343 />
258344 ) ) }
259345 </ Menu >
346+ </ View >
260347
261348 < Text style = { styles . splitTitle } > Split Method</ Text >
262349 < SegmentedButtons
@@ -341,6 +428,11 @@ const styles = StyleSheet.create({
341428 ...typography . body ,
342429 color : colors . text ,
343430 } ,
431+ label : {
432+ ...typography . body ,
433+ color : colors . textSecondary ,
434+ marginBottom : spacing . sm ,
435+ } ,
344436 checkboxContainer : {
345437 flexDirection : "row" ,
346438 alignItems : "center" ,
@@ -351,6 +443,27 @@ const styles = StyleSheet.create({
351443 color : colors . text ,
352444 marginLeft : spacing . md ,
353445 } ,
446+ splitRow : {
447+ flexDirection : "row" ,
448+ justifyContent : "space-between" ,
449+ alignItems : "center" ,
450+ paddingVertical : spacing . sm ,
451+ } ,
452+ splitLabel : {
453+ ...typography . body ,
454+ color : colors . text ,
455+ flex : 1 ,
456+ } ,
457+ splitInput : {
458+ width : 100 ,
459+ textAlign : "right" ,
460+ backgroundColor : colors . white ,
461+ } ,
462+ percentageSymbol : {
463+ ...typography . body ,
464+ color : colors . textSecondary ,
465+ marginLeft : spacing . sm ,
466+ } ,
354467} ) ;
355468
356469export default AddExpenseScreen ;
0 commit comments