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