Re_Figma_Code/src/pages/CreateRequest/hooks/useCreateRequestHandlers.ts
2026-01-23 20:43:55 +05:30

197 lines
6.0 KiB
TypeScript

/**
* Hook for CreateRequest event handlers
*
* Contains all handler functions for:
* - Template selection
* - Step navigation
* - Document preview
*/
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { RequestTemplate, FormData, SystemPolicy } from '@/hooks/useCreateRequestForm';
import { PreviewDocument } from '../types/createRequest.types';
import { getDocumentPreviewUrl } from '@/services/workflowApi';
import { validateApprovers } from './useApproverValidation';
interface UseHandlersOptions {
selectedTemplate: RequestTemplate | null;
setSelectedTemplate: (template: RequestTemplate | null) => void;
updateFormData: (field: keyof FormData, value: any) => void;
formData: FormData;
currentStep: number;
isStepValid: () => boolean;
wizardNextStep: () => void;
wizardPrevStep: () => void;
user: any;
openValidationModal: (
type: 'error' | 'self-assign' | 'not-found',
email: string,
message: string
) => void;
systemPolicy?: SystemPolicy;
onPolicyViolation?: (violations: Array<{ type: string; message: string; currentValue?: number; maxValue?: number }>) => void;
onSubmit?: (requestData: any) => void;
goToStep?: (step: number) => void;
}
export function useCreateRequestHandlers({
selectedTemplate: _selectedTemplate,
setSelectedTemplate,
updateFormData,
formData,
currentStep,
isStepValid,
wizardNextStep,
wizardPrevStep,
user,
openValidationModal,
systemPolicy,
onPolicyViolation,
onSubmit,
// goToStep,
}: UseHandlersOptions) {
const navigate = useNavigate();
const [showTemplateModal, setShowTemplateModal] = useState(false);
const [previewDocument, setPreviewDocument] =
useState<PreviewDocument | null>(null);
// Template selection handler
const selectTemplate = (template: RequestTemplate) => {
setSelectedTemplate(template);
updateFormData('template', template.id);
updateFormData('category', template.category);
updateFormData('priority', template.priority);
const suggestedDate = new Date();
suggestedDate.setDate(suggestedDate.getDate() + template.suggestedSLA);
updateFormData('slaEndDate', suggestedDate);
// Note: For 'existing-template', the modal will open when Next is clicked (handled in nextStep)
if (template.id !== 'custom' && template.id !== 'existing-template') {
// Redirect to dedicated Admin Request flow
navigate(`/create-admin-request/${template.id}`);
}
};
const handleTemplateSelection = (templateId: string) => {
// Navigate directly to the template-specific route when template is selected from modal
if (templateId === 'claim-management') {
navigate('/claim-management');
} else if (templateId === 'vendor-payment') {
// Add vendor-payment route if it exists, otherwise fallback to onSubmit
navigate('/vendor-payment');
} else if (onSubmit) {
// Fallback to onSubmit for other template types
onSubmit({ templateType: templateId });
}
};
// Step navigation with validation
const nextStep = async () => {
if (!isStepValid()) return;
// On step 1, if "existing-template" is selected, open the template selection modal
if (currentStep === 1 && _selectedTemplate?.id === 'existing-template') {
setShowTemplateModal(true);
return;
}
if (window.innerWidth < 640) {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
// Special validation when leaving step 3 (Approval Workflow)
if (currentStep === 3) {
// Validate approval level count against system policy
if (systemPolicy && onPolicyViolation) {
const approverCount = formData.approverCount || 1;
if (approverCount > systemPolicy.maxApprovalLevels) {
onPolicyViolation([{
type: 'Maximum Approval Levels Exceeded',
message: `The request has ${approverCount} approval levels, which exceeds the maximum allowed (${systemPolicy.maxApprovalLevels}). Please reduce the number of approvers.`,
currentValue: approverCount,
maxValue: systemPolicy.maxApprovalLevels
}]);
return;
}
}
const initiatorEmail = (user as any)?.email?.toLowerCase() || '';
const validation = await validateApprovers(
formData.approvers,
initiatorEmail
);
if (!validation.success && validation.error) {
openValidationModal(
validation.error.type,
validation.error.email,
validation.error.message
);
return;
}
if (validation.validatedApprovers) {
updateFormData('approvers', validation.validatedApprovers);
}
}
wizardNextStep();
};
const prevStep = () => {
wizardPrevStep();
// Scroll to top on mobile to ensure content is visible
if (window.innerWidth < 640) {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
};
// Document preview handlers
const handlePreviewDocument = (doc: any, isExisting: boolean) => {
if (isExisting) {
const docId = doc.documentId || doc.document_id || '';
setPreviewDocument({
fileName: doc.originalFileName || doc.fileName || 'Document',
fileType:
doc.fileType || doc.file_type || 'application/octet-stream',
fileUrl: getDocumentPreviewUrl(docId),
fileSize: Number(doc.fileSize || doc.file_size || 0),
documentId: docId,
});
} else {
const fileUrl = URL.createObjectURL(doc);
setPreviewDocument({
fileName: doc.name,
fileType: doc.type || 'application/octet-stream',
fileUrl: fileUrl,
fileSize: doc.size,
file: doc,
});
}
};
const closePreview = () => {
if (previewDocument?.fileUrl && previewDocument?.file) {
URL.revokeObjectURL(previewDocument.fileUrl);
}
setPreviewDocument(null);
};
return {
showTemplateModal,
setShowTemplateModal,
previewDocument,
selectTemplate,
handleTemplateSelection,
nextStep,
prevStep,
handlePreviewDocument,
closePreview,
};
}