Skip to content

Commit dd9189a

Browse files
Add date format to FormattedDateTime component
Update formatDate fn update tests for various date formats.
1 parent f5e254f commit dd9189a

File tree

5 files changed

+160
-49
lines changed

5 files changed

+160
-49
lines changed

src/lib/components/barchartv2/Barchart.component.test.tsx

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { render, screen, waitFor } from '@testing-library/react';
22
import { getWrapper } from '../../testUtils';
3-
import { Barchart } from './Barchart.component';
3+
import { Barchart, CustomTick, formatDate } from './Barchart.component';
44
import { ChartLegendWrapper } from '../chartlegend/ChartLegendWrapper';
5+
import React from 'react';
56

67
const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
78
const ONE_HOUR_IN_MILLISECONDS = 60 * 60 * 1000;
@@ -384,4 +385,101 @@ describe('Barchart', () => {
384385
expect(screen.getByText('Test Right Title')).toBeInTheDocument();
385386
expect(screen.getByLabelText('Info')).toBeInTheDocument();
386387
});
388+
describe('formatDate', () => {
389+
it('should render the CustomTick component with over a day interval', () => {
390+
const { Wrapper } = getWrapper();
391+
render(
392+
<Wrapper>
393+
<CustomTick
394+
type={{
395+
type: 'time',
396+
timeRange: {
397+
startDate: new Date('2024-07-05'),
398+
endDate: new Date('2024-07-07'),
399+
interval: 2 * ONE_DAY_IN_MILLISECONDS,
400+
},
401+
}}
402+
x={100}
403+
y={100}
404+
payload={{ value: new Date('2024-07-05T10:00:00').getTime() }}
405+
visibleTicksCount={10}
406+
width={100}
407+
/>
408+
</Wrapper>,
409+
);
410+
expect(screen.getByText('Fri05Jul 10:00')).toBeInTheDocument();
411+
});
412+
413+
it('should render the CustomTick component with day format', () => {
414+
const { Wrapper } = getWrapper();
415+
render(
416+
<Wrapper>
417+
<CustomTick
418+
type={{
419+
type: 'time',
420+
timeRange: {
421+
startDate: new Date('2024-07-05'),
422+
endDate: new Date('2024-07-07'),
423+
interval: ONE_DAY_IN_MILLISECONDS,
424+
},
425+
}}
426+
x={100}
427+
y={100}
428+
payload={{ value: new Date('2024-07-05T10:00:00').getTime() }}
429+
visibleTicksCount={10}
430+
width={100}
431+
/>
432+
</Wrapper>,
433+
);
434+
expect(screen.getByText('Fri05Jul')).toBeInTheDocument();
435+
});
436+
it('should render the CustomTick component with hour format', () => {
437+
const { Wrapper } = getWrapper();
438+
render(
439+
<Wrapper>
440+
<CustomTick
441+
type={{
442+
type: 'time',
443+
timeRange: {
444+
startDate: new Date('2024-07-05'),
445+
endDate: new Date('2024-07-07'),
446+
interval: ONE_HOUR_IN_MILLISECONDS,
447+
},
448+
}}
449+
x={100}
450+
y={100}
451+
payload={{ value: new Date('2024-07-05T10:00:00').getTime() }}
452+
visibleTicksCount={10}
453+
width={100}
454+
/>
455+
</Wrapper>,
456+
);
457+
expect(screen.getByText('10:00')).toBeInTheDocument();
458+
});
459+
it('should render the CustomTick component with minute format', () => {
460+
const { Wrapper } = getWrapper();
461+
render(
462+
<Wrapper>
463+
<CustomTick
464+
type={{
465+
type: 'time',
466+
timeRange: {
467+
startDate: new Date('2024-07-05'),
468+
endDate: new Date('2024-07-07'),
469+
interval: 1000 * 30,
470+
},
471+
}}
472+
x={100}
473+
y={100}
474+
payload={{ value: new Date('2024-07-05T10:00:00').getTime() }}
475+
visibleTicksCount={10}
476+
width={100}
477+
/>
478+
</Wrapper>,
479+
);
480+
expect(
481+
screen.getByText(new Date('2024-07-05T10:00:00').getTime()),
482+
).toBeInTheDocument();
483+
});
484+
});
387485
});

