import type { FC } from 'react'; import { Box, Paper, styled, Typography } from '@mui/material'; import Timeline from '@mui/lab/Timeline'; import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem'; import TimelineSeparator from '@mui/lab/TimelineSeparator'; import TimelineDot from '@mui/lab/TimelineDot'; import TimelineConnector from '@mui/lab/TimelineConnector'; import TimelineContent from '@mui/lab/TimelineContent'; import type { ChangeRequestSchedule, ChangeRequestState, } from '../../changeRequest.types'; import { HtmlTooltip } from '../../../common/HtmlTooltip/HtmlTooltip'; import ErrorIcon from '@mui/icons-material/Error'; import { type ILocationSettings, useLocationSettings, } from 'hooks/useLocationSettings'; import { formatDateYMDHMS } from 'utils/formatDate'; export type ISuggestChangeTimelineProps = | { state: Exclude; schedule?: undefined; } | { state: 'Scheduled'; schedule: ChangeRequestSchedule; }; const StyledPaper = styled(Paper)(({ theme }) => ({ marginTop: theme.spacing(2), borderRadius: `${theme.shape.borderRadiusLarge}px`, })); const StyledBox = styled(Box)(({ theme }) => ({ padding: theme.spacing(2), marginBottom: `-${theme.spacing(4)}`, })); const StyledSubtitle = styled(Box)(({ theme }) => ({ display: 'flex', flexDirection: 'row', alignItems: 'flex-end', })); const StyledTimeline = styled(Timeline)(() => ({ [`& .${timelineItemClasses.root}:before`]: { flex: 0, padding: 0, }, })); const steps: ChangeRequestState[] = [ 'Draft', 'In review', 'Approved', 'Applied', ]; const rejectedSteps: ChangeRequestState[] = ['Draft', 'In review', 'Rejected']; const scheduledSteps: ChangeRequestState[] = [ 'Draft', 'In review', 'Approved', 'Scheduled', 'Applied', ]; export const determineColor = ( changeRequestState: ChangeRequestState, changeRequestStateIndex: number, displayStage: ChangeRequestState, displayStageIndex: number, ) => { if (changeRequestState === 'Cancelled') return 'grey'; if (changeRequestState === 'Rejected') return displayStage === 'Rejected' ? 'error' : 'success'; if ( changeRequestStateIndex !== -1 && changeRequestStateIndex >= displayStageIndex ) return 'success'; if (changeRequestStateIndex + 1 === displayStageIndex) return 'primary'; return 'grey'; }; export const ChangeRequestTimeline: FC = ({ state, schedule, }) => { let data: ChangeRequestState[]; switch (state) { case 'Rejected': data = rejectedSteps; break; case 'Scheduled': data = scheduledSteps; break; default: data = steps; } const activeIndex = data.findIndex((item) => item === state); const { locationSettings } = useLocationSettings(); return ( {data.map((title, index) => { if (schedule && title === 'Scheduled') { return createTimelineScheduleItem( schedule, locationSettings, ); } const color = determineColor( state, activeIndex, title, index, ); let timelineDotProps = {}; // Only add the outlined variant if it's the next step after the active one, but not for 'Draft' in 'Cancelled' state if ( activeIndex + 1 === index && !(state === 'Cancelled' && title === 'Draft') ) { timelineDotProps = { variant: 'outlined' }; } return createTimelineItem( color, title, index < data.length - 1, timelineDotProps, ); })} ); }; const createTimelineItem = ( color: 'primary' | 'success' | 'grey' | 'error' | 'warning', title: string, shouldConnectToNextItem: boolean, timelineDotProps: { [key: string]: string | undefined } = {}, ) => ( {shouldConnectToNextItem && } {title} ); export const getScheduleProps = ( schedule: ChangeRequestSchedule, formattedTime: string, ) => { switch (schedule.status) { case 'suspended': return { title: 'Schedule suspended', subtitle: `was ${formattedTime}`, color: 'grey' as const, reason: ( ), }; case 'failed': return { title: 'Schedule failed', subtitle: `at ${formattedTime}`, color: 'error' as const, reason: ( ), }; default: return { title: 'Scheduled', subtitle: `for ${formattedTime}`, color: 'warning' as const, reason: null, }; } }; const createTimelineScheduleItem = ( schedule: ChangeRequestSchedule, locationSettings: ILocationSettings, ) => { const time = formatDateYMDHMS( new Date(schedule.scheduledAt), locationSettings?.locale, ); const { title, subtitle, color, reason } = getScheduleProps(schedule, time); return ( {title} {`(${subtitle})`} {reason} ); };