fix: errors build
This commit is contained in:
parent
ebed666eba
commit
292c2496b3
|
|
@ -2,7 +2,13 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { PlusIcon, ModuleIcon, EditIcon, DeleteIcon } from "@/components/icons";
|
||||
import {
|
||||
MasterModule,
|
||||
|
|
@ -50,11 +56,11 @@ export default function ModulesSettingsPage() {
|
|||
if (module) {
|
||||
setEditingModule(module);
|
||||
setFormData({
|
||||
name: module.name,
|
||||
description: module.description,
|
||||
pathUrl: module.pathUrl,
|
||||
actionType: module.actionType,
|
||||
statusId: module.statusId,
|
||||
name: module.name ?? "",
|
||||
description: module.description ?? "",
|
||||
pathUrl: module.pathUrl ?? "",
|
||||
actionType: module.actionType ?? "",
|
||||
statusId: module.statusId ?? 1,
|
||||
});
|
||||
} else {
|
||||
setEditingModule(null);
|
||||
|
|
@ -80,8 +86,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
|
|
@ -90,8 +96,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
await loadData();
|
||||
setIsDialogOpen(false);
|
||||
|
|
@ -105,8 +111,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
|
|
@ -115,8 +121,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
await loadData();
|
||||
setIsDialogOpen(false);
|
||||
|
|
@ -130,8 +136,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -145,8 +151,8 @@ export default function ModulesSettingsPage() {
|
|||
confirmButtonText: "Yes, delete it",
|
||||
cancelButtonText: "Cancel",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
|
|
@ -159,8 +165,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
|
|
@ -169,8 +175,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
await loadData();
|
||||
}
|
||||
|
|
@ -182,8 +188,8 @@ export default function ModulesSettingsPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -195,14 +201,19 @@ export default function ModulesSettingsPage() {
|
|||
<div className="container mx-auto p-6 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">Modules Settings</h1>
|
||||
<h1 className="text-3xl font-bold text-gray-900">
|
||||
Modules Settings
|
||||
</h1>
|
||||
<p className="text-gray-600 mt-2">
|
||||
Manage system modules and their configurations
|
||||
</p>
|
||||
</div>
|
||||
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button className="flex items-center gap-2" onClick={() => handleOpenDialog()}>
|
||||
<Button
|
||||
className="flex items-center gap-2"
|
||||
onClick={() => handleOpenDialog()}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Create Module
|
||||
</Button>
|
||||
|
|
@ -210,7 +221,9 @@ export default function ModulesSettingsPage() {
|
|||
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{editingModule ? `Edit Module: ${editingModule.name}` : "Create New Module"}
|
||||
{editingModule
|
||||
? `Edit Module: ${editingModule.name}`
|
||||
: "Create New Module"}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
|
|
@ -220,7 +233,9 @@ export default function ModulesSettingsPage() {
|
|||
type="text"
|
||||
placeholder="e.g., View Articles, Create Content"
|
||||
value={formData.name}
|
||||
onChange={(value) => setFormData({ ...formData, name: value })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, name: value })
|
||||
}
|
||||
required
|
||||
/>
|
||||
<FormField
|
||||
|
|
@ -229,7 +244,9 @@ export default function ModulesSettingsPage() {
|
|||
type="text"
|
||||
placeholder="Brief description of the module"
|
||||
value={formData.description}
|
||||
onChange={(value) => setFormData({ ...formData, description: value })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, description: value })
|
||||
}
|
||||
required
|
||||
/>
|
||||
<FormField
|
||||
|
|
@ -238,7 +255,9 @@ export default function ModulesSettingsPage() {
|
|||
type="text"
|
||||
placeholder="e.g., /api/articles, /api/content"
|
||||
value={formData.pathUrl}
|
||||
onChange={(value) => setFormData({ ...formData, pathUrl: value })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, pathUrl: value })
|
||||
}
|
||||
required
|
||||
/>
|
||||
<FormField
|
||||
|
|
@ -247,7 +266,9 @@ export default function ModulesSettingsPage() {
|
|||
type="select"
|
||||
placeholder="Select action type"
|
||||
value={formData.actionType}
|
||||
onChange={(value) => setFormData({ ...formData, actionType: value })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, actionType: value })
|
||||
}
|
||||
options={[
|
||||
{ value: "view", label: "View" },
|
||||
{ value: "create", label: "Create" },
|
||||
|
|
@ -264,7 +285,9 @@ export default function ModulesSettingsPage() {
|
|||
type="number"
|
||||
placeholder="1"
|
||||
value={formData.statusId}
|
||||
onChange={(value) => setFormData({ ...formData, statusId: Number(value) || 1 })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, statusId: Number(value) || 1 })
|
||||
}
|
||||
required
|
||||
/>
|
||||
<div className="flex items-center justify-end gap-2 pt-4 border-t">
|
||||
|
|
@ -291,7 +314,10 @@ export default function ModulesSettingsPage() {
|
|||
) : modules.length > 0 ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{modules.map((module) => (
|
||||
<Card key={module.id} className="hover:shadow-lg transition-shadow">
|
||||
<Card
|
||||
key={module.id}
|
||||
className="hover:shadow-lg transition-shadow"
|
||||
>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center justify-between">
|
||||
<span className="truncate">{module.name}</span>
|
||||
|
|
@ -308,7 +334,9 @@ export default function ModulesSettingsPage() {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2 mb-4">
|
||||
<div className="text-sm text-gray-600">{module.description}</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
{module.description}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 font-mono bg-gray-50 p-2 rounded">
|
||||
{module.pathUrl}
|
||||
</div>
|
||||
|
|
@ -347,7 +375,9 @@ export default function ModulesSettingsPage() {
|
|||
<CardContent className="flex items-center justify-center py-12">
|
||||
<div className="text-center">
|
||||
<ModuleIcon className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-2">No Modules Found</h3>
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||
No Modules Found
|
||||
</h3>
|
||||
<p className="text-gray-500 mb-4">
|
||||
Create your first module to define system capabilities
|
||||
</p>
|
||||
|
|
@ -363,4 +393,3 @@ export default function ModulesSettingsPage() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -881,7 +881,7 @@ function TenantSettingsContentTable() {
|
|||
<UserLevelsForm
|
||||
mode="single"
|
||||
initialData={{
|
||||
id: editingUserLevel.id,
|
||||
// id: editingUserLevel.id,
|
||||
name: editingUserLevel.name,
|
||||
aliasName: editingUserLevel.aliasName,
|
||||
levelNumber: editingUserLevel.levelNumber,
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ function TenantSettingsContent() {
|
|||
<UserLevelsForm
|
||||
mode="single"
|
||||
initialData={editingUserLevel ? {
|
||||
id: editingUserLevel.id,
|
||||
// id: editingUserLevel.id,
|
||||
name: editingUserLevel.name,
|
||||
aliasName: editingUserLevel.aliasName,
|
||||
levelNumber: editingUserLevel.levelNumber,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,13 @@ import { useRouter, useParams } from "next/navigation";
|
|||
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 { ChevronLeftIcon, SaveIcon, SettingsIcon, UsersIcon, WorkflowIcon } from "@/components/icons";
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
SaveIcon,
|
||||
SettingsIcon,
|
||||
UsersIcon,
|
||||
WorkflowIcon,
|
||||
} from "@/components/icons";
|
||||
import {
|
||||
Tenant,
|
||||
TenantUpdateRequest,
|
||||
|
|
@ -47,7 +53,13 @@ import {
|
|||
} from "@tanstack/react-table";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import useTableColumns from "@/app/[locale]/(admin)/admin/settings/tenant/component/columns";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { PlusIcon, EditIcon, DeleteIcon } from "@/components/icons";
|
||||
import { errorAutoClose, successAutoClose } from "@/lib/swal";
|
||||
import { close, loading } from "@/config/swal";
|
||||
|
|
@ -56,6 +68,8 @@ export default function EditTenantPage() {
|
|||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const tenantId = params?.id as string;
|
||||
const [totalData, setTotalData] = useState<number>(0);
|
||||
const [totalPage, setTotalPage] = useState<number>(1);
|
||||
|
||||
const [tenant, setTenant] = useState<Tenant | null>(null);
|
||||
const [parentTenants, setParentTenants] = useState<Tenant[]>([]);
|
||||
|
|
@ -64,13 +78,16 @@ export default function EditTenantPage() {
|
|||
const [activeTab, setActiveTab] = useState("profile");
|
||||
|
||||
// Workflow state
|
||||
const [workflow, setWorkflow] = useState<ComprehensiveWorkflowResponse | null>(null);
|
||||
const [workflow, setWorkflow] =
|
||||
useState<ComprehensiveWorkflowResponse | null>(null);
|
||||
const [isEditingWorkflow, setIsEditingWorkflow] = useState(false);
|
||||
|
||||
// User Levels state
|
||||
const [userLevels, setUserLevels] = useState<UserLevel[]>([]);
|
||||
const [isUserLevelDialogOpen, setIsUserLevelDialogOpen] = useState(false);
|
||||
const [editingUserLevel, setEditingUserLevel] = useState<UserLevel | null>(null);
|
||||
const [editingUserLevel, setEditingUserLevel] = useState<UserLevel | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
// Tenant form data
|
||||
const [formData, setFormData] = useState<TenantUpdateRequest>({
|
||||
|
|
@ -96,8 +113,8 @@ export default function EditTenantPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
}).then(() => {
|
||||
router.push("/admin/dashboard");
|
||||
});
|
||||
|
|
@ -132,8 +149,8 @@ export default function EditTenantPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
}).then(() => {
|
||||
router.push("/admin/tenants");
|
||||
});
|
||||
|
|
@ -154,7 +171,8 @@ export default function EditTenantPage() {
|
|||
address: tenantData.address || "",
|
||||
phoneNumber: tenantData.phoneNumber || "",
|
||||
website: tenantData.website || "",
|
||||
isActive: tenantData.isActive !== undefined ? tenantData.isActive : true,
|
||||
isActive:
|
||||
tenantData.isActive !== undefined ? tenantData.isActive : true,
|
||||
logoUrl: tenantData.logoUrl || undefined,
|
||||
logoImagePath: tenantData.logoImagePath || undefined,
|
||||
});
|
||||
|
|
@ -173,8 +191,8 @@ export default function EditTenantPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
}).then(() => {
|
||||
router.push("/admin/tenants");
|
||||
});
|
||||
|
|
@ -195,6 +213,15 @@ export default function EditTenantPage() {
|
|||
} else {
|
||||
setWorkflow(null);
|
||||
}
|
||||
if (!userLevelsRes?.error) {
|
||||
const data = userLevelsRes?.data?.data || [];
|
||||
|
||||
setUserLevels(data);
|
||||
setTotalData(data.length);
|
||||
|
||||
const pageSize = pagination.pageSize;
|
||||
setTotalPage(Math.max(1, Math.ceil(data.length / pageSize)));
|
||||
}
|
||||
|
||||
if (!userLevelsRes?.error) {
|
||||
setUserLevels(userLevelsRes?.data?.data || []);
|
||||
|
|
@ -230,8 +257,8 @@ export default function EditTenantPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
|
|
@ -240,8 +267,8 @@ export default function EditTenantPage() {
|
|||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
await loadData();
|
||||
}
|
||||
|
|
@ -253,15 +280,17 @@ export default function EditTenantPage() {
|
|||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleWorkflowSave = async (data: CreateApprovalWorkflowWithClientSettingsRequest) => {
|
||||
const handleWorkflowSave = async (
|
||||
data: CreateApprovalWorkflowWithClientSettingsRequest,
|
||||
) => {
|
||||
setIsEditingWorkflow(false);
|
||||
await loadWorkflowAndUserLevels();
|
||||
};
|
||||
|
|
@ -304,8 +333,8 @@ export default function EditTenantPage() {
|
|||
confirmButtonText: "Yes, delete it",
|
||||
cancelButtonText: "Cancel",
|
||||
customClass: {
|
||||
popup: 'swal-z-index-9999'
|
||||
}
|
||||
popup: "swal-z-index-9999",
|
||||
},
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
|
|
@ -321,7 +350,7 @@ export default function EditTenantPage() {
|
|||
|
||||
const columns = React.useMemo(
|
||||
() => useTableColumns((data) => handleEditUserLevel(data)),
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
|
|
@ -379,7 +408,9 @@ export default function EditTenantPage() {
|
|||
Back
|
||||
</Button>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">Edit Tenant: {tenant.name}</h1>
|
||||
<h1 className="text-3xl font-bold text-gray-900">
|
||||
Edit Tenant: {tenant.name}
|
||||
</h1>
|
||||
<p className="text-gray-600 mt-2">
|
||||
Manage tenant information, workflows, and user levels
|
||||
</p>
|
||||
|
|
@ -397,7 +428,10 @@ export default function EditTenantPage() {
|
|||
<WorkflowIcon className="h-4 w-4" />
|
||||
Approval Workflows
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="user-levels" className="flex items-center gap-2">
|
||||
<TabsTrigger
|
||||
value="user-levels"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<UsersIcon className="h-4 w-4" />
|
||||
User Levels
|
||||
</TabsTrigger>
|
||||
|
|
@ -416,7 +450,9 @@ export default function EditTenantPage() {
|
|||
type="text"
|
||||
placeholder="e.g., Company ABC, Organization XYZ"
|
||||
value={formData.name}
|
||||
onChange={(value) => setFormData({ ...formData, name: value })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, name: value })
|
||||
}
|
||||
required
|
||||
/>
|
||||
<FormField
|
||||
|
|
@ -425,7 +461,12 @@ export default function EditTenantPage() {
|
|||
type="textarea"
|
||||
placeholder="Brief description of the tenant"
|
||||
value={formData.description || ""}
|
||||
onChange={(value) => setFormData({ ...formData, description: value || undefined })}
|
||||
onChange={(value) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
description: value || undefined,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<FormField
|
||||
label="Client Type"
|
||||
|
|
@ -433,7 +474,9 @@ export default function EditTenantPage() {
|
|||
type="select"
|
||||
placeholder="Select client type"
|
||||
value={formData.clientType}
|
||||
onChange={(value) => setFormData({ ...formData, clientType: value as any })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, clientType: value as any })
|
||||
}
|
||||
options={[
|
||||
{ value: "standalone", label: "Standalone" },
|
||||
{ value: "parent_client", label: "Parent Client" },
|
||||
|
|
@ -448,7 +491,12 @@ export default function EditTenantPage() {
|
|||
type="select"
|
||||
placeholder="Select parent tenant"
|
||||
value={formData.parentClientId || "none"}
|
||||
onChange={(value) => setFormData({ ...formData, parentClientId: value === "none" ? undefined : value })}
|
||||
onChange={(value) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
parentClientId: value === "none" ? undefined : value,
|
||||
})
|
||||
}
|
||||
options={[
|
||||
{ value: "none", label: "No Parent Tenant" },
|
||||
...parentTenants
|
||||
|
|
@ -468,7 +516,12 @@ export default function EditTenantPage() {
|
|||
type="number"
|
||||
placeholder="e.g., 100"
|
||||
value={formData.maxUsers?.toString() || ""}
|
||||
onChange={(value) => setFormData({ ...formData, maxUsers: value ? Number(value) : undefined })}
|
||||
onChange={(value) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
maxUsers: value ? Number(value) : undefined,
|
||||
})
|
||||
}
|
||||
helpText="Maximum number of users allowed"
|
||||
/>
|
||||
<FormField
|
||||
|
|
@ -477,7 +530,12 @@ export default function EditTenantPage() {
|
|||
type="number"
|
||||
placeholder="e.g., 10000"
|
||||
value={formData.maxStorage?.toString() || ""}
|
||||
onChange={(value) => setFormData({ ...formData, maxStorage: value ? Number(value) : undefined })}
|
||||
onChange={(value) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
maxStorage: value ? Number(value) : undefined,
|
||||
})
|
||||
}
|
||||
helpText="Maximum storage in MB"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -487,7 +545,9 @@ export default function EditTenantPage() {
|
|||
type="textarea"
|
||||
placeholder="Tenant address"
|
||||
value={formData.address || ""}
|
||||
onChange={(value) => setFormData({ ...formData, address: value || undefined })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, address: value || undefined })
|
||||
}
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormField
|
||||
|
|
@ -496,7 +556,12 @@ export default function EditTenantPage() {
|
|||
type="tel"
|
||||
placeholder="e.g., +62 123 456 7890"
|
||||
value={formData.phoneNumber || ""}
|
||||
onChange={(value) => setFormData({ ...formData, phoneNumber: value || undefined })}
|
||||
onChange={(value) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
phoneNumber: value || undefined,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<FormField
|
||||
label="Website"
|
||||
|
|
@ -504,7 +569,9 @@ export default function EditTenantPage() {
|
|||
type="url"
|
||||
placeholder="e.g., https://example.com"
|
||||
value={formData.website || ""}
|
||||
onChange={(value) => setFormData({ ...formData, website: value || undefined })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, website: value || undefined })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<FormField
|
||||
|
|
@ -513,7 +580,9 @@ export default function EditTenantPage() {
|
|||
type="select"
|
||||
placeholder="Select status"
|
||||
value={formData.isActive ? "active" : "inactive"}
|
||||
onChange={(value) => setFormData({ ...formData, isActive: value === "active" })}
|
||||
onChange={(value) =>
|
||||
setFormData({ ...formData, isActive: value === "active" })
|
||||
}
|
||||
options={[
|
||||
{ value: "active", label: "Active" },
|
||||
{ value: "inactive", label: "Inactive" },
|
||||
|
|
@ -537,7 +606,9 @@ export default function EditTenantPage() {
|
|||
{/* Approval Workflows Tab */}
|
||||
<TabsContent value="workflows" className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-semibold">Approval Workflow Setup</h2>
|
||||
<h2 className="text-2xl font-semibold">
|
||||
Approval Workflow Setup
|
||||
</h2>
|
||||
{workflow && !isEditingWorkflow && (
|
||||
<Button
|
||||
onClick={() => setIsEditingWorkflow(true)}
|
||||
|
|
@ -571,7 +642,8 @@ export default function EditTenantPage() {
|
|||
description: workflow.workflow.description,
|
||||
isDefault: workflow.workflow.isDefault,
|
||||
isActive: workflow.workflow.isActive,
|
||||
requiresApproval: workflow.workflow.requiresApproval,
|
||||
requiresApproval:
|
||||
workflow.workflow.requiresApproval,
|
||||
autoPublish: workflow.workflow.autoPublish,
|
||||
steps:
|
||||
workflow.steps?.map((step) => ({
|
||||
|
|
@ -579,23 +651,28 @@ export default function EditTenantPage() {
|
|||
stepName: step.stepName,
|
||||
requiredUserLevelId: step.requiredUserLevelId,
|
||||
canSkip: step.canSkip,
|
||||
autoApproveAfterHours: step.autoApproveAfterHours,
|
||||
autoApproveAfterHours:
|
||||
step.autoApproveAfterHours,
|
||||
isActive: step.isActive,
|
||||
conditionType: step.conditionType,
|
||||
conditionValue: step.conditionValue,
|
||||
})) || [],
|
||||
clientApprovalSettings: {
|
||||
approvalExemptCategories:
|
||||
workflow.clientSettings.exemptCategoriesDetails || [],
|
||||
workflow.clientSettings
|
||||
.exemptCategoriesDetails || [],
|
||||
approvalExemptRoles:
|
||||
workflow.clientSettings.exemptRolesDetails || [],
|
||||
workflow.clientSettings.exemptRolesDetails ||
|
||||
[],
|
||||
approvalExemptUsers:
|
||||
workflow.clientSettings.exemptUsersDetails || [],
|
||||
workflow.clientSettings.exemptUsersDetails ||
|
||||
[],
|
||||
autoPublishArticles:
|
||||
workflow.clientSettings.autoPublishArticles,
|
||||
isActive: workflow.clientSettings.isActive,
|
||||
requireApprovalFor:
|
||||
workflow.clientSettings.requireApprovalFor || [],
|
||||
workflow.clientSettings.requireApprovalFor ||
|
||||
[],
|
||||
requiresApproval:
|
||||
workflow.clientSettings.requiresApproval,
|
||||
skipApprovalFor:
|
||||
|
|
@ -639,38 +716,55 @@ export default function EditTenantPage() {
|
|||
</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-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-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
|
||||
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 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
|
||||
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 && workflow.steps.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-lg font-medium mb-3">Workflow Steps</h4>
|
||||
<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
|
||||
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="font-medium">
|
||||
{step.stepName}
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
Required Level: {step.requiredUserLevelName}
|
||||
</div>
|
||||
|
|
@ -697,7 +791,9 @@ export default function EditTenantPage() {
|
|||
<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 Found</h3>
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||
No Workflow Found
|
||||
</h3>
|
||||
<p className="text-gray-500 mb-4">
|
||||
No approval workflow has been set up for this tenant yet.
|
||||
</p>
|
||||
|
|
@ -715,12 +811,18 @@ export default function EditTenantPage() {
|
|||
<TabsContent value="user-levels" className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-semibold">User Levels Management</h2>
|
||||
<Dialog open={isUserLevelDialogOpen} onOpenChange={setIsUserLevelDialogOpen}>
|
||||
<Dialog
|
||||
open={isUserLevelDialogOpen}
|
||||
onOpenChange={setIsUserLevelDialogOpen}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button className="flex items-center gap-2" onClick={() => {
|
||||
<Button
|
||||
className="flex items-center gap-2"
|
||||
onClick={() => {
|
||||
setEditingUserLevel(null);
|
||||
setIsUserLevelDialogOpen(true);
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Create User Level
|
||||
</Button>
|
||||
|
|
@ -728,13 +830,17 @@ export default function EditTenantPage() {
|
|||
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{editingUserLevel ? `Edit User Level: ${editingUserLevel.name}` : "Create New User Level"}
|
||||
{editingUserLevel
|
||||
? `Edit User Level: ${editingUserLevel.name}`
|
||||
: "Create New User Level"}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<UserLevelsForm
|
||||
mode="single"
|
||||
initialData={editingUserLevel ? {
|
||||
id: editingUserLevel.id,
|
||||
initialData={
|
||||
editingUserLevel
|
||||
? {
|
||||
// id: editingUserLevel.id,
|
||||
name: editingUserLevel.name,
|
||||
aliasName: editingUserLevel.aliasName,
|
||||
levelNumber: editingUserLevel.levelNumber,
|
||||
|
|
@ -743,7 +849,9 @@ export default function EditTenantPage() {
|
|||
group: editingUserLevel.group || "",
|
||||
isApprovalActive: editingUserLevel.isApprovalActive,
|
||||
isActive: editingUserLevel.isActive,
|
||||
} : undefined}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onSave={handleUserLevelSave}
|
||||
onCancel={() => {
|
||||
setIsUserLevelDialogOpen(false);
|
||||
|
|
@ -760,17 +868,19 @@ export default function EditTenantPage() {
|
|||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{table.getHeaderGroups().map((headerGroup) =>
|
||||
{table
|
||||
.getHeaderGroups()
|
||||
.map((headerGroup) =>
|
||||
headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
))
|
||||
)),
|
||||
)}
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
|
|
@ -783,7 +893,7 @@ export default function EditTenantPage() {
|
|||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
cell.getContext(),
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
|
|
@ -792,7 +902,9 @@ export default function EditTenantPage() {
|
|||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleEditUserLevel(row.original)}
|
||||
onClick={() =>
|
||||
handleEditUserLevel(row.original)
|
||||
}
|
||||
>
|
||||
<EditIcon className="h-4 w-4 mr-2" />
|
||||
Edit
|
||||
|
|
@ -801,7 +913,9 @@ export default function EditTenantPage() {
|
|||
variant="outline"
|
||||
size="sm"
|
||||
className="text-red-600 hover:text-red-700 hover:bg-red-50"
|
||||
onClick={() => handleDeleteUserLevel(row.original)}
|
||||
onClick={() =>
|
||||
handleDeleteUserLevel(row.original)
|
||||
}
|
||||
>
|
||||
<DeleteIcon className="h-4 w-4 mr-2" />
|
||||
Delete
|
||||
|
|
@ -823,7 +937,11 @@ export default function EditTenantPage() {
|
|||
</TableBody>
|
||||
</Table>
|
||||
<div className="p-4">
|
||||
<TablePagination table={table} />
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -832,14 +950,18 @@ export default function EditTenantPage() {
|
|||
<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>
|
||||
<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 user hierarchy
|
||||
</p>
|
||||
<Button onClick={() => {
|
||||
<Button
|
||||
onClick={() => {
|
||||
setEditingUserLevel(null);
|
||||
setIsUserLevelDialogOpen(true);
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 mr-2" />
|
||||
Create User Level
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,142 @@
|
|||
@import "tailwindcss";
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ================================
|
||||
GLOBAL CSS VARIABLE (LIGHT MODE)
|
||||
================================ */
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--primary: 221.2 83.2% 53.3%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 215.3 19.3% 34.5%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 222.2 84% 4.9%;
|
||||
|
||||
--success: 154 52% 55%;
|
||||
--warning: 16 93% 70%;
|
||||
--info: 185 96% 51%;
|
||||
|
||||
--sidebar: 0 0% 100%;
|
||||
--sidebar-foreground: 215 20% 65%;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
DARK MODE VARIABLES
|
||||
================================ */
|
||||
.dark {
|
||||
--background: 222.2 47.4% 11.2%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--card: 215 27.9% 16.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--primary: 217.2 91.2% 59.8%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 215.3 25% 26.7%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
|
||||
--sidebar: 215 27.9% 16.9%;
|
||||
--sidebar-foreground: 214.3 31.8% 91.4%;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
BASE LAYER
|
||||
================================ */
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================
|
||||
GLOBAL UTILITIES
|
||||
================================ */
|
||||
@layer utilities {
|
||||
/* SweetAlert z-index fix */
|
||||
.swal-z-index-9999 {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
/* Scrollbar hide */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Input group helpers */
|
||||
.input-group :not(:first-child) input {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
.input-group.merged :not(:first-child) input {
|
||||
border-left-width: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.input-group :not(:last-child) input {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
.input-group.merged :not(:last-child) input {
|
||||
border-right-width: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* @import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
/* SweetAlert2 z-index fix */
|
||||
.swal-z-index-9999 {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
|
@ -297,4 +432,4 @@
|
|||
.no-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
} */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -75,6 +75,7 @@
|
|||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"cookie": "^1.0.2",
|
||||
"cookies-next": "^6.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dayjs": "^1.11.11",
|
||||
|
|
@ -142,7 +143,6 @@
|
|||
"devDependencies": {
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@next/bundle-analyzer": "^15.0.3",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
|
|
@ -160,6 +160,7 @@
|
|||
"@types/react-geocode": "^0.2.4",
|
||||
"@types/rtl-detect": "^1.0.3",
|
||||
"@types/sizzle": "^2.3.10",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"cross-env": "^7.0.3",
|
||||
"d3-shape": "^3.2.0",
|
||||
"eslint": "^8",
|
||||
|
|
@ -167,7 +168,7 @@
|
|||
"jest": "^30.0.4",
|
||||
"jest-environment-jsdom": "^30.0.4",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^4",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"tw-animate-css": "^1.3.5",
|
||||
"typescript": "^5"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,18 @@
|
|||
// /** @type {import('postcss-load-config').Config} */
|
||||
// const config = {
|
||||
// plugins: {
|
||||
// '@tailwindcss/postcss': {},
|
||||
// },
|
||||
// };
|
||||
|
||||
// export default config;
|
||||
|
||||
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue