Skip to content

Commit

Permalink
updated more of the example frontend and some other updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmetskilinc committed Nov 4, 2024
1 parent cc9e248 commit 007ec1a
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 311 deletions.
29 changes: 29 additions & 0 deletions dev/src/app/(frontend)/actions/appointment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use server";

import configPromise from "@payload-config";
import { getPayloadHMR } from "@payloadcms/next/utilities";
import moment from "moment";

async function createAppointment(host: string, customer: string, services: string[], start: Date) {
const payload = await getPayloadHMR({ config: configPromise });
const response = await payload.create({
collection: "appointments",
overrideAccess: false,
data: {
host,
customer,
services,
appointmentType: "appointment",
start: moment(start).toISOString(),
},
});

if (!response.id) {
throw new Error("Login failed");
}

return {
success: true,
message: "Appointment created successfully",
};
}
1 change: 0 additions & 1 deletion dev/src/app/(frontend)/actions/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use server";

import Users from "@collections/Users";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

Expand Down
19 changes: 0 additions & 19 deletions dev/src/app/(frontend)/api/auth/get-appointments/route.ts

This file was deleted.

109 changes: 10 additions & 99 deletions dev/src/app/(frontend)/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import { cookies } from "next/headers";
import { logout } from "../actions/auth";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { redirect } from "next/navigation";
import { Appointment } from "../../../payload-types";
import moment from "moment";

import { getDashboardData } from "@lib/dashboardData";

const SERVER_URL = process.env.SERVER_URL;

const fetchAppointmentsForCustomer = async (id: string, email: string) => {
const response = await fetch(`${SERVER_URL}/api/auth/get-appointments`, {
method: "post",
body: JSON.stringify({ id, email }),
});

const { data } = await response.json();
return data as Appointment[];
};
import AppointmentsList from "@components/Appointments";

