// Updated page.tsx with gift categories and summary sections "use client"; import React, { useEffect, useState } from "react"; import { useParams } from "next/navigation"; import Link from "next/link"; import { AlertTriangle, ChevronRight, Edit, ExternalLink, Loader2, MoreHorizontal, Plus, Search, Trash, } from "lucide-react"; import { useEvents } from "@/context/event-context"; import { useGifts } from "@/context/gift-context"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { GiftPriority, GiftStatus } from "@/client/types.gen"; import { CategoryModal } from "@/components/gifts/category-modal"; import { GiftModal } from "@/components/gifts/gift-modal"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; export default function GiftRegistryPage() { const { slug } = useParams<{ slug: string }>(); const { event, fetchEventBySlug, isLoadingEvent, eventError } = useEvents(); const { categories, items, isLoadingCategories, isLoadingItems, purchases, error, refetchCategories, refetchItems, currentEventId, setCurrentEventId, deleteItem, } = useGifts(); // State for modals const [isAddGiftModalOpen, setIsAddGiftModalOpen] = useState(false); const [isEditGiftModalOpen, setIsEditGiftModalOpen] = useState(false); const [isAddCategoryModalOpen, setIsAddCategoryModalOpen] = useState(false); const [isEditCategoryModalOpen, setIsEditCategoryModalOpen] = useState(false); const [selectedGiftId, setSelectedGiftId] = useState(null); const [selectedCategoryId, setSelectedCategoryId] = useState( null, ); // State for filtering and searching const [searchQuery, setSearchQuery] = useState(""); const [categoryFilter, setCategoryFilter] = useState("all"); const [statusFilter, setStatusFilter] = useState("all"); // Filter items based on search query and filters const filteredItems = items ? items.filter((item) => { // Filter by search query const matchesSearch = searchQuery === "" || item.name.toLowerCase().includes(searchQuery.toLowerCase()) || item.description?.toLowerCase().includes(searchQuery.toLowerCase()) || item.store_name?.toLowerCase().includes(searchQuery.toLowerCase()) || item.brand?.toLowerCase().includes(searchQuery.toLowerCase()); // Filter by category const matchesCategory = categoryFilter === "all" || item.category_id === categoryFilter; // Filter by status const matchesStatus = statusFilter === "all" || item.status === statusFilter; return matchesSearch && matchesCategory && matchesStatus; }) : []; // Helper to get status badge with color const getStatusBadge = (status: GiftStatus | null | undefined) => { if (!status) return null; const statusStyles: Record = { available: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300", reserved: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300", purchased: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300", received: "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300", removed: "bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300", }; return (
{status.toUpperCase()}
); }; // Helper to get priority badge with color const getPriorityBadge = (priority: GiftPriority | null | undefined) => { if (!priority) return null; const priorityStyles: Record = { low: "bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300", medium: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300", high: "bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300", must_have: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300", }; const priorityLabels: Record = { low: "LOW", medium: "MEDIUM", high: "HIGH", must_have: "MUST-HAVE", }; return ( {priorityLabels[priority]} ); }; // Calculate summary statistics const summaryStats = { totalItems: items?.length || 0, totalCategories: categories?.length || 0, availableItems: items?.filter((item) => item.status === GiftStatus.AVAILABLE).length || 0, availableQuantity: items ?.filter((item) => item.status === GiftStatus.AVAILABLE) .reduce((acc, item) => acc + (item.quantity_requested || 1), 0) || 0, reservedItems: items?.filter((item) => item.status === GiftStatus.RESERVED).length || 0, reservedQuantity: items ?.filter((item) => item.status === GiftStatus.RESERVED) .reduce((acc, item) => acc + (item.quantity_requested || 1), 0) || 0, purchasedItems: items?.filter((item) => item.status === GiftStatus.PURCHASED).length || 0, purchasedQuantity: items ?.filter((item) => item.status === GiftStatus.PURCHASED) .reduce((acc, item) => acc + (item.quantity_requested || 1), 0) || 0, receivedItems: items?.filter((item) => item.status === GiftStatus.RECEIVED).length || 0, receivedQuantity: items ?.filter((item) => item.status === GiftStatus.RECEIVED) .reduce((acc, item) => acc + (item.quantity_requested || 1), 0) || 0, }; // Functions to handle modal actions const handleAddGift = () => { setIsAddGiftModalOpen(true); }; const handleDeleteGift = async (id: string) => { await deleteItem(id); await refetchItems(undefined, event?.id); }; const handleEditGift = (giftId: string) => { setSelectedGiftId(giftId); setIsEditGiftModalOpen(true); }; const handleAddCategory = () => { setIsAddCategoryModalOpen(true); }; const handleEditCategory = (categoryId: string) => { setSelectedCategoryId(categoryId); setIsEditCategoryModalOpen(true); }; // Load event and gift data useEffect(() => { fetchEventBySlug(slug); }, [slug, fetchEventBySlug]); useEffect(() => { if (event?.id) { setCurrentEventId(event.id); refetchCategories(event.id); refetchItems(undefined, event.id); } }, [event, setCurrentEventId, refetchCategories, refetchItems]); // Loading state if (isLoadingEvent || isLoadingCategories || isLoadingItems) { return (
Loading gift registry...
); } // Error state if (eventError || error) { return (
Error loading gift registry: {(eventError || error)?.message}
); } // Not found state if (!event) { return ( Event Not Found

The event you're looking for doesn't exist or may have been removed.

); } return (
{/* Header */}
{/*

EVENTSPACE

*/}
Admin • {event.title}
{/* Breadcrumb Navigation */}
Dashboard Events {event.title} Gift Registry
{/* Gift Registry Content */}

GIFT REGISTRY MANAGEMENT

{/* Filters and Search */}
Filter by:
setSearchQuery(e.target.value)} />
{/* Gift Items Table */}
Category Name Qty Price Priority Status Actions {filteredItems.length === 0 ? ( No gifts found. Add your first gift! ) : ( filteredItems.map((item) => { const category = categories?.find( (c) => c.id === item.category_id, ); const canShowReservations = item.status ? ( [ GiftStatus.RESERVED, GiftStatus.RECEIVED, ] as GiftStatus[] ).includes(item.status) : false; return ( {category?.name || "Uncategorized"} {/* Purchase URL clickable icon */} {item.purchase_url ? ( ) : ( )} {item.name} {item.quantity_requested || 1} {item.formatted_price || "-"} {getPriorityBadge(item.priority)} {canShowReservations ? (
{getStatusBadge(item.status)}
{/**/} {/* {item.reservations &&*/} {/* item.reservations.length > 0 ? (*/} {/*
    */} {/* {item.reservations.map((res) => (*/} {/*
  • */} {/* {res.guest_name}: {res.quantity}*/} {/*
  • */} {/* ))}*/} {/*
*/} {/* ) : (*/} {/*

No reservations available.

*/} {/* )}*/} {/*
*/}
) : ( getStatusBadge(item.status) )}
handleEditGift(item.id)} > Edit handleDeleteGift(item.id)} > Delete
{/* Separate row for description */} {/*{item.description && (*/} {item.description} {/*)}*/}
); }) )}
{/* Categories Section */}

CATEGORIES

{categories && categories.length > 0 ? ( categories.map((category) => { const categoryItems = items?.filter((item) => item.category_id === category.id) || []; return (
{category.name} handleEditCategory(category.id)} > Edit Delete
{categoryItems.length} item {categoryItems.length !== 1 && "s"}
); }) ) : (

No categories found. Create your first category!

)}
{/* Summary Section */}

SUMMARY

  • • {summaryStats.totalItems} total gift item {summaryStats.totalItems !== 1 ? "s" : ""} across{" "} {summaryStats.totalCategories} categor {summaryStats.totalCategories !== 1 ? "ies" : "y"}
  • • {summaryStats.availableItems} gift {summaryStats.availableItems !== 1 ? "s are" : " is"} available ( {summaryStats.availableQuantity} item {summaryStats.availableQuantity !== 1 ? "s" : ""})
  • • {summaryStats.reservedItems} gift {summaryStats.reservedItems !== 1 ? "s are" : " is"} reserved ( {summaryStats.reservedQuantity} item {summaryStats.reservedQuantity !== 1 ? "s" : ""})
  • • {summaryStats.purchasedItems} gift {summaryStats.purchasedItems !== 1 ? "s have" : " has"} been purchased ({summaryStats.purchasedQuantity} item {summaryStats.purchasedQuantity !== 1 ? "s" : ""})
  • • {summaryStats.receivedItems} gift {summaryStats.receivedItems !== 1 ? "s have" : " has"} been fully received ({summaryStats.receivedQuantity} item {summaryStats.receivedQuantity !== 1 ? "s" : ""})
{/* Category Modals */} {isAddCategoryModalOpen && ( setIsAddCategoryModalOpen(false)} eventId={event.id} /> )} {/* Category Modals */} {isAddCategoryModalOpen && ( setIsAddCategoryModalOpen(false)} eventId={event.id} /> )} {isEditCategoryModalOpen && selectedCategoryId && ( { setIsEditCategoryModalOpen(false); setSelectedCategoryId(null); }} categoryId={selectedCategoryId} eventId={event.id} /> )} {/* Gift Modals */} {isAddGiftModalOpen && ( setIsAddGiftModalOpen(false)} eventId={event.id} /> )} {isEditGiftModalOpen && selectedGiftId && ( { setIsEditGiftModalOpen(false); setSelectedGiftId(null); }} giftId={selectedGiftId} eventId={event.id} /> )}
); }