import { useState, useEffect, useCallback, useMemo } from "react"; import toast from "react-hot-toast"; import { AxiosError } from "axios"; import { getHealthPackagesApi, getHealthCategoriesApi, updateHealthPackageApi, createHealthPackageApi, createCategoryApi, updateCategoryApi, deleteCategoryApi, HealthPackage, HealthCategory, } from "@/api/healthCheck"; import PackageInquiriesTab from "@/components/PackageInquiriesTab/PackageInquiriesTab"; import HealthPackageModal from "@/components/HealthPackageModal/HealthPackageModal"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Loader2, RefreshCw, Plus, Pencil, ChevronLeft, ChevronRight, LayoutGrid, Eye, } from "lucide-react"; export default function HealthPackagePage() { const [packages, setPackages] = useState([]); const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); // Modals const [packageModal, setPackageModal] = useState(false); const [categoryModal, setCategoryModal] = useState(false); const [viewModal, setViewModal] = useState(false); // States const [selectedPackage, setSelectedPackage] = useState( null, ); const [editingPackage, setEditingPackage] = useState( null, ); const [editingCategory, setEditingCategory] = useState( null, ); // Filters & Pagination const [searchText, setSearchText] = useState(""); const [filterCategory, setFilterCategory] = useState(""); const [currentPage, setCurrentPage] = useState(1); const itemsPerPage = 10; // Forms const [pkgForm, setPkgForm] = useState>({ name: "", slug: "", description: "", image: "", price: undefined, discountedPrice: undefined, categoryId: 0, isActive: true, sortOrder: 1000, seo: { seoTitle: "", metaDescription: "", focusKeyphrase: "", tags: [], ogTitle: "", ogDescription: "", ogImage: "", }, }); const [inclusionsList, setInclusionsList] = useState([ { id: Date.now(), category: "", items: "" }, ]); const [catForm, setCatForm] = useState({ name: "", slug: "", sortOrder: 1000, isActive: true, }); const fetchData = useCallback(async () => { setLoading(true); setError(""); try { const [p, c] = await Promise.all([ getHealthPackagesApi(), getHealthCategoriesApi(), ]); setPackages(p.data || []); setCategories(c.data || []); } catch (err) { if (err instanceof AxiosError) { setError(err.response?.data?.message || "Failed to load data"); } else { setError("Something went wrong"); } } finally { setLoading(false); } }, []); useEffect(() => { fetchData(); }, [fetchData]); // --- Package Filtering & Pagination --- const filteredPackages = useMemo(() => { return packages.filter((pkg) => { const matchesSearch = pkg.name.toLowerCase().includes(searchText.toLowerCase()) || pkg.category?.name.toLowerCase().includes(searchText.toLowerCase()); const matchesCat = filterCategory ? pkg.categoryId === Number(filterCategory) : true; return matchesSearch && matchesCat; }); }, [packages, searchText, filterCategory]); useEffect(() => { setCurrentPage(1); }, [searchText, filterCategory]); const totalPages = Math.ceil(filteredPackages.length / itemsPerPage); const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; const currentItems = filteredPackages.slice( indexOfFirstItem, indexOfLastItem, ); // --- Actions --- const handleToggleStatus = async (pkg: HealthPackage) => { if (!pkg.id) return; try { await updateHealthPackageApi(pkg.id, { isActive: !pkg.isActive }); toast.success(`Package ${pkg.isActive ? "hidden" : "activated"}`); fetchData(); } catch (err) { console.error("Failed to update status", err); toast.error("Failed to update status"); } }; const handleToggleCategoryStatus = async (cat: HealthCategory) => { if (!cat.id) return; try { if (cat.isActive) { const proceed = window.confirm( "Hiding this category will also hide all packages inside it. Proceed?", ); if (!proceed) return; } await updateCategoryApi(cat.id, { isActive: !cat.isActive }); toast.success(`Category ${cat.isActive ? "hidden" : "activated"}`); fetchData(); } catch (err) { console.error("Failed to update category status", err); toast.error("Failed to update category status"); } }; const openAddPackage = () => { if (categories.length === 0) { toast.error( "Please create at least one category before attempting to add a health package.", ); return; } setEditingPackage(null); setPkgForm({ name: "", slug: "", description: "", image: "", price: undefined, discountedPrice: undefined, categoryId: categories[0]?.id || 0, isActive: true, sortOrder: 1000, seo: { seoTitle: "", metaDescription: "", focusKeyphrase: "", tags: [], ogTitle: "", ogDescription: "", ogImage: "", }, }); setInclusionsList([{ id: Date.now(), category: "", items: "" }]); setPackageModal(true); }; const openEditPackage = (pkg: any) => { setEditingPackage(pkg); setPkgForm(pkg); if ( pkg.inclusions && typeof pkg.inclusions === "object" && !Array.isArray(pkg.inclusions) ) { const formattedList = Object.entries(pkg.inclusions).map( ([cat, items], idx) => ({ id: Date.now() + idx, category: cat, items: (items as string[]).join(", "), }), ); setInclusionsList( formattedList.length ? formattedList : [{ id: Date.now(), category: "", items: "" }], ); } else { setInclusionsList([{ id: Date.now(), category: "", items: "" }]); } setPackageModal(true); }; const savePackage = async () => { if (!pkgForm.image) return toast.error("Package image is required."); if (!pkgForm.name?.trim()) return toast.error("Package Name is required."); if (!pkgForm.slug?.trim()) return toast.error("URL Slug is required."); if (!pkgForm.categoryId) return toast.error("Please select a valid category."); if (!pkgForm.description?.trim()) return toast.error("Description is required."); const structureFilled = inclusionsList.some( (item) => item.category.trim() !== "" && item.items.trim() !== "", ); if (!structureFilled) { return toast.error( "Please provide at least one valid Category Group with tests inside it.", ); } try { const parsedInclusions: Record = {}; inclusionsList.forEach((entry) => { const catName = entry.category.trim(); if (catName) { parsedInclusions[catName] = entry.items .split(",") .map((i) => i.trim()) .filter(Boolean); } }); const finalData: Partial = { ...pkgForm, inclusions: parsedInclusions, }; finalData.price = finalData.price !== undefined && finalData.price !== null ? Number(finalData.price) : null; finalData.discountedPrice = finalData.discountedPrice !== undefined && finalData.discountedPrice !== null ? Number(finalData.discountedPrice) : null; if (editingPackage?.id) { const changedFields: Record = {}; Object.keys(finalData).forEach((key) => { const k = key as keyof HealthPackage; if ( JSON.stringify(finalData[k]) !== JSON.stringify(editingPackage[k]) ) { changedFields[k] = finalData[k]; } }); delete changedFields.id; delete changedFields.category; if (Object.keys(changedFields).length === 0) { setPackageModal(false); return; } await updateHealthPackageApi(editingPackage.id, changedFields); } else { await createHealthPackageApi(finalData); } setPackageModal(false); fetchData(); } catch (err) { console.error(err); toast.error( "An unexpected system error occurred while trying to save the package.", ); } }; const saveCategory = async () => { if (!catForm.name?.trim()) return toast.error("Category Name is required."); try { if (editingCategory?.id) { const changedFields: Record = {}; Object.keys(catForm).forEach((key) => { const k = key as keyof HealthCategory; if (catForm[k] !== editingCategory[k]) { changedFields[k] = catForm[k]; } }); delete changedFields.id; delete changedFields._count; if (Object.keys(changedFields).length === 0) { setCategoryModal(false); return; } await updateCategoryApi( editingCategory.id, changedFields as Partial, ); } else { await createCategoryApi(catForm as any); } setCategoryModal(false); fetchData(); } catch (err) { console.error(err); toast.error("An error occurred while saving the category."); } }; return (

