@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,5 @@
1
+ import crossFetch from 'cross-fetch';
2
+ import { ProgressionFromAPI } from '../actions/data/progression';
3
+ export declare const mockedProgression: ProgressionFromAPI;
4
+ declare const mockCreateProgression: typeof crossFetch;
5
+ export default mockCreateProgression;
@@ -0,0 +1,31 @@
1
+ import { okJSONResponse } from './tools/fetch.mocks';
2
+ export var mockedProgression = {
3
+ _id: '62b1d1087aa12f00253f40ee',
4
+ state: {
5
+ // ------------------------------------------------------
6
+ // unused for now / to decide whether to use it when the
7
+ // validation-progression is plugged in
8
+ pendingSlides: [],
9
+ step: {
10
+ current: Number.NaN
11
+ },
12
+ // ------------------------------------------------------
13
+ isCorrect: true,
14
+ nextContent: {
15
+ ref: 'sli_N1XACJobn',
16
+ type: 'slide'
17
+ }
18
+ // slides: [
19
+ // 'sli_NJ3m5KtWh',
20
+ // 'sli_V1gKpYYZ2',
21
+ // 'sli_VJzOgotbh',
22
+ // 'sli_V1ug-dtZn',
23
+ // 'sli_VyZU-ejW3',
24
+ // 'sli_Vy8ChgjZh',
25
+ // 'sli_V1ijS1oWh',
26
+ // 'sli_N1XACJobn'
27
+ // ],
28
+ }
29
+ };
30
+ var mockCreateProgression = okJSONResponse(mockedProgression);
31
+ export default mockCreateProgression;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (_) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import test from 'ava';
38
+ import { postProgression } from './post-progression';
39
+ import { okJSONResponse, token } from './tools/fetch.mocks';
40
+ var skillRef = '_skill-ref';
41
+ test('should create progression with success', function (t) { return __awaiter(void 0, void 0, void 0, function () {
42
+ var result, mockedPostProgression, progression;
43
+ return __generator(this, function (_a) {
44
+ switch (_a.label) {
45
+ case 0:
46
+ result = {
47
+ _id: '123456123456',
48
+ state: {
49
+ // is "isCorrect" always true for a 1st progression?
50
+ isCorrect: true,
51
+ step: {
52
+ current: 1
53
+ },
54
+ nextContent: {
55
+ type: 'slide',
56
+ ref: 'sli_NJ3m5KtWh'
57
+ },
58
+ pendingSlides: []
59
+ }
60
+ };
61
+ mockedPostProgression = postProgression(okJSONResponse(result));
62
+ return [4 /*yield*/, mockedPostProgression(skillRef, token)];
63
+ case 1:
64
+ progression = _a.sent();
65
+ t.deepEqual(result, progression);
66
+ return [2 /*return*/];
67
+ }
68
+ });
69
+ }); });
70
+ test('should reject bad token', function (t) { return __awaiter(void 0, void 0, void 0, function () {
71
+ var badToken, mockedPostProgression, error;
72
+ return __generator(this, function (_a) {
73
+ switch (_a.label) {
74
+ case 0:
75
+ badToken = 'token is not a jwt';
76
+ mockedPostProgression = postProgression(okJSONResponse(null));
77
+ return [4 /*yield*/, t.throwsAsync(function () { return mockedPostProgression(skillRef, badToken); })];
78
+ case 1:
79
+ error = _a.sent();
80
+ t.is(error === null || error === void 0 ? void 0 : error.message, "Invalid token specified: Cannot read properties of undefined (reading 'replace')");
81
+ return [2 /*return*/];
82
+ }
83
+ });
84
+ }); });
@@ -2,6 +2,6 @@ export declare class ResponseError extends Error {
2
2
  statusCode: number;
3
3
  constructor(statusCode: number, statusText: string, body?: string);
4
4
  }
5
- export declare const toJSON: (response: Response) => Promise<unknown>;
5
+ export declare const toJSON: <T = unknown>(response: Response) => Promise<T>;
6
6
  export declare const toText: (response: Response) => Promise<string>;
7
7
  export declare const toVoid: (response: Response) => Promise<void>;
