@coorpacademy/app-review 0.0.21-alpha.8 → 0.1.2

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 (232) hide show
  1. package/es/actions/courses.d.ts +0 -1
  2. package/es/actions/{api → data}/is-fetching.d.ts +0 -1
  3. package/{lib/actions/api → es/actions/data}/validate-slide.d.ts +0 -1
  4. package/es/actions/finished-slides.d.ts +0 -1
  5. package/es/actions/index.d.ts +0 -1
  6. package/es/actions/navigation.d.ts +0 -1
  7. package/es/actions/review-status.d.ts +0 -1
  8. package/es/actions/slides.d.ts +0 -1
  9. package/es/actions/step-items.d.ts +0 -1
  10. package/es/actions/token.d.ts +0 -1
  11. package/es/common/index.d.ts +1 -1
  12. package/es/common/index.js +1 -0
  13. package/es/configure-store.d.ts +2 -3
  14. package/es/configure-store.js +3 -9
  15. package/es/fixtures/qcm-slide.d.ts +2 -0
  16. package/es/fixtures/qcm-slide.js +29 -0
  17. package/es/{temp-fixture.d.ts → fixtures/temp-fixture.d.ts} +1 -2
  18. package/es/helpers/css-register.js +2 -0
  19. package/es/index.d.ts +1 -3
  20. package/es/index.js +43 -27
  21. package/es/index.test.js +52 -0
  22. package/es/middlewares/on-start-app.d.ts +0 -1
  23. package/es/middlewares/on-start-app.js +2 -0
  24. package/es/reducers/courses.d.ts +0 -1
  25. package/es/reducers/data.d.ts +7 -0
  26. package/es/reducers/{api.js → data.js} +15 -8
  27. package/es/reducers/finished-slides.d.ts +1 -2
  28. package/es/reducers/finished-slides.js +17 -7
  29. package/es/reducers/index.d.ts +9 -14
  30. package/es/reducers/index.js +7 -6
  31. package/es/reducers/navigation.d.ts +0 -1
  32. package/es/reducers/navigation.js +1 -1
  33. package/es/reducers/review-status.d.ts +0 -1
  34. package/es/reducers/slides.d.ts +1 -2
  35. package/es/reducers/slides.js +37 -25
  36. package/es/reducers/step-items.d.ts +1 -2
  37. package/es/reducers/step-items.js +19 -12
  38. package/es/reducers/token.d.ts +4 -7
  39. package/es/reducers/token.js +3 -14
  40. package/es/services/fetch-demo.d.ts +0 -1
  41. package/es/services/fetch-demo.test.d.ts +0 -1
  42. package/es/services/fetch-responses.d.ts +0 -1
  43. package/es/services/fetch.mocks.d.ts +0 -1
  44. package/es/types/common.d.ts +0 -1
  45. package/es/types/data/index.d.ts +14 -0
  46. package/es/types/data/index.js +1 -0
  47. package/es/types/dispatchers.d.ts +1 -2
  48. package/es/types/finished-slides.d.ts +4 -2
  49. package/es/types/review-status.d.ts +0 -1
  50. package/es/types/slides.d.ts +4 -2
  51. package/es/types/states.d.ts +1 -3
  52. package/es/types/step-items.d.ts +4 -2
  53. package/es/types/store-state.d.ts +10 -10
  54. package/es/types/utils.d.ts +0 -1
  55. package/es/types/views.d.ts +9 -3
  56. package/lib/actions/courses.d.ts +0 -1
  57. package/lib/actions/{api → data}/is-fetching.d.ts +0 -1
  58. package/{es/actions/api → lib/actions/data}/validate-slide.d.ts +0 -1
  59. package/lib/actions/finished-slides.d.ts +0 -1
  60. package/lib/actions/index.d.ts +0 -1
  61. package/lib/actions/navigation.d.ts +0 -1
  62. package/lib/actions/review-status.d.ts +0 -1
  63. package/lib/actions/slides.d.ts +0 -1
  64. package/lib/actions/step-items.d.ts +0 -1
  65. package/lib/actions/token.d.ts +0 -1
  66. package/lib/common/index.d.ts +1 -1
  67. package/lib/common/index.js +1 -0
  68. package/lib/configure-store.d.ts +2 -3
  69. package/lib/configure-store.js +10 -66
  70. package/lib/fixtures/qcm-slide.d.ts +2 -0
  71. package/lib/fixtures/qcm-slide.js +29 -0
  72. package/lib/{temp-fixture.d.ts → fixtures/temp-fixture.d.ts} +1 -2
  73. package/lib/helpers/css-register.d.ts +1 -0
  74. package/lib/helpers/css-register.js +2 -0
  75. package/lib/index.d.ts +1 -3
  76. package/lib/index.js +52 -52
  77. package/lib/index.test.d.ts +1 -0
  78. package/lib/index.test.js +160 -0
  79. package/lib/middlewares/on-start-app.d.ts +0 -1
  80. package/lib/middlewares/on-start-app.js +2 -0
  81. package/lib/reducers/courses.d.ts +0 -1
  82. package/lib/reducers/courses.js +1 -17
  83. package/lib/reducers/data.d.ts +7 -0
  84. package/lib/reducers/{api.js → data.js} +15 -8
  85. package/lib/reducers/finished-slides.d.ts +1 -2
  86. package/lib/reducers/finished-slides.js +28 -45
  87. package/lib/reducers/index.d.ts +9 -14
  88. package/lib/reducers/index.js +7 -6
  89. package/lib/reducers/navigation.d.ts +0 -1
  90. package/lib/reducers/navigation.js +3 -19
  91. package/lib/reducers/review-status.d.ts +0 -1
  92. package/lib/reducers/slides.d.ts +1 -2
  93. package/lib/reducers/slides.js +58 -106
  94. package/lib/reducers/step-items.d.ts +1 -2
  95. package/lib/reducers/step-items.js +21 -52
  96. package/lib/reducers/token.d.ts +4 -7
  97. package/lib/reducers/token.js +3 -15
  98. package/lib/services/fetch-demo.d.ts +0 -1
  99. package/lib/services/fetch-demo.test.d.ts +0 -1
  100. package/lib/services/fetch-responses.d.ts +0 -1
  101. package/lib/services/fetch.mocks.d.ts +0 -1
  102. package/lib/types/common.d.ts +0 -1
  103. package/lib/types/data/index.d.ts +14 -0
  104. package/lib/types/data/index.js +1 -0
  105. package/lib/types/dispatchers.d.ts +1 -2
  106. package/lib/types/finished-slides.d.ts +4 -2
  107. package/lib/types/review-status.d.ts +0 -1
  108. package/lib/types/slides.d.ts +4 -2
  109. package/lib/types/states.d.ts +1 -3
  110. package/lib/types/step-items.d.ts +4 -2
  111. package/lib/types/store-state.d.ts +10 -10
  112. package/lib/types/utils.d.ts +0 -1
  113. package/lib/types/views.d.ts +9 -3
  114. package/package.json +10 -7
  115. package/src/common/index.ts +2 -0
  116. package/src/configure-store.ts +10 -20
  117. package/src/fixtures/qcm-slide.ts +31 -0
  118. package/src/{temp-fixture.ts → fixtures/temp-fixture.ts} +1 -1
  119. package/src/helpers/css-modules-require-hook.d.ts +4 -0
  120. package/src/helpers/css-register.ts +3 -0
  121. package/src/index.test.tsx +82 -0
  122. package/src/index.tsx +48 -34
  123. package/src/middlewares/on-start-app.ts +2 -0
  124. package/src/reducers/{api.ts → data.ts} +17 -14
  125. package/src/reducers/finished-slides.ts +22 -7
  126. package/src/reducers/index.ts +8 -6
  127. package/src/reducers/navigation.ts +1 -1
  128. package/src/reducers/slides.ts +38 -25
  129. package/src/reducers/step-items.ts +22 -12
  130. package/src/reducers/token.ts +5 -17
  131. package/src/types/data/index.ts +16 -0
  132. package/src/types/dispatchers.ts +1 -1
  133. package/src/types/finished-slides.ts +5 -2
  134. package/src/types/globals.d.ts +6 -0
  135. package/src/types/slides.ts +6 -3
  136. package/src/types/states.ts +1 -2
  137. package/src/types/step-items.ts +4 -1
  138. package/src/types/store-state.ts +11 -11
  139. package/src/types/views.tsx +9 -2
  140. package/es/actions/api/is-fetching.d.ts.map +0 -1
  141. package/es/actions/api/validate-slide.d.ts.map +0 -1
  142. package/es/actions/courses.d.ts.map +0 -1
  143. package/es/actions/finished-slides.d.ts.map +0 -1
  144. package/es/actions/index.d.ts.map +0 -1
  145. package/es/actions/navigation.d.ts.map +0 -1
  146. package/es/actions/review-status.d.ts.map +0 -1
  147. package/es/actions/slides.d.ts.map +0 -1
  148. package/es/actions/step-items.d.ts.map +0 -1
  149. package/es/actions/token.d.ts.map +0 -1
  150. package/es/common/index.d.ts.map +0 -1
  151. package/es/configure-store.d.ts.map +0 -1
  152. package/es/index.d.ts.map +0 -1
  153. package/es/middlewares/on-start-app.d.ts.map +0 -1
  154. package/es/reducers/api.d.ts +0 -12
  155. package/es/reducers/api.d.ts.map +0 -1
  156. package/es/reducers/courses.d.ts.map +0 -1
  157. package/es/reducers/finished-slides.d.ts.map +0 -1
  158. package/es/reducers/index.d.ts.map +0 -1
  159. package/es/reducers/navigation.d.ts.map +0 -1
  160. package/es/reducers/review-status.d.ts.map +0 -1
  161. package/es/reducers/slides.d.ts.map +0 -1
  162. package/es/reducers/step-items.d.ts.map +0 -1
  163. package/es/reducers/token.d.ts.map +0 -1
  164. package/es/services/fetch-demo.d.ts.map +0 -1
  165. package/es/services/fetch-demo.test.d.ts.map +0 -1
  166. package/es/services/fetch-responses.d.ts.map +0 -1
  167. package/es/services/fetch.mocks.d.ts.map +0 -1
  168. package/es/temp-fixture.d.ts.map +0 -1
  169. package/es/types/api/index.d.ts +0 -16
  170. package/es/types/api/index.d.ts.map +0 -1
  171. package/es/types/common.d.ts.map +0 -1
  172. package/es/types/dispatchers.d.ts.map +0 -1
  173. package/es/types/finished-slides.d.ts.map +0 -1
  174. package/es/types/review-status.d.ts.map +0 -1
  175. package/es/types/slides.d.ts.map +0 -1
  176. package/es/types/states.d.ts.map +0 -1
  177. package/es/types/step-items.d.ts.map +0 -1
  178. package/es/types/store-state.d.ts.map +0 -1
  179. package/es/types/utils.d.ts.map +0 -1
  180. package/es/types/views.d.ts.map +0 -1
  181. package/lib/actions/api/is-fetching.d.ts.map +0 -1
  182. package/lib/actions/api/validate-slide.d.ts.map +0 -1
  183. package/lib/actions/courses.d.ts.map +0 -1
  184. package/lib/actions/finished-slides.d.ts.map +0 -1
  185. package/lib/actions/index.d.ts.map +0 -1
  186. package/lib/actions/navigation.d.ts.map +0 -1
  187. package/lib/actions/review-status.d.ts.map +0 -1
  188. package/lib/actions/slides.d.ts.map +0 -1
  189. package/lib/actions/step-items.d.ts.map +0 -1
  190. package/lib/actions/token.d.ts.map +0 -1
  191. package/lib/common/index.d.ts.map +0 -1
  192. package/lib/configure-store.d.ts.map +0 -1
  193. package/lib/index.d.ts.map +0 -1
  194. package/lib/middlewares/on-start-app.d.ts.map +0 -1
  195. package/lib/reducers/api.d.ts +0 -12
  196. package/lib/reducers/api.d.ts.map +0 -1
  197. package/lib/reducers/courses.d.ts.map +0 -1
  198. package/lib/reducers/finished-slides.d.ts.map +0 -1
  199. package/lib/reducers/index.d.ts.map +0 -1
  200. package/lib/reducers/navigation.d.ts.map +0 -1
  201. package/lib/reducers/review-status.d.ts.map +0 -1
  202. package/lib/reducers/slides.d.ts.map +0 -1
  203. package/lib/reducers/step-items.d.ts.map +0 -1
  204. package/lib/reducers/token.d.ts.map +0 -1
  205. package/lib/services/fetch-demo.d.ts.map +0 -1
  206. package/lib/services/fetch-demo.test.d.ts.map +0 -1
  207. package/lib/services/fetch-responses.d.ts.map +0 -1
  208. package/lib/services/fetch.mocks.d.ts.map +0 -1
  209. package/lib/temp-fixture.d.ts.map +0 -1
  210. package/lib/types/api/index.d.ts +0 -16
  211. package/lib/types/api/index.d.ts.map +0 -1
  212. package/lib/types/common.d.ts.map +0 -1
  213. package/lib/types/dispatchers.d.ts.map +0 -1
  214. package/lib/types/finished-slides.d.ts.map +0 -1
  215. package/lib/types/review-status.d.ts.map +0 -1
  216. package/lib/types/slides.d.ts.map +0 -1
  217. package/lib/types/states.d.ts.map +0 -1
  218. package/lib/types/step-items.d.ts.map +0 -1
  219. package/lib/types/store-state.d.ts.map +0 -1
  220. package/lib/types/utils.d.ts.map +0 -1
  221. package/lib/types/views.d.ts.map +0 -1
  222. package/src/types/api/index.ts +0 -16
  223. /package/es/actions/{api → data}/is-fetching.js +0 -0
  224. /package/es/actions/{api → data}/validate-slide.js +0 -0
  225. /package/es/{temp-fixture.js → fixtures/temp-fixture.js} +0 -0
  226. /package/es/{types/api/index.js → helpers/css-register.d.ts} +0 -0
  227. /package/{lib/types/api/index.js → es/index.test.d.ts} +0 -0
  228. /package/lib/actions/{api → data}/is-fetching.js +0 -0
  229. /package/lib/actions/{api → data}/validate-slide.js +0 -0
  230. /package/lib/{temp-fixture.js → fixtures/temp-fixture.js} +0 -0
  231. /package/src/actions/{api → data}/is-fetching.ts +0 -0
  232. /package/src/actions/{api → data}/validate-slide.ts +0 -0
