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
onClosefunctionClose button handler
secondaryActionfunctionDiscard/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.