260322:1648 Correct Coresspondence / Doing RFA / Correct CI
This commit is contained in:
+30
-30
@@ -1,60 +1,60 @@
|
||||
import { User, CreateUserDto, Organization, AuditLog } from "@/types/admin";
|
||||
import { User, CreateUserDto, Organization, AuditLog } from '@/types/admin';
|
||||
|
||||
// Mock Data
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
userId: 1,
|
||||
username: "admin",
|
||||
email: "admin@example.com",
|
||||
firstName: "System",
|
||||
lastName: "Admin",
|
||||
username: 'admin',
|
||||
email: 'admin@example.com',
|
||||
firstName: 'System',
|
||||
lastName: 'Admin',
|
||||
isActive: true,
|
||||
roles: [{ roleId: 1, roleName: "ADMIN", description: "Administrator" }],
|
||||
roles: [{ roleId: 1, roleName: 'ADMIN', description: 'Administrator' }],
|
||||
},
|
||||
{
|
||||
userId: 2,
|
||||
username: "jdoe",
|
||||
email: "john.doe@example.com",
|
||||
firstName: "John",
|
||||
lastName: "Doe",
|
||||
username: 'jdoe',
|
||||
email: 'john.doe@example.com',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
isActive: true,
|
||||
roles: [{ roleId: 2, roleName: "USER", description: "Regular User" }],
|
||||
roles: [{ roleId: 2, roleName: 'USER', description: 'Regular User' }],
|
||||
},
|
||||
];
|
||||
|
||||
const mockOrgs: Organization[] = [
|
||||
{
|
||||
orgId: 1,
|
||||
orgCode: "PAT",
|
||||
orgName: "Port Authority of Thailand",
|
||||
orgNameTh: "การท่าเรือแห่งประเทศไทย",
|
||||
description: "Owner",
|
||||
orgCode: 'PAT',
|
||||
orgName: 'Port Authority of Thailand',
|
||||
orgNameTh: 'การท่าเรือแห่งประเทศไทย',
|
||||
description: 'Owner',
|
||||
},
|
||||
{
|
||||
orgId: 2,
|
||||
orgCode: "CNPC",
|
||||
orgName: "CNPC Consortium",
|
||||
description: "Main Contractor",
|
||||
orgCode: 'CNPC',
|
||||
orgName: 'CNPC Consortium',
|
||||
description: 'Main Contractor',
|
||||
},
|
||||
];
|
||||
|
||||
const mockLogs: AuditLog[] = [
|
||||
{
|
||||
auditLogId: 1,
|
||||
userName: "admin",
|
||||
action: "CREATE",
|
||||
entityType: "user",
|
||||
userName: 'admin',
|
||||
action: 'CREATE',
|
||||
entityType: 'user',
|
||||
description: "Created user 'jdoe'",
|
||||
ipAddress: "192.168.1.1",
|
||||
ipAddress: '192.168.1.1',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60 * 24).toISOString(),
|
||||
},
|
||||
{
|
||||
auditLogId: 2,
|
||||
userName: "jdoe",
|
||||
action: "UPDATE",
|
||||
entityType: "rfa",
|
||||
description: "Updated status of RFA-001 to APPROVED",
|
||||
ipAddress: "192.168.1.5",
|
||||
userName: 'jdoe',
|
||||
action: 'UPDATE',
|
||||
entityType: 'rfa',
|
||||
description: 'Updated status of RFA-001 to APPROVED',
|
||||
ipAddress: '192.168.1.5',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 30).toISOString(),
|
||||
},
|
||||
];
|
||||
@@ -76,8 +76,8 @@ export const adminApi = {
|
||||
isActive: data.isActive,
|
||||
roles: data.roles.map((id) => ({
|
||||
roleId: id,
|
||||
roleName: id === 1 ? "ADMIN" : "USER",
|
||||
description: "",
|
||||
roleName: id === 1 ? 'ADMIN' : 'USER',
|
||||
description: '',
|
||||
})),
|
||||
};
|
||||
mockUsers.push(newUser);
|
||||
@@ -89,7 +89,7 @@ export const adminApi = {
|
||||
return [...mockOrgs];
|
||||
},
|
||||
|
||||
createOrganization: async (data: Omit<Organization, "orgId">): Promise<Organization> => {
|
||||
createOrganization: async (data: Omit<Organization, 'orgId'>): Promise<Organization> => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 600));
|
||||
const newOrg = { ...data, orgId: Math.max(...mockOrgs.map((o) => o.orgId)) + 1 };
|
||||
mockOrgs.push(newOrg);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// File: lib/api/client.ts
|
||||
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosError } from "axios";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosError } from 'axios';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
// อ่านค่า Base URL จาก Environment Variable
|
||||
const baseURL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001/api";
|
||||
const baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api';
|
||||
|
||||
// สร้าง Axios Instance หลัก
|
||||
const apiClient: AxiosInstance = axios.create({
|
||||
baseURL,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 15000, // Timeout 15 วินาที
|
||||
});
|
||||
@@ -23,13 +23,13 @@ apiClient.interceptors.request.use(
|
||||
// 1. Idempotency Key Injection
|
||||
// ป้องกันการทำรายการซ้ำสำหรับ Method ที่เปลี่ยนแปลงข้อมูล
|
||||
const method = config.method?.toLowerCase();
|
||||
if (method && ["post", "put", "delete", "patch"].includes(method)) {
|
||||
config.headers["Idempotency-Key"] = uuidv4();
|
||||
if (method && ['post', 'put', 'delete', 'patch'].includes(method)) {
|
||||
config.headers['Idempotency-Key'] = uuidv4();
|
||||
}
|
||||
|
||||
// 2. Authentication Token Injection
|
||||
// ดึง Token จาก Zustand persist store (localStorage)
|
||||
if (typeof window !== "undefined") {
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const authStorage = localStorage.getItem('auth-storage');
|
||||
if (authStorage) {
|
||||
@@ -37,10 +37,10 @@ apiClient.interceptors.request.use(
|
||||
const token = parsed?.state?.token;
|
||||
|
||||
if (token) {
|
||||
config.headers["Authorization"] = `Bearer ${token}`;
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
// Auth token retrieval failed - request will proceed without token
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DashboardStats, ActivityLog, PendingTask } from "@/types/dashboard";
|
||||
import { DashboardStats, ActivityLog, PendingTask } from '@/types/dashboard';
|
||||
|
||||
export const dashboardApi = {
|
||||
getStats: async (): Promise<DashboardStats> => {
|
||||
@@ -18,27 +18,27 @@ export const dashboardApi = {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
user: { name: "John Doe", initials: "JD" },
|
||||
action: "Created RFA",
|
||||
description: "RFA-001: Concrete Pouring Request",
|
||||
user: { name: 'John Doe', initials: 'JD' },
|
||||
action: 'Created RFA',
|
||||
description: 'RFA-001: Concrete Pouring Request',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 30).toISOString(), // 30 mins ago
|
||||
targetUrl: "/rfas/1",
|
||||
targetUrl: '/rfas/1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
user: { name: "Jane Smith", initials: "JS" },
|
||||
action: "Approved Correspondence",
|
||||
description: "COR-005: Site Safety Report",
|
||||
user: { name: 'Jane Smith', initials: 'JS' },
|
||||
action: 'Approved Correspondence',
|
||||
description: 'COR-005: Site Safety Report',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60 * 2).toISOString(), // 2 hours ago
|
||||
targetUrl: "/correspondences/5",
|
||||
targetUrl: '/correspondences/5',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
user: { name: "Mike Johnson", initials: "MJ" },
|
||||
action: "Uploaded Drawing",
|
||||
description: "A-101: Ground Floor Plan Rev B",
|
||||
user: { name: 'Mike Johnson', initials: 'MJ' },
|
||||
action: 'Uploaded Drawing',
|
||||
description: 'A-101: Ground Floor Plan Rev B',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60 * 5).toISOString(), // 5 hours ago
|
||||
targetUrl: "/drawings/1",
|
||||
targetUrl: '/drawings/1',
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -48,19 +48,19 @@ export const dashboardApi = {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
title: "Review RFA-002",
|
||||
description: "Approval required for steel reinforcement",
|
||||
title: 'Review RFA-002',
|
||||
description: 'Approval required for steel reinforcement',
|
||||
daysOverdue: 2,
|
||||
url: "/rfas/2",
|
||||
priority: "HIGH",
|
||||
url: '/rfas/2',
|
||||
priority: 'HIGH',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Approve Monthly Report",
|
||||
description: "January 2025 Progress Report",
|
||||
title: 'Approve Monthly Report',
|
||||
description: 'January 2025 Progress Report',
|
||||
daysOverdue: 0,
|
||||
url: "/correspondences/10",
|
||||
priority: "MEDIUM",
|
||||
url: '/correspondences/10',
|
||||
priority: 'MEDIUM',
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { Drawing } from "@/types/drawing";
|
||||
import { Drawing } from '@/types/drawing';
|
||||
|
||||
// Mock Data
|
||||
const mockDrawings: Drawing[] = [
|
||||
{
|
||||
drawingId: 1,
|
||||
drawingNumber: "S-201-A",
|
||||
title: "Structural Foundation Plan",
|
||||
discipline: "Structural",
|
||||
status: "APPROVED",
|
||||
revision: "A",
|
||||
drawingNumber: 'S-201-A',
|
||||
title: 'Structural Foundation Plan',
|
||||
discipline: 'Structural',
|
||||
status: 'APPROVED',
|
||||
revision: 'A',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5).toISOString(),
|
||||
updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 24).toISOString(),
|
||||
},
|
||||
{
|
||||
drawingId: 2,
|
||||
drawingNumber: "A-101-B",
|
||||
title: "Architectural Floor Plan - Level 1",
|
||||
discipline: "Architectural",
|
||||
status: "IN_REVIEW",
|
||||
revision: "B",
|
||||
drawingNumber: 'A-101-B',
|
||||
title: 'Architectural Floor Plan - Level 1',
|
||||
discipline: 'Architectural',
|
||||
status: 'IN_REVIEW',
|
||||
revision: 'B',
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 3).toISOString(),
|
||||
updatedAt: new Date(Date.now() - 1000 * 60 * 60 * 2).toISOString(),
|
||||
},
|
||||
@@ -35,7 +35,7 @@ export const drawingApi = {
|
||||
return mockDrawings.find((d) => d.drawingId === id);
|
||||
},
|
||||
|
||||
getByContract: async (contractId: number): Promise<{ data: Drawing[] }> => {
|
||||
getByContract: async (_contractId: number): Promise<{ data: Drawing[] }> => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 400));
|
||||
// Mock: return all drawings for any contract
|
||||
return { data: mockDrawings };
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import { NotificationResponse } from "@/types/notification";
|
||||
import { NotificationResponse } from '@/types/notification';
|
||||
|
||||
// Mock Data
|
||||
let mockNotifications = [
|
||||
{
|
||||
uuid: "019575a0-0001-7000-8000-000000000001",
|
||||
uuid: '019575a0-0001-7000-8000-000000000001',
|
||||
notificationId: 1,
|
||||
title: "RFA Approved",
|
||||
message: "RFA-001 has been approved by the Project Manager.",
|
||||
type: "SUCCESS" as const,
|
||||
title: 'RFA Approved',
|
||||
message: 'RFA-001 has been approved by the Project Manager.',
|
||||
type: 'SUCCESS' as const,
|
||||
isRead: false,
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 15).toISOString(), // 15 mins ago
|
||||
link: "/rfas/1",
|
||||
link: '/rfas/1',
|
||||
},
|
||||
{
|
||||
uuid: "019575a0-0002-7000-8000-000000000002",
|
||||
uuid: '019575a0-0002-7000-8000-000000000002',
|
||||
notificationId: 2,
|
||||
title: "New Correspondence",
|
||||
message: "You have received a new correspondence from Contractor A.",
|
||||
type: "INFO" as const,
|
||||
title: 'New Correspondence',
|
||||
message: 'You have received a new correspondence from Contractor A.',
|
||||
type: 'INFO' as const,
|
||||
isRead: false,
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60).toISOString(), // 1 hour ago
|
||||
link: "/correspondences/3",
|
||||
link: '/correspondences/3',
|
||||
},
|
||||
{
|
||||
uuid: "019575a0-0003-7000-8000-000000000003",
|
||||
uuid: '019575a0-0003-7000-8000-000000000003',
|
||||
notificationId: 3,
|
||||
title: "Drawing Revision Required",
|
||||
message: "Drawing S-201 requires revision based on recent comments.",
|
||||
type: "WARNING" as const,
|
||||
title: 'Drawing Revision Required',
|
||||
message: 'Drawing S-201 requires revision based on recent comments.',
|
||||
type: 'WARNING' as const,
|
||||
isRead: true,
|
||||
createdAt: new Date(Date.now() - 1000 * 60 * 60 * 24).toISOString(), // 1 day ago
|
||||
link: "/drawings/2",
|
||||
link: '/drawings/2',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -46,8 +46,6 @@ export const notificationApi = {
|
||||
|
||||
markAsRead: async (id: number) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||
mockNotifications = mockNotifications.map((n) =>
|
||||
n.notificationId === id ? { ...n, isRead: true } : n
|
||||
);
|
||||
mockNotifications = mockNotifications.map((n) => (n.notificationId === id ? { ...n, isRead: true } : n));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -130,18 +130,18 @@ export const numberingApi = {
|
||||
* Get all templates
|
||||
*/
|
||||
getTemplates: async (): Promise<NumberingTemplate[]> => {
|
||||
const res = await apiClient.get<any>('/admin/document-numbering/templates');
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.get<unknown>('/admin/document-numbering/templates');
|
||||
const data = res.data as { data: NumberingTemplate[] } | NumberingTemplate[];
|
||||
return Array.isArray(data) ? data : (data as { data: NumberingTemplate[] }).data || [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get templates for a specific project
|
||||
*/
|
||||
getTemplatesByProject: async (projectId: number): Promise<NumberingTemplate[]> => {
|
||||
const res = await apiClient.get<any>(
|
||||
`/admin/document-numbering/templates?projectId=${projectId}`
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.get<unknown>(`/admin/document-numbering/templates?projectId=${projectId}`);
|
||||
const data = res.data as { data: NumberingTemplate[] } | NumberingTemplate[];
|
||||
return Array.isArray(data) ? data : (data as { data: NumberingTemplate[] }).data || [];
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -157,7 +157,7 @@ export const numberingApi = {
|
||||
*/
|
||||
saveTemplate: async (dto: SaveTemplateDto): Promise<NumberingTemplate> => {
|
||||
// Clean the DTO to avoid sending nested objects that might confuse TypeORM or violate constraints
|
||||
const cleanDto: any = {
|
||||
const cleanDto: Record<string, unknown> = {
|
||||
id: dto.id,
|
||||
projectId: dto.projectId,
|
||||
correspondenceTypeId: dto.correspondenceTypeId,
|
||||
@@ -168,11 +168,9 @@ export const numberingApi = {
|
||||
isActive: dto.isActive ?? 1,
|
||||
};
|
||||
|
||||
const res = await apiClient.post<any>(
|
||||
'/admin/document-numbering/templates',
|
||||
cleanDto
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.post<unknown>('/admin/document-numbering/templates', cleanDto);
|
||||
const data = res.data as Record<string, unknown>;
|
||||
return (data.id ? data : data.data) as NumberingTemplate;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -190,30 +188,33 @@ export const numberingApi = {
|
||||
* Get audit logs
|
||||
*/
|
||||
getAuditLogs: async (limit = 100): Promise<DocumentNumberAudit[]> => {
|
||||
const res = await apiClient.get<any>(
|
||||
`/document-numbering/logs/audit?limit=${limit}`
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.get<unknown>(`/document-numbering/logs/audit?limit=${limit}`);
|
||||
const data = res.data as { data: DocumentNumberAudit[] } | DocumentNumberAudit[];
|
||||
return Array.isArray(data) ? data : (data as { data: DocumentNumberAudit[] }).data || [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get error logs
|
||||
*/
|
||||
getErrorLogs: async (limit = 100): Promise<DocumentNumberError[]> => {
|
||||
const res = await apiClient.get<any>(
|
||||
`/document-numbering/logs/errors?limit=${limit}`
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.get<unknown>(`/document-numbering/logs/errors?limit=${limit}`);
|
||||
const data = res.data as { data: DocumentNumberError[] } | DocumentNumberError[];
|
||||
return Array.isArray(data) ? data : (data as { data: DocumentNumberError[] }).data || [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get metrics (audit + errors combined)
|
||||
*/
|
||||
getMetrics: async (): Promise<{ audit: DocumentNumberAudit[]; errors: DocumentNumberError[] }> => {
|
||||
const res = await apiClient.get<any>(
|
||||
'/admin/document-numbering/metrics'
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.get<unknown>('/admin/document-numbering/metrics');
|
||||
const data = res.data as {
|
||||
data?: { audit: DocumentNumberAudit[]; errors: DocumentNumberError[] };
|
||||
audit?: DocumentNumberAudit[];
|
||||
errors?: DocumentNumberError[];
|
||||
};
|
||||
return 'audit' in data
|
||||
? (data as { audit: DocumentNumberAudit[]; errors: DocumentNumberError[] })
|
||||
: data.data || { audit: [], errors: [] };
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
@@ -224,44 +225,42 @@ export const numberingApi = {
|
||||
* Manually override/set a counter value
|
||||
*/
|
||||
manualOverride: async (dto: ManualOverrideDto): Promise<{ success: boolean; message: string }> => {
|
||||
const res = await apiClient.post<any>(
|
||||
'/admin/document-numbering/manual-override',
|
||||
dto
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.post<unknown>('/admin/document-numbering/manual-override', dto);
|
||||
const data = res.data as { data?: { success: boolean; message: string }; success?: boolean; message?: string };
|
||||
return 'success' in data
|
||||
? (data as { success: boolean; message: string })
|
||||
: data.data || { success: false, message: '' };
|
||||
},
|
||||
|
||||
/**
|
||||
* Void a document number and generate replacement
|
||||
*/
|
||||
voidAndReplace: async (dto: VoidAndReplaceDto): Promise<{ newNumber: string; auditId: number }> => {
|
||||
const res = await apiClient.post<any>(
|
||||
'/admin/document-numbering/void-and-replace',
|
||||
dto
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.post<unknown>('/admin/document-numbering/void-and-replace', dto);
|
||||
const data = res.data as { data?: { newNumber: string; auditId: number }; newNumber?: string; auditId?: number };
|
||||
return 'newNumber' in data
|
||||
? (data as { newNumber: string; auditId: number })
|
||||
: data.data || { newNumber: '', auditId: 0 };
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel/skip a document number
|
||||
*/
|
||||
cancelNumber: async (dto: CancelNumberDto): Promise<{ success: boolean }> => {
|
||||
const res = await apiClient.post<any>(
|
||||
'/admin/document-numbering/cancel',
|
||||
dto
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.post<unknown>('/admin/document-numbering/cancel', dto);
|
||||
const data = res.data as { data?: { success: boolean }; success?: boolean };
|
||||
return 'success' in data ? (data as { success: boolean }) : data.data || { success: false };
|
||||
},
|
||||
|
||||
/**
|
||||
* Bulk import counter values
|
||||
*/
|
||||
bulkImport: async (items: BulkImportItem[]): Promise<{ imported: number; errors: string[] }> => {
|
||||
const res = await apiClient.post<any>(
|
||||
'/admin/document-numbering/bulk-import',
|
||||
items
|
||||
);
|
||||
return res.data.data || res.data;
|
||||
const res = await apiClient.post<unknown>('/admin/document-numbering/bulk-import', items);
|
||||
const data = res.data as { data?: { imported: number; errors: string[] }; imported?: number; errors?: string[] };
|
||||
return 'imported' in data
|
||||
? (data as { imported: number; errors: string[] })
|
||||
: data.data || { imported: 0, errors: [] };
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -279,11 +278,10 @@ export const numberingApi = {
|
||||
* Get all counter sequences
|
||||
*/
|
||||
getSequences: async (projectId?: number): Promise<NumberSequence[]> => {
|
||||
const url = projectId
|
||||
? `/document-numbering/sequences?projectId=${projectId}`
|
||||
: '/document-numbering/sequences';
|
||||
const res = await apiClient.get<any>(url);
|
||||
return res.data.data || res.data;
|
||||
const url = projectId ? `/document-numbering/sequences?projectId=${projectId}` : '/document-numbering/sequences';
|
||||
const res = await apiClient.get<unknown>(url);
|
||||
const data = res.data as { data: NumberSequence[] } | NumberSequence[];
|
||||
return Array.isArray(data) ? data : (data as { data: NumberSequence[] }).data || [];
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -298,36 +296,37 @@ export const numberingApi = {
|
||||
rfaTypeId?: number;
|
||||
recipientOrganizationId?: number | string;
|
||||
}): Promise<{ previewNumber: string; nextSequence: number; isDefault: boolean }> => {
|
||||
const res = await apiClient.post<any>(
|
||||
'/document-numbering/preview',
|
||||
ctx
|
||||
);
|
||||
|
||||
// Explicit debug log for frontend developers to see in browser console
|
||||
console.log("[numberingApi.previewNumber] Raw Response Data:", res.data);
|
||||
// Preview what a document number would look like (without generating)
|
||||
const res = await apiClient.post<unknown>('/document-numbering/preview', ctx);
|
||||
|
||||
const body = res.data;
|
||||
console.log("[numberingApi.previewNumber] Full Body:", body);
|
||||
const body = res.data as Record<string, unknown>;
|
||||
|
||||
// Drill down to find the actual data object
|
||||
let data = body;
|
||||
let current: Record<string, unknown> = body;
|
||||
let depth = 0;
|
||||
while (data && typeof data === 'object' && !data.previewNumber && !data.number && data.data && depth < 3) {
|
||||
data = data.data;
|
||||
depth++;
|
||||
while (
|
||||
current &&
|
||||
typeof current === 'object' &&
|
||||
!current.previewNumber &&
|
||||
!current.number &&
|
||||
current.data &&
|
||||
depth < 3
|
||||
) {
|
||||
current = current.data as Record<string, unknown>;
|
||||
depth++;
|
||||
}
|
||||
|
||||
console.log(`[numberingApi.previewNumber] Unwrapped at depth ${depth}:`, data);
|
||||
|
||||
// Final extraction
|
||||
const previewNumber = data?.previewNumber || data?.number || (typeof data === 'string' ? data : '');
|
||||
const nextSequence = data?.nextSequence ?? data?.sequence ?? 0;
|
||||
const isDefault = data?.isDefault === true;
|
||||
const previewData = current;
|
||||
const previewNumber =
|
||||
((typeof current === 'string' ? current : previewData?.previewNumber || previewData?.number) as string) || '';
|
||||
const nextSequence = (previewData?.nextSequence ?? previewData?.sequence ?? 0) as number;
|
||||
const isDefault = previewData?.isDefault === true;
|
||||
|
||||
return {
|
||||
previewNumber: previewNumber || JSON.stringify(body), // Fallback to body string if all else fails
|
||||
nextSequence: nextSequence,
|
||||
isDefault: isDefault
|
||||
isDefault: isDefault,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -337,7 +336,7 @@ export const numberingApi = {
|
||||
*/
|
||||
generateTestNumber: async (
|
||||
_templateId: number,
|
||||
context: { organizationId: string; disciplineId: string }
|
||||
_context: { organizationId: string; disciplineId: string }
|
||||
): Promise<{ number: string }> => {
|
||||
// Fallback mock for legacy UI - requires proper context for real use
|
||||
const mockNumber = `TEST-${new Date().getFullYear()}-${String(Math.floor(Math.random() * 9999)).padStart(4, '0')}`;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Workflow, CreateWorkflowDto, ValidationResult } from "@/types/workflow";
|
||||
import { Workflow, CreateWorkflowDto, ValidationResult } from '@/types/workflow';
|
||||
|
||||
// Mock Data
|
||||
let mockWorkflows: Workflow[] = [
|
||||
{
|
||||
workflowId: 1,
|
||||
workflowName: "Standard RFA Workflow",
|
||||
description: "Default approval process for RFAs",
|
||||
workflowType: "RFA",
|
||||
workflowName: 'Standard RFA Workflow',
|
||||
description: 'Default approval process for RFAs',
|
||||
workflowType: 'RFA',
|
||||
version: 1,
|
||||
isActive: true,
|
||||
dslDefinition: `name: Standard RFA Workflow
|
||||
@@ -23,9 +23,9 @@ steps:
|
||||
},
|
||||
{
|
||||
workflowId: 2,
|
||||
workflowName: "Correspondence Review",
|
||||
description: "Incoming correspondence review flow",
|
||||
workflowType: "CORRESPONDENCE",
|
||||
workflowName: 'Correspondence Review',
|
||||
description: 'Incoming correspondence review flow',
|
||||
workflowType: 'CORRESPONDENCE',
|
||||
version: 2,
|
||||
isActive: true,
|
||||
dslDefinition: `name: Correspondence Review
|
||||
@@ -66,7 +66,7 @@ export const workflowApi = {
|
||||
updateWorkflow: async (id: number, data: Partial<CreateWorkflowDto>): Promise<Workflow> => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 600));
|
||||
const index = mockWorkflows.findIndex((w) => w.workflowId === id);
|
||||
if (index === -1) throw new Error("Workflow not found");
|
||||
if (index === -1) throw new Error('Workflow not found');
|
||||
|
||||
const updatedWorkflow = { ...mockWorkflows[index], ...data, updatedAt: new Date().toISOString() };
|
||||
mockWorkflows[index] = updatedWorkflow;
|
||||
@@ -76,7 +76,7 @@ export const workflowApi = {
|
||||
validateDSL: async (dsl: string): Promise<ValidationResult> => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 400));
|
||||
// Simple mock validation
|
||||
if (!dsl.includes("name:") || !dsl.includes("steps:")) {
|
||||
if (!dsl.includes('name:') || !dsl.includes('steps:')) {
|
||||
return { valid: false, errors: ["Missing 'name' or 'steps' field"] };
|
||||
}
|
||||
return { valid: true, errors: [] };
|
||||
|
||||
Reference in New Issue
Block a user