260220:1700 20260220 TASK-BEFE-001 Refactor by ADR-014 #5
All checks were successful
Build and Deploy / deploy (push) Successful in 2m33s
All checks were successful
Build and Deploy / deploy (push) Successful in 2m33s
This commit is contained in:
@@ -13,13 +13,22 @@ import {
|
||||
Shield,
|
||||
Menu,
|
||||
Layers,
|
||||
BookOpen,
|
||||
LucideIcon,
|
||||
} from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useState } from 'react';
|
||||
import { Can } from '@/components/common/can';
|
||||
import { useAuthStore } from '@/lib/stores/auth-store';
|
||||
|
||||
export const mainNavItems = [
|
||||
export type NavItem = {
|
||||
title: string;
|
||||
href: string;
|
||||
icon: LucideIcon;
|
||||
permission?: string | null;
|
||||
adminOnly?: boolean;
|
||||
};
|
||||
|
||||
export const mainNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
href: '/dashboard',
|
||||
@@ -67,24 +76,7 @@ export const mainNavItems = [
|
||||
href: '/admin',
|
||||
icon: Shield,
|
||||
permission: null,
|
||||
},
|
||||
{
|
||||
title: 'Security',
|
||||
href: '/admin/access-control/roles',
|
||||
icon: Shield,
|
||||
permission: 'system.manage_security',
|
||||
},
|
||||
{
|
||||
title: 'System Logs',
|
||||
href: '/admin/monitoring/system-logs/numbering',
|
||||
icon: Layers,
|
||||
permission: 'system.view_logs',
|
||||
},
|
||||
{
|
||||
title: 'Reference Data',
|
||||
href: '/admin/doc-control/reference',
|
||||
icon: BookOpen,
|
||||
permission: 'master_data.view',
|
||||
adminOnly: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -95,6 +87,8 @@ interface SidebarProps {
|
||||
export function Sidebar({ className }: SidebarProps) {
|
||||
const pathname = usePathname();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const user = useAuthStore((state) => state.user);
|
||||
const isAdmin = user?.role === 'ADMIN' || user?.role === 'DC';
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -119,6 +113,8 @@ export function Sidebar({ className }: SidebarProps) {
|
||||
<div className="flex-1 overflow-y-auto py-4">
|
||||
<nav className="grid gap-1 px-2">
|
||||
{mainNavItems.map((item, index) => {
|
||||
if (item.adminOnly && !isAdmin) return null;
|
||||
|
||||
const isActive = pathname.startsWith(item.href);
|
||||
|
||||
const LinkComponent = (
|
||||
@@ -172,6 +168,8 @@ import { Sheet, SheetContent, SheetTrigger, SheetTitle } from '@/components/ui/s
|
||||
export function MobileSidebar() {
|
||||
const pathname = usePathname();
|
||||
const [open, setOpen] = useState(false);
|
||||
const user = useAuthStore((state) => state.user);
|
||||
const isAdmin = user?.role === 'ADMIN' || user?.role === 'DC';
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
@@ -189,6 +187,8 @@ export function MobileSidebar() {
|
||||
<div className="flex-1 overflow-y-auto py-4 h-[calc(100vh-4rem)]">
|
||||
<nav className="grid gap-1 px-2">
|
||||
{mainNavItems.map((item, index) => {
|
||||
if (item.adminOnly && !isAdmin) return null;
|
||||
|
||||
const isActive = pathname.startsWith(item.href);
|
||||
|
||||
const LinkComponent = (
|
||||
|
||||
@@ -6,7 +6,7 @@ import { SearchContractDrawingDto, CreateContractDrawingDto } from '@/types/dto/
|
||||
import { SearchShopDrawingDto, CreateShopDrawingDto } from '@/types/dto/drawing/shop-drawing.dto';
|
||||
import { SearchAsBuiltDrawingDto, CreateAsBuiltDrawingDto } from '@/types/dto/drawing/asbuilt-drawing.dto';
|
||||
import { toast } from 'sonner';
|
||||
import { ContractDrawing, ShopDrawing, AsBuiltDrawing } from "@/types/drawing";
|
||||
import { ContractDrawing, ShopDrawing, AsBuiltDrawing } from '@/types/drawing';
|
||||
|
||||
type DrawingType = 'CONTRACT' | 'SHOP' | 'AS_BUILT';
|
||||
type DrawingSearchParams = SearchContractDrawingDto | SearchShopDrawingDto | SearchAsBuiltDrawingDto;
|
||||
@@ -31,38 +31,44 @@ export function useDrawings(type: DrawingType, params: DrawingSearchParams) {
|
||||
response = await contractDrawingService.getAll(params as SearchContractDrawingDto);
|
||||
// Map ContractDrawing to Drawing
|
||||
if (response && response.data) {
|
||||
response.data = response.data.map((d: ContractDrawing) => ({
|
||||
...d,
|
||||
drawingId: d.id,
|
||||
drawingNumber: d.contractDrawingNo,
|
||||
type: 'CONTRACT',
|
||||
}));
|
||||
const mappedData = response.data.map((d: ContractDrawing) => ({
|
||||
...d,
|
||||
drawingId: d.id,
|
||||
drawingNumber: d.contractDrawingNo,
|
||||
type: 'CONTRACT',
|
||||
}));
|
||||
// Re-wrap to preserve meta
|
||||
response = { ...response, data: mappedData };
|
||||
}
|
||||
} else if (type === 'SHOP') {
|
||||
response = await shopDrawingService.getAll(params as SearchShopDrawingDto);
|
||||
// Map ShopDrawing to Drawing
|
||||
if (response && response.data) {
|
||||
response.data = response.data.map((d: ShopDrawing) => ({
|
||||
...d,
|
||||
drawingId: d.id,
|
||||
type: 'SHOP',
|
||||
title: d.currentRevision?.title || "Untitled",
|
||||
revision: d.currentRevision?.revisionNumber,
|
||||
legacyDrawingNumber: d.currentRevision?.legacyDrawingNumber,
|
||||
}));
|
||||
const mappedData = response.data.map((d: ShopDrawing) => ({
|
||||
...d,
|
||||
drawingId: d.id,
|
||||
type: 'SHOP',
|
||||
title: d.currentRevision?.title || 'Untitled',
|
||||
revision: d.currentRevision?.revisionNumber,
|
||||
legacyDrawingNumber: d.currentRevision?.legacyDrawingNumber,
|
||||
}));
|
||||
// Re-wrap to preserve meta
|
||||
response = { ...response, data: mappedData };
|
||||
}
|
||||
} else {
|
||||
response = await asBuiltDrawingService.getAll(params as SearchAsBuiltDrawingDto);
|
||||
// Map AsBuiltDrawing to Drawing
|
||||
if (response && response.data) {
|
||||
response.data = response.data.map((d: AsBuiltDrawing) => ({
|
||||
...d,
|
||||
drawingId: d.id,
|
||||
type: 'AS_BUILT',
|
||||
title: d.currentRevision?.title || "Untitled",
|
||||
revision: d.currentRevision?.revisionNumber,
|
||||
}));
|
||||
}
|
||||
const mappedData = response.data.map((d: AsBuiltDrawing) => ({
|
||||
...d,
|
||||
drawingId: d.id,
|
||||
type: 'AS_BUILT',
|
||||
title: d.currentRevision?.title || 'Untitled',
|
||||
revision: d.currentRevision?.revisionNumber,
|
||||
}));
|
||||
// Re-wrap to preserve meta
|
||||
response = { ...response, data: mappedData };
|
||||
}
|
||||
}
|
||||
return response;
|
||||
},
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// File: lib/services/asbuilt-drawing.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import {
|
||||
CreateAsBuiltDrawingDto,
|
||||
CreateAsBuiltDrawingRevisionDto,
|
||||
SearchAsBuiltDrawingDto
|
||||
} from "@/types/dto/drawing/asbuilt-drawing.dto";
|
||||
SearchAsBuiltDrawingDto,
|
||||
} from '@/types/dto/drawing/asbuilt-drawing.dto';
|
||||
|
||||
export const asBuiltDrawingService = {
|
||||
/**
|
||||
* Get As Built Drawings list
|
||||
*/
|
||||
getAll: async (params: SearchAsBuiltDrawingDto) => {
|
||||
const response = await apiClient.get("/drawings/asbuilt", { params });
|
||||
const response = await apiClient.get('/drawings/asbuilt', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ export const asBuiltDrawingService = {
|
||||
* Create New As Built Drawing
|
||||
*/
|
||||
create: async (data: CreateAsBuiltDrawingDto | FormData) => {
|
||||
const response = await apiClient.post("/drawings/asbuilt", data);
|
||||
const response = await apiClient.post('/drawings/asbuilt', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -37,5 +37,5 @@ export const asBuiltDrawingService = {
|
||||
createRevision: async (id: string | number, data: CreateAsBuiltDrawingRevisionDto) => {
|
||||
const response = await apiClient.post(`/drawings/asbuilt/${id}/revisions`, data);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
// File: lib/services/contract-drawing.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import {
|
||||
CreateContractDrawingDto,
|
||||
UpdateContractDrawingDto,
|
||||
SearchContractDrawingDto
|
||||
} from "@/types/dto/drawing/contract-drawing.dto";
|
||||
SearchContractDrawingDto,
|
||||
} from '@/types/dto/drawing/contract-drawing.dto';
|
||||
|
||||
export const contractDrawingService = {
|
||||
/**
|
||||
* ดึงรายการแบบสัญญา (Contract Drawings)
|
||||
*/
|
||||
getAll: async (params: SearchContractDrawingDto) => {
|
||||
// GET /drawings/contract?projectId=1&page=1...
|
||||
const response = await apiClient.get("/drawings/contract", { params });
|
||||
const response = await apiClient.get('/drawings/contract', { params });
|
||||
// The interceptor returns { statusCode, message, data, meta }
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -28,7 +26,7 @@ export const contractDrawingService = {
|
||||
* สร้างแบบสัญญาใหม่
|
||||
*/
|
||||
create: async (data: CreateContractDrawingDto | FormData) => {
|
||||
const response = await apiClient.post("/drawings/contract", data);
|
||||
const response = await apiClient.post('/drawings/contract', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -46,5 +44,5 @@ export const contractDrawingService = {
|
||||
delete: async (id: string | number) => {
|
||||
const response = await apiClient.delete(`/drawings/contract/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// File: lib/services/shop-drawing.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import {
|
||||
CreateShopDrawingDto,
|
||||
CreateShopDrawingRevisionDto,
|
||||
SearchShopDrawingDto
|
||||
} from "@/types/dto/drawing/shop-drawing.dto";
|
||||
SearchShopDrawingDto,
|
||||
} from '@/types/dto/drawing/shop-drawing.dto';
|
||||
|
||||
export const shopDrawingService = {
|
||||
/**
|
||||
* ดึงรายการแบบก่อสร้าง (Shop Drawings)
|
||||
*/
|
||||
getAll: async (params: SearchShopDrawingDto) => {
|
||||
const response = await apiClient.get("/drawings/shop", { params });
|
||||
const response = await apiClient.get('/drawings/shop', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ export const shopDrawingService = {
|
||||
* สร้าง Shop Drawing ใหม่ (พร้อม Revision 0)
|
||||
*/
|
||||
create: async (data: CreateShopDrawingDto | FormData) => {
|
||||
const response = await apiClient.post("/drawings/shop", data);
|
||||
const response = await apiClient.post('/drawings/shop', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -37,5 +37,5 @@ export const shopDrawingService = {
|
||||
createRevision: async (id: string | number, data: CreateShopDrawingRevisionDto) => {
|
||||
const response = await apiClient.post(`/drawings/shop/${id}/revisions`, data);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// File: lib/services/workflow-engine.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import {
|
||||
CreateWorkflowDefinitionDto,
|
||||
UpdateWorkflowDefinitionDto,
|
||||
EvaluateWorkflowDto,
|
||||
GetAvailableActionsDto
|
||||
} from "@/types/dto/workflow-engine/workflow-engine.dto";
|
||||
GetAvailableActionsDto,
|
||||
} from '@/types/dto/workflow-engine/workflow-engine.dto';
|
||||
|
||||
export const workflowEngineService = {
|
||||
// --- Engine Execution (Low-Level) ---
|
||||
@@ -15,8 +15,8 @@ export const workflowEngineService = {
|
||||
* POST /workflow-engine/available-actions
|
||||
*/
|
||||
getAvailableActions: async (data: GetAvailableActionsDto) => {
|
||||
const response = await apiClient.post("/workflow-engine/available-actions", data);
|
||||
return response.data; // string[] e.g. ['APPROVE', 'REJECT']
|
||||
const response = await apiClient.post('/workflow-engine/available-actions', data);
|
||||
return response.data?.data || response.data; // string[] e.g. ['APPROVE', 'REJECT']
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -24,8 +24,8 @@ export const workflowEngineService = {
|
||||
* POST /workflow-engine/evaluate
|
||||
*/
|
||||
evaluate: async (data: EvaluateWorkflowDto) => {
|
||||
const response = await apiClient.post("/workflow-engine/evaluate", data);
|
||||
return response.data; // { nextState: '...', events: [...] }
|
||||
const response = await apiClient.post('/workflow-engine/evaluate', data);
|
||||
return response.data?.data || response.data; // { nextState: '...', events: [...] }
|
||||
},
|
||||
|
||||
// --- Definition Management (Admin / Workflow Editor) ---
|
||||
@@ -35,8 +35,8 @@ export const workflowEngineService = {
|
||||
* GET /workflow-engine/definitions
|
||||
*/
|
||||
getDefinitions: async () => {
|
||||
const response = await apiClient.get("/workflow-engine/definitions");
|
||||
return response.data;
|
||||
const response = await apiClient.get('/workflow-engine/definitions');
|
||||
return response.data?.data || response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ export const workflowEngineService = {
|
||||
*/
|
||||
getDefinitionById: async (id: string | number) => {
|
||||
const response = await apiClient.get(`/workflow-engine/definitions/${id}`);
|
||||
return response.data;
|
||||
return response.data?.data || response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -53,8 +53,8 @@ export const workflowEngineService = {
|
||||
* POST /workflow-engine/definitions
|
||||
*/
|
||||
createDefinition: async (data: CreateWorkflowDefinitionDto) => {
|
||||
const response = await apiClient.post("/workflow-engine/definitions", data);
|
||||
return response.data;
|
||||
const response = await apiClient.post('/workflow-engine/definitions', data);
|
||||
return response.data?.data || response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,7 @@ export const workflowEngineService = {
|
||||
*/
|
||||
updateDefinition: async (id: string | number, data: UpdateWorkflowDefinitionDto) => {
|
||||
const response = await apiClient.patch(`/workflow-engine/definitions/${id}`, data);
|
||||
return response.data;
|
||||
return response.data?.data || response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -72,6 +72,6 @@ export const workflowEngineService = {
|
||||
*/
|
||||
deleteDefinition: async (id: string | number) => {
|
||||
const response = await apiClient.delete(`/workflow-engine/definitions/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
return response.data?.data || response.data;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user