@coorpacademy/app-review 0.1.5 → 0.1.7

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 (103) hide show
  1. package/es/actions/data/progression.d.ts +30 -0
  2. package/es/actions/data/progression.js +12 -0
  3. package/es/actions/data/slides.d.ts +19 -15
  4. package/es/actions/data/slides.js +5 -0
  5. package/es/actions/data/token.d.ts +2 -2
  6. package/es/actions/data/token.js +1 -1
  7. package/es/actions/index.d.ts +2 -1
  8. package/es/configure-store.d.ts +2 -10
  9. package/es/configure-store.js +2 -1
  10. package/es/index.d.ts +1 -1
  11. package/es/index.js +43 -26
  12. package/es/index.test.js +5 -5
  13. package/es/middlewares/on-receive-progression.d.ts +6 -0
  14. package/es/middlewares/on-receive-progression.js +22 -0
  15. package/es/middlewares/on-receive-progression.test.d.ts +1 -0
  16. package/es/middlewares/on-receive-progression.test.js +43 -0
  17. package/es/middlewares/on-start-app.js +13 -5
  18. package/es/middlewares/on-start-app.test.d.ts +1 -0
  19. package/es/middlewares/on-start-app.test.js +53 -0
  20. package/es/reducers/data/index.d.ts +1 -1
  21. package/es/reducers/data/progression.d.ts +14 -8
  22. package/es/reducers/data/progression.js +17 -54
  23. package/es/reducers/data/slides.js +11 -6
  24. package/es/reducers/index.d.ts +1 -1
  25. package/es/services/fetch-skills.js +1 -2
  26. package/es/services/fetch-slide.d.ts +8 -0
  27. package/es/services/fetch-slide.js +26 -0
  28. package/es/services/post-progression.d.ts +8 -0
  29. package/es/services/post-progression.js +33 -0
  30. package/es/services/post-progression.mock.d.ts +5 -0
  31. package/es/services/post-progression.mock.js +31 -0
  32. package/es/services/post-progression.test.d.ts +1 -0
  33. package/es/services/post-progression.test.js +30 -0
  34. package/es/services/tools/fetch-responses.d.ts +1 -1
  35. package/es/services/tools/sleep.d.ts +1 -0
  36. package/es/services/tools/sleep.js +3 -0
  37. package/es/types/common.d.ts +8 -2
  38. package/es/types/ui-progression.d.ts +10 -0
  39. package/es/types/ui-progression.js +1 -0
  40. package/lib/actions/data/progression.d.ts +30 -0
  41. package/lib/actions/data/progression.js +12 -0
  42. package/lib/actions/data/slides.d.ts +19 -15
  43. package/lib/actions/data/slides.js +5 -0
  44. package/lib/actions/data/token.d.ts +2 -2
  45. package/lib/actions/data/token.js +1 -1
  46. package/lib/actions/index.d.ts +2 -1
  47. package/lib/configure-store.d.ts +2 -10
  48. package/lib/configure-store.js +2 -1
  49. package/lib/index.d.ts +1 -1
  50. package/lib/index.js +43 -26
  51. package/lib/index.test.js +5 -7
  52. package/lib/middlewares/on-receive-progression.d.ts +6 -0
  53. package/lib/middlewares/on-receive-progression.js +27 -0
  54. package/lib/middlewares/on-receive-progression.test.d.ts +1 -0
  55. package/lib/middlewares/on-receive-progression.test.js +88 -0
  56. package/lib/middlewares/on-start-app.js +15 -7
  57. package/lib/middlewares/on-start-app.test.d.ts +1 -0
  58. package/lib/middlewares/on-start-app.test.js +98 -0
  59. package/lib/reducers/data/index.d.ts +1 -1
  60. package/lib/reducers/data/progression.d.ts +14 -8
  61. package/lib/reducers/data/progression.js +17 -54
  62. package/lib/reducers/data/slides.js +11 -6
  63. package/lib/reducers/index.d.ts +1 -1
  64. package/lib/services/fetch-skills.js +2 -5
  65. package/lib/services/fetch-slide.d.ts +8 -0
  66. package/lib/services/fetch-slide.js +64 -0
  67. package/lib/services/post-progression.d.ts +8 -0
  68. package/lib/services/post-progression.js +77 -0
  69. package/lib/services/post-progression.mock.d.ts +5 -0
  70. package/lib/services/post-progression.mock.js +31 -0
  71. package/lib/services/post-progression.test.d.ts +1 -0
  72. package/lib/services/post-progression.test.js +84 -0
  73. package/lib/services/tools/fetch-responses.d.ts +1 -1
  74. package/lib/services/tools/sleep.d.ts +1 -0
  75. package/lib/services/tools/sleep.js +5 -0
  76. package/lib/types/common.d.ts +8 -2
  77. package/lib/types/ui-progression.d.ts +10 -0
  78. package/lib/types/ui-progression.js +1 -0
  79. package/package.json +4 -5
  80. package/readme.md +4 -5
  81. package/src/actions/data/progression.ts +50 -0
  82. package/src/actions/data/slides.ts +25 -17
  83. package/src/actions/data/token.ts +2 -2
  84. package/src/actions/index.ts +4 -1
  85. package/src/configure-store.ts +5 -13
  86. package/src/index.test.tsx +5 -7
  87. package/src/index.tsx +54 -29
  88. package/src/middlewares/on-receive-progression.test.ts +60 -0
  89. package/src/middlewares/on-receive-progression.ts +42 -0
  90. package/src/middlewares/on-start-app.test.ts +68 -0
  91. package/src/middlewares/on-start-app.ts +13 -5
  92. package/src/reducers/data/progression.ts +34 -69
  93. package/src/reducers/data/slides.ts +13 -8
  94. package/src/services/fetch-skills.ts +1 -2
  95. package/src/services/fetch-slide.ts +43 -0
  96. package/src/services/post-progression.mock.ts +35 -0
  97. package/src/services/post-progression.test.ts +41 -0
  98. package/src/services/post-progression.ts +50 -0
  99. package/src/services/tools/fetch-responses.ts +1 -1
  100. package/src/services/tools/sleep.ts +4 -0
  101. package/src/types/common.ts +8 -2
  102. package/src/types/globals.d.ts +1 -0
  103. package/src/types/ui-progression.ts +25 -0
