Compare commits
No commits in common. "9bdacdec7f7b46cf6f8be426f7faf3907199568d" and "fb1a0b15cf546180796832837b66579772e6e13c" have entirely different histories.
9bdacdec7f
...
fb1a0b15cf
@ -1,14 +0,0 @@
|
|||||||
[
|
|
||||||
{ "id": "DEP001", "name": "IT", "branchId": "BR001", "branchName": "Bengaluru", "companyId": "CMP001", "companyName": "CLRI", "status": "Active" },
|
|
||||||
{ "id": "DEP002", "name": "Training", "branchId": "BR002", "branchName": "Pune", "companyId": "CMP001", "companyName": "CLRI", "status": "Active" },
|
|
||||||
{ "id": "DEP003", "name": "Analytics", "branchId": "BR001", "branchName": "Bengaluru", "companyId": "CMP001", "companyName": "CLRI", "status": "Disabled" },
|
|
||||||
{ "id": "DEP004", "name": "Placement", "branchId": "BR001", "branchName": "Bengaluru", "companyId": "CMP001", "companyName": "CLRI", "status": "Active" },
|
|
||||||
{ "id": "DEP005", "name": "Digital Marketing", "branchId": "BR002", "branchName": "Pune", "companyId": "CMP001", "companyName": "CLRI", "status": "Active" },
|
|
||||||
{ "id": "DEP006", "name": "Software Dev", "branchId": "BR004", "branchName": "Mumbai", "companyId": "CMP002", "companyName": "TechNova Solutions", "status": "Active" },
|
|
||||||
{ "id": "DEP007", "name": "QA", "branchId": "BR004", "branchName": "Mumbai", "companyId": "CMP002", "companyName": "TechNova Solutions", "status": "Active" },
|
|
||||||
{ "id": "DEP008", "name": "HR", "branchId": "BR006", "branchName": "Chennai", "companyId": "CMP003", "companyName": "Infotech Ltd", "status": "Active" },
|
|
||||||
{ "id": "DEP009", "name": "Sales", "branchId": "BR006", "branchName": "Chennai", "companyId": "CMP003", "companyName": "Infotech Ltd", "status": "Disabled" },
|
|
||||||
{ "id": "DEP010", "name": "Support", "branchId": "BR008", "branchName": "Ahmedabad", "companyId": "CMP004", "companyName": "Global Systems", "status": "Active" },
|
|
||||||
{ "id": "DEP011", "name": "Admin", "branchId": "BR010", "branchName": "Surat", "companyId": "CMP005", "companyName": "Alpha Corp", "status": "Active" },
|
|
||||||
{ "id": "DEP012", "name": "Operations", "branchId": "BR011", "branchName": "Lucknow", "companyId": "CMP006", "companyName": "Beta Industries", "status": "Active" }
|
|
||||||
]
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
import { AlertTriangle, X } from 'lucide-react';
|
|
||||||
|
|
||||||
interface ConfirmationModalProps {
|
|
||||||
title: string;
|
|
||||||
message: string;
|
|
||||||
onConfirm: () => void;
|
|
||||||
onClose: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ConfirmationModal({ title, message, onConfirm, onClose }: ConfirmationModalProps) {
|
|
||||||
return (
|
|
||||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-[60] p-4">
|
|
||||||
<div className="bg-app-card rounded-lg shadow-xl w-full max-w-sm p-6 relative text-center">
|
|
||||||
<button onClick={onClose} className="absolute top-4 right-4 text-text-muted hover:text-text-primary">
|
|
||||||
<X size={24} />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-absent-100 mb-4">
|
|
||||||
<AlertTriangle className="h-6 w-6 text-absent-500" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 className="text-lg font-medium text-text-primary mb-2">{title}</h3>
|
|
||||||
<p className="text-sm text-text-muted mb-6">{message}</p>
|
|
||||||
|
|
||||||
<div className="flex justify-center space-x-3">
|
|
||||||
<button
|
|
||||||
onClick={onClose}
|
|
||||||
className="px-4 py-2 bg-app-muted text-text-primary rounded-lg hover:bg-app-border transition-colors text-sm font-medium"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={onConfirm}
|
|
||||||
className="px-4 py-2 bg-absent-500 text-white rounded-lg hover:bg-absent-600 transition-colors text-sm font-medium"
|
|
||||||
>
|
|
||||||
Yes, Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
|
||||||
import { fetchMockData } from '../../../api/client';
|
|
||||||
|
|
||||||
export interface Department {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
branchId: string;
|
|
||||||
branchName: string;
|
|
||||||
companyId: string;
|
|
||||||
companyName: string;
|
|
||||||
status: 'Active' | 'Disabled';
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useDepartments = () => {
|
|
||||||
return useQuery<Department[]>({
|
|
||||||
queryKey: ['departments'],
|
|
||||||
queryFn: () => fetchMockData<Department[]>('master-data/departments.json'),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { X } from 'lucide-react';
|
import { X } from 'lucide-react';
|
||||||
import type { Branch } from '../../api/useBranchData';
|
import type { Branch } from '../api/useBranchData';
|
||||||
import type { Company } from '../../api/useCompanyData';
|
import type { Company } from '../api/useCompanyData';
|
||||||
|
|
||||||
interface BranchFormModalProps {
|
interface BranchFormModalProps {
|
||||||
branch: Branch | null; // null means Add mode, object means Edit mode
|
branch: Branch | null; // null means Add mode, object means Edit mode
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo } from 'react';
|
||||||
import { ArrowUpDown, ArrowUp, ArrowDown, Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Pencil, Trash2 } from 'lucide-react';
|
import { ArrowUpDown, ArrowUp, ArrowDown, Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Pencil, Trash2 } from 'lucide-react';
|
||||||
import type { Branch } from '../../api/useBranchData';
|
import type { Branch } from '../api/useBranchData';
|
||||||
|
|
||||||
interface BranchTableProps {
|
interface BranchTableProps {
|
||||||
records: Branch[];
|
records: Branch[];
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { X } from 'lucide-react';
|
import { X } from 'lucide-react';
|
||||||
import type { Company } from '../../api/useCompanyData';
|
import type { Company } from '../api/useCompanyData';
|
||||||
|
|
||||||
interface CompanyFormModalProps {
|
interface CompanyFormModalProps {
|
||||||
company: Company | null; // null means Add mode, object means Edit mode
|
company: Company | null; // null means Add mode, object means Edit mode
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo } from 'react';
|
||||||
import { ArrowUpDown, ArrowUp, ArrowDown, Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Pencil, Trash2 } from 'lucide-react';
|
import { ArrowUpDown, ArrowUp, ArrowDown, Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Pencil, Trash2 } from 'lucide-react';
|
||||||
import type { Company } from '../../api/useCompanyData';
|
import type { Company } from '../api/useCompanyData';
|
||||||
|
|
||||||
interface CompanyTableProps {
|
interface CompanyTableProps {
|
||||||
records: Company[];
|
records: Company[];
|
||||||
@ -1,141 +0,0 @@
|
|||||||
import { useState, useEffect, useMemo } from 'react';
|
|
||||||
import { X } from 'lucide-react';
|
|
||||||
import type { Department } from '../../api/useDepartmentData';
|
|
||||||
import type { Company } from '../../api/useCompanyData';
|
|
||||||
import type { Branch } from '../../api/useBranchData';
|
|
||||||
|
|
||||||
interface DepartmentFormModalProps {
|
|
||||||
department: Department | null; // null means Add mode
|
|
||||||
companies: Company[];
|
|
||||||
branches: Branch[];
|
|
||||||
onClose: () => void;
|
|
||||||
onSave: (data: Omit<Department, 'id'>) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function DepartmentFormModal({ department, companies, branches, onClose, onSave }: DepartmentFormModalProps) {
|
|
||||||
const [name, setName] = useState('');
|
|
||||||
const [companyId, setCompanyId] = useState('');
|
|
||||||
const [branchId, setBranchId] = useState('');
|
|
||||||
const [status, setStatus] = useState<'Active' | 'Disabled'>('Active');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (department) {
|
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
||||||
setName(department.name);
|
|
||||||
setCompanyId(department.companyId);
|
|
||||||
setBranchId(department.branchId);
|
|
||||||
setStatus(department.status);
|
|
||||||
} else {
|
|
||||||
setName('');
|
|
||||||
setCompanyId(companies.length > 0 ? companies[0].id : '');
|
|
||||||
setBranchId('');
|
|
||||||
setStatus('Active');
|
|
||||||
}
|
|
||||||
}, [department, companies]);
|
|
||||||
|
|
||||||
// Filter branches based on selected company
|
|
||||||
const filteredBranches = useMemo(() => {
|
|
||||||
return branches.filter(b => b.companyId === companyId);
|
|
||||||
}, [branches, companyId]);
|
|
||||||
|
|
||||||
const handleCompanyChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
||||||
setCompanyId(e.target.value);
|
|
||||||
setBranchId(''); // Reset branch when company changes
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const selectedCompany = companies.find(c => c.id === companyId);
|
|
||||||
const selectedBranch = branches.find(b => b.id === branchId);
|
|
||||||
|
|
||||||
onSave({
|
|
||||||
name,
|
|
||||||
companyId,
|
|
||||||
companyName: selectedCompany?.name || '',
|
|
||||||
branchId,
|
|
||||||
branchName: selectedBranch?.name || '',
|
|
||||||
status,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
|
||||||
<div className="bg-app-card rounded-lg shadow-xl w-full max-w-md p-6 relative">
|
|
||||||
<button onClick={onClose} className="absolute top-4 right-4 text-text-muted hover:text-text-primary">
|
|
||||||
<X size={24} />
|
|
||||||
</button>
|
|
||||||
<h3 className="text-xl font-bold text-text-primary mb-6">
|
|
||||||
{department ? 'Edit Department' : 'Add New Department'}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-text-secondary mb-1">Department Name</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={name}
|
|
||||||
onChange={(e) => setName(e.target.value)}
|
|
||||||
required
|
|
||||||
className="w-full px-3 py-2 border border-app-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary text-text-secondary bg-app-card"
|
|
||||||
placeholder="Enter department name..."
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-text-secondary mb-1">Company</label>
|
|
||||||
<select
|
|
||||||
value={companyId}
|
|
||||||
onChange={handleCompanyChange}
|
|
||||||
required
|
|
||||||
className="w-full px-3 py-2 border border-app-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary text-text-secondary bg-app-card"
|
|
||||||
>
|
|
||||||
{companies.length === 0 ? (
|
|
||||||
<option value="">No companies available</option>
|
|
||||||
) : (
|
|
||||||
companies.map(c => <option key={c.id} value={c.id}>{c.name}</option>)
|
|
||||||
)}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-text-secondary mb-1">Branch</label>
|
|
||||||
<select
|
|
||||||
value={branchId}
|
|
||||||
onChange={(e) => setBranchId(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={!companyId || filteredBranches.length === 0}
|
|
||||||
className="w-full px-3 py-2 border border-app-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary text-text-secondary bg-app-card disabled:opacity-50 disabled:cursor-not-allowed"
|
|
||||||
>
|
|
||||||
<option value="">Select Branch</option>
|
|
||||||
{filteredBranches.map(b => <option key={b.id} value={b.id}>{b.name}</option>)}
|
|
||||||
</select>
|
|
||||||
{companyId && filteredBranches.length === 0 && (
|
|
||||||
<p className="text-xs text-absent-500 mt-1">No branches found for this company. Please add a branch first.</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-text-secondary mb-1">Status</label>
|
|
||||||
<select
|
|
||||||
value={status}
|
|
||||||
onChange={(e) => setStatus(e.target.value as 'Active' | 'Disabled')}
|
|
||||||
className="w-full px-3 py-2 border border-app-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary text-text-secondary bg-app-card"
|
|
||||||
>
|
|
||||||
<option value="Active">Active</option>
|
|
||||||
<option value="Disabled">Disabled</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-end space-x-3 mt-6">
|
|
||||||
<button type="button" onClick={onClose} className="px-4 py-2 bg-app-muted text-text-primary rounded-lg hover:bg-app-border transition-colors text-sm font-medium">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="submit" disabled={!branchId} className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-hover transition-colors text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed">
|
|
||||||
{department ? 'Update' : 'Add'} Department
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
import { useState, useMemo } from 'react';
|
|
||||||
import { ArrowUpDown, ArrowUp, ArrowDown, Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Pencil, Trash2 } from 'lucide-react';
|
|
||||||
import type { Department } from '../../api/useDepartmentData';
|
|
||||||
|
|
||||||
interface DepartmentTableProps {
|
|
||||||
records: Department[];
|
|
||||||
onEdit: (department: Department) => void;
|
|
||||||
onDelete: (id: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
type SortKey = 'id' | 'name' | 'branchName' | 'companyName' | 'status';
|
|
||||||
type SortDirection = 'ascending' | 'descending';
|
|
||||||
|
|
||||||
const getStatusClass = (status: string) => {
|
|
||||||
switch (status) {
|
|
||||||
case 'Active': return 'bg-present-100 text-present-700';
|
|
||||||
case 'Disabled': return 'bg-absent-100 text-absent-700';
|
|
||||||
default: return 'bg-app-muted text-text-secondary';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function DepartmentTable({ records, onEdit, onDelete }: DepartmentTableProps) {
|
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [pageSize, setPageSize] = useState(10);
|
|
||||||
|
|
||||||
const [sortConfig, setSortConfig] = useState<{ key: SortKey; direction: SortDirection }>({
|
|
||||||
key: 'name',
|
|
||||||
direction: 'ascending'
|
|
||||||
});
|
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
|
||||||
if (!searchQuery) return records;
|
|
||||||
return records.filter(record =>
|
|
||||||
record.id.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
record.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
record.branchName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
record.companyName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
record.status.toLowerCase().includes(searchQuery.toLowerCase())
|
|
||||||
);
|
|
||||||
}, [records, searchQuery]);
|
|
||||||
|
|
||||||
const sortedData = useMemo(() => {
|
|
||||||
const sortableData = [...filteredData];
|
|
||||||
sortableData.sort((a, b) => {
|
|
||||||
if (a[sortConfig.key] < b[sortConfig.key]) return sortConfig.direction === 'ascending' ? -1 : 1;
|
|
||||||
if (a[sortConfig.key] > b[sortConfig.key]) return sortConfig.direction === 'ascending' ? 1 : -1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
return sortableData;
|
|
||||||
}, [filteredData, sortConfig]);
|
|
||||||
|
|
||||||
const totalPages = Math.ceil(sortedData.length / pageSize);
|
|
||||||
const isPaginationEnabled = sortedData.length > pageSize;
|
|
||||||
|
|
||||||
const paginatedData = useMemo(() => {
|
|
||||||
const startIndex = (currentPage - 1) * pageSize;
|
|
||||||
return sortedData.slice(startIndex, startIndex + pageSize);
|
|
||||||
}, [sortedData, currentPage, pageSize]);
|
|
||||||
|
|
||||||
const pageNumbers = useMemo(() => {
|
|
||||||
const pages = [];
|
|
||||||
const maxVisiblePages = 5;
|
|
||||||
let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
|
|
||||||
let endPage = startPage + maxVisiblePages - 1;
|
|
||||||
if (endPage > totalPages) {
|
|
||||||
endPage = totalPages;
|
|
||||||
startPage = Math.max(1, endPage - maxVisiblePages + 1);
|
|
||||||
}
|
|
||||||
for (let i = startPage; i <= endPage; i++) pages.push(i);
|
|
||||||
return pages;
|
|
||||||
}, [currentPage, totalPages]);
|
|
||||||
|
|
||||||
const requestSort = (key: SortKey) => {
|
|
||||||
let direction: SortDirection = 'ascending';
|
|
||||||
if (sortConfig.key === key && sortConfig.direction === 'ascending') direction = 'descending';
|
|
||||||
setSortConfig({ key, direction });
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageSizeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
||||||
setPageSize(Number(e.target.value));
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSortIcon = (key: SortKey) => {
|
|
||||||
if (sortConfig.key !== key) return <ArrowUpDown size={14} className="ml-1 text-text-light" />;
|
|
||||||
if (sortConfig.direction === 'ascending') return <ArrowUp size={14} className="ml-1 text-primary" />;
|
|
||||||
return <ArrowDown size={14} className="ml-1 text-primary" />;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bg-app-card p-6 rounded-lg shadow-sm">
|
|
||||||
<div className="flex flex-col md:flex-row md:items-center justify-between mb-6 gap-4">
|
|
||||||
<h2 className="text-lg font-semibold text-text-primary">Departments List</h2>
|
|
||||||
<div className="relative w-full md:w-64">
|
|
||||||
<Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-text-light" />
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Search id, name, branch..."
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={(e) => { setSearchQuery(e.target.value); setCurrentPage(1); }}
|
|
||||||
className="pl-9 pr-3 py-2 border border-app-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary text-text-secondary bg-app-card w-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="min-w-full divide-y divide-app-border">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
{(['id', 'name', 'branchName', 'companyName', 'status'] as SortKey[]).map((key) => (
|
|
||||||
<th
|
|
||||||
key={key}
|
|
||||||
onClick={() => requestSort(key)}
|
|
||||||
className="px-6 py-3 text-left text-xs font-semibold text-text-muted uppercase tracking-wider cursor-pointer hover:bg-app-muted transition-colors"
|
|
||||||
>
|
|
||||||
<div className="flex items-center">
|
|
||||||
{key === 'id' ? 'Dept ID' : key === 'name' ? 'Department' : key === 'branchName' ? 'Branch' : key === 'companyName' ? 'Company' : key.charAt(0).toUpperCase() + key.slice(1)} {getSortIcon(key)}
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
))}
|
|
||||||
<th className="px-6 py-3 text-left text-xs font-semibold text-text-muted uppercase tracking-wider">Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="divide-y divide-app-border">
|
|
||||||
{paginatedData.length > 0 ? (
|
|
||||||
paginatedData.map((record) => (
|
|
||||||
<tr key={record.id} className="hover:bg-app-muted transition-colors">
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-text-primary">{record.id}</td>
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-text-secondary">{record.name}</td>
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-text-secondary">{record.branchName}</td>
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-text-secondary">{record.companyName}</td>
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm">
|
|
||||||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getStatusClass(record.status)}`}>{record.status}</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm flex space-x-3">
|
|
||||||
<button onClick={() => onEdit(record)} className="text-primary hover:text-primary-hover flex items-center">
|
|
||||||
<Pencil size={16} className="mr-1" /> Edit
|
|
||||||
</button>
|
|
||||||
<button onClick={() => onDelete(record.id)} className="text-absent-500 hover:text-absent-700 flex items-center">
|
|
||||||
<Trash2 size={16} className="mr-1" /> Delete
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<tr>
|
|
||||||
<td colSpan={6} className="px-6 py-8 text-center text-sm text-text-muted">No departments found.</td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col md:flex-row md:items-center justify-between mt-4 pt-4 border-t border-app-border gap-4">
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<span className="text-sm text-text-muted">Show</span>
|
|
||||||
<select value={pageSize} onChange={handlePageSizeChange} className="px-2 py-1 border border-app-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary text-text-secondary bg-app-card">
|
|
||||||
<option value={10}>10</option>
|
|
||||||
<option value={15}>15</option>
|
|
||||||
<option value={20}>20</option>
|
|
||||||
</select>
|
|
||||||
<span className="text-sm text-text-muted">entries</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isPaginationEnabled && totalPages > 1 && (
|
|
||||||
<div className="flex items-center space-x-1">
|
|
||||||
<span className="text-sm text-text-muted mr-2 hidden sm:inline">Page {currentPage} of {totalPages}</span>
|
|
||||||
<button onClick={() => setCurrentPage(1)} disabled={currentPage === 1} className="p-2 border border-app-border rounded-lg text-text-secondary hover:bg-app-muted disabled:opacity-50 disabled:cursor-not-allowed transition-colors"><ChevronsLeft size={16} /></button>
|
|
||||||
<button onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))} disabled={currentPage === 1} className="p-2 border border-app-border rounded-lg text-text-secondary hover:bg-app-muted disabled:opacity-50 disabled:cursor-not-allowed transition-colors"><ChevronLeft size={16} /></button>
|
|
||||||
{pageNumbers.map(num => (
|
|
||||||
<button key={num} onClick={() => setCurrentPage(num)} className={`w-8 h-8 flex items-center justify-center border rounded-lg text-sm transition-colors ${currentPage === num ? 'bg-primary text-white border-primary' : 'border-app-border text-text-secondary hover:bg-app-muted'}`}>{num}</button>
|
|
||||||
))}
|
|
||||||
<button onClick={() => setCurrentPage(prev => Math.min(prev + 1, totalPages))} disabled={currentPage === totalPages} className="p-2 border border-app-border rounded-lg text-text-secondary hover:bg-app-muted disabled:opacity-50 disabled:cursor-not-allowed transition-colors"><ChevronRight size={16} /></button>
|
|
||||||
<button onClick={() => setCurrentPage(totalPages)} disabled={currentPage === totalPages} className="p-2 border border-app-border rounded-lg text-text-secondary hover:bg-app-muted disabled:opacity-50 disabled:cursor-not-allowed transition-colors"><ChevronsRight size={16} /></button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -3,9 +3,8 @@ import { Network, Plus } from 'lucide-react';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import Loader from '../../../components/ui/Loader';
|
import Loader from '../../../components/ui/Loader';
|
||||||
import ErrorState from '../../../components/ui/ErrorState';
|
import ErrorState from '../../../components/ui/ErrorState';
|
||||||
import ConfirmationModal from '../../../components/ui/ConfirmationModal'; // New Import
|
import BranchTable from '../components/BranchTable';
|
||||||
import BranchTable from '../components/branch/BranchTable';
|
import BranchFormModal from '../components/BranchFormModal';
|
||||||
import BranchFormModal from '../components/branch/BranchFormModal';
|
|
||||||
import { useBranches, type Branch } from '../api/useBranchData';
|
import { useBranches, type Branch } from '../api/useBranchData';
|
||||||
import { useCompanies } from '../api/useCompanyData';
|
import { useCompanies } from '../api/useCompanyData';
|
||||||
|
|
||||||
@ -16,8 +15,8 @@ export default function ManageBranches() {
|
|||||||
const [localRecords, setLocalRecords] = useState<Branch[]>([]);
|
const [localRecords, setLocalRecords] = useState<Branch[]>([]);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [editingBranch, setEditingBranch] = useState<Branch | null>(null);
|
const [editingBranch, setEditingBranch] = useState<Branch | null>(null);
|
||||||
const [deleteId, setDeleteId] = useState<string | null>(null); // New state
|
|
||||||
|
|
||||||
|
// Sync local state when API data loads
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-render
|
// eslint-disable-next-line react-hooks/set-state-in-render
|
||||||
if (apiRecords) setLocalRecords(apiRecords);
|
if (apiRecords) setLocalRecords(apiRecords);
|
||||||
@ -34,22 +33,17 @@ export default function ManageBranches() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteClick = (id: string) => {
|
const handleDeleteClick = (id: string) => {
|
||||||
setDeleteId(id); // Open confirmation modal
|
setLocalRecords(prev => prev.filter(b => b.id !== id));
|
||||||
};
|
toast.success("Branch deleted successfully.");
|
||||||
|
|
||||||
const confirmDelete = () => {
|
|
||||||
if (deleteId) {
|
|
||||||
setLocalRecords(prev => prev.filter(b => b.id !== deleteId));
|
|
||||||
toast.success("Branch deleted successfully.");
|
|
||||||
setDeleteId(null);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = (name: string, companyId: string, companyName: string, status: 'Active' | 'Disabled') => {
|
const handleSave = (name: string, companyId: string, companyName: string, status: 'Active' | 'Disabled') => {
|
||||||
if (editingBranch) {
|
if (editingBranch) {
|
||||||
|
// Edit existing
|
||||||
setLocalRecords(prev => prev.map(b => b.id === editingBranch.id ? { ...b, name, companyId, companyName, status } : b));
|
setLocalRecords(prev => prev.map(b => b.id === editingBranch.id ? { ...b, name, companyId, companyName, status } : b));
|
||||||
toast.success("Branch updated successfully.");
|
toast.success("Branch updated successfully.");
|
||||||
} else {
|
} else {
|
||||||
|
// Add new
|
||||||
const newId = `BR${String(localRecords.length + 1).padStart(3, '0')}`;
|
const newId = `BR${String(localRecords.length + 1).padStart(3, '0')}`;
|
||||||
setLocalRecords(prev => [...prev, { id: newId, name, companyId, companyName, status }]);
|
setLocalRecords(prev => [...prev, { id: newId, name, companyId, companyName, status }]);
|
||||||
toast.success("Branch added successfully.");
|
toast.success("Branch added successfully.");
|
||||||
@ -62,6 +56,7 @@ export default function ManageBranches() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
{/* Header & Add Button */}
|
||||||
<div className="bg-app-card p-6 rounded-lg shadow-sm flex flex-col md:flex-row md:items-center justify-between gap-4">
|
<div className="bg-app-card p-6 rounded-lg shadow-sm flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<div className="p-3 bg-primary/10 rounded-full">
|
<div className="p-3 bg-primary/10 rounded-full">
|
||||||
@ -81,8 +76,10 @@ export default function ManageBranches() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Table */}
|
||||||
<BranchTable records={localRecords} onEdit={handleEditClick} onDelete={handleDeleteClick} />
|
<BranchTable records={localRecords} onEdit={handleEditClick} onDelete={handleDeleteClick} />
|
||||||
|
|
||||||
|
{/* Modal */}
|
||||||
{isModalOpen && (
|
{isModalOpen && (
|
||||||
<BranchFormModal
|
<BranchFormModal
|
||||||
branch={editingBranch}
|
branch={editingBranch}
|
||||||
@ -91,16 +88,6 @@ export default function ManageBranches() {
|
|||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
|
||||||
{deleteId && (
|
|
||||||
<ConfirmationModal
|
|
||||||
title="Delete Branch?"
|
|
||||||
message="Are you sure you want to delete this branch? This action cannot be undone."
|
|
||||||
onConfirm={confirmDelete}
|
|
||||||
onClose={() => setDeleteId(null)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3,9 +3,8 @@ import { Building, Plus } from 'lucide-react';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import Loader from '../../../components/ui/Loader';
|
import Loader from '../../../components/ui/Loader';
|
||||||
import ErrorState from '../../../components/ui/ErrorState';
|
import ErrorState from '../../../components/ui/ErrorState';
|
||||||
import ConfirmationModal from '../../../components/ui/ConfirmationModal'; // New Import
|
import CompanyTable from '../components/CompanyTable';
|
||||||
import CompanyTable from '../components/company/CompanyTable';
|
import CompanyFormModal from '../components/CompanyFormModal';
|
||||||
import CompanyFormModal from '../components/company/CompanyFormModal';
|
|
||||||
import { useCompanies, type Company } from '../api/useCompanyData';
|
import { useCompanies, type Company } from '../api/useCompanyData';
|
||||||
|
|
||||||
export default function ManageCompanies() {
|
export default function ManageCompanies() {
|
||||||
@ -13,8 +12,8 @@ export default function ManageCompanies() {
|
|||||||
const [localRecords, setLocalRecords] = useState<Company[]>([]);
|
const [localRecords, setLocalRecords] = useState<Company[]>([]);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [editingCompany, setEditingCompany] = useState<Company | null>(null);
|
const [editingCompany, setEditingCompany] = useState<Company | null>(null);
|
||||||
const [deleteId, setDeleteId] = useState<string | null>(null); // New state for delete confirmation
|
|
||||||
|
|
||||||
|
// Sync local state when API data loads
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-render
|
// eslint-disable-next-line react-hooks/set-state-in-render
|
||||||
if (apiRecords) setLocalRecords(apiRecords);
|
if (apiRecords) setLocalRecords(apiRecords);
|
||||||
@ -31,22 +30,18 @@ export default function ManageCompanies() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteClick = (id: string) => {
|
const handleDeleteClick = (id: string) => {
|
||||||
setDeleteId(id); // Open confirmation modal instead of deleting directly
|
// In a real app, you'd call an API to delete. Here we update local state.
|
||||||
};
|
setLocalRecords(prev => prev.filter(c => c.id !== id));
|
||||||
|
toast.success("Company deleted successfully.");
|
||||||
const confirmDelete = () => {
|
|
||||||
if (deleteId) {
|
|
||||||
setLocalRecords(prev => prev.filter(c => c.id !== deleteId));
|
|
||||||
toast.success("Company deleted successfully.");
|
|
||||||
setDeleteId(null);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = (name: string, status: 'Active' | 'Disabled') => {
|
const handleSave = (name: string, status: 'Active' | 'Disabled') => {
|
||||||
if (editingCompany) {
|
if (editingCompany) {
|
||||||
|
// Edit existing
|
||||||
setLocalRecords(prev => prev.map(c => c.id === editingCompany.id ? { ...c, name, status } : c));
|
setLocalRecords(prev => prev.map(c => c.id === editingCompany.id ? { ...c, name, status } : c));
|
||||||
toast.success("Company updated successfully.");
|
toast.success("Company updated successfully.");
|
||||||
} else {
|
} else {
|
||||||
|
// Add new
|
||||||
const newId = `CMP${String(localRecords.length + 1).padStart(3, '0')}`;
|
const newId = `CMP${String(localRecords.length + 1).padStart(3, '0')}`;
|
||||||
setLocalRecords(prev => [...prev, { id: newId, name, status }]);
|
setLocalRecords(prev => [...prev, { id: newId, name, status }]);
|
||||||
toast.success("Company added successfully.");
|
toast.success("Company added successfully.");
|
||||||
@ -59,6 +54,7 @@ export default function ManageCompanies() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
{/* Header & Add Button */}
|
||||||
<div className="bg-app-card p-6 rounded-lg shadow-sm flex flex-col md:flex-row md:items-center justify-between gap-4">
|
<div className="bg-app-card p-6 rounded-lg shadow-sm flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<div className="p-3 bg-primary/10 rounded-full">
|
<div className="p-3 bg-primary/10 rounded-full">
|
||||||
@ -78,8 +74,10 @@ export default function ManageCompanies() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Table */}
|
||||||
<CompanyTable records={localRecords} onEdit={handleEditClick} onDelete={handleDeleteClick} />
|
<CompanyTable records={localRecords} onEdit={handleEditClick} onDelete={handleDeleteClick} />
|
||||||
|
|
||||||
|
{/* Modal */}
|
||||||
{isModalOpen && (
|
{isModalOpen && (
|
||||||
<CompanyFormModal
|
<CompanyFormModal
|
||||||
company={editingCompany}
|
company={editingCompany}
|
||||||
@ -87,16 +85,6 @@ export default function ManageCompanies() {
|
|||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
|
||||||
{deleteId && (
|
|
||||||
<ConfirmationModal
|
|
||||||
title="Delete Company?"
|
|
||||||
message="Are you sure you want to delete this company? This action cannot be undone."
|
|
||||||
onConfirm={confirmDelete}
|
|
||||||
onClose={() => setDeleteId(null)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1,109 +0,0 @@
|
|||||||
import { useState, useMemo } from 'react';
|
|
||||||
import { Briefcase, Plus } from 'lucide-react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import Loader from '../../../components/ui/Loader';
|
|
||||||
import ErrorState from '../../../components/ui/ErrorState';
|
|
||||||
import ConfirmationModal from '../../../components/ui/ConfirmationModal'; // New Import
|
|
||||||
import DepartmentTable from '../components/department/DepartmentTable';
|
|
||||||
import DepartmentFormModal from '../components/department/DepartmentFormModal';
|
|
||||||
import { useDepartments, type Department } from '../api/useDepartmentData';
|
|
||||||
import { useCompanies } from '../api/useCompanyData';
|
|
||||||
import { useBranches } from '../api/useBranchData';
|
|
||||||
|
|
||||||
export default function ManageDepartments() {
|
|
||||||
const { data: apiRecords, isLoading: depLoading, isError: depError } = useDepartments();
|
|
||||||
const { data: companies, isLoading: compLoading, isError: compError } = useCompanies();
|
|
||||||
const { data: branches, isLoading: branchLoading, isError: branchError } = useBranches();
|
|
||||||
|
|
||||||
const [localRecords, setLocalRecords] = useState<Department[]>([]);
|
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
||||||
const [editingDepartment, setEditingDepartment] = useState<Department | null>(null);
|
|
||||||
const [deleteId, setDeleteId] = useState<string | null>(null); // New state
|
|
||||||
|
|
||||||
useMemo(() => {
|
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-render
|
|
||||||
if (apiRecords) setLocalRecords(apiRecords);
|
|
||||||
}, [apiRecords]);
|
|
||||||
|
|
||||||
const handleAddClick = () => {
|
|
||||||
setEditingDepartment(null);
|
|
||||||
setIsModalOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditClick = (department: Department) => {
|
|
||||||
setEditingDepartment(department);
|
|
||||||
setIsModalOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteClick = (id: string) => {
|
|
||||||
setDeleteId(id); // Open confirmation modal
|
|
||||||
};
|
|
||||||
|
|
||||||
const confirmDelete = () => {
|
|
||||||
if (deleteId) {
|
|
||||||
setLocalRecords(prev => prev.filter(d => d.id !== deleteId));
|
|
||||||
toast.success("Department deleted successfully.");
|
|
||||||
setDeleteId(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = (data: Omit<Department, 'id'>) => {
|
|
||||||
if (editingDepartment) {
|
|
||||||
setLocalRecords(prev => prev.map(d => d.id === editingDepartment.id ? { ...d, ...data } : d));
|
|
||||||
toast.success("Department updated successfully.");
|
|
||||||
} else {
|
|
||||||
const newId = `DEP${String(localRecords.length + 1).padStart(3, '0')}`;
|
|
||||||
setLocalRecords(prev => [...prev, { id: newId, ...data }]);
|
|
||||||
toast.success("Department added successfully.");
|
|
||||||
}
|
|
||||||
setIsModalOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (depLoading || compLoading || branchLoading) return <Loader message="Loading departments data..." />;
|
|
||||||
if (depError || compError || branchError) return <ErrorState message="Failed to load departments data." />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-6">
|
|
||||||
<div className="bg-app-card p-6 rounded-lg shadow-sm flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<div className="p-3 bg-primary/10 rounded-full">
|
|
||||||
<Briefcase className="text-primary" size={28} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2 className="text-xl font-bold text-text-primary">Manage Departments</h2>
|
|
||||||
<p className="text-sm text-text-muted">Add, edit, or disable departments.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={handleAddClick}
|
|
||||||
className="flex items-center justify-center px-4 py-2 bg-action text-white rounded-lg hover:bg-action-hover transition-colors font-medium"
|
|
||||||
>
|
|
||||||
<Plus size={18} className="mr-2" />
|
|
||||||
Add Department
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DepartmentTable records={localRecords} onEdit={handleEditClick} onDelete={handleDeleteClick} />
|
|
||||||
|
|
||||||
{isModalOpen && (
|
|
||||||
<DepartmentFormModal
|
|
||||||
department={editingDepartment}
|
|
||||||
companies={companies || []}
|
|
||||||
branches={branches || []}
|
|
||||||
onClose={() => setIsModalOpen(false)}
|
|
||||||
onSave={handleSave}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
|
||||||
{deleteId && (
|
|
||||||
<ConfirmationModal
|
|
||||||
title="Delete Department?"
|
|
||||||
message="Are you sure you want to delete this department? This action cannot be undone."
|
|
||||||
onConfirm={confirmDelete}
|
|
||||||
onClose={() => setDeleteId(null)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,8 +1,7 @@
|
|||||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||||
import MasterDataDashboard from '../pages/MasterDataDashboard';
|
import MasterDataDashboard from '../pages/MasterDataDashboard';
|
||||||
import ManageCompanies from '../pages/ManageCompanies';
|
import ManageCompanies from '../pages/ManageCompanies';
|
||||||
import ManageBranches from '../pages/ManageBranches';
|
import ManageBranches from '../pages/ManageBranches'; // New Import
|
||||||
import ManageDepartments from '../pages/ManageDepartments'; // New Import
|
|
||||||
|
|
||||||
const Placeholder = ({ title }: { title: string }) => (
|
const Placeholder = ({ title }: { title: string }) => (
|
||||||
<div className="bg-app-card p-6 rounded-lg shadow-sm">
|
<div className="bg-app-card p-6 rounded-lg shadow-sm">
|
||||||
@ -17,8 +16,8 @@ export default function MasterDataRouter() {
|
|||||||
<Route path="/" element={<Navigate to="/master-data/dashboard" replace />} />
|
<Route path="/" element={<Navigate to="/master-data/dashboard" replace />} />
|
||||||
<Route path="/dashboard" element={<MasterDataDashboard />} />
|
<Route path="/dashboard" element={<MasterDataDashboard />} />
|
||||||
<Route path="/company" element={<ManageCompanies />} />
|
<Route path="/company" element={<ManageCompanies />} />
|
||||||
<Route path="/branches" element={<ManageBranches />} />
|
<Route path="/branches" element={<ManageBranches />} /> {/* Updated Route */}
|
||||||
<Route path="/departments" element={<ManageDepartments />} /> {/* Updated Route */}
|
<Route path="/departments" element={<Placeholder title="Manage Departments" />} />
|
||||||
<Route path="/designations" element={<Placeholder title="Manage Designations" />} />
|
<Route path="/designations" element={<Placeholder title="Manage Designations" />} />
|
||||||
<Route path="/employees" element={<Placeholder title="Manage Employees" />} />
|
<Route path="/employees" element={<Placeholder title="Manage Employees" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import Loader from '../../../../components/ui/Loader';
|
import Loader from '../../../../components/ui/Loader';
|
||||||
import ErrorState from '../../../../components/ui/ErrorState';
|
import ErrorState from '../../../../components/ui/ErrorState';
|
||||||
import LeaveSummaryTable from '../../components/leave/LeaveSummaryTable';
|
import LeaveSummaryTable from '../../components/Leave/LeaveSummaryTable';
|
||||||
import ApplyLeaveForm from '../../components/leave/ApplyLeaveForm';
|
import ApplyLeaveForm from '../../components/Leave/ApplyLeaveForm';
|
||||||
import LeaveHistoryTable from '../../components/leave/LeaveHistoryTable';
|
import LeaveHistoryTable from '../../components/Leave/LeaveHistoryTable';
|
||||||
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
||||||
|
|
||||||
export default function AdminLeave() {
|
export default function AdminLeave() {
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import Loader from '../../../../components/ui/Loader';
|
import Loader from '../../../../components/ui/Loader';
|
||||||
import ErrorState from '../../../../components/ui/ErrorState';
|
import ErrorState from '../../../../components/ui/ErrorState';
|
||||||
import LeaveSummaryTable from '../../components/leave/LeaveSummaryTable';
|
import LeaveSummaryTable from '../../components/Leave/LeaveSummaryTable';
|
||||||
import ApplyLeaveForm from '../../components/leave/ApplyLeaveForm';
|
import ApplyLeaveForm from '../../components/Leave/ApplyLeaveForm';
|
||||||
import LeaveHistoryTable from '../../components/leave/LeaveHistoryTable';
|
import LeaveHistoryTable from '../../components/Leave/LeaveHistoryTable';
|
||||||
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
||||||
|
|
||||||
export default function EmployeeLeave() {
|
export default function EmployeeLeave() {
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import Loader from '../../../../components/ui/Loader';
|
import Loader from '../../../../components/ui/Loader';
|
||||||
import ErrorState from '../../../../components/ui/ErrorState';
|
import ErrorState from '../../../../components/ui/ErrorState';
|
||||||
import LeaveSummaryTable from '../../components/leave/LeaveSummaryTable';
|
import LeaveSummaryTable from '../../components/Leave/LeaveSummaryTable';
|
||||||
import ApplyLeaveForm from '../../components/leave/ApplyLeaveForm';
|
import ApplyLeaveForm from '../../components/Leave/ApplyLeaveForm';
|
||||||
import LeaveHistoryTable from '../../components/leave/LeaveHistoryTable';
|
import LeaveHistoryTable from '../../components/Leave/LeaveHistoryTable';
|
||||||
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
||||||
|
|
||||||
export default function ManagerLeave() {
|
export default function ManagerLeave() {
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import Loader from '../../../../components/ui/Loader';
|
import Loader from '../../../../components/ui/Loader';
|
||||||
import ErrorState from '../../../../components/ui/ErrorState';
|
import ErrorState from '../../../../components/ui/ErrorState';
|
||||||
import LeaveSummaryTable from '../../components/leave/LeaveSummaryTable';
|
import LeaveSummaryTable from '../../components/Leave/LeaveSummaryTable';
|
||||||
import ApplyLeaveForm from '../../components/leave/ApplyLeaveForm';
|
import ApplyLeaveForm from '../../components/Leave/ApplyLeaveForm';
|
||||||
import LeaveHistoryTable from '../../components/leave/LeaveHistoryTable';
|
import LeaveHistoryTable from '../../components/Leave/LeaveHistoryTable';
|
||||||
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
import { useLeaveSummary, useLeaveHistory } from '../../api/useLeaveData';
|
||||||
|
|
||||||
export default function SuperAdminLeaveLeave() {
|
export default function SuperAdminLeaveLeave() {
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import type { RootState } from '../../../store/store';
|
import type { RootState } from '../../../store/store';
|
||||||
import EmployeeLeave from '../pages/leave/EmployeeLeave';
|
import EmployeeLeave from '../pages/Leave/EmployeeLeave';
|
||||||
import ManagerLeave from '../pages/leave/ManagerLeave';
|
import ManagerLeave from '../pages/Leave/ManagerLeave';
|
||||||
import AdminLeave from '../pages/leave/AdminLeave';
|
import AdminLeave from '../pages/Leave/AdminLeave';
|
||||||
import SuperAdminLeaveLeave from '../pages/leave/SuperAdminLeave';
|
import SuperAdminLeaveLeave from '../pages/Leave/SuperAdminLeave';
|
||||||
|
|
||||||
export default function LeaveRouter() {
|
export default function LeaveRouter() {
|
||||||
const role = useSelector((state: RootState) => state.role.currentRole);
|
const role = useSelector((state: RootState) => state.role.currentRole);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user