Skip to content

Commit

Permalink
feat: edit dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
bepyan committed Jul 12, 2024
1 parent 16946bd commit c4fac1c
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/app/(playground)/playground/test/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from "@tanstack/react-query";
import { cache } from "react";
import { ALink, AMain } from "~/app/(playground)/playground/inner-tools";
import TestEditDialog from "~/app/(playground)/playground/test/test-edit-dialog";
import TestForm from "~/app/(playground)/playground/test/test-form";
import TestList from "~/app/(playground)/playground/test/test-list";
import { getTestWithTestJobCnt } from "~/lib/db/schema/test.query";
Expand All @@ -25,6 +26,7 @@ export default async function Page() {
<ALink href="/playground">playground</ALink>
<TestForm />
<TestList />
<TestEditDialog />
</AMain>
</HydrationBoundary>
);
Expand Down
149 changes: 149 additions & 0 deletions src/app/(playground)/playground/test/test-edit-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"use client";

import { useForm } from "@tanstack/react-form";
import { toast } from "sonner";
import { create } from "zustand";
import { Button } from "~/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "~/components/ui/dialog";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import type { Test } from "~/lib/db/schema/test";
import { updateTest } from "~/lib/db/schema/test.query";
import { useOptimisticMutation } from "~/lib/hooks/use-optimistic-mutation";

type TestEditDialogStore = {
isOpen: boolean;
data: Test;
openDialog: (test: Test) => void;
closeDialog: () => void;
};

export const useTestEditDialog = create<TestEditDialogStore>((set) => ({
isOpen: false,
data: {
id: 0,
name: "",
email: "",
number: 0,
},
openDialog: (test) => set({ isOpen: true, data: test }),
closeDialog: () => set({ isOpen: false }),
}));

export default function TestEditDialog() {
const { data, isOpen, closeDialog } = useTestEditDialog();

const { mutate, isPending } = useOptimisticMutation({
mutationFn: updateTest,
queryKey: ["tests"],
updater: (state: Test[]) => {
const newState = [...state];
const index = newState.findIndex((test) => test.id === data.id);
newState[index] = data;
return;
},
invalidates: ["tests"],
});

const form = useForm({
defaultValues: data,
onSubmit: ({ value }) => {
mutate(value);
closeDialog();
toast.success("수정되었습니다.");
},
});

return (
<Dialog open={isOpen} onOpenChange={(isOpen) => !isOpen && closeDialog()}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit Test</DialogTitle>
<DialogDescription>
Make changes to your Test here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<form
className="grid gap-4 py-4"
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
form.handleSubmit();
}}
>
<div className="grid grid-cols-4 items-center gap-4">
<Label className="text-right">ID</Label>
<Input defaultValue={data.id} className="col-span-3" disabled />
</div>
<form.Field
name="name"
children={(field) => (
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor={field.name} className="text-right">
이름
</Label>
<Input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
className="col-span-3"
/>
</div>
)}
/>
<form.Field
name="email"
children={(field) => (
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor={field.name} className="text-right">
이메일
</Label>
<Input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
className="col-span-3"
/>
</div>
)}
/>
<form.Field
name="number"
children={(field) => (
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor={field.name} className="text-right">
숫자
</Label>
<Input
type="number"
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.valueAsNumber)}
className="col-span-3"
/>
</div>
)}
/>
</form>
<DialogFooter>
<Button disabled={isPending} onClick={form.handleSubmit}>
수정하기
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
7 changes: 6 additions & 1 deletion src/app/(playground)/playground/test/test-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useIsMutating, useQuery } from "@tanstack/react-query";
import { josa } from "es-hangul";
import Link from "next/link";
import { toast } from "sonner";
import { useTestEditDialog } from "~/app/(playground)/playground/test/test-edit-dialog";
import { useAlertDialogStore } from "~/components/global-alert";
import { Button } from "~/components/ui/button";
import {
Expand Down Expand Up @@ -42,6 +43,8 @@ export default function TestList() {
invalidates: ["tests"],
});

const onOpenEditDialog = useTestEditDialog((state) => state.openDialog);

const onAlertDelete = useAlertDialogStore((state) => {
return (test: Test) => {
const onConfirm = () => {
Expand Down Expand Up @@ -103,7 +106,9 @@ export default function TestList() {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>수정하기</DropdownMenuItem>
<DropdownMenuItem onClick={() => onOpenEditDialog(test)}>
수정하기
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onAlertDelete(test)}>
삭제하기
</DropdownMenuItem>
Expand Down
8 changes: 3 additions & 5 deletions src/lib/db/schema/test.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,9 @@ export async function getTestWithTestJobs(id: Test["id"]) {
return { ...test, jobs };
}

export async function updateTest(
id: Test["id"],
data: Partial<Omit<Test, "id">>,
) {
await db.update(tests).set(data).where(eq(tests.id, id));
export async function updateTest(data: Test) {
await db.update(tests).set(data).where(eq(tests.id, data.id));
revalidatePath("/playground/test");
}

export async function deleteTest(id: Test["id"]) {
Expand Down

0 comments on commit c4fac1c

Please sign in to comment.