@aarhus-university/au-lib-react-components 10.8.0 → 10.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,142 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import React from 'react';
3
+ import { render } from '@testing-library/react';
4
+ import { SerializedError } from '@reduxjs/toolkit';
5
+ import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query';
6
+ // import userEvent from '@testing-library/user-event';
7
+ import '@testing-library/jest-dom';
8
+ import AUErrorComponent from '../../src/components/AUErrorComponent';
9
+
10
+ const auError: AU.IError = {
11
+ header: 'Our own custom error',
12
+ message: 'With a nice header and descriptive error message',
13
+ status: 500,
14
+ };
15
+
16
+ const fetchError1: FetchBaseQueryError = {
17
+ status: 'FETCH_ERROR',
18
+ error: 'Sum Ting Wong',
19
+ };
20
+
21
+ const fetchError2: FetchBaseQueryError = {
22
+ status: 500,
23
+ data: {
24
+ status: 'Error',
25
+ message: 'Sum Ting Wong',
26
+ },
27
+ };
28
+
29
+ const serializedError: SerializedError = {
30
+ code: '500',
31
+ message: 'Sum Ting Wong',
32
+ name: 'Some kind of error',
33
+ stack: 'Some kind of stack trace',
34
+ };
35
+
36
+ describe('<AUErrorComponent />', () => {
37
+ it('renders an AU custom error without a status code', () => {
38
+ const { container } = render(
39
+ <AUErrorComponent
40
+ error={auError}
41
+ />,
42
+ );
43
+
44
+ const header = container.querySelector('.notification__header');
45
+ const p = container.querySelector('.notification__content p');
46
+ expect(header).toBeInTheDocument();
47
+ expect(p?.innerHTML).toBe(auError.message);
48
+ });
49
+
50
+ it('renders an AU custom error with a status code', () => {
51
+ const { container } = render(
52
+ <AUErrorComponent
53
+ error={auError}
54
+ withStatus
55
+ />,
56
+ );
57
+
58
+ const header = container.querySelector('.notification__header');
59
+ expect(header?.innerHTML).toBe(`${auError.status}: ${auError.header}`);
60
+ });
61
+
62
+ it('renders a fetch error without a status code', () => {
63
+ const { container } = render(
64
+ <AUErrorComponent
65
+ fetchError={fetchError1}
66
+ />,
67
+ );
68
+
69
+ const header = container.querySelector('.notification__header');
70
+ const p = container.querySelector('.notification__content p');
71
+ expect(header).toBe(null);
72
+ expect(p?.innerHTML).toBe(fetchError1.error);
73
+ });
74
+
75
+ it('renders a fetch error with a status code', () => {
76
+ const { container } = render(
77
+ <AUErrorComponent
78
+ fetchError={fetchError1}
79
+ withStatus
80
+ />,
81
+ );
82
+
83
+ const header = container.querySelector('.notification__header');
84
+ const p = container.querySelector('.notification__content p');
85
+ expect(header?.innerHTML).toBe(fetchError1.status);
86
+ expect(p?.innerHTML).toBe(fetchError1.error);
87
+ });
88
+
89
+ it('renders a fetch error with stringified text without a status code', () => {
90
+ const { container } = render(
91
+ <AUErrorComponent
92
+ fetchError={fetchError2}
93
+ />,
94
+ );
95
+
96
+ const header = container.querySelector('.notification__header');
97
+ const p = container.querySelector('.notification__content p');
98
+ expect(header).toBe(null);
99
+ expect(p?.innerHTML).toBe(JSON.stringify(fetchError2.data));
100
+ });
101
+
102
+ it('renders a fetch error with stringified text with a status code', () => {
103
+ const { container } = render(
104
+ <AUErrorComponent
105
+ fetchError={fetchError2}
106
+ withStatus
107
+ />,
108
+ );
109
+
110
+ const header = container.querySelector('.notification__header');
111
+ const p = container.querySelector('.notification__content p');
112
+ expect(header?.innerHTML).toBe(`${fetchError2.status}`);
113
+ expect(p?.innerHTML).toBe(JSON.stringify(fetchError2.data));
114
+ });
115
+
116
+ it('renders a serialized error with without a status code', () => {
117
+ const { container } = render(
118
+ <AUErrorComponent
119
+ serializedError={serializedError}
120
+ />,
121
+ );
122
+
123
+ const header = container.querySelector('.notification__header');
124
+ const p = container.querySelector('.notification__content p');
125
+ expect(header).toBe(null);
126
+ expect(p?.innerHTML).toBe(serializedError.message);
127
+ });
128
+
129
+ it('renders a serialized error with a status code', () => {
130
+ const { container } = render(
131
+ <AUErrorComponent
132
+ serializedError={serializedError}
133
+ withStatus
134
+ />,
135
+ );
136
+
137
+ const header = container.querySelector('.notification__header');
138
+ const p = container.querySelector('.notification__content p');
139
+ expect(header?.innerHTML).toBe(serializedError.code);
140
+ expect(p?.innerHTML).toBe(serializedError.message);
141
+ });
142
+ });
@@ -6,7 +6,7 @@ import '@testing-library/jest-dom';
6
6
  import AUNotificationComponent from '../../src/components/AUNotificationComponent';
