diff --git a/frontend/src/components/EmployeeList.tsx b/frontend/src/components/EmployeeList.tsx
index 9167749..2b92767 100644
--- a/frontend/src/components/EmployeeList.tsx
+++ b/frontend/src/components/EmployeeList.tsx
@@ -20,6 +20,7 @@ interface Employee {
interface EmployeeListProps {
employees: Employee[];
+ isLoading?: boolean;
onEmployeeClick?: (employee: Employee) => void;
onAddEmployee: (employee: Employee) => void;
onEditEmployee?: (employee: Employee) => void;
@@ -27,8 +28,49 @@ interface EmployeeListProps {
onUpdateEmployeeImage?: (id: string, imageUrl: string) => void;
}
+const SKELETON_ROW_COUNT = 5;
+
+const EmployeeSkeletonRow: React.FC = () => (
+
+ {/* Name column */}
+ |
+
+ |
+ {/* Role */}
+
+
+ |
+ {/* Wallet */}
+
+
+ |
+ {/* Salary */}
+
+
+ |
+ {/* Status */}
+
+
+ |
+ {/* Actions */}
+
+
+ |
+
+);
+
export const EmployeeList: React.FC = ({
employees,
+ isLoading = false,
onAddEmployee,
onEditEmployee,
onRemoveEmployee,
@@ -212,7 +254,11 @@ export const EmployeeList: React.FC = ({
- {sortedEmployees.length === 0 ? (
+ {isLoading ? (
+ Array.from({ length: SKELETON_ROW_COUNT }, (_, i) => (
+
+ ))
+ ) : sortedEmployees.length === 0 ? (
|
{debouncedSearch ? `No employees match "${debouncedSearch}"` : 'No employees found'}
diff --git a/frontend/src/components/__tests__/EmployeeList.test.tsx b/frontend/src/components/__tests__/EmployeeList.test.tsx
index 022464a..ad7a294 100644
--- a/frontend/src/components/__tests__/EmployeeList.test.tsx
+++ b/frontend/src/components/__tests__/EmployeeList.test.tsx
@@ -40,4 +40,24 @@ describe('EmployeeList', () => {
expect(email).toHaveAttribute('title', employee.email);
expect(email.className).toContain('truncate');
});
+
+ test('renders skeleton rows and hides employee data while loading', () => {
+ render();
+
+ // Employee data must not be visible during loading
+ expect(screen.queryByLabelText(`Employee name: ${employee.name}`)).toBeNull();
+ expect(screen.queryByLabelText(`Employee email: ${employee.email}`)).toBeNull();
+
+ // Skeleton rows are rendered with pulse animation
+ const rows = document.querySelectorAll('tbody tr');
+ expect(rows.length).toBe(5);
+ rows.forEach((row) => {
+ expect(row.className).toContain('animate-pulse');
+ });
+ });
+
+ test('renders empty state message when not loading and no employees exist', () => {
+ render();
+ expect(screen.getByText('No employees found')).toBeTruthy();
+ });
});
|