import { useState, useEffect } from 'react'; import { useAuth } from '@/contexts/AuthContext'; import { getWorkflowDetails } from '@/services/workflowApi'; import { getAllConfigurations, AdminConfiguration } from '@/services/adminApi'; export interface RequestTemplate { id: string; name: string; description: string; category: string; icon: React.ComponentType; estimatedTime: string; commonApprovers: string[]; suggestedSLA: number; priority: 'high' | 'medium' | 'low'; fields: { amount?: boolean; vendor?: boolean; timeline?: boolean; impact?: boolean; }; } export interface FormData { template: string; title: string; description: string; category: string; priority: string; urgency: string; businessImpact: string; amount: string; currency: string; vendor: string; timeline: string; slaTemplate: string; slaHours: number; customSlaHours: number; slaEndDate: Date | undefined; expectedCompletionDate: Date | undefined; breachEscalation: boolean; reminderSchedule: '25' | '50' | '75'; workflowType: 'sequential' | 'parallel'; requiresAllApprovals: boolean; escalationEnabled: boolean; reminderEnabled: boolean; minimumLevel: number; maxLevel: number; approvers: any[]; approverCount: number; spectators: any[]; ccList: any[]; invitedUsers: any[]; allowComments: boolean; allowDocumentUpload: boolean; documents: File[]; tags: string[]; relatedRequests: string[]; costCenter: string; project: string; } const initialFormData: FormData = { template: '', title: '', description: '', category: '', priority: '', urgency: '', businessImpact: '', amount: '', currency: 'USD', vendor: '', timeline: '', slaTemplate: '', slaHours: 0, customSlaHours: 0, slaEndDate: undefined, expectedCompletionDate: undefined, breachEscalation: true, reminderSchedule: '50', workflowType: 'sequential', requiresAllApprovals: true, escalationEnabled: true, reminderEnabled: true, minimumLevel: 1, maxLevel: 1, approvers: [], approverCount: 1, spectators: [], ccList: [], invitedUsers: [], allowComments: true, allowDocumentUpload: true, documents: [], tags: [], relatedRequests: [], costCenter: '', project: '' }; export interface SystemPolicy { maxApprovalLevels: number; maxParticipants: number; allowSpectators: boolean; maxSpectators: number; } export interface DocumentPolicy { maxFileSizeMB: number; allowedFileTypes: string[]; } /** * Custom Hook: useCreateRequestForm * * Purpose: Manages form state, policies, and draft loading for CreateRequest * * Responsibilities: * - Manages form data state * - Loads system and document policies * - Handles draft loading in edit mode * - Provides form data update functions */ export function useCreateRequestForm( isEditing: boolean, editRequestId: string, templates: RequestTemplate[] ) { const { user } = useAuth(); const [formData, setFormData] = useState(initialFormData); const [selectedTemplate, setSelectedTemplate] = useState(null); const [loadingDraft, setLoadingDraft] = useState(isEditing); const [systemPolicy, setSystemPolicy] = useState({ maxApprovalLevels: 10, maxParticipants: 50, allowSpectators: true, maxSpectators: 20 }); const [documentPolicy, setDocumentPolicy] = useState({ maxFileSizeMB: 10, allowedFileTypes: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'jpg', 'jpeg', 'png', 'gif'] }); const [existingDocuments, setExistingDocuments] = useState([]); // Load policies on mount useEffect(() => { const loadPolicies = async () => { try { // Load document policy const docConfigs = await getAllConfigurations('DOCUMENT_POLICY'); const docConfigMap: Record = {}; docConfigs.forEach((c: AdminConfiguration) => { docConfigMap[c.configKey] = c.configValue; }); const maxFileSizeMB = parseInt(docConfigMap['MAX_FILE_SIZE_MB'] || '10'); const allowedFileTypesStr = docConfigMap['ALLOWED_FILE_TYPES'] || 'pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif'; const allowedFileTypes = allowedFileTypesStr.split(',').map(ext => ext.trim().toLowerCase()); setDocumentPolicy({ maxFileSizeMB, allowedFileTypes }); // Load system policy const workflowConfigs = await getAllConfigurations('WORKFLOW_SHARING'); const tatConfigs = await getAllConfigurations('TAT_SETTINGS'); const allConfigs = [...workflowConfigs, ...tatConfigs]; const configMap: Record = {}; allConfigs.forEach((c: AdminConfiguration) => { configMap[c.configKey] = c.configValue; }); setSystemPolicy({ maxApprovalLevels: parseInt(configMap['MAX_APPROVAL_LEVELS'] || '10'), maxParticipants: parseInt(configMap['MAX_PARTICIPANTS_PER_REQUEST'] || '50'), allowSpectators: configMap['ALLOW_ADD_SPECTATOR']?.toLowerCase() === 'true', maxSpectators: parseInt(configMap['MAX_SPECTATORS_PER_REQUEST'] || '20') }); } catch (error) { console.error('Failed to load policies:', error); } }; loadPolicies(); }, []); // Load draft data when in edit mode useEffect(() => { if (!isEditing || !editRequestId) return; let mounted = true; (async () => { try { setLoadingDraft(true); const details = await getWorkflowDetails(editRequestId); if (!mounted || !details) return; const wf = details.workflow || {}; const approvals = Array.isArray(details.approvals) ? details.approvals : []; const participants = Array.isArray(details.participants) ? details.participants : []; const documents = Array.isArray(details.documents) ? details.documents.filter((d: any) => !d.isDeleted) : []; // Store existing documents for tracking setExistingDocuments(documents); // Map priority const priority = (wf.priority || '').toString().toLowerCase(); const priorityMap: Record = { 'standard': 'standard', 'express': 'express' }; // Map template type const templateType = wf.templateType === 'TEMPLATE' ? 'existing-template' : 'custom'; const template = templates.find(t => t.id === templateType) || templates[0] || null; setSelectedTemplate(template); // Map approvers const mappedApprovers = approvals .sort((a: any, b: any) => (a.levelNumber || 0) - (b.levelNumber || 0)) .map((approval: any) => { const tatHours = Number(approval.tatHours || 24); const tatDays = Math.floor(tatHours / 24); const tatHoursRemainder = tatHours % 24; return { id: approval.approverId || `temp-${approval.levelNumber}`, name: approval.approverName || approval.approverEmail || '', email: approval.approverEmail || '', role: approval.levelName || `Level ${approval.levelNumber}`, department: '', avatar: (approval.approverName || approval.approverEmail || 'XX').substring(0, 2).toUpperCase(), level: approval.levelNumber || 1, canClose: false, tat: tatDays > 0 ? tatDays : tatHoursRemainder, tatType: tatDays > 0 ? 'days' as const : 'hours' as const, userId: approval.approverId }; }); // Map spectators const mappedSpectators = participants .filter((p: any) => { const pt = (p.participantType || p.participant_type || '').toString().toUpperCase().trim(); const isSpectator = pt === 'SPECTATOR'; if (!isSpectator) return false; const hasEmail = !!(p.userEmail || p.user_email || p.email); return hasEmail; }) .map((p: any, index: number) => { const userId = p.userId || p.user_id || p.id; const userName = p.userName || p.user_name || p.name || ''; const userEmail = p.userEmail || p.user_email || p.email || ''; const avatarText = userName || userEmail || 'XX'; const avatar = avatarText .split(' ') .map((s: string) => s[0]) .filter(Boolean) .join('') .slice(0, 2) .toUpperCase(); return { id: userId || `spectator-${editRequestId}-${index}-${Date.now()}`, userId: userId, name: userName || userEmail || 'Spectator', email: userEmail, role: 'Spectator', department: p.department || '', avatar: avatar, level: 1, canClose: false }; }); setFormData(prev => ({ ...prev, template: templateType, title: wf.title || '', description: wf.description || '', priority: priorityMap[priority] || 'standard', approvers: mappedApprovers, approverCount: mappedApprovers.length || 1, spectators: mappedSpectators, maxLevel: Math.max(...mappedApprovers.map((a: any) => a.level || 1), 1) })); } catch (error) { console.error('Failed to load draft:', error); } finally { if (mounted) setLoadingDraft(false); } })(); return () => { mounted = false; }; }, [isEditing, editRequestId, templates]); const updateFormData = (field: keyof FormData, value: any) => { setFormData(prev => ({ ...prev, [field]: value })); }; return { formData, setFormData, updateFormData, selectedTemplate, setSelectedTemplate, loadingDraft, systemPolicy, documentPolicy, existingDocuments, setExistingDocuments }; }