ui and extra inputs fwhile creeating region zone, assigning zm are removed

This commit is contained in:
laxman h 2026-04-15 21:13:39 +05:30
parent 8ea748fde6
commit bc2b7faf08
14 changed files with 251 additions and 179 deletions

View File

@ -9,6 +9,7 @@ export const API = {
// Master module routes // Master module routes
getRoles: () => client.get('/admin/roles'), getRoles: () => client.get('/admin/roles'),
createRole: (data: any) => client.post('/admin/roles', data),
getPermissions: () => client.get('/admin/permissions'), getPermissions: () => client.get('/admin/permissions'),
updateRole: (id: string, data: any) => client.put(`/admin/roles/${id}`, data), updateRole: (id: string, data: any) => client.put(`/admin/roles/${id}`, data),

View File

@ -490,7 +490,8 @@ export function UserManagementPage() {
{/* Geographical Assignments */} {/* Geographical Assignments */}
<div className="col-span-2 border-t pt-4 mt-2"> <div className="col-span-2 border-t pt-4 mt-2">
<h3 className="text-sm font-semibold text-slate-900 mb-4">Geographical Assignments</h3> <h3 className="text-sm font-semibold text-slate-900 mb-1">Geographical Assignments</h3>
<p className="text-xs text-slate-500 mb-4">Optional: you can create users without territory mapping and assign later.</p>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="zoneId">Zone (Top Level)</Label> <Label htmlFor="zoneId">Zone (Top Level)</Label>

View File

@ -174,7 +174,7 @@ export function AllApplicationsPage({ onViewDetails, initialFilter = 'all' }: Al
]; ];
const getStatusColor = (status: ApplicationStatus) => { const getStatusColor = (status: ApplicationStatus) => {
const colors: Record<ApplicationStatus, string> = { const colors: Partial<Record<ApplicationStatus, string>> = {
'Submitted': 'bg-blue-100 text-blue-800', 'Submitted': 'bg-blue-100 text-blue-800',
'Questionnaire Pending': 'bg-yellow-100 text-yellow-800', 'Questionnaire Pending': 'bg-yellow-100 text-yellow-800',
'Questionnaire Completed': 'bg-cyan-100 text-cyan-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 Approved': 'bg-green-100 text-green-800',
'Security Details': 'bg-amber-100 text-amber-800', 'Security Details': 'bg-amber-100 text-amber-800',
'LOA Issued': 'bg-pink-100 text-pink-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 ( return (

View File

@ -1875,6 +1875,8 @@ export const ApplicationDetails = () => {
].includes(application.status); ].includes(application.status);
const isLoaLocked = application.status === 'LOA Pending' && getDeposit('FIRST_FILL')?.status !== 'Verified'; 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'; const isFinalState = application.status === 'Onboarded' || application.status === 'Rejected';
// 2. Interview Specific Logic // 2. Interview Specific Logic
@ -1903,15 +1905,18 @@ export const ApplicationDetails = () => {
// 5. Final Permission Bits // 5. Final Permission Bits
const isDecisionMade = (activeInterviewForUser ? hasMadeInterviewDecision : false) || hasMadeStageDecision; const isDecisionMade = (activeInterviewForUser ? hasMadeInterviewDecision : false) || hasMadeStageDecision;
const canApproveReject = !isLoaLocked && !isFinalState && !isDecisionMade && ( const canApproveReject = !isFinalState && !isDecisionMade && (
(!!activeInterviewForUser && !!hasSubmittedFeedback) || (!!activeInterviewForUser && !!hasSubmittedFeedback) ||
(isAdminRole && isAdministrativeStage && sequenceMet && (!['EOR In Progress', 'Inauguration', 'Approved'].includes(application.status) || eorProgress === 100)) (isAdminRole && isAdministrativeStage && sequenceMet && (!['EOR In Progress', 'Inauguration', 'Approved'].includes(application.status) || eorProgress === 100))
); );
const canApprove = canApproveReject && !isLoaLocked && !isSecurityDetailsLocked;
const canReject = canApproveReject && !isLoaLocked;
return { return {
canApprove: canApproveReject, canApprove,
canReject: canApproveReject, canReject,
isLoaLocked, isLoaLocked,
isSecurityDetailsLocked,
showDecisionMessage: isDecisionMade && (!isAdministrativeStage || hasMadeStageDecision), showDecisionMessage: isDecisionMade && (!isAdministrativeStage || hasMadeStageDecision),
canSchedule: ['DD Admin', 'Super Admin', 'DD AM', 'ASM'].includes(currentUser.role) && canSchedule: ['DD Admin', 'Super Admin', 'DD AM', 'ASM'].includes(currentUser.role) &&
!isFinalState && !isFinalState &&
@ -3643,6 +3648,17 @@ export const ApplicationDetails = () => {
</Alert> </Alert>
)} )}
{permissions.isSecurityDetailsLocked && (
<Alert variant="destructive" className="mb-4 bg-amber-50 border-amber-200 text-amber-800">
<Lock className="w-4 h-4 text-amber-600" />
<AlertTitle className="text-amber-900 font-semibold">Security Details approval locked</AlertTitle>
<AlertDescription className="text-amber-800">
Finance must verify the <span className="font-medium">Security Deposit</span> before this stage can be approved.
You can still use <span className="font-medium">Reject</span> if needed.
</AlertDescription>
</Alert>
)}
{['Security Details', 'Payment Pending'].includes(application.status) && ( {['Security Details', 'Payment Pending'].includes(application.status) && (
<Alert className="mb-4 border-sky-200 bg-sky-50/90 text-sky-900"> <Alert className="mb-4 border-sky-200 bg-sky-50/90 text-sky-900">
<Info className="h-4 w-4 text-sky-700" /> <Info className="h-4 w-4 text-sky-700" />

View File

@ -21,6 +21,7 @@ import { UserManagementTable } from './MasterPage/UserManagementTable';
import { SLAConfiguration } from './MasterPage/SLAConfiguration'; import { SLAConfiguration } from './MasterPage/SLAConfiguration';
import { RolePermissions } from './MasterPage/RolePermissions'; import { RolePermissions } from './MasterPage/RolePermissions';
import { RoleDialog } from './MasterPage/RoleDialog'; import { RoleDialog } from './MasterPage/RoleDialog';
import { AddRoleDialog } from './MasterPage/AddRoleDialog';
import { EmailTemplates } from './MasterPage/EmailTemplates'; import { EmailTemplates } from './MasterPage/EmailTemplates';
import { LocationManagement } from './MasterPage/LocationManagement'; import { LocationManagement } from './MasterPage/LocationManagement';
import { ASMDialog } from './MasterPage/ASMDialog'; import { ASMDialog } from './MasterPage/ASMDialog';
@ -40,6 +41,7 @@ export const MasterPage: React.FC = () => {
const { fetchInitialData, fetchAreas } = useMasterData(); const { fetchInitialData, fetchAreas } = useMasterData();
const { const {
asms, zonalManagerMappings, ddLeads, asms, zonalManagerMappings, ddLeads,
allStates,
allDistricts, allDistricts,
users, users,
roles, roles,
@ -60,9 +62,6 @@ export const MasterPage: React.FC = () => {
// Form State (ASM) // Form State (ASM)
const [editingASMId, setEditingASMId] = useState<string | null>(null); const [editingASMId, setEditingASMId] = useState<string | null>(null);
const [asmManagerId, setAsmManagerId] = useState(''); const [asmManagerId, setAsmManagerId] = useState('');
const [asmName, setAsmName] = useState('');
const [asmCode, setAsmCode] = useState('');
const [asmEmployeeId, setAsmEmployeeId] = useState('');
const [asmStatus, setAsmStatus] = useState<'active' | 'inactive'>('active'); const [asmStatus, setAsmStatus] = useState<'active' | 'inactive'>('active');
const [selectedASMZone, setSelectedASMZone] = useState(''); const [selectedASMZone, setSelectedASMZone] = useState('');
const [selectedASMRegion, setSelectedASMRegion] = useState(''); const [selectedASMRegion, setSelectedASMRegion] = useState('');
@ -74,9 +73,6 @@ export const MasterPage: React.FC = () => {
const [showZMDialog, setShowZMDialog] = useState(false); const [showZMDialog, setShowZMDialog] = useState(false);
const [editingZMId, setEditingZMId] = useState<string | null>(null); const [editingZMId, setEditingZMId] = useState<string | null>(null);
const [zmManagerId, setZmManagerId] = useState(''); const [zmManagerId, setZmManagerId] = useState('');
const [zmName, setZmName] = useState('');
const [zmCode, setZmCode] = useState('');
const [zmEmployeeId, setZmEmployeeId] = useState('');
const [zmStatus, setZmStatus] = useState<'active' | 'inactive'>('active'); const [zmStatus, setZmStatus] = useState<'active' | 'inactive'>('active');
const [selectedZMZone, setSelectedZMZone] = useState(''); const [selectedZMZone, setSelectedZMZone] = useState('');
const [selectedZMRegions, setSelectedZMRegions] = useState<string[]>([]); const [selectedZMRegions, setSelectedZMRegions] = useState<string[]>([]);
@ -85,15 +81,13 @@ export const MasterPage: React.FC = () => {
const [showDDLeadDialog, setShowDDLeadDialog] = useState(false); const [showDDLeadDialog, setShowDDLeadDialog] = useState(false);
const [editingDDLeadId, setEditingDDLeadId] = useState<string | null>(null); const [editingDDLeadId, setEditingDDLeadId] = useState<string | null>(null);
const [ddLeadManagerId, setDdLeadManagerId] = useState(''); const [ddLeadManagerId, setDdLeadManagerId] = useState('');
const [ddLeadName, setDdLeadName] = useState('');
const [ddLeadCode, setDdLeadCode] = useState('');
const [ddLeadEmployeeId, setDdLeadEmployeeId] = useState('');
const [ddLeadStatus, setDdLeadStatus] = useState<'active' | 'inactive'>('active'); const [ddLeadStatus, setDdLeadStatus] = useState<'active' | 'inactive'>('active');
const [selectedDDLeadZones, setSelectedDDLeadZones] = useState<string[]>([]); const [selectedDDLeadZones, setSelectedDDLeadZones] = useState<string[]>([]);
// Role Management State // Role Management State
const [showRoleDialog, setShowRoleDialog] = useState(false); const [showRoleDialog, setShowRoleDialog] = useState(false);
const [editingRole, setEditingRole] = useState<any>(null); const [editingRole, setEditingRole] = useState<any>(null);
const [showAddRoleDialog, setShowAddRoleDialog] = useState(false);
// Form State (Zone) // Form State (Zone)
const [editingZoneId, setEditingZoneId] = useState<string | null>(null); const [editingZoneId, setEditingZoneId] = useState<string | null>(null);
@ -105,7 +99,6 @@ export const MasterPage: React.FC = () => {
// Form State (Region) // Form State (Region)
const [editingRegionId, setEditingRegionId] = useState<string | null>(null); const [editingRegionId, setEditingRegionId] = useState<string | null>(null);
const [regionName, setRegionName] = useState(''); const [regionName, setRegionName] = useState('');
const [regionCode, setRegionCode] = useState('');
const [regionDescription, setRegionDescription] = useState(''); const [regionDescription, setRegionDescription] = useState('');
const [selectedRegionZone, setSelectedRegionZone] = useState(''); const [selectedRegionZone, setSelectedRegionZone] = useState('');
const [regionalManagerId, setRegionalManagerId] = useState(''); const [regionalManagerId, setRegionalManagerId] = useState('');
@ -176,7 +169,6 @@ export const MasterPage: React.FC = () => {
const payload = { const payload = {
userId: asmManagerId, userId: asmManagerId,
roleCode: asmRoleCode, roleCode: asmRoleCode,
asmCode,
districts: selectedASMDistricts, districts: selectedASMDistricts,
status: asmStatus status: asmStatus
}; };
@ -197,9 +189,6 @@ export const MasterPage: React.FC = () => {
const handleEditASM = (asm: any) => { const handleEditASM = (asm: any) => {
setEditingASMId(asm.id); setEditingASMId(asm.id);
setAsmManagerId(asm.id); setAsmManagerId(asm.id);
setAsmName(asm.name);
setAsmCode(asm.asmCode);
setAsmEmployeeId(asm.employeeId);
setAsmStatus(asm.status.toLowerCase() as 'active' | 'inactive'); setAsmStatus(asm.status.toLowerCase() as 'active' | 'inactive');
setSelectedASMZone(asm.zoneId); setSelectedASMZone(asm.zoneId);
setSelectedASMRegion(asm.regionId); setSelectedASMRegion(asm.regionId);
@ -212,9 +201,6 @@ export const MasterPage: React.FC = () => {
const handleEditZM = (zm: any) => { const handleEditZM = (zm: any) => {
setEditingZMId(zm.id); setEditingZMId(zm.id);
setZmManagerId(zm.id); setZmManagerId(zm.id);
setZmName(zm.name);
setZmCode(zm.zmCode || zm.code || '');
setZmEmployeeId(zm.employeeId || '');
setZmStatus(zm.status?.toLowerCase() === 'active' ? 'active' : 'inactive'); setZmStatus(zm.status?.toLowerCase() === 'active' ? 'active' : 'inactive');
setSelectedZMZone(zm.zoneId || ''); setSelectedZMZone(zm.zoneId || '');
setSelectedZMRegions(zm.assignedRegionIds || []); setSelectedZMRegions(zm.assignedRegionIds || []);
@ -224,9 +210,6 @@ export const MasterPage: React.FC = () => {
const handleEditDDLead = (lead: any) => { const handleEditDDLead = (lead: any) => {
setEditingDDLeadId(lead.id); setEditingDDLeadId(lead.id);
setDdLeadManagerId(lead.id); setDdLeadManagerId(lead.id);
setDdLeadName(lead.name);
setDdLeadCode(lead.leadCode || '');
setDdLeadEmployeeId(lead.employeeId || '');
setDdLeadStatus(lead.status?.toLowerCase() === 'active' ? 'active' : 'inactive'); setDdLeadStatus(lead.status?.toLowerCase() === 'active' ? 'active' : 'inactive');
setSelectedDDLeadZones(lead.assignedZoneIds || []); setSelectedDDLeadZones(lead.assignedZoneIds || []);
setShowDDLeadDialog(true); setShowDDLeadDialog(true);
@ -240,7 +223,6 @@ export const MasterPage: React.FC = () => {
try { try {
const payload = { const payload = {
userId: zmManagerId, userId: zmManagerId,
zmCode,
zoneId: selectedZMZone, zoneId: selectedZMZone,
regionIds: selectedZMRegions, regionIds: selectedZMRegions,
status: zmStatus status: zmStatus
@ -268,7 +250,6 @@ export const MasterPage: React.FC = () => {
try { try {
const payload = { const payload = {
userId: ddLeadManagerId, userId: ddLeadManagerId,
leadCode: ddLeadCode,
zoneIds: selectedDDLeadZones, zoneIds: selectedDDLeadZones,
status: ddLeadStatus status: ddLeadStatus
}; };
@ -316,7 +297,6 @@ export const MasterPage: React.FC = () => {
const payload = { const payload = {
...(editingRegionId ? { id: editingRegionId } : {}), ...(editingRegionId ? { id: editingRegionId } : {}),
name: regionName, name: regionName,
code: regionCode,
description: regionDescription, description: regionDescription,
parentId: selectedRegionZone, parentId: selectedRegionZone,
managerId: regionalManagerId, managerId: regionalManagerId,
@ -384,11 +364,32 @@ export const MasterPage: React.FC = () => {
setShowRoleDialog(true); 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 handleEditLocation = (loc: any) => {
const matchedDistrict = allDistricts.find((d: any) => d.id === loc.districtId);
setEditingLocationId(loc.id); setEditingLocationId(loc.id);
setLocationState(loc.stateName || ''); setLocationState(matchedDistrict?.stateId || loc.stateId || '');
setLocationCity(loc.city || ''); setLocationCity(loc.city || '');
setLocationDistrict(loc.name || ''); setLocationDistrict(loc.districtId || '');
setLocationActiveFrom(loc.openFrom ? new Date(loc.openFrom).toISOString().split('T')[0] : ''); setLocationActiveFrom(loc.openFrom ? new Date(loc.openFrom).toISOString().split('T')[0] : '');
setLocationActiveTo(loc.openTo ? new Date(loc.openTo).toISOString().split('T')[0] : ''); setLocationActiveTo(loc.openTo ? new Date(loc.openTo).toISOString().split('T')[0] : '');
setLocationStatus(loc.isActive ? 'active' : 'inactive'); setLocationStatus(loc.isActive ? 'active' : 'inactive');
@ -397,10 +398,23 @@ export const MasterPage: React.FC = () => {
const handleSaveLocation = async () => { const handleSaveLocation = async () => {
try { 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 = { const payload = {
id: editingLocationId, id: editingLocationId,
stateName: locationState, stateId: locationState,
name: locationDistrict, stateName: selectedState?.name || selectedState?.stateName || '',
districtId: locationDistrict,
name: locationCity || selectedDistrict?.name || 'New Location',
city: locationCity, city: locationCity,
status: locationStatus, status: locationStatus,
openFrom: locationActiveFrom, openFrom: locationActiveFrom,
@ -474,11 +488,10 @@ export const MasterPage: React.FC = () => {
<ZoneDetails selectedZone={selectedZone} onAddZone={() => { setEditingZoneId(null); setZoneName(''); setZoneCode(''); setZoneDescription(''); setZonalBusinessHeadId('none'); setShowZoneDialog(true); }} <ZoneDetails selectedZone={selectedZone} onAddZone={() => { 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); }} /> onEditZone={(z) => { setEditingZoneId(z.id); setZoneName(z.name); setZoneCode(z.code); setZoneDescription(z.description); setZonalBusinessHeadId(z.zonalBusinessHead?.id || 'none'); setShowZoneDialog(true); }} />
<RegionalManagement selectedZone={selectedZone} onAddRegion={() => { setEditingRegionId(null); setRegionName(''); setRegionCode(''); setSelectedRegionZone(selectedZone === 'all' ? '' : selectedZone); setRegionalManagerId(''); setSelectedRegionDistricts([]); setShowRegionDialog(true); }} <RegionalManagement selectedZone={selectedZone} onAddRegion={() => { setEditingRegionId(null); setRegionName(''); setSelectedRegionZone(selectedZone === 'all' ? '' : selectedZone); setRegionalManagerId(''); setSelectedRegionDistricts([]); setShowRegionDialog(true); }}
onEditRegion={(r) => { onEditRegion={(r) => {
setEditingRegionId(r.id); setEditingRegionId(r.id);
setRegionName(r.name); setRegionName(r.name);
setRegionCode(r.code);
setSelectedRegionZone(r.zoneId); setSelectedRegionZone(r.zoneId);
setRegionalManagerId(r.regionalManager?.id || ''); setRegionalManagerId(r.regionalManager?.id || '');
setSelectedRegionDistricts(r.districts?.map((d: any) => d.id) || []); setSelectedRegionDistricts(r.districts?.map((d: any) => d.id) || []);
@ -488,7 +501,7 @@ export const MasterPage: React.FC = () => {
<ZMManagement selectedZone={selectedZone} <ZMManagement selectedZone={selectedZone}
onAddZM={() => { onAddZM={() => {
setEditingZMId(null); setZmManagerId(''); setZmName(''); setZmCode(''); setZmEmployeeId(''); setEditingZMId(null); setZmManagerId('');
setZmStatus('active'); setSelectedZMZone(selectedZone === 'all' ? '' : selectedZone); setZmStatus('active'); setSelectedZMZone(selectedZone === 'all' ? '' : selectedZone);
setSelectedZMRegions([]); setSelectedZMRegions([]);
setShowZMDialog(true); setShowZMDialog(true);
@ -496,12 +509,12 @@ export const MasterPage: React.FC = () => {
onEditZM={handleEditZM} onEditZM={handleEditZM}
onDeleteZM={() => toast.error('ZM deletion restricted')} /> onDeleteZM={() => toast.error('ZM deletion restricted')} />
<ASMManagement selectedZone={selectedZone} onAddASM={() => { setEditingASMId(null); setAsmManagerId(''); setAsmName(''); setAsmCode(''); setAsmEmployeeId(''); setSelectedASMZone(selectedZone === 'all' ? '' : selectedZone); setSelectedASMRegion(''); setSelectedASMStates([]); setSelectedASMDistricts([]); setShowASMDialog(true); }} <ASMManagement selectedZone={selectedZone} onAddASM={() => { setEditingASMId(null); setAsmManagerId(''); setSelectedASMZone(selectedZone === 'all' ? '' : selectedZone); setSelectedASMRegion(''); setSelectedASMStates([]); setSelectedASMDistricts([]); setShowASMDialog(true); }}
onEditASM={handleEditASM} onDeleteASM={() => toast.error('ASM deletion restricted')} /> onEditASM={handleEditASM} onDeleteASM={() => toast.error('ASM deletion restricted')} />
<DDLeadManagement selectedZone={selectedZone} <DDLeadManagement selectedZone={selectedZone}
onAddLead={() => { onAddLead={() => {
setEditingDDLeadId(null); setDdLeadManagerId(''); setDdLeadName(''); setDdLeadCode(''); setDdLeadEmployeeId(''); setEditingDDLeadId(null); setDdLeadManagerId('');
setDdLeadStatus('active'); setSelectedDDLeadZones([]); setDdLeadStatus('active'); setSelectedDDLeadZones([]);
setShowDDLeadDialog(true); setShowDDLeadDialog(true);
}} }}
@ -512,7 +525,7 @@ export const MasterPage: React.FC = () => {
</TabsContent> </TabsContent>
<TabsContent value="roles" className="animate-in fade-in duration-300"> <TabsContent value="roles" className="animate-in fade-in duration-300">
<RolePermissions onAddRole={() => toast.info('Unified Role Management interface being updated')} <RolePermissions onAddRole={() => setShowAddRoleDialog(true)}
onEditRole={handleEditRole} /> onEditRole={handleEditRole} />
</TabsContent> </TabsContent>
@ -592,20 +605,14 @@ export const MasterPage: React.FC = () => {
{/* Main Dialogs */} {/* Main Dialogs */}
<ZoneDialog isOpen={showZoneDialog} onOpenChange={setShowZoneDialog} editingZoneId={editingZoneId} zoneName={zoneName} setZoneName={setZoneName} zoneCode={zoneCode} setZoneCode={setZoneCode} zoneDescription={zoneDescription} setZoneDescription={setZoneDescription} zonalBusinessHeadId={zonalBusinessHeadId} setZonalBusinessHeadId={setZonalBusinessHeadId} onSave={handleSaveZone} userAssignedData={users.length > 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} /> <ZoneDialog isOpen={showZoneDialog} onOpenChange={setShowZoneDialog} editingZoneId={editingZoneId} zoneName={zoneName} setZoneName={setZoneName} zoneCode={zoneCode} setZoneCode={setZoneCode} zoneDescription={zoneDescription} setZoneDescription={setZoneDescription} zonalBusinessHeadId={zonalBusinessHeadId} setZonalBusinessHeadId={setZonalBusinessHeadId} onSave={handleSaveZone} userAssignedData={users.length > 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} />
<RegionDialog isOpen={showRegionDialog} onOpenChange={setShowRegionDialog} editingRegionId={editingRegionId} regionName={regionName} setRegionName={setRegionName} regionCode={regionCode} setRegionCode={setRegionCode} regionDescription={regionDescription} setRegionDescription={setRegionDescription} selectedRegionZone={selectedRegionZone} setSelectedRegionZone={setSelectedRegionZone} regionalManagerId={regionalManagerId} setRegionalManagerId={setRegionalManagerId} selectedRegionStates={selectedRegionDistricts} setSelectedRegionStates={setSelectedRegionDistricts} onSave={handleSaveRegion} userAssignedData={users.length > 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} /> <RegionDialog isOpen={showRegionDialog} onOpenChange={setShowRegionDialog} editingRegionId={editingRegionId} regionName={regionName} setRegionName={setRegionName} regionDescription={regionDescription} setRegionDescription={setRegionDescription} selectedRegionZone={selectedRegionZone} setSelectedRegionZone={setSelectedRegionZone} regionalManagerId={regionalManagerId} setRegionalManagerId={setRegionalManagerId} selectedRegionStates={selectedRegionDistricts} setSelectedRegionStates={setSelectedRegionDistricts} onSave={handleSaveRegion} userAssignedData={users.length > 0 ? users.map(u => ({...u, name: u.fullName || u.name, role: u.role?.roleName, roleCode: u.role?.roleCode, allRoles: u.allRoles})) : asms} />
<ASMDialog isOpen={showASMDialog} onOpenChange={setShowASMDialog} editingASMId={editingASMId} asmManagerId={asmManagerId} setAsmManagerId={setAsmManagerId} asmName={asmName} setAsmName={setAsmName} asmCode={asmCode} setAsmCode={setAsmCode} asmEmployeeId={asmEmployeeId} setAsmEmployeeId={setAsmEmployeeId} asmStatus={asmStatus} setAsmStatus={setAsmStatus} selectedASMZone={selectedASMZone} setSelectedASMZone={setSelectedASMZone} selectedASMRegion={selectedASMRegion} setSelectedASMRegion={setSelectedASMRegion} selectedASMStates={selectedASMStates} setSelectedASMStates={setSelectedASMStates} selectedASMDistricts={selectedASMDistricts} setSelectedASMDistricts={setSelectedASMDistricts} onSave={handleSaveASM} asmRoleCode={asmRoleCode} setAsmRoleCode={setAsmRoleCode} userAssignedData={users.length > 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)} /> <ASMDialog isOpen={showASMDialog} onOpenChange={setShowASMDialog} editingASMId={editingASMId} asmManagerId={asmManagerId} setAsmManagerId={setAsmManagerId} asmStatus={asmStatus} setAsmStatus={setAsmStatus} selectedASMZone={selectedASMZone} setSelectedASMZone={setSelectedASMZone} selectedASMRegion={selectedASMRegion} setSelectedASMRegion={setSelectedASMRegion} selectedASMStates={selectedASMStates} setSelectedASMStates={setSelectedASMStates} selectedASMDistricts={selectedASMDistricts} setSelectedASMDistricts={setSelectedASMDistricts} onSave={handleSaveASM} asmRoleCode={asmRoleCode} setAsmRoleCode={setAsmRoleCode} userAssignedData={users.length > 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)} />
<ZMDialog <ZMDialog
isOpen={showZMDialog} isOpen={showZMDialog}
onOpenChange={setShowZMDialog} onOpenChange={setShowZMDialog}
editingZMId={editingZMId} editingZMId={editingZMId}
zmManagerId={zmManagerId} zmManagerId={zmManagerId}
setZmManagerId={setZmManagerId} setZmManagerId={setZmManagerId}
zmName={zmName}
setZmName={setZmName}
zmCode={zmCode}
setZmCode={setZmCode}
zmEmployeeId={zmEmployeeId}
setZmEmployeeId={setZmEmployeeId}
zmStatus={zmStatus} zmStatus={zmStatus}
setZmStatus={setZmStatus} setZmStatus={setZmStatus}
selectedZone={selectedZMZone} selectedZone={selectedZMZone}
@ -621,12 +628,6 @@ export const MasterPage: React.FC = () => {
editingLeadId={editingDDLeadId} editingLeadId={editingDDLeadId}
leadManagerId={ddLeadManagerId} leadManagerId={ddLeadManagerId}
setLeadManagerId={setDdLeadManagerId} setLeadManagerId={setDdLeadManagerId}
leadName={ddLeadName}
setLeadName={setDdLeadName}
leadCode={ddLeadCode}
setLeadCode={setDdLeadCode}
leadEmployeeId={ddLeadEmployeeId}
setLeadEmployeeId={setDdLeadEmployeeId}
leadStatus={ddLeadStatus} leadStatus={ddLeadStatus}
setLeadStatus={setDdLeadStatus} setLeadStatus={setDdLeadStatus}
selectedZones={selectedDDLeadZones} 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} 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}
/> />
<TemplateDialog isOpen={showTemplateDialog} onOpenChange={setShowTemplateDialog} editingTemplate={editingTemplate} setEditingTemplate={setEditingTemplate} testDataInput={testDataInput} setTestDataInput={setTestDataInput} previewLoading={previewLoading} handlePreviewTemplate={handlePreviewTemplate} previewContent={previewContent} handleSaveTemplate={handleSaveTemplate} /> <TemplateDialog isOpen={showTemplateDialog} onOpenChange={setShowTemplateDialog} editingTemplate={editingTemplate} setEditingTemplate={setEditingTemplate} testDataInput={testDataInput} setTestDataInput={setTestDataInput} previewLoading={previewLoading} handlePreviewTemplate={handlePreviewTemplate} previewContent={previewContent} handleSaveTemplate={handleSaveTemplate} />
<LocationDialog isOpen={showLocationDialog} onOpenChange={setShowLocationDialog} editingLocationId={editingLocationId} locationState={locationState} setLocationState={setLocationState} locationDistrict={locationDistrict} setLocationDistrict={setLocationDistrict} locationCity={locationCity} setLocationCity={setLocationCity} locationActiveFrom={locationActiveFrom} setLocationActiveFrom={setLocationActiveFrom} locationActiveTo={locationActiveTo} setLocationActiveTo={setLocationActiveTo} locationStatus={locationStatus} setLocationStatus={setLocationStatus} onSave={handleSaveLocation} /> <LocationDialog isOpen={showLocationDialog} onOpenChange={setShowLocationDialog} editingLocationId={editingLocationId} locationState={locationState} setLocationState={setLocationState} locationDistrict={locationDistrict} setLocationDistrict={setLocationDistrict} locationCity={locationCity} setLocationCity={setLocationCity} locationActiveFrom={locationActiveFrom} setLocationActiveFrom={setLocationActiveFrom} locationActiveTo={locationActiveTo} setLocationActiveTo={setLocationActiveTo} locationStatus={locationStatus} setLocationStatus={setLocationStatus} allStates={allStates} allDistricts={allDistricts} onSave={handleSaveLocation} />
<RoleDialog isOpen={showRoleDialog} onOpenChange={setShowRoleDialog} role={editingRole} onSave={handleSaveRole} /> <RoleDialog isOpen={showRoleDialog} onOpenChange={setShowRoleDialog} role={editingRole} onSave={handleSaveRole} />
<AddRoleDialog isOpen={showAddRoleDialog} onOpenChange={setShowAddRoleDialog} onSave={handleCreateRole} />
</div> </div>
); );
}; };

View File

@ -3,7 +3,6 @@ import { useSelector } from 'react-redux';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog';
import { Button } from '../../ui/button'; import { Button } from '../../ui/button';
import { Label } from '../../ui/label'; import { Label } from '../../ui/label';
import { Input } from '../../ui/input';
import { Checkbox } from '../../ui/checkbox'; import { Checkbox } from '../../ui/checkbox';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip';
@ -15,12 +14,6 @@ interface ASMDialogProps {
editingASMId: string | null; editingASMId: string | null;
asmManagerId: string; asmManagerId: string;
setAsmManagerId: (id: string) => void; 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'; asmStatus: 'active' | 'inactive';
setAsmStatus: (status: 'active' | 'inactive') => void; setAsmStatus: (status: 'active' | 'inactive') => void;
selectedASMZone: string; selectedASMZone: string;
@ -41,7 +34,6 @@ interface ASMDialogProps {
export const ASMDialog: React.FC<ASMDialogProps> = ({ export const ASMDialog: React.FC<ASMDialogProps> = ({
isOpen, onOpenChange, editingASMId, asmManagerId, setAsmManagerId, isOpen, onOpenChange, editingASMId, asmManagerId, setAsmManagerId,
asmName, setAsmName, asmCode, setAsmCode, asmEmployeeId, setAsmEmployeeId,
asmStatus, setAsmStatus, selectedASMZone, setSelectedASMZone, asmStatus, setAsmStatus, selectedASMZone, setSelectedASMZone,
selectedASMRegion, setSelectedASMRegion, selectedASMStates, setSelectedASMStates, selectedASMRegion, setSelectedASMRegion, selectedASMStates, setSelectedASMStates,
selectedASMDistricts, setSelectedASMDistricts, onSave, selectedASMDistricts, setSelectedASMDistricts, onSave,
@ -257,13 +249,7 @@ export const ASMDialog: React.FC<ASMDialogProps> = ({
setAsmManagerId(value); setAsmManagerId(value);
const selectedUser = userAssignedData.find(u => u.id === value); const selectedUser = userAssignedData.find(u => u.id === value);
if (selectedUser) { 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 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 // Extract zone/region from assignments if present
if (roleProfile?.zoneId) setSelectedASMZone(roleProfile.zoneId); if (roleProfile?.zoneId) setSelectedASMZone(roleProfile.zoneId);
@ -295,22 +281,6 @@ export const ASMDialog: React.FC<ASMDialogProps> = ({
</Select> </Select>
</div> </div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label>Employee ID</Label>
<Input readOnly placeholder="Auto-populated" className="mt-2 bg-slate-100" value={asmEmployeeId} />
</div>
<div>
<Label>ASM Code</Label>
<Input placeholder="Enter ASM Code" className="mt-2 text-slate-900" value={asmCode} onChange={(e) => setAsmCode(e.target.value)} />
</div>
</div>
<div>
<Label>Full Name</Label>
<Input placeholder="Enter full name" className="mt-2 text-slate-900" value={asmName} onChange={(e) => setAsmName(e.target.value)} />
</div>
<div> <div>
<Label>Status</Label> <Label>Status</Label>
<Select value={asmStatus} onValueChange={(val: 'active' | 'inactive') => setAsmStatus(val)}> <Select value={asmStatus} onValueChange={(val: 'active' | 'inactive') => setAsmStatus(val)}>

View File

@ -0,0 +1,99 @@
import React, { useEffect, useState } from 'react';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog';
import { Button } from '../../ui/button';
import { Input } from '../../ui/input';
import { Label } from '../../ui/label';
import { Textarea } from '../../ui/textarea';
interface AddRoleDialogProps {
isOpen: boolean;
onOpenChange: (open: boolean) => void;
onSave: (data: { roleCode: string; roleName: string; description?: string }) => Promise<void>;
}
export const AddRoleDialog: React.FC<AddRoleDialogProps> = ({
isOpen,
onOpenChange,
onSave
}) => {
const [roleName, setRoleName] = useState('');
const [roleCode, setRoleCode] = useState('');
const [description, setDescription] = useState('');
const [saving, setSaving] = useState(false);
useEffect(() => {
if (!isOpen) return;
setRoleName('');
setRoleCode('');
setDescription('');
setSaving(false);
}, [isOpen]);
const handleSubmit = async () => {
if (!roleName.trim() || !roleCode.trim()) return;
setSaving(true);
try {
await onSave({
roleName: roleName.trim(),
roleCode: roleCode.trim(),
description: description.trim() || undefined
});
onOpenChange(false);
} finally {
setSaving(false);
}
};
return (
<Dialog open={isOpen} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Add Role</DialogTitle>
<DialogDescription>Create a new role for Master Configuration.</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="role-name">Role Name</Label>
<Input
id="role-name"
value={roleName}
onChange={(e) => setRoleName(e.target.value)}
placeholder="e.g. Finance Admin"
/>
</div>
<div className="space-y-2">
<Label htmlFor="role-code">Role Code</Label>
<Input
id="role-code"
value={roleCode}
onChange={(e) => setRoleCode(e.target.value)}
placeholder="e.g. FINANCE_ADMIN"
/>
</div>
<div className="space-y-2">
<Label htmlFor="role-description">Description</Label>
<Textarea
id="role-description"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Optional"
rows={3}
/>
</div>
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={saving}>
Cancel
</Button>
<Button onClick={handleSubmit} disabled={saving || !roleName.trim() || !roleCode.trim()}>
{saving ? 'Saving...' : 'Create Role'}
</Button>
</div>
</DialogContent>
</Dialog>
);
};

View File

@ -3,7 +3,6 @@ import { useSelector } from 'react-redux';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog';
import { Button } from '../../ui/button'; import { Button } from '../../ui/button';
import { Label } from '../../ui/label'; import { Label } from '../../ui/label';
import { Input } from '../../ui/input';
import { Checkbox } from '../../ui/checkbox'; import { Checkbox } from '../../ui/checkbox';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
import { RootState } from '../../../store'; import { RootState } from '../../../store';
@ -14,12 +13,6 @@ interface DDLeadDialogProps {
editingLeadId: string | null; editingLeadId: string | null;
leadManagerId: string; leadManagerId: string;
setLeadManagerId: (id: string) => void; setLeadManagerId: (id: string) => void;
leadName: string;
setLeadName: (name: string) => void;
leadCode: string;
setLeadCode: (code: string) => void;
leadEmployeeId: string;
setLeadEmployeeId: (id: string) => void;
leadStatus: 'active' | 'inactive'; leadStatus: 'active' | 'inactive';
setLeadStatus: (status: 'active' | 'inactive') => void; setLeadStatus: (status: 'active' | 'inactive') => void;
selectedZones: string[]; selectedZones: string[];
@ -30,7 +23,6 @@ interface DDLeadDialogProps {
export const DDLeadDialog: React.FC<DDLeadDialogProps> = ({ export const DDLeadDialog: React.FC<DDLeadDialogProps> = ({
isOpen, onOpenChange, editingLeadId, leadManagerId, setLeadManagerId, isOpen, onOpenChange, editingLeadId, leadManagerId, setLeadManagerId,
leadName, setLeadName, leadCode, setLeadCode, leadEmployeeId, setLeadEmployeeId,
leadStatus, setLeadStatus, selectedZones, setSelectedZones, onSave, leadStatus, setLeadStatus, selectedZones, setSelectedZones, onSave,
userAssignedData userAssignedData
}) => { }) => {
@ -70,10 +62,6 @@ export const DDLeadDialog: React.FC<DDLeadDialogProps> = ({
setLeadManagerId(value); setLeadManagerId(value);
const selectedUser = userAssignedData.find(u => u.id === value); const selectedUser = userAssignedData.find(u => u.id === value);
if (selectedUser) { if (selectedUser) {
setLeadName(selectedUser.name);
setLeadEmployeeId(selectedUser.employeeId || '');
setLeadCode(selectedUser.leadCode || selectedUser.employeeId || '');
// If they have existing assigned zones // If they have existing assigned zones
if (selectedUser.assignedZoneIds) { if (selectedUser.assignedZoneIds) {
setSelectedZones(selectedUser.assignedZoneIds); setSelectedZones(selectedUser.assignedZoneIds);
@ -124,22 +112,6 @@ export const DDLeadDialog: React.FC<DDLeadDialogProps> = ({
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label>Employee ID</Label>
<Input readOnly placeholder="Auto-populated" className="mt-2 bg-slate-50 border-slate-200" value={leadEmployeeId} />
</div>
<div>
<Label>Lead Code</Label>
<Input placeholder="Enter Lead Code" className="mt-2 text-slate-900 border-slate-200" value={leadCode} onChange={(e) => setLeadCode(e.target.value)} />
</div>
</div>
<div>
<Label>Full Name</Label>
<Input placeholder="Enter full name" className="mt-2 text-slate-900 border-slate-200" value={leadName} onChange={(e) => setLeadName(e.target.value)} />
</div>
<div> <div>
<Label>Status</Label> <Label>Status</Label>
<Select value={leadStatus} onValueChange={(val: 'active' | 'inactive') => setLeadStatus(val)}> <Select value={leadStatus} onValueChange={(val: 'active' | 'inactive') => setLeadStatus(val)}>

View File

@ -9,9 +9,9 @@ interface LocationDialogProps {
isOpen: boolean; isOpen: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
editingLocationId: string | null; editingLocationId: string | null;
locationState: string; locationState: string; // stateId
setLocationState: (id: string) => void; setLocationState: (id: string) => void;
locationDistrict: string; locationDistrict: string; // districtId
setLocationDistrict: (id: string) => void; setLocationDistrict: (id: string) => void;
locationCity: string; locationCity: string;
setLocationCity: (city: string) => void; setLocationCity: (city: string) => void;
@ -21,6 +21,8 @@ interface LocationDialogProps {
setLocationActiveTo: (date: string) => void; setLocationActiveTo: (date: string) => void;
locationStatus: string; locationStatus: string;
setLocationStatus: (status: string) => void; setLocationStatus: (status: string) => void;
allStates: any[];
allDistricts: any[];
onSave: () => void; onSave: () => void;
} }
@ -28,8 +30,14 @@ export const LocationDialog: React.FC<LocationDialogProps> = ({
isOpen, onOpenChange, editingLocationId, locationState, setLocationState, isOpen, onOpenChange, editingLocationId, locationState, setLocationState,
locationDistrict, setLocationDistrict, locationCity, setLocationCity, locationDistrict, setLocationDistrict, locationCity, setLocationCity,
locationActiveFrom, setLocationActiveFrom, locationActiveFrom, setLocationActiveFrom,
locationActiveTo, setLocationActiveTo, locationStatus, setLocationStatus, onSave locationActiveTo, setLocationActiveTo, locationStatus, setLocationStatus,
allStates, allDistricts, onSave
}) => { }) => {
const filteredDistricts = React.useMemo(() => {
if (!locationState) return [];
return (allDistricts || []).filter((d: any) => d.stateId === locationState);
}, [allDistricts, locationState]);
return ( return (
<Dialog open={isOpen} onOpenChange={onOpenChange}> <Dialog open={isOpen} onOpenChange={onOpenChange}>
<DialogContent> <DialogContent>
@ -40,12 +48,24 @@ export const LocationDialog: React.FC<LocationDialogProps> = ({
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<Label className="flex items-center gap-2 text-sm leading-none font-medium text-slate-700">State</Label> <Label className="flex items-center gap-2 text-sm leading-none font-medium text-slate-700">State</Label>
<Input <Select
placeholder="Enter state name"
className="mt-2 text-slate-900 border-slate-200 focus-visible:ring-amber-500/30 focus-visible:border-amber-500"
value={locationState} value={locationState}
onChange={(e) => setLocationState(e.target.value)} onValueChange={(value) => {
/> setLocationState(value);
setLocationDistrict('');
}}
>
<SelectTrigger className="mt-2 text-slate-900 border-slate-200 focus:ring-amber-500/30 focus:border-amber-500">
<SelectValue placeholder="Select state" />
</SelectTrigger>
<SelectContent>
{(allStates || []).map((state: any) => (
<SelectItem key={state.id} value={state.id}>
{state.name || state.stateName}
</SelectItem>
))}
</SelectContent>
</Select>
</div> </div>
<div> <div>
<Label className="flex items-center gap-2 text-sm leading-none font-medium text-slate-700">City</Label> <Label className="flex items-center gap-2 text-sm leading-none font-medium text-slate-700">City</Label>
@ -58,12 +78,18 @@ export const LocationDialog: React.FC<LocationDialogProps> = ({
</div> </div>
<div> <div>
<Label className="flex items-center gap-2 text-sm leading-none font-medium text-slate-700">District</Label> <Label className="flex items-center gap-2 text-sm leading-none font-medium text-slate-700">District</Label>
<Input <Select value={locationDistrict} onValueChange={setLocationDistrict} disabled={!locationState}>
placeholder="Enter district name" <SelectTrigger className="mt-2 text-slate-900 border-slate-200 focus:ring-amber-500/30 focus:border-amber-500">
className="mt-2 text-slate-900 border-slate-200 focus-visible:ring-amber-500/30 focus-visible:border-amber-500" <SelectValue placeholder={locationState ? 'Select district' : 'Select state first'} />
value={locationDistrict} </SelectTrigger>
onChange={(e) => setLocationDistrict(e.target.value)} <SelectContent>
/> {filteredDistricts.map((district: any) => (
<SelectItem key={district.id} value={district.id}>
{district.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div> </div>
<div className="border rounded-lg p-4 bg-gradient-to-br from-blue-50 to-cyan-50 border-blue-200"> <div className="border rounded-lg p-4 bg-gradient-to-br from-blue-50 to-cyan-50 border-blue-200">

View File

@ -16,8 +16,6 @@ interface RegionDialogProps {
editingRegionId: string | null; editingRegionId: string | null;
regionName: string; regionName: string;
setRegionName: (name: string) => void; setRegionName: (name: string) => void;
regionCode: string;
setRegionCode: (code: string) => void;
regionDescription: string; regionDescription: string;
setRegionDescription: (desc: string) => void; setRegionDescription: (desc: string) => void;
selectedRegionZone: string; selectedRegionZone: string;
@ -32,7 +30,7 @@ interface RegionDialogProps {
export const RegionDialog: React.FC<RegionDialogProps> = ({ export const RegionDialog: React.FC<RegionDialogProps> = ({
isOpen, onOpenChange, editingRegionId, regionName, setRegionName, isOpen, onOpenChange, editingRegionId, regionName, setRegionName,
regionCode, setRegionCode, regionDescription, setRegionDescription, regionDescription, setRegionDescription,
selectedRegionZone, setSelectedRegionZone, regionalManagerId, setRegionalManagerId, selectedRegionZone, setSelectedRegionZone, regionalManagerId, setRegionalManagerId,
selectedRegionStates, setSelectedRegionStates, onSave, userAssignedData selectedRegionStates, setSelectedRegionStates, onSave, userAssignedData
}) => { }) => {
@ -142,16 +140,10 @@ export const RegionDialog: React.FC<RegionDialogProps> = ({
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
{/* Region Code & Name */} {/* Region Name */}
<div className="grid grid-cols-2 gap-4"> <div>
<div> <Label>Region Name</Label>
<Label>Region Code</Label> <Input placeholder="e.g., Delhi NCR Region" className="mt-2 text-slate-900" value={regionName} onChange={(e) => setRegionName(e.target.value)} />
<Input placeholder="e.g., NZ-R1" className="mt-2 text-slate-900" value={regionCode} onChange={(e) => setRegionCode(e.target.value)} />
</div>
<div>
<Label>Region Name</Label>
<Input placeholder="e.g., Delhi NCR Region" className="mt-2 text-slate-900" value={regionName} onChange={(e) => setRegionName(e.target.value)} />
</div>
</div> </div>
{/* Zone */} {/* Zone */}

View File

@ -3,7 +3,6 @@ import { useSelector } from 'react-redux';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog';
import { Button } from '../../ui/button'; import { Button } from '../../ui/button';
import { Label } from '../../ui/label'; import { Label } from '../../ui/label';
import { Input } from '../../ui/input';
import { Checkbox } from '../../ui/checkbox'; import { Checkbox } from '../../ui/checkbox';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
import { RootState } from '../../../store'; import { RootState } from '../../../store';
@ -14,12 +13,6 @@ interface ZMDialogProps {
editingZMId: string | null; editingZMId: string | null;
zmManagerId: string; zmManagerId: string;
setZmManagerId: (id: string) => void; setZmManagerId: (id: string) => void;
zmName: string;
setZmName: (name: string) => void;
zmCode: string;
setZmCode: (code: string) => void;
zmEmployeeId: string;
setZmEmployeeId: (id: string) => void;
zmStatus: 'active' | 'inactive'; zmStatus: 'active' | 'inactive';
setZmStatus: (status: 'active' | 'inactive') => void; setZmStatus: (status: 'active' | 'inactive') => void;
selectedZone: string; selectedZone: string;
@ -32,7 +25,6 @@ interface ZMDialogProps {
export const ZMDialog: React.FC<ZMDialogProps> = ({ export const ZMDialog: React.FC<ZMDialogProps> = ({
isOpen, onOpenChange, editingZMId, zmManagerId, setZmManagerId, isOpen, onOpenChange, editingZMId, zmManagerId, setZmManagerId,
zmName, setZmName, zmCode, setZmCode, zmEmployeeId, setZmEmployeeId,
zmStatus, setZmStatus, selectedZone, setSelectedZone, zmStatus, setZmStatus, selectedZone, setSelectedZone,
selectedRegions, setSelectedRegions, onSave, selectedRegions, setSelectedRegions, onSave,
userAssignedData userAssignedData
@ -66,10 +58,6 @@ export const ZMDialog: React.FC<ZMDialogProps> = ({
setZmManagerId(value); setZmManagerId(value);
const selectedUser = userAssignedData.find(u => u.id === value); const selectedUser = userAssignedData.find(u => u.id === value);
if (selectedUser) { if (selectedUser) {
setZmName(selectedUser.name);
setZmEmployeeId(selectedUser.employeeId || '');
setZmCode(selectedUser.zmCode || selectedUser.employeeId || '');
if (selectedUser.zoneId) setSelectedZone(selectedUser.zoneId); if (selectedUser.zoneId) setSelectedZone(selectedUser.zoneId);
if (selectedUser.assignedRegionIds) setSelectedRegions(selectedUser.assignedRegionIds); if (selectedUser.assignedRegionIds) setSelectedRegions(selectedUser.assignedRegionIds);
} }
@ -92,17 +80,6 @@ export const ZMDialog: React.FC<ZMDialogProps> = ({
</Select> </Select>
</div> </div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label>Employee ID</Label>
<Input readOnly className="mt-2 bg-slate-50 border-slate-200" value={zmEmployeeId} />
</div>
<div>
<Label>ZM Code</Label>
<Input placeholder="Enter ZM Code" className="mt-2" value={zmCode} onChange={(e) => setZmCode(e.target.value)} />
</div>
</div>
<div> <div>
<Label>Managed Zone <span className="text-red-500">*</span></Label> <Label>Managed Zone <span className="text-red-500">*</span></Label>
<Select value={selectedZone} onValueChange={(value) => { <Select value={selectedZone} onValueChange={(value) => {

View File

@ -31,14 +31,15 @@ export const ZoneDialog: React.FC<ZoneDialogProps> = ({
// Always include the currently assigned head to ensure pre-filling works // Always include the currently assigned head to ensure pre-filling works
if (zonalBusinessHeadId !== 'none' && u.id === zonalBusinessHeadId) return true; if (zonalBusinessHeadId !== 'none' && u.id === zonalBusinessHeadId) return true;
const roles = u.allRoles || []; const roles = (u.allRoles || []).map((r: string) => String(r || '').toUpperCase());
const topLevelRole = (u.roleCode || '').toUpperCase(); const topLevelRole = String(u.roleCode || u.role || '').toUpperCase();
return topLevelRole === 'ZBH' || roles.some((r: string) => { return topLevelRole === 'ZBH' || topLevelRole.includes('ZONAL BUSINESS HEAD') || roles.some((r: string) => {
const roleStr = (r || '').toUpperCase(); const roleStr = String(r || '').toUpperCase();
return roleStr === 'ZBH' || roleStr === 'ZONE BUSINESS HEAD' || roleStr === 'ZONAL BUSINESS HEAD'; return roleStr === 'ZBH' || roleStr === 'ZONE BUSINESS HEAD' || roleStr === 'ZONAL BUSINESS HEAD';
}); });
}); });
const dropdownUsers = filteredZBHUsers.length > 0 ? filteredZBHUsers : (userAssignedData || []);
// PRE-FILLING: When editing an existing zone, find its current ZBH from master data // PRE-FILLING: When editing an existing zone, find its current ZBH from master data
React.useEffect(() => { React.useEffect(() => {
@ -84,7 +85,7 @@ export const ZoneDialog: React.FC<ZoneDialogProps> = ({
</SelectTrigger> </SelectTrigger>
<SelectContent className="max-h-60"> <SelectContent className="max-h-60">
<SelectItem value="none">None / Unassigned</SelectItem> <SelectItem value="none">None / Unassigned</SelectItem>
{filteredZBHUsers.map((user) => ( {dropdownUsers.map((user) => (
<SelectItem key={user.id} value={user.id}> <SelectItem key={user.id} value={user.id}>
{user.name} ({user.email}) {user.name} ({user.email})
</SelectItem> </SelectItem>

View File

@ -50,14 +50,29 @@ export const useMasterData = () => {
const bodyZms = getBody(zmsRes); const bodyZms = getBody(zmsRes);
const bodyDdLeads = getBody(ddLeadsRes); const bodyDdLeads = getBody(ddLeadsRes);
const users = (bodyUsers?.users || bodyUsers?.data || []).map((u: any) => ({ const users = (bodyUsers?.users || bodyUsers?.data || []).map((u: any) => {
...u, const territory = Array.isArray(u.territoryProfile) ? u.territoryProfile : [];
name: u.fullName || u.name, const territoryZones = territory
role: u.role?.roleName || 'System User', .filter((t: any) => String(t.locationType || '').toLowerCase() === 'zone')
zone: u.allZones?.join(', ') || 'Global', .map((t: any) => t.locationName || t.zone)
region: u.allRegions?.join(', ') || 'Unassigned', .filter(Boolean);
status: u.isActive !== false ? 'Active' : 'Inactive' const territoryRegions = territory
})); .filter((t: any) => String(t.locationType || '').toLowerCase() === 'region')
.map((t: any) => t.locationName || t.region)
.filter(Boolean);
const zones = Array.from(new Set([...(u.allZones || []), ...territoryZones]));
const regions = Array.from(new Set([...(u.allRegions || []), ...territoryRegions]));
return {
...u,
name: u.fullName || u.name,
role: u.role?.roleName || (Array.isArray(u.allRoles) && u.allRoles.length > 0 ? u.allRoles[0] : 'System User'),
zone: zones.length > 0 ? zones.join(', ') : 'Global',
region: regions.length > 0 ? regions.join(', ') : 'Unassigned',
status: u.isActive !== false ? 'Active' : 'Inactive'
};
});
const roles = (bodyRoles?.roles || bodyRoles?.data || []).map((r: any) => ({ const roles = (bodyRoles?.roles || bodyRoles?.data || []).map((r: any) => ({
id: r.id, name: r.roleName, permissions: r.permissions?.map((p: any) => p.permissionCode) || [], userCount: r.userCount || 0 id: r.id, name: r.roleName, permissions: r.permissions?.map((p: any) => p.permissionCode) || [], userCount: r.userCount || 0

View File

@ -14,6 +14,10 @@ export const masterService = {
const response = await API.updateRole(id, data); const response = await API.updateRole(id, data);
return response.data; return response.data;
}, },
createRole: async (data: any) => {
const response = await (API as any).createRole(data);
return response.data;
},
// Zones & Regions // Zones & Regions
getZones: async () => { getZones: async () => {