diff --git a/src/components/expense-form.tsx b/src/components/expense-form.tsx index fdde7452..af998bb7 100644 --- a/src/components/expense-form.tsx +++ b/src/components/expense-form.tsx @@ -35,7 +35,11 @@ import { } from '@/components/ui/select' import { getCategories, getExpense, getGroup, randomId } from '@/lib/api' import { RuntimeFeatureFlags } from '@/lib/featureFlags' -import { ExpenseFormValues, expenseFormSchema } from '@/lib/schemas' +import { + ExpenseFormValues, + SplittingOptions, + expenseFormSchema, +} from '@/lib/schemas' import { cn } from '@/lib/utils' import { zodResolver } from '@hookform/resolvers/zod' import { Save } from 'lucide-react' @@ -67,6 +71,78 @@ const enforceCurrencyPattern = (value: string) => // remove all non-numeric and non-dot characters .replace(/[^\d.]/g, '') +const getDefaultSplittingOptions = (group: Props['group']) => { + const defaultValue = { + splitMode: 'EVENLY' as const, + paidFor: group.participants.map(({ id }) => ({ + participant: id, + shares: '1' as unknown as number, + })), + } + + if (typeof localStorage === 'undefined') return defaultValue + const defaultSplitMode = localStorage.getItem( + `${group.id}-defaultSplittingOptions`, + ) + if (defaultSplitMode === null) return defaultValue + const parsedDefaultSplitMode = JSON.parse( + defaultSplitMode, + ) as SplittingOptions + + if (parsedDefaultSplitMode.paidFor === null) { + parsedDefaultSplitMode.paidFor = defaultValue.paidFor + } + + // if there is a participant in the default options that does not exist anymore, + // remove the stale default splitting options + for (const parsedPaidFor of parsedDefaultSplitMode.paidFor) { + if ( + !group.participants.some(({ id }) => id === parsedPaidFor.participant) + ) { + localStorage.removeItem(`${group.id}-defaultSplittingOptions`) + return defaultValue + } + } + + return { + splitMode: parsedDefaultSplitMode.splitMode, + paidFor: parsedDefaultSplitMode.paidFor.map((paidFor) => ({ + participant: paidFor.participant, + shares: String(paidFor.shares / 100) as unknown as number, + })), + } +} + +async function persistDefaultSplittingOptions( + groupId: string, + expenseFormValues: ExpenseFormValues, +) { + if (localStorage && expenseFormValues.saveDefaultSplittingOptions) { + const computePaidFor = (): SplittingOptions['paidFor'] => { + if (expenseFormValues.splitMode === 'EVENLY') { + return expenseFormValues.paidFor.map(({ participant }) => ({ + participant, + shares: '100' as unknown as number, + })) + } else if (expenseFormValues.splitMode === 'BY_AMOUNT') { + return null + } else { + return expenseFormValues.paidFor + } + } + + const splittingOptions = { + splitMode: expenseFormValues.splitMode, + paidFor: computePaidFor(), + } satisfies SplittingOptions + + localStorage.setItem( + `${groupId}-defaultSplittingOptions`, + JSON.stringify(splittingOptions), + ) + } +} + export function ExpenseForm({ group, expense, @@ -86,6 +162,7 @@ export function ExpenseForm({ } return field?.value } + const defaultSplittingOptions = getDefaultSplittingOptions(group) const form = useForm({ resolver: zodResolver(expenseFormSchema), defaultValues: expense @@ -100,6 +177,7 @@ export function ExpenseForm({ shares: String(shares / 100) as unknown as number, })), splitMode: expense.splitMode, + saveDefaultSplittingOptions: false, isReimbursement: expense.isReimbursement, documents: expense.documents, } @@ -121,7 +199,8 @@ export function ExpenseForm({ : undefined, ], isReimbursement: true, - splitMode: 'EVENLY', + splitMode: defaultSplittingOptions.splitMode, + saveDefaultSplittingOptions: false, documents: [], } : { @@ -134,13 +213,11 @@ export function ExpenseForm({ ? Number(searchParams.get('categoryId')) : 0, // category with Id 0 is General // paid for all, split evenly - paidFor: group.participants.map(({ id }) => ({ - participant: id, - shares: '1' as unknown as number, - })), + paidFor: defaultSplittingOptions.paidFor, paidBy: getSelectedPayer(), isReimbursement: false, - splitMode: 'EVENLY', + splitMode: defaultSplittingOptions.splitMode, + saveDefaultSplittingOptions: false, documents: searchParams.get('imageUrl') ? [ { @@ -155,9 +232,14 @@ export function ExpenseForm({ }) const [isCategoryLoading, setCategoryLoading] = useState(false) + const submit = async (values: ExpenseFormValues) => { + await persistDefaultSplittingOptions(group.id, values) + return onSubmit(values) + } + return (
- onSubmit(values))}> + @@ -511,7 +593,10 @@ export function ExpenseForm({ )} /> - +