Skip to content

Commit d6c13ba

Browse files
committed
feat(DGT-342): Coral Quality Bars
1 parent f4889d3 commit d6c13ba

19 files changed

+1129
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { render, screen } from '@testing-library/react';
3+
4+
import { QualityBar, QualityBarProps } from './QualityBar.component';
5+
6+
describe('QualityBar', () => {
7+
describe('QualityBar component in classic mode', () => {
8+
it('should render a quality bar', () => {
9+
// given
10+
const props: QualityBarProps = {
11+
valid: 523,
12+
invalid: 123,
13+
empty: 332,
14+
};
15+
16+
// when
17+
render(<QualityBar {...props} />);
18+
19+
// then
20+
expect(screen.getByTestId('quality-bar-valid')).toBeInTheDocument();
21+
expect(screen.getByTestId('quality-bar-invalid')).toBeInTheDocument();
22+
expect(screen.getByTestId('quality-bar-empty')).toBeInTheDocument();
23+
expect(screen.queryByTestId('quality-bar-na')).not.toBeInTheDocument();
24+
expect(screen.queryByTestId('quality-bar-placeholder')).not.toBeInTheDocument();
25+
});
26+
27+
it('should render quality bar with just na and placeholder', () => {
28+
// given
29+
const props: QualityBarProps = {
30+
na: 10,
31+
placeholder: 100,
32+
};
33+
34+
// when
35+
render(<QualityBar {...props} />);
36+
37+
// then
38+
expect(screen.queryByTestId('quality-bar-valid')).not.toBeInTheDocument();
39+
expect(screen.queryByTestId('quality-bar-invalid')).not.toBeInTheDocument();
40+
expect(screen.queryByTestId('quality-bar-empty')).not.toBeInTheDocument();
41+
expect(screen.getByTestId('quality-bar-na')).toBeInTheDocument();
42+
expect(screen.getByTestId('quality-bar-placeholder')).toBeInTheDocument();
43+
});
44+
45+
it('should render a quality bar in a disabled state', () => {
46+
// given
47+
const props: QualityBarProps = {
48+
valid: 523,
49+
invalid: 123,
50+
empty: 332,
51+
disabled: true,
52+
};
53+
54+
// when
55+
render(<QualityBar {...props} />);
56+
57+
// then
58+
expect(screen.queryByTestId('quality-bar-valid')).not.toBeInTheDocument();
59+
expect(screen.queryByTestId('quality-bar-invalid')).not.toBeInTheDocument();
60+
expect(screen.queryByTestId('quality-bar-empty')).not.toBeInTheDocument();
61+
expect(screen.queryByTestId('quality-bar-na')).not.toBeInTheDocument();
62+
expect(screen.getByTestId('quality-bar-placeholder')).toBeInTheDocument();
63+
});
64+
65+
it('should render an chart with action button', () => {
66+
// given
67+
const mockFunctionAction = jest.fn();
68+
const props = {
69+
valid: 523,
70+
invalid: 123,
71+
empty: 332,
72+
na: 100,
73+
onClick: mockFunctionAction,
74+
getDataFeature: (qualityType: string) => {
75+
return `data-feature-${qualityType}`;
76+
},
77+
};
78+
79+
// when
80+
render(<QualityBar {...props} />);
81+
screen.getAllByTestId('quality-bar-valid')[0].click();
82+
// then
83+
expect(mockFunctionAction).toHaveBeenCalledWith(expect.anything(), { type: 'valid' });
84+
});
85+
});
86+
87+
describe('QualityBar component in split mode', () => {
88+
it('should render quality bars with numbers', () => {
89+
// given
90+
const props: QualityBarProps = {
91+
valid: 15,
92+
invalid: 30,
93+
empty: 55,
94+
split: true,
95+
};
96+
97+
// when
98+
render(<QualityBar {...props} />);
99+
100+
// then
101+
expect(screen.getByText('15%', { collapseWhitespace: true })).toBeInTheDocument();
102+
expect(screen.getByTestId('quality-bar-valid')).toBeInTheDocument();
103+
expect(screen.getByText('30%', { collapseWhitespace: true })).toBeInTheDocument();
104+
expect(screen.getByTestId('quality-bar-invalid')).toBeInTheDocument();
105+
expect(screen.getByText('55%', { collapseWhitespace: true })).toBeInTheDocument();
106+
expect(screen.getByTestId('quality-bar-empty')).toBeInTheDocument();
107+
expect(screen.queryByTestId('quality-bar-na')).not.toBeInTheDocument();
108+
expect(screen.getAllByTestId('quality-bar-placeholder')).toHaveLength(3);
109+
});
110+
});
111+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { QualityCommonProps } from './QualityBar.types';
2+
import { QualityBarRatioBars } from './QualityBarRatioBars.component';
3+
import { getQualityPercentagesRounded } from './QualityRatioBar.utils';
4+
import { SplitQualityBar } from './SplitQualityBar.component';
5+
6+
export type QualityBarProps = QualityCommonProps & {
7+
digits?: number;
8+
split?: boolean;
9+
};
10+
11+
export const QualityBar = ({
12+
valid,
13+
invalid,
14+
empty,
15+
na,
16+
placeholder,
17+
digits = 1,
18+
split = false,
19+
...rest
20+
}: QualityBarProps) => {
21+
const percentages = getQualityPercentagesRounded(digits, invalid, empty, valid, na, placeholder);
22+
23+
return split ? (
24+
<SplitQualityBar
25+
valid={valid}
26+
invalid={invalid}
27+
empty={empty}
28+
na={na}
29+
percentages={percentages}
30+
{...rest}
31+
/>
32+
) : (
33+
<QualityBarRatioBars
34+
valid={valid}
35+
invalid={invalid}
36+
empty={empty}
37+
na={na}
38+
placeholder={placeholder}
39+
percentages={percentages}
40+
{...rest}
41+
/>
42+
);
43+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { action } from '@storybook/addon-actions';
2+
3+
import { QualityBar } from './QualityBar.component';
4+
5+
export default {
6+
title: 'Dataviz/QualityBar',
7+
};
8+
9+
export const _QualityBar = () => (
10+
<section style={{ maxWidth: 500, padding: 20 }}>
11+
<header>Quality Bar</header>
12+
13+
<div>
14+
<div>Homogeneous Quality</div>
15+
<QualityBar
16+
invalid={30}
17+
valid={30}
18+
empty={30}
19+
tooltipLabels={{
20+
empty: '30 empty values',
21+
invalid: '30 invalid values',
22+
valid: '30 valid values',
23+
}}
24+
/>
25+
26+
<div>Very invalid</div>
27+
<QualityBar
28+
invalid={30}
29+
valid={0}
30+
empty={0}
31+
tooltipLabels={{
32+
invalid: '30 invalid values',
33+
}}
34+
/>
35+
36+
<div>Not applicable</div>
37+
<QualityBar
38+
invalid={30}
39+
valid={0}
40+
empty={0}
41+
na={20}
42+
tooltipLabels={{
43+
invalid: '30 invalid values',
44+
na: '20 not applicable values',
45+
}}
46+
/>
47+
48+
<div>Best quality ever</div>
49+
<QualityBar
50+
invalid={0}
51+
valid={30}
52+
empty={0}
53+
tooltipLabels={{
54+
valid: '30 valid values',
55+
}}
56+
/>
57+
58+
<div>Nothing to see here</div>
59+
<QualityBar
60+
invalid={0}
61+
valid={0}
62+
empty={30}
63+
tooltipLabels={{
64+
empty: '30 empty values',
65+
}}
66+
/>
67+
68+
<div>Invalid and Empty</div>
69+
<QualityBar
70+
invalid={0}
71+
valid={30}
72+
empty={30}
73+
tooltipLabels={{
74+
empty: '30 empty values',
75+
valid: '30 valid values',
76+
}}
77+
/>
78+
79+
<div>Classic look</div>
80+
<QualityBar
81+
invalid={2}
82+
valid={88}
83+
empty={3}
84+
tooltipLabels={{
85+
empty: '3 empty values',
86+
invalid: '2 invalid values',
87+
valid: '88 valid values',
88+
}}
89+
/>
90+
91+
<div>Classic look (again yep)</div>
92+
<QualityBar
93+
invalid={122}
94+
valid={1088}
95+
empty={293}
96+
tooltipLabels={{
97+
empty: '293 empty values',
98+
invalid: '122 invalid values',
99+
valid: '1088 valid values',
100+
}}
101+
/>
102+
103+
<div>I really like the digits !</div>
104+
<QualityBar
105+
invalid={30}
106+
valid={30}
107+
empty={30}
108+
digits={5}
109+
tooltipLabels={{
110+
empty: '30 empty values',
111+
invalid: '30 invalid values',
112+
valid: '30 valid values',
113+
}}
114+
/>
115+
116+
<div>With a placeholder</div>
117+
<QualityBar
118+
invalid={30}
119+
valid={0}
120+
empty={0}
121+
placeholder={70}
122+
tooltipLabels={{
123+
invalid: '30 invalid values',
124+
}}
125+
/>
126+
127+
<div>Disabled</div>
128+
<QualityBar invalid={30} valid={0} empty={0} placeholder={70} disabled />
129+
130+
<div>Classic look with action button</div>
131+
<QualityBar
132+
invalid={2}
133+
valid={88}
134+
empty={3}
135+
onClick={action('onClickAction')}
136+
getDataFeature={qualityType => `data-feature.${qualityType}`}
137+
tooltipLabels={{
138+
empty: '3 empty values',
139+
invalid: '2 invalid values',
140+
valid: '88 valid values',
141+
}}
142+
/>
143+
</div>
144+
</section>
145+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import type { MouseEvent } from 'react';
2+
3+
export enum QualityType {
4+
VALID = 'valid',
5+
INVALID = 'invalid',
6+
EMPTY = 'empty',
7+
NA = 'na',
8+
}
9+
10+
export type EnrichedQualityType = QualityType | 'placeholder';
11+
12+
export type QualityTypeValues = {
13+
valid?: number;
14+
invalid?: number;
15+
empty?: number;
16+
na?: number;
17+
};
18+
19+
export type QualityBarPercentages = Required<QualityTypeValues> & {
20+
placeholder: number;
21+
};
22+
23+
export type QualityCommonProps = QualityTypeValues & {
24+
disabled?: boolean;
25+
getDataFeature?: (type: string) => string;
26+
onClick?: (e: MouseEvent<HTMLElement>, data: { type: EnrichedQualityType }) => void;
27+
placeholder?: number;
28+
tooltipLabels?: QualityBarTooltips;
29+
};
30+
31+
export type QualityBarTooltips = {
32+
empty?: string;
33+
invalid?: string;
34+
na?: string;
35+
valid?: string;
36+
};

0 commit comments

Comments
 (0)