From bc2b7faf087e51e5d8d6a6dabad0902027c01542 Mon Sep 17 00:00:00 2001 From: laxman h Date: Wed, 15 Apr 2026 21:13:39 +0530 Subject: [PATCH] ui and extra inputs fwhile creeating region zone, assigning zm are removed --- src/api/API.ts | 1 + src/components/admin/UserManagementPage.tsx | 3 +- .../applications/AllApplicationsPage.tsx | 8 +- .../applications/ApplicationDetails.tsx | 22 ++++- src/components/applications/MasterPage.tsx | 98 +++++++++--------- .../applications/MasterPage/ASMDialog.tsx | 30 ------ .../applications/MasterPage/AddRoleDialog.tsx | 99 +++++++++++++++++++ .../applications/MasterPage/DDLeadDialog.tsx | 28 ------ .../MasterPage/LocationDialog.tsx | 54 +++++++--- .../applications/MasterPage/RegionDialog.tsx | 18 +--- .../applications/MasterPage/ZMDialog.tsx | 23 ----- .../applications/MasterPage/ZoneDialog.tsx | 11 ++- src/hooks/useMasterData.ts | 31 ++++-- src/services/master.service.ts | 4 + 14 files changed, 251 insertions(+), 179 deletions(-) create mode 100644 src/components/applications/MasterPage/AddRoleDialog.tsx diff --git a/src/api/API.ts b/src/api/API.ts index aacac4a..bfc4ac5 100644 --- a/src/api/API.ts +++ b/src/api/API.ts @@ -9,6 +9,7 @@ export const API = { // Master module routes getRoles: () => client.get('/admin/roles'), + createRole: (data: any) => client.post('/admin/roles', data), getPermissions: () => client.get('/admin/permissions'), updateRole: (id: string, data: any) => client.put(`/admin/roles/${id}`, data), diff --git a/src/components/admin/UserManagementPage.tsx b/src/components/admin/UserManagementPage.tsx index e081512..245e8bb 100644 --- a/src/components/admin/UserManagementPage.tsx +++ b/src/components/admin/UserManagementPage.tsx @@ -490,7 +490,8 @@ export function UserManagementPage() { {/* Geographical Assignments */}
-

Geographical Assignments

+

Geographical Assignments

+

Optional: you can create users without territory mapping and assign later.

diff --git a/src/components/applications/AllApplicationsPage.tsx b/src/components/applications/AllApplicationsPage.tsx index 1e355aa..4153e17 100644 --- a/src/components/applications/AllApplicationsPage.tsx +++ b/src/components/applications/AllApplicationsPage.tsx @@ -174,7 +174,7 @@ export function AllApplicationsPage({ onViewDetails, initialFilter = 'all' }: Al ]; const getStatusColor = (status: ApplicationStatus) => { - const colors: Record = { + const colors: Partial> = { 'Submitted': 'bg-blue-100 text-blue-800', 'Questionnaire Pending': 'bg-yellow-100 text-yellow-800', 'Questionnaire Completed': 'bg-cyan-100 text-cyan-800', @@ -219,12 +219,8 @@ export function AllApplicationsPage({ onViewDetails, initialFilter = 'all' }: Al 'Security Details Approved': 'bg-green-100 text-green-800', 'Security Details': 'bg-amber-100 text-amber-800', 'LOA Issued': 'bg-pink-100 text-pink-800', - 'EOR Complete': 'bg-violet-100 text-violet-800', - 'Level 1 Approved': 'bg-green-100 text-green-800', - 'Level 2 Approved': 'bg-green-100 text-green-800', - 'Level 3 Approved': 'bg-green-100 text-green-800', }; - return (statusColors as any)[status] || 'bg-gray-100 text-gray-800'; + return colors[status] || 'bg-gray-100 text-gray-800'; }; return ( diff --git a/src/components/applications/ApplicationDetails.tsx b/src/components/applications/ApplicationDetails.tsx index e7a93fa..e1a7108 100644 --- a/src/components/applications/ApplicationDetails.tsx +++ b/src/components/applications/ApplicationDetails.tsx @@ -1875,6 +1875,8 @@ export const ApplicationDetails = () => { ].includes(application.status); const isLoaLocked = application.status === 'LOA Pending' && getDeposit('FIRST_FILL')?.status !== 'Verified'; + const isSecurityDetailsLocked = ['Security Details', 'Payment Pending'].includes(application.status) && + getDeposit('SECURITY_DEPOSIT')?.status !== 'Verified'; const isFinalState = application.status === 'Onboarded' || application.status === 'Rejected'; // 2. Interview Specific Logic @@ -1903,15 +1905,18 @@ export const ApplicationDetails = () => { // 5. Final Permission Bits const isDecisionMade = (activeInterviewForUser ? hasMadeInterviewDecision : false) || hasMadeStageDecision; - const canApproveReject = !isLoaLocked && !isFinalState && !isDecisionMade && ( + const canApproveReject = !isFinalState && !isDecisionMade && ( (!!activeInterviewForUser && !!hasSubmittedFeedback) || (isAdminRole && isAdministrativeStage && sequenceMet && (!['EOR In Progress', 'Inauguration', 'Approved'].includes(application.status) || eorProgress === 100)) ); + const canApprove = canApproveReject && !isLoaLocked && !isSecurityDetailsLocked; + const canReject = canApproveReject && !isLoaLocked; return { - canApprove: canApproveReject, - canReject: canApproveReject, + canApprove, + canReject, isLoaLocked, + isSecurityDetailsLocked, showDecisionMessage: isDecisionMade && (!isAdministrativeStage || hasMadeStageDecision), canSchedule: ['DD Admin', 'Super Admin', 'DD AM', 'ASM'].includes(currentUser.role) && !isFinalState && @@ -3643,6 +3648,17 @@ export const ApplicationDetails = () => { )} + {permissions.isSecurityDetailsLocked && ( + + + Security Details approval locked + + Finance must verify the Security Deposit before this stage can be approved. + You can still use Reject if needed. + + + )} + {['Security Details', 'Payment Pending'].includes(application.status) && ( diff --git a/src/components/applications/MasterPage.tsx b/src/components/applications/MasterPage.tsx index 5e622c5..60a8d81 100644 --- a/src/components/applications/MasterPage.tsx +++ b/src/components/applications/MasterPage.tsx @@ -21,6 +21,7 @@ import { UserManagementTable } from './MasterPage/UserManagementTable'; import { SLAConfiguration } from './MasterPage/SLAConfiguration'; import { RolePermissions } from './MasterPage/RolePermissions'; import { RoleDialog } from './MasterPage/RoleDialog'; +import { AddRoleDialog } from './MasterPage/AddRoleDialog'; import { EmailTemplates } from './MasterPage/EmailTemplates'; import { LocationManagement } from './MasterPage/LocationManagement'; import { ASMDialog } from './MasterPage/ASMDialog'; @@ -40,6 +41,7 @@ export const MasterPage: React.FC = () => { const { fetchInitialData, fetchAreas } = useMasterData(); const { asms, zonalManagerMappings, ddLeads, + allStates, allDistricts, users, roles, @@ -60,9 +62,6 @@ export const MasterPage: React.FC = () => { // Form State (ASM) const [editingASMId, setEditingASMId] = useState(null); const [asmManagerId, setAsmManagerId] = useState(''); - const [asmName, setAsmName] = useState(''); - const [asmCode, setAsmCode] = useState(''); - const [asmEmployeeId, setAsmEmployeeId] = useState(''); const [asmStatus, setAsmStatus] = useState<'active' | 'inactive'>('active'); const [selectedASMZone, setSelectedASMZone] = useState(''); const [selectedASMRegion, setSelectedASMRegion] = useState(''); @@ -74,9 +73,6 @@ export const MasterPage: React.FC = () => { const [showZMDialog, setShowZMDialog] = useState(false); const [editingZMId, setEditingZMId] = useState(null); const [zmManagerId, setZmManagerId] = useState(''); - const [zmName, setZmName] = useState(''); - const [zmCode, setZmCode] = useState(''); - const [zmEmployeeId, setZmEmployeeId] = useState(''); const [zmStatus, setZmStatus] = useState<'active' | 'inactive'>('active'); const [selectedZMZone, setSelectedZMZone] = useState(''); const [selectedZMRegions, setSelectedZMRegions] = useState([]); @@ -85,15 +81,13 @@ export const MasterPage: React.FC = () => { const [showDDLeadDialog, setShowDDLeadDialog] = useState(false); const [editingDDLeadId, setEditingDDLeadId] = useState(null); const [ddLeadManagerId, setDdLeadManagerId] = useState(''); - const [ddLeadName, setDdLeadName] = useState(''); - const [ddLeadCode, setDdLeadCode] = useState(''); - const [ddLeadEmployeeId, setDdLeadEmployeeId] = useState(''); const [ddLeadStatus, setDdLeadStatus] = useState<'active' | 'inactive'>('active'); const [selectedDDLeadZones, setSelectedDDLeadZones] = useState([]); // Role Management State const [showRoleDialog, setShowRoleDialog] = useState(false); const [editingRole, setEditingRole] = useState(null); + const [showAddRoleDialog, setShowAddRoleDialog] = useState(false); // Form State (Zone) const [editingZoneId, setEditingZoneId] = useState(null); @@ -105,7 +99,6 @@ export const MasterPage: React.FC = () => { // Form State (Region) const [editingRegionId, setEditingRegionId] = useState(null); const [regionName, setRegionName] = useState(''); - const [regionCode, setRegionCode] = useState(''); const [regionDescription, setRegionDescription] = useState(''); const [selectedRegionZone, setSelectedRegionZone] = useState(''); const [regionalManagerId, setRegionalManagerId] = useState(''); @@ -176,7 +169,6 @@ export const MasterPage: React.FC = () => { const payload = { userId: asmManagerId, roleCode: asmRoleCode, - asmCode, districts: selectedASMDistricts, status: asmStatus }; @@ -197,9 +189,6 @@ export const MasterPage: React.FC = () => { const handleEditASM = (asm: any) => { setEditingASMId(asm.id); setAsmManagerId(asm.id); - setAsmName(asm.name); - setAsmCode(asm.asmCode); - setAsmEmployeeId(asm.employeeId); setAsmStatus(asm.status.toLowerCase() as 'active' | 'inactive'); setSelectedASMZone(asm.zoneId); setSelectedASMRegion(asm.regionId); @@ -212,9 +201,6 @@ export const MasterPage: React.FC = () => { const handleEditZM = (zm: any) => { setEditingZMId(zm.id); setZmManagerId(zm.id); - setZmName(zm.name); - setZmCode(zm.zmCode || zm.code || ''); - setZmEmployeeId(zm.employeeId || ''); setZmStatus(zm.status?.toLowerCase() === 'active' ? 'active' : 'inactive'); setSelectedZMZone(zm.zoneId || ''); setSelectedZMRegions(zm.assignedRegionIds || []); @@ -224,9 +210,6 @@ export const MasterPage: React.FC = () => { const handleEditDDLead = (lead: any) => { setEditingDDLeadId(lead.id); setDdLeadManagerId(lead.id); - setDdLeadName(lead.name); - setDdLeadCode(lead.leadCode || ''); - setDdLeadEmployeeId(lead.employeeId || ''); setDdLeadStatus(lead.status?.toLowerCase() === 'active' ? 'active' : 'inactive'); setSelectedDDLeadZones(lead.assignedZoneIds || []); setShowDDLeadDialog(true); @@ -240,7 +223,6 @@ export const MasterPage: React.FC = () => { try { const payload = { userId: zmManagerId, - zmCode, zoneId: selectedZMZone, regionIds: selectedZMRegions, status: zmStatus @@ -268,7 +250,6 @@ export const MasterPage: React.FC = () => { try { const payload = { userId: ddLeadManagerId, - leadCode: ddLeadCode, zoneIds: selectedDDLeadZones, status: ddLeadStatus }; @@ -316,7 +297,6 @@ export const MasterPage: React.FC = () => { const payload = { ...(editingRegionId ? { id: editingRegionId } : {}), name: regionName, - code: regionCode, description: regionDescription, parentId: selectedRegionZone, managerId: regionalManagerId, @@ -384,11 +364,32 @@ export const MasterPage: React.FC = () => { setShowRoleDialog(true); }; + const handleCreateRole = async (data: { roleCode: string; roleName: string; description?: string }) => { + try { + const payload = { + ...data, + permissionIds: [] + }; + const res = await (masterService as any).createRole(payload); + if (res?.success) { + toast.success('Role created successfully'); + fetchInitialData(); + return; + } + throw new Error(res?.message || 'Failed to create role'); + } catch (error: any) { + const msg = error?.response?.data?.message || error?.message || 'Failed to create role'; + toast.error(msg); + throw error; + } + }; + const handleEditLocation = (loc: any) => { + const matchedDistrict = allDistricts.find((d: any) => d.id === loc.districtId); setEditingLocationId(loc.id); - setLocationState(loc.stateName || ''); + setLocationState(matchedDistrict?.stateId || loc.stateId || ''); setLocationCity(loc.city || ''); - setLocationDistrict(loc.name || ''); + setLocationDistrict(loc.districtId || ''); setLocationActiveFrom(loc.openFrom ? new Date(loc.openFrom).toISOString().split('T')[0] : ''); setLocationActiveTo(loc.openTo ? new Date(loc.openTo).toISOString().split('T')[0] : ''); setLocationStatus(loc.isActive ? 'active' : 'inactive'); @@ -397,10 +398,23 @@ export const MasterPage: React.FC = () => { const handleSaveLocation = async () => { try { + if (!locationState) { + toast.error('Please select a state'); + return; + } + if (!locationDistrict) { + toast.error('Please select a district'); + return; + } + + const selectedState = allStates.find((s: any) => s.id === locationState); + const selectedDistrict = allDistricts.find((d: any) => d.id === locationDistrict); const payload = { id: editingLocationId, - stateName: locationState, - name: locationDistrict, + stateId: locationState, + stateName: selectedState?.name || selectedState?.stateName || '', + districtId: locationDistrict, + name: locationCity || selectedDistrict?.name || 'New Location', city: locationCity, status: locationStatus, openFrom: locationActiveFrom, @@ -474,11 +488,10 @@ export const MasterPage: React.FC = () => { { setEditingZoneId(null); setZoneName(''); setZoneCode(''); setZoneDescription(''); setZonalBusinessHeadId('none'); setShowZoneDialog(true); }} onEditZone={(z) => { setEditingZoneId(z.id); setZoneName(z.name); setZoneCode(z.code); setZoneDescription(z.description); setZonalBusinessHeadId(z.zonalBusinessHead?.id || 'none'); setShowZoneDialog(true); }} /> - { setEditingRegionId(null); setRegionName(''); setRegionCode(''); setSelectedRegionZone(selectedZone === 'all' ? '' : selectedZone); setRegionalManagerId(''); setSelectedRegionDistricts([]); setShowRegionDialog(true); }} + { setEditingRegionId(null); setRegionName(''); setSelectedRegionZone(selectedZone === 'all' ? '' : selectedZone); setRegionalManagerId(''); setSelectedRegionDistricts([]); setShowRegionDialog(true); }} onEditRegion={(r) => { setEditingRegionId(r.id); setRegionName(r.name); - setRegionCode(r.code); setSelectedRegionZone(r.zoneId); setRegionalManagerId(r.regionalManager?.id || ''); setSelectedRegionDistricts(r.districts?.map((d: any) => d.id) || []); @@ -488,7 +501,7 @@ export const MasterPage: React.FC = () => { { - setEditingZMId(null); setZmManagerId(''); setZmName(''); setZmCode(''); setZmEmployeeId(''); + setEditingZMId(null); setZmManagerId(''); setZmStatus('active'); setSelectedZMZone(selectedZone === 'all' ? '' : selectedZone); setSelectedZMRegions([]); setShowZMDialog(true); @@ -496,12 +509,12 @@ export const MasterPage: React.FC = () => { onEditZM={handleEditZM} onDeleteZM={() => toast.error('ZM deletion restricted')} /> - { setEditingASMId(null); setAsmManagerId(''); setAsmName(''); setAsmCode(''); setAsmEmployeeId(''); setSelectedASMZone(selectedZone === 'all' ? '' : selectedZone); setSelectedASMRegion(''); setSelectedASMStates([]); setSelectedASMDistricts([]); setShowASMDialog(true); }} + { setEditingASMId(null); setAsmManagerId(''); setSelectedASMZone(selectedZone === 'all' ? '' : selectedZone); setSelectedASMRegion(''); setSelectedASMStates([]); setSelectedASMDistricts([]); setShowASMDialog(true); }} onEditASM={handleEditASM} onDeleteASM={() => toast.error('ASM deletion restricted')} /> { - setEditingDDLeadId(null); setDdLeadManagerId(''); setDdLeadName(''); setDdLeadCode(''); setDdLeadEmployeeId(''); + setEditingDDLeadId(null); setDdLeadManagerId(''); setDdLeadStatus('active'); setSelectedDDLeadZones([]); setShowDDLeadDialog(true); }} @@ -512,7 +525,7 @@ export const MasterPage: React.FC = () => { - toast.info('Unified Role Management interface being updated')} + setShowAddRoleDialog(true)} onEditRole={handleEditRole} /> @@ -592,20 +605,14 @@ export const MasterPage: React.FC = () => { {/* Main Dialogs */} 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} /> - 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} /> - 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} districtsAssignedToOthers={districtsAssignedToOthers} getDistrictsForSelectedState={(state) => getDistrictsForSelectedState(state, selectedASMRegion || undefined)} /> + 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} /> + 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} districtsAssignedToOthers={districtsAssignedToOthers} getDistrictsForSelectedState={(state) => getDistrictsForSelectedState(state, selectedASMRegion || undefined)} /> { editingLeadId={editingDDLeadId} leadManagerId={ddLeadManagerId} setLeadManagerId={setDdLeadManagerId} - leadName={ddLeadName} - setLeadName={setDdLeadName} - leadCode={ddLeadCode} - setLeadCode={setDdLeadCode} - leadEmployeeId={ddLeadEmployeeId} - setLeadEmployeeId={setDdLeadEmployeeId} leadStatus={ddLeadStatus} setLeadStatus={setDdLeadStatus} selectedZones={selectedDDLeadZones} @@ -635,8 +636,9 @@ export const MasterPage: React.FC = () => { userAssignedData={users.length > 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles, assignedZoneIds: (ddLeads.find(l => l.id === u.id)?.assignedZoneIds || [])})) : asms} /> - + +
); }; diff --git a/src/components/applications/MasterPage/ASMDialog.tsx b/src/components/applications/MasterPage/ASMDialog.tsx index 4aad4a4..f286da7 100644 --- a/src/components/applications/MasterPage/ASMDialog.tsx +++ b/src/components/applications/MasterPage/ASMDialog.tsx @@ -3,7 +3,6 @@ import { useSelector } from 'react-redux'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; import { Button } from '../../ui/button'; import { Label } from '../../ui/label'; -import { Input } from '../../ui/input'; import { Checkbox } from '../../ui/checkbox'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip'; @@ -15,12 +14,6 @@ interface ASMDialogProps { editingASMId: string | null; asmManagerId: string; setAsmManagerId: (id: string) => void; - asmName: string; - setAsmName: (name: string) => void; - asmCode: string; - setAsmCode: (code: string) => void; - asmEmployeeId: string; - setAsmEmployeeId: (id: string) => void; asmStatus: 'active' | 'inactive'; setAsmStatus: (status: 'active' | 'inactive') => void; selectedASMZone: string; @@ -41,7 +34,6 @@ interface ASMDialogProps { export const ASMDialog: React.FC = ({ isOpen, onOpenChange, editingASMId, asmManagerId, setAsmManagerId, - asmName, setAsmName, asmCode, setAsmCode, asmEmployeeId, setAsmEmployeeId, asmStatus, setAsmStatus, selectedASMZone, setSelectedASMZone, selectedASMRegion, setSelectedASMRegion, selectedASMStates, setSelectedASMStates, selectedASMDistricts, setSelectedASMDistricts, onSave, @@ -257,13 +249,7 @@ export const ASMDialog: React.FC = ({ setAsmManagerId(value); const selectedUser = userAssignedData.find(u => u.id === value); if (selectedUser) { - setAsmName(selectedUser.name); - setAsmEmployeeId(selectedUser.employeeId || ''); - - // Extraction logic: Look for managerCode in the territoryProfile matching the current role const roleProfile = (selectedUser.territoryProfile || []).find((t: any) => t.roleCode === asmRoleCode); - const existingCode = roleProfile?.managerCode || selectedUser.asmCode || selectedUser.employeeId || ''; - setAsmCode(existingCode); // Extract zone/region from assignments if present if (roleProfile?.zoneId) setSelectedASMZone(roleProfile.zoneId); @@ -295,22 +281,6 @@ export const ASMDialog: React.FC = ({
-
-
- - -
-
- - setAsmCode(e.target.value)} /> -
-
- -
- - setAsmName(e.target.value)} /> -
-
setRoleName(e.target.value)} + placeholder="e.g. Finance Admin" + /> +
+ +
+ + setRoleCode(e.target.value)} + placeholder="e.g. FINANCE_ADMIN" + /> +
+ +
+ +