orc-shared 1.1.0-dev.7 → 1.1.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.
Files changed (245) hide show
  1. package/dist/actions/applications.js +1 -1
  2. package/dist/actions/authentication.js +1 -1
  3. package/dist/actions/countries.js +1 -1
  4. package/dist/actions/locale.js +1 -1
  5. package/dist/actions/makeApiAction.js +71 -1
  6. package/dist/actions/metadata.js +295 -31
  7. package/dist/actions/navigation.js +1 -1
  8. package/dist/actions/requestState.js +78 -0
  9. package/dist/actions/requestsApi.js +58 -7
  10. package/dist/actions/scopes.js +1 -1
  11. package/dist/actions/timezones.js +1 -1
  12. package/dist/actions/toasts.js +1 -1
  13. package/dist/actions/versionInfo.js +1 -1
  14. package/dist/actions/view.js +1 -1
  15. package/dist/buildStore.js +5 -2
  16. package/dist/components/AppFrame/About.js +1 -1
  17. package/dist/components/AppFrame/ApplicationSelector/ApplicationDialog.js +115 -62
  18. package/dist/components/AppFrame/ApplicationSelector/index.js +45 -47
  19. package/dist/components/AppFrame/MenuItem.js +1 -1
  20. package/dist/components/AppFrame/Preferences.js +1 -1
  21. package/dist/components/AppFrame/Sidebar.js +1 -1
  22. package/dist/components/AppFrame/Topbar.js +1 -1
  23. package/dist/components/Authenticate.js +1 -1
  24. package/dist/components/CategoryList.js +1 -1
  25. package/dist/components/Checkbox.js +1 -1
  26. package/dist/components/DropMenu/Menu.js +1 -1
  27. package/dist/components/DropMenu/index.js +1 -1
  28. package/dist/components/Form/FieldList.js +1 -1
  29. package/dist/components/Form/Form.js +1 -1
  30. package/dist/components/Form/Inputs/Button.js +1 -1
  31. package/dist/components/Form/Inputs/FieldButtons.js +1 -1
  32. package/dist/components/Form/Inputs/Number.js +1 -1
  33. package/dist/components/Form/Inputs/ReadOnly.js +1 -1
  34. package/dist/components/Form/Inputs/SmallButton.js +1 -1
  35. package/dist/components/Form/Inputs/Text.js +1 -1
  36. package/dist/components/Form/Inputs/Time.js +1 -1
  37. package/dist/components/Form/Inputs/Toggles.js +1 -1
  38. package/dist/components/Form/Inputs/Translation.js +1 -1
  39. package/dist/components/List/HeadCell.js +1 -1
  40. package/dist/components/List/List.js +1 -1
  41. package/dist/components/List/Row.js +1 -1
  42. package/dist/components/MaterialUI/DataDisplay/List.js +1 -1
  43. package/dist/components/MaterialUI/DataDisplay/NotificationProps.js +1 -1
  44. package/dist/components/MaterialUI/DataDisplay/PredefinedElements/Translations.js +1 -1
  45. package/dist/components/MaterialUI/DataDisplay/SelectionList.js +19 -6
  46. package/dist/components/MaterialUI/DataDisplay/Table.js +28 -10
  47. package/dist/components/MaterialUI/DataDisplay/TableProps.js +5 -2
  48. package/dist/components/MaterialUI/DataDisplay/TransferList.js +5 -2
  49. package/dist/components/MaterialUI/DataDisplay/chipProps.js +1 -1
  50. package/dist/components/MaterialUI/DataDisplay/collapsableListProps.js +1 -1
  51. package/dist/components/MaterialUI/DataDisplay/dividerProps.js +1 -1
  52. package/dist/components/MaterialUI/DataDisplay/index.js +1 -1
  53. package/dist/components/MaterialUI/DataDisplay/modalProps.js +1 -1
  54. package/dist/components/MaterialUI/DataDisplay/useTableSelection.js +1 -1
  55. package/dist/components/MaterialUI/Feedback/useNotification.js +1 -1
  56. package/dist/components/MaterialUI/Inputs/AutocompleteProps.js +1 -1
  57. package/dist/components/MaterialUI/Inputs/CheckboxGroupProps.js +1 -1
  58. package/dist/components/MaterialUI/Inputs/CheckboxProps.js +1 -1
  59. package/dist/components/MaterialUI/Inputs/DatePicker.js +11 -0
  60. package/dist/components/MaterialUI/Inputs/InputBase.js +3 -2
  61. package/dist/components/MaterialUI/Inputs/InputBaseProps.js +1 -1
  62. package/dist/components/MaterialUI/Inputs/PredefinedElements/SearchControl.js +1 -1
  63. package/dist/components/MaterialUI/Inputs/RadioProps.js +1 -1
  64. package/dist/components/MaterialUI/Inputs/SelectProps.js +1 -1
  65. package/dist/components/MaterialUI/Inputs/Switch.js +1 -1
  66. package/dist/components/MaterialUI/Inputs/SwitchProps.js +1 -1
  67. package/dist/components/MaterialUI/Inputs/TimePicker.js +19 -8
  68. package/dist/components/MaterialUI/Inputs/createInput.js +1 -1
  69. package/dist/components/MaterialUI/Inputs/index.js +1 -1
  70. package/dist/components/MaterialUI/Inputs/standaloneRadioProps.js +1 -1
  71. package/dist/components/MaterialUI/Navigation/DropDownMenuProps.js +1 -1
  72. package/dist/components/MaterialUI/Navigation/TabBar.js +38 -33
  73. package/dist/components/MaterialUI/ScopeSelector/ScopeSelector.js +6 -4
  74. package/dist/components/MaterialUI/ScopeSelector/ScopeTreeView.js +8 -4
  75. package/dist/components/MaterialUI/ScopeSelector/TreeItem.js +9 -6
  76. package/dist/components/MaterialUI/Surfaces/ExpansionPanel.js +11 -2
  77. package/dist/components/MaterialUI/Surfaces/SectionExpansionPanel.js +10 -2
  78. package/dist/components/MaterialUI/Surfaces/expansionPanelProps.js +5 -2
  79. package/dist/components/MaterialUI/Surfaces/paperProps.js +1 -1
  80. package/dist/components/MaterialUI/muiThemes.js +19 -4
  81. package/dist/components/MaterialUI/textProps.js +1 -1
  82. package/dist/components/Modules.js +24 -2
  83. package/dist/components/MultiSelector.js +1 -1
  84. package/dist/components/Navigation/Bar.js +1 -1
  85. package/dist/components/Navigation/Tab.js +1 -1
  86. package/dist/components/Navigation/useNavigationState.js +28 -2
  87. package/dist/components/Placeholder.js +1 -1
  88. package/dist/components/Routing/FullPage.js +2 -0
  89. package/dist/components/Routing/Segment.js +4 -3
  90. package/dist/components/Routing/SegmentPage.js +24 -11
  91. package/dist/components/Routing/withWaypointing.js +8 -2
  92. package/dist/components/Scope/ScopeNode.js +1 -1
  93. package/dist/components/Scope/Selector.js +1 -1
  94. package/dist/components/Scope/index.js +9 -1
  95. package/dist/components/Scope/useScopeSelect.js +1 -1
  96. package/dist/components/Selector.js +1 -1
  97. package/dist/components/Sidepanel.js +1 -2
  98. package/dist/components/Spritesheet.js +1 -1
  99. package/dist/components/Switch.js +1 -1
  100. package/dist/components/Text.js +1 -1
  101. package/dist/components/ToastList.js +1 -1
  102. package/dist/components/Toolbar.js +1 -1
  103. package/dist/components/Treeview/Label.js +1 -1
  104. package/dist/components/Treeview/Leaf.js +1 -1
  105. package/dist/components/Treeview/Node.js +1 -1
  106. package/dist/components/Treeview/settings.js +1 -1
  107. package/dist/constants.js +26 -1
  108. package/dist/content/icons/html-templates.svg +3 -0
  109. package/dist/content/iconsSheet.svg +3 -0
  110. package/dist/hocs/withInfiniteScroll.js +1 -1
  111. package/dist/hooks/useDispatchWithModulesData.js +1 -1
  112. package/dist/hooks/useEditState.js +1 -1
  113. package/dist/hooks/useEntityLoader.js +182 -0
  114. package/dist/hooks/useFullEntityEditState.js +1 -1
  115. package/dist/hooks/useInfiniteScroll.js +104 -0
  116. package/dist/hooks/useLabelMessage.js +1 -1
  117. package/dist/hooks/useLoader.js +1 -0
  118. package/dist/hooks/useNavigationHandler.js +1 -1
  119. package/dist/hooks/useNotificationRequestState.js +159 -0
  120. package/dist/hooks/useRequestState.js +146 -0
  121. package/dist/hooks/useSelectorAndUnwrap.js +1 -1
  122. package/dist/reducers/metadata.js +52 -26
  123. package/dist/reducers/requestStates.js +181 -0
  124. package/dist/schemas/countries.js +1 -1
  125. package/dist/schemas/definitions.js +1 -1
  126. package/dist/schemas/metadata.js +1 -1
  127. package/dist/schemas/productDefinitions.js +1 -1
  128. package/dist/schemas/timezones.js +1 -1
  129. package/dist/selectors/applications.js +1 -1
  130. package/dist/selectors/authentication.js +1 -2
  131. package/dist/selectors/countries.js +1 -1
  132. package/dist/selectors/locale.js +1 -1
  133. package/dist/selectors/metadata.js +102 -12
  134. package/dist/selectors/navigation.js +1 -1
  135. package/dist/selectors/requestStates.js +82 -0
  136. package/dist/selectors/requests.js +1 -1
  137. package/dist/selectors/scope.js +1 -1
  138. package/dist/selectors/versionInfo.js +1 -1
  139. package/dist/selectors/view.js +1 -1
  140. package/dist/sharedMessages.js +44 -0
  141. package/dist/spawnerMiddleware.js +1 -1
  142. package/dist/utils/displayModeHelper.js +1 -1
  143. package/dist/utils/localizationHelper.js +1 -1
  144. package/dist/utils/mapHelper.js +1 -1
  145. package/dist/utils/modelValidationHelper.js +2 -2
  146. package/dist/utils/parseHelper.js +1 -1
  147. package/dist/utils/propertyHelper.js +2 -2
  148. package/dist/utils/propertyValidator.js +1 -1
  149. package/dist/utils/setTranslationWithFallback.js +3 -2
  150. package/dist/utils/testUtils.js +6 -2
  151. package/dist/utils/timezoneHelper.js +111 -0
  152. package/dist/utils/unwrapImmutable.js +1 -1
  153. package/dist/utils/urlHelper.js +11 -1
  154. package/package.json +3 -7
  155. package/src/actions/makeApiAction.js +24 -1
  156. package/src/actions/makeApiAction.test.js +76 -3
  157. package/src/actions/metadata.js +130 -0
  158. package/src/actions/metadata.test.js +337 -5
  159. package/src/actions/requestState.js +8 -0
  160. package/src/actions/requestState.test.js +14 -0
  161. package/src/actions/requestsApi.js +30 -0
  162. package/src/buildStore.js +2 -0
  163. package/src/components/AppFrame/AppFrame.test.js +6 -16
  164. package/src/components/AppFrame/ApplicationSelector/ApplicationDialog.js +105 -82
  165. package/src/components/AppFrame/ApplicationSelector/ApplicationDialog.test.js +60 -23
  166. package/src/components/AppFrame/ApplicationSelector/ApplicationSelector.test.js +22 -89
  167. package/src/components/AppFrame/ApplicationSelector/index.js +34 -15
  168. package/src/components/AppFrame/Topbar.test.js +2 -4
  169. package/src/components/MaterialUI/DataDisplay/SelectionList.js +14 -6
  170. package/src/components/MaterialUI/DataDisplay/SelectionList.test.js +21 -11
  171. package/src/components/MaterialUI/DataDisplay/Table.js +29 -5
  172. package/src/components/MaterialUI/DataDisplay/Table.test.js +23 -0
  173. package/src/components/MaterialUI/DataDisplay/TableProps.js +2 -0
  174. package/src/components/MaterialUI/DataDisplay/TableProps.test.js +2 -0
  175. package/src/components/MaterialUI/DataDisplay/TransferList.js +3 -0
  176. package/src/components/MaterialUI/Inputs/DatePicker.js +11 -0
  177. package/src/components/MaterialUI/Inputs/InputBase.js +3 -1
  178. package/src/components/MaterialUI/Inputs/InputBase.test.js +38 -0
  179. package/src/components/MaterialUI/Inputs/TimePicker.js +9 -3
  180. package/src/components/MaterialUI/Inputs/TimePicker.test.js +263 -118
  181. package/src/components/MaterialUI/Navigation/TabBar.js +82 -78
  182. package/src/components/MaterialUI/Navigation/TabBar.test.js +129 -3
  183. package/src/components/MaterialUI/ScopeSelector/ScopeSelector.js +4 -2
  184. package/src/components/MaterialUI/ScopeSelector/ScopeSelector.test.js +29 -0
  185. package/src/components/MaterialUI/ScopeSelector/ScopeTreeView.js +4 -1
  186. package/src/components/MaterialUI/ScopeSelector/ScopeTreeView.test.js +52 -0
  187. package/src/components/MaterialUI/ScopeSelector/TreeItem.js +9 -6
  188. package/src/components/MaterialUI/ScopeSelector/TreeItem.test.js +63 -2
  189. package/src/components/MaterialUI/Surfaces/ExpansionPanel.js +14 -1
  190. package/src/components/MaterialUI/Surfaces/ExpansionPanel.test.js +16 -0
  191. package/src/components/MaterialUI/Surfaces/SectionExpansionPanel.js +11 -2
  192. package/src/components/MaterialUI/Surfaces/SectionExpansionPanel.test.js +36 -0
  193. package/src/components/MaterialUI/Surfaces/expansionPanelProps.js +2 -0
  194. package/src/components/MaterialUI/Surfaces/expansionPanelProps.test.js +2 -2
  195. package/src/components/MaterialUI/muiThemes.js +18 -3
  196. package/src/components/Modules.js +13 -1
  197. package/src/components/Modules.test.js +133 -1
  198. package/src/components/Navigation/Navigation.test.js +2 -0
  199. package/src/components/Navigation/useNavigationState.js +21 -1
  200. package/src/components/Navigation/useNavigationState.test.js +10 -0
  201. package/src/components/Routing/FullPage.js +2 -1
  202. package/src/components/Routing/FullPage.test.js +149 -79
  203. package/src/components/Routing/Segment.js +5 -2
  204. package/src/components/Routing/Segment.test.js +22 -1
  205. package/src/components/Routing/SegmentPage.js +19 -9
  206. package/src/components/Routing/SubPage.test.js +1 -1
  207. package/src/components/Routing/withWaypointing.js +19 -17
  208. package/src/components/Routing/withWaypointing.test.js +50 -0
  209. package/src/components/Scope/Scope.test.js +117 -0
  210. package/src/components/Scope/index.js +6 -10
  211. package/src/components/Sidepanel.js +0 -1
  212. package/src/components/Sidepanel.test.js +0 -3
  213. package/src/constants.js +18 -0
  214. package/src/content/icons/html-templates.svg +3 -0
  215. package/src/content/iconsSheet.svg +3 -0
  216. package/src/hooks/useEntityLoader.js +68 -0
  217. package/src/hooks/useEntityLoader.test.js +266 -0
  218. package/src/hooks/useInfiniteScroll.js +25 -0
  219. package/src/hooks/useInfiniteScroll.test.js +87 -0
  220. package/src/hooks/useLoader.js +1 -0
  221. package/src/hooks/useNotificationRequestState.js +78 -0
  222. package/src/hooks/useNotificationRequestState.test.js +264 -0
  223. package/src/hooks/useRequestState.js +57 -0
  224. package/src/hooks/useRequestState.test.js +217 -0
  225. package/src/reducers/metadata.js +76 -16
  226. package/src/reducers/metadata.test.js +458 -4
  227. package/src/reducers/requestStates.js +98 -0
  228. package/src/reducers/requestStates.test.js +399 -0
  229. package/src/selectors/authentication.js +0 -1
  230. package/src/selectors/locale.test.js +0 -2
  231. package/src/selectors/metadata.js +73 -13
  232. package/src/selectors/metadata.test.js +479 -8
  233. package/src/selectors/requestStates.js +12 -0
  234. package/src/selectors/requestStates.test.js +83 -0
  235. package/src/sharedMessages.js +44 -0
  236. package/src/translations/en-US.json +12 -1
  237. package/src/translations/fr-CA.json +13 -2
  238. package/src/utils/modelValidationHelper.js +1 -1
  239. package/src/utils/setTranslationWithFallback.js +1 -1
  240. package/src/utils/setTranslationWithFallback.test.js +4 -14
  241. package/src/utils/testUtils.js +3 -1
  242. package/src/utils/timezoneHelper.js +140 -0
  243. package/src/utils/timezoneHelper.test.js +33 -0
  244. package/src/utils/urlHelper.js +6 -0
  245. package/src/translations/it-IT.json +0 -54
