Skip to main content

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​

Workflow Components​

Specialized Status Components​


StatusFormatter​

The main status badge component with enhanced styling, dot indicators, and tooltip support.

Component Location​

import StatusFormatter from 'components/Status/StatusFormatter';

Props​

PropTypeRequiredDefaultDescription
statusstring✓-Status value to display
showTooltipboolean-trueWhether to show tooltip
tooltipstring--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 text
  • approved - Green background, white text
  • completed - Green background, white text
  • successful - Green background, white text
  • paid - Green background, white text

Pending/Processing States​

  • pending - Chrome background, dark text
  • processing - Chrome background, dark text
  • awaiting_approval - Chrome background, dark text
  • sent - Chrome background, dark text

Negative/Error States​

  • failed - Red background, white text
  • denied - Red background, white text
  • cancelled - Red background, white text
  • rejected - Red background, white text
  • disapproved - Red background, white text

Neutral/Inactive States​

  • inactive - Gray background, dark text
  • draft - Purple background, white text
  • on_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​

PropTypeRequiredDefaultDescription
statusstring✓-Status value to display
colorCodestring--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​

PropTypeRequiredDefaultDescription
statusstring✓-Status value
statusMapRecord<string, object>--Custom status mapping
titlestring--Custom title override
hasDotboolean-trueShow status dot indicator
leftIconobject--Custom left icon with tooltip
rightIconobject--Custom right icon with tooltip
customColorsobject--Color overrides
sizestring-'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&lt;StatusEntry&gt;;
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​

PropTypeRequiredDefaultDescription
statusTextstring✓-Status text display
tooltipstring--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​

PropTypeRequiredDefaultDescription
originalobject✓-Data object with approval information
modulestring✓-Module name (e.g., 'Leaves', 'Expenses')
isNewDesignboolean-falseUse 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​

PropTypeRequiredDefaultDescription
stagesarray✓-Array of approval stages
modulestring✓-Module name
isNewDesignboolean-falseUse 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) && (
&lt;Menu&gt;
<MenuButton as={Button} variant='ghost' size='sm'>
Actions
</MenuButton>
&lt;MenuList&gt;
{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​

  1. Use Appropriate Components

    • StatusFormatter for modern, enhanced status display
    • WPStatusFormatter for legacy compatibility
    • WpBaseStatusFormatter for custom status mappings
    • PolicyViolationBadge for policy violations
  2. Consistent Status Values

    • Use standardized status values across modules
    • Maintain consistent color coding
    • Provide meaningful tooltips
  3. Module-Specific Formatters

    • Use specialized formatters for complex workflows
    • Maintain consistency within modules
    • Document custom status mappings

Accessibility​

  1. Color Accessibility

    • Don't rely solely on color for status information
    • Provide sufficient contrast ratios
    • Include text labels for all status states
  2. Screen Reader Support

    • Provide meaningful aria-labels
    • Include status descriptions in tooltips
    • Use semantic HTML structure
  3. Keyboard Navigation

    • Ensure tooltips are accessible via keyboard
    • Provide keyboard shortcuts for status actions
    • Handle focus management properly

Performance​

  1. Component Optimization

    • Memoize status components with stable props
    • Avoid unnecessary re-renders
    • Use efficient status lookups
  2. 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​

  1. Update Import Paths

    // Old
    import StatusBadge from 'components/OldStatusBadge';

    // New
    import StatusFormatter from 'components/Status/StatusFormatter';
  2. Update Props Structure

    // Old
    <StatusBadge status="approved" color="green" />

    // New
    <StatusFormatter
    status="approved"
    showTooltip
    tooltip="Status information"
    />
  3. 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'>
&lt;Text&gt;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>
);
}