@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,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<
|
|
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>;
|
package/lib/types/common.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coorpacademy/app-review",
|
|
3
|
-
"version": "0.1.
|
|
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.
|
|
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": "
|
|
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 [
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
40
|
+
nextContent: Slide;
|
|
29
41
|
};
|
|
30
42
|
|
|
31
|
-
export type OnNextPayload = Omit<ValidationPayload, '
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
});
|
package/src/actions/index.ts
CHANGED
|
@@ -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;
|
package/src/configure-store.ts
CHANGED
|
@@ -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;
|
package/src/index.test.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
137
|
+
if (!store || !appStarted) return null;
|
|
138
|
+
|
|
139
|
+
const {templateContext: values} = options;
|
|
117
140
|
|
|
118
141
|
return (
|
|
119
142
|
<Provider store={store}>
|
|
120
|
-
<
|
|
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
|
+
});
|