@@ -0,0 +1,31 @@
1
+ import {Slide} from '../types/slides';
2
+
3
+ export const slide: Slide = {
4
+ questionText: 'QCM',
5
+ answerUI: {
6
+ help: '__help',
7
+ model: {
8
+ type: 'qcm',
9
+ choices: [
10
+ {
11
+ selected: false,
12
+ title: 'choix1',
13
+ help: '(help choix1)',
14
+ ariaLabel: '__ariaLabel1'
15
+ },
16
+ {
17
+ selected: false,
18
+ title: 'choix2',
19
+ help: '(help choix2)',
20
+ ariaLabel: '__ariaLabel2'
21
+ },
22
+ {
23
+ selected: false,
24
+ title: 'choix3',
25
+ help: '(help choix3)',
26
+ ariaLabel: '__ariaLabel3'
27
+ }
28
+ ]
29
+ }
30
+ }
31
+ };
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable no-console */
2
- import {SlidesViewProps} from './types/views';
2
+ import {SlidesViewProps} from '../types/views';
3
3
 
4
4
  export const correctionPopinProps: SlidesViewProps['correctionPopinProps'] = {
5
5
  klf: {
@@ -0,0 +1,4 @@
1
+ declare module '@coorpacademy/css-modules-require-hook' {
2
+ export const cssRegister: () => void;
3
+ export default cssRegister;
4
+ }
@@ -0,0 +1,3 @@
1
+ import cssRegister from '@coorpacademy/css-modules-require-hook';
2
+
3
+ cssRegister();
@@ -0,0 +1,82 @@
1
+ import browserEnv from 'browser-env';
2
+ import test from 'ava';
3
+ import type {ExecutionContext} from 'ava';
4
+ import React from 'react';
5
+ import {render, fireEvent, act} from '@testing-library/react';
6
+ import {slide} from './fixtures/qcm-slide';
7
+ import type {AppOptions} from './types/common';
8
+ import AppReview from '.';
9
+
10
+ browserEnv({pretendToBeVisual: true});
11
+
12
+ const elementExists = (foundElements: NodeListOf<Element>): Element =>
13
+ foundElements && foundElements[0];
14
+
15
+ const sleep = (msToSleep: number): Promise<void> =>
16
+ new Promise(resolve => {
17
+ setTimeout(resolve, msToSleep);
18
+ });
19
+
20
+ const waitForChanges = async (msToWait = 3000): Promise<void> => {
21
+ await act(async () => {
22
+ await sleep(msToWait); // wait *just* a little longer than the timeout in the component
23
+ });
24
+ };
25
+
26
+ const LIMIT = 5;
27
+
28
+ const clickAllSlides = async (
29
+ t: ExecutionContext<unknown>,
30
+ container: HTMLElement,
31
+ accumulator = 0
32
+ ): Promise<void> => {
33
+ if (accumulator === LIMIT) return;
34
+
35
+ // last one needs to wait for more calculations && components updates
36
+ if (accumulator === 4)
37
+ await act(async () => {
38
+ await sleep(1000);
39
+ });
40
+
41
+ const validateButton = container.querySelectorAll(
42
+ `[data-name="slide-validate-button-${accumulator}"]`
43
+ );
44
+ t.truthy(elementExists(validateButton));
45
+
46
+ await act(async () => {
47
+ await fireEvent.click(validateButton[0]);
48
+ });
49
+
50
+ const nextButton = container.querySelectorAll(
51
+ `[data-name="next-question-button-${accumulator}"]`
52
+ );
53
+ t.truthy(elementExists(nextButton));
54
+
55
+ await act(async () => {
56
+ await fireEvent.click(nextButton[0]);
57
+ });
58
+
59
+ await clickAllSlides(t, container, accumulator + 1);
60
+ };
61
+
62
+ const appOptions: AppOptions = {
63
+ token: process.env.API_TEST_TOKEN || '',
64
+ slide
65
+ };
66
+
67
+ test('should validate all the slides (all correct scenario)', async t => {
68
+ t.plan(13);
69
+ const {container} = render(<AppReview options={appOptions} key={0} />);
70
+ await waitForChanges(1000);
71
+
72
+ const wrapper = container.querySelector('[data-name="slides-revision-container"]');
73
+ t.truthy(wrapper);
74
+
75
+ const stackedSlidesContainer = wrapper.querySelector('[data-name="stacked-slides-container"]');
76
+
77
+ t.truthy(stackedSlidesContainer);
78
+
79
+ await clickAllSlides(t, container);
80
+
81
+ t.pass();
82
+ });
package/src/index.tsx CHANGED
@@ -6,15 +6,15 @@ import configureStore from './configure-store';
6
6
  import {navigateTo, navigateBack, startApp} from './actions/navigation';
7
7
  import {updateSlidesOnNext, updateSlidesOnValidation} from './actions/slides';
8
8
  import {getCurrentViewName} from './reducers/navigation';
9
- import {SlidesViewStaticProps} from './types/views';
10
- import {AppOptions} from './types/common';
11
- import {StoreState} from './types/store-state';
12
- import {congratsProps, correctionPopinProps} from './temp-fixture';
9
+ import type {SlidesViewStaticProps} from './types/views';
10
+ import type {AppOptions} from './types/common';
11
+ import type {StoreState} from './types/store-state';
12
+ import {congratsProps, correctionPopinProps} from './fixtures/temp-fixture';
13
13
  import {updateFinishedSlides} from './actions/finished-slides';
14
14
  import {updateReviewStatus} from './actions/review-status';
15
15
  import {updateStepItemsOnValidation, updateStepItemsOnNext} from './actions/step-items';
16
- import {Dispatchers} from './types/dispatchers';
17
- import {validateSlide} from './actions/api/validate-slide';
16
+ import type {Dispatchers} from './types/dispatchers';
17
+ import {validateSlide} from './actions/data/validate-slide';
18
18
 
19
19
  // -----------------------------------------------------------------------------
20
20
 
@@ -36,22 +36,34 @@ const mapDispatchToProps: Dispatchers = {
36
36
  updateStepItemsOnNext,
37
37
  updateFinishedSlides
38
38
  };
39
- // StaticProps
40
- const mapStateToProps = (state: StoreState): StaticProps => ({
41
- viewName: getCurrentViewName(state),
42
- slides: {
43
- slides: state.slides,
44
- validate: {
45
- label: '__validate'
46
- },
47
- finishedSlides: state.finishedSlides,
48
- stepItems: state.stepItems,
49
- reviewStatus: state.reviewStatus,
50
- correctionPopinProps,
51
- congratsProps,
52
- slideValidationResult: state.api.entities.slideValidationResult
53
- }
54
- });
39
+
40
+ const mapStateToProps = (state: StoreState): StaticProps => {
41
+ return {
42
+ viewName: getCurrentViewName(state),
43
+ slides: {
44
+ headerProps: {
45
+ mode: '__revision_mode',
46
+ skillName: '__agility',
47
+ onQuitClick: (): void => {
48
+ // eslint-disable-next-line no-console
49
+ console.log('onQuitClick');
50
+ },
51
+ 'aria-label': 'aria-header-wrapper',
52
+ closeButtonAriaLabel: 'aria-close-button'
53
+ },
54
+ slides: state.ui.slides,
55
+ validate: {
56
+ label: '__validate'
57
+ },
58
+ finishedSlides: state.ui.finishedSlides,
59
+ stepItems: state.ui.stepItems,
60
+ reviewStatus: state.ui.reviewStatus,
61
+ correctionPopinProps,
62
+ congratsProps,
63
+ slideValidationResult: state.data.slideValidationResult
64
+ }
65
+ };
66
+ };
55
67
 
56
68
  // Props = StaticProps && Dispatchers
57
69
 
@@ -61,18 +73,22 @@ const App = connect(mapStateToProps, mapDispatchToProps)(AppReviewTemplate);
61
73
 
62
74
  const AppReview = ({options}: {options: AppOptions}): JSX.Element => {
63
75
  const [store, setStore] = useState(null);
76
+ const [appStarted, setAppStarted] = useState(false);
64
77
 
65
78
  useEffect(() => {
66
- const _configure = async (): Promise<void> => {
67
- const _store = await configureStore();
68
- _store.dispatch(startApp(options));
69
- setStore(_store);
70
- };
71
-
72
- _configure();
73
- }, [options]);
74
-
75
- if (!store) return null;
79
+ if (store) {
80
+ store.dispatch(startApp(options));
81
+ setAppStarted(true);
82
+ } else {
83
+ const _configure = async (): Promise<void> => {
84
+ const _store = await configureStore();
85
+ setStore(_store);
86
+ };
87
+ _configure();
88
+ }
89
+ }, [options, store]);
90
+
91
+ if (!store || !appStarted) return null;
76
92
 
77
93
  return (
78
94
  <Provider store={store}>
@@ -90,8 +106,6 @@ declare global {
90
106
  }
91
107
  }
92
108
 
93
- // type Props = {options: AppOptions};
94
-
95
109
  // -----------------------------------------------------------------------------
96
110
 
97
111
  export default AppReview;
@@ -15,6 +15,8 @@ const onStartApp: Middleware<{}, StoreState, Dispatch<Action>> =
15
15
  next =>
16
16
  (action: Action) => {
17
17
  if (action.type === START_APP) {
18
+ // eslint-disable-next-line no-warning-comments
19
+ // TODO: fetchProgression + fetchSlide à partir de la progression passée dans les options de l'app
18
20
  const {slide} = action.payload;
19
21
  if (slide) {
20
22
  const {token} = action.payload;
@@ -1,28 +1,31 @@
1
1
  import getOr from 'lodash/fp/getOr';
2
2
  import noop from 'lodash/fp/noop';
3
3
  import set from 'lodash/fp/set';
4
- import {IsFetching, IS_FETCHING_TRUE} from '../actions/api/is-fetching';
5
- import {ValidateSlide, VALIDATE_SLIDE} from '../actions/api/validate-slide';
6
- import {ApiState} from '../types/api';
4
+ import {StoreToken, STORE_TOKEN} from '../actions/token';
5
+ import {IsFetching, IS_FETCHING_TRUE} from '../actions/data/is-fetching';
6
+ import {ValidateSlide, VALIDATE_SLIDE} from '../actions/data/validate-slide';
7
+ import {DataState} from '../types/data';
8
+ import {setToken} from './token';
7
9
 
8
10
  const defaultState = {
9
- entities: {isFetching: true, slideValidationResult: null}
11
+ isFetching: true,
12
+ slideValidationResult: null,
13
+ token: null
10
14
  };
11
15
 
12
- type ApiActions = IsFetching | ValidateSlide;
16
+ type ApiActions = IsFetching | ValidateSlide | StoreToken;
13
17
 
14
18
  // eslint-disable-next-line default-param-last
15
- const api = (state = defaultState, action: ApiActions): ApiState => {
19
+ const data = (state: DataState = defaultState, action: ApiActions): DataState => {
16
20
  switch (action.type) {
21
+ case STORE_TOKEN: {
22
+ return setToken(action.payload, state);
23
+ }
17
24
  case VALIDATE_SLIDE: {
18
- const previousSlideNumber: number = getOr(
19
- -1,
20
- 'entities.slideValidationResult.slideNumber',
21
- state
22
- );
25
+ const previousSlideNumber: number = getOr(-1, 'slideValidationResult.slideNumber', state);
23
26
  // hard coded for now
24
27
  return set(
25
- ['entities', 'slideValidationResult'],
28
+ 'slideValidationResult',
26
29
  {
27
30
  slideNumber: previousSlideNumber + 1,
28
31
  result: 'success',
@@ -70,7 +73,7 @@ const api = (state = defaultState, action: ApiActions): ApiState => {
70
73
  );
71
74
  }
72
75
  case IS_FETCHING_TRUE: {
73
- return set('entities.isFetching', true, state);
76
+ return set('isFetching', true, state);
74
77
  }
75
78
 
76
79
  // case VALIDATE_SLIDE_FAILURE: {
@@ -82,4 +85,4 @@ const api = (state = defaultState, action: ApiActions): ApiState => {
82
85
  }
83
86
  };
84
87
 
85
- export default api;
88
+ export default data;
@@ -1,10 +1,22 @@
1
+ import forEach from 'lodash/fp/forEach';
1
2
  import {UpdateFinishedSlides, UPDATE_FINISHED_SLIDES} from '../actions/finished-slides';
3
+ import {slideNumbers} from '../common';
2
4
  import {FinishedSlides} from '../types/finished-slides';
3
5
 
6
+ const _forEach: <T>(
7
+ iteratee: (value: T[keyof T], index: number) => void,
8
+ collection: T
9
+ // @ts-expect-error to remove lodash's forEach iteratee args number cap
10
+ ) => void = forEach.convert({
11
+ cap: false
12
+ });
13
+
4
14
  // -----------------------------------------------------------------------------
5
15
 
6
16
  export type State = FinishedSlides;
7
- export const initialState: State = new Map<number, true>();
17
+ export const initialState: State = {
18
+ slideNumbers
19
+ };
8
20
 
9
21
  // -----------------------------------------------------------------------------
10
22
 
@@ -12,15 +24,18 @@ export const initialState: State = new Map<number, true>();
12
24
  const reducer = (state: State = initialState, action: UpdateFinishedSlides): State => {
13
25
  switch (action.type) {
14
26
  case UPDATE_FINISHED_SLIDES: {
27
+ const {slideNumbers: _slideNumbers, ...rest} = state;
15
28
  const {slideNumber, value} = action.payload;
16
- const _state = new Map();
29
+ const _state: State = {
30
+ slideNumbers: _slideNumbers
31
+ };
17
32
 
18
- // eslint-disable-next-line fp/no-loops
19
- for (const [index, previousValue] of state) {
20
- _state.set(index, previousValue);
21
- }
33
+ _forEach<Omit<State, 'slideNumbers'>>((finishedSlide, index) => {
34
+ const previousValue = finishedSlide;
35
+ _state[index] = previousValue;
36
+ }, rest);
22
37
 
23
- _state.set(slideNumber, value);
38
+ _state[slideNumber] = value;
24
39
  return _state;
25
40
  }
26
41
  default:
@@ -1,21 +1,23 @@
1
1
  import {combineReducers} from 'redux';
2
2
 
3
- import api from './api';
3
+ import data from './data';
4
4
  import courses from './courses';
5
5
  import finishedSlides from './finished-slides';
6
6
  import navigation from './navigation';
7
7
  import reviewStatus from './review-status';
8
8
  import slides from './slides';
9
9
  import stepItems from './step-items';
10
- import token from './token';
11
10
 
12
- export default combineReducers({
13
- api,
11
+ const ui = combineReducers({
14
12
  courses,
15
13
  finishedSlides,
16
14
  navigation,
17
15
  reviewStatus,
18
16
  slides,
19
- stepItems,
20
- token
17
+ stepItems
18
+ });
19
+
20
+ export default combineReducers({
21
+ ui,
22
+ data
21
23
  });
@@ -29,7 +29,7 @@ const reducer = (state: State = initialState, action: NavigateTo | NavigateBack)
29
29
  // -----------------------------------------------------------------------------
30
30
 
31
31
  export const getCurrentViewName = (appState: StoreState): ViewPath =>
32
- appState.navigation[appState.navigation.length - 1];
32
+ appState.ui.navigation[appState.ui.navigation.length - 1];
33
33
 
34
34
  // -----------------------------------------------------------------------------
35
35
 
@@ -1,10 +1,11 @@
1
+ import map from 'lodash/fp/map';
1
2
  import {
2
3
  SlidesAction,
3
4
  STORE_FIRST_SLIDE,
4
5
  UPDATE_SLIDES_ON_NEXT,
5
6
  UPDATE_SLIDES_ON_VALIDATION
6
7
  } from '../actions/slides';
7
- import {HIGHEST_INDEX, TOTAL_SLIDES_STACK} from '../common';
8
+ import {HIGHEST_INDEX, slideNumbers, TOTAL_SLIDES_STACK} from '../common';
8
9
  import {
9
10
  Slide,
10
11
  Slides,
@@ -17,10 +18,12 @@ import {
17
18
  export type State = Slides;
18
19
 
19
20
  const getInitialState = (): State => {
20
- const state: State = new Map();
21
+ const state: State = {
22
+ slideNumbers
23
+ };
21
24
  // eslint-disable-next-line fp/no-loops
22
25
  for (let index = 0; index < TOTAL_SLIDES_STACK; index++) {
23
- state.set(index, {hidden: false, position: index});
26
+ state[index] = {hidden: false, position: index};
24
27
  }
25
28
  return state;
26
29
  };
@@ -30,13 +33,17 @@ export const initialState: State = getInitialState();
30
33
  // -----------------------------------------------------------------------------
31
34
 
32
35
  const setFirstSlide = (state, slide: Slide): State => {
33
- const _state: State = new Map();
34
- // eslint-disable-next-line fp/no-loops
35
- for (const [index, previousValue] of state) {
36
+ const _state: State = {
37
+ slideNumbers
38
+ };
39
+ // eslint-disable-next-line lodash-fp/no-unused-result
40
+ map(index => {
41
+ const previousValue = state[index];
36
42
  // Only update the 1st one
37
43
  const content = index === 0 ? {...previousValue, ...slide} : {...previousValue};
38
- _state.set(index, {...content});
39
- }
44
+ _state[index] = {...content};
45
+ }, state.slideNumbers);
46
+
40
47
  return _state;
41
48
  };
42
49
 
@@ -44,27 +51,30 @@ const setFirstSlide = (state, slide: Slide): State => {
44
51
  // & then updates de remaining slides if this given change should impact their content
45
52
  const stateUpdateOnValidation = (state: State, payload: UpdateSlidesOnValidationPayload): State => {
46
53
  const {slideNumber, newSlideContent, numberOfFinishedSlides, nextSlide} = payload;
47
- const _state: State = new Map();
54
+ const _state: State = {
55
+ slideNumbers
56
+ };
48
57
 
49
- // eslint-disable-next-line fp/no-loops
50
- for (const [index, previousValue] of state) {
58
+ // eslint-disable-next-line lodash-fp/no-unused-result
59
+ map(index => {
60
+ const previousValue = state[index];
51
61
  // the current slide
52
62
  if (index === slideNumber) {
53
63
  // only one slide remaining, presets the next value
54
64
  if (numberOfFinishedSlides === HIGHEST_INDEX) {
55
- _state.set(index, {
65
+ _state[index] = {
56
66
  ...previousValue,
57
67
  nextSlide,
58
68
  position: newSlideContent.position,
59
69
  validationResult: newSlideContent.validationResult
60
- });
61
- } else _state.set(slideNumber, newSlideContent);
70
+ };
71
+ } else _state[slideNumber] = {...previousValue, ...newSlideContent};
62
72
  } else {
63
73
  // updates the rest of the slides here
64
74
  const {hidden, position} = previousValue;
65
- _state.set(index, {...nextSlide, endReview: newSlideContent.endReview, hidden, position});
75
+ _state[index] = {...nextSlide, endReview: newSlideContent.endReview, hidden, position};
66
76
  }
67
- }
77
+ }, state.slideNumbers);
68
78
 
69
79
  return _state;
70
80
  };
@@ -73,28 +83,31 @@ const stateUpdateOnValidation = (state: State, payload: UpdateSlidesOnValidation
73
83
  // & then updates de remaining slides (updates position to trigger animations)
74
84
  const stateUpdateOnNext = (state: State, payload: UpdateSlidesOnNextPayload): State => {
75
85
  const {slideNumber, newSlideContent, numberOfFinishedSlides} = payload;
76
- const _state: State = new Map();
86
+ const _state: State = {
87
+ slideNumbers
88
+ };
77
89
 
78
- // eslint-disable-next-line fp/no-loops
79
- for (const [index, previousValue] of state) {
90
+ // eslint-disable-next-line lodash-fp/no-unused-result
91
+ map(index => {
92
+ const previousValue = state[index];
80
93
  // the current slide
81
94
  if (index === slideNumber) {
82
95
  // when there is only one slide remaining, updates the slide value
83
- if (numberOfFinishedSlides === HIGHEST_INDEX) {
84
- _state.set(index, {...previousValue.nextSlide, position: previousValue.position});
85
- } else _state.set(slideNumber, newSlideContent);
96
+ if (numberOfFinishedSlides === HIGHEST_INDEX && previousValue.nextSlide) {
97
+ _state[index] = {...previousValue.nextSlide, position: previousValue.position};
98
+ } else _state[slideNumber] = newSlideContent;
86
99
  } else {
87
100
  // updates the rest of the slides here
88
101
  const {hidden, position, answerUI, questionText} = previousValue;
89
- _state.set(index, {
102
+ _state[index] = {
90
103
  hidden,
91
104
  position: position - 1, // position shift
92
105
  answerUI,
93
106
  questionText,
94
107
  endReview: newSlideContent.endReview
95
- });
108
+ };
96
109
  }
97
- }
110
+ }, state.slideNumbers);
98
111
 
99
112
  return _state;
100
113
  };
@@ -1,11 +1,13 @@
1
1
  import isNil from 'lodash/fp/isNil';
2
2
  import get from 'lodash/fp/get';
3
+ import has from 'lodash/fp/has';
4
+ import map from 'lodash/fp/map';
3
5
  import {
4
6
  StepItemsAction,
5
7
  UPDATE_STEP_ITEMS_ON_NEXT,
6
8
  UPDATE_STEP_ITEMS_ON_VALIDATION
7
9
  } from '../actions/step-items';
8
- import {HIGHEST_INDEX, TOTAL_SLIDES_STACK} from '../common';
10
+ import {HIGHEST_INDEX, slideNumbers, TOTAL_SLIDES_STACK} from '../common';
9
11
  import {SlideNumber} from '../types/slides';
10
12
  import {FinishedSlides} from '../types/finished-slides';
11
13
  import {StepItem, StepItems} from '../types/step-items';
@@ -15,11 +17,14 @@ import {StepItem, StepItems} from '../types/step-items';
15
17
  export type State = StepItems;
16
18
 
17
19
  const getInitialState = (): State => {
18
- const state: StepItems = new Map();
20
+ const state: StepItems = {
21
+ slideNumbers
22
+ };
23
+
19
24
  // eslint-disable-next-line fp/no-loops
20
25
  for (let index = 0; index < TOTAL_SLIDES_STACK; index++) {
21
26
  const current = index === 0;
22
- state.set(index, {current, value: `${index + 1}`, icon: null});
27
+ state[index] = {current, value: `${index + 1}`, icon: null};
23
28
  }
24
29
  return state;
25
30
  };
@@ -48,7 +53,7 @@ const calculateNextStepIndex = (
48
53
  const indexToVisit = getNextIndex(isNil(lastVisitedIndex) ? currentStepNumber : lastVisitedIndex);
49
54
 
50
55
  // if the index is already included in the correctly answered (finished) slides, then we proceed to check for the next one
51
- return finishedSlides.has(indexToVisit)
56
+ return has(indexToVisit, finishedSlides)
52
57
  ? calculateNextStepIndex(currentStepNumber, finishedSlides, indexToVisit)
53
58
  : indexToVisit;
54
59
  };
@@ -63,18 +68,23 @@ const recalculateStepItemsState = (
63
68
  stepItemToUpdateProps: StepItemToUpdateProps
64
69
  ): State => {
65
70
  const nextIndex: number | null = get('nextIndex', stepItemToUpdateProps);
66
- const _state: State = new Map();
67
- // eslint-disable-next-line fp/no-loops
68
- for (const [index, previousValue] of state) {
71
+ const _state: State = {
72
+ slideNumbers
73
+ };
74
+
75
+ // eslint-disable-next-line lodash-fp/no-unused-result
76
+ map(index => {
77
+ const previousValue = state[index];
69
78
  if (stepNumber === index)
70
- _state.set(stepNumber, {
79
+ _state[stepNumber] = {
71
80
  ...previousValue,
72
81
  ...stepItemToUpdateProps
73
- });
82
+ };
74
83
  /* only for UPDATE_STEP_ITEMS_ON_NEXT -> */ else if (nextIndex === index) {
75
- _state.set(index, {...previousValue, current: true});
76
- } else _state.set(index, previousValue);
77
- }
84
+ _state[index] = {...previousValue, current: true};
85
+ } else _state[index] = previousValue;
86
+ }, state.slideNumbers);
87
+
78
88
  return _state;
79
89
  };
80
90
 
@@ -1,29 +1,17 @@
1
- import {StoreToken, STORE_TOKEN} from '../actions/token';
1
+ import set from 'lodash/fp/set';
2
2
  import {StoreState} from '../types/store-state';
3
- import {TokenState as State} from '../types/states';
3
+ import {DataState} from '../types/data';
4
4
 
5
5
  // -----------------------------------------------------------------------------
6
6
 
7
- // export type State = string;
8
- export const initialState: State = null;
7
+ export const initialState: DataState['token'] = null;
9
8
 
10
9
  // -----------------------------------------------------------------------------
11
10
 
12
- // eslint-disable-next-line default-param-last
13
- const reducer = (state: State = initialState, action: StoreToken): State => {
14
- switch (action.type) {
15
- case STORE_TOKEN: {
16
- return action.payload;
17
- }
18
- default:
19
- return state;
20
- }
21
- };
11
+ export const setToken = (token: string, state: DataState): DataState => set('token', token, state);
22
12
 
23
13
  // -----------------------------------------------------------------------------
24
14
 
25
- export const getToken = (appState: StoreState): StoreState['token'] => appState.token;
15
+ export const getToken = (appState: StoreState): StoreState['data']['token'] => appState.data.token;
26
16
 
27
17
  // -----------------------------------------------------------------------------
28
-
29
- export default reducer;
@@ -0,0 +1,16 @@
1
+ import {AnswerUI} from '../slides';
2
+
3
+ export type DataState = {
4
+ isFetching?: boolean;
5
+ slideValidationResult?: {
6
+ slideNumber: number;
7
+ result: 'success' | 'failure';
8
+ // pass down the successExitNode if all slides are finished, not before
9
+ exitNode?: 'successExitNode' | 'failExitNode';
10
+ nextSlide: {
11
+ questionText?: string;
12
+ answerUI?: AnswerUI;
13
+ };
14
+ };
15
+ token?: string;
16
+ };
@@ -1,4 +1,4 @@
1
- import {validateSlide} from '../actions/api/validate-slide';
1
+ import {validateSlide} from '../actions/data/validate-slide';
2
2
  import {updateFinishedSlides} from '../actions/finished-slides';
3
3
  import {navigateBack, navigateTo} from '../actions/navigation';
4
4
  import {updateReviewStatus} from '../actions/review-status';