260218:1712 20260218 TASK-BEFE-001n
All checks were successful
Build and Deploy / deploy (push) Successful in 4m55s
All checks were successful
Build and Deploy / deploy (push) Successful in 4m55s
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"use client";
|
||||
|
||||
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
|
||||
import { masterDataService } from "@/lib/services/master-data.service";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
export default function CorrespondenceTypesPage() {
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "typeCode",
|
||||
header: "Code",
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono font-bold">{row.getValue("typeCode")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "typeName",
|
||||
header: "Name",
|
||||
},
|
||||
{
|
||||
accessorKey: "sortOrder",
|
||||
header: "Sort Order",
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => (
|
||||
<span
|
||||
className={`px-2 py-1 rounded-full text-xs ${
|
||||
row.getValue("isActive")
|
||||
? "bg-green-100 text-green-800"
|
||||
: "bg-red-100 text-red-800"
|
||||
}`}
|
||||
>
|
||||
{row.getValue("isActive") ? "Active" : "Inactive"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<GenericCrudTable
|
||||
entityName="Correspondence Type"
|
||||
title="Correspondence Types Management"
|
||||
description="Manage global correspondence types (e.g., LETTER, TRANSMITTAL)"
|
||||
queryKey={["correspondence-types"]}
|
||||
fetchFn={() => masterDataService.getCorrespondenceTypes()}
|
||||
createFn={(data) => masterDataService.createCorrespondenceType(data)}
|
||||
updateFn={(id, data) => masterDataService.updateCorrespondenceType(id, data)}
|
||||
deleteFn={(id) => masterDataService.deleteCorrespondenceType(id)}
|
||||
columns={columns}
|
||||
fields={[
|
||||
{ name: "typeCode", label: "Code", type: "text", required: true },
|
||||
{ name: "typeName", label: "Name", type: "text", required: true },
|
||||
{ name: "sortOrder", label: "Sort Order", type: "text" },
|
||||
{ name: "isActive", label: "Active", type: "checkbox" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
"use client";
|
||||
|
||||
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
|
||||
import { masterDataService } from "@/lib/services/master-data.service";
|
||||
import { contractService } from "@/lib/services/contract.service";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
export default function DisciplinesPage() {
|
||||
const [contracts, setContracts] = useState<any[]>([]);
|
||||
const [selectedContractId, setSelectedContractId] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch contracts for filter and form options
|
||||
contractService.getAll().then((data) => {
|
||||
setContracts(Array.isArray(data) ? data : []);
|
||||
}).catch(err => {
|
||||
console.error("Failed to load contracts:", err);
|
||||
setContracts([]);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "disciplineCode",
|
||||
header: "Code",
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono font-bold">
|
||||
{row.getValue("disciplineCode")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "codeNameTh",
|
||||
header: "Name (TH)",
|
||||
},
|
||||
{
|
||||
accessorKey: "codeNameEn",
|
||||
header: "Name (EN)",
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => (
|
||||
<span
|
||||
className={`px-2 py-1 rounded-full text-xs ${
|
||||
row.getValue("isActive")
|
||||
? "bg-green-100 text-green-800"
|
||||
: "bg-red-100 text-red-800"
|
||||
}`}
|
||||
>
|
||||
{row.getValue("isActive") ? "Active" : "Inactive"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const contractOptions = contracts.map((c) => ({
|
||||
label: `${c.contractName} (${c.contractNo})`,
|
||||
value: c.id,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<GenericCrudTable
|
||||
entityName="Discipline"
|
||||
title="Disciplines Management"
|
||||
description="Manage system disciplines (e.g., ARCH, STR, MEC)"
|
||||
queryKey={["disciplines", selectedContractId ?? "all"]}
|
||||
fetchFn={() =>
|
||||
masterDataService.getDisciplines(
|
||||
selectedContractId ? parseInt(selectedContractId) : undefined
|
||||
)
|
||||
}
|
||||
createFn={(data) => masterDataService.createDiscipline(data)}
|
||||
updateFn={(id, data) => Promise.reject("Not implemented yet")} // Update endpoint needs to be verified/added if missing
|
||||
deleteFn={(id) => masterDataService.deleteDiscipline(id)}
|
||||
columns={columns}
|
||||
filters={
|
||||
<div className="w-[300px]">
|
||||
<Select
|
||||
value={selectedContractId || "all"}
|
||||
onValueChange={(val) =>
|
||||
setSelectedContractId(val === "all" ? null : val)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Filter by Contract" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Contracts</SelectItem>
|
||||
{contracts.map((c) => (
|
||||
<SelectItem key={c.id} value={c.id.toString()}>
|
||||
{c.contractName} ({c.contractNo})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
}
|
||||
fields={[
|
||||
{
|
||||
name: "contractId",
|
||||
label: "Contract",
|
||||
type: "select",
|
||||
required: true,
|
||||
options: contractOptions,
|
||||
},
|
||||
{
|
||||
name: "disciplineCode",
|
||||
label: "Code",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "codeNameTh",
|
||||
label: "Name (TH)",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{ name: "codeNameEn", label: "Name (EN)", type: "text" },
|
||||
{ name: "isActive", label: "Active", type: "checkbox" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
|
||||
import { masterDataService } from "@/lib/services/master-data.service";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
export default function DrawingCategoriesPage() {
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "subTypeCode",
|
||||
header: "Code",
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono font-bold">{row.getValue("subTypeCode")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "subTypeName",
|
||||
header: "Name",
|
||||
},
|
||||
{
|
||||
accessorKey: "subTypeNumber",
|
||||
header: "Running Code",
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono">{row.getValue("subTypeNumber") || "-"}</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<GenericCrudTable
|
||||
entityName="Drawing Category (Sub-Type)"
|
||||
title="Drawing Categories Management"
|
||||
description="Manage drawing sub-types and categories"
|
||||
queryKey={["drawing-categories"]}
|
||||
fetchFn={() => masterDataService.getSubTypes(1)} // Default contract ID 1
|
||||
createFn={(data) => masterDataService.createSubType({ ...data, contractId: 1, correspondenceTypeId: 3 })} // Assuming 3 is Drawings, hardcoded for now to prevent error
|
||||
updateFn={() => Promise.reject("Not implemented yet")}
|
||||
deleteFn={() => Promise.reject("Not implemented yet")} // Delete might be restricted
|
||||
columns={columns}
|
||||
fields={[
|
||||
{ name: "subTypeCode", label: "Code", type: "text", required: true },
|
||||
{ name: "subTypeName", label: "Name", type: "text", required: true },
|
||||
{ name: "subTypeNumber", label: "Running Code", type: "text" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
63
frontend/app/(admin)/admin/doc-control/reference/page.tsx
Normal file
63
frontend/app/(admin)/admin/doc-control/reference/page.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { BookOpen, Tag, Settings, Layers } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
const refMenu = [
|
||||
{
|
||||
title: "Disciplines",
|
||||
description: "Manage system-wide disciplines (e.g., ARCH, STR)",
|
||||
href: "/admin/reference/disciplines",
|
||||
icon: Layers,
|
||||
},
|
||||
{
|
||||
title: "RFA Types",
|
||||
description: "Manage RFA types and approve codes",
|
||||
href: "/admin/reference/rfa-types",
|
||||
icon: BookOpen,
|
||||
},
|
||||
{
|
||||
title: "Correspondence Types",
|
||||
description: "Manage generic correspondence types",
|
||||
href: "/admin/reference/correspondence-types",
|
||||
icon: Settings,
|
||||
},
|
||||
{
|
||||
title: "Tags",
|
||||
description: "Manage system tags for documents",
|
||||
href: "/admin/reference/tags",
|
||||
icon: Tag,
|
||||
},
|
||||
{
|
||||
title: "Drawing Categories",
|
||||
description: "Manage drawing sub-types and classifications",
|
||||
href: "/admin/reference/drawing-categories",
|
||||
icon: Layers,
|
||||
},
|
||||
];
|
||||
|
||||
export default function ReferenceDataPage() {
|
||||
return (
|
||||
<div className="p-6 space-y-6">
|
||||
<h1 className="text-2xl font-bold">Reference Data Management</h1>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{refMenu.map((item) => (
|
||||
<Link key={item.href} href={item.href}>
|
||||
<Card className="hover:shadow-md transition-shadow cursor-pointer h-full">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">
|
||||
{item.title}
|
||||
</CardTitle>
|
||||
<item.icon className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{item.description}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
"use client";
|
||||
|
||||
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
|
||||
import { masterDataService } from "@/lib/services/master-data.service";
|
||||
import { contractService } from "@/lib/services/contract.service";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
export default function RfaTypesPage() {
|
||||
const [contracts, setContracts] = useState<any[]>([]);
|
||||
const [selectedContractId, setSelectedContractId] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch contracts for filter and form options
|
||||
contractService.getAll().then((data) => {
|
||||
setContracts(Array.isArray(data) ? data : []);
|
||||
}).catch(err => {
|
||||
console.error("Failed to load contracts:", err);
|
||||
setContracts([]);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "typeCode",
|
||||
header: "Code",
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono font-bold">{row.getValue("typeCode")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "typeNameTh",
|
||||
header: "Name (TH)",
|
||||
},
|
||||
{
|
||||
accessorKey: "typeNameEn",
|
||||
header: "Name (EN)",
|
||||
},
|
||||
{
|
||||
accessorKey: "remark",
|
||||
header: "Remark",
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => (
|
||||
<span
|
||||
className={`px-2 py-1 rounded-full text-xs ${
|
||||
row.getValue("isActive")
|
||||
? "bg-green-100 text-green-800"
|
||||
: "bg-red-100 text-red-800"
|
||||
}`}
|
||||
>
|
||||
{row.getValue("isActive") ? "Active" : "Inactive"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const contractOptions = contracts.map((c) => ({
|
||||
label: `${c.contractName} (${c.contractNo})`,
|
||||
value: c.id,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<GenericCrudTable
|
||||
entityName="RFA Type"
|
||||
title="RFA Types Management"
|
||||
queryKey={["rfa-types", selectedContractId ?? "all"]}
|
||||
fetchFn={() =>
|
||||
masterDataService.getRfaTypes(
|
||||
selectedContractId ? parseInt(selectedContractId) : undefined
|
||||
)
|
||||
}
|
||||
createFn={(data) => masterDataService.createRfaType(data)}
|
||||
updateFn={(id, data) => masterDataService.updateRfaType(id, data)}
|
||||
deleteFn={(id) => masterDataService.deleteRfaType(id)}
|
||||
columns={columns}
|
||||
filters={
|
||||
<div className="w-[300px]">
|
||||
<Select
|
||||
value={selectedContractId || "all"}
|
||||
onValueChange={(val) =>
|
||||
setSelectedContractId(val === "all" ? null : val)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Filter by Contract" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Contracts</SelectItem>
|
||||
{contracts.map((c) => (
|
||||
<SelectItem key={c.id} value={c.id.toString()}>
|
||||
{c.contractName} ({c.contractNo})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
}
|
||||
fields={[
|
||||
{
|
||||
name: "contractId",
|
||||
label: "Contract",
|
||||
type: "select",
|
||||
required: true,
|
||||
options: contractOptions,
|
||||
},
|
||||
{ name: "typeCode", label: "Code", type: "text", required: true },
|
||||
{ name: "typeNameTh", label: "Name (TH)", type: "text", required: true },
|
||||
{ name: "typeNameEn", label: "Name (EN)", type: "text" },
|
||||
{ name: "remark", label: "Remark", type: "textarea" },
|
||||
{ name: "isActive", label: "Active", type: "checkbox" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
|
||||
import { masterDataService } from "@/lib/services/master-data.service";
|
||||
import { CreateTagDto } from "@/types/dto/master/tag.dto";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
export default function TagsPage() {
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "tag_name",
|
||||
header: "Tag Name",
|
||||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: "Description",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<GenericCrudTable
|
||||
title="Tags"
|
||||
description="Manage system tags."
|
||||
entityName="Tag"
|
||||
queryKey={["tags"]}
|
||||
fetchFn={() => masterDataService.getTags()}
|
||||
createFn={(data: CreateTagDto) => masterDataService.createTag(data)}
|
||||
updateFn={(id, data) => masterDataService.updateTag(id, data)}
|
||||
deleteFn={(id) => masterDataService.deleteTag(id)}
|
||||
columns={columns}
|
||||
fields={[
|
||||
{
|
||||
name: "tag_name",
|
||||
label: "Tag Name",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
label: "Description",
|
||||
type: "textarea",
|
||||
required: false,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user