"use client"; import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Card, CardBody, Button, Input, addToast, Spinner, Divider, Chip, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure, Switch, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Tabs, Tab, Image, } from "@heroui/react"; import { getFirestore, collection, addDoc, updateDoc, deleteDoc, doc, onSnapshot, query, orderBy, serverTimestamp, } from "firebase/firestore"; import { getAuth, onAuthStateChanged, User } from "firebase/auth"; import firebaseApp from "@/config/firebase"; import { fontCursive, fontSans } from "@/config/fonts"; import { TrashIcon, CheckIcon, Logo } from "@/components/icons"; const db = getFirestore(firebaseApp()); const auth = getAuth(firebaseApp()); interface RegistryItem { id: string; name: string; category: string; price: number; groupAllowed: boolean; totalContributed: number; status: "available" | "completed"; imageUrl?: string; storeUrl?: string; received?: boolean; } interface Contribution { id: string; itemId: string; itemName: string; guestId: string; guestName: string; amount: number; timestamp: any; thanked?: boolean; } export default function RegistryMakerPage() { const [user, setUser] = useState(null); const [authLoading, setAuthLoading] = useState(true); const [items, setItems] = useState([]); const [contributions, setContributions] = useState([]); const [loading, setLoading] = useState(true); const [captcha, setCaptcha] = useState(""); const { isOpen, onOpen, onOpenChange } = useDisclosure(); const { isOpen: isDeleteOpen, onOpen: onDeleteOpen, onOpenChange: onDeleteOpenChange } = useDisclosure(); const [itemToDelete, setItemToDelete] = useState(null); const [currentItem, setCurrentItem] = useState>({ name: "", category: "", price: 0, groupAllowed: true, imageUrl: "", storeUrl: "", }); const ADMIN_EMAIL = process.env.NEXT_PUBLIC_ADMIN_EMAIL; useEffect(() => { const unsubscribeAuth = onAuthStateChanged(auth, (currentUser) => { setUser(currentUser); setAuthLoading(false); }); // Listen to items const qItems = query(collection(db, "registry_items"), orderBy("category")); const unsubscribeItems = onSnapshot(qItems, (snapshot) => { const itemsData = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })) as RegistryItem[]; setItems(itemsData); setLoading(false); }); // Listen to contributions const qContribs = query(collection(db, "registry_contributions"), orderBy("timestamp", "desc")); const unsubscribeContribs = onSnapshot(qContribs, (snapshot) => { const contribsData = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })) as Contribution[]; setContributions(contribsData); }); return () => { unsubscribeAuth(); unsubscribeItems(); unsubscribeContribs(); }; }, []); const handleSaveItem = async (onClose: () => void) => { if (!currentItem.name || !currentItem.category || (currentItem.price || 0) <= 0) { addToast({ title: "Error", description: "Please fill all fields correctly.", color: "danger" }); return; } if (captcha !== "10") { addToast({ title: "Security Check", description: "Answer correctly!", color: "warning" }); return; } try { if (currentItem.id) { await updateDoc(doc(db, "registry_items", currentItem.id), { ...currentItem, updatedAt: serverTimestamp(), }); addToast({ title: "Success", description: "Item updated.", color: "success" }); } else { await addDoc(collection(db, "registry_items"), { ...currentItem, totalContributed: 0, status: "available", createdAt: serverTimestamp(), }); addToast({ title: "Success", description: "Item added.", color: "success" }); } onClose(); setCurrentItem({ name: "", category: "", price: 0, groupAllowed: true, imageUrl: "", storeUrl: "" }); setCaptcha(""); } catch (error) { console.error("Save error", error); addToast({ title: "Error", description: "Failed to save item.", color: "danger" }); } }; const confirmDelete = async (onClose: () => void) => { if (!itemToDelete) return; try { await deleteDoc(doc(db, "registry_items", itemToDelete)); addToast({ title: "Deleted", description: "Item removed from registry.", color: "warning" }); onClose(); } catch (error) { addToast({ title: "Error", description: "Failed to delete item.", color: "danger" }); } }; const toggleThanked = async (contributionId: string, currentStatus: boolean) => { try { await updateDoc(doc(db, "registry_contributions", contributionId), { thanked: !currentStatus, }); addToast({ title: "Updated", description: "Contribution status updated.", color: "success" }); } catch (error) { addToast({ title: "Error", description: "Failed to update status.", color: "danger" }); } }; const toggleReceived = async (itemId: string, currentStatus: boolean) => { try { await updateDoc(doc(db, "registry_items", itemId), { received: !currentStatus, }); addToast({ title: "Updated", description: "Item status updated.", color: "success" }); } catch (error) { addToast({ title: "Error", description: "Failed to update status.", color: "danger" }); } }; if (authLoading) return
; if (!user || user.email !== ADMIN_EMAIL) { return (

Access Restricted

This tool is for administrators only.

); } return (

Registry Manager

Curate the gift list and track contributions.

Total Items

{items.length}

Total Goal

₹{items.reduce((acc, item) => acc + (item.price ?? 0), 0).toLocaleString()}

Contributed

₹{contributions.reduce((acc, c) => acc + (c.amount ?? 0), 0).toLocaleString()}

Contributors

{new Set(contributions.map(c => c.guestId)).size}

Gift Catalog

{items.length === 0 ? (

Your registry is empty

Start by adding items you'd love for your new home.

) : ( items.map((item) => ( {item.imageUrl && (
{item.name}
)}
{item.category}
Received toggleReceived(item.id, !!item.received)} />

{item.name}

Price: ₹{(item.price ?? 0).toLocaleString()} | {item.groupAllowed ? "Group Allowed" : "Single Gift"}

Contribution {Math.round(((item.totalContributed ?? 0) / (item.price || 1)) * 100)}%

₹{(item.totalContributed ?? 0).toLocaleString()} / ₹{(item.price ?? 0).toLocaleString()}

{/* Contributors List */} {contributions.filter(c => c.itemId === item.id).length > 0 && (

Contributors

{contributions .filter(c => c.itemId === item.id) .map((c) => (
{c.guestName} ₹{c.amount.toLocaleString()}
))}
)}
)))}
GUEST GIFT ITEM AMOUNT DATE THANKED {contributions.map((c) => ( {c.guestName} {c.itemName} ₹{(c.amount ?? 0).toLocaleString()} {c.timestamp?.toDate() ? new Date(c.timestamp.toDate()).toLocaleString() : "Just now"} toggleThanked(c.id, !!c.thanked)} /> ))}
{/* Edit/Add Modal */} {(onClose) => ( <> {currentItem.id ? "Edit Gift" : "Add New Gift"} setCurrentItem({ ...currentItem, name: e.target.value })} isRequired variant="bordered" classNames={{ input: "outline-none" }} /> setCurrentItem({ ...currentItem, category: e.target.value })} isRequired variant="bordered" classNames={{ input: "outline-none" }} /> setCurrentItem({ ...currentItem, price: Number(e.target.value) })} isRequired variant="bordered" classNames={{ input: "outline-none" }} /> setCurrentItem({ ...currentItem, imageUrl: e.target.value })} variant="bordered" classNames={{ input: "outline-none" }} /> setCurrentItem({ ...currentItem, storeUrl: e.target.value })} variant="bordered" classNames={{ input: "outline-none" }} />
Allow Group Contribution setCurrentItem({ ...currentItem, groupAllowed: val })} color="danger" />

Bot Protection

setCaptcha(e.target.value)} />
)}
{/* Delete Confirmation Modal */} {(onClose) => ( <> Confirm Deletion Are you sure you want to remove this item from the registry? This action cannot be undone. )}
); }