Status Components
The Status Components provide status badges, workflow indicators, and approval tracking functionality for the WorkPayCore Frontend application. These components handle various status states with consistent styling, colors, and behavioral patterns across different modules.
Overview
This document covers status-related components that display approval workflows, process states, and status indicators throughout the application with WorkPay's branded styling and interaction patterns.
Components Overview
Core Status Components
- StatusFormatter - Main status badge component with enhanced styling
- WPStatusFormatter - Legacy status formatter with basic styling
- WpBaseStatusFormatter - Base status component with customizable styling
- PolicyViolationBadge - Specialized badge for policy violations
Workflow Components
- ApprovalWorkflowStatus - Complex approval workflow indicator
- ApprovalActionStageHistory - Approval stages timeline
Specialized Status Components
- ExpenseStatusFormatter - Expense-specific status formatting
- LoansStatusFormatter - Loan-specific status formatting
- DisciplinaryStatusBadge - Disciplinary tracking status
- BatchStatusBadge - Payment batch status indicator
StatusFormatter
The main status badge component with enhanced styling, dot indicators, and tooltip support.
Component Location
import StatusFormatter from 'components/Status/StatusFormatter';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| status | string | ✓ | - | Status value to display |
| showTooltip | boolean | - | true | Whether to show tooltip |
| tooltip | string | - | - | Custom tooltip text |
TypeScript Interface
interface StatusProps {
status: string;
showTooltip?: boolean;
tooltip?: string;
}
Supported Status Values
The component supports a wide range of status values with predefined colors:
Positive/Success States
active- Green background, white textapproved- Green background, white textcompleted- Green background, white textsuccessful- Green background, white textpaid- Green background, white text
Pending/Processing States
pending- Chrome background, dark textprocessing- Chrome background, dark textawaiting_approval- Chrome background, dark textsent- Chrome background, dark text
Negative/Error States
failed- Red background, white textdenied- Red background, white textcancelled- Red background, white textrejected- Red background, white textdisapproved- Red background, white text
Neutral/Inactive States
inactive- Gray background, dark textdraft- Purple background, white texton_hold- Sky background, white text
Usage Examples
Basic Status Display
import StatusFormatter from 'components/Status/StatusFormatter';
function EmployeeStatus({ employee }) {
return (
<StatusFormatter
status={employee.status}
showTooltip
tooltip='Employee current status'
/>
);
}
Leave Request Status
import StatusFormatter from 'components/Status/StatusFormatter';
function LeaveRequestStatus({ request }) {
return (
<StatusFormatter
status={request.status}
showTooltip
tooltip={`Leave request ${request.status} on ${request.updatedAt}`}
/>
);
}
Payment Status with Dot Indicator
import StatusFormatter from 'components/Status/StatusFormatter';
function PaymentStatus({ payment }) {
return (
<StatusFormatter
status={payment.status}
showTooltip
tooltip={`Payment ${payment.status} - ${payment.amount}`}
/>
);
}
Multiple Status Display
import StatusFormatter from 'components/Status/StatusFormatter';
import { HStack } from '@chakra-ui/react';
function MultipleStatusDisplay({ items }) {
return (
<HStack spacing={2}>
{items.map(item => (
<StatusFormatter
key={item.id}
status={item.status}
showTooltip
tooltip={`${item.type}: ${item.status}`}
/>
))}
</HStack>
);
}
WPStatusFormatter
Legacy status formatter component with basic styling and color mapping.
Component Location
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| status | string | ✓ | - | Status value to display |
| colorCode | string | - | - | Custom color override |
Usage Examples
Basic Legacy Status
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function LegacyStatusDisplay({ status }) {
return <WPStatusFormatter status={status} />;
}
Custom Color Status
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function CustomColorStatus({ status }) {
return <WPStatusFormatter status={status} colorCode='#FF6B6B' />;
}
WpBaseStatusFormatter
Base reusable status component with full customization support.
Component Location
import WpBaseStatusFormatter from 'components/Status/WpBaseStatusFormatter';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| status | string | ✓ | - | Status value |
| statusMap | Record<string, object> | - | - | Custom status mapping |
| title | string | - | - | Custom title override |
| hasDot | boolean | - | true | Show status dot indicator |
| leftIcon | object | - | - | Custom left icon with tooltip |
| rightIcon | object | - | - | Custom right icon with tooltip |
| customColors | object | - | - | Color overrides |
| size | string | - | 'md' | Badge size |
TypeScript Interface
interface StatusEntry {
bgColor: string;
color: string;
dotColor: string;
defaultTitle: string;
}
interface WpBaseStatusBadgeProps<T extends string> {
status: T;
statusMap?: Record<T, StatusEntry>;
title?: string;
hasDot?: boolean;
leftIcon?: {
icon: ReactNode;
tooltip?: string;
};
rightIcon?: {
icon?: ReactNode;
tooltip?: string;
};
customColors?: Partial<StatusEntry>;
size?: 'sm' | 'md' | 'lg';
}
Usage Examples
Custom Status Mapping
import WpBaseStatusFormatter from 'components/Status/WpBaseStatusFormatter';
function CustomStatusBadge({ status }) {
const customStatusMap = {
'in-progress': {
bgColor: 'blue.100',
color: 'blue.800',
dotColor: 'blue.500',
defaultTitle: 'In Progress',
},
'under-review': {
bgColor: 'orange.100',
color: 'orange.800',
dotColor: 'orange.500',
defaultTitle: 'Under Review',
},
};
return (
<WpBaseStatusFormatter
status={status}
statusMap={customStatusMap}
hasDot
size='md'
/>
);
}
Status with Custom Icons
import WpBaseStatusFormatter from 'components/Status/WpBaseStatusFormatter';
import { CheckIcon, WarningIcon } from '@chakra-ui/icons';
function IconStatusBadge({ status }) {
const leftIcon =
status === 'completed'
? {
icon: <CheckIcon />,
tooltip: 'Task completed successfully',
}
: undefined;
const rightIcon =
status === 'warning'
? {
icon: <WarningIcon />,
tooltip: 'Attention required',
}
: undefined;
return (
<WpBaseStatusFormatter
status={status}
leftIcon={leftIcon}
rightIcon={rightIcon}
size='lg'
/>
);
}
Payment Status Example
function PaymentStatusBadge({ status }) {
const paymentStatusMap = {
pending: {
bgColor: 'yellow.100',
color: 'yellow.800',
dotColor: 'yellow.500',
defaultTitle: 'Payment Pending',
},
completed: {
bgColor: 'green.100',
color: 'green.800',
dotColor: 'green.500',
defaultTitle: 'Payment Completed',
},
failed: {
bgColor: 'red.100',
color: 'red.800',
dotColor: 'red.500',
defaultTitle: 'Payment Failed',
},
};
return (
<WpBaseStatusFormatter
status={status}
statusMap={paymentStatusMap}
hasDot
/>
);
}
PolicyViolationBadge
Specialized badge for displaying policy violations with tooltip information.
Component Location
import PolicyViolationBadge from 'components/Status/PolicyViolationBadge';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| statusText | string | ✓ | - | Status text display |
| tooltip | string | - | - | Tooltip information |
Usage Examples
Basic Policy Violation
import PolicyViolationBadge from 'components/Status/PolicyViolationBadge';
function AttendanceViolation({ violation }) {
return (
<PolicyViolationBadge
statusText='Policy Violation'
tooltip={violation.description}
/>
);
}
Leave Policy Violation
import PolicyViolationBadge from 'components/Status/PolicyViolationBadge';
function LeaveViolationBadge({ violation }) {
return (
<PolicyViolationBadge
statusText='Leave Policy Violation'
tooltip={`Exceeded ${violation.type} limit by ${violation.days} days`}
/>
);
}
ApprovalWorkflowStatus
Complex component for displaying approval workflow stages and progress.
Component Location
import { ApprovalWorkflowStatus } from 'components/Status';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| original | object | ✓ | - | Data object with approval information |
| module | string | ✓ | - | Module name (e.g., 'Leaves', 'Expenses') |
| isNewDesign | boolean | - | false | Use new design layout |
TypeScript Interface
interface ApprovalWorkflowStatusProps {
original: Record<string, any>;
module: string;
isNewDesign?: boolean;
}
Supported Modules
- Leaves - Leave request approvals
- Expenses - Expense claim approvals
- Loans - Loan application approvals
- Salary Advance - Salary advance approvals
- Overtime - Overtime request approvals
- Payroll - Payroll approvals
- Global Payroll - Global payroll approvals
Usage Examples
Leave Approval Workflow
import { ApprovalWorkflowStatus } from 'components/Status';
function LeaveApprovalDisplay({ leaveRequest }) {
return (
<ApprovalWorkflowStatus
original={leaveRequest}
module='Leaves'
isNewDesign
/>
);
}
Expense Approval Workflow
import { ApprovalWorkflowStatus } from 'components/Status';
function ExpenseApprovalDisplay({ expense }) {
return <ApprovalWorkflowStatus original={expense} module='Expenses' />;
}
Loan Approval Workflow
import { ApprovalWorkflowStatus } from 'components/Status';
function LoanApprovalDisplay({ loan }) {
return <ApprovalWorkflowStatus original={loan} module='Loans' isNewDesign />;
}
ApprovalActionStageHistory
Component for displaying approval stages timeline with detailed history.
Component Location
import { ApprovalActionStageHistory } from 'components/Status';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| stages | array | ✓ | - | Array of approval stages |
| module | string | ✓ | - | Module name |
| isNewDesign | boolean | - | false | Use new design layout |
Usage Examples
Approval History Tooltip
import { ApprovalActionStageHistory } from 'components/Status';
function ApprovalHistoryTooltip({ stages, module }) {
return (
<ApprovalActionStageHistory stages={stages} module={module} isNewDesign />
);
}
Specialized Status Components
ExpenseStatusFormatter
Expense-specific status formatter with expense workflow states.
import ExpenseStatusFormatter from 'containers/ExpensesRedesign/Tables/ExpensesStatusFormatter';
function ExpenseRow({ expense }) {
return <ExpenseStatusFormatter row={expense} />;
}
LoansStatusFormatter
Loan-specific status formatter with loan lifecycle states.
import LoansStatusFormatter from 'containers/Loans/statusFormatter';
function LoanRow({ loan }) {
return <LoansStatusFormatter row={loan} />;
}
DisciplinaryStatusBadge
Disciplinary tracking status with specialized workflow states.
import DisciplinaryStatusBadge from 'containers/DisciplinaryTracking/Page/table/columns/DisciplinaryStatusBadge';
function DisciplinaryRow({ disciplinary }) {
return (
<DisciplinaryStatusBadge
status={disciplinary.status}
statusText={disciplinary.statusText}
/>
);
}
BatchStatusBadge
Payment batch status indicator with success/failure counts.
import BatchStatusBadge from 'containers/PaymentsRedesign/Components/BatchStatusBadge';
function PaymentBatchRow({ batch, activeTab }) {
return <BatchStatusBadge row={{ original: batch }} activeTab={activeTab} />;
}
Status Patterns
Basic Status Display Pattern
import StatusFormatter from 'components/Status/StatusFormatter';
import { HStack, VStack, Text } from '@chakra-ui/react';
function StatusDisplayPattern({ item }) {
return (
<HStack spacing={4} align='center'>
<VStack align='start' spacing={0}>
<Text fontWeight='medium'>{item.name}</Text>
<Text fontSize='sm' color='gray.600'>
{item.description}
</Text>
</VStack>
<StatusFormatter
status={item.status}
showTooltip
tooltip={`${item.type} status: ${item.status}`}
/>
</HStack>
);
}
Multi-Stage Approval Pattern
import { ApprovalWorkflowStatus } from 'components/Status';
import StatusFormatter from 'components/Status/StatusFormatter';
import { VStack, HStack, Text, Progress } from '@chakra-ui/react';
function MultiStageApprovalPattern({ request }) {
const approvalProgress =
(request.approved_attempts_count / request.approval_stages.length) * 100;
return (
<VStack spacing={4} align='stretch'>
{/* Current Status */}
<HStack justify='space-between' align='center'>
<Text fontWeight='medium'>Current Status</Text>
<StatusFormatter
status={request.status}
showTooltip
tooltip='Current approval status'
/>
</HStack>
{/* Progress Bar */}
<VStack align='stretch' spacing={2}>
<HStack justify='space-between'>
<Text fontSize='sm'>Approval Progress</Text>
<Text fontSize='sm' color='gray.600'>
{request.approved_attempts_count} of{' '}
{request.approval_stages.length} stages
</Text>
</HStack>
<Progress value={approvalProgress} colorScheme='green' />
</VStack>
{/* Workflow Status */}
<ApprovalWorkflowStatus original={request} module='Leaves' isNewDesign />
</VStack>
);
}
Status with Actions Pattern
import StatusFormatter from 'components/Status/StatusFormatter';
import {
HStack,
Button,
Menu,
MenuButton,
MenuList,
MenuItem,
} from '@chakra-ui/react';
function StatusWithActionsPattern({ item, onStatusChange }) {
const canApprove = item.status === 'pending' && item.canApprove;
const canReject = item.status === 'pending' && item.canReject;
return (
<HStack spacing={4} align='center'>
<StatusFormatter
status={item.status}
showTooltip
tooltip={`Request ${item.status} on ${item.updatedAt}`}
/>
{(canApprove || canReject) && (
<Menu>
<MenuButton as={Button} variant='ghost' size='sm'>
Actions
</MenuButton>
<MenuList>
{canApprove && (
<MenuItem onClick={() => onStatusChange('approved')}>
Approve
</MenuItem>
)}
{canReject && (
<MenuItem onClick={() => onStatusChange('rejected')}>
Reject
</MenuItem>
)}
</MenuList>
</Menu>
)}
</HStack>
);
}
Conditional Status Display Pattern
import StatusFormatter from 'components/Status/StatusFormatter';
import PolicyViolationBadge from 'components/Status/PolicyViolationBadge';
import { HStack } from '@chakra-ui/react';
function ConditionalStatusPattern({ item }) {
const hasPolicyViolation = item.policyViolations?.length > 0;
return (
<HStack spacing={2}>
<StatusFormatter
status={item.status}
showTooltip
tooltip={`${item.type} status`}
/>
{hasPolicyViolation && (
<PolicyViolationBadge
statusText='Policy Violation'
tooltip={item.policyViolations.map(v => v.description).join(', ')}
/>
)}
</HStack>
);
}
Best Practices
Status Selection
-
Use Appropriate Components
StatusFormatterfor modern, enhanced status displayWPStatusFormatterfor legacy compatibilityWpBaseStatusFormatterfor custom status mappingsPolicyViolationBadgefor policy violations
-
Consistent Status Values
- Use standardized status values across modules
- Maintain consistent color coding
- Provide meaningful tooltips
-
Module-Specific Formatters
- Use specialized formatters for complex workflows
- Maintain consistency within modules
- Document custom status mappings
Accessibility
-
Color Accessibility
- Don't rely solely on color for status information
- Provide sufficient contrast ratios
- Include text labels for all status states
-
Screen Reader Support
- Provide meaningful aria-labels
- Include status descriptions in tooltips
- Use semantic HTML structure
-
Keyboard Navigation
- Ensure tooltips are accessible via keyboard
- Provide keyboard shortcuts for status actions
- Handle focus management properly
Performance
-
Component Optimization
- Memoize status components with stable props
- Avoid unnecessary re-renders
- Use efficient status lookups
-
Status Mapping
- Cache status mappings for repeated use
- Use efficient data structures
- Minimize prop drilling
Testing
Unit Tests
import { render, screen } from '@testing-library/react';
import StatusFormatter from 'components/Status/StatusFormatter';
describe('StatusFormatter', () => {
it('renders status correctly', () => {
render(<StatusFormatter status='approved' />);
expect(screen.getByText('approved')).toBeInTheDocument();
});
it('shows tooltip when provided', async () => {
const { user } = render(
<StatusFormatter
status='pending'
tooltip='Request is pending approval'
/>,
);
await user.hover(screen.getByText('pending'));
expect(screen.getByText('Request is pending approval')).toBeInTheDocument();
});
it('applies correct styling for different statuses', () => {
const { rerender } = render(<StatusFormatter status='approved' />);
expect(screen.getByText('approved')).toHaveClass('chakra-badge');
rerender(<StatusFormatter status='rejected' />);
expect(screen.getByText('rejected')).toHaveClass('chakra-badge');
});
});
Integration Tests
describe('ApprovalWorkflowStatus', () => {
it('displays correct approval stage', () => {
const mockRequest = {
approval_stages: [{ id: 1 }, { id: 2 }],
approved_attempts: [{ id: 1 }],
approved_attempts_count: 1,
status: 'NOT_APPROVED',
};
render(<ApprovalWorkflowStatus original={mockRequest} module='Leaves' />);
expect(screen.getByText('2nd approval stage')).toBeInTheDocument();
});
it('handles completed approval workflow', () => {
const mockRequest = {
approval_stages: [{ id: 1 }, { id: 2 }],
approved_attempts: [{ id: 1 }, { id: 2 }],
approved_attempts_count: 2,
status: 'APPROVED',
};
render(<ApprovalWorkflowStatus original={mockRequest} module='Leaves' />);
expect(screen.getByText('approved')).toBeInTheDocument();
});
});
Migration Guide
From Legacy Status Components
-
Update Import Paths
// Old
import StatusBadge from 'components/OldStatusBadge';
// New
import StatusFormatter from 'components/Status/StatusFormatter'; -
Update Props Structure
// Old
<StatusBadge status="approved" color="green" />
// New
<StatusFormatter
status="approved"
showTooltip
tooltip="Status information"
/> -
Update Status Values
// Old inconsistent values
status: 'APPROVED' | 'REJECTED' | 'PENDING';
// New consistent values
status: 'approved' | 'rejected' | 'pending';
Custom Status Mappings
// Old manual color mapping
const getStatusColor = status => {
switch (status) {
case 'approved':
return 'green';
case 'rejected':
return 'red';
default:
return 'gray';
}
};
// New status mapping
const customStatusMap = {
approved: {
bgColor: 'green.100',
color: 'green.800',
dotColor: 'green.500',
defaultTitle: 'Approved',
},
rejected: {
bgColor: 'red.100',
color: 'red.800',
dotColor: 'red.500',
defaultTitle: 'Rejected',
},
};
Advanced Usage
Dynamic Status Updates
import { useState, useEffect } from 'react';
import StatusFormatter from 'components/Status/StatusFormatter';
function DynamicStatusDisplay({ itemId }) {
const [status, setStatus] = useState('pending');
const [statusHistory, setStatusHistory] = useState([]);
useEffect(() => {
// Subscribe to status updates
const subscription = subscribeToStatusUpdates(itemId, newStatus => {
setStatusHistory(prev => [...prev, { status, timestamp: Date.now() }]);
setStatus(newStatus);
});
return () => subscription.unsubscribe();
}, [itemId]);
return (
<VStack spacing={2} align='stretch'>
<HStack justify='space-between'>
<Text>Current Status</Text>
<StatusFormatter
status={status}
showTooltip
tooltip={`Status updated ${new Date().toLocaleString()}`}
/>
</HStack>
{statusHistory.length > 0 && (
<VStack align='stretch' spacing={1}>
<Text fontSize='sm' fontWeight='medium'>
Status History
</Text>
{statusHistory.slice(-3).map((item, index) => (
<HStack key={index} justify='space-between' fontSize='xs'>
<StatusFormatter status={item.status} />
<Text color='gray.600'>
{new Date(item.timestamp).toLocaleString()}
</Text>
</HStack>
))}
</VStack>
)}
</VStack>
);
}
Bulk Status Operations
import StatusFormatter from 'components/Status/StatusFormatter';
import { useState } from 'react';
function BulkStatusOperations({ items, onBulkStatusChange }) {
const [selectedItems, setSelectedItems] = useState([]);
const [bulkStatus, setBulkStatus] = useState('');
const statusCounts = items.reduce((acc, item) => {
acc[item.status] = (acc[item.status] || 0) + 1;
return acc;
}, {});
const handleBulkApproval = () => {
onBulkStatusChange(selectedItems, 'approved');
setSelectedItems([]);
};
return (
<VStack spacing={4} align='stretch'>
{/* Status Summary */}
<HStack spacing={4}>
{Object.entries(statusCounts).map(([status, count]) => (
<VStack key={status} spacing={1}>
<StatusFormatter status={status} />
<Text fontSize='sm'>{count} items</Text>
</VStack>
))}
</HStack>
{/* Bulk Actions */}
{selectedItems.length > 0 && (
<HStack spacing={2}>
<Button size='sm' colorScheme='green' onClick={handleBulkApproval}>
Approve Selected ({selectedItems.length})
</Button>
<Button
size='sm'
variant='outline'
onClick={() => setSelectedItems([])}
>
Clear Selection
</Button>
</HStack>
)}
</VStack>
);
}
Status Workflow Visualization
import StatusFormatter from 'components/Status/StatusFormatter';
import { HStack, VStack, Box, Text } from '@chakra-ui/react';
function StatusWorkflowVisualization({ workflow, currentStatus }) {
const currentIndex = workflow.findIndex(
step => step.status === currentStatus,
);
return (
<VStack spacing={4} align='stretch'>
<Text fontWeight='bold'>Workflow Progress</Text>
<HStack spacing={4} align='center'>
{workflow.map((step, index) => (
<VStack key={step.status} spacing={2} align='center'>
<StatusFormatter
status={step.status}
showTooltip
tooltip={step.description}
/>
<Text fontSize='xs' textAlign='center'>
{step.label}
</Text>
{index < workflow.length - 1 && (
<Box
w='20px'
h='2px'
bg={index < currentIndex ? 'green.400' : 'gray.300'}
ml={4}
/>
)}
</VStack>
))}
</HStack>
<Text fontSize='sm' color='gray.600'>
Step {currentIndex + 1} of {workflow.length}
</Text>
</VStack>
);
}