export default async function Dashboard() {
const cookieStore = await cookies();
Expand All @@ -30,10 +16,8 @@ export default async function Dashboard() {
}

let dashboardData;
let appointments;
try {
dashboardData = await getDashboardData();
appointments = await fetchAppointmentsForCustomer(dashboardData.user.id, dashboardData.user.email);
} catch (error) {
return (
<div className="p-8">
Expand All @@ -46,12 +30,11 @@ export default async function Dashboard() {
);
}

const appointments = dashboardData.user.appointments.docs as Appointment[];
const currentDate = new Date();

// @ts-expect-error
const upcomingAppointments = appointments.filter((appointment) => new Date(appointment.start) >= currentDate);
// @ts-expect-error
const pastAppointments = appointments.filter((appointment) => new Date(appointment.start) < currentDate);
const upcomingAppointments = appointments.filter((appointment) => new Date(appointment.start!) >= currentDate);
const pastAppointments = appointments.filter((appointment) => new Date(appointment.start!) < currentDate);

return (
<div className="w-screen flex justify-center py-4 px-4">
Expand All @@ -65,86 +48,14 @@ export default async function Dashboard() {
</TabsTrigger>
</TabsList>
<TabsContent value="upcoming">
{upcomingAppointments && upcomingAppointments.length ? (
upcomingAppointments.map((appointment: Appointment) => {
return (
<Card className="" key={appointment.id}>
<CardHeader>
<CardTitle className="text-base">{moment(appointment.start).format("dddd, MMM Do YYYY")}</CardTitle>
<CardDescription>
{moment(appointment.start).format("HH:mm")}
{" - "}
{moment(appointment.end).format("HH:mm")}
</CardDescription>
</CardHeader>
<CardContent>
{appointment.services?.map((service, index) => {
if (typeof service === "string") return;

// @ts-ignore
const previousServicesDuration = appointment.services!.slice(0, index).reduce((total, s) => total + s.duration, 0);

const serviceStartTime = moment(appointment.start).add(previousServicesDuration, "minutes");

const startsAt = serviceStartTime.format("HH:mm");

return (
<div key={index} className="mb-2">
<p className="text-sm">
{startsAt} {service.title} <br />
<span className="text-neutral-950/50">with {typeof appointment.host !== "string" ? appointment.host?.firstName : null}</span>
</p>
</div>
);
})}
</CardContent>
</Card>
);
})
) : (
<p>No appointments</p>
)}
<div className="flex flex-col gap-4">
<AppointmentsList appointments={upcomingAppointments} />
</div>
</TabsContent>
<TabsContent value="past">
{pastAppointments && pastAppointments.length ? (
pastAppointments.map((appointment: Appointment) => {
return (
<Card className="" key={appointment.id}>
<CardHeader>
<CardTitle className="text-base">{moment(appointment.start).format("dddd, MMM Do YYYY")}</CardTitle>
<CardDescription>
{moment(appointment.start).format("HH:mm")}
{" - "}
{moment(appointment.end).format("HH:mm")}
</CardDescription>
</CardHeader>
<CardContent>
{appointment.services?.map((service, index) => {
if (typeof service === "string") return;

// @ts-ignore
const previousServicesDuration = appointment.services!.slice(0, index).reduce((total, s) => total + s.duration, 0);

const serviceStartTime = moment(appointment.start).add(previousServicesDuration, "minutes");

const startsAt = serviceStartTime.format("HH:mm");

return (
<div key={index} className="mb-2">
<p className="text-sm">
{startsAt} {service.title} <br />
<span className="text-neutral-950/50">with {typeof appointment.host !== "string" ? appointment.host?.firstName : null}</span>
</p>
</div>
);
})}
</CardContent>
</Card>
);
})
) : (
<p>No appointments</p>
)}
<div className="flex flex-col gap-4">
<AppointmentsList appointments={pastAppointments} />
</div>
</TabsContent>
</Tabs>
</div>
Expand Down
46 changes: 46 additions & 0 deletions dev/src/components/Appointments/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Appointment } from "payload/generated-types";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import moment from "moment";

type Props = {
appointments: Appointment[];
};

const Appointments = ({ appointments }: Props) =>
appointments && appointments.length ? (
appointments.map((appointment: Appointment) => {
return (
<Card className="" key={appointment.id}>
<CardHeader>
<CardTitle className="text-base">{moment(appointment.start).format("dddd, MMM Do YYYY")}</CardTitle>
<CardDescription>
{moment(appointment.start).format("HH:mm")}
{" - "}
{moment(appointment.end).format("HH:mm")}
</CardDescription>
</CardHeader>
<CardContent>
{appointment.services?.map((service, index) => {
if (typeof service === "string") return;
// @ts-expect-error
const previousServicesDuration = appointment.services!.slice(0, index).reduce((total, s) => total + s.duration, 0);
const serviceStartTime = moment(appointment.start).add(previousServicesDuration, "minutes");
const startsAt = serviceStartTime.format("HH:mm");
return (
<div key={index} className="mb-2">
<p className="text-sm">
{startsAt} {service.title} <br />
<span className="text-neutral-950/50">with {typeof appointment.host !== "string" ? appointment.host?.firstName : null}</span>
</p>
</div>
);
})}
</CardContent>
</Card>
);
})
) : (
<p>No appointments</p>
);

export default Appointments;
95 changes: 27 additions & 68 deletions dev/src/components/Book/CustomerDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Service, TeamMember } from "../../../src/payload-types";
const CustomerDetails: React.FC<{
chosenDateTime: Date | null;
chosenServices: Service[];
chosenStaff: TeamMember[];
chosenStaff: TeamMember | null;
setCustomerDetails: React.Dispatch<
React.SetStateAction<{
firstName: string;
Expand All @@ -25,88 +25,47 @@ const CustomerDetails: React.FC<{
return (
<div className="flex flex-col gap-2 md:gap-4 mt-6">
<div className="flex gap-2 md:gap-6 w-full">
<label className="w-full" htmlFor="firstname">
<span className="text-sm font-semibold leading-6 text-gray-900">First name</span>
<label className="w-full" htmlFor="chosenServices">
<span className="text-sm font-semibold leading-6 text-gray-900">Services</span>
<div className="mt-2.5">
<input
className="block w-full rounded-none border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm/6"
id="firstname"
name="firstname"
placeholder="First name"
id="chosenServices"
name="chosenServices"
type="text"
value={customerDetails.firstName}
onChange={(e) => {
setCustomerDetails({
...customerDetails,
firstName: e.currentTarget.value,
});
}}
disabled
value={chosenServices.map((service) => service.id)}
/>
</div>
</label>
<label className="w-full block" htmlFor="lastname">
<span className="text-sm font-semibold leading-6 text-gray-900">Last name</span>
<label className="w-full block" htmlFor="host">
<span className="text-sm font-semibold leading-6 text-gray-900">Host</span>
<div className="mt-2.5">
<input
className="block w-full rounded-none border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm/6"
id="lastname"
name="lastname"
placeholder="Last name"
id="host"
disabled
name="host"
type="text"
value={customerDetails.lastName}
onChange={(e) => {
setCustomerDetails({
...customerDetails,
lastName: e.currentTarget.value,
});
}}
/>
</div>
</label>
</div>
<div className="flex gap-2 md:gap-6 w-full">
<label className="w-full block" htmlFor="phone">
<span className="block text-sm font-medium leading-6 text-gray-900">Phone</span>
<div className="relative mt-2.5 rounded-none shadow-sm">
<div className="pointer-events-none absolute text-sm inset-y-0 left-0 flex items-center pl-3">
<span className="text-gray-500">+44</span>
</div>
<input
className="block w-full rounded-none border-0 py-1.5 px-2 pl-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm/6"
id="phone"
name="phone"
placeholder="0000000000"
type="text"
value={customerDetails.phone}
onChange={(e) => {
setCustomerDetails({
...customerDetails,
phone: e.currentTarget.value,
});
}}
/>
</div>
</label>
<label className="w-full block" htmlFor="email">
<span className="text-sm font-semibold leading-6 text-gray-900">Email</span>
<div className="mt-2.5">
<input
className="block w-full rounded-none border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm/6"
id="email"
name="email"
placeholder="Email"
type="text"
value={customerDetails.email}
onChange={(e) => {
setCustomerDetails({
...customerDetails,
email: e.currentTarget.value,
});
}}
value={chosenStaff?.id}
onChange={() => {}}
/>
</div>
</label>
</div>
<label className="w-full block" htmlFor="host">
<span className="text-sm font-semibold leading-6 text-gray-900">Host</span>
<div className="mt-2.5">
<input
className="block w-full rounded-none border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm/6"
id="host"
disabled
name="host"
type="text"
value={chosenDateTime?.toISOString()}
/>
</div>
</label>
<label className="w-full block" htmlFor="message">
<span className="text-sm font-semibold leading-6 text-gray-900">Customer notes (optional)</span>
<div className="mt-2.5">
Expand Down
Loading

0 comments on commit 007ec1a

Please sign in to comment.