"use client" import { useState, useEffect } from "react" import { format, eachDayOfInterval, isSameDay } from "date-fns" import { CalendarIcon, User, Home, X, Info } from "lucide-react" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { createBooking, deleteBooking } from "@/app/actions/booking" import { PlanSettings } from "@/components/plan-settings" type Booking = { id: number date: Date sitterName: string | null type: string } type Plan = { id: string startDate: Date endDate: Date instructions: string | null webhookUrl: string | null notifyAll: boolean bookings: Booking[] } export function PlanDashboard({ plan }: { plan: Plan }) { const [selectedDate, setSelectedDate] = useState(null) const [sitterName, setSitterName] = useState("") const [bookingType, setBookingType] = useState<"SITTER" | "OWNER_HOME">("SITTER") const [isDialogOpen, setIsDialogOpen] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false) // Load saved name from localStorage useEffect(() => { const savedName = localStorage.getItem("sitter_name") if (savedName) setSitterName(savedName) }, []) // Generate all days const days = eachDayOfInterval({ start: new Date(plan.startDate), end: new Date(plan.endDate), }) const handleBook = async () => { if (!selectedDate) return if (bookingType === "SITTER" && !sitterName.trim()) { toast.error("Please enter your name") return } setIsSubmitting(true) try { await createBooking(plan.id, selectedDate, bookingType === "SITTER" ? sitterName : "Owner", bookingType) // Save name to localStorage if it's a sitter booking if (bookingType === "SITTER") { localStorage.setItem("sitter_name", sitterName) } toast.success("Spot booked!") setIsDialogOpen(false) // We keep the sitterName in state for the next booking } catch (error) { toast.error("Failed to book spot. Maybe it was just taken?") } finally { setIsSubmitting(false) } } const handleCancel = async (bookingId: number) => { // Optimistic UI could stay here, but relying on revalidatePath is safer for simple apps if (!confirm("Are you sure you want to remove this entry?")) return try { await deleteBooking(bookingId, plan.id) toast.success("Entry removed") } catch { toast.error("Failed to remove entry") } } return (

Overview

{plan.instructions && ( Cat Care Instructions
{plan.instructions}
)}
{days.map((day) => { const booking = plan.bookings.find((b) => isSameDay(new Date(b.date), day)) const isOwnerHome = booking?.type === "OWNER_HOME" return (
{format(day, "EEEE, MMMM do")}
{booking && ( )}
{booking ? (
{isOwnerHome ? ( <> Owner Home ) : ( <> {booking.sitterName} )}
) : ( { setIsDialogOpen(open) if (open) setSelectedDate(day) else setSelectedDate(null) }}> Book {format(day, "MMMM do")} Who is taking care of the cats?
setBookingType(v)} className="flex gap-4">
{bookingType === "SITTER" && (
setSitterName(e.target.value)} placeholder="Your Name" autoFocus />
)}
)}
) })}
) }