"use client"; import React, { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { PlusIcon, ModuleIcon, EditIcon, DeleteIcon } from "@/components/icons"; import { MasterModule, MasterMenu, getMasterModules, getMasterMenus, getMenuModulesByModuleId, createMasterModule, updateMasterModule, deleteMasterModule, createMenuModulesBatch, } from "@/service/menu-modules"; import SiteBreadcrumb from "@/components/site-breadcrumb"; import Swal from "sweetalert2"; import { FormField } from "@/components/form/common/FormField"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { getCookiesDecrypt } from "@/lib/utils"; export default function ModuleManagementPage() { const router = useRouter(); const [modules, setModules] = useState([]); const [menus, setMenus] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingModule, setEditingModule] = useState(null); const [formData, setFormData] = useState({ name: "", description: "", pathUrl: "", actionType: "", statusId: 1, menuIds: [] as number[], }); useEffect(() => { // Check if user has roleId = 1 const roleId = getCookiesDecrypt("urie"); if (Number(roleId) !== 1) { Swal.fire({ title: "Access Denied", text: "You don't have permission to access this page", icon: "error", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }).then(() => { router.push("/admin/dashboard"); }); return; } loadData(); }, [router]); const loadData = async () => { setIsLoading(true); try { const res = await getMasterModules({ limit: 100 }); if (!res?.error) { setModules(res?.data?.data || []); } } catch (error) { console.error("Error loading modules:", error); } finally { setIsLoading(false); } }; const loadMenus = async () => { try { const res = await getMasterMenus({ limit: 100 }); if (!res?.error) { setMenus(res?.data?.data || []); } } catch (error) { console.error("Error loading menus:", error); } }; const loadModuleMenus = async (moduleId: number) => { try { const res = await getMenuModulesByModuleId(moduleId); if (!res?.error) { const menuIds = (res?.data?.data || []).map((mm: any) => mm.menu_id || mm.menuId).filter((id: any) => id); setFormData((prev) => ({ ...prev, menuIds })); } } catch (error) { console.error("Error loading module menus:", error); } }; const handleOpenDialog = async (module?: MasterModule) => { await loadMenus(); if (module) { setEditingModule(module); setFormData({ name: module.name, description: module.description, pathUrl: module.pathUrl, actionType: module.actionType || "", statusId: module.statusId, menuIds: [], }); await loadModuleMenus(module.id); } else { setEditingModule(null); setFormData({ name: "", description: "", pathUrl: "", actionType: "", statusId: 1, menuIds: [], }); } setIsDialogOpen(true); }; const handleSave = async () => { try { const { menuIds, ...moduleData } = formData; if (editingModule) { const res = await updateMasterModule(editingModule.id, moduleData); if (res?.error) { Swal.fire({ title: "Error", text: res?.message || "Failed to update module", icon: "error", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); return; } // Update menu associations if (menuIds && menuIds.length > 0) { // Create associations for each selected menu for (const menuId of menuIds) { try { await createMenuModulesBatch({ menuId, moduleIds: [editingModule.id], }); } catch (err) { // Ignore duplicate errors, backend should handle it console.log("Menu association may already exist:", err); } } } Swal.fire({ title: "Success", text: "Module updated successfully", icon: "success", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); await loadData(); setIsDialogOpen(false); } else { const res = await createMasterModule(moduleData); if (res?.error) { Swal.fire({ title: "Error", text: res?.message || "Failed to create module", icon: "error", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); return; } // Get the created module ID from response const createdModuleId = res?.data?.data?.id || res?.data?.id; // Create menu associations if menuIds provided if (createdModuleId && menuIds && menuIds.length > 0) { for (const menuId of menuIds) { await createMenuModulesBatch({ menuId, moduleIds: [createdModuleId], }); } } Swal.fire({ title: "Success", text: "Module created successfully", icon: "success", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); await loadData(); setIsDialogOpen(false); } } catch (error) { console.error("Error saving module:", error); Swal.fire({ title: "Error", text: "An unexpected error occurred", icon: "error", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); } }; const handleDelete = async (module: MasterModule) => { const result = await Swal.fire({ title: "Delete Module?", text: `Are you sure you want to delete "${module.name}"? This action cannot be undone.`, icon: "warning", showCancelButton: true, confirmButtonText: "Yes, delete it", cancelButtonText: "Cancel", customClass: { popup: 'swal-z-index-9999' } }); if (result.isConfirmed) { try { const res = await deleteMasterModule(module.id); if (res?.error) { Swal.fire({ title: "Error", text: res?.message || "Failed to delete module", icon: "error", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); } else { Swal.fire({ title: "Deleted!", text: "Module has been deleted.", icon: "success", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); await loadData(); } } catch (error) { console.error("Error deleting module:", error); Swal.fire({ title: "Error", text: "An unexpected error occurred", icon: "error", confirmButtonText: "OK", customClass: { popup: 'swal-z-index-9999' } }); } } }; const roleId = getCookiesDecrypt("urie"); if (Number(roleId) !== 1) { return null; // Will redirect in useEffect } return ( <>

Module Management

Manage system modules and their configurations

{editingModule ? `Edit Module: ${editingModule.name}` : "Create New Module"}
setFormData({ ...formData, name: value })} required /> setFormData({ ...formData, description: value })} required /> setFormData({ ...formData, pathUrl: value })} required /> setFormData({ ...formData, actionType: value })} options={[ { value: "view", label: "View" }, { value: "create", label: "Create" }, { value: "update", label: "Update" }, { value: "delete", label: "Delete" }, { value: "approve", label: "Approve" }, { value: "reject", label: "Reject" }, ]} required />

Select which menus this module belongs to. A module can belong to multiple menus.

{menus.length > 0 ? (
{menus.map((menu) => (
{ if (checked) { setFormData({ ...formData, menuIds: [...formData.menuIds, menu.id], }); } else { setFormData({ ...formData, menuIds: formData.menuIds.filter((id) => id !== menu.id), }); } }} />
))}
) : (

No menus available

)}
setFormData({ ...formData, statusId: Number(value) || 1 })} required />
{isLoading ? (

Loading modules...

) : modules.length > 0 ? (
{modules.map((module) => ( {module.name} {module.isActive ? ( Active ) : ( Inactive )}
{module.description}
{module.pathUrl}
{module.actionType}
))}
) : (

No Modules Found

Create your first module to define system capabilities

)}
); }