Health Packages

setSearchText(e.target.value)} className="w-[250px] text-base" />
{error && (
{error}
)} Packages Categories Inquiries {/* PACKAGES TAB */} Package List
Priority Package Details Category Pricing Status Actions {loading ? ( ) : currentItems.length === 0 ? ( No packages found ) : ( currentItems.map((pkg) => ( {pkg.sortOrder}
{pkg.name}
/{pkg.slug}
{pkg.category?.name}
{pkg.discountedPrice != null ? `₹${pkg.discountedPrice}` : pkg.price != null ? `₹${pkg.price}` : "Not Entered"}
{pkg.discountedPrice != null && pkg.price != null && pkg.discountedPrice < pkg.price && (
₹{pkg.price}
)}
handleToggleStatus(pkg)} /> {pkg.isActive ? "Active" : "Hidden"}
)) )}
{!loading && filteredPackages.length > 0 && (
Showing{" "} {indexOfFirstItem + 1} {" "} to{" "} {Math.min(indexOfLastItem, filteredPackages.length)} {" "} of{" "} {filteredPackages.length} {" "} packages
Page {currentPage} of {totalPages}
)}
{/* CATEGORIES TAB */} Category List
Priority Category Name Status Actions {categories.map((cat) => ( {cat.sortOrder} {cat.name}
handleToggleCategoryStatus(cat) } /> {cat.isActive ? "Active" : "Hidden"}
))}
{/* --- REPLACED MODAL CONTAINER --- */} {/* --- CATEGORY MODAL --- */} {editingCategory ? "Edit Category" : "Add Category"}
setCatForm({ ...catForm, name: e.target.value }) } className="text-base" />
setCatForm({ ...catForm, sortOrder: Number(e.target.value) }) } className="text-base" />
setCatForm({ ...catForm, isActive: val }) } />
{/* --- VIEW MODAL --- */} {selectedPackage?.name}

Category

{selectedPackage?.category?.name}

Pricing

{selectedPackage?.discountedPrice != null ? `₹${selectedPackage.discountedPrice}` : selectedPackage?.price != null ? `₹${selectedPackage.price}` : "Not Entered"}

Inclusions

{selectedPackage?.inclusions && typeof selectedPackage.inclusions === "object" && !Array.isArray(selectedPackage.inclusions) ? ( Object.entries(selectedPackage.inclusions).map( ([category, tests], idx) => (

{category}

{Array.isArray(tests) && tests.map((item, i) => (
✓ {item}
))}
), ) ) : (
{Array.isArray(selectedPackage?.inclusions) && selectedPackage.inclusions.map((item, i) => (
✓ {item}
))}
)}
); }