diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/helpers/timeline.headers.helper.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/helpers/timeline.headers.helper.js new file mode 100644 index 0000000000000000000000000000000000000000..940237d5c4958be3a7a049630a07380b35773156 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/helpers/timeline.headers.helper.js @@ -0,0 +1,67 @@ +import React from "react"; + +// parameters 'getIntervalProps, intervalContext' are mandatory for the library +/** + * Shifts the header intervals for the LST time header + * Library's documentation about date header renderers: https://github.com/namespace-ee/react-calendar-timeline#dateheader + * @param getIntervalProps mandatory by library + * @param intervalContext + * @param lstShiftInSeconds based on the visible start time of the Timeline in utc, the corresponding lst time is retrieved + * and the approximate shift between the two is calculated for the header intervals. It is not a 100% correct, but close enough + * @return {JSX.Element} + */ +export function getIntervalRendererLST({getIntervalProps, intervalContext, lstShiftInSeconds}) { + let lstTime = "-" + + if (lstShiftInSeconds !== undefined) { + lstTime = intervalContext?.interval?.startTime?.add(lstShiftInSeconds, 'seconds') + if (lstTime === undefined) { + console.error("Interval error in library") + lstTime = "X" + } else { + lstTime = lstTime.format("HH:mm") + } + } + + return <div {...getIntervalProps()} className="rct-dateHeader" style={getIntervalProps().style} + data-testid={"dateheader-lst-" + lstTime}> + {lstTime} + </div>; +} + +export function getUnit(duration) { + if (duration < 4) { + return "minute" + } else { + return "hour" + } +} + +/** + * The Timeline library takes this timeSteps object as a property to display the columns nicely (including the header). + * This function makes sure that it changes accordingly to the visible start- and endtime in the Timeline + * @param durationInHours based on this duration, the header time steps should change + * @return {{hour: number, month: number, year: number, day: number, second: number, minute: number}} + */ +export function getTimeSteps(durationInHours) { + let timeSteps = { + second: 15, + minute: 5, + hour: 0.5, + day: 1, + month: 1, + year: 1 + }; + + if (durationInHours <= 0.5) { + timeSteps.minute = 1 + } else if (durationInHours < 2) { + timeSteps.minute = 5 + } else if (durationInHours < 4) { + timeSteps.minute = 10 + } else if (durationInHours > 12) { + timeSteps.hour = 1 + } + + return timeSteps +} \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/helpers/timeline.headers.helper.test.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/helpers/timeline.headers.helper.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f2c8318071c634d3431b6104ef4e80223d2d01f4 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/helpers/timeline.headers.helper.test.js @@ -0,0 +1,113 @@ +import {getIntervalRendererLST, getTimeSteps, getUnit} from "./timeline.headers.helper"; +import {render} from "@testing-library/react"; +import {removeReact18ConsoleErrors} from "../../../utils/test.helper"; + +removeReact18ConsoleErrors() + +describe('getTimeSteps', () => { + test.each([1.5, 12, undefined])('should return default timesteps when duration is: %s', (duration) => { + const result = getTimeSteps(duration); + expect(result).toEqual({ + second: 15, + minute: 5, + hour: 0.5, + day: 1, + month: 1, + year: 1 + }); + }) + + it('should return correct time steps when duration is less than or equal to 0.5 hours', () => { + const result = getTimeSteps(0.5); + expect(result).toEqual({ + second: 15, + minute: 1, + hour: 0.5, + day: 1, + month: 1, + year: 1 + }); + }); + + it('should return correct time steps when duration is greater than or equal to 2 hours and less than 4 hours', () => { + const result = getTimeSteps(3); + expect(result).toEqual({ + second: 15, + minute: 10, + hour: 0.5, + day: 1, + month: 1, + year: 1 + }); + }); + + it('should return correct time steps when duration is greater than 4 hours and less than 12 hours', () => { + const result = getTimeSteps(8); + expect(result).toEqual({ + second: 15, + minute: 5, + hour: 0.5, + day: 1, + month: 1, + year: 1 + }); + }); +}); + + +describe('getUnit', () => { + it('should return "minute" when duration is less than 4', () => { + const result = getUnit(3); + expect(result).toBe('minute'); + }); + + test.each([4, 5, undefined])('should return "hour" when duration is: %s', (duration) => { + const result = getUnit(duration); + expect(result).toBe('hour'); + }) +}); + +describe('getIntervalRendererLST', () => { + it('should render "-" when lstShiftInSeconds is undefined', () => { + const intervalProps = { + getIntervalProps: jest.fn(() => ({})), + intervalContext: {interval: {startTime: {add: jest.fn()}}}, + lstShiftInSeconds: undefined + }; + + const content = render(getIntervalRendererLST({...intervalProps})) + + expect(content.getByTestId("dateheader-lst--")).toBeInTheDocument() + }); + + it('should render formatted time when lstShiftInSeconds is defined', () => { + const mockedAdd = jest.fn().mockReturnValue({format: jest.fn().mockReturnValue('12:34')}); + const intervalProps = { + getIntervalProps: jest.fn(() => ({})), + intervalContext: {interval: {startTime: {add: mockedAdd}}}, + lstShiftInSeconds: 3600 + }; + + const content = render(getIntervalRendererLST({...intervalProps})) + + expect(content.getByTestId("dateheader-lst-12:34")).toBeInTheDocument() + expect(mockedAdd).toHaveBeenCalledWith(3600, 'seconds'); + }); + it('should render formatted time when intervalContext is empty', () => { + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { + }); + + const intervalProps = { + getIntervalProps: jest.fn(() => ({})), + intervalContext: undefined, + lstShiftInSeconds: 1337 + }; + + const content = render(getIntervalRendererLST({...intervalProps})) + expect(content.getByTestId("dateheader-lst-X")).toBeInTheDocument() + + expect(consoleErrorSpy).toHaveBeenCalledWith("Interval error in library"); + consoleErrorSpy.mockRestore(); + }); + +}); \ No newline at end of file