From e10e43fb8b3ae05ae72990794141248eb15315b1 Mon Sep 17 00:00:00 2001 From: Felipe Cardoso Date: Sun, 16 Mar 2025 17:56:14 +0100 Subject: [PATCH] Add gift modal --- .../dashboard/events/[slug]/gifts/page.tsx | 32 +- frontend/src/components/gifts/gift-modal.tsx | 495 ++++++++++++++++++ 2 files changed, 525 insertions(+), 2 deletions(-) create mode 100644 frontend/src/components/gifts/gift-modal.tsx diff --git a/frontend/src/app/(main)/dashboard/events/[slug]/gifts/page.tsx b/frontend/src/app/(main)/dashboard/events/[slug]/gifts/page.tsx index 537f159..3568a8b 100644 --- a/frontend/src/app/(main)/dashboard/events/[slug]/gifts/page.tsx +++ b/frontend/src/app/(main)/dashboard/events/[slug]/gifts/page.tsx @@ -47,6 +47,7 @@ import { } from "@/components/ui/select"; import { GiftStatus, GiftPriority } from "@/client/types.gen"; import { CategoryModal } from "@/components/gifts/category-modal"; +import { GiftModal } from "@/components/gifts/gift-modal"; export default function GiftRegistryPage() { const { slug } = useParams<{ slug: string }>(); @@ -588,6 +589,15 @@ export default function GiftRegistryPage() { /> )} + {/* Category Modals */} + {isAddCategoryModalOpen && ( + setIsAddCategoryModalOpen(false)} + eventId={event.id} + /> + )} + {isEditCategoryModalOpen && selectedCategoryId && ( )} - {/* Modal placeholders - will be implemented later */} - {/* These would render the appropriate modals when isAddGiftModalOpen, etc. are true */} + {/* Gift Modals */} + {isAddGiftModalOpen && ( + setIsAddGiftModalOpen(false)} + eventId={event.id} + /> + )} + + {isEditGiftModalOpen && selectedGiftId && ( + { + setIsEditGiftModalOpen(false); + setSelectedGiftId(null); + }} + giftId={selectedGiftId} + eventId={event.id} + /> + )} ); } diff --git a/frontend/src/components/gifts/gift-modal.tsx b/frontend/src/components/gifts/gift-modal.tsx new file mode 100644 index 0000000..912d96f --- /dev/null +++ b/frontend/src/components/gifts/gift-modal.tsx @@ -0,0 +1,495 @@ +// components/gifts/gift-modal.tsx + +import React, { useEffect } from "react"; +import { useForm } from "react-hook-form"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { useGifts } from "@/context/gift-context"; +import { + GiftItem, + GiftItemCreate, + GiftItemUpdate, + GiftPriority, + GiftStatus, +} from "@/client/types.gen"; +import { Loader2 } from "lucide-react"; +import { useAuth } from "@/context/auth-context"; + +interface GiftModalProps { + isOpen: boolean; + onClose: () => void; + giftId?: string; + eventId: string; +} + +export function GiftModal({ + isOpen, + onClose, + giftId, + eventId, +}: GiftModalProps) { + const { + item, + categories, + createItem, + updateItem, + fetchItemById, + isLoadingItem, + isLoadingCategories, + } = useGifts(); + + const { user } = useAuth(); + const isEditMode = Boolean(giftId); + + const { + register, + handleSubmit, + reset, + setValue, + watch, + formState: { errors, isSubmitting }, + } = useForm(); + + const watchPriority = watch("priority"); + const watchStatus = watch("status"); + + // Load gift data when editing + useEffect(() => { + if (isEditMode && giftId) { + fetchItemById(giftId); + } + }, [isEditMode, giftId, fetchItemById]); + + // Reset form when modal opens or gift changes + useEffect(() => { + if (isOpen) { + if (isEditMode && item) { + reset({ + name: item.name, + description: item.description, + price: item.price, + currency: item.currency || "CHF", + quantity_requested: item.quantity_requested || 1, + quantity_received: item.quantity_received || 0, + status: item.status, + priority: item.priority, + purchase_url: item.purchase_url, + store_name: item.store_name, + brand: item.brand, + model: item.model, + image_url: item.image_url, + notes: item.notes, + category_id: item.category_id, + }); + } else { + reset({ + name: "", + description: "", + price: undefined, + currency: "CHF", + quantity_requested: 1, + quantity_received: 0, + status: GiftStatus.AVAILABLE, + priority: GiftPriority.MEDIUM, + purchase_url: "", + store_name: "", + brand: "", + model: "", + image_url: "", + notes: "", + category_id: "none", + }); + } + } + }, [isOpen, item, isEditMode, reset]); + + const onSubmit = async (data: GiftItemCreate | GiftItemUpdate) => { + try { + // Handle the "none" category value by converting it to null/undefined + const submissionData = { + ...data, + category_id: data.category_id === "none" ? undefined : data.category_id, + }; + + if (isEditMode && giftId) { + await updateItem(giftId, submissionData as GiftItemUpdate); + } else { + const createData = { + ...submissionData, + event_id: eventId, + added_by: user?.id, + } as GiftItemCreate; + + await createItem(createData); + } + onClose(); + } catch (error) { + console.error("Error saving gift:", error); + } + }; + + const isLoading = isLoadingItem || isLoadingCategories; + + return ( + + + + {isEditMode ? "Edit Gift" : "Add Gift"} + + + {isLoading && isEditMode ? ( +
+ +
+ ) : ( +
+
+

+ Gift Information +

+
+
+ +
+ +
+ + {errors.name && ( +

+ {errors.name.message} +

+ )} +
+
+ +
+ +
+