Skip to main content

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​

Utility Components​


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​

PropTypeRequiredDefaultDescription
statusstring✓-The status string to format
colorCodestring--Custom color override
...restobject--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-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 (
&lt;Table&gt;
&lt;Thead&gt;
&lt;Tr&gt;
&lt;Th&gt;Name</Th>
&lt;Th&gt;Status</Th>
&lt;Th&gt;Department</Th>
</Tr>
</Thead>
&lt;Tbody&gt;
{employees.map(employee => (
<Tr key={employee.id}>
&lt;Td&gt;{employee.name}</Td>
&lt;Td&gt;
<WPStatusFormatter status={employee.status} fontSize='xs' />
</Td>
&lt;Td&gt;{employee.department}</Td>
</Tr>
))}
</Tbody>
</Table>
);
}

Payment Status Display​

import WPStatusFormatter from 'components/Notifications/StatusFormatter';

function PaymentCard({ payment }) {
return (
&lt;Card&gt;
&lt;CardHeader&gt;
<Heading size='md'>Payment #{payment.id}</Heading>
<WPStatusFormatter status={payment.status} size='sm' />
</CardHeader>
&lt;CardBody&gt;
&lt;Text&gt;Amount: ${payment.amount}</Text>
&lt;Text&gt;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 (
&lt;HStack&gt;
&lt;Text&gt;{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​

PropTypeRequiredDefaultDescription
isOpenboolean✓-Controls modal visibility
onClosefunction✓-Modal close handler
titlestring-'Confirmation'Modal title
contentReactNode-'You have unsaved changes do you want to discard them?'Modal content
footerReactNode-nullCustom footer component

TypeScript Interface​

interface ConfirmationPopoverProps {
isOpen: boolean;
onClose: () => void;
title?: string;
content?: React.ReactNode;
footer?: React.ReactNode;
}

Features​

  • 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.'
/>
</>
);
}
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'>
&lt;Text&gt;You are about to process payroll for:</Text>
<List spacing={2}>
&lt;ListItem&gt;• 150 Active Employees</ListItem>
&lt;ListItem&gt;• Total Amount: $125,000</ListItem>
&lt;ListItem&gt;• 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={
&lt;ModalFooter&gt;
<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​

PropTypeRequiredDescription
onClosefunction✓Close button handler
secondaryActionfunction✓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 (
&lt;Table&gt;
&lt;Thead&gt;
&lt;Tr&gt;
&lt;Th&gt;Item</Th>
&lt;Th&gt;Status</Th>
&lt;Th&gt;Actions</Th>
</Tr>
</Thead>
&lt;Tbody&gt;
{data.map(item => (
<Tr key={item.id}>
&lt;Td&gt;{item.name}</Td>
&lt;Td&gt;
<WPStatusFormatter status={item.status} fontSize='xs' />
</Td>
&lt;Td&gt;
<ActionButtons item={item} />
</Td>
</Tr>
))}
</Tbody>
</Table>
);
}

Card Status Display​

function StatusCard({ item }) {
return (
&lt;Card&gt;
&lt;CardHeader&gt;
<HStack justify='space-between'>
<Heading size='md'>{item.title}</Heading>
<WPStatusFormatter status={item.status} size='sm' />
</HStack>
</CardHeader>
&lt;CardBody&gt;
&lt;Text&gt;{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={
&lt;ModalFooter&gt;
<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'>
&lt;Text&gt;
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​

  1. Consistent Colors: Use predefined status colors for consistency
  2. Readable Text: Ensure sufficient contrast between text and background
  3. Print Compatibility: Include print-specific styling for reports
  4. Responsive Design: Test status badges on different screen sizes

Confirmation Dialogs​

  1. Clear Actions: Use descriptive button text
  2. Consequence Explanation: Clearly explain what will happen
  3. Escape Routes: Always provide a way to cancel
  4. Confirmation Hierarchy: Use appropriate visual hierarchy

User Experience​

  1. Immediate Feedback: Show status changes immediately
  2. Consistent Patterns: Use similar confirmation patterns throughout
  3. Progressive Disclosure: Show details only when necessary
  4. 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.