import apiClient from './authApi'; export type PriorityUi = 'standard' | 'express'; export interface ApproverFormItem { email: string; name?: string; tat?: number | ''; tatType?: 'hours' | 'days'; } export interface ParticipantItem { id?: string; name: string; email: string; } export interface CreateWorkflowFromFormPayload { templateId?: string | null; templateType: 'CUSTOM' | 'TEMPLATE'; title: string; description: string; priorityUi: PriorityUi; approverCount: number; approvers: ApproverFormItem[]; spectators?: ParticipantItem[]; ccList?: ParticipantItem[]; } // Utility to generate a RFC4122 v4 UUID (fallback if crypto.randomUUID not available) function generateUuid(): string { if (typeof crypto !== 'undefined' && (crypto as any).randomUUID) { return (crypto as any).randomUUID(); } // Fallback return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } export interface CreateWorkflowResponse { id: string; } export async function createWorkflowFromForm(form: CreateWorkflowFromFormPayload): Promise { // Map UI priority to API enum const priority = form.priorityUi.toUpperCase() === 'EXPRESS' ? 'EXPRESS' : 'STANDARD'; // Build approval levels to match backend schema const approvalLevels = Array.from({ length: form.approverCount || 1 }, (_, i) => { const idx = i; const a = form.approvers[idx] || {} as ApproverFormItem; const levelNumber = idx + 1; const tatRaw = a.tat ?? ''; let tatHours = 0; if (typeof tatRaw === 'number') { tatHours = a.tatType === 'days' ? tatRaw * 24 : tatRaw; } const approverEmail = a.email || ''; const approverName = (a.name && a.name.trim()) || approverEmail.split('@')[0] || `Approver ${levelNumber}`; return { levelNumber, levelName: `Level ${levelNumber}`, approverId: generateUuid(), approverEmail, approverName, tatHours: tatHours > 0 ? tatHours : 24, isFinalApprover: levelNumber === (form.approverCount || 1), }; }); // Participants -> spectators and ccList const participants = [ ...(form.spectators || []).map(p => ({ userId: generateUuid(), userEmail: p.email, userName: p.name || p.email.split('@')[0] || 'Spectator', participantType: 'SPECTATOR' as const, canComment: true, canViewDocuments: true, canDownloadDocuments: false, notificationEnabled: true, })), ...(form.ccList || []).map(p => ({ userId: generateUuid(), userEmail: p.email, userName: p.name || p.email.split('@')[0] || 'CC', participantType: 'CONSULTATION' as const, canComment: false, canViewDocuments: true, canDownloadDocuments: false, notificationEnabled: true, })), ]; const payload = { templateType: form.templateType, title: form.title, description: form.description, priority, // STANDARD | EXPRESS approvalLevels, participants: participants.length ? participants : undefined, }; const res = await apiClient.post('/workflows', payload); const data = (res.data?.data || res.data) as any; return { id: data.id || data.workflowId || '' }; } export async function createWorkflowMultipart(form: CreateWorkflowFromFormPayload, files: File[], category: 'SUPPORTING' | 'APPROVAL' | 'REFERENCE' | 'FINAL' | 'OTHER' = 'SUPPORTING') { const isUuid = (v: any) => typeof v === 'string' && /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/.test(v.trim()); const payload: any = { templateType: form.templateType, title: form.title, description: form.description, priority: form.priorityUi.toUpperCase() === 'EXPRESS' ? 'EXPRESS' : 'STANDARD', approvalLevels: Array.from({ length: form.approverCount || 1 }, (_, i) => { const a = form.approvers[i] || ({} as any); const tat = typeof a.tat === 'number' ? a.tat : 0; const approverId = (a.userId || '').trim(); if (!isUuid(approverId)) { throw new Error(`Invalid approverId for level ${i + 1}. Please pick an approver via @ search.`); } return { levelNumber: i + 1, levelName: `Level ${i + 1}`, approverId, approverEmail: a.email || '', approverName: a.name || (a.email ? a.email.split('@')[0] : `Approver ${i + 1}`), tatHours: a.tatType === 'days' ? tat * 24 : tat || 24, isFinalApprover: i + 1 === (form.approverCount || 1), }; }), }; // Pass participants if provided by caller (CreateRequest builds this) const incomingParticipants = (form as any).participants; if (Array.isArray(incomingParticipants) && incomingParticipants.length) { payload.participants = incomingParticipants; } const formData = new FormData(); formData.append('payload', JSON.stringify(payload)); formData.append('category', category); files.forEach(f => formData.append('files', f)); const res = await apiClient.post('/workflows/multipart', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }); const data = res.data?.data || res.data; return { id: data?.requestId } as any; } export async function listWorkflows(params: { page?: number; limit?: number } = {}) { const { page = 1, limit = 20 } = params; const res = await apiClient.get('/workflows', { params: { page, limit } }); return res.data?.data || res.data; } export async function listMyWorkflows(params: { page?: number; limit?: number } = {}) { const { page = 1, limit = 20 } = params; const res = await apiClient.get('/workflows/my', { params: { page, limit } }); return res.data?.data || res.data; } export async function listOpenForMe(params: { page?: number; limit?: number } = {}) { const { page = 1, limit = 20 } = params; const res = await apiClient.get('/workflows/open-for-me', { params: { page, limit } }); return res.data?.data || res.data; } export async function listClosedByMe(params: { page?: number; limit?: number } = {}) { const { page = 1, limit = 20 } = params; const res = await apiClient.get('/workflows/closed-by-me', { params: { page, limit } }); return res.data?.data || res.data; } export async function getWorkflowDetails(requestId: string) { const res = await apiClient.get(`/workflows/${requestId}/details`); return res.data?.data || res.data; } export default { createWorkflowFromForm, createWorkflowMultipart, listWorkflows, listMyWorkflows, listOpenForMe, listClosedByMe, submitWorkflow, getWorkflowDetails, }; export async function submitWorkflow(requestId: string) { const res = await apiClient.patch(`/workflows/${requestId}/submit`); return res.data?.data || res.data; } // Also export in default for convenience // Note: keeping separate named export above for tree-shaking