@@ -0,0 +1,30 @@
1
+ export declare type ProgressionFromAPI = {
2
+ _id: string;
3
+ state: {
4
+ isCorrect: boolean;
5
+ step: {
6
+ current: number;
7
+ };
8
+ nextContent: {
9
+ type: 'success' | 'slide';
10
+ ref: 'successExitNode' | string;
11
+ };
12
+ pendingSlides: [];
13
+ };
14
+ };
15
+ export declare const RECEIVE_PROGRESSION = "@@data/progression/RECEIVE_PROGRESSION";
16
+ export declare const ERROR_CREATING_PROGRESSION = "@@data/progression/ERROR_CREATING_PROGRESSION";
17
+ export declare type ReceiveProgressionPayload = {
18
+ progression: ProgressionFromAPI;
19
+ token: string;
20
+ };
21
+ export declare type ReceiveProgression = {
22
+ type: typeof RECEIVE_PROGRESSION;
23
+ payload: ReceiveProgressionPayload;
24
+ };
25
+ export declare type ErrorCreatingProgression = {
26
+ type: typeof ERROR_CREATING_PROGRESSION;
27
+ payload: Error;
28
+ };
29
+ export declare const receiveProgression: (payload: ReceiveProgressionPayload) => ReceiveProgression;
30
+ export declare const errorCreatingProgression: (error: Error) => ErrorCreatingProgression;
@@ -0,0 +1,12 @@
1
+ // -----------------------------------------------------------------------------
2
+ export const RECEIVE_PROGRESSION = '@@data/progression/RECEIVE_PROGRESSION';
3
+ export const ERROR_CREATING_PROGRESSION = '@@data/progression/ERROR_CREATING_PROGRESSION';
4
+ // -----------------------------------------------------------------------------
5
+ export const receiveProgression = (payload) => ({
6
+ type: RECEIVE_PROGRESSION,
7
+ payload
8
+ });
9
+ export const errorCreatingProgression = (error) => ({
10
+ type: ERROR_CREATING_PROGRESSION,
11
+ payload: error
12
+ });
@@ -1,32 +1,35 @@
1
- import { Slide as SlideFromAPI } from '../../types/slides';
1
+ import { Slide as UISlide } from '../../types/slides';
2
2
  export declare const STORE_FIRST_SLIDE = "@@slide/STORE_FIRST_SLIDE";
3
3
  export declare const UPDATE_SLIDES_ON_VALIDATION = "@@slide/UPDATE_SLIDES_ON_VALIDATION";
