fix: table user level, navbar show detail profile login

This commit is contained in:
Sabda Yagra 2025-10-04 22:10:40 +07:00
parent 741fe97641
commit 24c0adfa8d
11 changed files with 1392 additions and 739 deletions

View File

@ -0,0 +1,283 @@
"use client";
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
import { useRouter } from "next/navigation";
import { deleteMedia } from "@/service/content/content";
import { error } from "@/lib/swal";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import Link from "next/link";
const useTableColumns = () => {
const MySwal = withReactContent(Swal);
const userLevelId = getCookiesDecrypt("ulie");
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "aliasName",
header: "Name",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("aliasName")}
</h4>
</div>
</div>
),
},
{
accessorKey: "group",
header: "Group",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("group")}
</h4>
</div>
</div>
),
},
{
accessorKey: "parentLevelName",
header: "Parent Level",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("parentLevelName")}
</h4>
</div>
</div>
),
},
// {
// accessorKey: "createdAt",
// header: "Upload Date",
// cell: ({ row }) => {
// const createdAt = row.getValue("createdAt") as string | number | undefined;
// const formattedDate =
// createdAt && !isNaN(new Date(createdAt).getTime())
// ? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
// : "-";
// return <span className="whitespace-nowrap">{formattedDate}</span>;
// },
// },
// {
// accessorKey: "creatorName",
// header: "Creator Group",
// cell: ({ row }) => (
// <span className="whitespace-nowrap">
// {row.original.creatorName || row.original.createdByName || "-"}
// </span>
// ),
// },
// {
// accessorKey: "creatorGroupLevelName",
// header: "Source",
// cell: ({ row }) => (
// <span className="whitespace-nowrap">
// {row.getValue("creatorGroupLevelName") || "-"}
// </span>
// ),
// },
// {
// accessorKey: "publishedOn",
// header: "Published",
// cell: ({ row }) => {
// const isPublish = row.original.isPublish;
// const isPublishOnPolda = row.original.isPublishOnPolda;
// const creatorGroupParentLevelId = row.original.creatorGroupParentLevelId;
// let displayText = "-";
// if (isPublish && !isPublishOnPolda) {
// displayText = "Mabes";
// } else if (isPublish && isPublishOnPolda) {
// if (Number(creatorGroupParentLevelId) === 761) {
// displayText = "Mabes & Satker";
// } else {
// displayText = "Mabes & Polda";
// }
// } else if (!isPublish && isPublishOnPolda) {
// if (Number(creatorGroupParentLevelId) === 761) {
// displayText = "Satker";
// } else {
// displayText = "Polda";
// }
// }
// return (
// <div className="text-center whitespace-nowrap" title={displayText}>
// {displayText}
// </div>
// );
// },
// },
// {
// accessorKey: "statusName",
// header: "Status",
// cell: ({ row }) => {
// const statusId = Number(row.original?.statusId);
// const reviewedAtLevel = row.original?.reviewedAtLevel || "";
// const creatorGroupLevelId = Number(row.original?.creatorGroupLevelId);
// const needApprovalFromLevel = Number(row.original?.needApprovalFromLevel);
// const userHasReviewed = reviewedAtLevel.includes(`:${userLevelId}:`);
// const isCreator = creatorGroupLevelId === Number(userLevelId);
// const isWaitingForReview = statusId === 2 && !userHasReviewed && !isCreator;
// const isApprovalNeeded = statusId === 1 && needApprovalFromLevel === Number(userLevelId);
// const label =
// isWaitingForReview || isApprovalNeeded
// ? "Menunggu Review"
// : statusId === 2
// ? "Diterima"
// : row.original?.statusName;
// const colors: Record<string, string> = {
// "Menunggu Review": "bg-orange-100 text-orange-600",
// Diterima: "bg-green-100 text-green-600",
// default: "bg-red-200 text-red-600",
// };
// const statusStyles = colors[label] || colors.default;
// return (
// <Badge className={cn("rounded-full px-5 w-full whitespace-nowrap", statusStyles)}>
// {label}
// </Badge>
// );
// },
// },
{
id: "actions",
accessorKey: "action",
header: "Action",
enableHiding: false,
cell: ({ row }) => {
const router = useRouter();
const MySwal = withReactContent(Swal);
async function doDelete(id: any) {
const data = { id };
const response = await deleteMedia(data);
if (response?.error) {
error(response.message);
return false;
}
success();
}
function success() {
MySwal.fire({
title: "Sukses",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
window.location.reload();
}
});
}
const handleDeleteMedia = (id: any) => {
MySwal.fire({
title: "Hapus Data",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#3085d6",
confirmButtonColor: "#d33",
confirmButtonText: "Hapus",
}).then((result) => {
if (result.isConfirmed) {
doDelete(id);
}
});
};
const [isMabesApprover, setIsMabesApprover] = React.useState(false);
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const roleId = getCookiesDecrypt("urie");
React.useEffect(() => {
if (userLevelId !== undefined && roleId !== undefined) {
setIsMabesApprover(Number(userLevelId) === 216 && Number(roleId) === 3);
}
}, [userLevelId, roleId]);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0 hover:text-black" align="end">
<Link
href={`/admin/content/image/detail/${row.original.id}`}
className="hover:text-black"
>
<DropdownMenuItem className="p-2 border-b text-default-700 rounded-none">
<Eye className="w-4 h-4 me-1.5" />
View
</DropdownMenuItem>
</Link>
{/* {(Number(row.original.uploadedById) === Number(userId) || isMabesApprover) && ( */}
<Link href={`/admin/content/image/update/${row.original.id}`}>
<DropdownMenuItem className="p-2 border-b text-default-700 rounded-none">
<SquarePen className="w-4 h-4 me-1.5" />
Edit
</DropdownMenuItem>
</Link>
{/* )} */}
<DropdownMenuItem
onClick={() => handleDeleteMedia(row.original.id)}
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-white rounded-none"
>
<Trash2 className="w-4 h-4 me-1.5" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
];
return columns;
};
export default useTableColumns;

