bugfix: Fix share values being incorrectly divided by 100 in expense form (#453)

* Update expense-form.tsx to handle shares as strings

Proposing fix to #424

The issue is in the data flow between the form and the schema transform function:

When editing existing expenses: Form loads shares by dividing database values by 100 (e.g., 200 / 100 = 2), but loads them as numbers
When users change values: Input fields return strings via enforceCurrencyPattern
Schema transform: Only multiplies by 100 for string values, not number values
Result: Modified shares (strings) get multiplied by 100, unmodified shares (numbers) stay as-is

Proposed fix: handle all shares consistently as strings throughout the form

* Add type assertions to fix TypeScript errors in expense form

Fix formatting.

---------

Co-authored-by: yllar <yllar.pajus@gmail.com>
This commit is contained in:
Derek
2025-11-08 03:34:57 -05:00
committed by GitHub
parent 0f4c96fc46
commit 157ed4fd96

View File

@@ -81,7 +81,7 @@ const getDefaultSplittingOptions = (
splitMode: 'EVENLY' as const, splitMode: 'EVENLY' as const,
paidFor: group.participants.map(({ id }) => ({ paidFor: group.participants.map(({ id }) => ({
participant: id, participant: id,
shares: 1, shares: '1' as any, // Use string to ensure consistent schema handling
})), })),
} }
@@ -113,7 +113,7 @@ const getDefaultSplittingOptions = (
splitMode: parsedDefaultSplitMode.splitMode, splitMode: parsedDefaultSplitMode.splitMode,
paidFor: parsedDefaultSplitMode.paidFor.map((paidFor) => ({ paidFor: parsedDefaultSplitMode.paidFor.map((paidFor) => ({
participant: paidFor.participant, participant: paidFor.participant,
shares: paidFor.shares / 100, shares: (paidFor.shares / 100).toString() as any, // Convert to string for consistent schema handling
})), })),
} }
} }
@@ -197,10 +197,9 @@ export function ExpenseForm({
paidBy: expense.paidById, paidBy: expense.paidById,
paidFor: expense.paidFor.map(({ participantId, shares }) => ({ paidFor: expense.paidFor.map(({ participantId, shares }) => ({
participant: participantId, participant: participantId,
shares: shares: (expense.splitMode === 'BY_AMOUNT'
expense.splitMode === 'BY_AMOUNT' ? amountAsDecimal(shares, groupCurrency)
? amountAsDecimal(shares, groupCurrency) : (shares / 100).toString()) as any, // Convert to string to ensure consistent handling
: shares / 100,
})), })),
splitMode: expense.splitMode, splitMode: expense.splitMode,
saveDefaultSplittingOptions: false, saveDefaultSplittingOptions: false,
@@ -226,7 +225,7 @@ export function ExpenseForm({
searchParams.get('to') searchParams.get('to')
? { ? {
participant: searchParams.get('to')!, participant: searchParams.get('to')!,
shares: 1, shares: '1' as any, // String for consistent form handling
} }
: undefined, : undefined,
], ],
@@ -359,9 +358,9 @@ export function ExpenseForm({
if (!editedParticipants.includes(participant.participant)) { if (!editedParticipants.includes(participant.participant)) {
return { return {
...participant, ...participant,
shares: Number( shares: amountPerRemaining.toFixed(
amountPerRemaining.toFixed(groupCurrency.decimal_digits), groupCurrency.decimal_digits,
), ) as any, // Keep as string for consistent schema handling
} }
} }
return participant return participant
@@ -825,11 +824,11 @@ export function ExpenseForm({
? [] ? []
: group.participants.map((p) => ({ : group.participants.map((p) => ({
participant: p.id, participant: p.id,
shares: shares: (paidFor.find(
paidFor.find((pfor) => pfor.participant === p.id) (pfor) => pfor.participant === p.id,
?.shares ?? 1, )?.shares ?? '1') as any, // Use string to ensure consistent schema handling
})) }))
form.setValue('paidFor', newPaidFor, { form.setValue('paidFor', newPaidFor as any, {
shouldDirty: true, shouldDirty: true,
shouldTouch: true, shouldTouch: true,
shouldValidate: true, shouldValidate: true,
@@ -886,9 +885,9 @@ export function ExpenseForm({
...field.value, ...field.value,
{ {
participant: id, participant: id,
shares: 1, shares: '1', // Use string to ensure consistent schema handling
}, },
], ] as any,
options, options,
) )
: form.setValue( : form.setValue(