import { 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 { ChangeRequestSchedule, ChangeRequestState, } from '../../changeRequest.types'; import { ConditionallyRender } from '../../../common/ConditionallyRender/ConditionallyRender'; import { HtmlTooltip } from '../../../common/HtmlTooltip/HtmlTooltip'; import { Error as ErrorIcon } from '@mui/icons-material'; import { useLocationSettings } from 'hooks/useLocationSettings'; import { formatDateYMDHMS } from 'utils/formatDate'; 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 && changeRequestStateIndex === displayStageIndex ) { return changeRequestState === 'Scheduled' ? failureReason ? 'error' : 'warning' : 'success'; } if (changeRequestStateIndex + 1 === displayStageIndex) return 'primary'; return 'grey'; }; export const ChangeRequestTimeline: FC = ({ state, schedule, }) => { let data; switch (state) { case 'Rejected': data = rejectedSteps; break; case 'Scheduled': data = scheduledSteps; break; default: data = steps; } const activeIndex = data.findIndex((item) => item === state); return ( {data.map((title, index) => { if (schedule && title === 'Scheduled') { return createTimelineScheduleItem(schedule); } 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 createTimelineScheduleItem = (schedule: ChangeRequestSchedule) => { const { locationSettings } = useLocationSettings(); const time = formatDateYMDHMS( new Date(schedule.scheduledAt), locationSettings?.locale, ); const color = (() => { switch (schedule.status) { case 'suspended': return 'grey'; case 'failed': return 'error'; case 'pending': default: return 'warning'; } })(); const title = `Schedule ${schedule.status}`; const subtitle = (() => { switch (schedule.status) { case 'suspended': return `was ${time}`; case 'failed': return `at ${time}`; case 'pending': default: return `for ${time}`; } })(); const reason = (() => { switch (schedule.status) { case 'suspended': return ( ); case 'failed': return ( ); case 'pending': default: return <>; } })(); return ( {title} {`(${subtitle})`} {reason} ); }; const createTimelineItem = ( color: 'primary' | 'success' | 'grey' | 'error' | 'warning', title: string, shouldConnectToNextItem: boolean, timelineDotProps: { [key: string]: string | undefined } = {}, ) => ( {shouldConnectToNextItem && } {title} );