Top-Level Components
Top-level components are individual utility components that provide specific functionality without requiring their own directory structure. These components handle common patterns like text truncation, modals, toggles, navigation, and form inputs.
Overview
This document covers standalone components that are directly placed in the
src/components/ directory and provide focused functionality for the
WorkPayCore Frontend application.
Components Overview
Text & Display Components
- WPTruncateText - Text truncation with tooltip
- ComingSoon - Empty state for features under development
- UnderMaintenance - System maintenance page
Modal Components
- WPModal - Basic modal wrapper with customizable width
Input Components
- WPNumberInput - Numeric input with validation
- BoxInput - Read-only input display component
Navigation Components
- GlobalSidebar - Global application sidebar
- OnboardingStepper - Onboarding progress indicator
- ScrollArea - Custom scrollable area with styled scrollbar
Toggle Components
- ToggleSwitchOne - Multi-option toggle switch
- ToggleSwitch - Basic toggle switch
Utility Components
- ScrollToTop - Scroll to top functionality
- ProtectedRoutes - Route protection wrapper
- RenewSubscription - Subscription renewal component
WPTruncateText
A component that truncates text with a tooltip if it exceeds the maximum length. Shows the full text in a tooltip on hover.
Component Location
import WPTruncatedText from 'components/WPTruncateText';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| textToTruncate | string | ✓ | - | The text to be truncated |
| maxLength | number | - | 16 | Maximum length before truncation occurs |
TypeScript Interface
interface WPTruncatedTextProps {
textToTruncate: string;
maxLength?: number;
}
Usage Examples
Basic Usage
import WPTruncatedText from 'components/WPTruncateText';
function UserName() {
return (
<WPTruncatedText
textToTruncate='This is a very long user name that needs truncation'
maxLength={20}
/>
);
}
Default Length
import WPTruncatedText from 'components/WPTruncateText';
function FileName() {
return (
<WPTruncatedText textToTruncate='very-long-filename-that-exceeds-default-length.pdf' />
);
}
Styling
- Uses
textStyle='body-small'from theme - Font weight:
semi-bold - Font size:
13px - White space:
nowrap - Tooltip placement:
top-start
Accessibility
- Tooltip shows full text when truncated
- Supports keyboard navigation
- Screen reader accessible through tooltip
ComingSoon
Empty state component for features under development or maintenance.
Component Location
import ComingSoon from 'components/ComingSoon';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| page | string | - | - | Page/feature name |
| plural | boolean | - | false | Use plural form |
| variant | string | - | - | Variant (maintenance, under-maintenance) |
TypeScript Interface
interface ComingSoonProps {
page?: string;
plural?: boolean;
variant?: 'maintenance' | 'under-maintenance';
}
Usage Examples
Feature Coming Soon
import ComingSoon from 'components/ComingSoon';
function ReportsPage() {
return <ComingSoon page='Reports' plural={true} />;
}
Under Maintenance
import ComingSoon from 'components/ComingSoon';
function DashboardPage() {
return <ComingSoon page='Dashboard' variant='maintenance' />;
}
System Maintenance
import ComingSoon from 'components/ComingSoon';
function MaintenancePage() {
return <ComingSoon variant='under-maintenance' />;
}
Styling
- Uses background image from
assets/images/ComingSoon.svg - Centered layout with VStack
- Logo positioned absolutely for maintenance variant
- Responsive typography
WPModal
Basic modal wrapper component with customizable width and loading states.
Component Location
import WPModal from 'components/WPModal';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| heading | string | ✓ | - | Modal heading text |
| isOpen | boolean | ✓ | - | Modal open state |
| handleClose | function | ✓ | - | Close handler function |
| children | ReactNode | ✓ | - | Modal content |
| customWidth | string | ✓ | - | Custom modal width |
| isLoading | boolean | - | false | Loading state |
| isCentered | boolean | - | false | Center modal |
TypeScript Interface
interface WPModalProps {
heading: string;
isOpen: boolean;
handleClose: () => void;
children: React.ReactNode;
customWidth: string;
isLoading?: boolean;
isCentered?: boolean;
}
Usage Examples
Basic Modal
import WPModal from 'components/WPModal';
function UserEditModal() {
const [isOpen, setIsOpen] = useState(false);
return (
<WPModal
heading='Edit User'
isOpen={isOpen}
handleClose={() => setIsOpen(false)}
customWidth='600px'
>
<UserForm />
</WPModal>
);
}
Loading Modal
import WPModal from 'components/WPModal';
function SaveModal() {
const [isLoading, setIsLoading] = useState(false);
return (
<WPModal
heading='Saving Changes'
isOpen={isOpen}
handleClose={() => setIsOpen(false)}
customWidth='400px'
isLoading={isLoading}
>
<Text>Please wait while we save your changes...</Text>
</WPModal>
);
}
Styling
- Header font size:
28px - Header padding bottom:
0 - Text transform:
capitalize - Closes on overlay click (disabled when loading)
- Close button disabled during loading
WPNumberInput
Numeric input component with validation and React Hook Form integration.
Component Location
import { WPNumberInput, WPNumberInput2 } from 'components/WPNumberInput';
Props
WPNumberInput Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| name | string | ✓ | - | Input name |
| control | Control | ✓ | - | React Hook Form control |
| placeholder | string | ✓ | - | Input placeholder |
| required | boolean | - | false | Required field |
| defaultValue | number | - | - | Default value |
| rules | object | - | - | Additional validation rules |
| styles | object | - | - | Custom styles |
WPNumberInput2 Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| name | string | ✓ | - | Input name |
| control | Control | ✓ | - | React Hook Form control |
| label | string | ✓ | - | Input label |
| placeholder | string | ✓ | - | Input placeholder |
| isRequired | boolean | - | false | Required field |
| isDisabled | boolean | - | false | Disabled state |
| error | FieldError | - | - | Error object |
| helperText | string | - | - | Helper text |
| size | string | - | 'sm' | Input size |
| inputMode | string | - | 'numeric' | Input mode |
TypeScript Interface
interface WPNumberInputProps {
name: string;
control: Control;
placeholder: string;
required?: boolean;
defaultValue?: number;
rules?: object;
styles?: object;
}
interface WPNumberInput2Props {
name: string;
control: Control;
label: string;
placeholder: string;
isRequired?: boolean;
isDisabled?: boolean;
error?: FieldError;
helperText?: string;
size?: string;
inputMode?: string;
}
Usage Examples
Basic Usage
import { WPNumberInput } from 'components/WPNumberInput';
import { useForm } from 'react-hook-form';
function AccruedDaysForm() {
const {
control,
formState: { errors },
} = useForm();
return (
<FormControl isInvalid={errors.days_accrued}>
<FormLabel isRequired>ACCRUED DAYS</FormLabel>
<WPNumberInput
name='days_accrued'
control={control}
placeholder='Enter number of days'
required
/>
<FormErrorMessage>{errors.days_accrued?.message}</FormErrorMessage>
</FormControl>
);
}
Advanced Usage (WPNumberInput2)
import { WPNumberInput2 } from 'components/WPNumberInput';
import { useForm } from 'react-hook-form';
function SalaryForm() {
const {
control,
formState: { errors },
} = useForm();
return (
<WPNumberInput2
name='salary'
control={control}
label='Monthly Salary'
placeholder='Enter salary amount'
isRequired
error={errors.salary}
helperText='Enter amount in local currency'
size='md'
/>
);
}
Validation
- Built-in pattern validation:
/^[1-9]\d*$/ - Custom validation messages
- Required field validation
- Numeric keyboard on mobile devices
Styling
- Focus border color:
green - Form control integration
- Error state styling
- Helper text support
ToggleSwitchOne
Multi-option toggle switch component with customizable styling and loading states.
Component Location
import ToggleSwitchOne from 'components/ToggleSwitchOne';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| options | Array | ✓ | - | Array of option objects |
| selected | object | ✓ | - | Currently selected option |
| handleChange | function | ✓ | - | Change handler |
| name | string | ✓ | - | Form field name |
| isLoading | boolean | - | false | Loading state |
| isDisabled | boolean | - | false | Disabled state |
| minWidth | number | - | 100 | Minimum width per option |
TypeScript Interface
interface ToggleSwitchOneProps {
options: Array<{
value: string | number;
label: string;
}>;
selected: {
value: string | number;
label: string;
};
handleChange: (value: any) => void;
name: string;
isLoading?: boolean;
isDisabled?: boolean;
minWidth?: number;
}
Usage Examples
Basic Toggle
import ToggleSwitchOne from 'components/ToggleSwitchOne';
function StatusToggle() {
const [selected, setSelected] = useState({
value: 'active',
label: 'Active',
});
const options = [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
];
return (
<ToggleSwitchOne
options={options}
selected={selected}
handleChange={setSelected}
name='status'
/>
);
}
Loading State
import ToggleSwitchOne from 'components/ToggleSwitchOne';
function PayrollToggle() {
const [isLoading, setIsLoading] = useState(false);
const handleChange = async value => {
setIsLoading(true);
// API call
await updatePayrollStatus(value);
setIsLoading(false);
};
return (
<ToggleSwitchOne
options={payrollOptions}
selected={currentStatus}
handleChange={handleChange}
name='payroll_status'
isLoading={isLoading}
minWidth={120}
/>
);
}
Styling
- Background color:
skeletonTable - Border radius:
28px - Height:
35px - Animated selection indicator
- Loading spinner integration
- Cursor states for disabled/loading
GlobalSidebar
Global application sidebar with navigation menu for multi-tenant applications.
Component Location
import GlobalSidebar from 'components/GlobalSidebar';
Features
- Role-based navigation (admin/employee views)
- Feature flag integration
- Permission-based access control
- Subscription-based menu visibility
- Hierarchical menu structure
- Remote payroll support
- Country-specific features
Usage Examples
Basic Usage
import GlobalSidebar from 'components/GlobalSidebar';
function AppLayout() {
return (
<Flex>
<GlobalSidebar />
<Box flex={1}>
<MainContent />
</Box>
</Flex>
);
}
Menu Structure
Employee Menu Items
- Home
- People (with submenus)
- Payroll (with submenus)
- Expenses
- Leave
- Performance Management
- Documents
Admin Menu Items
- All employee items plus:
- Settings
- Analytics
- Billing
- Admin tools
Integration
- Works with feature flags system
- Integrates with subscription status
- Supports remote payroll switching
- Country-specific menu items
OnboardingStepper
Onboarding progress indicator showing completion steps.
Component Location
import OnboardingStepper from 'components/OnboardingStepper';
Features
- 5-step onboarding process
- Progress visualization
- Step completion indicators
- Responsive design
Usage Examples
Basic Usage
import OnboardingStepper from 'components/OnboardingStepper';
function OnboardingLayout() {
return (
<Box>
<OnboardingStepper />
<OnboardingContent />
</Box>
);
}
Steps
- Create Organization
- Adjust Settings
- Add People
- Run Payroll
- Choose Plan
Styling
- Background:
green-dark - Progress bar with
whiteAlphacolor scheme - Circular step indicators
- Responsive step layout
ScrollArea
Custom scrollable area with styled scrollbar and drag functionality.
Component Location
import ScrollArea from 'components/ScrollArea';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| children | ReactNode | ✓ | - | Scrollable content |
| scrollThumbColor | string | - | 'whiteAlpha.500' | Scroll thumb color |
Features
- Custom scrollbar styling
- Drag-to-scroll functionality
- Hidden native scrollbars
- Smooth scrolling animation
- Responsive thumb sizing
Usage Examples
Basic Usage
import ScrollArea from 'components/ScrollArea';
function LongContent() {
return (
<ScrollArea>
<Box height='2000px'>
<Text>Very long content that needs scrolling...</Text>
</Box>
</ScrollArea>
);
}
Custom Thumb Color
import ScrollArea from 'components/ScrollArea';
function CustomScrollArea() {
return (
<ScrollArea scrollThumbColor='green.500'>
<LongContentList />
</ScrollArea>
);
}
Styling
- Hidden native scrollbars
- Custom thumb appearance
- Hover states
- Drag states
- Responsive sizing
BoxInput
Read-only input display component that mimics input styling.
Component Location
import BoxInput from 'components/BoxInput';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| title | string | - | 'This is a readonly field' | Tooltip text |
| width | string | - | 'full' | Input width |
| isDisabled | boolean | - | false | Disabled state |
| isRequired | boolean | - | false | Required field |
| label | string | - | - | Field label |
| labelSize | string | - | 'md' | Label size |
| children | ReactNode | - | - | Input content |
TypeScript Interface
interface BoxInputProps {
title?: string;
width?: string;
isDisabled?: boolean;
isRequired?: boolean;
label?: string;
labelSize?: string;
children?: React.ReactNode;
}
Usage Examples
Basic Usage
import BoxInput from 'components/BoxInput';
function ReadOnlyField() {
return (
<BoxInput label='Employee ID' title='This field is automatically generated'>
<Text>EMP-001</Text>
</BoxInput>
);
}
Disabled State
import BoxInput from 'components/BoxInput';
function DisabledField() {
return (
<BoxInput
label='Calculated Value'
isDisabled
title='This value is calculated automatically'
>
<Text>$5,000.00</Text>
</BoxInput>
);
}
Styling
- Background color:
#F2F2F2 - Border:
1px transparent - Height:
2.5rem - Padding:
1rem - Disabled opacity:
0.8 - Cursor:
not-allowedwhen disabled
UnderMaintenance
System maintenance page with contact information and support channels.
Component Location
import { UnderMaintenance } from 'components/UnderMaintenance';
Features
- Full-page maintenance message
- Contact information with copy functionality
- Country-specific phone numbers
- Support email integration
- Responsive design
Usage Examples
Basic Usage
import { UnderMaintenance } from 'components/UnderMaintenance';
function MaintenancePage() {
return <UnderMaintenance />;
}
Contact Channels
- Email: support@myworkpay.com
- Kenya: +254 711 082123 / +254 730 731303
- Nigeria: +234 810 401 5886 / +234 906 382 9334
- Uganda: +256 323 200 740
Styling
- Centered layout
- Logo positioning
- Country flag integration
- Copy-to-clipboard functionality
- Responsive design
Migration Notes
Breaking Changes
- WPNumberInput: Updated validation patterns
- GlobalSidebar: New menu structure for remote payroll
- ToggleSwitchOne: Improved loading states
Deprecation Warnings
- Old modal patterns should migrate to WPModal
- Legacy number inputs should use WPNumberInput2
Upgrade Paths
- Replace old text truncation with WPTruncateText
- Update modal implementations to use WPModal
- Migrate number inputs to WPNumberInput2
- Update sidebar implementations to use GlobalSidebar
Best Practices
Text Truncation
- Use appropriate maxLength based on container width
- Provide meaningful tooltips
- Consider responsive truncation lengths
Modal Usage
- Always provide proper close handlers
- Use loading states for async operations
- Set appropriate modal widths
Number Inputs
- Use proper validation rules
- Provide clear error messages
- Set appropriate input modes for mobile
Navigation
- Implement proper permission checks
- Use feature flags for conditional navigation
- Provide clear visual hierarchy
Scrolling
- Use ScrollArea for custom scroll styling
- Implement proper keyboard navigation
- Consider mobile scroll behavior
Accessibility
General Guidelines
- All components support keyboard navigation
- Proper ARIA attributes where applicable
- Screen reader friendly implementations
- High contrast mode support
Specific Features
- WPTruncateText: Tooltip accessibility
- WPModal: Focus management
- ToggleSwitchOne: Keyboard selection
- GlobalSidebar: Navigation accessibility
- ScrollArea: Keyboard scrolling support
Performance Considerations
Optimization Tips
- Use React.memo for expensive components
- Implement proper loading states
- Optimize menu rendering with visibility checks
- Use efficient scroll handling
Memory Management
- Proper cleanup in useEffect hooks
- Event listener removal
- Animation frame cancellation
- Ref cleanup
Testing Strategies
Unit Testing
- Test prop validation
- Test state changes
- Test event handlers
- Test accessibility features
Integration Testing
- Test with React Hook Form
- Test navigation flows
- Test permission systems
- Test responsive behavior
E2E Testing
- Test complete user flows
- Test accessibility compliance
- Test performance metrics
- Test cross-browser compatibility