(Feat): More changes
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { RefreshCw, Plus, Trash2, Edit, Save, X, Search, AlertTriangle, UserX } from 'lucide-react';
|
||||
import { Card, CardHeader, CardContent } from '../components/ui/Card';
|
||||
import { Card, CardContent } from '../components/ui/Card';
|
||||
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '../components/ui/Table';
|
||||
import { Button } from '../components/ui/Button';
|
||||
import { Input, Select } from '../components/ui/Input';
|
||||
import { Input, Select, PasswordInput } from '../components/ui/Input';
|
||||
import { useEmployees } from '../hooks/useEmployees';
|
||||
import { useDepartments } from '../hooks/useDepartments';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
@@ -29,6 +29,16 @@ export const UsersPage: React.FC = () => {
|
||||
departmentId: '',
|
||||
contractorId: '',
|
||||
isActive: true,
|
||||
// New fields
|
||||
phoneNumber: '',
|
||||
aadharNumber: '',
|
||||
bankAccountNumber: '',
|
||||
bankName: '',
|
||||
bankIfsc: '',
|
||||
// Contractor-specific
|
||||
contractorAgreementNumber: '',
|
||||
pfNumber: '',
|
||||
esicNumber: '',
|
||||
});
|
||||
const [formError, setFormError] = useState('');
|
||||
const [formLoading, setFormLoading] = useState(false);
|
||||
@@ -99,6 +109,16 @@ export const UsersPage: React.FC = () => {
|
||||
role: formData.role,
|
||||
departmentId: formData.departmentId ? parseInt(formData.departmentId) : null,
|
||||
contractorId: formData.contractorId ? parseInt(formData.contractorId) : null,
|
||||
// New fields
|
||||
phoneNumber: formData.phoneNumber || null,
|
||||
aadharNumber: formData.aadharNumber || null,
|
||||
bankAccountNumber: formData.bankAccountNumber || null,
|
||||
bankName: formData.bankName || null,
|
||||
bankIfsc: formData.bankIfsc || null,
|
||||
// Contractor-specific
|
||||
contractorAgreementNumber: formData.contractorAgreementNumber || null,
|
||||
pfNumber: formData.pfNumber || null,
|
||||
esicNumber: formData.esicNumber || null,
|
||||
});
|
||||
|
||||
// Reset form and switch to list
|
||||
@@ -111,6 +131,15 @@ export const UsersPage: React.FC = () => {
|
||||
role: 'Employee',
|
||||
departmentId: '',
|
||||
contractorId: '',
|
||||
isActive: true,
|
||||
phoneNumber: '',
|
||||
aadharNumber: '',
|
||||
bankAccountNumber: '',
|
||||
bankName: '',
|
||||
bankIfsc: '',
|
||||
contractorAgreementNumber: '',
|
||||
pfNumber: '',
|
||||
esicNumber: '',
|
||||
});
|
||||
setActiveTab('list');
|
||||
refresh();
|
||||
@@ -143,6 +172,15 @@ export const UsersPage: React.FC = () => {
|
||||
departmentId: user.department_id ? String(user.department_id) : '',
|
||||
contractorId: user.contractor_id ? String(user.contractor_id) : '',
|
||||
isActive: user.is_active,
|
||||
// New fields
|
||||
phoneNumber: user.phone_number || '',
|
||||
aadharNumber: user.aadhar_number || '',
|
||||
bankAccountNumber: user.bank_account_number || '',
|
||||
bankName: user.bank_name || '',
|
||||
bankIfsc: user.bank_ifsc || '',
|
||||
contractorAgreementNumber: user.contractor_agreement_number || '',
|
||||
pfNumber: user.pf_number || '',
|
||||
esicNumber: user.esic_number || '',
|
||||
});
|
||||
setEditingUserId(user.id);
|
||||
setActiveTab('edit');
|
||||
@@ -166,6 +204,15 @@ export const UsersPage: React.FC = () => {
|
||||
departmentId: formData.departmentId ? parseInt(formData.departmentId) : null,
|
||||
contractorId: formData.contractorId ? parseInt(formData.contractorId) : null,
|
||||
isActive: formData.isActive,
|
||||
// New fields
|
||||
phoneNumber: formData.phoneNumber || null,
|
||||
aadharNumber: formData.aadharNumber || null,
|
||||
bankAccountNumber: formData.bankAccountNumber || null,
|
||||
bankName: formData.bankName || null,
|
||||
bankIfsc: formData.bankIfsc || null,
|
||||
contractorAgreementNumber: formData.contractorAgreementNumber || null,
|
||||
pfNumber: formData.pfNumber || null,
|
||||
esicNumber: formData.esicNumber || null,
|
||||
});
|
||||
|
||||
resetForm();
|
||||
@@ -189,6 +236,14 @@ export const UsersPage: React.FC = () => {
|
||||
departmentId: '',
|
||||
contractorId: '',
|
||||
isActive: true,
|
||||
phoneNumber: '',
|
||||
aadharNumber: '',
|
||||
bankAccountNumber: '',
|
||||
bankName: '',
|
||||
bankIfsc: '',
|
||||
contractorAgreementNumber: '',
|
||||
pfNumber: '',
|
||||
esicNumber: '',
|
||||
});
|
||||
setEditingUserId(null);
|
||||
setFormError('');
|
||||
@@ -329,60 +384,89 @@ export const UsersPage: React.FC = () => {
|
||||
<TableHead>EMAIL</TableHead>
|
||||
<TableHead>ROLE</TableHead>
|
||||
<TableHead>DEPARTMENT</TableHead>
|
||||
<TableHead>REPORTS TO</TableHead>
|
||||
<TableHead>STATUS</TableHead>
|
||||
<TableHead>ACTIONS</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{filteredEmployees.map((user) => (
|
||||
<TableRow key={user.id}>
|
||||
<TableCell>{user.id}</TableCell>
|
||||
<TableCell className="text-blue-600">{user.username}</TableCell>
|
||||
<TableCell>{user.name}</TableCell>
|
||||
<TableCell>{user.email}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.role === 'SuperAdmin' ? 'bg-purple-100 text-purple-700' :
|
||||
user.role === 'Supervisor' ? 'bg-blue-100 text-blue-700' :
|
||||
user.role === 'Contractor' ? 'bg-orange-100 text-orange-700' :
|
||||
'bg-gray-100 text-gray-700'
|
||||
}`}>
|
||||
{user.role}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>{user.department_name || '-'}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.is_active ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
|
||||
}`}>
|
||||
{user.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{canManageUsers && (
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleEditUser(user)}
|
||||
className="text-blue-600 hover:text-blue-800"
|
||||
title="Edit"
|
||||
>
|
||||
<Edit size={14} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleDeleteUser(user.id, user.username)}
|
||||
className="text-red-600 hover:text-red-800"
|
||||
title="Delete"
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{filteredEmployees.map((user) => {
|
||||
// Find supervisor for contractors (supervisor in same department)
|
||||
const getSupervisorName = () => {
|
||||
if (user.role !== 'Contractor') return null;
|
||||
const supervisor = employees.find(
|
||||
e => e.role === 'Supervisor' && e.department_id === user.department_id
|
||||
);
|
||||
return supervisor?.name || null;
|
||||
};
|
||||
|
||||
// Get reports to info based on role
|
||||
const getReportsTo = () => {
|
||||
if (user.role === 'Employee') {
|
||||
return user.contractor_name ? (
|
||||
<span className="text-orange-600">{user.contractor_name}</span>
|
||||
) : '-';
|
||||
}
|
||||
if (user.role === 'Contractor') {
|
||||
const supervisorName = getSupervisorName();
|
||||
return supervisorName ? (
|
||||
<span className="text-blue-600">{supervisorName}</span>
|
||||
) : '-';
|
||||
}
|
||||
return '-';
|
||||
};
|
||||
|
||||
return (
|
||||
<TableRow key={user.id}>
|
||||
<TableCell>{user.id}</TableCell>
|
||||
<TableCell className="text-blue-600">{user.username}</TableCell>
|
||||
<TableCell>{user.name}</TableCell>
|
||||
<TableCell>{user.email}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.role === 'SuperAdmin' ? 'bg-purple-100 text-purple-700' :
|
||||
user.role === 'Supervisor' ? 'bg-blue-100 text-blue-700' :
|
||||
user.role === 'Contractor' ? 'bg-orange-100 text-orange-700' :
|
||||
'bg-gray-100 text-gray-700'
|
||||
}`}>
|
||||
{user.role}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>{user.department_name || '-'}</TableCell>
|
||||
<TableCell>{getReportsTo()}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.is_active ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
|
||||
}`}>
|
||||
{user.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{canManageUsers && (
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleEditUser(user)}
|
||||
className="text-blue-600 hover:text-blue-800"
|
||||
title="Edit"
|
||||
>
|
||||
<Edit size={14} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleDeleteUser(user.id, user.username)}
|
||||
className="text-red-600 hover:text-red-800"
|
||||
title="Delete"
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
) : !loading && (
|
||||
@@ -410,10 +494,9 @@ export const UsersPage: React.FC = () => {
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
<PasswordInput
|
||||
label="Password"
|
||||
name="password"
|
||||
type="password"
|
||||
value={formData.password}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
@@ -425,10 +508,9 @@ export const UsersPage: React.FC = () => {
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
<PasswordInput
|
||||
label="Confirm Password"
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
value={formData.confirmPassword}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
@@ -476,6 +558,82 @@ export const UsersPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Personal & Bank Details - for Employee and Contractor */}
|
||||
{(formData.role === 'Employee' || formData.role === 'Contractor') && (
|
||||
<>
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-6">Personal Details</h3>
|
||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
||||
<Input
|
||||
label="Phone Number"
|
||||
name="phoneNumber"
|
||||
value={formData.phoneNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="e.g., 9876543210"
|
||||
/>
|
||||
<Input
|
||||
label="Aadhar Card Number"
|
||||
name="aadharNumber"
|
||||
value={formData.aadharNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="12-digit Aadhar number"
|
||||
maxLength={12}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-6">Bank Details</h3>
|
||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
||||
<Input
|
||||
label="Bank Account Number"
|
||||
name="bankAccountNumber"
|
||||
value={formData.bankAccountNumber}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Input
|
||||
label="Bank Name"
|
||||
name="bankName"
|
||||
value={formData.bankName}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Input
|
||||
label="IFSC Code"
|
||||
name="bankIfsc"
|
||||
value={formData.bankIfsc}
|
||||
onChange={handleInputChange}
|
||||
placeholder="e.g., SBIN0001234"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Contractor-specific fields */}
|
||||
{formData.role === 'Contractor' && (
|
||||
<>
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-6">Contractor Details</h3>
|
||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
||||
<Input
|
||||
label="Contractor Agreement Number"
|
||||
name="contractorAgreementNumber"
|
||||
value={formData.contractorAgreementNumber}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Input
|
||||
label="PF Number"
|
||||
name="pfNumber"
|
||||
value={formData.pfNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Provident Fund number"
|
||||
/>
|
||||
<Input
|
||||
label="ESIC Number"
|
||||
name="esicNumber"
|
||||
value={formData.esicNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="ESIC registration number"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end gap-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -599,6 +757,82 @@ export const UsersPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Personal & Bank Details - for Employee and Contractor */}
|
||||
{(formData.role === 'Employee' || formData.role === 'Contractor') && (
|
||||
<>
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-6">Personal Details</h3>
|
||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
||||
<Input
|
||||
label="Phone Number"
|
||||
name="phoneNumber"
|
||||
value={formData.phoneNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="e.g., 9876543210"
|
||||
/>
|
||||
<Input
|
||||
label="Aadhar Card Number"
|
||||
name="aadharNumber"
|
||||
value={formData.aadharNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="12-digit Aadhar number"
|
||||
maxLength={12}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-6">Bank Details</h3>
|
||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
||||
<Input
|
||||
label="Bank Account Number"
|
||||
name="bankAccountNumber"
|
||||
value={formData.bankAccountNumber}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Input
|
||||
label="Bank Name"
|
||||
name="bankName"
|
||||
value={formData.bankName}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Input
|
||||
label="IFSC Code"
|
||||
name="bankIfsc"
|
||||
value={formData.bankIfsc}
|
||||
onChange={handleInputChange}
|
||||
placeholder="e.g., SBIN0001234"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Contractor-specific fields */}
|
||||
{formData.role === 'Contractor' && (
|
||||
<>
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-6">Contractor Details</h3>
|
||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
||||
<Input
|
||||
label="Contractor Agreement Number"
|
||||
name="contractorAgreementNumber"
|
||||
value={formData.contractorAgreementNumber}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Input
|
||||
label="PF Number"
|
||||
name="pfNumber"
|
||||
value={formData.pfNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Provident Fund number"
|
||||
/>
|
||||
<Input
|
||||
label="ESIC Number"
|
||||
name="esicNumber"
|
||||
value={formData.esicNumber}
|
||||
onChange={handleInputChange}
|
||||
placeholder="ESIC registration number"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end gap-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -718,49 +952,78 @@ export const UsersPage: React.FC = () => {
|
||||
<TableHead>EMAIL</TableHead>
|
||||
<TableHead>ROLE</TableHead>
|
||||
<TableHead>DEPARTMENT</TableHead>
|
||||
<TableHead>REPORTS TO</TableHead>
|
||||
<TableHead>STATUS</TableHead>
|
||||
<TableHead>ACTION</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{deletableUsers.map((user) => (
|
||||
<TableRow key={user.id} className="hover:bg-red-50">
|
||||
<TableCell>{user.id}</TableCell>
|
||||
<TableCell className="text-blue-600">{user.username}</TableCell>
|
||||
<TableCell>{user.name}</TableCell>
|
||||
<TableCell>{user.email}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.role === 'Contractor' ? 'bg-orange-100 text-orange-700' :
|
||||
'bg-gray-100 text-gray-700'
|
||||
}`}>
|
||||
{user.role}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>{user.department_name || '-'}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.is_active ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
|
||||
}`}>
|
||||
{user.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
if (confirm(`Are you sure you want to permanently delete "${user.name}" (${user.username})?\n\nThis action cannot be undone!`)) {
|
||||
deleteEmployee(user.id);
|
||||
}
|
||||
}}
|
||||
className="text-red-600 border-red-300 hover:bg-red-50 hover:border-red-400"
|
||||
>
|
||||
<UserX size={14} className="mr-1" />
|
||||
Delete
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{deletableUsers.map((user) => {
|
||||
// Find supervisor for contractors (supervisor in same department)
|
||||
const getSupervisorName = () => {
|
||||
if (user.role !== 'Contractor') return null;
|
||||
const supervisor = employees.find(
|
||||
e => e.role === 'Supervisor' && e.department_id === user.department_id
|
||||
);
|
||||
return supervisor?.name || null;
|
||||
};
|
||||
|
||||
// Get reports to info based on role
|
||||
const getReportsTo = () => {
|
||||
if (user.role === 'Employee') {
|
||||
return user.contractor_name ? (
|
||||
<span className="text-orange-600">{user.contractor_name}</span>
|
||||
) : '-';
|
||||
}
|
||||
if (user.role === 'Contractor') {
|
||||
const supervisorName = getSupervisorName();
|
||||
return supervisorName ? (
|
||||
<span className="text-blue-600">{supervisorName}</span>
|
||||
) : '-';
|
||||
}
|
||||
return '-';
|
||||
};
|
||||
|
||||
return (
|
||||
<TableRow key={user.id} className="hover:bg-red-50">
|
||||
<TableCell>{user.id}</TableCell>
|
||||
<TableCell className="text-blue-600">{user.username}</TableCell>
|
||||
<TableCell>{user.name}</TableCell>
|
||||
<TableCell>{user.email}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.role === 'Contractor' ? 'bg-orange-100 text-orange-700' :
|
||||
'bg-gray-100 text-gray-700'
|
||||
}`}>
|
||||
{user.role}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>{user.department_name || '-'}</TableCell>
|
||||
<TableCell>{getReportsTo()}</TableCell>
|
||||
<TableCell>
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
user.is_active ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
|
||||
}`}>
|
||||
{user.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
if (confirm(`Are you sure you want to permanently delete "${user.name}" (${user.username})?\n\nThis action cannot be undone!`)) {
|
||||
deleteEmployee(user.id);
|
||||
}
|
||||
}}
|
||||
className="text-red-600 border-red-300 hover:bg-red-50 hover:border-red-400"
|
||||
>
|
||||
<UserX size={14} className="mr-1" />
|
||||
Delete
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user