kontenhumas-fe/app/[locale]/(admin)/admin/settings/tenant/component/tenant-settings-content-tab...

1052 lines
44 KiB
TypeScript

"use client";
import React, { useState } 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 {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
PlusIcon,
SettingsIcon,
UsersIcon,
WorkflowIcon,
} from "@/components/icons";
import { ChevronDownIcon, ChevronUpIcon } from "@/components/icons";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { ApprovalWorkflowForm } from "@/components/form/ApprovalWorkflowForm";
import { UserLevelsForm } from "@/components/form/UserLevelsForm";
import { useWorkflowModal } from "@/components/modals/WorkflowModalProvider";
import { useWorkflowStatusCheck } from "@/hooks/useWorkflowStatusCheck";
import { useLocalStorage } from "@/hooks/use-local-storage";
import {
CreateApprovalWorkflowWithClientSettingsRequest,
UserLevelsCreateRequest,
UserLevel,
getUserLevels,
getApprovalWorkflowComprehensiveDetails,
ComprehensiveWorkflowResponse,
createUserLevel,
} from "@/service/approval-workflows";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
PaginationState,
useReactTable,
} from "@tanstack/react-table";
import TablePagination from "@/components/table/table-pagination";
import useTableColumns from "./columns";
import { errorAutoClose, successAutoClose } from "@/lib/swal";
import { close, loading } from "@/config/swal";
import DetailTenant from "@/components/form/tenant/tenant-detail-update-form";
function TenantSettingsContentTable() {
const [activeTab, setActiveTab] = useLocalStorage(
"tenant-settings-active-tab",
"profile",
);
const [isUserLevelDialogOpen, setIsUserLevelDialogOpen] = useState(false);
const [workflow, setWorkflow] =
useState<ComprehensiveWorkflowResponse | null>(null);
const [userLevels, setUserLevels] = useState<UserLevel[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isEditingWorkflow, setIsEditingWorkflow] = useState(false);
const { checkWorkflowStatus } = useWorkflowStatusCheck();
const { showWorkflowModal } = useWorkflowModal();
const [isEditDialogOpen, setIsEditDialogOpen] = React.useState(false);
const [editingUserLevel, setEditingUserLevel] =
React.useState<UserLevel | null>(null);
const [isHierarchyExpanded, setIsHierarchyExpanded] = useState(false);
const handleEditUserLevel = (userLevel: UserLevel) => {
setEditingUserLevel(userLevel);
setIsEditDialogOpen(true);
};
React.useEffect(() => {
loadData();
}, []);
const loadData = async () => {
setIsLoading(true);
try {
const [comprehensiveWorkflowRes, userLevelsRes] = await Promise.all([
getApprovalWorkflowComprehensiveDetails(),
getUserLevels(),
]);
if (!comprehensiveWorkflowRes?.error) {
setWorkflow(comprehensiveWorkflowRes?.data?.data || null);
} else {
setWorkflow(null);
}
if (!userLevelsRes?.error) {
const data = userLevelsRes?.data?.data ?? [];
data.forEach((item: any, index: number) => {
item.no = (page - 1) * Number(showData) + index + 1;
item.parentLevelName =
data.length > 0
? data.find((ul: any) => ul.id === item.parentLevelId)?.name ||
`Level ${item.parentLevelId}`
: `Level ${item.parentLevelId}`;
});
setUserLevels(data);
console.log("LLL", data);
setTotalData(data.length);
setTotalPage(Math.ceil(data.length / Number(showData)));
}
} catch (error) {
console.error("Error loading data:", error);
} finally {
setIsLoading(false);
}
};
const handleWorkflowSave = async (
data: CreateApprovalWorkflowWithClientSettingsRequest,
) => {
setIsEditingWorkflow(false);
await loadData();
};
const handleUserLevelSave = async (data: UserLevelsCreateRequest) => {
try {
loading();
const response = await createUserLevel(data);
close();
if (response?.error) {
errorAutoClose(response.message || "Gagal membuat user level.");
return;
}
successAutoClose("User level berhasil dibuat.");
setIsUserLevelDialogOpen(false);
setTimeout(async () => {
await loadData();
}, 3000);
} catch (error) {
close();
errorAutoClose("Terjadi kesalahan saat membuat user level.");
console.error("Error creating user level:", error);
}
};
const handleBulkUserLevelSave = async (data: UserLevelsCreateRequest[]) => {
setIsUserLevelDialogOpen(false);
await loadData();
};
const columns = React.useMemo(
() => useTableColumns((data) => handleEditUserLevel(data)),
[],
);
const [showData, setShowData] = React.useState("10");
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [totalData, setTotalData] = React.useState<number>(1);
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: Number(showData),
});
const table = useReactTable({
data: userLevels,
columns,
// onSortingChange: setSorting,
// onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
// onColumnVisibilityChange: setColumnVisibility,
// onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
// sorting,
// columnFilters,
// columnVisibility,
// rowSelection,
pagination,
},
});
return (
<div className="container mx-auto p-6 space-y-6 border rounded-lg">
<div className="flex items-center justify-between ">
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">Tenant Settings</h1>
<p className="text-gray-600 mt-2">
Manage approval workflows and user levels for your tenant
</p>
</div>
<div className="flex items-center gap-2">
<SettingsIcon className="h-6 w-6 text-gray-500" />
<Button variant="outline" size="sm" onClick={checkWorkflowStatus}>
Check Workflow Status
</Button>
<Button
variant="outline"
size="sm"
onClick={() => showWorkflowModal({ hasWorkflowSetup: false })}
className="bg-red-50 text-red-600 border-red-200 hover:bg-red-100"
>
Test Modal
</Button>
</div>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger
value="profile"
className="flex items-center gap-2 border rounded-lg"
>
<WorkflowIcon className="h-4 w-4" />
Detail Tenant
</TabsTrigger>
<TabsTrigger
value="workflows"
className="flex items-center gap-2 border rounded-lg"
>
<WorkflowIcon className="h-4 w-4" />
Approval Workflows
</TabsTrigger>
<TabsTrigger
value="user-levels"
className="flex items-center gap-2 border rounded-lg"
>
<UsersIcon className="h-4 w-4" />
User Levels
</TabsTrigger>
</TabsList>
{/* Approval Workflows Tab */}
<TabsContent value="profile" className="space-y-6 border rounded-lg">
<DetailTenant id={10} />
</TabsContent>
<TabsContent value="workflows" className="space-y-6 border rounded-lg">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-semibold ml-2 mt-4">
Approval Workflow Setup
</h2>
{workflow && !isEditingWorkflow && (
<Button
variant="outline"
onClick={() => setIsEditingWorkflow(true)}
className="flex items-center gap-2"
>
<SettingsIcon className="h-4 w-4" />
Edit Workflow
</Button>
)}
</div>
{isEditingWorkflow && workflow && workflow.workflow?.id ? (
<Card>
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>Setup Approval Workflow</span>
<Button
variant="outline"
onClick={() => setIsEditingWorkflow(false)}
>
Cancel
</Button>
</CardTitle>
</CardHeader>
<CardContent>
<ApprovalWorkflowForm
key={workflow.workflow.id}
workflowId={workflow.workflow.id}
initialData={
workflow
? {
name: workflow.workflow.name,
description: workflow.workflow.description,
isDefault: workflow.workflow.isDefault,
isActive: workflow.workflow.isActive,
requiresApproval:
workflow.clientSettings.requiresApproval,
// workflow.workflow.requiresApproval,
autoPublish:
workflow.clientSettings.autoPublishArticles,
// workflow.workflow.autoPublish,
steps:
workflow.steps?.map((step) => ({
stepOrder: step.stepOrder,
stepName: step.stepName,
requiredUserLevelId: step.requiredUserLevelId,
canSkip: step.canSkip,
autoApproveAfterHours: step.autoApproveAfterHours,
isActive: step.isActive,
conditionType: step.conditionType,
conditionValue: step.conditionValue,
})) || [],
clientApprovalSettings: {
approvalExemptCategories:
workflow.clientSettings.exemptCategoriesDetails ||
[],
approvalExemptRoles:
workflow.clientSettings.exemptRolesDetails || [],
approvalExemptUsers:
workflow.clientSettings.exemptUsersDetails || [],
autoPublishArticles:
workflow.clientSettings.autoPublishArticles,
isActive: workflow.clientSettings.isActive,
requireApprovalFor:
workflow.clientSettings.requireApprovalFor || [],
requiresApproval:
workflow.clientSettings.requiresApproval,
skipApprovalFor:
workflow.clientSettings.skipApprovalFor || [],
},
}
: undefined
}
onSave={handleWorkflowSave}
onCancel={() => setIsEditingWorkflow(false)}
/>
</CardContent>
</Card>
) : workflow ? (
<Card>
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>{workflow.workflow.name}</span>
<div className="flex items-center gap-2">
{workflow.workflow.isDefault && (
<span className="px-2 py-1 text-xs bg-blue-100 text-blue-800 rounded-full">
Default
</span>
)}
{workflow.workflow.isActive ? (
<span className="px-2 py-1 text-xs bg-green-100 text-green-800 rounded-full">
Active
</span>
) : (
<span className="px-2 py-1 text-xs bg-gray-100 text-gray-800 rounded-full">
Inactive
</span>
)}
</div>
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-gray-600 text-sm mb-4">
{workflow.workflow.description}
</p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-blue-600">
{workflow.workflow.totalSteps}
</div>
<div className="text-sm text-gray-600">Total Steps</div>
</div>
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-green-600">
{workflow.workflow.activeSteps}
</div>
<div className="text-sm text-gray-600">Active Steps</div>
</div>
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div
className={`text-2xl font-bold ${
// workflow.workflow.requiresApproval
workflow.clientSettings.requiresApproval
? "text-green-600"
: "text-red-600"
}`}
>
{
// workflow.workflow.requiresApproval
workflow.clientSettings.requiresApproval
? "Yes"
: "No"
}
</div>
<div className="text-sm text-gray-600">
Requires Approval
</div>
</div>
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div
className={`text-2xl font-bold ${
// workflow.workflow.autoPublish
workflow.clientSettings.autoPublishArticles
? "text-green-600"
: "text-red-600"
}`}
>
{
// workflow.workflow.autoPublish
workflow.clientSettings.autoPublishArticles
? "Yes"
: "No"
}
</div>
<div className="text-sm text-gray-600">Auto Publish</div>
</div>
</div>
{/* Workflow Steps Overview */}
{workflow.steps && workflow.steps.length > 0 && (
<div className="mb-6">
<h4 className="text-lg font-medium mb-3">Workflow Steps</h4>
<div className="space-y-2">
{workflow.steps.map((step: any, index: number) => (
<div
key={index}
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center text-sm font-medium">
{step.stepOrder}
</div>
<div>
<div className="font-medium dark:text-black">{step.stepName}</div>
<div className="text-sm text-gray-500">
{step.conditionType &&
`Condition: ${step.conditionType}`}
{step.autoApproveAfterHours &&
` • Auto-approve after ${step.autoApproveAfterHours}h`}
{step.requiredUserLevelName &&
` • Required Level: ${step.requiredUserLevelName}`}
</div>
</div>
</div>
<div className="flex items-center gap-2">
{step.canSkip && (
<span className="px-2 py-1 text-xs bg-yellow-100 text-yellow-800 rounded-full">
Can Skip
</span>
)}
{step.isParallel && (
<span className="px-2 py-1 text-xs bg-purple-100 text-purple-800 rounded-full">
Parallel
</span>
)}
{step.isActive && (
<span className="px-2 py-1 text-xs bg-green-100 text-green-800 rounded-full">
Active
</span>
)}
{step.isFirstStep && (
<span className="px-2 py-1 text-xs bg-blue-100 text-blue-800 rounded-full">
First Step
</span>
)}
{step.isLastStep && (
<span className="px-2 py-1 text-xs bg-orange-100 text-orange-800 rounded-full">
Last Step
</span>
)}
</div>
</div>
))}
</div>
</div>
)}
{/* Client Settings */}
<div className="mb-6">
<h4 className="text-lg font-medium mb-3">Client Settings</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Default Workflow
</div>
<div className="text-sm text-gray-600">
{workflow.clientSettings.defaultWorkflowName}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Auto Publish Articles
</div>
<div
className={`text-sm font-medium ${
workflow.clientSettings.autoPublishArticles
? "text-green-600"
: "text-red-600"
}`}
>
{workflow.clientSettings.autoPublishArticles
? "Yes"
: "No"}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Requires Approval
</div>
<div
className={`text-sm font-medium ${
workflow.clientSettings.requiresApproval
? "text-green-600"
: "text-red-600"
}`}
>
{workflow.clientSettings.requiresApproval
? "Yes"
: "No"}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Settings Active
</div>
<div
className={`text-sm font-medium ${
workflow.clientSettings.isActive
? "text-green-600"
: "text-red-600"
}`}
>
{workflow.clientSettings.isActive ? "Yes" : "No"}
</div>
</div>
</div>
</div>
{/* Statistics */}
<div className="mb-6">
<h4 className="text-lg font-medium mb-3">
Workflow Statistics
</h4>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Total Articles Processed
</div>
<div className="text-2xl font-bold text-blue-600">
{workflow.statistics.totalArticlesProcessed}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Pending Articles
</div>
<div className="text-2xl font-bold text-yellow-600">
{workflow.statistics.pendingArticles}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Approved Articles
</div>
<div className="text-2xl font-bold text-green-600">
{workflow.statistics.approvedArticles}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Rejected Articles
</div>
<div className="text-2xl font-bold text-red-600">
{workflow.statistics.rejectedArticles}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Average Processing Time
</div>
<div className="text-2xl font-bold text-purple-600">
{workflow.statistics.averageProcessingTime}h
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Most Active Step
</div>
<div className="text-sm text-gray-600">
{workflow.statistics.mostActiveStep || "N/A"}
</div>
</div>
</div>
</div>
{/* Workflow Metadata */}
<div className="mb-6">
<h4 className="text-lg font-medium mb-3">
Workflow Information
</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Client ID
</div>
<div className="text-sm text-gray-600 font-mono">
{workflow.workflow.clientId}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Created At
</div>
<div className="text-sm text-gray-600">
{new Date(workflow.workflow.createdAt).toLocaleString()}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Updated At
</div>
<div className="text-sm text-gray-600">
{new Date(workflow.workflow.updatedAt).toLocaleString()}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Workflow ID
</div>
<div className="text-sm text-gray-600 font-mono">
{workflow.workflow.id}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Has Branches
</div>
<div
className={`text-sm font-medium ${
workflow.workflow.hasBranches
? "text-green-600"
: "text-gray-600"
}`}
>
{workflow.workflow.hasBranches ? "Yes" : "No"}
</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-sm font-medium text-gray-700 mb-1">
Max Step Order
</div>
<div className="text-sm text-gray-600">
{workflow.workflow.maxStepOrder}
</div>
</div>
</div>
</div>
</CardContent>
</Card>
) : (
<Card>
<CardContent className="flex items-center justify-center py-12">
<div className="text-center">
<WorkflowIcon className="h-12 w-12 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">
No Workflow Configured
</h3>
<p className="text-gray-500 mb-4">
Set up your approval workflow to manage content approval
process
</p>
<Button onClick={() => setIsEditingWorkflow(true)}>
<PlusIcon className="h-4 w-4 mr-2" />
Setup Workflow
</Button>
</div>
</CardContent>
</Card>
)}
</TabsContent>
{/* User Levels Tab */}
<TabsContent value="user-levels" className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-semibold">User Levels</h2>
<Dialog
open={isUserLevelDialogOpen}
onOpenChange={setIsUserLevelDialogOpen}
>
<DialogTrigger asChild>
<Button
variant="outline"
className="flex items-center gap-2 hover:bg-muted focus-visible:bg-muted"
>
<PlusIcon className="h-4 w-4" />
Create User Level
</Button>
</DialogTrigger>
<DialogContent className="md:max-w-6xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Create New User Level</DialogTitle>
</DialogHeader>
<UserLevelsForm
mode="single"
onSave={handleUserLevelSave}
onCancel={() => setIsUserLevelDialogOpen(false)}
/>
</DialogContent>
</Dialog>
</div>
{/* User Levels Summary */}
{userLevels.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-blue-600">
{userLevels.length}
</div>
<div className="text-sm text-gray-600">Total User Levels</div>
</div>
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-green-600">
{userLevels.filter((ul) => ul.isActive).length}
</div>
<div className="text-sm text-gray-600">Active Levels</div>
</div>
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-purple-600">
{userLevels.filter((ul) => ul.isApprovalActive).length}
</div>
<div className="text-sm text-gray-600">Approval Active</div>
</div>
<div className="text-center p-4 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-orange-600">
{userLevels.filter((ul) => ul.parentLevelId).length}
</div>
<div className="text-sm text-gray-600">Child Levels</div>
</div>
</div>
)}
{/* User Levels Hierarchy */}
{userLevels.length > 0 && (
<Card>
<Collapsible
open={isHierarchyExpanded}
onOpenChange={setIsHierarchyExpanded}
>
<CollapsibleTrigger asChild>
<CardHeader className="cursor-pointer hover:bg-gray-50 transition-colors">
<CardTitle className="flex items-center justify-between">
<div className="flex items-center gap-2">
<UsersIcon className="h-5 w-5" />
User Levels Hierarchy
</div>
{isHierarchyExpanded ? (
<ChevronUpIcon className="h-4 w-4" />
) : (
<ChevronDownIcon className="h-4 w-4" />
)}
</CardTitle>
</CardHeader>
</CollapsibleTrigger>
<CollapsibleContent>
<CardContent>
<div className="space-y-3">
{userLevels
.filter((ul) => !ul.parentLevelId) // Root levels
.sort((a, b) => a.levelNumber - b.levelNumber)
.map((rootLevel) => (
<div key={rootLevel.id} className="space-y-2">
{/* Root Level */}
<div className="flex items-center gap-3 p-3 bg-blue-50 rounded-lg border-l-4 border-blue-500">
<div className="w-8 h-8 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center text-sm font-medium">
{rootLevel.levelNumber}
</div>
<div className="flex-1">
<div className="font-medium">
{rootLevel.name}
</div>
<div className="text-sm text-gray-500">
{rootLevel.aliasName} {" "}
{rootLevel.group || "No group"}
</div>
</div>
<div className="flex items-center gap-2">
{rootLevel.isActive && (
<span className="px-2 py-1 text-xs bg-green-100 text-green-800 rounded-full">
Active
</span>
)}
{rootLevel.isApprovalActive && (
<span className="px-2 py-1 text-xs bg-purple-100 text-purple-800 rounded-full">
Approval Active
</span>
)}
</div>
</div>
{/* Child Levels */}
{userLevels
.filter((ul) => ul.parentLevelId === rootLevel.id)
.sort((a, b) => a.levelNumber - b.levelNumber)
.map((childLevel) => (
<div
key={childLevel.id}
className="ml-8 flex items-center gap-3 p-3 bg-gray-50 rounded-lg border-l-4 border-gray-300"
>
<div className="w-6 h-6 bg-gray-100 text-gray-600 rounded-full flex items-center justify-center text-xs font-medium">
{childLevel.levelNumber}
</div>
<div className="flex-1">
<div className="font-medium text-sm">
{childLevel.name}
</div>
<div className="text-xs text-gray-500">
{childLevel.aliasName} {" "}
{childLevel.group || "No group"}
</div>
</div>
<div className="flex items-center gap-1">
{childLevel.isActive && (
<span className="px-1 py-0.5 text-xs bg-green-100 text-green-800 rounded-full">
Active
</span>
)}
{childLevel.isApprovalActive && (
<span className="px-1 py-0.5 text-xs bg-purple-100 text-purple-800 rounded-full">
Approval
</span>
)}
</div>
</div>
))}
</div>
))}
</div>
</CardContent>
</CollapsibleContent>
</Collapsible>
</Card>
)}
<Table className="overflow-hidden mt-3 mx-3">
<TableHeader className="sticky top-0 bg-white shadow-sm z-10">
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
<DialogContent className="md:max-w-6xl max-h-[90vh] overflow-y-auto transition-all duration-200 ease-in-out">
<DialogHeader>
<DialogTitle>
{editingUserLevel
? `Edit User Level: ${editingUserLevel.name}`
: "Edit User Level"}
</DialogTitle>
</DialogHeader>
{editingUserLevel ? (
<UserLevelsForm
mode="single"
initialData={{
// id: editingUserLevel.id,
name: editingUserLevel.name,
aliasName: editingUserLevel.aliasName,
levelNumber: editingUserLevel.levelNumber,
parentLevelId: editingUserLevel.parentLevelId || 0,
provinceId: editingUserLevel.provinceId,
group: editingUserLevel.group || "",
isApprovalActive: editingUserLevel.isApprovalActive,
isActive: editingUserLevel.isActive,
}}
onSave={async (data) => {
// The form handles the update internally
setIsEditDialogOpen(false);
setEditingUserLevel(null);
await loadData();
}}
onCancel={() => {
setIsEditDialogOpen(false);
setEditingUserLevel(null);
}}
/>
) : (
<p className="text-gray-500 text-center py-6">Loading...</p>
)}
</DialogContent>
</Dialog>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
{/* <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{userLevels.length > 0 ? userLevels.map((userLevel) => (
<Card key={userLevel.id} className="hover:shadow-lg transition-shadow">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span className="truncate">{userLevel.name}</span>
<div className="flex items-center gap-2">
<span className="px-2 py-1 text-xs bg-blue-100 text-blue-800 rounded-full">
Level {userLevel.levelNumber}
</span>
{userLevel.isActive ? (
<span className="px-2 py-1 text-xs bg-green-100 text-green-800 rounded-full">
Active
</span>
) : (
<span className="px-2 py-1 text-xs bg-gray-100 text-gray-800 rounded-full">
Inactive
</span>
)}
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2 mb-4">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500">Alias:</span>
<span className="font-mono text-xs bg-gray-100 px-2 py-1 rounded">
{userLevel.aliasName}
</span>
</div>
{userLevel.group && (
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500">Group:</span>
<span className="font-medium">{userLevel.group}</span>
</div>
)}
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500">Approval Active:</span>
<span className={`font-medium ${userLevel.isApprovalActive ? 'text-green-600' : 'text-red-600'}`}>
{userLevel.isApprovalActive ? 'Yes' : 'No'}
</span>
</div>
{userLevel.parentLevelId && (
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500">Parent Level:</span>
<span className="font-medium">
{ userLevels.length > 0 ? userLevels.find(ul => ul.id === userLevel.parentLevelId)?.name || `Level ${userLevel.parentLevelId}` : `Level ${userLevel.parentLevelId}`}
</span>
</div>
)}
{userLevel.provinceId && (
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500">Province:</span>
<span className="font-medium">Province {userLevel.provinceId}</span>
</div>
)}
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500">Created:</span>
<span className="font-medium text-xs">
{userLevel.createdAt ? new Date(userLevel.createdAt).toLocaleDateString() : 'N/A'}
</span>
</div>
</div>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" className="flex-1">
Edit
</Button>
<Button variant="outline" size="sm" className="flex-1">
Users
</Button>
</div>
</CardContent>
</Card>
)) : ''}
</div> */}
{userLevels.length === 0 && !isLoading && (
<Card>
<CardContent className="flex items-center justify-center py-12">
<div className="text-center">
<UsersIcon className="h-12 w-12 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">
No User Levels Found
</h3>
<p className="text-gray-500 mb-4">
Create your first user level to define approval hierarchy
</p>
<Button onClick={() => setIsUserLevelDialogOpen(true)}>
<PlusIcon className="h-4 w-4 mr-2" />
Create User Level
</Button>
</div>
</CardContent>
</Card>
)}
</TabsContent>
</Tabs>
</div>
);
}
export default function TenantSettingsPageTable() {
return <TenantSettingsContentTable />;
}