From 1e66efe5169dfad9a0c62ba42fbf31ce977bf49e Mon Sep 17 00:00:00 2001 From: Sebastien Castiel Date: Tue, 19 Dec 2023 09:36:40 -0500 Subject: Use modal dialogs for expense creation & edition (#10) * First attemps at using route interception and modals * Remove route interception * Make it work * Use Vaul on small screens * Improve vaul --- src/components/expense-form.tsx | 388 ++++++++++++++++++++-------------------- 1 file changed, 195 insertions(+), 193 deletions(-) (limited to 'src/components/expense-form.tsx') diff --git a/src/components/expense-form.tsx b/src/components/expense-form.tsx index bdee9d0..0f677e6 100644 --- a/src/components/expense-form.tsx +++ b/src/components/expense-form.tsx @@ -1,14 +1,12 @@ 'use client' +import { + createExpenseAction, + deleteExpenseAction, + updateExpenseAction, +} from '@/app/groups/[groupId]/expenses/actions' import { AsyncButton } from '@/components/async-button' import { SubmitButton } from '@/components/submit-button' import { Button } from '@/components/ui/button' -import { - Card, - CardContent, - CardFooter, - CardHeader, - CardTitle, -} from '@/components/ui/card' import { Checkbox } from '@/components/ui/checkbox' import { Form, @@ -30,17 +28,15 @@ import { import { getExpense, getGroup } from '@/lib/api' import { ExpenseFormValues, expenseFormSchema } from '@/lib/schemas' import { zodResolver } from '@hookform/resolvers/zod' -import { useSearchParams } from 'next/navigation' +import { useRouter, useSearchParams } from 'next/navigation' import { useForm } from 'react-hook-form' export type Props = { group: NonNullable>> expense?: NonNullable>> - onSubmit: (values: ExpenseFormValues) => Promise - onDelete?: () => Promise } -export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) { +export function ExpenseForm({ group, expense }: Props) { const isCreate = expense === undefined const searchParams = useSearchParams() const form = useForm({ @@ -65,204 +61,210 @@ export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) { } : { title: '', amount: 0, paidFor: [], isReimbursement: false }, }) + const router = useRouter() return (
- onSubmit(values))}> - - - - {isCreate ? <>Create expense : <>Edit expense} - - - - ( - - Expense title + { + if (expense) { + await updateExpenseAction(group.id, expense.id, values) + } else { + await createExpenseAction(group.id, values) + } + router.back() + })} + > +
+ ( + + Expense title + + + + + Enter a description for the expense. + + + + )} + /> + + ( + + Paid by + + + Select the participant who paid the expense. + + + + )} + /> + + ( + + Amount +
+ {group.currency} - - Enter a description for the expense. - - - - )} - /> +
+ - ( - - Paid by - + ( + + + + +
+ This is a reimbursement +
+
+ )} + /> +
+ )} + /> + + ( + +
+ + Paid for + + - Select the participant who paid the expense. + Select who the expense was paid for. - - - )} - /> - - ( - - Amount -
- {group.currency} - - - -
- - +
+ {group.participants.map(({ id, name }) => ( ( - - - - -
- This is a reimbursement -
-
- )} + name="paidFor" + render={({ field }) => { + return ( + + + { + return checked + ? field.onChange([...field.value, id]) + : field.onChange( + field.value?.filter( + (value) => value !== id, + ), + ) + }} + /> + + + {name} + + + ) + }} /> -
- )} - /> - - ( - -
- - Paid for - - - - Select who the expense was paid for. - -
- {group.participants.map(({ id, name }) => ( - { - return ( - - - { - return checked - ? field.onChange([...field.value, id]) - : field.onChange( - field.value?.filter( - (value) => value !== id, - ), - ) - }} - /> - - - {name} - - - ) - }} - /> - ))} - -
- )} - /> - + ))} + +
+ )} + /> +
- - Creating… : <>Saving…} +
+ Creating… : <>Saving…} + > + {isCreate ? <>Create : <>Save} + + {!isCreate && ( + { + await deleteExpenseAction(group.id, expense.id) + router.back() + }} > - {isCreate ? <>Create : <>Save} - - {!isCreate && onDelete && ( - - Delete - - )} - - + Delete + + )} +
) -- cgit v1.3