"use client"; import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; import { ChevronDownIcon, ChevronUpIcon, SaveIcon, EyeIcon, RotateCcwIcon, UsersIcon, HierarchyIcon, PlusIcon, TrashIcon, } from "@/components/icons"; import { FormField } from "./common/FormField"; import { DynamicArray } from "./common/DynamicArray"; import { UserLevelsCreateRequest, UserLevel, Province, createUserLevel, updateUserLevel, getUserLevels, getProvinces, } from "@/service/approval-workflows"; import { MasterMenu, getMasterMenus } from "@/service/menu-modules"; import { getUserLevelMenuAccessesByUserLevelId, createUserLevelMenuAccessesBatch, deleteUserLevelMenuAccess, UserLevelMenuAccess, } from "@/service/user-level-menu-accesses"; import { getUserLevelMenuActionAccessesByUserLevelIdAndMenuId, createUserLevelMenuActionAccessesBatch, deleteUserLevelMenuActionAccess, UserLevelMenuActionAccess, } from "@/service/user-level-menu-action-accesses"; import { getMenuActionsByMenuId, MenuAction } from "@/service/menu-actions"; import Swal from "sweetalert2"; interface UserLevelsFormProps { initialData?: UserLevelsCreateRequest; onSave?: (data: UserLevelsCreateRequest) => void; onCancel?: () => void; isLoading?: boolean; mode?: "single" | "bulk"; } export const UserLevelsForm: React.FC = ({ initialData, onSave, onCancel, isLoading = false, mode = "single", }) => { // Form state const [formData, setFormData] = useState({ name: "", aliasName: "", levelNumber: 1, parentLevelId: undefined, provinceId: undefined, group: "", isApprovalActive: true, isActive: true, }); const [bulkFormData, setBulkFormData] = useState( [], ); const [userLevels, setUserLevels] = useState([]); const [provinces, setProvinces] = useState([]); const [menus, setMenus] = useState([]); const [selectedMenuIds, setSelectedMenuIds] = useState([]); const [userLevelMenuAccesses, setUserLevelMenuAccesses] = useState< UserLevelMenuAccess[] >([]); const [menuActionsMap, setMenuActionsMap] = useState< Record >({}); const [selectedActionAccesses, setSelectedActionAccesses] = useState< Record >({}); const [errors, setErrors] = useState>({}); const [isSubmitting, setIsSubmitting] = useState(false); const [expandedHierarchy, setExpandedHierarchy] = useState(false); const [isLoadingData, setIsLoadingData] = useState(true); const [activeTab, setActiveTab] = useState( mode === "single" ? "basic" : "bulk", ); useEffect(() => { if (initialData) { setFormData(initialData); } }, [initialData]); useEffect(() => { const loadData = async () => { try { const [userLevelsRes, provincesRes, menusRes] = await Promise.all([ getUserLevels(), getProvinces(), getMasterMenus({ limit: 100 }), ]); if (!userLevelsRes?.error) setUserLevels(userLevelsRes?.data?.data || []); if (!provincesRes?.error) setProvinces(provincesRes?.data?.data || []); if (!menusRes?.error) { const menusData = (menusRes?.data?.data || []).map((menu: any) => ({ ...menu, moduleId: menu.module_id || menu.moduleId, parentMenuId: menu.parent_menu_id !== undefined ? menu.parent_menu_id : menu.parentMenuId, statusId: menu.status_id || menu.statusId, isActive: menu.is_active !== undefined ? menu.is_active : menu.isActive, })); setMenus(menusData); // Load actions for each menu const actionsMap: Record = {}; for (const menu of menusData) { try { const actionsRes = await getMenuActionsByMenuId(menu.id); if (!actionsRes?.error) { actionsMap[menu.id] = actionsRes?.data?.data || []; } } catch (error) { console.error( `Error loading actions for menu ${menu.id}:`, error, ); } } setMenuActionsMap(actionsMap); } } catch (error) { console.error("Error loading form data:", error); } finally { setIsLoadingData(false); } }; loadData(); }, []); useEffect(() => { const loadAccesses = async () => { if (initialData && (initialData as any).id) { const userLevelId = (initialData as any).id; try { // Load menu accesses const menuRes = await getUserLevelMenuAccessesByUserLevelId(userLevelId); if (!menuRes?.error) { const menuAccesses = menuRes?.data?.data || []; setUserLevelMenuAccesses(menuAccesses); setSelectedMenuIds( menuAccesses .filter((a: UserLevelMenuAccess) => a.canAccess) .map((a: UserLevelMenuAccess) => a.menuId), ); // Load action accesses for each menu const actionAccesses: Record = {}; for (const menuAccess of menuAccesses.filter( (a: UserLevelMenuAccess) => a.canAccess, )) { try { const actionRes = await getUserLevelMenuActionAccessesByUserLevelIdAndMenuId( userLevelId, menuAccess.menuId, ); if (!actionRes?.error) { const actions = actionRes?.data?.data || []; actionAccesses[menuAccess.menuId] = actions .filter((a: UserLevelMenuActionAccess) => a.canAccess) .map((a: UserLevelMenuActionAccess) => a.actionCode); } } catch (error) { console.error( `Error loading action accesses for menu ${menuAccess.menuId}:`, error, ); } } setSelectedActionAccesses(actionAccesses); } } catch (error) { console.error("Error loading accesses:", error); } } }; loadAccesses(); }, [initialData]); const validateForm = ( data: UserLevelsCreateRequest, ): Record => { const newErrors: Record = {}; if (!data.name.trim()) { newErrors.name = "Level name is required"; } else if (data.name.trim().length < 3) { newErrors.name = "Level name must be at least 3 characters"; } if (!data.aliasName.trim()) { newErrors.aliasName = "Alias name is required"; } else if (data.aliasName.trim().length < 3) { newErrors.aliasName = "Alias name must be at least 3 characters"; } if (!data.levelNumber || data.levelNumber <= 0) { newErrors.levelNumber = "Level number must be a positive integer"; } // Check for duplicate level numbers // const existingLevel = userLevels.length > 0 ? userLevels.find(level => level.levelNumber === data.levelNumber) : null; // if (existingLevel && (!initialData || existingLevel.id !== (initialData as any).id)) { // newErrors.levelNumber = "Level number already exists"; // } return newErrors; }; const validateBulkForm = (): boolean => { let isValid = true; const newErrors: Record = {}; bulkFormData.forEach((data, index) => { const itemErrors = validateForm(data); Object.keys(itemErrors).forEach((key) => { newErrors[`${index}.${key}`] = itemErrors[key]; }); if (Object.keys(itemErrors).length > 0) { isValid = false; } }); setErrors(newErrors); return isValid; }; const handleFieldChange = ( field: keyof UserLevelsCreateRequest, value: any, ) => { setFormData((prev) => ({ ...prev, [field]: value })); if (errors[field]) { setErrors((prev) => ({ ...prev, [field]: "" })); } }; const handleBulkFieldChange = ( index: number, field: keyof UserLevelsCreateRequest, value: any, ) => { setBulkFormData((prev: UserLevelsCreateRequest[]) => { const newData = [...prev]; newData[index] = { ...newData[index], [field]: value }; return newData; }); }; const handleTabChange = (value: string) => { setActiveTab(value); if (value === "bulk") { } else { } }; const addBulkItem = () => { const newItem: UserLevelsCreateRequest = { name: "", aliasName: "", levelNumber: 1, parentLevelId: undefined, provinceId: undefined, group: "", isApprovalActive: true, isActive: true, }; setBulkFormData((prev) => [...prev, newItem]); }; const renderBulkItemForm = ( item: UserLevelsCreateRequest, index: number, onUpdate: (item: UserLevelsCreateRequest) => void, onDelete: () => void, ) => { return (
onUpdate({ ...item, name: value })} error={errors[`${index}.name`]} required /> onUpdate({ ...item, aliasName: value.toUpperCase() }) } error={errors[`${index}.aliasName`]} required helpText="Short identifier for system use" /> onUpdate({ ...item, levelNumber: value ? Number(value) : 1 }) } error={errors[`${index}.levelNumber`]} required min={1} helpText="Higher number = higher authority" />
0 ? "Select parent level" : "No parent levels available" } value={item.parentLevelId} onChange={(value) => onUpdate({ ...item, parentLevelId: value !== undefined ? Number(value) : undefined, }) } options={[ { value: 0, label: "No Parent (Root Level)" }, ...(userLevels.length > 0 ? userLevels.map((level) => ({ value: level.id, label: `${level.name} (Level ${level.levelNumber})`, })) : []), ]} helpText={ userLevels.length === 0 ? "No parent levels found. This will be a root level." : "Select parent level for hierarchy" } disabled={userLevels.length === 0} /> 0 ? "Select province" : "No provinces available" } value={item.provinceId} onChange={(value) => onUpdate({ ...item, provinceId: value ? Number(value) : undefined, }) } options={ provinces.length > 0 ? provinces.map((province) => ({ value: province.id, label: province.prov_name, })) : [] } helpText={ provinces.length === 0 ? "No provinces found. Please ensure provinces are available in the system." : "Geographic scope for this level" } disabled={provinces.length === 0} />
onUpdate({ ...item, group: value })} helpText="Group classification for organization" /> onUpdate({ ...item, isApprovalActive: value })} helpText="Users with this level can participate in approval process" /> onUpdate({ ...item, isActive: value })} helpText="Level is available for assignment" />
); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (isSubmitting) return; // 🔒 HARD LOCK setIsSubmitting(true); try { const isBulkMode = activeTab === "bulk"; const isEditing = Boolean((initialData as any)?.id); const userLevelId = (initialData as any)?.id; /* =============================== * BULK MODE * =============================== */ if (isBulkMode) { if (!validateBulkForm()) { Swal.fire({ title: "Validation Error", text: "Please fix the errors before submitting", icon: "error", }); return; } let successCount = 0; let failedCount = 0; for (const item of bulkFormData) { try { const res = await createUserLevel(item); if (res?.error) { failedCount++; } else { successCount++; } } catch { failedCount++; } } Swal.fire({ title: failedCount === 0 ? "Success" : "Partial Success", text: failedCount === 0 ? `${successCount} user levels created successfully` : `${successCount} success, ${failedCount} failed`, icon: failedCount === 0 ? "success" : "warning", }).then(() => { window.location.reload(); }); return; // ⛔ STOP HERE (PENTING) } /* =============================== * SINGLE MODE * =============================== */ const validationErrors = validateForm(formData); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); Swal.fire({ title: "Validation Error", text: "Please fix the errors before submitting", icon: "error", }); return; } let response; if (isEditing) { response = await updateUserLevel(userLevelId, formData); } else { response = await createUserLevel(formData); } if (response?.error) { Swal.fire({ title: "Error", text: response?.message || "Failed to save user level", icon: "error", }); return; } const createdUserLevelId = response?.data?.data?.id || userLevelId; /* =============================== * MENU ACCESS * =============================== */ if (createdUserLevelId) { if (isEditing) { for (const access of userLevelMenuAccesses) { await deleteUserLevelMenuAccess(access.id); } } if (selectedMenuIds.length > 0) { await createUserLevelMenuAccessesBatch({ userLevelId: createdUserLevelId, menuIds: selectedMenuIds, }); for (const menuId of selectedMenuIds) { const actionCodes = selectedActionAccesses[menuId] || []; if (isEditing) { const existing = await getUserLevelMenuActionAccessesByUserLevelIdAndMenuId( createdUserLevelId, menuId, ); for (const a of existing?.data?.data || []) { await deleteUserLevelMenuActionAccess(a.id); } } if (actionCodes.length > 0) { await createUserLevelMenuActionAccessesBatch({ userLevelId: createdUserLevelId, menuId, actionCodes, }); } } } } // Swal.fire({ // title: "Success", // text: isEditing // ? "User level updated successfully" // : "User level created successfully", // icon: "success", // }).then(() => { // window.location.reload(); // }); Swal.fire({ icon: "success", title: "Sukses", text: isEditing ? "User level updated successfully" : "User level created successfully", timer: 1500, showConfirmButton: false, allowOutsideClick: false, }).then(() => { window.location.reload(); }); } catch (err) { console.error(err); Swal.fire({ title: "Error", text: "Unexpected error occurred", icon: "error", }); } finally { setIsSubmitting(false); } }; // const handleSubmit = async (e: React.FormEvent) => { // e.preventDefault(); // // Determine current mode based on active tab // const currentMode = activeTab === "bulk" ? "bulk" : "single"; // if (currentMode === "single") { // const validationErrors = validateForm(formData); // console.log("Form mode: ", currentMode); // console.log("Error single ", validationErrors); // if (Object.keys(validationErrors).length > 0) { // setErrors(validationErrors); // Swal.fire({ // title: "Validation Error", // text: "Please fix the errors before submitting", // icon: "error", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // return; // } // } else { // if (!validateBulkForm()) { // Swal.fire({ // title: "Validation Error", // text: "Please fix the errors before submitting", // icon: "error", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // return; // } // } // setIsSubmitting(true); // try { // if (onSave) { // if (currentMode === "single") { // // Check if editing or creating // const isEditing = !!(initialData as any)?.id; // const userLevelId = (initialData as any)?.id; // // Save user level first // let userLevelResponse; // if (isEditing) { // userLevelResponse = await updateUserLevel(userLevelId, formData); // } else { // userLevelResponse = await createUserLevel(formData); // } // if (userLevelResponse?.error) { // Swal.fire({ // title: "Error", // text: userLevelResponse?.message || `Failed to ${isEditing ? 'update' : 'create'} user level`, // icon: "error", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // setIsSubmitting(false); // return; // } // // Get the user level ID // const createdUserLevelId = userLevelResponse?.data?.data?.id || userLevelId; // // Save menu accesses // if (createdUserLevelId && selectedMenuIds.length > 0) { // // Delete existing menu accesses if editing // if ((initialData as any)?.id) { // for (const access of userLevelMenuAccesses) { // await deleteUserLevelMenuAccess(access.id); // } // } // // Create new menu accesses in batch // const menuAccessResponse = await createUserLevelMenuAccessesBatch({ // userLevelId: createdUserLevelId, // menuIds: selectedMenuIds, // }); // if (menuAccessResponse?.error) { // console.error("Error saving menu accesses:", menuAccessResponse?.message); // } else { // // Save action accesses for each menu // for (const menuId of selectedMenuIds) { // const actionCodes = selectedActionAccesses[menuId] || []; // // Delete existing action accesses for this menu if editing // if ((initialData as any)?.id) { // try { // const existingActionsRes = await getUserLevelMenuActionAccessesByUserLevelIdAndMenuId(createdUserLevelId, menuId); // if (!existingActionsRes?.error) { // const existingActions = existingActionsRes?.data?.data || []; // for (const action of existingActions) { // await deleteUserLevelMenuActionAccess(action.id); // } // } // } catch (error) { // console.error(`Error deleting existing action accesses for menu ${menuId}:`, error); // } // } // // Create new action accesses in batch // if (actionCodes.length > 0) { // const actionAccessResponse = await createUserLevelMenuActionAccessesBatch({ // userLevelId: createdUserLevelId, // menuId: menuId, // actionCodes: actionCodes, // }); // if (actionAccessResponse?.error) { // console.error(`Error saving action accesses for menu ${menuId}:`, actionAccessResponse?.message); // } // } // } // } // } // onSave(formData); // } else { // // For bulk mode, save each item individually // let hasErrors = false; // let successCount = 0; // for (const item of bulkFormData) { // const response = await createUserLevel(item); // if (response?.error) { // hasErrors = true; // Swal.fire({ // title: "Error", // text: `Failed to create user level "${item.name}": ${response?.message || "Unknown error"}`, // icon: "error", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // } else { // successCount++; // Swal.fire({ // title: "Success", // text: `User level "${item.name}" created successfully`, // icon: "success", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // } // } // // Refresh page if at least one item was created successfully // if (successCount > 0) { // setTimeout(() => { // window.location.reload(); // }, 1000); // Small delay to let user see the success message // } // } // } else { // if (currentMode === "single") { // // Check if editing or creating // const isEditing = !!(initialData as any)?.id; // const userLevelId = (initialData as any)?.id; // let response; // if (isEditing) { // response = await updateUserLevel(userLevelId, formData); // } else { // response = await createUserLevel(formData); // } // console.log(`${isEditing ? 'Update' : 'Create'} Response: `, response); // if (response?.error) { // Swal.fire({ // title: "Error", // text: response?.message || `Failed to ${isEditing ? 'update' : 'create'} user level`, // icon: "error", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // } else { // // Get the user level ID // const createdUserLevelId = response?.data?.data?.id || userLevelId; // // Save menu accesses // if (createdUserLevelId && selectedMenuIds.length > 0) { // // Delete existing menu accesses if editing // if ((initialData as any)?.id) { // for (const access of userLevelMenuAccesses) { // await deleteUserLevelMenuAccess(access.id); // } // } // // Create new menu accesses in batch // const menuAccessResponse = await createUserLevelMenuAccessesBatch({ // userLevelId: createdUserLevelId, // menuIds: selectedMenuIds, // }); // if (menuAccessResponse?.error) { // console.error("Error saving menu accesses:", menuAccessResponse?.message); // } else { // // Save action accesses for each menu // for (const menuId of selectedMenuIds) { // const actionCodes = selectedActionAccesses[menuId] || []; // // Delete existing action accesses for this menu if editing // if ((initialData as any)?.id) { // try { // const existingActionsRes = await getUserLevelMenuActionAccessesByUserLevelIdAndMenuId(createdUserLevelId, menuId); // if (!existingActionsRes?.error) { // const existingActions = existingActionsRes?.data?.data || []; // for (const action of existingActions) { // await deleteUserLevelMenuActionAccess(action.id); // } // } // } catch (error) { // console.error(`Error deleting existing action accesses for menu ${menuId}:`, error); // } // } // // Create new action accesses in batch // if (actionCodes.length > 0) { // const actionAccessResponse = await createUserLevelMenuActionAccessesBatch({ // userLevelId: createdUserLevelId, // menuId: menuId, // actionCodes: actionCodes, // }); // if (actionAccessResponse?.error) { // console.error(`Error saving action accesses for menu ${menuId}:`, actionAccessResponse?.message); // } // } // } // } // } // Swal.fire({ // title: "Success", // text: isEditing ? "User level updated successfully" : "User level created successfully", // icon: "success", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }).then(() => { // // Refresh page after successful save // window.location.reload(); // }); // } // } else { // // Bulk creation // const promises = bulkFormData.map(item => createUserLevel(item)); // const responses = await Promise.all(promises); // console.log("Create Responses: ", responses); // const failedCount = responses.filter((r: any) => r.error).length; // const successCount = responses.length - failedCount; // if (failedCount === 0) { // Swal.fire({ // title: "Success", // text: `All ${successCount} user levels created successfully`, // icon: "success", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // } else { // Swal.fire({ // title: "Partial Success", // text: `${successCount} user levels created successfully, ${failedCount} failed`, // icon: "warning", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // } // } // } // } catch (error) { // console.error("Error submitting form:", error); // Swal.fire({ // title: "Error", // text: "An unexpected error occurred", // icon: "error", // confirmButtonText: "OK", // customClass: { // popup: 'swal-z-index-9999' // } // }); // } finally { // setIsSubmitting(false); // } // }; const handleReset = () => { Swal.fire({ title: "Reset Form", text: "Are you sure you want to reset all form data?", icon: "warning", showCancelButton: true, confirmButtonText: "Yes, reset", cancelButtonText: "Cancel", customClass: { popup: "swal-z-index-9999", }, }).then((result) => { if (result.isConfirmed) { if (mode === "single") { setFormData({ name: "", aliasName: "", levelNumber: 1, parentLevelId: undefined, provinceId: undefined, group: "", isApprovalActive: true, isActive: true, }); } else { setBulkFormData([]); } setErrors({}); } }); }; const renderHierarchyTree = () => { const buildTree = (levels: UserLevel[], parentId?: number): UserLevel[] => { return levels .filter((level) => level.parentLevelId === parentId) .map((level) => ({ ...level, children: buildTree(levels, level.id), })); }; const tree = buildTree(userLevels); const renderNode = ( node: UserLevel & { children?: UserLevel[] }, depth = 0, ) => (
{node.name} (Level {node.levelNumber}) {node.group && ( - {node.group} )}
{node.children?.map((child: any) => renderNode(child, depth + 1))}
); return (
{tree.map((node) => renderNode(node))}
); }; return (
{isLoadingData && (
Loading form data...
)} Basic Information Menu Access Action Access Bulk Operations {/* Basic Information Tab */} User Level Basic Information
handleFieldChange("name", value)} error={errors.name} required /> handleFieldChange("aliasName", value.toUpperCase()) } error={errors.aliasName} required helpText="Short identifier for system use" /> handleFieldChange("levelNumber", value ? Number(value) : 1) } error={errors.levelNumber} required min={1} helpText="Higher number = higher authority" />
0 ? "Select parent level" : "No parent levels available" } value={formData.parentLevelId} onChange={(value) => handleFieldChange( "parentLevelId", value !== undefined ? Number(value) : undefined, ) } options={[ { value: 0, label: "No Parent (Root Level)" }, ...(userLevels.length > 0 ? userLevels.map((level) => ({ value: level.id, label: `${level.name} (Level ${level.levelNumber})`, })) : []), ]} helpText={ userLevels.length === 0 ? "No parent levels found. This will be a root level." : "Select parent level for hierarchy" } disabled={userLevels.length === 0} /> 0 ? "Select province" : "No provinces available" } value={formData.provinceId} onChange={(value) => handleFieldChange( "provinceId", value ? Number(value) : undefined, ) } options={ provinces.length > 0 ? provinces.map((province) => ({ value: province.id, label: province.prov_name, })) : [] } helpText={ provinces.length === 0 ? "No provinces found. Please ensure provinces are available in the system." : "Geographic scope for this level" } disabled={provinces.length === 0} />
handleFieldChange("group", value)} helpText="Group classification for organization" />
handleFieldChange("isApprovalActive", value) } helpText="Users with this level can participate in approval process" /> handleFieldChange("isActive", value)} helpText="Level is available for assignment" />
{/* Hierarchy Tab */} {/* Level Hierarchy Visualization {userLevels.length > 0 ? (
{renderHierarchyTree()}
) : (

No user levels found

)}
*/} {/* Menu Access Tab */} Menu Access Configuration