@@ -0,0 +1,264 @@
1
+ import Immutable from "immutable";
2
+ import React from "react";
3
+ import useNotificationRequestState from "./useNotificationRequestState";
4
+ import { extractMessages, TestWrapper } from "../utils/testUtils";
5
+ import { requestStateOperations } from "../constants";
6
+ import sharedMessages from "../sharedMessages";
7
+ import sinon from "sinon";
8
+ import { mount } from "enzyme";
9
+ import { resetRequestState } from "../actions/requestState";
10
+ import Snackbar from "@material-ui/core/Snackbar";
11
+ import * as getRequestStateInfo from "../selectors/requestStates";
12
+
13
+ const messages = extractMessages(sharedMessages);
14
+
15
+ describe("useNotificationRequestState", () => {
16
+ let buildRequestState;
17
+
18
+ const TestComp = props => {
19
+ [buildRequestState] = useNotificationRequestState(props);
20
+ return <div>some content</div>;
21
+ };
22
+
23
+ let state, store, successSpy, errorSpy, dispatchSpy;
24
+ beforeEach(() => {
25
+ state = Immutable.fromJS({
26
+ requestStates: {
27
+ creates: {},
28
+ deletes: {},
29
+ fetches: {},
30
+ updates: {},
31
+ },
32
+ });
33
+
34
+ successSpy = sinon.spy().named("success");
35
+ errorSpy = sinon.spy().named("error");
36
+ dispatchSpy = sinon.spy().named("dispatch");
37
+
38
+ store = {
39
+ subscribe: () => {},
40
+ getState: () => state,
41
+ dispatch: dispatchSpy,
42
+ };
43
+ });
44
+
45
+ afterEach(() => {
46
+ successSpy.resetHistory();
47
+ errorSpy.resetHistory();
48
+ dispatchSpy.resetHistory();
49
+ });
50
+
51
+ it("buildRequestState builds the expected object", () => {
52
+ const component = (
53
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
54
+ <TestComp
55
+ keys={["key1", "key2"]}
56
+ operation={requestStateOperations.delete}
57
+ successMessageId={sharedMessages.delete}
58
+ successAction={successSpy}
59
+ errorMessageId={sharedMessages.error}
60
+ errorAction={errorSpy}
61
+ />
62
+ </TestWrapper>
63
+ );
64
+
65
+ mount(component);
66
+
67
+ const obj = buildRequestState();
68
+ expect(obj, "to equal", {
69
+ keys: ["key1", "key2"],
70
+ operation: requestStateOperations.delete,
71
+ });
72
+ });
73
+
74
+ it("does not dispatch anything for an empty state", () => {
75
+ const component = (
76
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
77
+ <TestComp
78
+ keys={["key1", "key2"]}
79
+ operation={requestStateOperations.delete}
80
+ successMessageId={sharedMessages.delete}
81
+ successAction={successSpy}
82
+ errorMessageId={sharedMessages.error}
83
+ errorAction={errorSpy}
84
+ />
85
+ </TestWrapper>
86
+ );
87
+
88
+ mount(component);
89
+
90
+ expect(dispatchSpy, "was not called");
91
+ });
92
+
93
+ it("dispatches the success actions", () => {
94
+ state = state.setIn(
95
+ ["requestStates", "deletes", "key1", "key2", "state"],
96
+ Immutable.fromJS({
97
+ inProgress: false,
98
+ value: true,
99
+ error: false,
100
+ }),
101
+ );
102
+
103
+ const component = (
104
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
105
+ <TestComp
106
+ keys={["key1", "key2"]}
107
+ operation={requestStateOperations.delete}
108
+ successMessageId={sharedMessages.delete}
109
+ successAction={successSpy}
110
+ errorMessageId={sharedMessages.error}
111
+ errorAction={errorSpy}
112
+ />
113
+ </TestWrapper>
114
+ );
115
+
116
+ const mountedComponent = mount(component);
117
+ const sb = mountedComponent.find(Snackbar);
118
+
119
+ const resetAction = resetRequestState(["key1", "key2"], requestStateOperations.delete);
120
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
121
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
122
+ expect(successSpy, "was called");
123
+ expect(errorSpy, "was not called");
124
+ expect(sb.prop("open"), "to equal", true);
125
+ });
126
+
127
+ it("success callback is not called when undefined", () => {
128
+ state = state.setIn(
129
+ ["requestStates", "deletes", "key1", "key2", "state"],
130
+ Immutable.fromJS({
131
+ inProgress: false,
132
+ value: true,
133
+ error: false,
134
+ }),
135
+ );
136
+
137
+ const component = (
138
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
139
+ <TestComp
140
+ keys={["key1", "key2"]}
141
+ operation={requestStateOperations.delete}
142
+ successMessageId={sharedMessages.delete}
143
+ errorMessageId={sharedMessages.error}
144
+ errorAction={errorSpy}
145
+ />
146
+ </TestWrapper>
147
+ );
148
+
149
+ const mountedComponent = mount(component);
150
+ const sb = mountedComponent.find(Snackbar);
151
+
152
+ expect(successSpy, "was not called");
153
+ expect(sb.prop("open"), "to equal", true);
154
+ });
155
+
156
+ it("dispatches the error actions", () => {
157
+ state = state.setIn(
158
+ ["requestStates", "deletes", "key1", "key2", "state"],
159
+ Immutable.fromJS({
160
+ inProgress: false,
161
+ value: false,
162
+ error: true,
163
+ }),
164
+ );
165
+
166
+ const component = (
167
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
168
+ <TestComp
169
+ keys={["key1", "key2"]}
170
+ operation={requestStateOperations.delete}
171
+ successMessageId={sharedMessages.delete}
172
+ successAction={successSpy}
173
+ errorMessageId={sharedMessages.error}
174
+ errorAction={errorSpy}
175
+ />
176
+ </TestWrapper>
177
+ );
178
+
179
+ const mountedComponent = mount(component);
180
+ const sb = mountedComponent.find(Snackbar);
181
+
182
+ const resetAction = resetRequestState(["key1", "key2"], requestStateOperations.delete);
183
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
184
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
185
+ expect(successSpy, "was not called");
186
+ expect(errorSpy, "was called");
187
+ expect(sb.prop("open"), "to equal", true);
188
+ });
189
+
190
+ it("dispatches the error actions with a message", () => {
191
+ const errorPayload = {
192
+ response: {
193
+ responseStatus: {
194
+ message: "some error message",
195
+ },
196
+ },
197
+ };
198
+
199
+ const getRequestStateInfoOverride = () => ({
200
+ inProgress: false,
201
+ value: false,
202
+ error: errorSpy.callCount === 0,
203
+ errorResponse: errorSpy.callCount === 0 ? errorPayload : null,
204
+ });
205
+
206
+ const getRequestStateInfoStub = sinon
207
+ .stub(getRequestStateInfo, "getRequestStateInfo")
208
+ .returns(() => getRequestStateInfoOverride());
209
+
210
+ const component = (
211
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
212
+ <TestComp
213
+ keys={["key1", "key2"]}
214
+ operation={requestStateOperations.delete}
215
+ successMessageId={sharedMessages.delete}
216
+ successAction={successSpy}
217
+ errorMessageId={sharedMessages.error}
218
+ errorAction={errorSpy}
219
+ />
220
+ </TestWrapper>
221
+ );
222
+
223
+ const mountedComponent = mount(component);
224
+ const sb = mountedComponent.find(Snackbar);
225
+
226
+ const resetAction = resetRequestState(["key1", "key2"], requestStateOperations.delete);
227
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
228
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
229
+ expect(successSpy, "was not called");
230
+ expect(errorSpy, "to have a call satisfying", { args: [errorPayload] });
231
+ expect(sb.prop("open"), "to equal", true);
232
+
233
+ getRequestStateInfoStub.restore();
234
+ });
235
+
236
+ it("error action is not called when undefined", () => {
237
+ state = state.setIn(
238
+ ["requestStates", "deletes", "key1", "key2", "state"],
239
+ Immutable.fromJS({
240
+ inProgress: false,
241
+ value: false,
242
+ error: true,
243
+ }),
244
+ );
245
+
246
+ const component = (
247
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
248
+ <TestComp
249
+ keys={["key1", "key2"]}
250
+ operation={requestStateOperations.delete}
251
+ successMessageId={sharedMessages.delete}
252
+ successAction={successSpy}
253
+ errorMessageId={sharedMessages.error}
254
+ />
255
+ </TestWrapper>
256
+ );
257
+
258
+ const mountedComponent = mount(component);
259
+ const sb = mountedComponent.find(Snackbar);
260
+
261
+ expect(errorSpy, "was not called");
262
+ expect(sb.prop("open"), "to equal", true);
263
+ });
264
+ });
@@ -0,0 +1,57 @@
1
+ import useSelectorAndUnwrap from "./useSelectorAndUnwrap";
2
+ import { getRequestStateInfo } from "../selectors/requestStates";
3
+ import { useEffect } from "react";
4
+ import { useDispatch } from "react-redux";
5
+ import { resetRequestState } from "../actions/requestState";
6
+
7
+ /*
8
+ This hook is used to handle custom action after deletes and updates requests. We can add additional operation if required.
9
+ We have a reducer scanning every request for a special payload (meta.requestState).
10
+ If this payload is detected we set some flags (inProgress, value, error) depending on the request type (_REQUEST, _SUCCESS, _FAILURE):
11
+ * inProgress: set to true while the request is executing
12
+ * value: set to false when starting the request and to true when the request has been executed successfully
13
+ * error: set to false when starting the request and to true when the request has not been executed successfully
14
+
15
+ This hook returns a method used to build a requestState object that is used in the meta data property of the dispatched action.
16
+ The expected format for the action is as follow:
17
+ {
18
+ type: 'some type',
19
+ ... // other properties
20
+ meta: {
21
+ requestState: {
22
+ keys: [],
23
+ operation: requestStateOperations.delete
24
+ }
25
+ }
26
+ }
27
+ */
28
+
29
+ const useRequestState = ({ keys, operation, successAction, errorAction }) => {
30
+ const { inProgress, value, error, errorResponse } = useSelectorAndUnwrap(getRequestStateInfo(operation, keys));
31
+ const dispatch = useDispatch();
32
+
33
+ useEffect(() => {
34
+ if (value && !inProgress && !error) {
35
+ dispatch(resetRequestState(keys, operation));
36
+ if (successAction) {
37
+ successAction();
38
+ }
39
+ } else if (!value && !inProgress && error) {
40
+ dispatch(resetRequestState(keys, operation));
41
+ if (errorAction) {
42
+ errorAction(errorResponse);
43
+ }
44
+ }
45
+ }, [dispatch, keys, operation, successAction, errorAction, errorResponse, inProgress, value, error]);
46
+
47
+ const buildRequestState = () => {
48
+ return {
49
+ keys,
50
+ operation,
51
+ };
52
+ };
53
+
54
+ return [buildRequestState];
55
+ };
56
+
57
+ export default useRequestState;
@@ -0,0 +1,217 @@
1
+ import Immutable from "immutable";
2
+ import React from "react";
3
+ import useRequestState from "./useRequestState";
4
+ import { extractMessages, TestWrapper } from "../utils/testUtils";
5
+ import { requestStateOperations } from "../constants";
6
+ import sharedMessages from "../sharedMessages";
7
+ import sinon from "sinon";
8
+ import { mount } from "enzyme";
9
+ import { resetRequestState } from "../actions/requestState";
10
+
11
+ const messages = extractMessages(sharedMessages);
12
+
13
+ describe("useRequestState", () => {
14
+ let buildRequestState;
15
+
16
+ const TestComp = props => {
17
+ [buildRequestState] = useRequestState(props);
18
+ return <div>some content</div>;
19
+ };
20
+
21
+ let state, store, successSpy, errorSpy, dispatchSpy;
22
+ beforeEach(() => {
23
+ state = Immutable.fromJS({
24
+ requestStates: {
25
+ deletes: {},
26
+ updates: {},
27
+ },
28
+ });
29
+
30
+ successSpy = sinon.spy().named("success");
31
+ errorSpy = sinon.spy().named("error");
32
+ dispatchSpy = sinon.spy().named("dispatch");
33
+
34
+ store = {
35
+ subscribe: () => {},
36
+ getState: () => state,
37
+ dispatch: dispatchSpy,
38
+ };
39
+ });
40
+
41
+ afterEach(() => {
42
+ successSpy.resetHistory();
43
+ errorSpy.resetHistory();
44
+ dispatchSpy.resetHistory();
45
+ });
46
+
47
+ it("buildRequestState builds the expected object", () => {
48
+ const component = (
49
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
50
+ <TestComp
51
+ keys={["key1", "key2"]}
52
+ operation={requestStateOperations.delete}
53
+ successAction={successSpy}
54
+ errorAction={errorSpy}
55
+ />
56
+ </TestWrapper>
57
+ );
58
+
59
+ mount(component);
60
+
61
+ const obj = buildRequestState();
62
+ expect(obj, "to equal", {
63
+ keys: ["key1", "key2"],
64
+ operation: requestStateOperations.delete,
65
+ });
66
+ });
67
+
68
+ it("does not dispatch anything for an empty state", () => {
69
+ const component = (
70
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
71
+ <TestComp
72
+ keys={["key1", "key2"]}
73
+ operation={requestStateOperations.delete}
74
+ successAction={successSpy}
75
+ errorAction={errorSpy}
76
+ />
77
+ </TestWrapper>
78
+ );
79
+
80
+ mount(component);
81
+
82
+ expect(dispatchSpy, "was not called");
83
+ });
84
+
85
+ it("dispatches the success actions", () => {
86
+ state = state.setIn(
87
+ ["requestStates", "deletes", "key1", "key2", "state"],
88
+ Immutable.fromJS({
89
+ inProgress: false,
90
+ value: true,
91
+ error: false,
92
+ }),
93
+ );
94
+
95
+ const component = (
96
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
97
+ <TestComp
98
+ keys={["key1", "key2"]}
99
+ operation={requestStateOperations.delete}
100
+ successAction={successSpy}
101
+ errorAction={errorSpy}
102
+ />
103
+ </TestWrapper>
104
+ );
105
+
106
+ mount(component);
107
+
108
+ const resetAction = resetRequestState(["key1", "key2"], requestStateOperations.delete);
109
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
110
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
111
+ expect(successSpy, "was called");
112
+ expect(errorSpy, "was not called");
113
+ });
114
+
115
+ it("success callback is not called when undefined", () => {
116
+ state = state.setIn(
117
+ ["requestStates", "deletes", "key1", "key2", "state"],
118
+ Immutable.fromJS({
119
+ inProgress: false,
120
+ value: true,
121
+ error: false,
122
+ }),
123
+ );
124
+
125
+ const component = (
126
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
127
+ <TestComp keys={["key1", "key2"]} operation={requestStateOperations.delete} errorAction={errorSpy} />
128
+ </TestWrapper>
129
+ );
130
+
131
+ mount(component);
132
+
133
+ expect(successSpy, "was not called");
134
+ });
135
+
136
+ it("dispatches the error actions", () => {
137
+ state = state.setIn(
138
+ ["requestStates", "deletes", "key1", "key2", "state"],
139
+ Immutable.fromJS({
140
+ inProgress: false,
141
+ value: false,
142
+ error: true,
143
+ }),
144
+ );
145
+
146
+ const component = (
147
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
148
+ <TestComp
149
+ keys={["key1", "key2"]}
150
+ operation={requestStateOperations.delete}
151
+ successAction={successSpy}
152
+ errorAction={errorSpy}
153
+ />
154
+ </TestWrapper>
155
+ );
156
+
157
+ mount(component);
158
+
159
+ const resetAction = resetRequestState(["key1", "key2"], requestStateOperations.delete);
160
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
161
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
162
+ expect(successSpy, "was not called");
163
+ expect(errorSpy, "was called");
164
+ });
165
+
166
+ it("dispatches the error actions with a message", () => {
167
+ state = state.setIn(
168
+ ["requestStates", "deletes", "key1", "key2", "state"],
169
+ Immutable.fromJS({
170
+ inProgress: false,
171
+ value: false,
172
+ error: true,
173
+ errorResponse: "some error message",
174
+ }),
175
+ );
176
+
177
+ const component = (
178
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
179
+ <TestComp
180
+ keys={["key1", "key2"]}
181
+ operation={requestStateOperations.delete}
182
+ successAction={successSpy}
183
+ errorAction={errorSpy}
184
+ />
185
+ </TestWrapper>
186
+ );
187
+
188
+ mount(component);
189
+
190
+ const resetAction = resetRequestState(["key1", "key2"], requestStateOperations.delete);
191
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
192
+ expect(dispatchSpy, "to have a call satisfying", { args: [resetAction] });
193
+ expect(successSpy, "was not called");
194
+ expect(errorSpy, "to have a call satisfying", { args: ["some error message"] });
195
+ });
196
+
197
+ it("error action is not called when undefined", () => {
198
+ state = state.setIn(
199
+ ["requestStates", "deletes", "key1", "key2", "state"],
200
+ Immutable.fromJS({
201
+ inProgress: false,
202
+ value: false,
203
+ error: true,
204
+ }),
205
+ );
206
+
207
+ const component = (
208
+ <TestWrapper provider={{ store }} intlProvider={{ messages }} stylesProvider>
209
+ <TestComp keys={["key1", "key2"]} operation={requestStateOperations.delete} successAction={successSpy} />
210
+ </TestWrapper>
211
+ );
212
+
213
+ mount(component);
214
+
215
+ expect(errorSpy, "was not called");
216
+ });
217
+ });
@@ -18,11 +18,19 @@ import {
18
18
  INCREMENT_CUSTOMER_LOOKUPS_PAGE,
19
19
  REFRESH_PAGED_CUSTOMER_LOOKUPS,
20
20
  SET_PAGED_CUSTOMER_LOOKUPS_CURRENT_INFO,
21
+ SAVE_ORDER_LOOKUP_SUCCESS,
22
+ SAVE_CUSTOMER_LOOKUP_SUCCESS,
23
+ CREATE_PROFILE_DEFINITION_SUCCESS,
24
+ ADD_ORDER_LOOKUP_SUCCESS,
25
+ ADD_CUSTOMER_LOOKUP_SUCCESS,
26
+ UPDATE_PROFILE_DEFINITION_SUCCESS,
27
+ GET_ORDER_LOOKUP_SUCCESS,
28
+ GET_CUSTOMER_LOOKUP_SUCCESS,
21
29
  } from "../actions/metadata";