7
7
  import AUButtonComponent from '../../src/components/AUButtonComponent';
8
8
 
9
- describe('<AUNotification />', () => {
9
+ describe('<AUNotificationComponent />', () => {
10
10
  it('renders a notification without a header but with a paragraph', () => {
11
11
  const { container } = render(
12
12
  <AUNotificationComponent
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "sideEffects": false,
3
3
  "name": "@aarhus-university/au-lib-react-components",
4
- "version": "10.8.0",
4
+ "version": "10.9.0",
5
5
  "description": "Library for shared React components for various applications on au.dk",
6
6
  "scripts": {
7
7
  "test": "jest",
@@ -69,7 +69,8 @@
69
69
  },
70
70
  "dependencies": {
71
71
  "@aarhus-university/au-designsystem-delphinus": "0.29.0",
72
- "@aarhus-university/types": "^0.4.0",
72
+ "@aarhus-university/types": "^0.5.0",
73
+ "@reduxjs/toolkit": "^1.8.3",
73
74
  "@types/google.analytics": "^0.0.42",
74
75
  "@types/history": "^5.0.0",
75
76
  "@types/react": "^18.0.14",
@@ -0,0 +1,78 @@
1
+ import React, { FC } from 'react';
2
+ import { SerializedError } from '@reduxjs/toolkit';
3
+ import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
4
+ import AUNotificationComponent from './AUNotificationComponent';
5
+
6
+ interface AUErrorComponentProps {
7
+ error?: AU.IError,
8
+ fetchError?: FetchBaseQueryError,
9
+ serializedError?: SerializedError,
10
+ withStatus?: boolean,
11
+ }
12
+
13
+ const AUErrorComponent: FC<AUErrorComponentProps> = ({
14
+ error: auError,
15
+ fetchError,
16
+ serializedError,
17
+ withStatus,
18
+ }: AUErrorComponentProps) => {
19
+ if (auError) {
20
+ const { status, header, message } = auError;
21
+ return (
22
+ <AUNotificationComponent
23
+ type="warning"
24
+ header={`${withStatus ? `${status}: ` : ''}${header}`}
25
+ content={[
26
+ <p>{message}</p>,
27
+ ]}
28
+ />
29
+ );
30
+ }
31
+ if (fetchError && 'error' in fetchError) {
32
+ const { status, error } = fetchError;
33
+ return (
34
+ <AUNotificationComponent
35
+ type="warning"
36
+ header={withStatus ? status : undefined}
37
+ content={[
38
+ <p>{error}</p>,
39
+ ]}
40
+ />
41
+ );
42
+ }
43
+ if (fetchError && 'data' in fetchError) {
44
+ const { status, data } = fetchError;
45
+ return (
46
+ <AUNotificationComponent
47
+ type="warning"
48
+ header={withStatus ? `${status}` : undefined}
49
+ content={[
50
+ <p>{JSON.stringify(data)}</p>,
51
+ ]}
52
+ />
53
+ );
54
+ }
55
+ if (serializedError && 'message' in serializedError) {
56
+ const { code, message } = serializedError;
57
+ return (
58
+ <AUNotificationComponent
59
+ type="warning"
60
+ header={withStatus ? code : undefined}
61
+ content={[
62
+ <p>{message}</p>,
63
+ ]}
64
+ />
65
+ );
66
+ }
67
+ return null;
68
+ };
69
+
70
+ AUErrorComponent.defaultProps = {
71
+ error: undefined,
72
+ fetchError: undefined,
73
+ serializedError: undefined,
74
+ withStatus: false,
75
+ };
76
+
77
+ AUErrorComponent.displayName = 'AUErrorComponent';
78
+ export default AUErrorComponent;
@@ -1,12 +1,12 @@
1
1
  import React, { FC } from 'react';
2
2
 
3
- const AUNotificationsComponent: FC<AUNotificationsComponentProps> = ({
3
+ const AUNotificationComponent: FC<AUNotificationComponentProps> = ({
4
4
  header,
5
5
  content,
6
6
  actions,
7
7
  type,
8
8
  classNames,
9
- }: AUNotificationsComponentProps) => {
9
+ }: AUNotificationComponentProps) => {
10
10
  const typeClass = type === 'default' ? '' : `notification--${type}`;
11
11
  return (
12
12
  <div className={[
@@ -31,12 +31,12 @@ const AUNotificationsComponent: FC<AUNotificationsComponentProps> = ({
31
31
  );
32
32
  };
33
33
 
34
- AUNotificationsComponent.defaultProps = {
34
+ AUNotificationComponent.defaultProps = {
35
35
  header: null,
36
36
  actions: [],
37
37
  type: 'default',
38
38
  classNames: [],
39
39
  };
40
40
 
41
- AUNotificationsComponent.displayName = 'AUNotificationsComponent';
42
- export default AUNotificationsComponent;
41
+ AUNotificationComponent.displayName = 'AUNotificationComponent';
42
+ export default AUNotificationComponent;
@@ -0,0 +1,117 @@
1
+ import React from 'react';
2
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
3
+
4
+ import AUErrorComponent from '../src/components/AUErrorComponent';
5
+
6
+ // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
7
+ export default {
8
+ title: 'Delphinus/Error',
9
+ component: AUErrorComponent,
10
+ // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
11
+ decorators: [
12
+ (Story) => { // , context) => {
13
+ /*
14
+ const { args: { themeColor, themeMode } } = context;
15
+ const themeColorClass = themeColor === 'none' ? '' : `theme--${themeColor}`;
16
+ const themeModeClass = themeMode === 'light' ? '' : `theme--${themeMode}`;
17
+ */
18
+ return (
19
+ <div>
20
+ {Story()}
21
+ </div>
22
+ );
23
+ }
24
+ ]
25
+ } as ComponentMeta<typeof AUErrorComponent>;
26
+
27
+ // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
28
+ const Template: ComponentStory<typeof AUErrorComponent> = (args) => <AUErrorComponent {...args} />;
29
+
30
+ export const AU_Error = Template.bind({});
31
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
32
+ AU_Error.args = {
33
+ error: {
34
+ header: 'Our own custom error',
35
+ message: 'With a nice header and descriptive error message',
36
+ status: 500,
37
+ },
38
+ };
39
+
40
+ export const AU_Error_With_Status = Template.bind({});
41
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
42
+ AU_Error_With_Status.args = {
43
+ error: {
44
+ header: 'Our own custom error',
45
+ message: 'With a nice header and descriptive error message',
46
+ status: 500,
47
+ },
48
+ withStatus: true,
49
+ };
50
+
51
+ export const Fetch_Error = Template.bind({});
52
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
53
+ Fetch_Error.args = {
54
+ fetchError: {
55
+ error: 'Something horrible has happened on the server...',
56
+ status: 'FETCH_ERROR',
57
+ },
58
+ };
59
+
60
+ export const Fetch_Error_With_Status = Template.bind({});
61
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
62
+ Fetch_Error_With_Status.args = {
63
+ fetchError: {
64
+ error: 'Something horrible has happened on the server...',
65
+ status: 'FETCH_ERROR',
66
+ },
67
+ withStatus: true,
68
+ };
69
+
70
+ export const Fetch_Error_With_Data = Template.bind({});
71
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
72
+ Fetch_Error_With_Data.args = {
73
+ fetchError: {
74
+ data: {
75
+ status: 'Error',
76
+ message: 'This could be anything...',
77
+ somethingElse: 'Even this...',
78
+ },
79
+ status: 500,
80
+ },
81
+ withStatus: false,
82
+ };
83
+
84
+ export const Fetch_Error_With_Data_And_Status = Template.bind({});
85
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
86
+ Fetch_Error_With_Data_And_Status.args = {
87
+ fetchError: {
88
+ data: {
89
+ status: 'Error',
90
+ message: 'This could be anything...',
91
+ somethingElse: 'Even this...',
92
+ },
93
+ status: 500,
94
+ },
95
+ withStatus: true,
96
+ };
97
+
98
+ export const Serialized_Error = Template.bind({});
99
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
100
+ Serialized_Error.args = {
101
+ serializedError: {
102
+ message: 'Something funky has happened in the code...',
103
+ code: '500',
104
+ },
105
+ withStatus: false,
106
+ };
107
+
108
+ export const Serialized_Error_With_Code = Template.bind({});
109
+ // More on args: https://storybook.js.org/docs/react/writing-stories/args
110
+ Serialized_Error_With_Code.args = {
111
+ serializedError: {
112
+ message: 'Something funky has happened in the code...',
113
+ code: '500',
114
+ },
115
+ withStatus: true,
116
+ };
117
+