From 2f5438985aecbbe2d334f80d2fa775999a1b143d Mon Sep 17 00:00:00 2001 From: Taek Been Nam Date: Tue, 7 May 2024 16:51:07 -0400 Subject: [PATCH 1/2] clean up --- .../newAppointmentDialog.tsx | 2 +- app/(protected)/my-appointments/page.tsx | 29 +------------------ 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx b/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx index d6744e7..6a13c30 100644 --- a/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx +++ b/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx @@ -49,7 +49,7 @@ export default function NewAppointmentDialog({ {trigger} - Edit Appointment + New Appointment Change your appointment details. diff --git a/app/(protected)/my-appointments/page.tsx b/app/(protected)/my-appointments/page.tsx index 0e46d2b..10ae4dd 100644 --- a/app/(protected)/my-appointments/page.tsx +++ b/app/(protected)/my-appointments/page.tsx @@ -1,18 +1,10 @@ import { Button } from "@/components/atoms/button"; import { Container } from "@/components/templates/container"; import { PlusIcon } from "lucide-react"; -import { AppointmentForm, AppointmentList } from "./components"; +import { AppointmentList } from "./components"; import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"; import { redirect } from "next/navigation"; import NewAppointmentDialog from "./components/newAppointmentDialog/newAppointmentDialog"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/molecules/dialog"; export default async function MyAppointments() { const { isAuthenticated } = getKindeServerSession(); @@ -27,25 +19,6 @@ export default async function MyAppointments() {

My Appointments

- {/* - - - - - - Edit Appointment - - Change your appointment details. - - - - - */} Date: Tue, 7 May 2024 21:41:43 -0400 Subject: [PATCH 2/2] implement edit appointment --- .../appointmentDateTimePicker.tsx | 1 - .../appointmentForm/appointmentForm.tsx | 58 ++++++---- .../appointments/upcomingAppointments.tsx | 105 +++++++++--------- .../components/cancelDialog/cancelDialog.tsx | 2 - .../components/editDialog/editDialog.tsx | 13 ++- .../newAppointmentDialog.tsx | 3 +- app/api/my-appointments/route.ts | 2 +- lib/sanity/client.ts | 6 +- lib/sanity/sanity.types.ts | 4 +- 9 files changed, 100 insertions(+), 94 deletions(-) diff --git a/app/(protected)/my-appointments/components/appointmentDateTimePicker/appointmentDateTimePicker.tsx b/app/(protected)/my-appointments/components/appointmentDateTimePicker/appointmentDateTimePicker.tsx index 4686c0a..1742fa7 100644 --- a/app/(protected)/my-appointments/components/appointmentDateTimePicker/appointmentDateTimePicker.tsx +++ b/app/(protected)/my-appointments/components/appointmentDateTimePicker/appointmentDateTimePicker.tsx @@ -28,7 +28,6 @@ function AppointmentDateTimePicker({ selected={selectedDate} onSelect={(selectedDate) => handleSelect(selectedDate)} disabled={(date) => { - console.log(date < new Date(), date); return new Date(date).getTime() < new Date().setHours(0, 0, 0, 0); }} /> diff --git a/app/(protected)/my-appointments/components/appointmentForm/appointmentForm.tsx b/app/(protected)/my-appointments/components/appointmentForm/appointmentForm.tsx index 4510dc7..7ab3504 100644 --- a/app/(protected)/my-appointments/components/appointmentForm/appointmentForm.tsx +++ b/app/(protected)/my-appointments/components/appointmentForm/appointmentForm.tsx @@ -1,7 +1,6 @@ "use client"; import { z } from "zod"; -import { format } from "date-fns"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@/components/atoms/button"; @@ -19,12 +18,13 @@ import { useToast } from "@/components/molecules/toast"; import { FormSchema } from "@/lib/formSchema"; import { cn, formatToDisplayDate, formatToDisplayTime } from "@/lib/utils"; import AppointmentDateTimePicker from "../appointmentDateTimePicker/appointmentDateTimePicker"; +import { APPOINTMENT_QUERYResult } from "@/lib/sanity/sanity.types"; /** * Extracted async calls into its own functions to manage them separate from rendering logic. * We can potentially make them into server actions. */ -async function createAppointment(formValues: any) { +async function createAppointment(formValues: z.infer) { const res = await fetch("/api/my-appointments", { method: "POST", body: JSON.stringify({ @@ -35,6 +35,21 @@ async function createAppointment(formValues: any) { return Response.json(res); } +async function editAppointment( + formValues: z.infer, + appointmentId: string, +) { + const res = await fetch("/api/my-appointments", { + method: "PATCH", + body: JSON.stringify({ + id: appointmentId, + formValues, + }), + }); + + return Response.json(res); +} + async function sendEmail(formValues: z.infer) { const { timeslot, address1, address2, city, state, zipCode, comment } = formValues; @@ -67,7 +82,7 @@ const INITIAL_FORM_VALUES: z.infer = { interface AppointmentFormProps { id?: string; mode?: "create" | "edit"; - appointment?: any; + appointment?: APPOINTMENT_QUERYResult[0]; onClose?: () => void; } @@ -82,29 +97,30 @@ export const AppointmentForm = ({ const submitBtnLabel = (mode === "create" ? "Book" : "Edit") + " Appointment"; const { toast } = useToast(); const form = useForm>({ - defaultValues: INITIAL_FORM_VALUES, - // mode === "edit" && !!appointment - // ? { - // date: appointment.timeSlot - // ? unixToDateTimeStrings(appointment.timeSlot?.startTime).date - // : "", - // time: appointment.timeSlot - // ? unixToDateTimeStrings(appointment.timeSlot?.startTime).time - // : "", - // address1: appointment.address1, - // address2: appointment.address2, - // city: appointment.city, - // state: appointment.state, - // zipCode: appointment.zipCode, - // comment: appointment.comment, - // } - // : INITIAL_FORM_VALUES, + defaultValues: + mode === "edit" && !!appointment + ? { + timeslot: { + id: appointment.timeslotId, + date: appointment.date, + time: appointment.time, + }, + address1: appointment.address1, + address2: appointment.address2, + city: appointment.city, + state: appointment.state, + zipCode: appointment.zipCode, + comment: appointment.comment, + } + : INITIAL_FORM_VALUES, resolver: zodResolver(FormSchema), }); const onSubmit = async (values: z.infer) => { try { - await createAppointment({ ...values }); + mode === "edit" && !!appointment + ? await editAppointment(values, appointment.id) + : await createAppointment({ ...values }); await sendEmail(values); onClose ? onClose() : null; diff --git a/app/(protected)/my-appointments/components/appointments/upcomingAppointments.tsx b/app/(protected)/my-appointments/components/appointments/upcomingAppointments.tsx index 178ea21..57074e7 100644 --- a/app/(protected)/my-appointments/components/appointments/upcomingAppointments.tsx +++ b/app/(protected)/my-appointments/components/appointments/upcomingAppointments.tsx @@ -18,61 +18,56 @@ export default async function UpcomingAppointments() { // TODO: add logic for handling error and empty array state. return ( <> - {appointments.map( - ({ - id, - date, - time, - address1, - address2, - city, - state, - zipCode, - comment, - }) => ( - - -

- - {formatToDisplayDate(date)} -

-

- - {formatToDisplayTime(time)} -

-

- {[address1, address2, city, state, zipCode] - .filter((address) => address) - .join(", ")} -

-

- {comment} -

-
- - - Cancel - - } - /> - - Edit - - } - /> - -
- ), - )} + {appointments.map((appointment) => ( + + +

+ + {formatToDisplayDate(appointment.date)} +

+

+ + {formatToDisplayTime(appointment.time)} +

+

+ {[ + appointment.address1, + appointment.address2, + appointment.city, + appointment.state, + appointment.zipCode, + ] + .filter((address) => address) + .join(", ")} +

+

+ {appointment.comment} +

+
+ + + Cancel + + } + /> + + Edit + + } + /> + +
+ ))} ); } diff --git a/app/(protected)/my-appointments/components/cancelDialog/cancelDialog.tsx b/app/(protected)/my-appointments/components/cancelDialog/cancelDialog.tsx index 9490c99..d0d8dc7 100644 --- a/app/(protected)/my-appointments/components/cancelDialog/cancelDialog.tsx +++ b/app/(protected)/my-appointments/components/cancelDialog/cancelDialog.tsx @@ -35,13 +35,11 @@ const cancelAppointment = async ( }; interface CancelDialogProps { - timeSlotId?: string; appointmentId: string; trigger: React.ReactNode; } export default function CancelDialog({ - timeSlotId, appointmentId, trigger, }: CancelDialogProps) { diff --git a/app/(protected)/my-appointments/components/editDialog/editDialog.tsx b/app/(protected)/my-appointments/components/editDialog/editDialog.tsx index a669eca..240cd1d 100644 --- a/app/(protected)/my-appointments/components/editDialog/editDialog.tsx +++ b/app/(protected)/my-appointments/components/editDialog/editDialog.tsx @@ -17,6 +17,7 @@ import { } from "@/components/molecules/drawer"; import { useEffect, useState } from "react"; import { AppointmentForm } from "../appointmentForm/appointmentForm"; +import { APPOINTMENT_QUERYResult } from "@/lib/sanity/sanity.types"; /** * Renders `` in ``. @@ -27,7 +28,7 @@ export default function EditDialog({ appointment, }: { trigger: React.ReactNode; - appointment?: any; + appointment: APPOINTMENT_QUERYResult[0]; }) { const [matches, setMatches] = useState(false); const [open, setOpen] = useState(false); @@ -46,18 +47,18 @@ export default function EditDialog({ return matches ? ( {trigger} - + Edit Appointment Change your appointment details. - {/* setOpen(false)} - /> */} + /> ) : ( @@ -67,11 +68,11 @@ export default function EditDialog({ Edit Appointment - {/* setOpen(false)} - /> */} + /> ); diff --git a/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx b/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx index 6a13c30..e864a69 100644 --- a/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx +++ b/app/(protected)/my-appointments/components/newAppointmentDialog/newAppointmentDialog.tsx @@ -28,7 +28,6 @@ export default function NewAppointmentDialog({ trigger, }: { trigger: React.ReactNode; - appointment?: any; }) { const [matches, setMatches] = useState(false); const [open, setOpen] = useState(false); @@ -69,7 +68,7 @@ export default function NewAppointmentDialog({ - Edit Appointment + New Appointment
setOpen(false)} /> diff --git a/app/api/my-appointments/route.ts b/app/api/my-appointments/route.ts index 2269997..c518acd 100644 --- a/app/api/my-appointments/route.ts +++ b/app/api/my-appointments/route.ts @@ -42,7 +42,7 @@ export async function PATCH(req: NextRequest) { } const payload = await req.json(); - const res = await updateAppointment(payload, user.id); + const res = await updateAppointment(payload.formValues, user.id, payload.id); return Response.json(res); } diff --git a/lib/sanity/client.ts b/lib/sanity/client.ts index 19829b5..89737f1 100644 --- a/lib/sanity/client.ts +++ b/lib/sanity/client.ts @@ -117,12 +117,10 @@ export const createAppointment = async ( export const updateAppointment = async ( form: z.infer, userId: string, + appointmentId: string, ) => { const appointment = mapAppointment(form, userId); - const res = await client - .patch("YamW7iUfTGgX1JkiOPz5iP") - .set(appointment) - .commit(); + const res = await client.patch(appointmentId).set(appointment).commit(); return res; }; diff --git a/lib/sanity/sanity.types.ts b/lib/sanity/sanity.types.ts index ec74b44..49c33c5 100644 --- a/lib/sanity/sanity.types.ts +++ b/lib/sanity/sanity.types.ts @@ -281,11 +281,11 @@ export type APPOINTMENT_QUERYResult = Array<{ date: string; time: string; address1: string; - address2: string | null; + address2: string | undefined; city: string; state: string; zipCode: string; - comment: string | null; + comment: string | undefined; customer: { id: string; firstName: string;