orc-shared 1.6.0-dev.4 → 1.6.0-dev.5

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.
Files changed (26) hide show
  1. package/dist/actions/globalErrorMessages.js +67 -0
  2. package/dist/actions/makeApiAction.js +1 -1
  3. package/dist/buildStore.js +3 -1
  4. package/dist/components/MaterialUI/DataDisplay/PredefinedElements/GlobalErrorMessages.js +133 -0
  5. package/dist/components/MaterialUI/DataDisplay/PredefinedElements/LookupDisplayValue.js +78 -0
  6. package/dist/components/Scope/useScopeConfirmationModalState.js +1 -1
  7. package/dist/hooks/useDispatchWithErrorHandling.js +106 -0
  8. package/dist/reducers/globalErrorMessages.js +79 -0
  9. package/dist/selectors/globalErrorMessages.js +58 -0
  10. package/dist/utils/responseProcessingHelper.js +86 -0
  11. package/package.json +4 -2
  12. package/src/actions/globalErrorMessages.js +12 -0
  13. package/src/actions/globalErrorMessages.test.js +21 -0
  14. package/src/buildStore.js +2 -0
  15. package/src/components/MaterialUI/DataDisplay/PredefinedElements/GlobalErrorMessages.js +92 -0
  16. package/src/components/MaterialUI/DataDisplay/PredefinedElements/GlobalErrorMessages.test.js +444 -0
  17. package/src/components/MaterialUI/DataDisplay/PredefinedElements/LookupDisplayValue.js +12 -0
  18. package/src/components/MaterialUI/DataDisplay/PredefinedElements/LookupDisplayValue.test.js +85 -0
  19. package/src/hooks/useDispatchWithErrorHandling.js +57 -0
  20. package/src/hooks/useDispatchWithErrorHandling.test.js +230 -0
  21. package/src/reducers/globalErrorMessages.js +25 -0
  22. package/src/reducers/globalErrorMessages.test.js +66 -0
  23. package/src/selectors/globalErrorMessages.js +11 -0
  24. package/src/selectors/globalErrorMessages.test.js +25 -0
  25. package/src/utils/responseProcessingHelper.js +41 -0
  26. package/src/utils/responseProcessingHelper.test.js +182 -0
