@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.
- package/es/actions/data/progression.d.ts +30 -0
- package/es/actions/data/progression.js +12 -0
- package/es/actions/data/slides.d.ts +19 -15
- package/es/actions/data/slides.js +5 -0
- package/es/actions/data/token.d.ts +2 -2
- package/es/actions/data/token.js +1 -1
- package/es/actions/index.d.ts +2 -1
- package/es/configure-store.d.ts +2 -10
- package/es/configure-store.js +2 -1
- package/es/index.d.ts +1 -1
- package/es/index.js +43 -26
- package/es/index.test.js +5 -5
- package/es/middlewares/on-receive-progression.d.ts +6 -0
- package/es/middlewares/on-receive-progression.js +22 -0
- package/es/middlewares/on-receive-progression.test.d.ts +1 -0
- package/es/middlewares/on-receive-progression.test.js +43 -0
- package/es/middlewares/on-start-app.js +13 -5
- package/es/middlewares/on-start-app.test.d.ts +1 -0
- package/es/middlewares/on-start-app.test.js +53 -0
- package/es/reducers/data/index.d.ts +1 -1
- package/es/reducers/data/progression.d.ts +14 -8
- package/es/reducers/data/progression.js +17 -54
- package/es/reducers/data/slides.js +11 -6
- package/es/reducers/index.d.ts +1 -1
- package/es/services/fetch-skills.js +1 -2
- package/es/services/fetch-slide.d.ts +8 -0
- package/es/services/fetch-slide.js +26 -0
- package/es/services/post-progression.d.ts +8 -0
- package/es/services/post-progression.js +33 -0
- package/es/services/post-progression.mock.d.ts +5 -0
- package/es/services/post-progression.mock.js +31 -0
- package/es/services/post-progression.test.d.ts +1 -0
- package/es/services/post-progression.test.js +30 -0
- package/es/services/tools/fetch-responses.d.ts +1 -1
- package/es/services/tools/sleep.d.ts +1 -0
- package/es/services/tools/sleep.js +3 -0
- package/es/types/common.d.ts +8 -2
- package/es/types/ui-progression.d.ts +10 -0
- package/es/types/ui-progression.js +1 -0
- package/lib/actions/data/progression.d.ts +30 -0
- package/lib/actions/data/progression.js +12 -0
- package/lib/actions/data/slides.d.ts +19 -15
- package/lib/actions/data/slides.js +5 -0
- package/lib/actions/data/token.d.ts +2 -2
- package/lib/actions/data/token.js +1 -1
- package/lib/actions/index.d.ts +2 -1
- package/lib/configure-store.d.ts +2 -10
- package/lib/configure-store.js +2 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +43 -26
- package/lib/index.test.js +5 -7
- package/lib/middlewares/on-receive-progression.d.ts +6 -0
- package/lib/middlewares/on-receive-progression.js +27 -0
- package/lib/middlewares/on-receive-progression.test.d.ts +1 -0
- package/lib/middlewares/on-receive-progression.test.js +88 -0
- package/lib/middlewares/on-start-app.js +15 -7
- package/lib/middlewares/on-start-app.test.d.ts +1 -0
- package/lib/middlewares/on-start-app.test.js +98 -0
- package/lib/reducers/data/index.d.ts +1 -1
- package/lib/reducers/data/progression.d.ts +14 -8
- package/lib/reducers/data/progression.js +17 -54
- package/lib/reducers/data/slides.js +11 -6
- package/lib/reducers/index.d.ts +1 -1
- package/lib/services/fetch-skills.js +2 -5
- package/lib/services/fetch-slide.d.ts +8 -0
- package/lib/services/fetch-slide.js +64 -0
- package/lib/services/post-progression.d.ts +8 -0
- package/lib/services/post-progression.js +77 -0
- package/lib/services/post-progression.mock.d.ts +5 -0
- package/lib/services/post-progression.mock.js +31 -0
- package/lib/services/post-progression.test.d.ts +1 -0
- package/lib/services/post-progression.test.js +84 -0
- package/lib/services/tools/fetch-responses.d.ts +1 -1
- package/lib/services/tools/sleep.d.ts +1 -0
- package/lib/services/tools/sleep.js +5 -0
- package/lib/types/common.d.ts +8 -2
- package/lib/types/ui-progression.d.ts +10 -0
- package/lib/types/ui-progression.js +1 -0
- package/package.json +4 -5
- package/readme.md +4 -5
- package/src/actions/data/progression.ts +50 -0
- package/src/actions/data/slides.ts +25 -17
- package/src/actions/data/token.ts +2 -2
- package/src/actions/index.ts +4 -1
- package/src/configure-store.ts +5 -13
- package/src/index.test.tsx +5 -7
- package/src/index.tsx +54 -29
- package/src/middlewares/on-receive-progression.test.ts +60 -0
- package/src/middlewares/on-receive-progression.ts +42 -0
- package/src/middlewares/on-start-app.test.ts +68 -0
- package/src/middlewares/on-start-app.ts +13 -5
- package/src/reducers/data/progression.ts +34 -69
- package/src/reducers/data/slides.ts +13 -8
- package/src/services/fetch-skills.ts +1 -2
- package/src/services/fetch-slide.ts +43 -0
- package/src/services/post-progression.mock.ts +35 -0
- package/src/services/post-progression.test.ts +41 -0
- package/src/services/post-progression.ts +50 -0
- package/src/services/tools/fetch-responses.ts +1 -1
- package/src/services/tools/sleep.ts +4 -0
- package/src/types/common.ts +8 -2
- package/src/types/globals.d.ts +1 -0
- 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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
46
|
-
type: typeof
|
|
47
|
-
payload:
|
|
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:
|
|
3
|
+
type: typeof STORE_TOKEN;
|
|
4
4
|
payload: string;
|
|
5
5
|
};
|
|
6
6
|
export declare const storeToken: (token: string) => StoreToken;
|
package/es/actions/data/token.js
CHANGED
package/es/actions/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/es/configure-store.d.ts
CHANGED
|
@@ -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 {
|
|
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;
|
package/es/configure-store.js
CHANGED
|
@@ -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
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
105
|
+
return null;
|
|
106
|
+
const { templateContext: values } = options;
|
|
91
107
|
return (React.createElement(Provider, { store: store },
|
|
92
|
-
React.createElement(
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
12
|
+
const { skillRef, token } = action.payload;
|
|
11
13
|
dispatch(storeToken(token));
|
|
12
|
-
if (
|
|
13
|
-
|
|
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 =
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
}
|