Select which menus this user level can access. Users with this level will only see selected menus in the navigation.

{menus.length > 0 ? (
{menus.map((menu) => ( ))}
) : (
No menus available
)}
{/* Action Access Tab */} Action Access Configuration

Configure which actions users with this level can perform in each menu. First select menus in the "Menu Access" tab.

{selectedMenuIds.length > 0 ? (
{selectedMenuIds.map((menuId) => { const menu = menus.find((m) => m.id === menuId); const actions = menuActionsMap[menuId] || []; const selectedActions = selectedActionAccesses[menuId] || []; if (!menu) return null; return ( {menu.name}

{menu.description}

{actions.length > 0 ? (
{actions.map((action) => ( ))}
) : (
No actions available for this menu
)}
); })}
) : (

No menus selected

Please select menus in the "Menu Access" tab first

)}
{/* Bulk Operations Tab */} Bulk User Level Creation

User Levels

{bulkFormData.length === 0 ? (

No user levels added yet. Add multiple levels to create them in bulk.

) : (
{bulkFormData.map((item, index) => (
User Level #{index + 1}
{renderBulkItemForm( item, index, (updatedItem) => { const newItems = [...bulkFormData]; newItems[index] = updatedItem; setBulkFormData(newItems); }, () => { const newItems = bulkFormData.filter( (_, i) => i !== index, ); setBulkFormData(newItems); }, )}
))}
)}
{/* Form Actions */}
{onCancel && ( )} {/* */}
); };