251210:1709 Frontend: reeactor organization and run build
Some checks failed
Spec Validation / validate-markdown (push) Has been cancelled
Spec Validation / validate-diagrams (push) Has been cancelled
Spec Validation / check-todos (push) Has been cancelled

This commit is contained in:
admin
2025-12-10 17:09:11 +07:00
parent aa96cd90e3
commit c8a0f281ef
140 changed files with 3780 additions and 1473 deletions

View File

@@ -1,33 +1,40 @@
"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";
import apiClient from "@/lib/api/client";
// Service wrapper
const correspondenceTypeService = {
getAll: async () => (await apiClient.get("/master/correspondence-types")).data,
create: async (data: any) => (await apiClient.post("/master/correspondence-types", data)).data,
update: async (id: number, data: any) => (await apiClient.patch(`/master/correspondence-types/${id}`, data)).data,
delete: async (id: number) => (await apiClient.delete(`/master/correspondence-types/${id}`)).data,
};
export default function CorrespondenceTypesPage() {
const columns: ColumnDef<any>[] = [
{
accessorKey: "type_code",
accessorKey: "typeCode",
header: "Code",
cell: ({ row }) => (
<span className="font-mono font-bold">{row.getValue("type_code")}</span>
<span className="font-mono font-bold">{row.getValue("typeCode")}</span>
),
},
{
accessorKey: "type_name_th",
header: "Name (TH)",
accessorKey: "typeName",
header: "Name",
},
{
accessorKey: "type_name_en",
header: "Name (EN)",
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>
),
},
];
@@ -36,16 +43,18 @@ export default function CorrespondenceTypesPage() {
<GenericCrudTable
entityName="Correspondence Type"
title="Correspondence Types Management"
description="Manage global correspondence types (e.g., LETTER, TRANSMITTAL)"
queryKey={["correspondence-types"]}
fetchFn={correspondenceTypeService.getAll}
createFn={correspondenceTypeService.create}
updateFn={correspondenceTypeService.update}
deleteFn={correspondenceTypeService.delete}
fetchFn={() => masterDataService.getCorrespondenceTypes()}
createFn={(data) => masterDataService.createCorrespondenceType(data)}
updateFn={(id, data) => masterDataService.updateCorrespondenceType(id, data)}
deleteFn={(id) => masterDataService.deleteCorrespondenceType(id)}
columns={columns}
fields={[
{ name: "type_code", label: "Code", type: "text", required: true },
{ name: "type_name_th", label: "Name (TH)", type: "text", required: true },
{ name: "type_name_en", label: "Name (EN)", type: "text" },
{ 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>

View File

@@ -2,59 +2,135 @@
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
import { masterDataService } from "@/lib/services/master-data.service";
import { projectService } from "@/lib/services/project.service";
import { ColumnDef } from "@tanstack/react-table";
import { useState, useEffect } from "react";
import apiClient from "@/lib/api/client";
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
// Fetch contracts for filter and form options
projectService.getAllContracts().then((data) => {
setContracts(Array.isArray(data) ? data : []);
}).catch(err => {
console.error("Failed to load contracts:", err);
setContracts([]);
});
}, []);
const columns: ColumnDef<any>[] = [
{
accessorKey: "discipline_code",
accessorKey: "disciplineCode",
header: "Code",
cell: ({ row }) => (
<span className="font-mono font-bold">{row.getValue("discipline_code")}</span>
<span className="font-mono font-bold">
{row.getValue("disciplineCode")}
</span>
),
},
{
accessorKey: "code_name_th",
accessorKey: "codeNameTh",
header: "Name (TH)",
},
{
accessorKey: "code_name_en",
accessorKey: "codeNameEn",
header: "Name (EN)",
},
{
accessorKey: "is_active",
accessorKey: "isActive",
header: "Status",
cell: ({ row }) => (
<span
className={`px-2 py-1 rounded-full text-xs ${
row.getValue("is_active")
row.getValue("isActive")
? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800"
}`}
>
{row.getValue("is_active") ? "Active" : "Inactive"}
{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"]}
fetchFn={() => masterDataService.getDisciplines()} // Assuming generic fetch supports no args for all
createFn={(data) => masterDataService.createDiscipline({ ...data, contractId: 1 })} // Default contract for now
updateFn={(id, data) => Promise.reject("Not implemented yet")} // Update endpoint might need addition
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: "discipline_code", label: "Code", type: "text", required: true },
{ name: "code_name_th", label: "Name (TH)", type: "text", required: true },
{ name: "code_name_en", label: "Name (EN)", type: "text" },
{ name: "is_active", label: "Active", type: "checkbox" },
{
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>

View File

@@ -2,51 +2,127 @@
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
import { masterDataService } from "@/lib/services/master-data.service";
import { projectService } from "@/lib/services/project.service";
import { ColumnDef } from "@tanstack/react-table";
import { useState, useEffect } from "react";
import apiClient from "@/lib/api/client";
// Extending masterDataService locally if needed or using direct API calls for specific RFA types logic
const rfaTypeService = {
getAll: async () => (await apiClient.get("/master/rfa-types")).data,
create: async (data: any) => (await apiClient.post("/master/rfa-types", data)).data, // Endpoint assumption
update: async (id: number, data: any) => (await apiClient.patch(`/master/rfa-types/${id}`, data)).data,
delete: async (id: number) => (await apiClient.delete(`/master/rfa-types/${id}`)).data,
};
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
// Fetch contracts for filter and form options
projectService.getAllContracts().then((data) => {
setContracts(Array.isArray(data) ? data : []);
}).catch(err => {
console.error("Failed to load contracts:", err);
setContracts([]);
});
}, []);
const columns: ColumnDef<any>[] = [
{
accessorKey: "type_code",
accessorKey: "typeCode",
header: "Code",
cell: ({ row }) => (
<span className="font-mono font-bold">{row.getValue("type_code")}</span>
<span className="font-mono font-bold">{row.getValue("typeCode")}</span>
),
},
{
accessorKey: "type_name_th",
accessorKey: "typeNameTh",
header: "Name (TH)",
},
{
accessorKey: "type_name_en",
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"]}
fetchFn={rfaTypeService.getAll}
createFn={rfaTypeService.create}
updateFn={rfaTypeService.update}
deleteFn={rfaTypeService.delete}
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: "type_code", label: "Code", type: "text", required: true },
{ name: "type_name_th", label: "Name (TH)", type: "text", required: true },
{ name: "type_name_en", label: "Name (EN)", type: "text" },
{
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>