@@ -0,0 +1,444 @@
1
+ import React from "react";
2
+ import GlobalErrorMessagesModal from "./GlobalErrorMessages";
3
+ import { createMuiTheme, extractMessages, TestWrapper } from "../../../../utils/testUtils";
4
+ import Immutable from "immutable";
5
+ import ActionModal from "./ActionModal";
6
+ import sharedMessages from "../../../../sharedMessages";
7
+ import LookupDisplayValue from "./LookupDisplayValue";
8
+ import Grid from "@material-ui/core/Grid";
9
+ import ListItemText from "@material-ui/core/ListItemText";
10
+ import List from "@material-ui/core/List";
11
+ import ListItem from "@material-ui/core/ListItem";
12
+ import ListItemIcon from "@material-ui/core/ListItemIcon";
13
+ import { popGlobalErrorMessage } from "../../../../actions/globalErrorMessages";
14
+ import sinon from "sinon";
15
+ import { render } from "@testing-library/react";
16
+ import { getByText, fireEvent } from "@testing-library/react";
17
+
18
+ const theme = createMuiTheme();
19
+ const messages = extractMessages(sharedMessages);
20
+
21
+ const metadataPayload = {
22
+ metadata: {
23
+ lookups: {
24
+ order: {
25
+ index: {
26
+ OrderStatus: {
27
+ lookupName: "OrderStatus",
28
+ values: {
29
+ Completed: {
30
+ id: "03caa0ebecd04792a96c2f8df5b9b35a",
31
+ value: "Completed",
32
+ lookupId: "OrderStatus",
33
+ displayName: {
34
+ "en-US": "Completed",
35
+ },
36
+ sortOrder: 0,
37
+ isActive: true,
38
+ isSystem: true,
39
+ },
40
+ InProgress: {
41
+ id: "13caa0ebecd04792a96c2f8df5b9b35a",
42
+ value: "InProgress",
43
+ lookupId: "InProgress",
44
+ displayName: {
45
+ "en-US": "In Progress",
46
+ },
47
+ sortOrder: 1,
48
+ isActive: false,
49
+ isSystem: true,
50
+ },
51
+ },
52
+ displayName: {
53
+ "en-US": "Order Status",
54
+ },
55
+ isActive: true,
56
+ isSystem: true,
57
+ },
58
+ },
59
+ list: [],
60
+ },
61
+ },
62
+ },
63
+ };
64
+
65
+ describe("GlobalErrorMessagesModal", () => {
66
+ let store, state, dispatch;
67
+ beforeEach(() => {
68
+ state = Immutable.fromJS({
69
+ locale: {
70
+ locale: "en",
71
+ supportedLocales: ["en", "fr"],
72
+ },
73
+ globalErrorMessages: {
74
+ dialog: {
75
+ errorMessages: [],
76
+ },
77
+ },
78
+ ...metadataPayload,
79
+ });
80
+
81
+ dispatch = sinon.spy().named("dispatch");
82
+
83
+ store = {
84
+ subscribe: () => {},
85
+ getState: () => state,
86
+ dispatch: dispatch,
87
+ };
88
+ });
89
+
90
+ const errorMessages = [
91
+ {
92
+ title: "ze title",
93
+ description: "desc",
94
+ messages: [
95
+ { message: "error msg" },
96
+ { lookupModule: "order", lookupName: "OrderStatus", lookupKey: "InProgress" },
97
+ ],
98
+ },
99
+ ];
100
+ const expectedMessagesContent = (
101
+ <Grid item xs={12}>
102
+ <List>
103
+ <ListItem key={0}>
104
+ <ListItemIcon>●</ListItemIcon>
105
+ <ListItemText>error msg</ListItemText>
106
+ </ListItem>
107
+ <ListItem key={1}>
108
+ <ListItemIcon>●</ListItemIcon>
109
+ <ListItemText>
110
+ <LookupDisplayValue moduleName="order" lookupName="OrderStatus" lookupKey="InProgress" />
111
+ </ListItemText>
112
+ </ListItem>
113
+ </List>
114
+ </Grid>
115
+ );
116
+
117
+ it("Renders no dialog because state contains no messages", () => {
118
+ const component = (
119
+ <TestWrapper
120
+ provider={{ store }}
121
+ intlProvider={{ messages }}
122
+ memoryRouter
123
+ stylesProvider
124
+ muiThemeProvider={{ theme }}
125
+ >
126
+ <GlobalErrorMessagesModal>
127
+ <div>children</div>
128
+ </GlobalErrorMessagesModal>
129
+ </TestWrapper>
130
+ );
131
+
132
+ const expected = (
133
+ <TestWrapper
134
+ provider={{ store }}
135
+ intlProvider={{ messages }}
136
+ memoryRouter
137
+ stylesProvider
138
+ muiThemeProvider={{ theme }}
139
+ >
140
+ <div>children</div>
141
+ </TestWrapper>
142
+ );
143
+
144
+ expect(component, "when mounted", "to satisfy", expected);
145
+ });
146
+
147
+ it("Renders dialog with messages", () => {
148
+ state = state.setIn(["globalErrorMessages", "dialog", "errorMessages"], Immutable.fromJS(errorMessages));
149
+
150
+ const component = (
151
+ <TestWrapper
152
+ provider={{ store }}
153
+ intlProvider={{ messages }}
154
+ memoryRouter
155
+ stylesProvider
156
+ muiThemeProvider={{ theme }}
157
+ >
158
+ <div>
159
+ <GlobalErrorMessagesModal>
160
+ <div>children</div>
161
+ </GlobalErrorMessagesModal>
162
+ </div>
163
+ </TestWrapper>
164
+ );
165
+
166
+ const content = (
167
+ <Grid container spacing={2}>
168
+ <Grid container item spacing={0}>
169
+ <Grid item xs={12}>
170
+ desc
171
+ </Grid>
172
+ {expectedMessagesContent}
173
+ </Grid>
174
+ </Grid>
175
+ );
176
+
177
+ const expected = (
178
+ <TestWrapper
179
+ provider={{ store }}
180
+ intlProvider={{ messages }}
181
+ memoryRouter
182
+ stylesProvider
183
+ muiThemeProvider={{ theme }}
184
+ >
185
+ <div>
186
+ <div>children</div>
187
+ <ActionModal
188
+ title={"ze title"}
189
+ message={content}
190
+ open={true}
191
+ actions={[{ label: sharedMessages.close, isPrimary: true }]}
192
+ />
193
+ </div>
194
+ </TestWrapper>
195
+ );
196
+
197
+ expect(component, "when mounted", "to satisfy", expected);
198
+ });
199
+
200
+ it("Renders dialog with messages with default title", () => {
201
+ state = state.setIn(
202
+ ["globalErrorMessages", "dialog", "errorMessages"],
203
+ Immutable.fromJS([{ ...errorMessages[0], title: null }]),
204
+ );
205
+
206
+ const component = (
207
+ <TestWrapper
208
+ provider={{ store }}
209
+ intlProvider={{ messages }}
210
+ memoryRouter
211
+ stylesProvider
212
+ muiThemeProvider={{ theme }}
213
+ >
214
+ <div>
215
+ <GlobalErrorMessagesModal>
216
+ <div>children</div>
217
+ </GlobalErrorMessagesModal>
218
+ </div>
219
+ </TestWrapper>
220
+ );
221
+
222
+ const content = (
223
+ <Grid container spacing={2}>
224
+ <Grid container item spacing={0}>
225
+ <Grid item xs={12}>
226
+ desc
227
+ </Grid>
228
+ {expectedMessagesContent}
229
+ </Grid>
230
+ </Grid>
231
+ );
232
+
233
+ const expected = (
234
+ <TestWrapper
235
+ provider={{ store }}
236
+ intlProvider={{ messages }}
237
+ memoryRouter
238
+ stylesProvider
239
+ muiThemeProvider={{ theme }}
240
+ >
241
+ <div>
242
+ <div>children</div>
243
+ <ActionModal
244
+ title={"Error"}
245
+ message={content}
246
+ open={true}
247
+ actions={[{ label: sharedMessages.close, isPrimary: true }]}
248
+ />
249
+ </div>
250
+ </TestWrapper>
251
+ );
252
+
253
+ expect(component, "when mounted", "to satisfy", expected);
254
+ });
255
+
256
+ it("Renders dialog with messages without description", () => {
257
+ state = state.setIn(
258
+ ["globalErrorMessages", "dialog", "errorMessages"],
259
+ Immutable.fromJS([{ ...errorMessages[0], description: null }]),
260
+ );
261
+
262
+ const component = (
263
+ <TestWrapper
264
+ provider={{ store }}
265
+ intlProvider={{ messages }}
266
+ memoryRouter
267
+ stylesProvider
268
+ muiThemeProvider={{ theme }}
269
+ >
270
+ <div>
271
+ <GlobalErrorMessagesModal>
272
+ <div>children</div>
273
+ </GlobalErrorMessagesModal>
274
+ </div>
275
+ </TestWrapper>
276
+ );
277
+
278
+ const content = (
279
+ <Grid container spacing={2}>
280
+ <Grid container item spacing={0}>
281
+ {expectedMessagesContent}
282
+ </Grid>
283
+ </Grid>
284
+ );
285
+
286
+ const expected = (
287
+ <TestWrapper
288
+ provider={{ store }}
289
+ intlProvider={{ messages }}
290
+ memoryRouter
291
+ stylesProvider
292
+ muiThemeProvider={{ theme }}
293
+ >
294
+ <div>
295
+ <div>children</div>
296
+ <ActionModal
297
+ title={"ze title"}
298
+ message={content}
299
+ open={true}
300
+ actions={[{ label: sharedMessages.close, isPrimary: true }]}
301
+ />
302
+ </div>
303
+ </TestWrapper>
304
+ );
305
+
306
+ expect(component, "when mounted", "to satisfy", expected);
307
+ });
308
+
309
+ it("Renders dialog without messages (empty)", () => {
310
+ state = state.setIn(
311
+ ["globalErrorMessages", "dialog", "errorMessages"],
312
+ Immutable.fromJS([{ ...errorMessages[0], messages: [] }]),
313
+ );
314
+
315
+ const component = (
316
+ <TestWrapper
317
+ provider={{ store }}
318
+ intlProvider={{ messages }}
319
+ memoryRouter
320
+ stylesProvider
321
+ muiThemeProvider={{ theme }}
322
+ >
323
+ <div>
324
+ <GlobalErrorMessagesModal>
325
+ <div>children</div>
326
+ </GlobalErrorMessagesModal>
327
+ </div>
328
+ </TestWrapper>
329
+ );
330
+
331
+ const content = (
332
+ <Grid container spacing={2}>
333
+ <Grid container item spacing={0}>
334
+ <Grid item xs={12}>
335
+ desc
336
+ </Grid>
337
+ </Grid>
338
+ </Grid>
339
+ );
340
+
341
+ const expected = (
342
+ <TestWrapper
343
+ provider={{ store }}
344
+ intlProvider={{ messages }}
345
+ memoryRouter
346
+ stylesProvider
347
+ muiThemeProvider={{ theme }}
348
+ >
349
+ <div>
350
+ <div>children</div>
351
+ <ActionModal
352
+ title={"ze title"}
353
+ message={content}
354
+ open={true}
355
+ actions={[{ label: sharedMessages.close, isPrimary: true }]}
356
+ />
357
+ </div>
358
+ </TestWrapper>
359
+ );
360
+
361
+ expect(component, "when mounted", "to satisfy", expected);
362
+ });
363
+
364
+ it("Renders dialog without messages (null)", () => {
365
+ state = state.setIn(
366
+ ["globalErrorMessages", "dialog", "errorMessages"],
367
+ Immutable.fromJS([{ ...errorMessages[0], messages: null }]),
368
+ );
369
+
370
+ const component = (
371
+ <TestWrapper
372
+ provider={{ store }}
373
+ intlProvider={{ messages }}
374
+ memoryRouter
375
+ stylesProvider
376
+ muiThemeProvider={{ theme }}
377
+ >
378
+ <div>
379
+ <GlobalErrorMessagesModal>
380
+ <div>children</div>
381
+ </GlobalErrorMessagesModal>
382
+ </div>
383
+ </TestWrapper>
384
+ );
385
+
386
+ const content = (
387
+ <Grid container spacing={2}>
388
+ <Grid container item spacing={0}>
389
+ <Grid item xs={12}>
390
+ desc
391
+ </Grid>
392
+ </Grid>
393
+ </Grid>
394
+ );
395
+
396
+ const expected = (
397
+ <TestWrapper
398
+ provider={{ store }}
399
+ intlProvider={{ messages }}
400
+ memoryRouter
401
+ stylesProvider
402
+ muiThemeProvider={{ theme }}
403
+ >
404
+ <div>
405
+ <div>children</div>
406
+ <ActionModal
407
+ title={"ze title"}
408
+ message={content}
409
+ open={true}
410
+ actions={[{ label: sharedMessages.close, isPrimary: true }]}
411
+ />
412
+ </div>
413
+ </TestWrapper>
414
+ );
415
+
416
+ expect(component, "when mounted", "to satisfy", expected);
417
+ });
418
+
419
+ it("The close button pop the message", () => {
420
+ state = state.setIn(["globalErrorMessages", "dialog", "errorMessages"], Immutable.fromJS(errorMessages));
421
+
422
+ const component = (
423
+ <TestWrapper
424
+ provider={{ store }}
425
+ intlProvider={{ messages }}
426
+ memoryRouter
427
+ stylesProvider
428
+ muiThemeProvider={{ theme }}
429
+ >
430
+ <div>
431
+ <GlobalErrorMessagesModal>
432
+ <div>children</div>
433
+ </GlobalErrorMessagesModal>
434
+ </div>
435
+ </TestWrapper>
436
+ );
437
+
438
+ const { container } = render(component);
439
+ const button = getByText(container, "Close");
440
+ fireEvent.click(button);
441
+
442
+ expect(dispatch, "to have calls satisfying", [{ args: [popGlobalErrorMessage()] }]);
443
+ });
444
+ });
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import TooltippedTypography from "../TooltippedElements/TooltippedTypography";
3
+ import { namedLookupLocalizedSelector } from "../../../../selectors/metadata";
4
+ import { useSelector } from "react-redux";
5
+
6
+ const LookupDisplayValue = ({ moduleName, lookupName, lookupKey, ...otherProps }) => {
7
+ const value = useSelector(namedLookupLocalizedSelector(moduleName, lookupName, lookupKey));
8
+
9
+ return <TooltippedTypography noWrap {...otherProps} children={value} titleValue={value} />;
10
+ };
11
+
12
+ export default LookupDisplayValue;
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+ import LookupDisplayValue from "./LookupDisplayValue";
3
+ import { createMuiTheme, TestWrapper } from "../../../../utils/testUtils";
4
+ import Immutable from "immutable";
5
+ import TooltippedTypography from "../TooltippedElements/TooltippedTypography";
6
+
7
+ const theme = createMuiTheme();
8
+
9
+ const metadataPayload = {
10
+ metadata: {
11
+ lookups: {
12
+ order: {
13
+ index: {
14
+ OrderStatus: {
15
+ lookupName: "OrderStatus",
16
+ values: {
17
+ Completed: {
18
+ id: "03caa0ebecd04792a96c2f8df5b9b35a",
19
+ value: "Completed",
20
+ lookupId: "OrderStatus",
21
+ displayName: {
22
+ "en-US": "Completed",
23
+ },
24
+ sortOrder: 0,
25
+ isActive: true,
26
+ isSystem: true,
27
+ },
28
+ InProgress: {
29
+ id: "13caa0ebecd04792a96c2f8df5b9b35a",
30
+ value: "InProgress",
31
+ lookupId: "InProgress",
32
+ displayName: {
33
+ "en-US": "In Progress",
34
+ },
35
+ sortOrder: 1,
36
+ isActive: false,
37
+ isSystem: true,
38
+ },
39
+ },
40
+ displayName: {
41
+ "en-US": "Order Status",
42
+ },
43
+ isActive: true,
44
+ isSystem: true,
45
+ },
46
+ },
47
+ list: [],
48
+ },
49
+ },
50
+ },
51
+ };
52
+
53
+ describe("LookupDisplayValue", () => {
54
+ let store, state;
55
+ beforeEach(() => {
56
+ state = Immutable.fromJS({
57
+ locale: {
58
+ locale: "en",
59
+ supportedLocales: ["en", "fr"],
60
+ },
61
+ ...metadataPayload,
62
+ });
63
+ store = {
64
+ subscribe: () => {},
65
+ getState: () => state,
66
+ dispatch: () => {},
67
+ };
68
+ });
69
+
70
+ it("Renders lookup value", () => {
71
+ const component = (
72
+ <TestWrapper provider={{ store }} memoryRouter stylesProvider muiThemeProvider={{ theme }}>
73
+ <LookupDisplayValue moduleName="order" lookupName="OrderStatus" lookupKey="InProgress" />
74
+ </TestWrapper>
75
+ );
76
+
77
+ const expected = (
78
+ <TestWrapper provider={{ store }} memoryRouter stylesProvider muiThemeProvider={{ theme }}>
79
+ <TooltippedTypography noWrap children={"In Progress"} titleValue={"In Progress"} />
80
+ </TestWrapper>
81
+ );
82
+
83
+ expect(component, "when mounted", "to satisfy", expected);
84
+ });
85
+ });
@@ -0,0 +1,57 @@
1
+ import { useDispatch } from "react-redux";
2
+ import { useCallback } from "react";
3
+ import { extractStandardErrorMessagesFromResponse } from "../utils/responseProcessingHelper";
4
+ import { pushGlobalErrorMessage } from "../actions/globalErrorMessages";
5
+
6
+ export const executeDispatchWithErrorHandling = ({
7
+ dispatch,
8
+ action,
9
+ errorTitle,
10
+ errorDescription,
11
+ validationLookupModule,
12
+ validationLookupName,
13
+ }) => {
14
+ return dispatch(action).then(data => {
15
+ const extractedMessages = extractStandardErrorMessagesFromResponse(
16
+ data,
17
+ validationLookupModule,
18
+ validationLookupName,
19
+ );
20
+ if (extractedMessages.hasErrors) {
21
+ const newMsg = {
22
+ messages: extractedMessages.messages,
23
+ };
24
+
25
+ if (extractedMessages.messages.length > 0) {
26
+ newMsg.title = errorDescription;
27
+ } else {
28
+ newMsg.title = errorTitle;
29
+ newMsg.description = errorDescription;
30
+ }
31
+
32
+ dispatch(pushGlobalErrorMessage(newMsg));
33
+ }
34
+
35
+ return data;
36
+ });
37
+ };
38
+
39
+ export const useDispatchWithErrorHandling = () => {
40
+ const dispatch = useDispatch();
41
+
42
+ return useCallback(
43
+ ({ action, errorTitle, errorDescription, validationLookupModule, validationLookupName }) => {
44
+ return executeDispatchWithErrorHandling({
45
+ dispatch,
46
+ action,
47
+ errorTitle,
48
+ errorDescription,
49
+ validationLookupModule,
50
+ validationLookupName,
51
+ });
52
+ },
53
+ [dispatch],
54
+ );
55
+ };
56
+
57
+ export default useDispatchWithErrorHandling;