Notification Components
The Notification Components provide user feedback mechanisms including status displays and confirmation dialogs for the WorkPayCore Frontend application. These components handle status visualization and user confirmation workflows.
Overview
This document covers notification-related components that provide visual feedback for status changes and user confirmation workflows throughout the application.
Components Overview
Status Components
- WPStatusFormatter - Status badge formatter with predefined color schemes
- ConfirmationPopover - Modal-based confirmation dialog
Utility Components
- ConfirmationFooter - Reusable footer for confirmation dialogs
WPStatusFormatter
A flexible status badge component that formats status strings with predefined colors and labels according to WorkPay's design system.
Component Location
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| status | string | ✓ | - | The status string to format |
| colorCode | string | - | - | Custom color override |
| ...rest | object | - | - | Additional Badge props from Chakra UI |
TypeScript Interface
interface WPStatusFormatterProps {
status: string;
colorCode?: string;
[key: string]: any; // Additional Badge props
}
Features
Status Normalization
- Converts status strings to lowercase
- Handles underscore and space variations
- Consistent formatting across different input formats
- Automatic text capitalization
Predefined Status Mapping
Comprehensive status mapping with consistent color schemes:
- Success States:
active,approved,successful,completed,paid,marked_as_paid,released - Pending States:
processing,pending,ongoing,awaiting_approval,sent,unreleased - Error States:
failed,denied,cancelled,rejected,not_paid,purged - Inactive States:
in_active,inactive,on_leave,deleted,existed - Special States:
on_hold,refunded,draft,exempted,reactivated
Print Optimization
- Print-specific styling with
@media print - Color preservation with
-webkit-print-color-adjust: exact - Consistent appearance across digital and print media
Usage Examples
Basic Status Display
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function EmployeeStatus({ employee }) {
return <WPStatusFormatter status={employee.status} />;
}
// Renders: <Badge colorScheme="green">Active</Badge>
Custom Color Override
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function CustomStatusBadge() {
return <WPStatusFormatter status='processing' colorCode='#FF6B35' />;
}
Table Status Column
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function EmployeeTable({ employees }) {
return (
<Table>
<Thead>
<Tr>
<Th>Name</Th>
<Th>Status</Th>
<Th>Department</Th>
</Tr>
</Thead>
<Tbody>
{employees.map(employee => (
<Tr key={employee.id}>
<Td>{employee.name}</Td>
<Td>
<WPStatusFormatter status={employee.status} fontSize='xs' />
</Td>
<Td>{employee.department}</Td>
</Tr>
))}
</Tbody>
</Table>
);
}
Payment Status Display
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function PaymentCard({ payment }) {
return (
<Card>
<CardHeader>
<Heading size='md'>Payment #{payment.id}</Heading>
<WPStatusFormatter status={payment.status} size='sm' />
</CardHeader>
<CardBody>
<Text>Amount: ${payment.amount}</Text>
<Text>Date: {payment.date}</Text>
</CardBody>
</Card>
);
}
Conditional Status Rendering
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
function ConditionalStatus({ item }) {
const getStatusColor = status => {
if (status === 'urgent') return '#FF4444';
if (status === 'high_priority') return '#FF8800';
return undefined; // Use default mapping
};
return (
<HStack>
<Text>{item.name}</Text>
<WPStatusFormatter
status={item.status}
colorCode={getStatusColor(item.status)}
/>
</HStack>
);
}
Status Configuration
Success States (Green)
const successStates = {
active: { label: 'Active', colorCode: 'green' },
approved: { label: 'Approved', colorCode: 'green' },
successful: { label: 'Successful', colorCode: 'green' },
completed: { label: 'Successful', colorCode: 'green' },
paid: { label: 'Paid', colorCode: 'green' },
marked_as_paid: { label: 'Marked as Paid', colorCode: 'green' },
released: { label: 'Released', colorCode: 'green' },
};
Pending States (Yellow/Orange)
const pendingStates = {
processing: { label: 'Processing', colorCode: 'chrome-dark' },
pending: { label: 'Pending', colorCode: 'chrome' },
ongoing: { label: 'Pending', colorCode: 'atlantic' },
awaiting_approval: { label: 'Pending', colorCode: 'chrome' },
sent: { label: 'Sent', colorCode: 'chrome' },
unreleased: { label: 'Unreleased', colorCode: 'chrome' },
};
Error States (Red)
const errorStates = {
failed: { label: 'Failed', colorCode: 'wp-red' },
denied: { label: 'Denied', colorCode: 'wp-red' },
cancelled: { label: 'Failed', colorCode: '#DE350B' },
rejected: { label: 'Rejected', colorCode: '#FF0000' },
not_paid: { label: 'Not Paid', colorCode: 'wp-red' },
purged: { label: 'Purged', colorCode: 'wp-red' },
};
Inactive States (Gray)
const inactiveStates = {
in_active: { label: 'INACTIVE', colorCode: '#8091A5' },
inactive: { label: 'INACTIVE', colorCode: '#8091A5' },
on_leave: { label: 'INACTIVE', colorCode: 'sky' },
deleted: { label: 'INACTIVE', colorCode: 'wp-red' },
existed: { label: 'INACTIVE', colorCode: 'wp-red' },
};
Styling
- Text Color: White (#FFFFFF) by default
- Text Transform: Capitalize
- Padding: 1 vertical, 2 horizontal
- Font Weight: Normal
- Width: Fit-content
- Print Support: Color preservation enabled
ConfirmationPopover
A modal-based confirmation dialog component for user actions that require explicit confirmation.
Component Location
import ConfirmationPopover from 'components/Notifications/ConfirmationPopover';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| isOpen | boolean | ✓ | - | Controls modal visibility |
| onClose | function | ✓ | - | Modal close handler |
| title | string | - | 'Confirmation' | Modal title |
| content | ReactNode | - | 'You have unsaved changes do you want to discard them?' | Modal content |
| footer | ReactNode | - | null | Custom footer component |
TypeScript Interface
interface ConfirmationPopoverProps {
isOpen: boolean;
onClose: () => void;
title?: string;
content?: React.ReactNode;
footer?: React.ReactNode;
}
Features
Modal Configuration
- Small size modal (sm)
- Custom positioning with top margin
- Overlay backdrop
- Consistent header and footer styling
Flexible Content
- Support for string, ReactNode, or array of nodes
- Customizable title and content
- Optional custom footer component
Responsive Design
- Responsive sizing
- Proper spacing and typography
- Consistent with WorkPay design system
Usage Examples
Basic Confirmation
import ConfirmationPopover from 'components/Notifications/ConfirmationPopover';
function DeleteConfirmation() {
const [isOpen, setIsOpen] = useState(false);
const handleDelete = () => {
// Delete logic here
setIsOpen(false);
};
return (
<>
<Button onClick={() => setIsOpen(true)} colorScheme='red'>
Delete Employee
</Button>
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title='Delete Employee'
content='Are you sure you want to delete this employee? This action cannot be undone.'
/>
</>
);
}
Custom Footer
import ConfirmationPopover, {
ConfirmationFooter,
} from 'components/Notifications/ConfirmationPopover';
function CustomConfirmation() {
const [isOpen, setIsOpen] = useState(false);
const handleDiscard = () => {
// Discard changes logic
setIsOpen(false);
};
return (
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title='Unsaved Changes'
content='You have unsaved changes. What would you like to do?'
footer={
<ConfirmationFooter
onClose={() => setIsOpen(false)}
secondaryAction={handleDiscard}
/>
}
/>
);
}
Complex Content
import ConfirmationPopover from 'components/Notifications/ConfirmationPopover';
function PayrollConfirmation() {
const [isOpen, setIsOpen] = useState(false);
const confirmationContent = (
<VStack spacing={4} align='start'>
<Text>You are about to process payroll for:</Text>
<List spacing={2}>
<ListItem>• 150 Active Employees</ListItem>
<ListItem>• Total Amount: $125,000</ListItem>
<ListItem>• Pay Period: March 1-15, 2024</ListItem>
</List>
<Alert status='warning' size='sm'>
<AlertIcon />
This action cannot be undone once processing begins.
</Alert>
</VStack>
);
return (
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title='Process Payroll'
content={confirmationContent}
footer={
<ModalFooter>
<Button variant='outline' mr={3} onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button colorScheme='green' onClick={handleProcessPayroll}>
Process Payroll
</Button>
</ModalFooter>
}
/>
);
}
Form Exit Confirmation
import ConfirmationPopover from 'components/Notifications/ConfirmationPopover';
function FormWithConfirmation() {
const [isOpen, setIsOpen] = useState(false);
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const handleFormLeave = () => {
if (hasUnsavedChanges) {
setIsOpen(true);
} else {
// Navigate away
}
};
return (
<>
<form>
{/* Form fields */}
<Button onClick={handleFormLeave}>Cancel</Button>
</form>
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title='Unsaved Changes'
content='You have unsaved changes. Are you sure you want to leave?'
/>
</>
);
}
ConfirmationFooter
A reusable footer component for confirmation dialogs with close and discard actions.
Component Location
import { ConfirmationFooter } from 'components/Notifications/ConfirmationPopover';
Props
| Prop | Type | Required | Description |
|---|---|---|---|
| onClose | function | ✓ | Close button handler |
| secondaryAction | function | ✓ | Discard/Secondary action handler |
TypeScript Interface
interface ConfirmationFooterProps {
onClose: () => void;
secondaryAction: () => void;
}
Usage Examples
Basic Usage
import { ConfirmationFooter } from 'components/Notifications/ConfirmationPopover';
function CustomModal() {
const handleDiscard = () => {
// Discard logic
console.log('Changes discarded');
};
return (
<ConfirmationFooter
onClose={() => setIsOpen(false)}
secondaryAction={handleDiscard}
/>
);
}
Notification Patterns
Status Display Patterns
Table Status Column
function StatusTable({ data }) {
return (
<Table>
<Thead>
<Tr>
<Th>Item</Th>
<Th>Status</Th>
<Th>Actions</Th>
</Tr>
</Thead>
<Tbody>
{data.map(item => (
<Tr key={item.id}>
<Td>{item.name}</Td>
<Td>
<WPStatusFormatter status={item.status} fontSize='xs' />
</Td>
<Td>
<ActionButtons item={item} />
</Td>
</Tr>
))}
</Tbody>
</Table>
);
}
Card Status Display
function StatusCard({ item }) {
return (
<Card>
<CardHeader>
<HStack justify='space-between'>
<Heading size='md'>{item.title}</Heading>
<WPStatusFormatter status={item.status} size='sm' />
</HStack>
</CardHeader>
<CardBody>
<Text>{item.description}</Text>
</CardBody>
</Card>
);
}
Confirmation Patterns
Delete Confirmation
function useDeleteConfirmation() {
const [isOpen, setIsOpen] = useState(false);
const [itemToDelete, setItemToDelete] = useState(null);
const confirmDelete = item => {
setItemToDelete(item);
setIsOpen(true);
};
const handleDelete = async () => {
try {
await deleteItem(itemToDelete.id);
toast.success('Item deleted successfully');
} catch (error) {
toast.error('Failed to delete item');
} finally {
setIsOpen(false);
setItemToDelete(null);
}
};
const DeleteConfirmationModal = (
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title='Delete Item'
content={`Are you sure you want to delete "${itemToDelete?.name}"?`}
footer={
<ModalFooter>
<Button variant='outline' mr={3} onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button colorScheme='red' onClick={handleDelete}>
Delete
</Button>
</ModalFooter>
}
/>
);
return { confirmDelete, DeleteConfirmationModal };
}
Form Exit Confirmation
function useFormExitConfirmation() {
const [isOpen, setIsOpen] = useState(false);
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const confirmExit = () => {
if (hasUnsavedChanges) {
setIsOpen(true);
} else {
// Navigate away
navigate('/');
}
};
const handleDiscard = () => {
setHasUnsavedChanges(false);
setIsOpen(false);
navigate('/');
};
const ExitConfirmationModal = (
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title='Unsaved Changes'
content='You have unsaved changes. Are you sure you want to leave?'
footer={
<ConfirmationFooter
onClose={() => setIsOpen(false)}
secondaryAction={handleDiscard}
/>
}
/>
);
return { confirmExit, setHasUnsavedChanges, ExitConfirmationModal };
}
Advanced Usage Patterns
Bulk Action Confirmation
function BulkActionConfirmation({ selectedItems, action }) {
const [isOpen, setIsOpen] = useState(false);
const confirmationContent = (
<VStack spacing={3} align='start'>
<Text>
You are about to {action} {selectedItems.length} items:
</Text>
<List spacing={1} maxH='200px' overflowY='auto'>
{selectedItems.map(item => (
<ListItem key={item.id}>• {item.name}</ListItem>
))}
</List>
<Alert status='warning' size='sm'>
<AlertIcon />
This action will affect all selected items.
</Alert>
</VStack>
);
return (
<ConfirmationPopover
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title={`Bulk ${action}`}
content={confirmationContent}
/>
);
}
Best Practices
Status Display
- Consistent Colors: Use predefined status colors for consistency
- Readable Text: Ensure sufficient contrast between text and background
- Print Compatibility: Include print-specific styling for reports
- Responsive Design: Test status badges on different screen sizes
Confirmation Dialogs
- Clear Actions: Use descriptive button text
- Consequence Explanation: Clearly explain what will happen
- Escape Routes: Always provide a way to cancel
- Confirmation Hierarchy: Use appropriate visual hierarchy
User Experience
- Immediate Feedback: Show status changes immediately
- Consistent Patterns: Use similar confirmation patterns throughout
- Progressive Disclosure: Show details only when necessary
- Error Handling: Provide clear error messages
Testing
import { render, screen, fireEvent } from '@testing-library/react';
import WPStatusFormatter from 'components/Notifications/StatusFormatter';
import ConfirmationPopover from 'components/Notifications/ConfirmationPopover';
describe('Notification Components', () => {
it('should render status badge with correct color', () => {
render(<WPStatusFormatter status='active' />);
const badge = screen.getByText('active');
expect(badge).toHaveStyle('background-color: green');
});
it('should show confirmation dialog when opened', () => {
render(
<ConfirmationPopover
isOpen={true}
onClose={() => {}}
title='Test Confirmation'
content='Are you sure?'
/>,
);
expect(screen.getByText('Test Confirmation')).toBeInTheDocument();
expect(screen.getByText('Are you sure?')).toBeInTheDocument();
});
it('should call onClose when close button is clicked', () => {
const onClose = jest.fn();
render(
<ConfirmationPopover
isOpen={true}
onClose={onClose}
title='Test'
content='Content'
/>,
);
fireEvent.click(screen.getByText('Close'));
expect(onClose).toHaveBeenCalled();
});
});
This comprehensive notification system provides consistent status visualization and user confirmation workflows for the WorkPayCore Frontend application.