// components/baselineRatematrix/RateMatrixForm.tsx import React, { useState, useCallback } from 'react'; // import { useForm } from 'react-hook-form'; // import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Loader2, Save, Send, Shield, AlertTriangle } from 'lucide-react'; import { RateTypeSection } from './RateTypeSection'; import { ConfirmationDialog } from './ConfirmationDialog'; import { ValidationSummary } from './ValidationSummary'; import { LoadingScreen } from '@/ui/LoadingScreen'; import { useRateMatrixAuth } from '@/auth/hooks/useAuth'; import { useReferenceData } from '@/hooks/useReferenceData'; import { queryKeys } from '@/constants/queryKeys'; import { API_URLS } from '@/constants/apiUrls'; import { RATE_TYPES, RATE_TYPE_LABELS, REQUIRED_RATE_TYPES } from '@/constants/rateMatrixConstants'; import { rateMatrixRulesEngine } from '../../ruleEngine/rateMatrixRules'; import type { RateEntry } from './types'; const formSchema = z.object({ matrixName: z.string().min(1, 'Matrix name is required').max(200), effectiveDate: z.string().min(1, 'Effective date is required'), expiryDate: z.string().optional(), currency: z.string().min(1, 'Currency is required'), }); type FormData = z.infer; const createInitialSections = (): RateEntry[] => { return REQUIRED_RATE_TYPES.map(rateType => ({ rateType, entries: [{ validFrom: '', validTo: '', }], })); }; export function RateMatrixForm() { const [rateSections, setRateSections] = useState(createInitialSections()); const [showConfirmation, setShowConfirmation] = useState(false); const [savedMatrixId, setSavedMatrixId] = useState(null); const [validationErrors, setValidationErrors] = useState([]); const { isDirector } = useRateMatrixAuth(); const { data: referenceData, isLoading: isLoadingReference } = useReferenceData(); const queryClient = useQueryClient(); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { matrixName: '', effectiveDate: '', expiryDate: '', currency: 'USD', }, }); // Save draft mutation const saveDraftMutation = useMutation({ mutationFn: async (data: FormData & { rateSections: RateEntry[] }) => { const response = await fetch(API_URLS.RATE_MATRIX.DRAFT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Failed to save draft'); return response.json(); }, onSuccess: (data) => { setSavedMatrixId(data.id); queryClient.invalidateQueries({ queryKey: queryKeys.rateMatrix.all }); toast.success('Draft saved successfully'); }, onError: (error) => { toast.error('Failed to save draft'); }, }); // Submit for approval mutation const submitMutation = useMutation({ mutationFn: async (matrixId: string) => { const response = await fetch(API_URLS.RATE_MATRIX.SUBMIT(matrixId), { method: 'POST', }); if (!response.ok) throw new Error('Failed to submit'); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.rateMatrix.all }); toast.success('Rate matrix submitted for executive approval and locked!'); setShowConfirmation(false); }, onError: (error) => { toast.error('Failed to submit for approval'); setShowConfirmation(false); }, }); const handleValidate = useCallback(() => { const validation = rateMatrixRulesEngine.validate(rateSections); setValidationErrors([...validation.errors, ...validation.warnings]); if (validation.isValid) { toast.success('All validations passed!'); } }, [rateSections]); const handleSaveDraft = async () => { const formData = form.getValues(); await saveDraftMutation.mutateAsync({ ...formData, rateSections, }); }; const handleSubmitClick = async () => { const isFormValid = await form.trigger(); if (!isFormValid) return; const validation = rateMatrixRulesEngine.validate(rateSections); setValidationErrors([...validation.errors, ...validation.warnings]); if (!validation.isValid) { toast.error('Please fix validation errors before submitting'); return; } setShowConfirmation(true); }; const handleConfirmSubmit = async () => { const formData = form.getValues(); try { let matrixId = savedMatrixId; if (!matrixId) { const draftResult = await saveDraftMutation.mutateAsync({ ...formData, rateSections, }); matrixId = draftResult.id; } await submitMutation.mutateAsync(matrixId!); } catch (error) { // Error handling done in mutations } }; if (isLoadingReference) { return ; } if (!isDirector) { return (
Access Denied Only Directors can access the rate matrix registration.
); } return (
{/* Header */}

Baseline Rate Matrix Registration

Submit a comprehensive rate matrix for executive approval

{/* Director Warning */} Director Notice Once submitted, this matrix will be locked pending Chief Executive approval. No edits can be made by any user until authorization is granted.
e.preventDefault()}> {/* Matrix Metadata */} Matrix Information
{form.formState.errors.matrixName && (

{form.formState.errors.matrixName.message}

)}
{/* Rate Type Sections */}
{rateSections.map((section, index) => ( { const newSections = [...rateSections]; newSections[index] = updatedSection; setRateSections(newSections); }} referenceData={referenceData} /> ))}
{/* Validation Errors */} {validationErrors.length > 0 && (
)} {/* Form Actions */}
{/* Confirmation Dialog */}
); }