"use client" import { useState, useEffect } from "react" import { format, eachDayOfInterval, isSameDay } from "date-fns" import { de, enUS } from "date-fns/locale" import { CalendarIcon, User, Home, X, Info, Utensils, Trash2, Check, Share2 } 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 { Textarea } from "@/components/ui/textarea" import { uploadImage } from "@/app/actions/upload-image" import { Camera, Upload } from "lucide-react" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { createBooking, deleteBooking, completeBooking } from "@/app/actions/booking" import { PlanSettings } from "@/components/plan-settings" type Booking = { id: number date: Date sitterName: string | null type: string completedAt?: Date | string | null } type Plan = { id: string title: string startDate: Date endDate: Date instructions: string | null webhookUrl: string | null notifyAll: boolean bookings: Booking[] feedingPerDay: number feedingInterval: number litterInterval: number } interface PlanDashboardProps { plan: Plan; dict: any; settingsDict: any; lang: string; } export function PlanDashboard({ plan, dict, settingsDict, lang }: PlanDashboardProps) { const [selectedDate, setSelectedDate] = useState(null) const [sitterName, setSitterName] = useState("") const [bookingType, setBookingType] = useState<"SITTER" | "OWNER_HOME">("SITTER") const [isDialogOpen, setIsDialogOpen] = useState(false) const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false) const [bookingToCancel, setBookingToCancel] = useState(null) const [cancelReason, setCancelReason] = useState("") const [isSubmitting, setIsSubmitting] = useState(false) // Completion Dialog State const [isCompleteDialogOpen, setIsCompleteDialogOpen] = useState(false) const [bookingToComplete, setBookingToComplete] = useState(null) const [completionMessage, setCompletionMessage] = useState("") const [completionImage, setCompletionImage] = useState(null) const [imagePreview, setImagePreview] = useState(null) const handleCompleteClick = (bookingId: number) => { setBookingToComplete(bookingId) setCompletionMessage("") setCompletionImage(null) setImagePreview(null) setIsCompleteDialogOpen(true) } const handleImageChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { setCompletionImage(file) const reader = new FileReader() reader.onloadend = () => { setImagePreview(reader.result as string) } reader.readAsDataURL(file) } } const handleConfirmComplete = async () => { if (!bookingToComplete) return setIsSubmitting(true) try { let imageUrl: string | undefined = undefined if (completionImage) { const formData = new FormData() formData.append("file", completionImage) formData.append("planId", plan.id) imageUrl = await uploadImage(formData) } await completeBooking(bookingToComplete, plan.id, lang, completionMessage, imageUrl) toast.success(dict.jobDone) setIsCompleteDialogOpen(false) setBookingToComplete(null) } catch (error) { console.error(error) toast.error(dict.bookError) } finally { setIsSubmitting(false) } } const dateLocale = lang === "de" ? de : enUS // 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(dict.namePlaceholder) // Could use a more specific key if needed return } setIsSubmitting(true) try { await createBooking(plan.id, selectedDate, bookingType === "SITTER" ? sitterName : "Owner", bookingType, lang) // Save name to localStorage if it's a sitter booking if (bookingType === "SITTER") { localStorage.setItem("sitter_name", sitterName) } toast.success(dict.bookedSuccess) setIsDialogOpen(false) } catch (error) { toast.error(dict.bookError) } finally { setIsSubmitting(false) } } const handleCancelClick = (bookingId: number) => { setBookingToCancel(bookingId) setCancelReason("") setIsCancelDialogOpen(true) } const handleConfirmCancel = async () => { if (!bookingToCancel) return setIsSubmitting(true) try { await deleteBooking(bookingToCancel, plan.id, lang, cancelReason) toast.success(dict.cancelSuccess) setIsCancelDialogOpen(false) setBookingToCancel(null) } catch { toast.error(dict.cancelError) } finally { setIsSubmitting(false) } } return (

{dict.overview}

{plan.instructions && ( {dict.instructionsTitle}
{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, "PPPP", { locale: dateLocale })}
{booking && ( )}
{booking ? (
{isOwnerHome ? ( <> {dict.ownerHome} ) : ( <> {booking.sitterName} )}
{booking.type === "SITTER" && (
{booking.completedAt ? (
{dict.jobDone}
) : ( // Only show button if day is today or in the past day <= new Date() || isSameDay(day, new Date()) ? ( ) : null )}
)}
) : ( { setIsDialogOpen(open) if (open) setSelectedDate(day) else setSelectedDate(null) }}> {dict.bookTitle.replace("{date}", format(day, "PPP", { locale: dateLocale }))} {dict.bookDesc}
setBookingType(v)} className="flex gap-4">
{bookingType === "SITTER" && (
setSitterName(e.target.value)} placeholder={dict.namePlaceholder} autoFocus />
)}
)}
{Math.floor((day.getTime() - new Date(plan.startDate).setHours(0, 0, 0, 0)) / (1000 * 60 * 60 * 24)) % plan.feedingInterval === 0 && (
{Array.from({ length: plan.feedingPerDay }).map((_, i) => ( ))}
)} {Math.floor((day.getTime() - new Date(plan.startDate).setHours(0, 0, 0, 0)) / (1000 * 60 * 60 * 24)) % plan.litterInterval === 0 && (
)}
) })}
{/* Cancellation Dialog */} {dict.cancelTitle} {dict.cancelConfirm} {plan.webhookUrl && (
setCancelReason(e.target.value)} placeholder={dict.cancelMessagePlaceholder} autoFocus />
)}
{/* Completion Dialog */} {dict.completeTitle} {dict.completeDesc}