src/lib/components/barchartv2/Barchart.component.tsx

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@ import { ConstrainedText } from '../constrainedtext/Constrainedtext.component';
1818
import { IconHelp } from '../iconhelper/IconHelper';
1919
import { Loader } from '../loader/Loader.component';
2020
import { Text } from '../text/Text.component';
21-
import {
22-
formatDate,
23-
renderTooltipContent,
24-
UnitRange,
25-
useChartData,
26-
} from './utils';
21+
import { renderTooltipContent, UnitRange, useChartData } from './utils';
2722
import { useChartLegend } from '../chartlegend/ChartLegendWrapper';
23+
import { FormattedDateTime } from '../date/FormattedDateTime';
2824

2925
const CHART_CONSTANTS = {
3026
TICK_WIDTH_OFFSET: 5,
@@ -100,7 +96,7 @@ interface CustomTickProps {
10096
x: number;
10197
y: number;
10298
payload: {
103-
value: string | number;
99+
value: number;
104100
};
105101
visibleTicksCount: number;
106102
width: number;
@@ -109,7 +105,38 @@ interface CustomTickProps {
109105

110106
/* ---------------------------------- COMPONENTS ---------------------------------- */
111107

112-
const CustomTick = ({
108+
/**
109+
* Formats a date based on the interval
110+
* @param timestamp - Timestamp
111+
* @param interval - Interval in milliseconds
112+
* @returns Formatted string
113+
*/
114+
export const formatDate = (
115+
timestamp: number,
116+
interval: number,
117+
): React.ReactNode => {
118+
const date = new Date(timestamp);
119+
// More than 24 hours interval - use day and time format
120+
if (interval > 24 * 60 * 60 * 1000) {
121+
return (
122+
<>
123+
<FormattedDateTime format="chart-date" value={date} />{' '}
124+
<FormattedDateTime format="time" value={date} />
125+
</>
126+
);
127+
} else if (interval === 24 * 60 * 60 * 1000) {
128+
// Daily interval - use day format
129+
return <FormattedDateTime format="chart-date" value={date} />;
130+
} else if (interval >= 60 * 1000) {
131+
//Hourly and minute intervals - use minute format
132+
return <FormattedDateTime format="time" value={date} />;
133+
} else {
134+
// minute interval or less - use full timestamp
135+
return timestamp;
136+
}
137+
};
138+
139+
export const CustomTick = ({
113140
x,
114141
y,
115142
payload,
@@ -135,7 +162,7 @@ const CustomTick = ({
135162
text={
136163
<Text variant="Smaller">
137164
{type.type === 'time'
138-
? formatDate(new Date(payload.value), type.timeRange.interval)
165+
? formatDate(payload.value, type.timeRange.interval)
139166
: String(payload.value)}
140167
</Text>
141168
}

src/lib/components/barchartv2/ChartTooltip.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Text } from '../text/Text.component';
44
import { BarchartBars } from './Barchart.component';
55
import { fontSize, fontWeight } from '../../style/theme';
66
import { LegendShape } from '../chartlegend/ChartLegend';
7+
import { FormattedDateTime } from '../date/FormattedDateTime';
78

89
export const ChartTooltipContainer = styled.div`
910
background-color: ${({ theme }) => theme.backgroundLevel1};
@@ -42,14 +43,14 @@ export const ChartTooltip = <T extends BarchartBars>({
4243
return (
4344
<ChartTooltipContainer>
4445
<Text isEmphazed>
45-
{type === 'time'
46-
? new Date(currentPoint.category).toLocaleDateString('en-GB', {
47-
weekday: 'long',
48-
year: 'numeric',
49-
month: 'long',
50-
day: 'numeric',
51-
})
52-
: currentPoint.category}
46+
{type === 'time' ? (
47+
<FormattedDateTime
48+
format="long-date"
49+
value={new Date(currentPoint.category)}
50+
/>
51+
) : (
52+
currentPoint.category
53+
)}
5354
</Text>
5455
<Stack direction="vertical" gap="r8" style={{ width: '100%' }}>
5556
{currentPoint.values.map((value) => {

src/lib/components/barchartv2/utils.ts

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
BarchartBars,
44
BarchartTooltipFn,
55
} from './Barchart.component';
6-
import { DAY_MONTH_FORMATER, TIME_FORMATER } from '../date/FormattedDateTime';
76
import { TooltipContentProps } from 'recharts';
87
import { chartColors, ChartColors } from '../../style/theme';
98
import { useChartLegend } from '../chartlegend/ChartLegendWrapper';
@@ -84,31 +83,6 @@ const generateTimeRanges = (
8483
return ranges;
8584
};
8685

87-
/**
88-
* Formats a date based on the interval
89-
* @param date - Date object
90-
* @param interval - Interval in milliseconds
91-
* @returns Formatted string
92-
*/
93-
export const formatDate = (date: Date, interval: number): string => {
94-
if (interval > 24 * 60 * 60 * 1000) {
95-
return (
96-
DAY_MONTH_FORMATER.format(date).replace(/[ ,]/g, '') +
97-
' ' +
98-
TIME_FORMATER.format(date)
99-
);
100-
} else if (interval === 24 * 60 * 60 * 1000) {
101-
// Daily or longer intervals - use day format
102-
return DAY_MONTH_FORMATER.format(date).replace(/[ ,]/g, '');
103-
} else if (interval >= 60 * 1000) {
104-
//Handle hourly and minute intervals - use minute format
105-
return TIME_FORMATER.format(date);
106-
} else {
107-
// Second intervals or less - use full timestamp
108-
return date.toISOString();
109-
}
110-
};
111-
11286
/**
11387
* Finds the time range that contains the given date
11488
* @param date - Data point date
@@ -149,10 +123,7 @@ export const transformTimeData = <T extends BarchartBars>(
149123
type.timeRange.interval,
150124
);
151125

152-
const categoryMap = new Map<
153-
string | number,
154-
{ [key: string]: string | number }
155-
>();
126+
const categoryMap = new Map<number, { [key: string]: string | number }>();
156127

157128
// Initialize all ranges with zeros
158129
timeRanges.forEach((range) => {

src/lib/components/date/FormattedDateTime.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { getDateDaysDiff } from './dateDiffer';
22
import { Tooltip } from '../tooltip/Tooltip.component';
33

4+
export const LONG_DATE_FORMATER = Intl.DateTimeFormat('en-GB', {
5+
weekday: 'long',
6+
year: 'numeric',
7+
month: 'long',
8+
day: 'numeric',
9+
});
10+
411
export const DATE_FORMATER = Intl.DateTimeFormat('fr-CA', {
512
year: 'numeric',
613
month: '2-digit',
@@ -56,7 +63,10 @@ type FormattedDateTimeProps = {
5663
| 'time-second'
5764
| 'relative'
5865
| 'day-month-abbreviated-hour-minute'
59-
| 'day-month-abbreviated-hour-minute-second';
66+
| 'day-month-abbreviated-hour-minute-second'
67+
| 'long-date'
68+
| 'chart-date';
69+
6070
value: Date;
6171
};
6272

@@ -184,6 +194,10 @@ export const FormattedDateTime = ({
184194
)}
185195
</>
186196
);
197+
case 'long-date':
198+
return <>{LONG_DATE_FORMATER.format(value)}</>;
199+
case 'chart-date':
200+
return <>{DAY_MONTH_FORMATER.format(value).replace(/[ ,]/g, '')}</>;
187201
default:
188202
return <></>;
189203
}

0 commit comments

Comments
 (0)