4
4
  export declare const UPDATE_SLIDES_ON_NEXT = "@@slide/UPDATE_SLIDES_ON_NEXT";
5
5
  export declare const VALIDATE_SLIDE = "@@slide/VALIDATE";
6
6
  export declare const FETCH_NEXT_CONTENT = "@@slide/FETCH_NEXT_CONTENT";
7
+ export declare const ERROR_FETCHING_SLIDE = "@@data/slide/ERROR_FETCHING_SLIDE";
7
8
  declare type SlideUIAnimations = 'unstack' | 'restack';
8
- export declare type Slide = SlideFromAPI & {
9
+ export declare type Slide = UISlide & {
9
10
  hidden?: boolean;
10
11
  position: number;
11
12
  animationType?: SlideUIAnimations;
12
13
  isCorrect?: boolean;
13
14
  endReview?: boolean;
14
- nextSlide?: Omit<Slide, 'endReview' | 'hidden' | 'position' | 'nextSlide'>;
15
+ nextContent?: Omit<Slide, 'endReview' | 'hidden' | 'position' | 'nextContent'>;
16
+ };
17
+ export declare type SlideFromAPI = {
18
+ question: {
19
+ content: {
20
+ choices: Record<string, unknown>[];
21
+ };
22
+ };
23
+ klf: string;
24
+ universalRef: string;
15
25
  };
16
26
  export declare type ValidationPayload = {
17
27
  slideNumber: number;
18
28
  newSlideContent: Slide;
19
29
  numberOfFinishedSlides: number;
20
- nextSlide: Slide;
21
- };
22
- export declare type OnNextPayload = Omit<ValidationPayload, 'nextSlide'>;
23
- export declare type FetchNextPayload = {
24
- answer: string[];
25
- content: {
26
- ref: string;
27
- type: string;
28
- };
30
+ nextContent: Slide;
29
31
  };
32
+ export declare type OnNextPayload = Omit<ValidationPayload, 'nextContent'>;
30
33
  export declare type StoreFirstSlide = {
31
34
  type: typeof STORE_FIRST_SLIDE;
32
35
  payload: SlideFromAPI;
@@ -42,13 +45,14 @@ export declare type UpdateSlidesOnNext = {
42
45
  export declare type ValidateSlide = {
43
46
  type: typeof VALIDATE_SLIDE;
44
47
  };
45
- export declare type FetchNextContent = {
46
- type: typeof FETCH_NEXT_CONTENT;
47
- payload: FetchNextPayload;
48
+ export declare type ErrorFetchingSlide = {
49
+ type: typeof ERROR_FETCHING_SLIDE;
50
+ payload: Error;
48
51
  };
49
52
  export declare type SlidesAction = StoreFirstSlide | UpdateSlidesOnValidation | UpdateSlidesOnNext;
50
53
  export declare const storeFirstSlide: (slide: SlideFromAPI) => StoreFirstSlide;
51
54
  export declare const updateSlidesOnValidation: (payload: ValidationPayload) => UpdateSlidesOnValidation;
52
55
  export declare const updateSlidesOnNext: (payload: OnNextPayload) => UpdateSlidesOnNext;
53
56
  export declare const validateSlide: () => ValidateSlide;
57
+ export declare const errorFetchingSlide: (error: Error) => ErrorFetchingSlide;
54
58
  export {};
@@ -4,6 +4,7 @@ export const UPDATE_SLIDES_ON_VALIDATION = '@@slide/UPDATE_SLIDES_ON_VALIDATION'
4
4
  export const UPDATE_SLIDES_ON_NEXT = '@@slide/UPDATE_SLIDES_ON_NEXT';
5
5
  export const VALIDATE_SLIDE = '@@slide/VALIDATE';
6
6
  export const FETCH_NEXT_CONTENT = '@@slide/FETCH_NEXT_CONTENT';
7
+ export const ERROR_FETCHING_SLIDE = '@@data/slide/ERROR_FETCHING_SLIDE';
7
8
  // -----------------------------------------------------------------------------
8
9
  export const storeFirstSlide = (slide) => ({
9
10
  type: STORE_FIRST_SLIDE,
@@ -20,3 +21,7 @@ export const updateSlidesOnNext = (payload) => ({
20
21
  export const validateSlide = () => ({
21
22
  type: VALIDATE_SLIDE
22
23
  });
24
+ export const errorFetchingSlide = (error) => ({
25
+ type: ERROR_FETCHING_SLIDE,
26
+ payload: error
27
+ });
@@ -1,6 +1,6 @@
1
- export declare const STORE_TOKEN = "@@token/STORE_TOKEN";
1
+ export declare const STORE_TOKEN = "@@data/token/STORE_TOKEN";
2
2
  export declare type StoreToken = {
3
- type: '@@token/STORE_TOKEN';
3
+ type: typeof STORE_TOKEN;
4
4
  payload: string;
5
5
  };
6
6
  export declare const storeToken: (token: string) => StoreToken;
@@ -1,4 +1,4 @@
1
- export const STORE_TOKEN = '@@token/STORE_TOKEN';
1
+ export const STORE_TOKEN = '@@data/token/STORE_TOKEN';
2
2
  export const storeToken = (token) => ({
3
3
  type: STORE_TOKEN,
4
4
  payload: token
@@ -5,7 +5,8 @@ import { updateFinishedSlides } from './ui/finished-slides';
5
5
  import { navigateBack, navigateTo, NavigateBack, NavigateTo, StartApp } from './ui/navigation';
6
6
  import { updateReviewStatus } from './ui/review-status';
7
7
  import { updateStepItemsOnValidation, updateStepItemsOnNext } from './ui/step-items';
8
- export declare type Action = NavigateBack | NavigateTo | ReceivedSkills | ErrorFetchingSkills | StartApp | StoreFirstSlide | StoreToken;
8
+ import { ErrorCreatingProgression, ReceiveProgression } from './data/progression';
9
+ export declare type Action = NavigateBack | NavigateTo | ReceivedSkills | ErrorFetchingSkills | StartApp | StoreFirstSlide | StoreToken | ErrorCreatingProgression | ReceiveProgression;
9
10
  export declare type Dispatchers = {
10
11
  navigateTo: typeof navigateTo;
11
12
  navigateBack: typeof navigateBack;
@@ -6,18 +6,10 @@ import { NavigationState } from './reducers/ui/navigation';
6
6
  import { ReviewStatusState } from './reducers/ui/review-status';
7
7
  import { StepItemsState } from './reducers/ui/step-items';
8
8
  import { FinishedSlidesState } from './reducers/ui/finished-slides';
9
- import { AnswerUI } from './types/slides';
9
+ import { ProgressionState } from './reducers/data/progression';
10
10
  declare type DataState = {
11
11
  isFetching?: boolean;
12
- progression?: {
13
- slideNumber: number;
14
- isCorrect?: boolean;
15
- exitNode?: 'successExitNode' | 'failExitNode';
16
- nextSlide?: {
17
- questionText?: string;
18
- answerUI?: AnswerUI;
19
- };
20
- } | null;
12
+ progression?: ProgressionState;
21
13
  skills: SkillsState;
22
14
  slides: SlidesState;
23
15
  token?: TokenState;
@@ -2,6 +2,7 @@ import { applyMiddleware, compose, createStore } from 'redux';
2
2
  import thunk from 'redux-thunk';
3
3
  import rootReducer from './reducers';
4
4
  import onStartApp from './middlewares/on-start-app';
5
+ import onReceiveProgression from './middlewares/on-receive-progression';
5
6
  // -----------------------------------------------------------------------------
6
7
  export default function configureStore() {
7
8
  const _compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
@@ -11,7 +12,7 @@ export default function configureStore() {
11
12
  traceLimit: 25
12
13
  })
13
14
  : compose;
14
- const enhancer = _compose(applyMiddleware(thunk, onStartApp));
15
+ const enhancer = _compose(applyMiddleware(thunk, onStartApp, onReceiveProgression));
15
16
  const store = createStore(rootReducer, undefined, enhancer);
16
17
  return store;
17
18
  }
package/es/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { AppOptions } from './types/common';
2
2
  declare const AppReview: ({ options }: {
3
3
  options: AppOptions;
4
- }) => JSX.Element;
4
+ }) => JSX.Element | null;
5
5
  declare global {
6
6
  interface Window {
7
7
  __REDUX_DEVTOOLS_EXTENSION__?: boolean;
package/es/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { connect, Provider } from 'react-redux';
3
3
  import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
4
+ import { TemplateContext } from '@coorpacademy/components/es/template/app-review/template-context';
4
5
  import configureStore from './configure-store';
5
6
  import { congratsProps, correctionPopinProps } from './fixtures/temp-fixture';
6
7
  import { updateSlidesOnNext, updateSlidesOnValidation, validateSlide } from './actions/data/slides';
@@ -21,29 +22,38 @@ const mapDispatchToProps = {
21
22
  updateFinishedSlides
22
23
  };
23
24
  const getCurrentViewName = (storeState) => storeState.ui.navigation[storeState.ui.navigation.length - 1];
24
- const mapStateToSkillsProps = (state) => ({
25
- title: '@todo title',
26
- titleNoSkills: '@todo titleNoSkills',
27
- textNoSkills: '@todo textNoSkills',
28
- iconSkillAriaLabel: '@todo iconSkillAriaLabel',
29
- isLoading: false,
30
- isLoadingAriaLabel: '@todo loading',
31
- listSkills: state.data.skills.map(skill => ({
32
- 'aria-label': '',
33
- isCustom: skill.custom,
34
- skillTitle: skill.name,
35
- skillAriaLabel: '@todo skill aria label',
36
- buttonLabel: '@todo button',
37
- buttonAriaLabel: '@todo button aria label',
38
- reviseLabel: '@todo revise',
39
- reviseAriaLabel: '@todo revise aria label',
40
- // eslint-disable-next-line no-console
41
- onClick: () => console.log('@todo plug dispatcher select skill')
42
- }))
43
- });
44
- const mapStateToProps = (state) => ({
45
- viewName: getCurrentViewName(state),
46
- slides: {
25
+ // -----------------------------------------------------------------------------
26
+ const mapStateToSkillsProps = (state) => {
27
+ if (!state.data.skills) {
28
+ return null;
29
+ }
30
+ return {
31
+ title: '@todo title',
32
+ titleNoSkills: '@todo titleNoSkills',
33
+ textNoSkills: '@todo textNoSkills',
34
+ iconSkillAriaLabel: '@todo iconSkillAriaLabel',
35
+ isLoading: false,
36
+ isLoadingAriaLabel: '@todo loading',
37
+ listSkills: state.data.skills.map(skill => ({
38
+ 'aria-label': '',
39
+ isCustom: skill.custom,
40
+ skillTitle: skill.name,
41
+ skillAriaLabel: '@todo skill aria label',
42
+ buttonLabel: '@todo button',
43
+ buttonAriaLabel: '@todo button aria label',
44
+ reviseLabel: '@todo revise',
45
+ reviseAriaLabel: '@todo revise aria label',
46
+ // eslint-disable-next-line no-console
47
+ onClick: () => console.log('@todo plug dispatcher select skill')
48
+ }))
49
+ };
50
+ };
51
+ // -----------------------------------------------------------------------------
52
+ const mapStateToSlidesProps = (state) => {
53
+ if (!state.data.slides) {
54
+ return null;
55
+ }
56
+ return {
47
57
  headerProps: {
48
58
  mode: '__revision_mode',
49
59
  skillName: '__agility',
@@ -64,7 +74,12 @@ const mapStateToProps = (state) => ({
64
74
  correctionPopinProps,
65
75
  congratsProps,
66
76
  progression: state.data.progression
67
- },
77
+ };
78
+ };
79
+ // -----------------------------------------------------------------------------
80
+ const mapStateToProps = (state) => ({
81
+ viewName: getCurrentViewName(state),
82
+ slides: mapStateToSlidesProps(state),
68
83
  skills: mapStateToSkillsProps(state)
69
84
  });
70
85
  // Props = StaticProps && Dispatchers
@@ -87,9 +102,11 @@ const AppReview = ({ options }) => {
87
102
  }
88
103
  }, [options, store]);
89
104
  if (!store || !appStarted)
90
- return React.createElement("div", null);
105
+ return null;
106
+ const { templateContext: values } = options;
91
107
  return (React.createElement(Provider, { store: store },
92
- React.createElement(App, null)));
108
+ React.createElement(TemplateContext, { values: values },
109
+ React.createElement(App, null))));
93
110
  };
94
111
  // -----------------------------------------------------------------------------
95
112
  export default AppReview;
package/es/index.test.js CHANGED
@@ -2,13 +2,10 @@ import browserEnv from 'browser-env';
2
2
  import test from 'ava';
3
3
  import React from 'react';
4
4
  import { render, fireEvent, act } from '@testing-library/react';
5
- import { slide } from './fixtures/qcm-slide';
5
+ import { sleep } from './services/tools/sleep';
6
6
  import AppReview from '.';
7
7
  browserEnv({ pretendToBeVisual: true });
8
8
  const elementExists = (foundElements) => foundElements && foundElements[0];
9
- const sleep = (msToSleep) => new Promise(resolve => {
10
- setTimeout(resolve, msToSleep);
11
- });
12
9
  const waitForChanges = async (msToWait = 3000) => {
13
10
  await act(async () => {
14
11
  await sleep(msToWait); // wait *just* a little longer than the timeout in the component
@@ -37,7 +34,10 @@ const clickAllSlides = async (t, container, accumulator = 0) => {
37
34
  };
38
35
  const appOptions = {
39
36
  token: process.env.API_TEST_TOKEN || '',
40
- slide
37
+ templateContext: {
38
+ theme: { color: { primary: '#123' } }
39
+ },
40
+ skillRef: 'skill_NJC0jFKoH'
41
41
  };
42
42
  test('should validate all the slides (all correct scenario)', async (t) => {
43
43
  t.plan(13);
@@ -0,0 +1,6 @@
1
+ import type { Middleware, Store } from 'redux';
2
+ import { Dispatch } from 'redux';
3
+ import { ErrorFetchingSlide, StoreFirstSlide } from '../actions/data/slides';
4
+ import { ReceiveProgression } from '../actions/data/progression';
5
+ declare const onReceiveProgression: Middleware<{}, Store, Dispatch<ReceiveProgression | StoreFirstSlide | ErrorFetchingSlide>>;
6
+ export default onReceiveProgression;
@@ -0,0 +1,22 @@
1
+ import get from 'lodash/fp/get';
2
+ // eslint-disable-next-line import/no-named-as-default
3
+ import fetchSlide from '../services/fetch-slide';
4
+ import { errorFetchingSlide, storeFirstSlide } from '../actions/data/slides';
5
+ import { RECEIVE_PROGRESSION } from '../actions/data/progression';
6
+ const onReceiveProgression = ({ dispatch }) => next => (action) => {
7
+ if (action.type === RECEIVE_PROGRESSION) {
8
+ const { progression, token } = action.payload;
9
+ const slideRef = get('state.nextContent.ref', progression);
10
+ // TOASK: do we need to check for exit nodes before fetching??
11
+ // TODO: To implement fetchSlide in next ticket
12
+ fetchSlide(slideRef, token)
13
+ .then(slide => {
14
+ return dispatch(storeFirstSlide(slide));
15
+ })
16
+ .catch(err => {
17
+ return dispatch(errorFetchingSlide(err));
18
+ });
19
+ }
20
+ return next(action);
21
+ };
22
+ export default onReceiveProgression;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import test from 'ava';
2
+ import { receiveProgression } from '../actions/data/progression';
3
+ import { mockedProgression } from '../services/post-progression.mock';
4
+ import { sleep } from '../services/tools/sleep';
5
+ import { STORE_FIRST_SLIDE } from '../actions/data/slides';
6
+ import onReceiveProgression from './on-receive-progression';
7
+ const appOptions = {
8
+ token: process.env.API_TEST_TOKEN || ''
9
+ };
10
+ const otherAction = (payload) => ({
11
+ type: '@@other/OTHER',
12
+ payload
13
+ });
14
+ test('should not dispatch anything if action is not RECEIVE_PROGRESSION', t => {
15
+ t.plan(1);
16
+ const dispatch = () => {
17
+ t.fail();
18
+ };
19
+ const next = () => {
20
+ return t.pass();
21
+ };
22
+ onReceiveProgression({ dispatch })(next)(otherAction('other'));
23
+ });
24
+ test('should dispatch actions: STORE_FIRST_SLIDE', async (t) => {
25
+ t.plan(2);
26
+ const dispatch = (action) => {
27
+ switch (action.type) {
28
+ case STORE_FIRST_SLIDE: {
29
+ const slide = action.payload;
30
+ t.deepEqual(slide, {});
31
+ return;
32
+ }
33
+ default:
34
+ t.fail();
35
+ break;
36
+ }
37
+ };
38
+ const next = () => {
39
+ return t.pass();
40
+ };
41
+ onReceiveProgression({ dispatch })(next)(receiveProgression({ token: appOptions.token, progression: mockedProgression }));
42
+ await sleep(1000); // wait for the .then to fire
43
+ });
@@ -1,16 +1,24 @@
1
1
  import { VIEWS } from '../common';
2
2
  import { storeToken } from '../actions/data/token';
3
3
  import { receivedSkills, errorFetchingSkills } from '../actions/data/skills';
4
- import { storeFirstSlide } from '../actions/data/slides';
5
4
  import { navigateTo, START_APP } from '../actions/ui/navigation';
6
5
  // eslint-disable-next-line import/no-named-as-default
7
6
  import fetchSkills from '../services/fetch-skills';
7
+ // eslint-disable-next-line import/no-named-as-default
8
+ import postProgression from '../services/post-progression';
9
+ import { errorCreatingProgression, receiveProgression } from '../actions/data/progression';
8
10
  const onStartApp = ({ dispatch }) => next => (action) => {
9
11
  if (action.type === START_APP) {
10
- const { slide, token } = action.payload;
12
+ const { skillRef, token } = action.payload;
11
13
  dispatch(storeToken(token));
12
- if (slide) {
13
- dispatch(storeFirstSlide(slide));
14
+ if (skillRef) {
15
+ postProgression(skillRef, token)
16
+ .then(progression => {
17
+ return dispatch(receiveProgression({ progression, token }));
18
+ })
19
+ .catch(err => {
20
+ return dispatch(errorCreatingProgression(err));
21
+ });
14
22
  }
15
23
  else {
16
24
  fetchSkills(token)
@@ -21,7 +29,7 @@ const onStartApp = ({ dispatch }) => next => (action) => {
21
29
  return dispatch(errorFetchingSkills(err));
22
30
  });
23
31
  }
24
- const initialView = slide ? VIEWS.slides : VIEWS.skills;
32
+ const initialView = skillRef ? VIEWS.slides : VIEWS.skills;
25
33
  dispatch(navigateTo(initialView));
26
34
  }
27
35
  return next(action);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ import test from 'ava';
2
+ import { STORE_TOKEN } from '../actions/data/token';
3
+ import { RECEIVE_PROGRESSION } from '../actions/data/progression';
4
+ import { NAVIGATE_TO, startApp } from '../actions/ui/navigation';
5
+ import { mockedProgression } from '../services/post-progression.mock';
6
+ import { VIEWS } from '../common';
7
+ import { sleep } from '../services/tools/sleep';
8
+ import onStartApp from './on-start-app';
9
+ const appOptions = {
10
+ token: process.env.API_TEST_TOKEN || '',
11
+ skillRef: 'skill_NJC0jFKoH'
12
+ };
13
+ const otherAction = (payload) => ({
14
+ type: '@@other/OTHER',
15
+ payload
16
+ });
17
+ test('should not dispatch anything if action is not START_APP', t => {
18
+ t.plan(1);
19
+ const dispatch = () => {
20
+ t.fail();
21
+ };
22
+ const next = () => {
23
+ return t.pass();
24
+ };
25
+ onStartApp({ dispatch })(next)(otherAction('other'));
26
+ });
27
+ test('should dispatch actions: STORE_TOKEN && RECEIVE_PROGRESSION if an skillRef is given, on a successful response', async (t) => {
28
+ t.plan(5);
29
+ const dispatch = (action) => {
30
+ switch (action.type) {
31
+ case STORE_TOKEN:
32
+ t.is(action.payload, appOptions.token);
33
+ return;
34
+ case RECEIVE_PROGRESSION: {
35
+ const { token, progression } = action.payload;
36
+ t.is(token, appOptions.token);
37
+ t.deepEqual(progression, JSON.parse(JSON.stringify(mockedProgression)));
38
+ return;
39
+ }
40
+ case NAVIGATE_TO:
41
+ t.is(action.payload, VIEWS.slides);
42
+ return;
43
+ default:
44
+ t.fail();
45
+ break;
46
+ }
47
+ };
48
+ const next = () => {
49
+ return t.pass();
50
+ };
51
+ onStartApp({ dispatch })(next)(startApp(appOptions));
52
+ await sleep(1000); // wait for the .then to fire
53
+ });
@@ -3,5 +3,5 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
3
3
  skills: import("../../types/skills").Skills;
4
4
  slides: import("./slides").SlidesState;
5
5
  token: import("./token").TokenState;
6
- }>, import("../../actions/data/slides").ValidateSlide | import("../../actions/data/slides").SlidesAction | import("../../actions/data/skills").ReceivedSkills | import("../../actions/data/token").StoreToken>;
6
+ }>, import("../../actions/data/progression").ReceiveProgression | import("../../actions/data/slides").ValidateSlide | import("../../actions/data/slides").SlidesAction | import("../../actions/data/skills").ReceivedSkills | import("../../actions/data/token").StoreToken>;
7
7
  export default _default;
@@ -1,14 +1,20 @@
1
+ import { ReceiveProgression } from '../../actions/data/progression';
1
2
  import { ValidateSlide } from '../../actions/data/slides';
2
- import { AnswerUI } from '../../types/slides';
3
3
  export declare type ProgressionState = {
4
- slideNumber: number;
5
- isCorrect?: boolean;
6
- exitNode?: 'successExitNode' | 'failExitNode';
7
- nextSlide?: {
8
- questionText?: string;
9
- answerUI?: AnswerUI;
4
+ _id?: string;
5
+ state: {
6
+ isCorrect: boolean;
7
+ nextContent: {
8
+ ref: 'successExitNode' | string;
9
+ type: 'success' | 'slide';
10
+ };
11
+ pendingSlides: string[];
12
+ step: {
13
+ current: number;
14
+ };
10
15
  };
16
+ slideNumber?: number;
11
17
  } | null;
12
18
  export declare const initialState: ProgressionState;
13
- declare const reducer: (state: ProgressionState | undefined, action: ValidateSlide) => ProgressionState;
19
+ declare const reducer: (state: ProgressionState | undefined, action: ValidateSlide | ReceiveProgression) => ProgressionState;
14
20
  export default reducer;
@@ -1,4 +1,5 @@
1
- import { getOr, noop } from 'lodash/fp';
1
+ import { getOr } from 'lodash/fp';
2
+ import { RECEIVE_PROGRESSION } from '../../actions/data/progression';
2
3
  import { VALIDATE_SLIDE } from '../../actions/data/slides';
3
4
  // -----------------------------------------------------------------------------
4
5
  export const initialState = null;
@@ -10,66 +11,28 @@ state = initialState, action) => {
10
11
  case VALIDATE_SLIDE: {
11
12
  const previousSlideNumber = getOr(-1, 'slideNumber', state);
12
13
  // hard coded for now
14
+ // TODO: fix on VALIDATE ticket
13
15
  return {
16
+ _id: '1234',
14
17
  // virtual field
15
18
  slideNumber: previousSlideNumber + 1,
16
- isCorrect: true,
17
- // exitNode
18
- // TODO: create another action, to retrieve the next slide
19
- // nextSlide should be corrected to nextContent, when this new action is created
20
- // ex: nextContent: {ref: "sli_E1n2i2sBo", type: "slide"}
21
- // the middleware should trigger a next content request once the result is
22
- // received && update the state accordingly,
23
- //
24
- nextSlide: {
25
- questionText: 'Test',
26
- answerUI: {
27
- model: {
28
- answers: [
29
- {
30
- title: 'There is no need for a password',
31
- // TODO: onClick of each answer should use a dispatcher to
32
- // update selected answers (in order to use them on validation)
33
- // in each retrieval, the answers of answerUI need to be augmented
34
- // for the onClick prop to achieve this.
35
- onClick: noop,
36
- selected: false,
37
- help: 'help'
38
- },
39
- {
40
- title: 'Lorem ipsum',
41
- onClick: noop,
42
- selected: false,
43
- help: 'help'
44
- },
45
- {
46
- title: 'Lorem',
47
- onClick: noop,
48
- selected: true,
49
- order: 1,
50
- help: 'help'
51
- },
52
- {
53
- title: 'You need to have a password',
54
- onClick: noop,
55
- selected: false,
56
- help: 'help'
57
- },
58
- {
59
- title: 'Pouet',
60
- onClick: noop,
61
- selected: true,
62
- order: 0,
63
- help: 'help'
64
- }
65
- ],
66
- type: 'qcmDrag'
67
- },
68
- help: 'Help text will appear here'
19
+ state: {
20
+ pendingSlides: [],
21
+ step: {
22
+ current: Number.NaN
23
+ },
24
+ isCorrect: true,
25
+ nextContent: {
26
+ ref: 'sli_V1gKpYYZ2',
27
+ type: 'slide'
69
28
  }
70
29
  }
71
30
  };
72
31
  }
32
+ case RECEIVE_PROGRESSION: {
33
+ const { progression } = action.payload;
34
+ return progression;
35
+ }
73
36
  default:
74
37
  return state;
75
38
  }