22
30
 
23
- export const ORDER_LOOKUP_MODULE_NAME = "order";
24
- export const CUSTOMER_LOOKUP_MODULE_NAME = "customer";
25
- export const PRODUCT_LOOKUP_MODULE_NAME = "product";
31
+ export const ORDER_MODULE_NAME = "order";
32
+ export const CUSTOMER_MODULE_NAME = "customer";
33
+ export const PRODUCT_MODULE_NAME = "product";
26
34
 
27
35
  const arrayToIndex = (items, keyField) =>
28
36
  items.reduce((index, item) => {
@@ -57,7 +65,7 @@ const lookupReducerHelper = {
57
65
  incrementPage: (moduleName, state, action) => {
58
66
  return state.setIn(["lookups", moduleName, "nextPageToLoad"], action.pageToLoad);
59
67
  },
60
- getPagedLookups: (moduleName, state, action) => {
68
+ getPagedLookups: (moduleName, state) => {
61
69
  const page = state.getIn(["lookups", moduleName, "nextPageToLoad"]) ?? 1;
62
70
  const index = state.getIn(["lookups", moduleName, "index"]);
63
71
  const [...keys] = index.keys();
@@ -95,48 +103,100 @@ const lookupReducerHelper = {
95
103
  const metadataReducer = (state = initialState, action) => {
96
104
  switch (action.type) {
97
105
  case INCREMENT_ORDER_LOOKUPS_PAGE: {
98
- return lookupReducerHelper.incrementPage(ORDER_LOOKUP_MODULE_NAME, state, action);
106
+ return lookupReducerHelper.incrementPage(ORDER_MODULE_NAME, state, action);
99
107
  }
100
108
  case REFRESH_PAGED_ORDER_LOOKUPS: {
101
- return lookupReducerHelper.getPagedLookups(ORDER_LOOKUP_MODULE_NAME, state, action);
109
+ return lookupReducerHelper.getPagedLookups(ORDER_MODULE_NAME, state);
102
110
  }
103
111
  case SET_PAGED_ORDER_LOOKUPS_CURRENT_INFO: {
104
- return lookupReducerHelper.setPagedCurrentInfo(ORDER_LOOKUP_MODULE_NAME, state, action);
112
+ return lookupReducerHelper.setPagedCurrentInfo(ORDER_MODULE_NAME, state, action);
105
113
  }
106
114
  case GET_ORDER_LOOKUPS_SUCCESS: {
107
- return lookupReducerHelper.getLookupsQuerySuccess(ORDER_LOOKUP_MODULE_NAME, state, action);
115
+ return lookupReducerHelper.getLookupsQuerySuccess(ORDER_MODULE_NAME, state, action);
108
116
  }
109
117
  case INCREMENT_CUSTOMER_LOOKUPS_PAGE: {
110
- return lookupReducerHelper.incrementPage(CUSTOMER_LOOKUP_MODULE_NAME, state, action);
118
+ return lookupReducerHelper.incrementPage(CUSTOMER_MODULE_NAME, state, action);
111
119
  }
112
120
  case REFRESH_PAGED_CUSTOMER_LOOKUPS: {
113
- return lookupReducerHelper.getPagedLookups(CUSTOMER_LOOKUP_MODULE_NAME, state, action);
121
+ return lookupReducerHelper.getPagedLookups(CUSTOMER_MODULE_NAME, state);
114
122
  }
115
123
  case SET_PAGED_CUSTOMER_LOOKUPS_CURRENT_INFO: {
116
- return lookupReducerHelper.setPagedCurrentInfo(CUSTOMER_LOOKUP_MODULE_NAME, state, action);
124
+ return lookupReducerHelper.setPagedCurrentInfo(CUSTOMER_MODULE_NAME, state, action);
117
125
  }
118
126
  case GET_CUSTOMER_LOOKUPS_SUCCESS: {
119
- return lookupReducerHelper.getLookupsQuerySuccess(CUSTOMER_LOOKUP_MODULE_NAME, state, action);
127
+ return lookupReducerHelper.getLookupsQuerySuccess(CUSTOMER_MODULE_NAME, state, action);
120
128
  }
121
129
  case GET_PRODUCT_LOOKUPS_SUCCESS: {
122
- return lookupReducerHelper.getLookupsQuerySuccess(PRODUCT_LOOKUP_MODULE_NAME, state, action);
130
+ return lookupReducerHelper.getLookupsQuerySuccess(PRODUCT_MODULE_NAME, state, action);
123
131
  }
124
132
  case GET_CUSTOMER_DEFINITIONS_SUCCESS: {
125
133
  const normalizedDefinitons = normalize(action.payload, definitionsListSchema);
126
- return state.setIn(["definitions", "customer"], Immutable.fromJS(normalizedDefinitons.entities.definitions));
134
+ return state.setIn(
135
+ ["definitions", CUSTOMER_MODULE_NAME],
136
+ Immutable.fromJS(normalizedDefinitons.entities.definitions),
137
+ );
127
138
  }
128
139
  case GET_ORDER_DEFINITIONS_SUCCESS: {
129
140
  const normalizedDefinitons = normalize(action.payload, definitionsListSchema);
130
- return state.setIn(["definitions", "order"], Immutable.fromJS(normalizedDefinitons.entities.definitions));
141
+ return state.setIn(
142
+ ["definitions", ORDER_MODULE_NAME],
143
+ Immutable.fromJS(normalizedDefinitons.entities.definitions),
144
+ );
131
145
  }
132
146
  case GET_PRODUCT_DEFINITIONS_SUCCESS: {
133
147
  const normalizedDefinitons = normalize(action.payload, productDefinitionsListSchema);
134
- return state.setIn(["definitions", "product"], Immutable.fromJS(normalizedDefinitons.entities.definitions));
148
+ return state.setIn(
149
+ ["definitions", PRODUCT_MODULE_NAME],
150
+ Immutable.fromJS(normalizedDefinitons.entities.definitions),
151
+ );
135
152
  }
136
153
  case GET_PROFILE_ATTRIBUTE_GROUPS_SUCCESS: {
137
154
  const normalizedData = normalize(action.payload?.profileAttributeGroups, profileAttributeGroupsListSchema);
138
155
  return state.set("profileAttributeGroups", Immutable.fromJS(normalizedData.entities.metadata));
139
156
  }
157
+ case SAVE_ORDER_LOOKUP_SUCCESS:
158
+ case GET_ORDER_LOOKUP_SUCCESS:
159
+ return state.setIn(
160
+ ["lookups", ORDER_MODULE_NAME, "index", action.payload.lookupName],
161
+ Immutable.fromJS(action.payload),
162
+ );
163
+
164
+ case ADD_ORDER_LOOKUP_SUCCESS: {
165
+ state = state.setIn(
166
+ ["lookups", ORDER_MODULE_NAME, "index", action.payload.lookupName],
167
+ Immutable.fromJS(action.payload),
168
+ );
169
+
170
+ return lookupReducerHelper.getPagedLookups(ORDER_MODULE_NAME, state);
171
+ }
172
+
173
+ case SAVE_CUSTOMER_LOOKUP_SUCCESS:
174
+ case GET_CUSTOMER_LOOKUP_SUCCESS:
175
+ return state.setIn(
176
+ ["lookups", CUSTOMER_MODULE_NAME, "index", action.payload.lookupName],
177
+ Immutable.fromJS(action.payload),
178
+ );
179
+
180
+ case ADD_CUSTOMER_LOOKUP_SUCCESS: {
181
+ state = state.setIn(
182
+ ["lookups", CUSTOMER_MODULE_NAME, "index", action.payload.lookupName],
183
+ Immutable.fromJS(action.payload),
184
+ );
185
+
186
+ return lookupReducerHelper.getPagedLookups(CUSTOMER_MODULE_NAME, state);
187
+ }
188
+
189
+ case CREATE_PROFILE_DEFINITION_SUCCESS:
190
+ return state.setIn(
191
+ ["definitions", CUSTOMER_MODULE_NAME, action.payload.entityTypeName],
192
+ Immutable.fromJS(action.payload),
193
+ );
194
+
195
+ case UPDATE_PROFILE_DEFINITION_SUCCESS:
196
+ return state.setIn(
197
+ ["definitions", CUSTOMER_MODULE_NAME, action.payload.entityTypeName],
198
+ Immutable.fromJS(action.payload),
199
+ );
140
200
  default:
141
201
  return state;
142
202
  }