View File

@ -0,0 +1,923 @@
"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 { ApprovalWorkflowForm } from "@/components/form/ApprovalWorkflowForm";
import { UserLevelsForm } from "@/components/form/UserLevelsForm";
import { useWorkflowModal } from "@/components/modals/WorkflowModalProvider";
import { useWorkflowStatusCheck } from "@/hooks/useWorkflowStatusCheck";
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";
function TenantSettingsContentTable() {
const [activeTab, setActiveTab] = useState("workflows");
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();
React.useEffect(() => {
loadData();
}, []);
const loadData = async () => {
setIsLoading(true);
try {
const [comprehensiveWorkflowRes, userLevelsRes] = await Promise.all([
getApprovalWorkflowComprehensiveDetails(4),
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);
}
} 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 {
const response = await createUserLevel(data);
if (response?.error) {
console.error("Error creating user level:", response?.message);
} else {
console.log("User level created successfully:", response);
}
} catch (error) {
console.error("Error creating user level:", error);
}
setIsUserLevelDialogOpen(false);
await loadData();
};
const handleBulkUserLevelSave = async (data: UserLevelsCreateRequest[]) => {
setIsUserLevelDialogOpen(false);
await loadData();
};
const columns = useTableColumns();
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">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-2">
<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="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
onClick={() => setIsEditingWorkflow(true)}
className="flex items-center gap-2"
>
<SettingsIcon className="h-4 w-4" />
Edit Workflow
</Button>
)}
</div>
{isEditingWorkflow ? (
<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
initialData={
workflow
? {
name: workflow.workflow.name,
description: workflow.workflow.description,
isDefault: workflow.workflow.isDefault,
isActive: workflow.workflow.isActive,
requiresApproval: workflow.workflow.requiresApproval,
autoPublish: 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
? "text-green-600"
: "text-red-600"
}`}
>
{workflow.workflow.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
? "text-green-600"
: "text-red-600"
}`}
>
{workflow.workflow.autoPublish ? "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">{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 className="flex items-center gap-2">
<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>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<UsersIcon className="h-5 w-5" />
User Levels Hierarchy
</CardTitle>
</CardHeader>
<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>
</Card>
)}
<Table className="overflow-hidden mt-3 mx-3">
<TableHeader>
{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>
<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 />;
}

View File

@ -3,8 +3,19 @@ import React, { useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import {
import { PlusIcon, SettingsIcon, UsersIcon, WorkflowIcon } from "@/components/icons"; Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
PlusIcon,
SettingsIcon,
UsersIcon,
WorkflowIcon,
} from "@/components/icons";
import { ApprovalWorkflowForm } from "@/components/form/ApprovalWorkflowForm"; import { ApprovalWorkflowForm } from "@/components/form/ApprovalWorkflowForm";
import { UserLevelsForm } from "@/components/form/UserLevelsForm"; import { UserLevelsForm } from "@/components/form/UserLevelsForm";
import { useWorkflowModal } from "@/components/modals/WorkflowModalProvider"; import { useWorkflowModal } from "@/components/modals/WorkflowModalProvider";
@ -18,637 +29,29 @@ import {
ComprehensiveWorkflowResponse, ComprehensiveWorkflowResponse,
createUserLevel, createUserLevel,
} from "@/service/approval-workflows"; } 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 useTableColumns from "./component/columns";
import TablePagination from "@/components/table/table-pagination";
import TenantSettingsPageTable from "./component/table-user-level";
function TenantSettingsContent() {
const [activeTab, setActiveTab] = useState("workflows");
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();
React.useEffect(() => {
loadData();
}, []);
const loadData = async () => {
setIsLoading(true);
try {
const [comprehensiveWorkflowRes, userLevelsRes] = await Promise.all([
getApprovalWorkflowComprehensiveDetails(4),
getUserLevels(),
]);
if (!comprehensiveWorkflowRes?.error) {
setWorkflow(comprehensiveWorkflowRes?.data?.data || null);
} else {
setWorkflow(null);
}
if (!userLevelsRes?.error) {
setUserLevels(userLevelsRes?.data?.data || []);
}
} 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 {
const response = await createUserLevel(data);
if (response?.error) {
console.error("Error creating user level:", response?.message);
} else {
console.log("User level created successfully:", response);
}
} catch (error) {
console.error("Error creating user level:", error);
}
setIsUserLevelDialogOpen(false);
await loadData();
};
const handleBulkUserLevelSave = async (data: UserLevelsCreateRequest[]) => {
setIsUserLevelDialogOpen(false);
await loadData();
};
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">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-2">
<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="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
onClick={() => setIsEditingWorkflow(true)}
className="flex items-center gap-2"
>
<SettingsIcon className="h-4 w-4" />
Edit Workflow
</Button>
)}
</div>
{isEditingWorkflow ? (
<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
initialData={workflow ? {
name: workflow.workflow.name,
description: workflow.workflow.description,
isDefault: workflow.workflow.isDefault,
isActive: workflow.workflow.isActive,
requiresApproval: workflow.workflow.requiresApproval,
autoPublish: 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 ? 'text-green-600' : 'text-red-600'}`}>
{workflow.workflow.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 ? 'text-green-600' : 'text-red-600'}`}>
{workflow.workflow.autoPublish ? '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">{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 className="flex items-center gap-2">
<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>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<UsersIcon className="h-5 w-5" />
User Levels Hierarchy
</CardTitle>
</CardHeader>
<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>
</Card>
)}
<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 TenantSettingsPage() { export default function TenantSettingsPage() {
return <TenantSettingsContent />; return <TenantSettingsPageTable />;
} }

View File

@ -96,9 +96,15 @@ export default function Login() {
Cookies.set("username", profile?.data?.data?.username, { Cookies.set("username", profile?.data?.data?.username, {
expires: 1, expires: 1,
}); });
Cookies.set("urie", profile?.data?.data?.roleId, { Cookies.set("urie", profile?.data?.data?.userRoleId, {
expires: 1, expires: 1,
}); });
console.log(
"RRR",
profile?.data?.data?.role.id,
"TTTT",
profile?.data?.data?.roleId
);
Cookies.set("roleName", profile?.data?.data?.roleName, { Cookies.set("roleName", profile?.data?.data?.roleName, {
expires: 1, expires: 1,
}); });
@ -114,7 +120,9 @@ export default function Login() {
Cookies.set("email", profile?.data?.data?.email, { Cookies.set("email", profile?.data?.data?.email, {
expires: 1, expires: 1,
}); });
router.push("/admin/dashboard"); // router.push("/admin/dashboard");
console.log("OOO", profile?.data?.data);
Cookies.set("status", "login", { Cookies.set("status", "login", {
expires: 1, expires: 1,
}); });

View File

@ -28,51 +28,61 @@ const PUBLIKASI_SUBMENU = [
export default function Navbar() { export default function Navbar() {
const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [user, setUser] = useState<{ // const [user, setUser] = useState<{
id: number; // id: number;
name: string; // name: string;
avatar: string; // avatar: string;
} | null>(null); // } | null>(null);
const [isDropdownOpen, setDropdownOpen] = useState(false); const [isDropdownOpen, setDropdownOpen] = useState(false);
const [showProfileMenu, setShowProfileMenu] = useState(false); const [showProfileMenu, setShowProfileMenu] = useState(false);
const pathname = usePathname(); const pathname = usePathname();
useEffect(() => {
const roleId = getCookiesDecrypt("urie");
console.log("roleId", roleId);
switch (roleId) {
case "3":
setUser({
id: 3,
name: "Mabes Polri - Approver",
avatar: "/contributor.png",
});
break;
case "7": // useEffect(() => {
setUser({ // const roleId = getCookiesDecrypt("urie");
id: 7, // console.log("roleId", roleId);
name: "DivHumas - RoMulmed - BagDise",
avatar: "/contributor.png",
});
break;
case "6": // switch (roleId) {
setUser({ // case "1":
id: 11, // setUser({
name: "jurnalis-kompas1", // id: 1,
avatar: "/contributor.png", // name: "User Test",
}); // avatar: "/contributor.png",
break; // });
// break;
// case "3":
// setUser({
// id: 3,
// name: "Mabes Polri - Approver",
// avatar: "/contributor.png",
// });
// break;
default: // case "7":
setUser(null); // setUser({
} // id: 7,
}, []); // name: "DivHumas - RoMulmed - BagDise",
// avatar: "/contributor.png",
// });
// break;
const isLoggedIn = user !== null; // case "6":
// setUser({
// id: 11,
// name: "jurnalis-kompas1",
// avatar: "/contributor.png",
// });
// break;
// default:
// setUser(null);
// }
// }, []);
const roleId = getCookiesDecrypt("urie");
const isLoggedIn = roleId !== null;
const filteredNavItems = isLoggedIn const filteredNavItems = isLoggedIn
? NAV_ITEMS.filter((item) => item.label !== "Mengikuti") ? NAV_ITEMS.filter((item) => item.label !== "Mengikuti")
@ -85,10 +95,27 @@ export default function Navbar() {
window.location.href = "/"; window.location.href = "/";
setUser(null); // setUser(null);
setShowProfileMenu(false); setShowProfileMenu(false);
}; };
const username = Cookies.get("username");
const fullname = Cookies.get("ufne");
// const router = useRouter();
// const [detail, setDetail] = useState<Detail>();
// const onLogout = () => {
// Object.keys(Cookies.get()).forEach((cookieName) => {
// Cookies.remove(cookieName);
// });
// router.push("/");
// };
const [isLogin, setIsLogin] = useState(false);
useEffect(() => {
setIsLogin(fullname ? true : false);
}, [fullname]);
return ( return (
<header className="relative max-w-[1400px] mx-auto flex items-center justify-between px-4 py-3 border-b bg-white z-50"> <header className="relative max-w-[1400px] mx-auto flex items-center justify-between px-4 py-3 border-b bg-white z-50">
<div className="flex flex-row items-center justify-between space-x-4 z-10"> <div className="flex flex-row items-center justify-between space-x-4 z-10">
@ -188,15 +215,15 @@ export default function Navbar() {
> >
<div className="w-9 h-9 rounded-full overflow-hidden border"> <div className="w-9 h-9 rounded-full overflow-hidden border">
<Image <Image
src={user.avatar} src="/contributor.png"
alt={user.name} alt={username as string}
width={36} width={36}
height={36} height={36}
className="object-cover" className="object-cover"
/> />
</div> </div>
<span className="text-sm font-medium text-gray-800"> <span className="text-sm font-medium text-gray-800">
{user.name} {fullname}
</span> </span>
<ChevronDown className="w-4 h-4 text-gray-600" /> <ChevronDown className="w-4 h-4 text-gray-600" />
</button> </button>

View File

@ -113,12 +113,12 @@ export function WorkflowModalProvider({ children }: WorkflowModalProviderProps)
return ( return (
<WorkflowModalContext.Provider value={{ showWorkflowModal, hideWorkflowModal, refreshWorkflowStatus }}> <WorkflowModalContext.Provider value={{ showWorkflowModal, hideWorkflowModal, refreshWorkflowStatus }}>
{children} {children}
<WorkflowSetupModal {/* <WorkflowSetupModal
isOpen={isModalOpen} isOpen={isModalOpen}
onClose={hideWorkflowModal} onClose={hideWorkflowModal}
workflowInfo={workflowInfo} workflowInfo={workflowInfo}
onRefresh={refreshWorkflowStatus} onRefresh={refreshWorkflowStatus}
/> /> */}
</WorkflowModalContext.Provider> </WorkflowModalContext.Provider>
); );
} }

View File

@ -171,7 +171,8 @@ const LoginForm = () => {
setCookiesEncrypt("uie", profile?.data?.data?.id, { setCookiesEncrypt("uie", profile?.data?.data?.id, {
expires: 1, expires: 1,
}); });
setCookiesEncrypt("urie", profile?.data?.data?.roleId, { console.log("QQQ", profile?.data?.data?.role.id, "LLL", profile?.data?.data?.roleId,)
setCookiesEncrypt("urie", profile?.data?.data?.userRoleId, {
expires: 1, expires: 1,
}); });
setCookiesEncrypt("urne", profile?.data?.data?.role?.name, { setCookiesEncrypt("urne", profile?.data?.data?.role?.name, {
@ -203,50 +204,53 @@ const LoginForm = () => {
setCookiesEncrypt("uinse", profile?.data?.data?.instituteId, { setCookiesEncrypt("uinse", profile?.data?.data?.instituteId, {
expires: 1, expires: 1,
}); });
console.log("ssaddd", profile?.data?.data?.roleId); setCookiesEncrypt("username", profile?.data?.data?.username, {
if ( expires: 1,
Number(profile?.data?.data?.roleId) == 2 || });
Number(profile?.data?.data?.roleId) == 3 || console.log("KKKK", profile?.data?.data)
Number(profile?.data?.data?.roleId) == 4 || // if (
Number(profile?.data?.data?.roleId) == 9 || // Number(profile?.data?.data?.roleId) == 2 ||
Number(profile?.data?.data?.roleId) == 10 || // Number(profile?.data?.data?.roleId) == 3 ||
Number(profile?.data?.data?.roleId) == 11 || // Number(profile?.data?.data?.roleId) == 4 ||
Number(profile?.data?.data?.roleId) == 12 || // Number(profile?.data?.data?.roleId) == 9 ||
Number(profile?.data?.data?.roleId) == 18 || // Number(profile?.data?.data?.roleId) == 10 ||
Number(profile?.data?.data?.roleId) == 19 // Number(profile?.data?.data?.roleId) == 11 ||
) { // Number(profile?.data?.data?.roleId) == 12 ||
if (profile?.data?.data?.roleId === 18) { // Number(profile?.data?.data?.roleId) == 18 ||
window.location.href = "/in/dashboard/executive-data"; // Number(profile?.data?.data?.roleId) == 19
// router.push('/admin/dashboard'); // ) {
Cookies.set("status", "login", { // if (profile?.data?.data?.roleId === 18) {
expires: 1, // window.location.href = "/in/dashboard/executive-data";
}); // // router.push('/admin/dashboard');
} else if (profile?.data?.data?.roleId === 2) { // Cookies.set("status", "login", {
window.location.href = "/in/dashboard/executive"; // expires: 1,
Cookies.set("status", "login", { // });
expires: 1, // } else if (profile?.data?.data?.roleId === 2) {
}); // window.location.href = "/in/dashboard/executive";
} else if ( // Cookies.set("status", "login", {
profile?.data?.data?.userLevel?.id == 794 || // expires: 1,
profile?.data?.data?.userLevel?.parentLevelId == 761 // });
) { // } else if (
window.location.href = "/in/dashboard"; // profile?.data?.data?.userLevel?.id == 794 ||
Cookies.set("status", "login", { // profile?.data?.data?.userLevel?.parentLevelId == 761
expires: 1, // ) {
}); // window.location.href = "/in/dashboard";
} else { // Cookies.set("status", "login", {
window.location.href = "/in/dashboard"; // expires: 1,
// router.push('/admin/dashboard'); // });
Cookies.set("status", "login", { // } else {
expires: 1, // window.location.href = "/in/dashboard";
}); // // router.push('/admin/dashboard');
} // Cookies.set("status", "login", {
} else { // expires: 1,
window.location.href = "/"; // });
Cookies.set("status", "login", { // }
expires: 1, // } else {
}); // window.location.href = "/";
} // Cookies.set("status", "login", {
// expires: 1,
// });
// }
} }
} catch (err: any) { } catch (err: any) {
toast.error(err.message || "An unexpected error occurred."); toast.error(err.message || "An unexpected error occurred.");

View File

@ -20,6 +20,7 @@ import Cookies from "js-cookie";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useRouter } from "@/components/navigation"; import { useRouter } from "@/components/navigation";
import { getInfoProfile } from "@/service/auth"; import { getInfoProfile } from "@/service/auth";
import { getCookiesDecrypt } from "@/lib/utils";
type Detail = { type Detail = {
id: number; id: number;
@ -35,10 +36,11 @@ type Detail = {
}; };
const ProfileInfo = () => { const ProfileInfo = () => {
const username = Cookies.get("access_token"); const username = Cookies.get("username");
const fullname = Cookies.get("ufne");
const picture = Cookies.get("profile_picture"); const picture = Cookies.get("profile_picture");
const router = useRouter(); const router = useRouter();
const [detail, setDetail] = useState<Detail>(); // const [detail, setDetail] = useState<Detail>();
const onLogout = () => { const onLogout = () => {
Object.keys(Cookies.get()).forEach((cookieName) => { Object.keys(Cookies.get()).forEach((cookieName) => {
@ -49,28 +51,28 @@ const ProfileInfo = () => {
}; };
useEffect(() => { useEffect(() => {
if (!username) { if (!fullname) {
router.push("/auth"); router.push("/auth");
} }
}, [username]); }, [fullname]);
useEffect(() => { // useEffect(() => {
async function initState() { // async function initState() {
const response = await getInfoProfile(); // const response = await getInfoProfile();
const details = response?.data?.data; // const details = response?.data?.data;
setDetail(details); // setDetail(details);
console.log("data", details); // console.log("data", details);
} // }
initState(); // initState();
}, []); // }, []);
return ( return (
<div className="md:block hidden"> <div className="md:block hidden">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild className=" cursor-pointer"> <DropdownMenuTrigger asChild className=" cursor-pointer">
{detail !== undefined ? ( {/* {detail !== undefined ? ( */}
<div className="flex items-center gap-3 text-default-800"> <div className="flex items-center gap-3 text-default-800">
<Image <Image
src={"/avatar-profile.png"} src={"/avatar-profile.png"}
@ -81,17 +83,17 @@ const ProfileInfo = () => {
/> />
<div> <div>
<div className="text-sm font-medium capitalize lg:block hidden"> <div className="text-sm font-medium capitalize lg:block hidden">
{detail?.fullname} {fullname}
</div> </div>
<p className="text-xs">({detail?.username})</p> <p className="text-xs">({username})</p>
</div> </div>
<span className="text-base me-2.5 lg:inline-block hidden"> <span className="text-base me-2.5 lg:inline-block hidden">
<Icon icon="heroicons-outline:chevron-down"></Icon> <Icon icon="heroicons-outline:chevron-down"></Icon>
</span> </span>
</div> </div>
) : ( {/* ) : (
"" ""
)} )} */}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="w-56 p-0" align="end"> <DropdownMenuContent className="w-56 p-0" align="end">
{/* <DropdownMenuLabel className="flex gap-2 items-center mb-1 p-3"> {/* <DropdownMenuLabel className="flex gap-2 items-center mb-1 p-3">

View File

@ -33,6 +33,7 @@ import {
AUTH_CONSTANTS, AUTH_CONSTANTS,
} from "@/lib/auth-utils"; } from "@/lib/auth-utils";
import { warning } from "@/lib/swal"; import { warning } from "@/lib/swal";
import { setCookiesEncrypt } from "@/lib/utils";
export const useAuth = (): AuthContextType => { export const useAuth = (): AuthContextType => {
const router = useRouter(); const router = useRouter();
@ -154,7 +155,7 @@ export const useAuth = (): AuthContextType => {
Cookies.set("username", profile?.username, { Cookies.set("username", profile?.username, {
expires: 1, expires: 1,
}); });
Cookies.set("urie", profile?.roleId, { setCookiesEncrypt("urie", profile?.userRoleId, {
expires: 1, expires: 1,
}); });
Cookies.set("roleName", profile?.roleName, { Cookies.set("roleName", profile?.roleName, {

View File

@ -42,7 +42,7 @@ export const setProfileCookies = (profile: ProfileData): void => {
Cookies.set("state-prov", profile.userLevel?.province?.provName || "", { expires: 1 }); Cookies.set("state-prov", profile.userLevel?.province?.provName || "", { expires: 1 });
setCookiesEncrypt("uie", profile.id, { expires: 1 }); setCookiesEncrypt("uie", profile.id, { expires: 1 });
setCookiesEncrypt("urie", profile.roleId.toString(), { expires: 1 }); setCookiesEncrypt("urie", profile.userRoleId.toString(), { expires: 1 });
setCookiesEncrypt("urne", profile.role?.name || "", { expires: 1 }); setCookiesEncrypt("urne", profile.role?.name || "", { expires: 1 });
setCookiesEncrypt("ulie", profile.userLevel?.id.toString() || "", { expires: 1 }); setCookiesEncrypt("ulie", profile.userLevel?.id.toString() || "", { expires: 1 });
setCookiesEncrypt("uplie", profile.userLevel?.parentLevelId?.toString() || "", { expires: 1 }); setCookiesEncrypt("uplie", profile.userLevel?.parentLevelId?.toString() || "", { expires: 1 });

View File

@ -53,6 +53,7 @@ export interface ProfileData {
fullname: string; fullname: string;
email: string; email: string;
roleId: number; roleId: number;
userRoleId:number;
role: { role: {
name: string; name: string;
}; };
@ -169,4 +170,5 @@ export interface AuthCookies {
ulnae: string; // user level name encrypted ulnae: string; // user level name encrypted
uinse: string; // user institute id encrypted uinse: string; // user institute id encrypted
status: string; status: string;
username: string;
} }