diff --git a/prisma/migrations/20231206195936_add_cascades/migration.sql b/prisma/migrations/20231206195936_add_cascades/migration.sql new file mode 100644 index 0000000..4075d7a --- /dev/null +++ b/prisma/migrations/20231206195936_add_cascades/migration.sql @@ -0,0 +1,11 @@ +-- DropForeignKey +ALTER TABLE "ExpensePaidFor" DROP CONSTRAINT "ExpensePaidFor_expenseId_fkey"; + +-- DropForeignKey +ALTER TABLE "Participant" DROP CONSTRAINT "Participant_groupId_fkey"; + +-- AddForeignKey +ALTER TABLE "Participant" ADD CONSTRAINT "Participant_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ExpensePaidFor" ADD CONSTRAINT "ExpensePaidFor_expenseId_fkey" FOREIGN KEY ("expenseId") REFERENCES "Expense"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 73c3ad1..d073378 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -21,7 +21,7 @@ model Group { model Participant { id String @id name String - group Group @relation(fields: [groupId], references: [id]) + group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) groupId String expensesPaidBy Expense[] expensesPaidFor ExpensePaidFor[] @@ -39,7 +39,7 @@ model Expense { } model ExpensePaidFor { - expense Expense @relation(fields: [expenseId], references: [id]) + expense Expense @relation(fields: [expenseId], references: [id], onDelete: Cascade) participant Participant @relation(fields: [participantId], references: [id]) expenseId String participantId String diff --git a/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx b/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx index 934d346..0623f50 100644 --- a/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx +++ b/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx @@ -1,5 +1,5 @@ import { ExpenseForm } from '@/components/expense-form' -import { getExpense, getGroup, updateExpense } from '@/lib/api' +import { deleteExpense, getExpense, getGroup, updateExpense } from '@/lib/api' import { expenseFormSchema } from '@/lib/schemas' import { notFound, redirect } from 'next/navigation' @@ -20,11 +20,18 @@ export default async function EditExpensePage({ redirect(`/groups/${groupId}`) } + async function deleteExpenseAction() { + 'use server' + await deleteExpense(expenseId) + redirect(`/groups/${groupId}`) + } + return ( ) } diff --git a/src/components/async-button.tsx b/src/components/async-button.tsx new file mode 100644 index 0000000..7d2bf93 --- /dev/null +++ b/src/components/async-button.tsx @@ -0,0 +1,42 @@ +'use client' +import { Button, ButtonProps } from '@/components/ui/button' +import { Loader2 } from 'lucide-react' +import { ReactNode, useState } from 'react' + +type Props = ButtonProps & { + action?: () => Promise + loadingContent?: ReactNode +} + +export function AsyncButton({ + action, + children, + loadingContent, + ...props +}: Props) { + const [loading, setLoading] = useState(false) + return ( + + ) +} diff --git a/src/components/expense-form.tsx b/src/components/expense-form.tsx index 35c6aaf..3202788 100644 --- a/src/components/expense-form.tsx +++ b/src/components/expense-form.tsx @@ -1,4 +1,5 @@ 'use client' +import { AsyncButton } from '@/components/async-button' import { SubmitButton } from '@/components/submit-button' import { Card, @@ -33,10 +34,12 @@ import { useForm } from 'react-hook-form' export type Props = { group: NonNullable>> expense?: NonNullable>> - onSubmit: (values: ExpenseFormValues) => void + onSubmit: (values: ExpenseFormValues) => Promise + onDelete?: () => Promise } -export function ExpenseForm({ group, expense, onSubmit }: Props) { +export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) { + const isCreate = expense === undefined const form = useForm({ resolver: zodResolver(expenseFormSchema), defaultValues: expense @@ -54,7 +57,9 @@ export function ExpenseForm({ group, expense, onSubmit }: Props) {
onSubmit(values))}> - Expense information + + {isCreate ? <>Create expense : <>Edit expense} + - - Submit + + + {isCreate ? <>Create : <>Save} + + {!isCreate && onDelete && ( + + Delete + + )}
diff --git a/src/components/group-form.tsx b/src/components/group-form.tsx index 5ddc865..2e21aea 100644 --- a/src/components/group-form.tsx +++ b/src/components/group-form.tsx @@ -22,6 +22,7 @@ import { Input } from '@/components/ui/input' import { getGroup } from '@/lib/api' import { GroupFormValues, groupFormSchema } from '@/lib/schemas' import { zodResolver } from '@hookform/resolvers/zod' +import { Trash2 } from 'lucide-react' import { useFieldArray, useForm } from 'react-hook-form' export type Props = { @@ -105,11 +106,13 @@ export function GroupForm({ group, onSubmit }: Props) {
diff --git a/src/components/submit-button.tsx b/src/components/submit-button.tsx index 7489c6c..c5215c5 100644 --- a/src/components/submit-button.tsx +++ b/src/components/submit-button.tsx @@ -1,16 +1,16 @@ -import { Button } from '@/components/ui/button' +import { Button, ButtonProps } from '@/components/ui/button' import { Loader2 } from 'lucide-react' -import { PropsWithChildren, ReactNode } from 'react' +import { ReactNode } from 'react' import { useFormState } from 'react-hook-form' -type Props = PropsWithChildren<{ +type Props = { loadingContent: ReactNode -}> +} & ButtonProps -export function SubmitButton({ children, loadingContent }: Props) { +export function SubmitButton({ children, loadingContent, ...props }: Props) { const { isSubmitting } = useFormState() return ( -