diff --git a/suncityla/app/booking/actions/onSubmitAction.ts b/suncityla/app/booking/actions/onSubmitAction.ts index 517747b..5f16fc2 100644 --- a/suncityla/app/booking/actions/onSubmitAction.ts +++ b/suncityla/app/booking/actions/onSubmitAction.ts @@ -39,7 +39,6 @@ const onSubmitAction = async (prvState: FormState, data: FormData): Promise
{ {booking.firstname} {booking.lastname} - {format(new Date(booking.bookingDate), 'yyyy-MM-dd')} - {booking.bookingTime} + {format(new Date(booking.bookingDate), 'EE dd/MM/yy')} + {`${format(new Date(booking.bookingDate), 'h:mm a')} - ${format( + add(new Date(booking.bookingDate), { hours: 1 }), + 'h:mm a', + )}`} {booking.streetAddress} {booking.postalCode} {booking.state} diff --git a/suncityla/app/booking/components/BookingForm/BookingForm.tsx b/suncityla/app/booking/components/BookingForm/BookingForm.tsx index c154264..d5f1228 100644 --- a/suncityla/app/booking/components/BookingForm/BookingForm.tsx +++ b/suncityla/app/booking/components/BookingForm/BookingForm.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useActionState, useRef, startTransition, useEffect } from 'react'; +import { useActionState, useRef, startTransition, useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; @@ -14,7 +14,8 @@ import onSubmitAction from '@/app/booking/actions/onSubmitAction'; import { bookingFormSchema } from '../../schemas/newBookingForm'; import { Booking } from '@prisma/client'; import TimeSelect from '../TimeSelect/TimeSelect'; -import availableTimes from '../TimeSelect/times'; +import createAvailableTimes from '../TimeSelect/times'; +import { set } from 'date-fns'; export type BookingFormData = z.infer; @@ -34,16 +35,21 @@ export default function BookingForm({ booking }: { booking?: Booking | null }) { 'street-address': booking?.streetAddress ?? '', 'postal-code': booking?.postalCode ?? '', state: 'LA', - bookingDate: booking?.bookingDate.toISOString() ?? new Date().toISOString(), - bookingTime: booking?.bookingTime || availableTimes[0].time, + bookingDate: booking?.bookingDate.toISOString() || '', ...(state.fields ?? {}), }, }); + // Time Stamp + const [time, setSelectedTime] = useState(booking?.bookingDate.getTime()); + const watchDate = form.watch('bookingDate'); + const availableTimes = createAvailableTimes(new Date(watchDate)); + const formRef = useRef(null); const handleClearForm = () => { form.reset(); + setSelectedTime(undefined); }; useEffect(() => { @@ -52,6 +58,16 @@ export default function BookingForm({ booking }: { booking?: Booking | null }) { } }, [state.bookingRef, isPending, router, state.message]); + useEffect(() => { + if (time) { + const newDateWithTime = new Date(watchDate); + const hours = new Date(time).getHours(); + newDateWithTime.setHours(hours); + form.setValue('bookingDate', newDateWithTime.toISOString()); + return; + } + }, [watchDate, time, form]); + return (
@@ -78,13 +94,21 @@ export default function BookingForm({ booking }: { booking?: Booking | null }) { - - + setSelectedTime(undefined)} /> + {watchDate && ( + + )}
- - + )} +
diff --git a/suncityla/app/booking/components/TimeDatePicker/TimeDatePicker.tsx b/suncityla/app/booking/components/TimeDatePicker/TimeDatePicker.tsx index 4505cd7..462aff7 100644 --- a/suncityla/app/booking/components/TimeDatePicker/TimeDatePicker.tsx +++ b/suncityla/app/booking/components/TimeDatePicker/TimeDatePicker.tsx @@ -1,25 +1,21 @@ -"use client"; +'use client'; -import { useState } from "react"; -import { format } from "date-fns"; -import { Calendar as CalendarIcon } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { Calendar } from "@/components/ui/calendar"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; +import { useState } from 'react'; +import { format } from 'date-fns'; +import { Calendar as CalendarIcon } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { Button } from '@/components/ui/button'; +import { Calendar } from '@/components/ui/calendar'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { FormControl, FormDescription, FormField, FormItem, FormMessage, -} from "@/components/ui/form"; +} from '@/components/ui/form'; -export function DateTimePickerForm() { +export function DateTimePickerForm({ onChange }: { onChange: () => void }) { const [open, setOpen] = useState(false); return ( @@ -34,16 +30,12 @@ export function DateTimePickerForm() { onClick={() => setOpen(true)} variant="outline" className={cn( - "w-full justify-start font-normal", - !field.value && "text-muted-foreground" + 'w-full justify-start font-normal', + !field.value && 'text-muted-foreground', )} > - {field.value ? ( - format(field.value, "PPP") - ) : ( - Pick a date - )} + {field.value ? format(field.value, 'PPP') : Pick a date} @@ -54,17 +46,12 @@ export function DateTimePickerForm() { onSelect={(date) => { field.onChange(date?.toISOString()); setOpen(false); + onChange(); }} - initialFocus /> - + diff --git a/suncityla/app/booking/components/TimeSelect/TimeSelect.tsx b/suncityla/app/booking/components/TimeSelect/TimeSelect.tsx index 0a66f23..7a41e70 100644 --- a/suncityla/app/booking/components/TimeSelect/TimeSelect.tsx +++ b/suncityla/app/booking/components/TimeSelect/TimeSelect.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as React from 'react'; import { @@ -9,34 +11,47 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; -import availableTimes from './times'; import { FormField, FormItem } from '@/components/ui/form'; +import { format } from 'date-fns'; -export function TimeSelect() { +export function TimeSelect({ + availableTimes, + selectedTime, + onTimeSelect, +}: { + availableTimes: { from: number; to: number }[]; + selectedTime?: number; + onTimeSelect: (time: number) => void; +}) { return ( ( - - - - )} + name="" + render={() => { + return ( + + + + ); + }} /> ); } diff --git a/suncityla/app/booking/components/TimeSelect/times.ts b/suncityla/app/booking/components/TimeSelect/times.ts index 213e835..fcf93d5 100644 --- a/suncityla/app/booking/components/TimeSelect/times.ts +++ b/suncityla/app/booking/components/TimeSelect/times.ts @@ -1,18 +1,12 @@ -const availableTimes = [ - { time: '8:00 - 9:00 AM' }, - { time: '9:00 - 10:00 AM' }, - { time: '10:00 - 11:00 AM' }, - { time: '11:00 - 12:00 PM' }, - { time: '12:00 - 1:00 PM' }, - { time: '1:00 - 2:00 PM' }, - { time: '2:00 - 3:00 PM' }, - { time: '3:00 - 4:00 PM' }, - { time: '4:00 - 5:00 PM' }, - { time: '5:00 - 6:00 PM' }, - { time: '6:00 - 7:00 PM' }, - { time: '7:00 - 8:00 PM' }, - { time: '8:00 - 9:00 PM' }, - { time: '9:00 - 10:00 PM' }, -]; +const createAvailableTimes = (date: Date) => { + const availableTimes = []; + for (let i = 8; i < 20; i++) { + availableTimes.push({ + from: date.setHours(i, 0, 0, 0), + to: date.setHours(i + 1, 0, 0, 0), + }); + } + return availableTimes; +}; -export default availableTimes; +export default createAvailableTimes; diff --git a/suncityla/app/booking/schemas/newBookingForm.ts b/suncityla/app/booking/schemas/newBookingForm.ts index 2d33740..e8610a8 100644 --- a/suncityla/app/booking/schemas/newBookingForm.ts +++ b/suncityla/app/booking/schemas/newBookingForm.ts @@ -31,6 +31,5 @@ export const bookingFormSchema = z.object({ message: 'Booking date must be in the future.', }, ), - bookingTime: z.string(), bookingId: z.string().optional(), }); diff --git a/suncityla/components/ui/calendar.tsx b/suncityla/components/ui/calendar.tsx index d465dc8..037ce79 100644 --- a/suncityla/components/ui/calendar.tsx +++ b/suncityla/components/ui/calendar.tsx @@ -1,67 +1,60 @@ -"use client"; +'use client'; -import * as React from "react"; -import { ChevronLeft, ChevronRight } from "lucide-react"; -import { DayPicker } from "react-day-picker"; +import * as React from 'react'; +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import { DayPicker } from 'react-day-picker'; -import { cn } from "@/lib/utils"; -import { buttonVariants } from "@/components/ui/button"; +import { cn } from '@/lib/utils'; +import { buttonVariants } from '@/components/ui/button'; export type CalendarProps = React.ComponentProps; -function Calendar({ - className, - classNames, - showOutsideDays = true, - ...props -}: CalendarProps) { +function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) { return ( .day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md" - : "[&:has([aria-selected])]:rounded-md" + 'relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md', + props.mode === 'range' + ? '[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md' + : '[&:has([aria-selected])]:rounded-md', ), day: cn( - buttonVariants({ variant: "ghost" }), - "h-8 w-8 p-0 font-normal aria-selected:opacity-100" + buttonVariants({ variant: 'ghost' }), + 'h-8 w-8 p-0 font-normal aria-selected:opacity-100', ), - day_range_start: "day-range-start", - day_range_end: "day-range-end", + day_range_start: 'day-range-start', + day_range_end: 'day-range-end', day_selected: - "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground", - day_today: "bg-accent text-accent-foreground", + 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground', + day_today: 'bg-accent text-accent-foreground', day_outside: - "day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground", - day_disabled: "text-muted-foreground opacity-50", - day_range_middle: - "aria-selected:bg-accent aria-selected:text-accent-foreground", - day_hidden: "invisible", + 'day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground', + day_disabled: 'text-muted-foreground opacity-50', + day_range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground', + day_hidden: 'invisible', ...classNames, }} components={{ Chevron(props) { - if (props.orientation === "left") { + if (props.orientation === 'left') { return ; } return ; @@ -71,6 +64,6 @@ function Calendar({ /> ); } -Calendar.displayName = "Calendar"; +Calendar.displayName = 'Calendar'; export { Calendar }; diff --git a/suncityla/prisma/migrations/20241206173508_remove_bookingtime_column/migration.sql b/suncityla/prisma/migrations/20241206173508_remove_bookingtime_column/migration.sql new file mode 100644 index 0000000..f0d702d --- /dev/null +++ b/suncityla/prisma/migrations/20241206173508_remove_bookingtime_column/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to drop the column `bookingTime` on the `Booking` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Booking" DROP COLUMN "bookingTime"; diff --git a/suncityla/prisma/schema.prisma b/suncityla/prisma/schema.prisma index 0d2f795..0f1eb63 100644 --- a/suncityla/prisma/schema.prisma +++ b/suncityla/prisma/schema.prisma @@ -95,7 +95,6 @@ model Booking { postalCode String state String bookingDate DateTime - bookingTime String? status BookingStatus @default(PENDING) }