@@ -0,0 +1 @@
1
+ export declare const sleep: (msToSleep: number) => Promise<void>;
@@ -0,0 +1,5 @@
1
+ export var sleep = function (msToSleep) {
2
+ return new Promise(function (resolve) {
3
+ setTimeout(resolve, msToSleep);
4
+ });
5
+ };
@@ -1,9 +1,14 @@
1
- import { Slide } from './slides';
1
+ declare type TemplateContextValues = {
2
+ brandTheme?: unknown;
3
+ theme?: unknown;
4
+ translations?: unknown;
5
+ };
2
6
  export declare type AppOptions = {
3
7
  token: string;
4
8
  theme?: unknown;
5
9
  translations?: unknown;
6
- slide?: Slide;
10
+ templateContext?: TemplateContextValues;
11
+ skillRef?: string;
7
12
  };
8
13
  export declare type JWT = {
9
14
  exp: number;
@@ -17,3 +22,4 @@ export declare type JWT = {
17
22
  export declare type WithRequired<T, K extends keyof T> = T & {
18
23
  [P in K]-?: T[P];
19
24
  };
25
+ export {};
@@ -0,0 +1,10 @@
1
+ export declare type UiProgression = {
2
+ _id?: string;
3
+ slideNumber?: number;
4
+ isCorrect?: boolean;
5
+ exitNode?: 'successExitNode' | 'failExitNode';
6
+ nextContent?: {
7
+ ref: 'successExitNode' | string;
8
+ type: 'success' | 'slide';
9
+ };
10
+ } | null;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coorpacademy/app-review",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "",
5
5
  "engines": {
6
6
  "node": ">=16.15.0"
@@ -40,7 +40,7 @@
40
40
  "./package.json": "./package.json"
41
41
  },
42
42
  "dependencies": {
43
- "@coorpacademy/components": "10.21.4",
43
+ "@coorpacademy/components": "10.22.1",
44
44
  "cross-fetch": "^3.1.5",
45
45
  "jwt-decode": "^3.1.2",
46
46
  "react-redux": "^8.0.1",
@@ -49,8 +49,7 @@
49
49
  },
50
50
  "peerDependencies": {
51
51
  "lodash": "^4.17.21",
52
- "react": "^17.0.2",
53
- "react-native": "0.68.1"
52
+ "react": "^17.0.2"
54
53
  },
55
54
  "devDependencies": {
56
55
  "@coorpacademy/css-modules-require-hook": "2.1.5",
@@ -76,5 +75,5 @@
76
75
  "ts-node": "^10.8.1",
77
76
  "typescript": "^4.7.4"
78
77
  },
79
- "gitHead": "aeb09b5a833e5f1a16c8ca15bf82fd2fcc9c3adb"
78
+ "gitHead": "2d54e2e52323f3feca8dc93a02ef62a53f7d89de"
80
79
  }
package/readme.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # App Review
2
2
 
3
- 📚 [Static Demo](http://coorpacademy.github.io/components/app-review)
4
- 🏹 Architecture illustrated with [Excalidraw](../../../documentation/documentation/review-mode/frontend-app-review.excalidraw). This package is the `@app-review` section.
3
+ - 📚 [Static Demo](http://coorpacademy.github.io/components/app-review)
4
+ - 🏹 Architecture illustrated with Excalidraw ([local](../../../documentation/documentation/review-mode/frontend-app-review.excalidraw) and [github](https://github.com/coorpacademy/documentation/blob/master/documentation/review-mode/frontend-app-review.excalidraw)).
5
+
6
+ This package is the `@app-review` section.
5
7
 
6
8
  ## start local sandbox
7
9
 
@@ -47,9 +49,6 @@ npx ava --watch
47
49
 
48
50
  ## dependencies notes
49
51
 
50
- `react-native` must be the same version on this package and the rootApp
51
- *(possible generic error "Invariant Violation: Module AppRegistry is not a registered callable module")*
52
-
53
52
  `react` must also be the same version on this package and the rootApp
54
53
  *(possible generic error Warning: Invalid hook call. [...] 3. You might have more than one copy of React in the same app)*
55
54
 
@@ -0,0 +1,50 @@
1
+ export 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
+
16
+ // -----------------------------------------------------------------------------
17
+
18
+ export const RECEIVE_PROGRESSION = '@@data/progression/RECEIVE_PROGRESSION';
19
+ export const ERROR_CREATING_PROGRESSION = '@@data/progression/ERROR_CREATING_PROGRESSION';
20
+
21
+ // -----------------------------------------------------------------------------
22
+
23
+ export type ReceiveProgressionPayload = {
24
+ progression: ProgressionFromAPI;
25
+ token: string;
26
+ };
27
+
28
+ // -----------------------------------------------------------------------------
29
+
30
+ export type ReceiveProgression = {
31
+ type: typeof RECEIVE_PROGRESSION;
32
+ payload: ReceiveProgressionPayload;
33
+ };
34
+
35
+ export type ErrorCreatingProgression = {
36
+ type: typeof ERROR_CREATING_PROGRESSION;
37
+ payload: Error;
38
+ };
39
+
40
+ // -----------------------------------------------------------------------------
41
+
42
+ export const receiveProgression = (payload: ReceiveProgressionPayload): ReceiveProgression => ({
43
+ type: RECEIVE_PROGRESSION,
44
+ payload
45
+ });
46
+
47
+ export const errorCreatingProgression = (error: Error): ErrorCreatingProgression => ({
48
+ type: ERROR_CREATING_PROGRESSION,
49
+ payload: error
50
+ });
@@ -1,4 +1,4 @@
1
- import {Slide as SlideFromAPI} from '../../types/slides';
1
+ import {Slide as UISlide} from '../../types/slides';
2
2
 
3
3
  // -----------------------------------------------------------------------------
4
4
 
@@ -7,36 +7,40 @@ export const UPDATE_SLIDES_ON_VALIDATION = '@@slide/UPDATE_SLIDES_ON_VALIDATION'
7
7
  export const UPDATE_SLIDES_ON_NEXT = '@@slide/UPDATE_SLIDES_ON_NEXT';
8
8
  export const VALIDATE_SLIDE = '@@slide/VALIDATE';
9
9
  export const FETCH_NEXT_CONTENT = '@@slide/FETCH_NEXT_CONTENT';
10
+ export const ERROR_FETCHING_SLIDE = '@@data/slide/ERROR_FETCHING_SLIDE';
10
11
 
11
12
  // -----------------------------------------------------------------------------
12
13
 
13
14
  type SlideUIAnimations = 'unstack' | 'restack';
14
15
 
15
- export type Slide = SlideFromAPI & {
16
+ export type Slide = UISlide & {
16
17
  hidden?: boolean;
17
18
  position: number;
18
19
  animationType?: SlideUIAnimations;
19
20
  isCorrect?: boolean;
20
21
  endReview?: boolean;
21
- nextSlide?: Omit<Slide, 'endReview' | 'hidden' | 'position' | 'nextSlide'>;
22
+ nextContent?: Omit<Slide, 'endReview' | 'hidden' | 'position' | 'nextContent'>;
23
+ };
24
+
25
+ // TODO: complete or modify typing as needed on Fetch Slide ticket
26
+ export type SlideFromAPI = {
27
+ question: {
28
+ content: {
29
+ choices: Record<string, unknown>[];
30
+ };
31
+ };
32
+ klf: string;
33
+ universalRef: string;
22
34
  };
23
35
 
24
36
  export type ValidationPayload = {
25
37
  slideNumber: number;
26
38
  newSlideContent: Slide;
27
39
  numberOfFinishedSlides: number;
28
- nextSlide: Slide;
40
+ nextContent: Slide;
29
41
  };
30
42
 
31
- export type OnNextPayload = Omit<ValidationPayload, 'nextSlide'>;
32
-
33
- export type FetchNextPayload = {
34
- answer: string[];
35
- content: {
36
- ref: string;
37
- type: string;
38
- };
39
- };
43
+ export type OnNextPayload = Omit<ValidationPayload, 'nextContent'>;
40
44
 
41
45
  // -----------------------------------------------------------------------------
42
46
 
@@ -59,10 +63,9 @@ export type ValidateSlide = {
59
63
  type: typeof VALIDATE_SLIDE;
60
64
  };
61
65
 
62
- // TODO
63
- export type FetchNextContent = {
64
- type: typeof FETCH_NEXT_CONTENT;
65
- payload: FetchNextPayload;
66
+ export type ErrorFetchingSlide = {
67
+ type: typeof ERROR_FETCHING_SLIDE;
68
+ payload: Error;
66
69
  };
67
70
 
68
71
  export type SlidesAction = StoreFirstSlide | UpdateSlidesOnValidation | UpdateSlidesOnNext;
@@ -87,3 +90,8 @@ export const updateSlidesOnNext = (payload: OnNextPayload): UpdateSlidesOnNext =
87
90
  export const validateSlide = (): ValidateSlide => ({
88
91
  type: VALIDATE_SLIDE
89
92
  });
93
+
94
+ export const errorFetchingSlide = (error: Error): ErrorFetchingSlide => ({
95
+ type: ERROR_FETCHING_SLIDE,
96
+ payload: error
97
+ });
@@ -1,7 +1,7 @@
1
- export const STORE_TOKEN = '@@token/STORE_TOKEN';
1
+ export const STORE_TOKEN = '@@data/token/STORE_TOKEN';
2
2
 
3
3
  export type StoreToken = {
4
- type: '@@token/STORE_TOKEN';
4
+ type: typeof STORE_TOKEN;
5
5
  payload: string;
6
6
  };
7
7
 
@@ -11,6 +11,7 @@ import {updateFinishedSlides} from './ui/finished-slides';
11
11
  import {navigateBack, navigateTo, NavigateBack, NavigateTo, StartApp} from './ui/navigation';
12
12
  import {updateReviewStatus} from './ui/review-status';
13
13
  import {updateStepItemsOnValidation, updateStepItemsOnNext} from './ui/step-items';
14
+ import {ErrorCreatingProgression, ReceiveProgression} from './data/progression';
14
15
 
15
16
  export type Action =
16
17
  | NavigateBack
@@ -19,7 +20,9 @@ export type Action =
19
20
  | ErrorFetchingSkills
20
21
  | StartApp
21
22
  | StoreFirstSlide
22
- | StoreToken;
23
+ | StoreToken
24
+ | ErrorCreatingProgression
25
+ | ReceiveProgression;
23
26
 
24
27
  export type Dispatchers = {
25
28
  navigateTo: typeof navigateTo;
@@ -3,6 +3,7 @@ import thunk from 'redux-thunk';
3
3
 
4
4
  import rootReducer from './reducers';
5
5
  import onStartApp from './middlewares/on-start-app';
6
+ import onReceiveProgression from './middlewares/on-receive-progression';
6
7
 
7
8
  import {SkillsState} from './reducers/data/skills';
8
9
  import {SlidesState} from './reducers/data/slides';
@@ -11,23 +12,13 @@ import {NavigationState} from './reducers/ui/navigation';
11
12
  import {ReviewStatusState} from './reducers/ui/review-status';
12
13
  import {StepItemsState} from './reducers/ui/step-items';
13
14
  import {FinishedSlidesState} from './reducers/ui/finished-slides';
14
-
15
- import {AnswerUI} from './types/slides';
15
+ import {ProgressionState} from './reducers/data/progression';
16
16
 
17
17
  // -----------------------------------------------------------------------------
18
18
 
19
19
  type DataState = {
20
20
  isFetching?: boolean;
21
- progression?: {
22
- slideNumber: number;
23
- isCorrect?: boolean;
24
- // pass down the successExitNode if all slides are finished, not before
25
- exitNode?: 'successExitNode' | 'failExitNode';
26
- nextSlide?: {
27
- questionText?: string;
28
- answerUI?: AnswerUI;
29
- };
30
- } | null;
21
+ progression?: ProgressionState;
31
22
  skills: SkillsState;
32
23
  slides: SlidesState;
33
24
  token?: TokenState;
@@ -39,6 +30,7 @@ export type StoreState = {
39
30
  stepItems: StepItemsState;
40
31
  finishedSlides: FinishedSlidesState;
41
32
  reviewStatus: ReviewStatusState;
33
+ // progression: UiProgression;
42
34
  };
43
35
  data: DataState;
44
36
  };
@@ -54,7 +46,7 @@ export default function configureStore(): Store<StoreState, AnyAction> {
54
46
  })
55
47
  : compose;
56
48
 
57
- const enhancer = _compose(applyMiddleware(thunk, onStartApp));
49
+ const enhancer = _compose(applyMiddleware(thunk, onStartApp, onReceiveProgression));
58
50
  const store = createStore(rootReducer, undefined, enhancer);
59
51
 
60
52
  return store;
@@ -3,8 +3,8 @@ import test from 'ava';
3
3
  import type {ExecutionContext} from 'ava';
4
4
  import React from 'react';
5
5
  import {render, fireEvent, act} from '@testing-library/react';
6
- import {slide} from './fixtures/qcm-slide';
7
6
  import type {AppOptions} from './types/common';
7
+ import {sleep} from './services/tools/sleep';
8
8
  import AppReview from '.';
9
9
 
10
10
  browserEnv({pretendToBeVisual: true});
@@ -12,11 +12,6 @@ browserEnv({pretendToBeVisual: true});
12
12
  const elementExists = (foundElements: NodeListOf<Element>): Element =>
13
13
  foundElements && foundElements[0];
14
14
 
15
- const sleep = (msToSleep: number): Promise<void> =>
16
- new Promise(resolve => {
17
- setTimeout(resolve, msToSleep);
18
- });
19
-
20
15
  const waitForChanges = async (msToWait = 3000): Promise<void> => {
21
16
  await act(async () => {
22
17
  await sleep(msToWait); // wait *just* a little longer than the timeout in the component
@@ -61,7 +56,10 @@ const clickAllSlides = async (
61
56
 
62
57
  const appOptions: AppOptions = {
63
58
  token: process.env.API_TEST_TOKEN || '',
64
- slide
59
+ templateContext: {
60
+ theme: {color: {primary: '#123'}}
61
+ },
62
+ skillRef: 'skill_NJC0jFKoH'
65
63
  };
66
64
 
67
65
  test('should validate all the slides (all correct scenario)', async t => {
package/src/index.tsx CHANGED
@@ -2,6 +2,7 @@ import React, {useEffect, useState} from 'react';
2
2
  import {AnyAction, Store} from 'redux';
3
3
  import {connect, Provider} from 'react-redux';
4
4
  import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
5
+ import {TemplateContext} from '@coorpacademy/components/es/template/app-review/template-context';
5
6
 
6
7
  import configureStore, {StoreState} from './configure-store';
7
8
  import {congratsProps, correctionPopinProps} from './fixtures/temp-fixture';
@@ -21,8 +22,8 @@ import {updateStepItemsOnValidation, updateStepItemsOnNext} from './actions/ui/s
21
22
 
22
23
  type StaticProps = {
23
24
  viewName: 'skills' | 'onboarding' | 'slides';
24
- slides: SlidesViewStaticProps;
25
- skills: SkillsProps;
25
+ slides: SlidesViewStaticProps | null;
26
+ skills: SkillsProps | null;
26
27
  };
27
28
 
28
29
  // -----------------------------------------------------------------------------
@@ -42,30 +43,43 @@ const mapDispatchToProps: Dispatchers = {
42
43
  const getCurrentViewName = (storeState: StoreState): ViewPath =>
43
44
  storeState.ui.navigation[storeState.ui.navigation.length - 1];
44
45
 
45
- const mapStateToSkillsProps = (state: StoreState): SkillsProps => ({
46
- title: '@todo title',
47
- titleNoSkills: '@todo titleNoSkills',
48
- textNoSkills: '@todo textNoSkills',
49
- iconSkillAriaLabel: '@todo iconSkillAriaLabel',
50
- isLoading: false,
51
- isLoadingAriaLabel: '@todo loading',
52
- listSkills: state.data.skills.map(skill => ({
53
- 'aria-label': '',
54
- isCustom: skill.custom,
55
- skillTitle: skill.name,
56
- skillAriaLabel: '@todo skill aria label',
57
- buttonLabel: '@todo button',
58
- buttonAriaLabel: '@todo button aria label',
59
- reviseLabel: '@todo revise',
60
- reviseAriaLabel: '@todo revise aria label',
61
- // eslint-disable-next-line no-console
62
- onClick: () => console.log('@todo plug dispatcher select skill')
63
- }))
64
- });
46
+ // -----------------------------------------------------------------------------
65
47
 
66
- const mapStateToProps = (state: StoreState): StaticProps => ({
67
- viewName: getCurrentViewName(state),
68
- slides: {
48
+ const mapStateToSkillsProps = (state: StoreState): SkillsProps | null => {
49
+ if (!state.data.skills) {
50
+ return null;
51
+ }
52
+
53
+ return {
54
+ title: '@todo title',
55
+ titleNoSkills: '@todo titleNoSkills',
56
+ textNoSkills: '@todo textNoSkills',
57
+ iconSkillAriaLabel: '@todo iconSkillAriaLabel',
58
+ isLoading: false,
59
+ isLoadingAriaLabel: '@todo loading',
60
+ listSkills: state.data.skills.map(skill => ({
61
+ 'aria-label': '',
62
+ isCustom: skill.custom,
63
+ skillTitle: skill.name,
64
+ skillAriaLabel: '@todo skill aria label',
65
+ buttonLabel: '@todo button',
66
+ buttonAriaLabel: '@todo button aria label',
67
+ reviseLabel: '@todo revise',
68
+ reviseAriaLabel: '@todo revise aria label',
69
+ // eslint-disable-next-line no-console
70
+ onClick: () => console.log('@todo plug dispatcher select skill')
71
+ }))
72
+ };
73
+ };
74
+
75
+ // -----------------------------------------------------------------------------
76
+
77
+ const mapStateToSlidesProps = (state: StoreState): SlidesViewStaticProps | null => {
78
+ if (!state.data.slides) {
79
+ return null;
80
+ }
81
+
82
+ return {
69
83
  headerProps: {
70
84
  mode: '__revision_mode',
71
85
  skillName: '__agility',
@@ -86,7 +100,14 @@ const mapStateToProps = (state: StoreState): StaticProps => ({
86
100
  correctionPopinProps,
87
101
  congratsProps,
88
102
  progression: state.data.progression
89
- },
103
+ };
104
+ };
105
+
106
+ // -----------------------------------------------------------------------------
107
+
108
+ const mapStateToProps = (state: StoreState): StaticProps => ({
109
+ viewName: getCurrentViewName(state),
110
+ slides: mapStateToSlidesProps(state),
90
111
  skills: mapStateToSkillsProps(state)
91
112
  });
92
113
 
@@ -96,7 +117,7 @@ const App = connect(mapStateToProps, mapDispatchToProps)(AppReviewTemplate);
96
117
 
97
118
  // -----------------------------------------------------------------------------
98
119
 
99
- const AppReview = ({options}: {options: AppOptions}): JSX.Element => {
120
+ const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
100
121
  const [store, setStore] = useState<Store<StoreState, AnyAction> | null>(null);
101
122
  const [appStarted, setAppStarted] = useState<boolean>(false);
102
123
 
@@ -113,11 +134,15 @@ const AppReview = ({options}: {options: AppOptions}): JSX.Element => {
113
134
  }
114
135
  }, [options, store]);
115
136
 
116
- if (!store || !appStarted) return <div />;
137
+ if (!store || !appStarted) return null;
138
+
139
+ const {templateContext: values} = options;
117
140
 
118
141
  return (
119
142
  <Provider store={store}>
120
- <App />
143
+ <TemplateContext values={values}>
144
+ <App />
145
+ </TemplateContext>
121
146
  </Provider>
122
147
  );
123
148
  };
@@ -0,0 +1,60 @@
1
+ import test from 'ava';
2
+ import {AnyAction, Dispatch, MiddlewareAPI} from 'redux';
3
+ import {receiveProgression} from '../actions/data/progression';
4
+ import {Action} from '../actions';
5
+ import {AppOptions} from '../types/common';
6
+ import {mockedProgression} from '../services/post-progression.mock';
7
+ import {sleep} from '../services/tools/sleep';
8
+ import {STORE_FIRST_SLIDE} from '../actions/data/slides';
9
+ import onReceiveProgression from './on-receive-progression';
10
+
11
+ const appOptions: AppOptions = {
12
+ token: process.env.API_TEST_TOKEN || ''
13
+ };
14
+
15
+ const otherAction = (
16
+ payload: string
17
+ ): {
18
+ type: string;
19
+ payload: string;
20
+ } => ({
21
+ type: '@@other/OTHER',
22
+ payload
23
+ });
24
+
25
+ test('should not dispatch anything if action is not RECEIVE_PROGRESSION', t => {
26
+ t.plan(1);
27
+ const dispatch = (): void => {
28
+ t.fail();
29
+ };
30
+ const next = (): boolean => {
31
+ return t.pass();
32
+ };
33
+
34
+ onReceiveProgression({dispatch} as unknown as MiddlewareAPI)(next as Dispatch<AnyAction>)(
35
+ otherAction('other')
36
+ );
37
+ });
38
+
39
+ test('should dispatch actions: STORE_FIRST_SLIDE', async t => {
40
+ t.plan(2);
41
+ const dispatch = (action: Action): void => {
42
+ switch (action.type) {
43
+ case STORE_FIRST_SLIDE: {
44
+ const slide = action.payload;
45
+ t.deepEqual(slide, {});
46
+ return;
47
+ }
48
+ default:
49
+ t.fail();
50
+ break;
51
+ }
52
+ };
53
+ const next = (): boolean => {
54
+ return t.pass();
55
+ };
56
+ onReceiveProgression({dispatch} as MiddlewareAPI)(next as Dispatch<AnyAction>)(
57
+ receiveProgression({token: appOptions.token, progression: mockedProgression})
58
+ );
59
+ await sleep(1000); // wait for the .then to fire
60
+ });