import { AlertTriangle, Calendar, Plus, Eye, XCircle } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import { useState, useEffect } from 'react'; import { API } from '@/api/API'; import { slaService, SlaStatusSnapshot } from '@/services/sla.service'; import { SlaBadge } from '@/components/sla/SlaBadge'; import { formatDateTime } from '@/components/ui/utils'; import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination"; import { User } from '@/lib/mock-data'; import { toast } from 'sonner'; import { formatTerminationStatusLabel, LAST_WORKING_DAY_LABEL, PROPOSED_LAST_WORKING_DAY_LABEL } from '@/lib/terminationDisplay'; interface TerminationPageProps { currentUser: User | null; onViewDetails: (id: string) => void; } const getSeverityColor = (severity: string) => { switch (severity) { case 'Critical': return 'bg-red-100 text-red-700 border-red-300'; case 'High': return 'bg-orange-100 text-orange-700 border-orange-300'; case 'Medium': return 'bg-yellow-100 text-yellow-700 border-yellow-300'; case 'Low': return 'bg-blue-100 text-blue-700 border-blue-300'; default: return 'bg-slate-100 text-slate-700 border-slate-300'; } }; const getStatusColor = (status: string) => { if (status.includes('Approved') || status.includes('Terminated')) return 'bg-green-100 text-green-700 border-green-300'; if (status.includes('Review') || status.includes('Pending')) return 'bg-yellow-100 text-yellow-700 border-yellow-300'; if (status.includes('Rejected')) return 'bg-red-100 text-red-700 border-red-300'; return 'bg-blue-100 text-blue-700 border-blue-300'; }; const formatStatus = formatTerminationStatusLabel; export function TerminationPage({ currentUser, onViewDetails }: TerminationPageProps) { const [isDialogOpen, setIsDialogOpen] = useState(false); const [dealers, setDealers] = useState([]); const [selectedDealerId, setSelectedDealerId] = useState(''); const [dialogDataLoading, setDialogDataLoading] = useState(false); const [dealerCode, setDealerCode] = useState(''); const [autoFilledData, setAutoFilledData] = useState(null); const [terminations, setTerminations] = useState([]); const [slaById, setSlaById] = useState>({}); const [loading, setLoading] = useState(true); const [currentPage, setCurrentPage] = useState(1); const [paginationMeta, setPaginationMeta] = useState(null); const [activeTab, setActiveTab] = useState('all'); const itemsPerPage = 10; const [formData, setFormData] = useState({ terminationCategory: '', reason: '', proposedLwd: '', comments: '', documents: [] as File[] }); const fetchTerminations = async () => { setLoading(true); try { const response = await API.getTerminations({ page: currentPage, limit: itemsPerPage, status: activeTab === 'all' ? undefined : activeTab }); const data = response.data as any; if (data?.success) { setTerminations(data.terminations); setPaginationMeta(data.meta); const rows = data.terminations || []; if (rows.length) { slaService .getBatchStatus(rows.map((t: any) => ({ entityType: 'termination', entityId: t.id }))) .then((slaRes) => { if (slaRes?.success) { const map: Record = {}; rows.forEach((t: any) => { map[t.id] = slaRes.data[`termination:${t.id}`] ?? null; }); setSlaById(map); } }) .catch(() => setSlaById({})); } else { setSlaById({}); } } } catch (error) { console.error('Error fetching terminations:', error); toast.error('Failed to fetch termination requests'); } finally { setLoading(false); } }; useEffect(() => { fetchTerminations(); }, [currentPage, activeTab]); const handleTabChange = (val: string) => { setActiveTab(val); setCurrentPage(1); }; useEffect(() => { if (!isDialogOpen || !canCreateTermination) return; let cancelled = false; (async () => { try { setDialogDataLoading(true); const response = await API.getDealers({ onboarded: 'true', activeOnly: 'true' }); const data = response.data as any; if (!cancelled && data?.success) { const activeDealers = (Array.isArray(data.data) ? data.data : []).filter((dealer: any) => { const dealerStatus = String(dealer?.status || '').toLowerCase(); const userStatus = String(dealer?.user?.status || '').toLowerCase(); return dealerStatus === 'active' && dealer?.user?.isActive && userStatus === 'active'; }); setDealers(activeDealers); } } catch (error) { if (!cancelled) { console.error('Error fetching dealers:', error); toast.error('Failed to load dealer list'); } } finally { if (!cancelled) { setDialogDataLoading(false); } } })(); return () => { cancelled = true; }; }, [isDialogOpen]); const mapDealerToFormData = (dealer: any) => ({ id: dealer.id, dealerId: dealer.id, dealerCode: dealer.dealerCode?.dealerCode || '', legalName: dealer.legalName || 'N/A', businessName: dealer.businessName || 'N/A', gstNumber: dealer.gstNumber || 'N/A', address: dealer.registeredAddress || dealer.application?.preferredLocation || 'N/A', city: dealer.application?.city || 'N/A', state: dealer.application?.state || 'N/A', email: dealer.user?.email || 'N/A', phoneNumber: dealer.user?.mobileNumber || 'N/A' }); const handleDealerSelect = (dealerId: string) => { setSelectedDealerId(dealerId); const dealer = dealers.find((row: any) => String(row.id) === String(dealerId)); if (!dealer) { setDealerCode(''); setAutoFilledData(null); return; } const mappedDealer = mapDealerToFormData(dealer); setDealerCode(mappedDealer.dealerCode); setAutoFilledData(mappedDealer); }; const handleDealerCodeChange = (code: string) => { setDealerCode(code); const normalizedCode = code.trim().toLowerCase(); if (!normalizedCode) { setSelectedDealerId(''); setAutoFilledData(null); return; } const matchedDealer = dealers.find((dealer: any) => String(dealer.dealerCode?.dealerCode || '').toLowerCase() === normalizedCode ); if (!matchedDealer) { setSelectedDealerId(''); setAutoFilledData(null); return; } setSelectedDealerId(String(matchedDealer.id)); setAutoFilledData(mapDealerToFormData(matchedDealer)); }; const isSuperAdmin = currentUser?.role === 'Super Admin'; const isPresentationMandatory = !isSuperAdmin; const isPptFile = (file: File) => { const name = file.name.toLowerCase(); return name.endsWith('.ppt') || name.endsWith('.pptx'); }; const handleFilesPicked = (files: FileList | null, inputEl?: HTMLInputElement | null) => { if (!files || files.length === 0) return; setFormData((prev) => { const existing = prev.documents; const seen = new Set(existing.map((f) => `${f.name}::${f.size}`)); const additions: File[] = []; Array.from(files).forEach((file) => { const key = `${file.name}::${file.size}`; if (!seen.has(key)) { seen.add(key); additions.push(file); } }); return { ...prev, documents: [...existing, ...additions] }; }); if (inputEl) inputEl.value = ''; }; const removeDocumentAt = (index: number) => { setFormData({ ...formData, documents: formData.documents.filter((_, i) => i !== index) }); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!autoFilledData) { toast.error('Please select a dealer'); return; } if (isPresentationMandatory) { if (formData.documents.length === 0) { toast.error('Please upload at least one Presentation (.ppt or .pptx)'); return; } if (!formData.documents.some(isPptFile)) { toast.error('At least one PowerPoint file (.ppt or .pptx) is required'); return; } } try { const dealerId = autoFilledData.dealerId || autoFilledData.id; if (!dealerId) { toast.error('Dealer record not found for the selected dealer'); return; } let requestBody: any; if (formData.documents.length > 0) { const fd = new FormData(); fd.append('dealerId', String(dealerId)); fd.append('category', formData.terminationCategory); fd.append('reason', formData.reason); fd.append('proposedLwd', formData.proposedLwd); fd.append('comments', formData.comments); formData.documents.forEach((file) => fd.append('files', file)); requestBody = fd; } else { requestBody = { dealerId, category: formData.terminationCategory, reason: formData.reason, proposedLwd: formData.proposedLwd, comments: formData.comments }; } const response = await API.createTermination(requestBody); const data = response.data as any; if (data?.success) { toast.success(formData.documents.length > 0 ? 'Termination request and documents submitted' : 'Termination request submitted successfully'); setIsDialogOpen(false); fetchTerminations(); // Reset form setSelectedDealerId(''); setDealerCode(''); setDealers([]); setAutoFilledData(null); setFormData({ terminationCategory: '', reason: '', proposedLwd: '', comments: '', documents: [] }); } } catch (error: any) { console.error('Error submitting termination:', error); toast.error(error.response?.data?.message || 'Failed to submit termination request'); } }; const allowedRoles = ['DD Lead', 'ASM', 'DD Admin', 'DD AM', 'Super Admin']; const canCreateTermination = currentUser?.role && allowedRoles.includes(currentUser.role); // Map terminations to tab-specific views (already filtered by backend, but need variables for render) const openRequests = activeTab === 'open' || activeTab === 'all' ? terminations : []; const completedRequests = activeTab === 'completed' || activeTab === 'all' ? terminations : []; return (
{/* Warning Alert */} {/* Header Stats */}
All Cases {paginationMeta?.total || 0}

Total Cases

Open {activeTab === 'open' ? paginationMeta?.total || 0 : '...'}

Requires Your Action

Completed {activeTab === 'completed' ? paginationMeta?.total || 0 : '...'}

Finalized

{/* Main Content */}
Termination Requests Manage dealer termination proceedings and legal compliance
{canCreateTermination && ( Create Termination Request Fill in the details to create a new termination request
{/* Dealer selection */}
{/* Optional dealer code lookup */}
handleDealerCodeChange(e.target.value)} placeholder="Type dealer code to auto-select" required />
{/* Auto-filled data */} {autoFilledData && (

{autoFilledData.legalName || 'N/A'}

{autoFilledData.businessName || 'N/A'}

{autoFilledData.gstNumber || 'N/A'}

{autoFilledData.address}

{autoFilledData.city}, {autoFilledData.state}

{autoFilledData.dealerCode || 'N/A'}

{autoFilledData.email} / {autoFilledData.phoneNumber}

)} {/* Date fields */}
setFormData({...formData, proposedLwd: e.target.value})} required />
setFormData({...formData, reason: e.target.value})} placeholder="Primary reason for termination" required />