From 90cbbb8f11f7f4c05d8c13570a9c9f32c01b83f4 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 20 Mar 2026 20:53:50 +0700 Subject: [PATCH] 690320:2053 UUID agian #01 --- frontend/hooks/use-master-data.ts | 4 +- frontend/lib/services/master-data.service.ts | 75 ++++++++++--------- frontend/lib/services/organization.service.ts | 32 ++++++-- frontend/lib/services/project.service.ts | 32 ++++++-- 4 files changed, 96 insertions(+), 47 deletions(-) diff --git a/frontend/hooks/use-master-data.ts b/frontend/hooks/use-master-data.ts index 70924ec..cac6b9f 100644 --- a/frontend/hooks/use-master-data.ts +++ b/frontend/hooks/use-master-data.ts @@ -112,7 +112,7 @@ export function useContractDrawingCategories(projectId?: number | string) { }); } -export function useShopMainCategories(projectId: number) { +export function useShopMainCategories(projectId: number | string) { return useQuery({ queryKey: ['shop-main-categories', projectId], queryFn: () => masterDataService.getShopMainCategories(projectId), @@ -120,7 +120,7 @@ export function useShopMainCategories(projectId: number) { }); } -export function useShopSubCategories(projectId: number, mainCategoryId?: number) { +export function useShopSubCategories(projectId: number | string, mainCategoryId?: number) { return useQuery({ queryKey: ['shop-sub-categories', projectId, mainCategoryId], queryFn: () => masterDataService.getShopSubCategories(projectId, mainCategoryId), diff --git a/frontend/lib/services/master-data.service.ts b/frontend/lib/services/master-data.service.ts index 7466a86..0f25f1d 100644 --- a/frontend/lib/services/master-data.service.ts +++ b/frontend/lib/services/master-data.service.ts @@ -15,14 +15,39 @@ import { SearchOrganizationDto, } from "@/types/dto/organization/organization.dto"; +type ApiEnvelope = { + data?: ApiEnvelope | T; + message?: string; + statusCode?: number; +}; + +function unwrapApiData(payload: ApiEnvelope | T): ApiEnvelope | T | null { + let current: ApiEnvelope | T | null = payload; + + while ( + current && + typeof current === "object" && + "data" in current && + current.data !== undefined + ) { + current = current.data; + } + + return current; +} + +function unwrapArrayResponse(payload: ApiEnvelope | T[]): T[] { + const unwrapped = unwrapApiData(payload); + return Array.isArray(unwrapped) ? unwrapped : []; +} + export const masterDataService = { // --- Tags Management --- /** ดึงรายการ Tags ทั้งหมด (Search & Pagination) */ getTags: async (params?: SearchTagDto) => { const response = await apiClient.get("/master/tags", { params }); - // Support both wrapped and unwrapped scenarios - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, /** สร้าง Tag ใหม่ */ @@ -48,27 +73,7 @@ export const masterDataService = { /** ดึงรายชื่อองค์กรทั้งหมด */ getOrganizations: async (params?: SearchOrganizationDto) => { const response = await apiClient.get("/organizations", { params }); - // Support paginated response - if (response.data && Array.isArray((response.data as { data: Organization[] }).data)) { - return (response.data as { data: Organization[] }).data; - } - // If response.data itself is an array - if (Array.isArray(response.data)) { - return response.data; - } - // If we're here, it might be { data: [], total: ... } but data is missing? or empty? - // Or it returned the object but data.data check failed (shouldn't happen if it follows schema). - // Let's default to [] if we can't find an array, because callers expect array. - // However, if we return [] we lose data if it was there but not recognized. - - // Fallback: Check if response.data is object? - // If it's the paginated object, return the data array if it exists - if (response.data && (response.data as { data: Organization[] }).data) { - // Maybe it's not an array? - return Array.isArray((response.data as { data: Organization[] }).data) ? (response.data as { data: Organization[] }).data : []; - } - - return []; // Return empty array to prevent map errors + return unwrapArrayResponse(response.data as ApiEnvelope | Organization[]); }, /** สร้างองค์กรใหม่ */ @@ -97,7 +102,7 @@ export const masterDataService = { const response = await apiClient.get("/master/disciplines", { params: { contractId } }); - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, /** สร้างสาขางานใหม่ */ @@ -119,7 +124,7 @@ export const masterDataService = { const response = await apiClient.get("/master/sub-types", { params: { contractId, correspondenceTypeId: typeId } }); - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, /** สร้างประเภทย่อยใหม่ */ @@ -135,7 +140,7 @@ export const masterDataService = { const response = await apiClient.get("/master/rfa-types", { params: { contractId } }); - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, /** สร้างประเภท RFA ใหม่ */ @@ -156,7 +161,7 @@ export const masterDataService = { // --- Correspondence Types Management --- getCorrespondenceTypes: async () => { const response = await apiClient.get("/master/correspondence-types"); - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, createCorrespondenceType: async (data: CreateCorrespondenceTypeDto) => { @@ -188,21 +193,21 @@ export const masterDataService = { // --- Drawing Categories --- getContractDrawingCategories: async (projectId?: number | string) => { - const response = await apiClient.get("/drawings/contract/categories", { + const response = await apiClient.get("/drawings/master-data/contract/categories", { params: { projectId } }); - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, - getShopMainCategories: async (projectId: number) => { - const response = await apiClient.get("/drawings/shop/main-categories", { params: { projectId } }); - return response.data.data || response.data; + getShopMainCategories: async (projectId: number | string) => { + const response = await apiClient.get("/drawings/master-data/shop/main-categories", { params: { projectId } }); + return unwrapArrayResponse(response.data); }, - getShopSubCategories: async (projectId: number, mainCategoryId?: number) => { - const response = await apiClient.get("/drawings/shop/sub-categories", { + getShopSubCategories: async (projectId: number | string, mainCategoryId?: number) => { + const response = await apiClient.get("/drawings/master-data/shop/sub-categories", { params: { projectId, mainCategoryId } }); - return response.data.data || response.data; + return unwrapArrayResponse(response.data); } }; diff --git a/frontend/lib/services/organization.service.ts b/frontend/lib/services/organization.service.ts index 7aa35b9..579f331 100644 --- a/frontend/lib/services/organization.service.ts +++ b/frontend/lib/services/organization.service.ts @@ -5,6 +5,32 @@ import { SearchOrganizationDto, } from "@/types/dto/organization/organization.dto"; +type ApiEnvelope = { + data?: ApiEnvelope | T; + message?: string; + statusCode?: number; +}; + +function unwrapApiData(payload: ApiEnvelope | T): ApiEnvelope | T | null { + let current: ApiEnvelope | T | null = payload; + + while ( + current && + typeof current === "object" && + "data" in current && + current.data !== undefined + ) { + current = current.data; + } + + return current; +} + +function unwrapArrayResponse(payload: ApiEnvelope | T[]): T[] { + const unwrapped = unwrapApiData(payload); + return Array.isArray(unwrapped) ? unwrapped : []; +} + export const organizationService = { /** * Get all organizations (supports filtering by projectId) @@ -12,11 +38,7 @@ export const organizationService = { */ getAll: async (params?: SearchOrganizationDto) => { const response = await apiClient.get("/organizations", { params }); - // Normalize response if wrapped in data.data or direct data - if (response.data && Array.isArray(response.data.data)) { - return response.data.data; - } - return response.data.data || response.data; + return unwrapArrayResponse(response.data); }, /** diff --git a/frontend/lib/services/project.service.ts b/frontend/lib/services/project.service.ts index 976949c..1c719db 100644 --- a/frontend/lib/services/project.service.ts +++ b/frontend/lib/services/project.service.ts @@ -6,6 +6,32 @@ import { SearchProjectDto } from "@/types/dto/project/project.dto"; +type ApiEnvelope = { + data?: ApiEnvelope | T; + message?: string; + statusCode?: number; +}; + +function unwrapApiData(payload: ApiEnvelope | T): ApiEnvelope | T | null { + let current: ApiEnvelope | T | null = payload; + + while ( + current && + typeof current === "object" && + "data" in current && + current.data !== undefined + ) { + current = current.data; + } + + return current; +} + +function unwrapArrayResponse(payload: ApiEnvelope | T[]): T[] { + const unwrapped = unwrapApiData(payload); + return Array.isArray(unwrapped) ? unwrapped : []; +} + export const projectService = { // --- Basic CRUD --- @@ -16,11 +42,7 @@ export const projectService = { getAll: async (params?: SearchProjectDto) => { // GET /projects const response = await apiClient.get("/projects", { params }); - // Handle paginated response - if (response.data && Array.isArray(response.data.data)) { - return response.data.data; - } - return response.data; + return unwrapArrayResponse(response.data); }, /** ดึงรายละเอียดโครงการตาม UUID */