From ca128cc7f68a9e6d5a8d1e4d1db525330d418b10 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 22 Jul 2025 14:01:56 +0200 Subject: [PATCH] Show change request stage timestamps in UI Respects user's locale, uses `time` element. Does not address potential collisions with scheduled change requests, which have additional time information. --- .../ChangeRequestOverview.tsx | 8 +- .../ChangeRequestTimeline.tsx | 129 ++++++++++++------ 2 files changed, 93 insertions(+), 44 deletions(-) diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx index 09a613f6ce..c85d941596 100644 --- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx +++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx @@ -349,7 +349,13 @@ export const ChangeRequestOverview: FC = () => { - + ; +} & ( | { state: Exclude; schedule?: undefined; @@ -26,7 +26,8 @@ export type ISuggestChangeTimelineProps = | { state: 'Scheduled'; schedule: ChangeRequestSchedule; - }; + } +); const StyledPaper = styled(Paper)(({ theme }) => ({ marginTop: theme.spacing(2), @@ -89,6 +90,7 @@ export const determineColor = ( export const ChangeRequestTimeline: FC = ({ state, schedule, + timestamps, }) => { let data: ChangeRequestState[]; switch (state) { @@ -109,10 +111,17 @@ export const ChangeRequestTimeline: FC = ({ {data.map((title, index) => { + const timestampComponent = timestamps?.[title] ? ( + + ) : undefined; + if (schedule && title === 'Scheduled') { - return createTimelineScheduleItem( - schedule, - locationSettings, + return ( + ); } @@ -132,11 +141,17 @@ export const ChangeRequestTimeline: FC = ({ timelineDotProps = { variant: 'outlined' }; } - return createTimelineItem( - color, - title, - index < data.length - 1, - timelineDotProps, + return ( + ); })} @@ -145,24 +160,53 @@ export const ChangeRequestTimeline: FC = ({ ); }; -const createTimelineItem = ( - color: 'primary' | 'success' | 'grey' | 'error' | 'warning', - title: string, - shouldConnectToNextItem: boolean, - timelineDotProps: { [key: string]: string | undefined } = {}, -) => ( - - - - {shouldConnectToNextItem && } - - {title} - -); +const Timestamp = styled(({ timestamp, ...props }: { timestamp: string }) => { + const { locationSettings } = useLocationSettings(); + const displayTime = formatDateYMDHM( + new Date(timestamp || ''), + locationSettings.locale, + ); + return ( + + ); +})(({ theme }) => ({ + color: theme.palette.text.secondary, + fontSize: theme.typography.body2.fontSize, + display: 'block', +})); + +const TimelineItem = ({ + color, + title, + shouldConnectToNextItem, + timestamp, + timelineDotProps = {}, +}: { + color: 'primary' | 'success' | 'grey' | 'error' | 'warning'; + title: string; + shouldConnectToNextItem: boolean; + timestamp?: ReactNode; + timelineDotProps: { [key: string]: string | undefined }; +}) => { + return ( + + + + {shouldConnectToNextItem && } + + + {title} + {timestamp} + + + ); +}; export const getScheduleProps = ( schedule: ChangeRequestSchedule, - formattedTime: string, + formattedTime: string = '2025/09/22 12:27', ) => { switch (schedule.status) { case 'suspended': @@ -202,25 +246,24 @@ export const getScheduleProps = ( } }; -const createTimelineScheduleItem = ( - schedule: ChangeRequestSchedule, - locationSettings: ILocationSettings, -) => { - const time = formatDateYMDHMS( - new Date(schedule.scheduledAt), - locationSettings?.locale, - ); - - const { title, subtitle, color, reason } = getScheduleProps(schedule, time); +const TimelineScheduleItem = ({ + schedule, + timestamp, +}: { + schedule: ChangeRequestSchedule; + timestamp: ReactNode; +}) => { + const { title, subtitle, color, reason } = getScheduleProps(schedule); return ( - + {title} + {timestamp} - + ); };