import React, { useState, useEffect, useCallback, useRef } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Checkbox } from '@/components/ui/checkbox'; import { Badge } from '@/components/ui/badge'; import { Plus, Edit2, Trash2, ShieldCheck, Layers, Settings2, Search, ChevronLeft, ChevronRight, Loader2, Database } from 'lucide-react'; import { onboardingService } from '@/services/onboarding.service'; import { toast } from 'sonner'; export const DocumentConfigManagement: React.FC = () => { const [configs, setConfigs] = useState([]); const [loading, setLoading] = useState(true); const [backgroundLoading, setBackgroundLoading] = useState(false); const [showDialog, setShowDialog] = useState(false); const [editingConfig, setEditingConfig] = useState(null); // Metadata from backend const [modules, setModules] = useState([]); const [stagesMap, setStagesMap] = useState>({}); const [metadataLoading, setMetadataLoading] = useState(true); // Pagination, Search & Module filter state const [search, setSearch] = useState(''); const [page, setPage] = useState(1); const [limit] = useState(10); const [selectedModule, setSelectedModule] = useState(''); const [pagination, setPagination] = useState({ total: 0, pages: 1 }); const isFirstLoad = useRef(true); const [formData, setFormData] = useState({ documentType: '', stageCode: 'General', allowedRoles: [] as string[], isMandatory: false, isActive: true, module: '' }); const ROLE_LIST = [ 'DD-ZM', 'RBM', 'DD', 'ZBH', 'DD Lead', 'DD Head', 'NBH', 'DD Admin', 'Legal Admin', 'Super Admin', 'DD AM', 'FDD', 'DDL', 'Finance', 'Finance Admin', 'Dealer', 'ARCHITECTURE' ]; // Fetch Metadata (Modules & Stages) from Backend useEffect(() => { const fetchMetadata = async () => { try { const res = await onboardingService.getDocumentConfigMetadata(); if (res) { setModules(res.modules || []); setStagesMap(res.stages || {}); if (res.modules?.length > 0) { setSelectedModule(res.modules[0]); setFormData(prev => ({ ...prev, module: res.modules[0] })); } } } catch (error) { toast.error('Failed to load system metadata'); } finally { setMetadataLoading(false); } }; fetchMetadata(); }, []); const fetchConfigs = useCallback(async () => { if (!selectedModule) return; if (isFirstLoad.current) { setLoading(true); } else { setBackgroundLoading(true); } try { const res: any = await onboardingService.getDocumentConfigs({ search, page, limit, module: selectedModule, isAdminView: true }); if (res && res.pagination) { setConfigs(res.data || []); setPagination(res.pagination); } else if (Array.isArray(res)) { setConfigs(res); setPagination({ total: res.length, pages: 1 }); } } catch (error) { console.error('Fetch Configs Error:', error); if (!isFirstLoad.current) { toast.error('Failed to sync configuration database'); } } finally { setLoading(false); setBackgroundLoading(false); isFirstLoad.current = false; } }, [search, page, limit, selectedModule]); useEffect(() => { const handler = setTimeout(() => { fetchConfigs(); }, 300); return () => clearTimeout(handler); }, [fetchConfigs]); const handleSave = async () => { try { if (editingConfig) { await onboardingService.updateDocumentConfig(editingConfig.id, formData); toast.success('Configuration updated'); } else { await onboardingService.createDocumentConfig(formData); toast.success('Configuration created'); } setShowDialog(false); fetchConfigs(); } catch (error) { toast.error('Failed to save configuration'); } }; const handleDelete = async (id: string) => { if (!window.confirm('Are you sure you want to delete this configuration?')) return; try { await onboardingService.deleteDocumentConfig(id); toast.success('Configuration deleted'); fetchConfigs(); } catch (error) { toast.error('Failed to delete configuration'); } }; const openCreate = () => { setEditingConfig(null); setFormData({ documentType: '', stageCode: 'General', allowedRoles: [], isMandatory: false, isActive: true, module: selectedModule }); setShowDialog(true); }; const openEdit = (config: any) => { setEditingConfig(config); setFormData({ documentType: config.documentType, stageCode: config.stageCode, allowedRoles: config.allowedRoles || [], isMandatory: config.isMandatory as boolean, isActive: config.isActive as boolean, module: config.module || 'ONBOARDING' }); setShowDialog(true); }; const toggleRole = (role: string) => { setFormData(prev => ({ ...prev, allowedRoles: prev.allowedRoles.includes(role) ? prev.allowedRoles.filter(r => r !== role) : [...prev.allowedRoles, role] })); }; if (metadataLoading) { return (

Connecting to Governance Engine...

); } return ( {backgroundLoading && (
)}
Governance Matrix

Baseline Document Rules (Synced from Backend)

{ setSearch(e.target.value); setPage(1); }} className="pl-10 h-10 rounded-xl bg-white border-slate-200 focus:ring-red-500 shadow-sm font-medium" />
{loading ? (
Syncing Policies...
) : null} Policy Detail Process Stage Module Stakeholders Compliance Rules Action {!loading && configs.length === 0 ? (

No policies found for {selectedModule}

Try adjusting your filters or search term

) : configs.map((config) => (
{config.documentType}
{config.stageCode}
{config.module?.replace(/_/g, ' ')}
{config.allowedRoles?.length > 0 ? ( <> {config.allowedRoles.slice(0, 2).map((role: string) => ( {role} ))} {config.allowedRoles.length > 2 && ( +{config.allowedRoles.length - 2} )} ) : ( Inherited )}
{config.isMandatory && ( BLOCKING )} {!config.isActive && ( DORMANT )} {config.isActive && !config.isMandatory && ( OPTIONAL )}
))}
{/* Pagination Controls */}
Dataset Index {configs.length > 0 ? (page - 1) * limit + 1 : 0} - {Math.min(page * limit, pagination.total)} Total Found {pagination.total}
{page} / {pagination.pages}
{editingConfig ? 'Modify Policy' : 'Publish Rule'}

Configuring {formData.module} Lifecycle

setFormData(prev => ({ ...prev, documentType: e.target.value }))} placeholder="e.g., PAN Card, Blueprint" className="h-12 rounded-xl border-slate-200 focus:ring-red-500 shadow-sm font-black text-sm uppercase placeholder:font-bold placeholder:text-slate-300" />
{ROLE_LIST.map((role: string) => (
toggleRole(role)} > toggleRole(role)} className="w-4 h-4 data-[state=checked]:bg-re-red data-[state=checked]:border-re-red rounded" />
))}
setFormData(prev => ({ ...prev, isMandatory: !prev.isMandatory }))} > setFormData(prev => ({ ...prev, isMandatory: !!checked }))} className="w-5 h-5 border-slate-300 data-[state=checked]:bg-re-red data-[state=checked]:border-re-red rounded-md" />

Blocking Next Stage Action

setFormData(prev => ({ ...prev, isActive: !prev.isActive }))} > setFormData(prev => ({ ...prev, isActive: !!checked }))} className="w-5 h-5 border-slate-300 data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600 rounded-md" />

Visible To Active Streams

); };