Skip to content

Commit

Permalink
feat: make guestbook editable
Browse files Browse the repository at this point in the history
  • Loading branch information
ixartz committed Aug 23, 2023
1 parent b7f823a commit 8ec1406
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 36 deletions.
28 changes: 25 additions & 3 deletions src/app/api/guestbook/route.ts
Expand Up @@ -5,14 +5,15 @@ import { z } from 'zod';
import { db } from '@/lib/DB';
import { guestbookTable } from '@/models/Schema';
import {
AddGuestbookSchema,
DeleteGuestbookSchema,
} from '@/validations/Guestbook';
EditGuestbookSchema,
GuestbookSchema,
} from '@/validations/GuestbookValidation';

export const POST = async (request: Request) => {
try {
const json = await request.json();
const body = AddGuestbookSchema.parse(json);
const body = GuestbookSchema.parse(json);

await db.insert(guestbookTable).values(body).run();

Expand All @@ -26,6 +27,27 @@ export const POST = async (request: Request) => {
}
};

export const PUT = async (request: Request) => {
try {
const json = await request.json();
const body = EditGuestbookSchema.parse(json);

await db
.update(guestbookTable)
.set(body)
.where(eq(guestbookTable.id, body.id))
.run();

return NextResponse.json({});
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(error.format(), { status: 422 });
}

return NextResponse.json({}, { status: 500 });
}
};

export const DELETE = async (request: Request) => {
try {
const json = await request.json();
Expand Down
16 changes: 9 additions & 7 deletions src/app/guestbook/page.tsx
@@ -1,7 +1,8 @@
import type { Metadata } from 'next';

import { AddGuestbookForm } from '@/components/AddGuestbookForm';
import { DeleteGuestbookEntry } from '@/components/DeleteGuestbookEntry';
import { EditableGuestbookEntry } from '@/components/EditableGuestbookEntry';
import { GuestbookForm } from '@/components/GuestbookForm';
import { db } from '@/lib/DB';
import { guestbookTable } from '@/models/Schema';
import { Main } from '@/templates/Main';
Expand All @@ -16,17 +17,18 @@ const Guestbook = async () => {

return (
<Main>
<AddGuestbookForm />
<GuestbookForm />

<div className="mt-5">
{guestbook.map((elt) => (
<div key={elt.id} className="mb-1 flex items-center">
<div key={elt.id} className="mb-1 flex items-center gap-x-1">
<DeleteGuestbookEntry id={elt.id} />

<div className="ml-2">
<span className="text-gray-500">{elt.username}:</span>{' '}
<span className="text-gray-800">{elt.body}</span>
</div>
<EditableGuestbookEntry
id={elt.id}
username={elt.username}
body={elt.body}
/>
</div>
))}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/DeleteGuestbookEntry.tsx
Expand Up @@ -31,7 +31,7 @@ const DeleteGuestbookEntry = (props: IDeleteGuestbookEntryProps) => {
}}
>
<svg
className="h-5 w-5 stroke-current"
className="h-6 w-6 stroke-current"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
Expand Down
66 changes: 66 additions & 0 deletions src/components/EditableGuestbookEntry.tsx
@@ -0,0 +1,66 @@
'use client';

import { useState } from 'react';

import { GuestbookForm } from './GuestbookForm';

type IEditableGuestbookEntryProps = {
id: number;
username: string;
body: string;
};

const EditableGuestbookEntry = (props: IEditableGuestbookEntryProps) => {
const [isEditing, setIsEditing] = useState(false);

const handleEdit = () => {
setIsEditing((value) => !value);
};

const handleStopEditing = () => {
setIsEditing(false);
};

return (
<>
<button
type="button"
onClick={() => {
handleEdit();
}}
>
<svg
className="h-6 w-6 stroke-current"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
viewBox="0 0 24 24"
>
<path stroke="none" d="M0 0h24v24H0z" />
<path d="M4 20h4L18.5 9.5a1.5 1.5 0 0 0-4-4L4 16v4M13.5 6.5l4 4" />
</svg>
</button>

<div className="ml-1 grow">
{isEditing ? (
<GuestbookForm
edit
id={props.id}
defaultValues={{
username: props.username,
body: props.body,
}}
handleStopEditing={handleStopEditing}
/>
) : (
<>
<span className="text-gray-500">{props.username}:</span>{' '}
<span className="text-gray-800">{props.body}</span>
</>
)}
</div>
</>
);
};

export { EditableGuestbookEntry };
Expand Up @@ -5,31 +5,57 @@ import { useRouter } from 'next/navigation';
import { useForm } from 'react-hook-form';
import type { z } from 'zod';

import { AddGuestbookSchema } from '@/validations/Guestbook';
import { GuestbookSchema } from '@/validations/GuestbookValidation';

const AddGuestbookForm = () => {
type IGuestbookFormProps =
| {
edit: true;
id: number;
defaultValues: z.infer<typeof GuestbookSchema>;
handleStopEditing: () => void;
}
| { edit?: false };

const GuestbookForm = (props: IGuestbookFormProps) => {
const {
handleSubmit,
register,
reset,
setFocus,
formState: { errors },
} = useForm<z.infer<typeof AddGuestbookSchema>>({
resolver: zodResolver(AddGuestbookSchema),
} = useForm<z.infer<typeof GuestbookSchema>>({
resolver: zodResolver(GuestbookSchema),
defaultValues: props.edit ? props.defaultValues : undefined,
});
const router = useRouter();

const handleCreate = handleSubmit(async (data) => {
await fetch(`/api/guestbook`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (props.edit) {
await fetch(`/api/guestbook`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: props.id,
...data,
}),
});

props.handleStopEditing();
} else {
await fetch(`/api/guestbook`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

setFocus('username');
reset();
}

setFocus('username');
reset();
router.refresh();
});

Expand Down Expand Up @@ -72,11 +98,11 @@ const AddGuestbookForm = () => {
className="rounded bg-blue-500 px-5 py-1 font-bold text-white hover:bg-blue-600 focus:outline-none focus:ring focus:ring-blue-300/50"
type="submit"
>
Send
Save
</button>
</div>
</form>
);
};

export { AddGuestbookForm };
export { GuestbookForm };
10 changes: 0 additions & 10 deletions src/validations/Guestbook.ts

This file was deleted.

16 changes: 16 additions & 0 deletions src/validations/GuestbookValidation.ts
@@ -0,0 +1,16 @@
import { z } from 'zod';

export const GuestbookSchema = z.object({
username: z.string().nonempty(),
body: z.string().nonempty(),
});

export const EditGuestbookSchema = z.object({
id: z.coerce.number(),
username: z.string().nonempty(),
body: z.string().nonempty(),
});

export const DeleteGuestbookSchema = z.object({
id: z.coerce.number(),
});

0 comments on commit 8ec1406

Please sign in to comment.