Timeline Components
The Timeline Components provide chronological visualization and progress tracking functionality for the WorkPayCore Frontend application. These components handle step-by-step processes, progress indicators, and time-based event displays with consistent styling and behavior patterns.
Overview
This document covers timeline, stepper, and progress components that display chronological data, multi-step processes, and workflow progression throughout the application.
Components Overview
Core Timeline Components
- WPDotTimeline - Basic timeline with dot indicators
- WPCheckedTimeline - Timeline with checkmark indicators
- WPTimelineConnector - Base timeline connector
Stepper Components
- OnboardingStepper - Main onboarding progress indicator
- ProjectStepper - Project creation stepper
- BulkUploadStepper - Bulk upload progress stepper
- FormStepper - Multi-step form stepper
- WalletOptInStepper - Wallet opt-in process stepper
Progress Components
- DayTimeline - Day-based timeline visualization
- WeekTimeline - Week-based timeline visualization
- TimelineView - Employee history timeline
- ContractStatusProgress - Contract progress tracking
WPDotTimeline
A basic timeline component with dot indicators for displaying chronological events or process steps.
Component Location
import WPDotTimeline from 'components/Timeline/WpDotTimeline';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| options | TimelineOption[] | ✓ | - | Array of timeline options |
TypeScript Interface
interface TimelineOption {
title: string | ReactNode;
display: string | ReactNode;
icon?: ReactNode;
}
interface WPDotTimelineProps {
options: TimelineOption[];
}
Usage Examples
Basic Project Timeline
import WPDotTimeline from 'components/Timeline/WpDotTimeline';
function ProjectTimeline() {
const timelineOptions = [
{
title: 'Project Started',
display: 'Project initialization and team assignment completed.',
},
{
title: 'Development Phase',
display: 'Core features development in progress.',
},
{
title: 'Testing Phase',
display: 'Quality assurance and user acceptance testing.',
},
{
title: 'Deployment',
display: 'Production deployment and go-live.',
},
];
return <WPDotTimeline options={timelineOptions} />;
}
Timeline with Custom Icons
import WPDotTimeline from 'components/Timeline/WpDotTimeline';
import { CheckIcon, TimeIcon, WarningIcon } from '@chakra-ui/icons';
function ProcessTimeline() {
const processSteps = [
{
title: 'Application Submitted',
display: 'Application received and under review.',
icon: <CheckIcon color='green' />,
},
{
title: 'In Review',
display: 'Currently being reviewed by the team.',
icon: <TimeIcon color='orange' />,
},
{
title: 'Requires Attention',
display: 'Additional information needed.',
icon: <WarningIcon color='red' />,
},
];
return <WPDotTimeline options={processSteps} />;
}
Request History Timeline
function RequestHistoryTimeline({ request }) {
const historyOptions = request.history.map(event => ({
title: event.action,
display: `${event.user} - ${format(
new Date(event.date),
'MMM dd, yyyy HH:mm',
)}`,
}));
return <WPDotTimeline options={historyOptions} />;
}
WPCheckedTimeline
A timeline component with checkmark indicators, ideal for displaying completed steps or achievements.
Component Location
import WPCheckedTimeline from 'components/Timeline/WpCheckedTimeline';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| options | TimelineOption[] | ✓ | - | Array of timeline options |
| spacing | number | - | - | Spacing between items |
TypeScript Interface
interface TimelineOption {
title?: ReactNode;
display?: ReactNode;
Icon?: ReactNode;
}
interface WPCheckedTimelineProps extends StackProps {
options: TimelineOption[];
}
Usage Examples
Onboarding Progress
import WPCheckedTimeline from 'components/Timeline/WpCheckedTimeline';
function OnboardingProgress() {
const onboardingSteps = [
{
title: 'Account Created',
display: 'User account has been successfully created.',
},
{
title: 'Profile Completed',
display: 'All required profile information has been provided.',
},
{
title: 'Training Completed',
display: 'Mandatory training sessions have been finished.',
},
];
return <WPCheckedTimeline options={onboardingSteps} />;
}
Approval Process
import WPCheckedTimeline from 'components/Timeline/WpCheckedTimeline';
function ApprovalTimeline({ approvals }) {
const approvalSteps = approvals.map(approval => ({
title: approval.stageName,
display: `Approved by ${approval.approverName} on ${format(
new Date(approval.date),
'MMM dd, yyyy',
)}`,
}));
return <WPCheckedTimeline options={approvalSteps} spacing={4} />;
}
Achievement Timeline
import WPCheckedTimeline from 'components/Timeline/WpCheckedTimeline';
import { TrophyIcon } from 'components/WPIcons';
function AchievementTimeline({ achievements }) {
const achievementSteps = achievements.map(achievement => ({
title: achievement.name,
display: achievement.description,
Icon: <TrophyIcon color='gold' />,
}));
return <WPCheckedTimeline options={achievementSteps} />;
}
WPTimelineConnector
The base timeline connector component that provides the visual connection line between timeline items.
Component Location
import WPTimelineConnector from 'components/Timeline/WPTimelineConnector';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| children | ReactNode | ✓ | - | Timeline items |
TypeScript Interface
interface WPTimelineConnectorProps extends StackProps {
children: React.ReactNode;
}
Usage Examples
Custom Timeline Implementation
import WPTimelineConnector from 'components/Timeline/WPTimelineConnector';
import { VStack, Box, Text } from '@chakra-ui/react';
function CustomTimeline({ events }) {
return (
<WPTimelineConnector>
{events.map((event, idx) => (
<VStack key={idx} alignItems='flex-start' pl={4} position='relative'>
<Box
sx={{
width: '12px',
height: '12px',
bgColor: event.completed ? 'green' : 'gray.300',
borderRadius: '50%',
position: 'absolute',
top: 0,
left: '-6px',
}}
/>
<Text fontWeight='bold'>{event.title}</Text>
<Text color='gray.600'>{event.description}</Text>
</VStack>
))}
</WPTimelineConnector>
);
}
OnboardingStepper
The main onboarding progress indicator showing the 5-step onboarding process.
Component Location
import OnboardingStepper from 'components/OnboardingStepper';
Features
- 5-step onboarding process
- Progress bar visualization
- Step completion indicators
- Responsive design
- Hide/show functionality
Onboarding Steps
- Create Organization - Basic organization setup
- Adjust Settings - Configuration and preferences
- Add People - Employee management setup
- Run Payroll - Payroll system configuration
- Choose Plan - Subscription plan selection
Usage Examples
Basic Onboarding Layout
import OnboardingStepper from 'components/OnboardingStepper';
function OnboardingLayout() {
return (
<Box>
<OnboardingStepper />
<Box p={8}>
<OnboardingContent />
</Box>
</Box>
);
}
Conditional Onboarding Display
import OnboardingStepper from 'components/OnboardingStepper';
function DashboardLayout({ user }) {
const showOnboarding = !user.onboardingCompleted;
return (
<Box>
{showOnboarding && <OnboardingStepper />}
<DashboardContent />
</Box>
);
}
Styling
- Background:
green-dark - Progress bar:
whiteAlphacolor scheme - Step indicators: Circular design with numbering
- Responsive step layout
ProjectStepper
A simple stepper component for project creation workflows.
Component Location
import Stepper from 'containers/Timesheets/Projects/Stepper';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| currentStep | number | ✓ | - | Current step index |
Steps
- Project details - Basic project information
- Billing details - Billing and payment configuration
Usage Examples
Project Creation Flow
import Stepper from 'containers/Timesheets/Projects/Stepper';
function ProjectCreationWizard() {
const [currentStep, setCurrentStep] = useState(1);
return (
<VStack spacing={6}>
<Stepper currentStep={currentStep} />
{currentStep === 1 && (
<ProjectDetailsForm onNext={() => setCurrentStep(2)} />
)}
{currentStep === 2 && (
<BillingDetailsForm onBack={() => setCurrentStep(1)} />
)}
</VStack>
);
}
BulkUploadStepper
A stepper component specifically designed for bulk upload processes.
Component Location
import BulkUploadStepper from 'components/BulkUpload/BulkUploadStepper';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| steps | string[] | ✓ | - | Array of step names |
| title | string | ✓ | - | Stepper title |
Usage Examples
Employee Bulk Upload
import BulkUploadStepper from 'components/BulkUpload/BulkUploadStepper';
function EmployeeBulkUpload() {
const uploadSteps = [
'Download Template',
'Fill Data',
'Upload File',
'Review & Confirm',
'Process Complete',
];
return (
<BulkUploadStepper
steps={uploadSteps}
title='Employee Bulk Upload Progress'
/>
);
}
Payroll Data Upload
function PayrollBulkUpload() {
const payrollSteps = [
'Prepare Data',
'Validate Information',
'Upload Payroll',
'Review Results',
];
return <BulkUploadStepper steps={payrollSteps} title='Payroll Data Upload' />;
}
FormStepper
A comprehensive multi-step form stepper for various form workflows.
Component Location
import { FormStepper } from 'containers/People/Employee/AddEmployeeSingleEntry/Stepper';
Features
- Multi-step form navigation
- Form validation per step
- Progress tracking
- Back/Next navigation
- Form state management
Usage Examples
Employee Registration Form
import { FormStepper } from 'containers/People/Employee/AddEmployeeSingleEntry/Stepper';
function EmployeeRegistrationModal() {
const [isOpen, setIsOpen] = useState(false);
return (
<FormStepper
isOpen={isOpen}
onClose={() => setIsOpen(false)}
option='add_employee'
onSuccess={() => {
setIsOpen(false);
// Refresh employee list
}}
/>
);
}
Company Setup Form
import { FormStepper } from 'containers/Settings/General/OrganisationSettings/CompaniesBranches/page/forms/AddCompany/Stepper';
function CompanySetupForm() {
return (
<FormStepper
onClose={() => navigate('/settings/companies')}
onSuccess={() => {
// Handle success
toast.success('Company created successfully');
}}
/>
);
}
WalletOptInStepper
A stepper component for wallet opt-in processes.
Component Location
import StepperWrapper from 'containers/MyWallet/Pages/OptIn/Forms/Stepper';
Steps
- Personal Details - User information collection
- Security Questions - Security setup
- PIN - PIN configuration
Usage Examples
Wallet Registration Flow
import StepperWrapper from 'containers/MyWallet/Pages/OptIn/Forms/Stepper';
function WalletRegistration() {
const [currentStep, setCurrentStep] = useState(1);
return (
<StepperWrapper
step={currentStep}
heading='Set up your wallet'
description='Complete the following steps to activate your wallet'
>
{currentStep === 1 && (
<PersonalDetailsForm onNext={() => setCurrentStep(2)} />
)}
{currentStep === 2 && (
<SecurityQuestionsForm
onNext={() => setCurrentStep(3)}
onBack={() => setCurrentStep(1)}
/>
)}
{currentStep === 3 && <PinSetupForm onBack={() => setCurrentStep(2)} />}
</StepperWrapper>
);
}
DayTimeline
A timeline component for visualizing daily time tracking and work intervals.
Component Location
import DayTimeline from 'containers/Timesheets/Employee/Timesheets/DayTimeline';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| intervals | TimeInterval[] | ✓ | - | Array of time intervals |
| totalTimeWorked | string | ✓ | - | Total time worked |
TypeScript Interface
interface TimeInterval {
startTime: string;
endTime: string;
duration: number;
}
interface DayTimelineProps {
intervals: TimeInterval[];
totalTimeWorked: string;
}
Usage Examples
Employee Time Tracking
import DayTimeline from 'containers/Timesheets/Employee/Timesheets/DayTimeline';
function EmployeeTimesheetDay({ timesheetData }) {
const intervals = timesheetData.intervals.map(interval => ({
startTime: interval.clock_in,
endTime: interval.clock_out,
duration: interval.duration,
}));
return (
<DayTimeline
intervals={intervals}
totalTimeWorked={timesheetData.totalTime}
/>
);
}
WeekTimeline
A timeline component for visualizing weekly time tracking across multiple days.
Component Location
import WeekTimeline from 'containers/Timesheets/Employee/Timesheets/WeekTimeline';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| data | WeekTimeData[] | ✓ | - | Array of week time data |
| totalTimeWorked | string | - | '00:00:00' | Total time worked |
| isLoading | boolean | - | false | Loading state |
Usage Examples
Weekly Timesheet View
import WeekTimeline from 'containers/Timesheets/Employee/Timesheets/WeekTimeline';
function WeeklyTimesheetView({ weekData, isLoading }) {
return (
<WeekTimeline
data={weekData}
totalTimeWorked={weekData.totalTime}
isLoading={isLoading}
/>
);
}
TimelineView
A comprehensive timeline component for displaying employee history and events.
Component Location
import TimelineView from 'containers/People/EmployeeHistory/components/TimelineView';
Features
- Infinite scroll loading
- Responsive design
- Event categorization
- Loading states
- Mobile-friendly
Usage Examples
Employee History Timeline
import TimelineView from 'containers/People/EmployeeHistory/components/TimelineView';
function EmployeeHistoryPage() {
const [viewMode, setViewMode] = useState('timeline');
return (
<Stack spacing={6}>
<HStack justify='space-between'>
<ViewToggleButtons viewMode={viewMode} setViewMode={setViewMode} />
</HStack>
{viewMode === 'timeline' ? (
<TimelineView
timelineData={historyData}
isLoading={isLoading}
paginatedData={paginatedData}
field='all'
/>
) : (
<TableHistoryView {...tableProps} />
)}
</Stack>
);
}
ContractStatusProgress
A specialized progress component for EOR contract status tracking.
Component Location
import ViewContractStatusProgress from 'containers/EOR/Employees/components/ViewContractStatusProgress';
Features
- Multi-stage contract process
- Status indicators
- Progress visualization
- Step completion tracking
Contract Stages
- Employee details - Basic information entry
- Generate & Send Contract to Legal - Contract creation
- Legal Contract Review & Signoff - Legal validation
- Send Contract to Employee - Employee notification
- Employee Contract is Signed - Employee signature
- Employee Activated - Account activation
Usage Examples
EOR Contract Progress
function EORContractProgress({ contractData }) {
return (
<ViewContractStatusProgress
contractStatus={contractData.status}
currentStage={contractData.currentStage}
completedStages={contractData.completedStages}
/>
);
}
Stepper Patterns
Multi-Step Form Pattern
function MultiStepFormPattern() {
const [currentStep, setCurrentStep] = useState(0);
const [formData, setFormData] = useState({});
const steps = [
{ id: 1, label: 'Personal Info', component: PersonalInfoStep },
{ id: 2, label: 'Employment', component: EmploymentStep },
{ id: 3, label: 'Payment', component: PaymentStep },
{ id: 4, label: 'Review', component: ReviewStep },
];
const handleNext = () => {
setCurrentStep(prev => Math.min(steps.length - 1, prev + 1));
};
const handleBack = () => {
setCurrentStep(prev => Math.max(0, prev - 1));
};
const isLastStep = currentStep === steps.length - 1;
const isFirstStep = currentStep === 0;
return (
<VStack spacing={6}>
{/* Stepper Header */}
<HStack spacing={4} align='center' justify='space-between' w='100%'>
{steps.map((step, index) => {
const isActive = currentStep === index;
const isCompleted = currentStep > index;
return (
<Box
key={step.id}
borderRadius='32px'
px={2}
py={1}
border='1px solid #62A446'
bgColor={isActive || isCompleted ? 'green' : 'white'}
>
<HStack spacing={3}>
<Circle
size='28px'
bgColor={isActive || isCompleted ? 'white' : 'green'}
color={isActive || isCompleted ? 'green' : 'white'}
>
{isCompleted ? <CheckIcon /> : step.id}
</Circle>
<Text
fontSize='sm'
fontWeight='normal'
color={isActive || isCompleted ? 'white' : 'green'}
>
{step.label}
</Text>
</HStack>
</Box>
);
})}
</HStack>
{/* Step Content */}
<Box w='100%' minH='400px'>
{React.createElement(steps[currentStep].component, {
formData,
setFormData,
onNext: handleNext,
onBack: handleBack,
})}
</Box>
{/* Navigation */}
<HStack spacing={4} justify='space-between' w='100%'>
<Button variant='outline' onClick={handleBack} isDisabled={isFirstStep}>
Back
</Button>
<Button
colorScheme='green'
onClick={isLastStep ? handleSubmit : handleNext}
>
{isLastStep ? 'Submit' : 'Next'}
</Button>
</HStack>
</VStack>
);
}
Progress Tracking Pattern
function ProgressTrackingPattern({ stages, currentStage }) {
const calculateProgress = () => {
const completedStages = stages.filter(stage => stage.completed).length;
return (completedStages / stages.length) * 100;
};
return (
<VStack spacing={4} w='100%'>
{/* Progress Bar */}
<Box w='100%'>
<Progress value={calculateProgress()} colorScheme='green' />
<Text textAlign='center' fontSize='sm' color='gray.600' mt={2}>
{stages.filter(stage => stage.completed).length} of {stages.length}{' '}
completed
</Text>
</Box>
{/* Timeline */}
<WPTimelineConnector>
{stages.map((stage, index) => (
<VStack
key={index}
alignItems='flex-start'
pl={4}
position='relative'
>
<Box
sx={{
width: '20px',
height: '20px',
borderRadius: '50%',
position: 'absolute',
top: 0,
left: '-10px',
border: '2px solid',
borderColor: stage.completed ? 'green' : 'gray.300',
bgColor: stage.completed ? 'green' : 'white',
}}
>
{stage.completed && <CheckIcon color='white' w='12px' h='12px' />}
</Box>
<Text
fontWeight='bold'
color={stage.completed ? 'green' : 'gray.600'}
>
{stage.title}
</Text>
<Text fontSize='sm' color='gray.600'>
{stage.description}
</Text>
{stage.completed && (
<Text fontSize='xs' color='green'>
Completed on{' '}
{format(new Date(stage.completedAt), 'MMM dd, yyyy')}
</Text>
)}
</VStack>
))}
</WPTimelineConnector>
</VStack>
);
}
Best Practices
Timeline Design
-
Consistent Visual Language
- Use consistent colors and spacing
- Maintain uniform icon sizes
- Apply consistent typography
-
Information Hierarchy
- Place most important information first
- Use clear visual distinctions between completed and pending items
- Provide adequate white space
-
Interactive Elements
- Make clickable elements obvious
- Provide hover states
- Include keyboard navigation support
Progress Tracking
-
Clear Progress Indicators
- Show current position clearly
- Indicate completed vs. pending steps
- Provide progress percentage when helpful
-
Error Handling
- Handle validation errors gracefully
- Allow users to fix errors and continue
- Provide clear error messages
-
State Management
- Persist progress across page refreshes
- Handle browser navigation properly
- Maintain form state during multi-step processes
Performance
-
Efficient Rendering
- Use React.memo for timeline items
- Implement virtualization for long timelines
- Optimize re-renders with proper dependencies
-
Data Loading
- Implement progressive loading for large datasets
- Use skeleton states during loading
- Cache timeline data appropriately
Accessibility
-
Screen Reader Support
- Provide proper ARIA labels
- Use semantic HTML structure
- Announce progress changes
-
Keyboard Navigation
- Support tab navigation
- Provide keyboard shortcuts for common actions
- Handle focus management properly
-
Visual Accessibility
- Ensure sufficient color contrast
- Don't rely solely on color to convey information
- Support different font sizes
Testing
Unit Tests
import { render, screen } from '@testing-library/react';
import WPDotTimeline from 'components/Timeline/WpDotTimeline';
describe('WPDotTimeline', () => {
it('renders timeline options correctly', () => {
const options = [
{ title: 'Step 1', display: 'First step description' },
{ title: 'Step 2', display: 'Second step description' },
];
render(<WPDotTimeline options={options} />);
expect(screen.getByText('Step 1')).toBeInTheDocument();
expect(screen.getByText('First step description')).toBeInTheDocument();
expect(screen.getByText('Step 2')).toBeInTheDocument();
expect(screen.getByText('Second step description')).toBeInTheDocument();
});
it('renders custom icons when provided', () => {
const options = [
{
title: 'Step 1',
display: 'Description',
icon: <div data-testid='custom-icon'>Custom Icon</div>,
},
];
render(<WPDotTimeline options={options} />);
expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
});
});
Integration Tests
describe('FormStepper', () => {
it('navigates through steps correctly', async () => {
const { user } = render(<FormStepper />);
// Start at step 1
expect(screen.getByText('Personal profile')).toBeInTheDocument();
// Click next
await user.click(screen.getByText('Next'));
// Should be at step 2
expect(screen.getByText('Employment profile')).toBeInTheDocument();
// Click back
await user.click(screen.getByText('Back'));
// Should be back at step 1
expect(screen.getByText('Personal profile')).toBeInTheDocument();
});
it('validates form data before proceeding', async () => {
const { user } = render(<FormStepper />);
// Try to proceed without filling required fields
await user.click(screen.getByText('Next'));
// Should show validation errors
expect(screen.getByText('This field is required')).toBeInTheDocument();
});
});
Migration Guide
From Legacy Timeline Components
-
Update Import Paths
// Old
import Timeline from 'components/Timeline/OldTimeline';
// New
import WPDotTimeline from 'components/Timeline/WpDotTimeline'; -
Update Data Structure
// Old
const timelineData = {
events: [
{ name: 'Event 1', description: 'Description 1' },
{ name: 'Event 2', description: 'Description 2' },
],
};
// New
const timelineOptions = [
{ title: 'Event 1', display: 'Description 1' },
{ title: 'Event 2', display: 'Description 2' },
]; -
Update Component Usage
// Old
<Timeline data={timelineData} />
// New
<WPDotTimeline options={timelineOptions} />
From Basic Stepper to FormStepper
-
Wrap in Form Provider
// Old
<BasicStepper steps={steps} />
// New
<FormProvider {...methods}>
<FormStepper onSuccess={handleSuccess} />
</FormProvider> -
Update Step Configuration
// Old
const steps = ['Step 1', 'Step 2', 'Step 3'];
// New - Steps are now defined within the FormStepper component
// Configuration is handled internally -
Handle Form Submission
// Old
const handleSubmit = data => {
// Handle submission
};
// New
const handleSuccess = success => {
if (success) {
// Handle successful submission
}
};
Styling Customization
Timeline Connector Styling
// Custom timeline connector with different styling
const CustomTimelineConnector = styled(WPTimelineConnector)`
border-left: 2px dashed #62a446;
&::before {
content: '';
position: absolute;
top: 0;
left: -1px;
width: 2px;
height: 20px;
background: linear-gradient(to bottom, transparent, #62a446);
}
`;
Stepper Color Customization
const customStepperTheme = {
completed: {
bg: '#62a446',
color: 'white',
border: '#62a446',
},
active: {
bg: '#62a446',
color: 'white',
border: '#62a446',
},
inactive: {
bg: 'white',
color: '#62a446',
border: '#62a446',
},
};
Timeline Item Customization
const TimelineItem = ({ item, isCompleted }) => (
<VStack alignItems='flex-start' pl={4} position='relative'>
<Box
sx={{
width: '16px',
height: '16px',
borderRadius: '50%',
position: 'absolute',
top: 0,
left: '-8px',
bg: isCompleted ? 'green.500' : 'gray.300',
border: '2px solid white',
boxShadow: '0 0 0 2px',
boxShadowColor: isCompleted ? 'green.500' : 'gray.300',
}}
/>
<Text fontWeight='semibold' color={isCompleted ? 'green.700' : 'gray.600'}>
{item.title}
</Text>
<Text fontSize='sm' color='gray.600'>
{item.description}
</Text>
</VStack>
);