@coorpacademy/app-review 0.1.15 → 0.1.16
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/api/fetch-skills.d.ts +4 -6
- package/es/actions/api/fetch-skills.js +7 -4
- package/es/actions/api/fetch-slide.d.ts +14 -7
- package/es/actions/api/fetch-slide.js +22 -19
- package/es/actions/api/post-progression.d.ts +4 -6
- package/es/actions/api/post-progression.js +13 -8
- package/es/actions/api/test/create-test-store.d.ts +5 -0
- package/es/actions/api/test/create-test-store.js +16 -0
- package/es/actions/api/test/fetch-skills.test.js +54 -0
- package/es/actions/api/test/fetch-slide.test.js +61 -0
- package/es/actions/api/test/post-progression.test.d.ts +1 -0
- package/es/actions/api/test/post-progression.test.js +102 -0
- package/es/actions/ui/answers.d.ts +7 -0
- package/es/actions/ui/answers.js +7 -0
- package/es/fixtures/temp-fixture.d.ts +1 -1
- package/es/index.js +10 -16
- package/es/reducers/data/index.d.ts +1 -1
- package/es/reducers/data/slides.d.ts +2 -2
- package/es/reducers/data/slides.js +5 -1
- package/es/reducers/data/test/progression.test.d.ts +1 -0
- package/es/reducers/data/test/progression.test.js +38 -0
- package/es/reducers/data/test/skills.test.d.ts +1 -0
- package/es/reducers/data/test/skills.test.js +12 -0
- package/es/reducers/data/test/slides.test.d.ts +1 -0
- package/es/reducers/data/test/slides.test.js +20 -0
- package/es/reducers/data/test/token.test.d.ts +1 -0
- package/es/reducers/data/test/token.test.js +11 -0
- package/es/reducers/index.d.ts +2 -2
- package/es/reducers/ui/answers.d.ts +4 -0
- package/es/reducers/ui/answers.js +13 -0
- package/es/reducers/ui/index.d.ts +4 -4
- package/es/reducers/ui/index.js +2 -2
- package/es/reducers/ui/test/answers.test.d.ts +1 -0
- package/es/reducers/ui/test/answers.test.js +11 -0
- package/es/reducers/ui/test/current-slide-ref.test.d.ts +1 -0
- package/es/reducers/ui/test/current-slide-ref.test.js +12 -0
- package/es/reducers/ui/test/navigation.test.d.ts +1 -0
- package/es/reducers/ui/test/navigation.test.js +15 -0
- package/es/services/fetch-slide.js +1 -1
- package/es/services/index.js +3 -1
- package/es/services/post-answer.d.ts +2 -0
- package/es/services/post-answer.js +18 -0
- package/es/services/test/fetch-slide.test.d.ts +1 -0
- package/es/services/test/fetch-slide.test.js +22 -0
- package/es/services/test/post-answer.test.d.ts +1 -0
- package/es/services/test/post-answer.test.js +57 -0
- package/es/services/test/post-progression.test.js +9 -1
- package/es/test/util/services.mock.js +37 -7
- package/es/types/common.d.ts +22 -8
- package/es/views/slides/index.d.ts +78 -2
- package/es/views/slides/index.js +70 -4
- package/es/views/slides/map-api-slide-to-ui.d.ts +8 -0
- package/es/views/slides/map-api-slide-to-ui.js +172 -0
- package/{lib/helpers → es/views/slides}/test/fixtures/free-text.d.ts +1 -1
- package/es/views/slides/test/fixtures/free-text.js +38 -0
- package/es/{helpers → views/slides}/test/fixtures/qcm-drag.d.ts +1 -1
- package/es/views/slides/test/fixtures/qcm-drag.js +108 -0
- package/es/{helpers → views/slides}/test/fixtures/qcm-graphic.d.ts +1 -1
- package/es/views/slides/test/fixtures/qcm-graphic.js +88 -0
- package/es/{helpers → views/slides}/test/fixtures/qcm.d.ts +1 -1
- package/es/{helpers → views/slides}/test/fixtures/qcm.js +5 -1
- package/es/{helpers → views/slides}/test/fixtures/select-template.d.ts +1 -1
- package/es/views/slides/test/fixtures/select-template.js +92 -0
- package/es/{helpers → views/slides}/test/fixtures/slider.d.ts +1 -1
- package/es/views/slides/test/fixtures/slider.js +36 -0
- package/es/{helpers → views/slides}/test/fixtures/text-template.d.ts +1 -1
- package/es/{helpers → views/slides}/test/fixtures/text-template.js +5 -1
- package/es/views/slides/test/map-api-slide-to-ui.test.d.ts +1 -0
- package/es/{helpers → views/slides}/test/map-api-slide-to-ui.test.js +19 -9
- package/lib/actions/api/fetch-skills.d.ts +4 -6
- package/lib/actions/api/fetch-skills.js +55 -7
- package/lib/actions/api/fetch-slide.d.ts +14 -7
- package/lib/actions/api/fetch-slide.js +70 -20
- package/lib/actions/api/post-progression.d.ts +4 -6
- package/lib/actions/api/post-progression.js +63 -9
- package/lib/actions/api/test/create-test-store.d.ts +5 -0
- package/lib/actions/api/test/create-test-store.js +18 -0
- package/lib/actions/api/test/fetch-skills.test.d.ts +1 -0
- package/lib/actions/api/test/fetch-skills.test.js +113 -0
- package/lib/actions/api/test/fetch-slide.test.d.ts +1 -0
- package/lib/actions/api/test/fetch-slide.test.js +120 -0
- package/lib/actions/api/test/post-progression.test.d.ts +1 -0
- package/lib/actions/api/test/post-progression.test.js +160 -0
- package/lib/actions/ui/answers.d.ts +7 -0
- package/lib/actions/ui/answers.js +9 -0
- package/lib/fixtures/temp-fixture.d.ts +1 -1
- package/lib/index.js +21 -18
- package/lib/reducers/data/index.d.ts +1 -1
- package/lib/reducers/data/slides.d.ts +2 -2
- package/lib/reducers/data/slides.js +5 -1
- package/lib/reducers/data/test/progression.test.d.ts +1 -0
- package/lib/reducers/data/test/progression.test.js +38 -0
- package/lib/reducers/data/test/skills.test.d.ts +1 -0
- package/lib/reducers/data/test/skills.test.js +12 -0
- package/lib/reducers/data/test/slides.test.d.ts +1 -0
- package/lib/reducers/data/test/slides.test.js +20 -0
- package/lib/reducers/data/test/token.test.d.ts +1 -0
- package/lib/reducers/data/test/token.test.js +11 -0
- package/lib/reducers/index.d.ts +2 -2
- package/lib/reducers/ui/answers.d.ts +4 -0
- package/lib/reducers/ui/answers.js +14 -0
- package/lib/reducers/ui/index.d.ts +4 -4
- package/lib/reducers/ui/index.js +2 -2
- package/lib/reducers/ui/test/answers.test.d.ts +1 -0
- package/lib/reducers/ui/test/answers.test.js +11 -0
- package/lib/reducers/ui/test/current-slide-ref.test.d.ts +1 -0
- package/lib/reducers/ui/test/current-slide-ref.test.js +12 -0
- package/lib/reducers/ui/test/navigation.test.d.ts +1 -0
- package/lib/reducers/ui/test/navigation.test.js +15 -0
- package/lib/services/fetch-slide.js +1 -1
- package/lib/services/index.js +3 -1
- package/lib/services/post-answer.d.ts +2 -0
- package/lib/services/post-answer.js +62 -0
- package/lib/services/test/fetch-slide.test.d.ts +1 -0
- package/lib/services/test/fetch-slide.test.js +76 -0
- package/lib/services/test/post-answer.test.d.ts +1 -0
- package/lib/services/test/post-answer.test.js +111 -0
- package/lib/services/test/post-progression.test.js +9 -1
- package/lib/test/util/services.mock.js +37 -7
- package/lib/types/common.d.ts +22 -8
- package/lib/views/slides/index.d.ts +78 -2
- package/lib/views/slides/index.js +70 -4
- package/lib/views/slides/map-api-slide-to-ui.d.ts +8 -0
- package/lib/views/slides/map-api-slide-to-ui.js +178 -0
- package/{es/helpers → lib/views/slides}/test/fixtures/free-text.d.ts +1 -1
- package/lib/views/slides/test/fixtures/free-text.js +38 -0
- package/lib/{helpers → views/slides}/test/fixtures/qcm-drag.d.ts +1 -1
- package/lib/views/slides/test/fixtures/qcm-drag.js +108 -0
- package/lib/{helpers → views/slides}/test/fixtures/qcm-graphic.d.ts +1 -1
- package/lib/views/slides/test/fixtures/qcm-graphic.js +88 -0
- package/lib/{helpers → views/slides}/test/fixtures/qcm.d.ts +1 -1
- package/lib/{helpers → views/slides}/test/fixtures/qcm.js +5 -1
- package/lib/{helpers → views/slides}/test/fixtures/select-template.d.ts +1 -1
- package/lib/views/slides/test/fixtures/select-template.js +92 -0
- package/lib/{helpers → views/slides}/test/fixtures/slider.d.ts +1 -1
- package/lib/views/slides/test/fixtures/slider.js +36 -0
- package/lib/{helpers → views/slides}/test/fixtures/text-template.d.ts +1 -1
- package/lib/{helpers → views/slides}/test/fixtures/text-template.js +5 -1
- package/lib/views/slides/test/map-api-slide-to-ui.test.d.ts +1 -0
- package/lib/{helpers → views/slides}/test/map-api-slide-to-ui.test.js +19 -9
- package/package.json +3 -3
- package/src/actions/api/fetch-skills.ts +12 -12
- package/src/actions/api/fetch-slide.ts +33 -29
- package/src/actions/api/post-progression.ts +18 -21
- package/src/actions/api/test/create-test-store.ts +25 -0
- package/src/actions/api/test/fetch-skills.test.ts +70 -0
- package/src/actions/api/test/fetch-slide.test.ts +77 -0
- package/src/actions/api/test/post-progression.test.ts +119 -0
- package/src/actions/ui/answers.ts +16 -0
- package/src/fixtures/temp-fixture.ts +1 -1
- package/src/index.tsx +14 -29
- package/src/reducers/data/index.ts +1 -1
- package/src/reducers/data/slides.ts +11 -2
- package/src/reducers/data/test/progression.test.ts +42 -0
- package/src/reducers/data/test/skills.test.ts +14 -0
- package/src/reducers/data/test/slides.test.ts +26 -0
- package/src/reducers/data/test/token.test.ts +13 -0
- package/src/reducers/ui/answers.ts +19 -0
- package/src/reducers/ui/index.ts +3 -3
- package/src/reducers/ui/test/answers.test.ts +13 -0
- package/src/reducers/ui/test/current-slide-ref.test.ts +14 -0
- package/src/reducers/ui/test/navigation.test.ts +19 -0
- package/src/services/fetch-slide.ts +1 -1
- package/src/services/index.ts +3 -1
- package/src/services/post-answer.ts +27 -0
- package/src/services/test/fetch-slide.test.ts +30 -0
- package/src/services/test/post-answer.test.ts +68 -0
- package/src/services/test/post-progression.test.ts +9 -1
- package/src/test/util/services.mock.ts +37 -7
- package/src/types/common.ts +34 -14
- package/src/views/slides/index.ts +164 -5
- package/src/views/slides/map-api-slide-to-ui.ts +251 -0
- package/src/views/slides/test/fixtures/free-text.ts +43 -0
- package/src/views/slides/test/fixtures/qcm-drag.ts +111 -0
- package/src/views/slides/test/fixtures/qcm-graphic.ts +94 -0
- package/src/{helpers → views/slides}/test/fixtures/qcm.ts +6 -2
- package/src/views/slides/test/fixtures/select-template.ts +98 -0
- package/src/views/slides/test/fixtures/slider.ts +41 -0
- package/src/{helpers → views/slides}/test/fixtures/text-template.ts +6 -2
- package/src/{helpers → views/slides}/test/map-api-slide-to-ui.test.ts +21 -10
- package/es/helpers/map-api-slide-to-ui.d.ts +0 -11
- package/es/helpers/map-api-slide-to-ui.js +0 -193
- package/es/helpers/test/fixtures/free-text.js +0 -30
- package/es/helpers/test/fixtures/qcm-drag.js +0 -112
- package/es/helpers/test/fixtures/qcm-graphic.js +0 -76
- package/es/helpers/test/fixtures/select-template.js +0 -94
- package/es/helpers/test/fixtures/slider.js +0 -33
- package/es/reducers/ui/slides.d.ts +0 -9
- package/es/reducers/ui/slides.js +0 -42
- package/es/types/views/slides.d.ts +0 -74
- package/es/types/views/slides.js +0 -6
- package/lib/helpers/map-api-slide-to-ui.d.ts +0 -11
- package/lib/helpers/map-api-slide-to-ui.js +0 -201
- package/lib/helpers/test/fixtures/free-text.js +0 -30
- package/lib/helpers/test/fixtures/qcm-drag.js +0 -112
- package/lib/helpers/test/fixtures/qcm-graphic.js +0 -76
- package/lib/helpers/test/fixtures/select-template.js +0 -94
- package/lib/helpers/test/fixtures/slider.js +0 -33
- package/lib/reducers/ui/slides.d.ts +0 -9
- package/lib/reducers/ui/slides.js +0 -43
- package/lib/types/views/slides.d.ts +0 -74
- package/lib/types/views/slides.js +0 -6
- package/src/helpers/map-api-slide-to-ui.ts +0 -279
- package/src/helpers/test/fixtures/free-text.ts +0 -33
- package/src/helpers/test/fixtures/qcm-drag.ts +0 -115
- package/src/helpers/test/fixtures/qcm-graphic.ts +0 -79
- package/src/helpers/test/fixtures/select-template.ts +0 -97
- package/src/helpers/test/fixtures/slider.ts +0 -36
- package/src/reducers/ui/slides.ts +0 -58
- package/src/types/views/slides.ts +0 -90
- /package/es/{helpers/test/map-api-slide-to-ui.test.d.ts → actions/api/test/fetch-skills.test.d.ts} +0 -0
- /package/{lib/helpers/test/map-api-slide-to-ui.test.d.ts → es/actions/api/test/fetch-slide.test.d.ts} +0 -0
|
@@ -10,6 +10,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
12
|
import test from 'ava';
|
|
13
|
+
import identity from 'lodash/fp/identity';
|
|
13
14
|
import { mapApiSlideToUi } from '../map-api-slide-to-ui';
|
|
14
15
|
import { qcmUISlide, qcmSlide } from './fixtures/qcm';
|
|
15
16
|
import { qcmDragUISlide, qcmDragSlide } from './fixtures/qcm-drag';
|
|
@@ -18,26 +19,35 @@ import { qcmGraphicUISlide, qcmGraphicSlide } from './fixtures/qcm-graphic';
|
|
|
18
19
|
import { textTemplateSlide, textTemplateUISlide } from './fixtures/text-template';
|
|
19
20
|
import { selectTemplateSlide, selectTemplateUISlide } from './fixtures/select-template';
|
|
20
21
|
import { sliderSlide, sliderUISlide } from './fixtures/slider';
|
|
21
|
-
var _mapApiSlideToUi = mapApiSlideToUi(
|
|
22
|
+
var _mapApiSlideToUi = mapApiSlideToUi(identity);
|
|
22
23
|
var macro = test.macro({
|
|
23
24
|
title: function (providedTitle) {
|
|
24
25
|
return "should handle ".concat(providedTitle, " conversion").trim();
|
|
25
26
|
},
|
|
26
27
|
exec: function (t, arg) {
|
|
27
|
-
t.deepEqual(JSON.parse(JSON.stringify(_mapApiSlideToUi(arg.slide))), JSON.parse(JSON.stringify(arg.expectedUiSlide)));
|
|
28
|
+
t.deepEqual(JSON.parse(JSON.stringify(_mapApiSlideToUi(arg.slide, arg.answers))), JSON.parse(JSON.stringify(arg.expectedUiSlide)));
|
|
28
29
|
}
|
|
29
30
|
});
|
|
30
|
-
test('qcm', macro, { slide: qcmSlide, expectedUiSlide: qcmUISlide });
|
|
31
|
-
test('qcm drag', macro, { slide: qcmDragSlide, expectedUiSlide: qcmDragUISlide });
|
|
32
|
-
test('qcm graphic', macro, {
|
|
33
|
-
|
|
31
|
+
test('qcm', macro, { slide: qcmSlide, answers: [], expectedUiSlide: qcmUISlide });
|
|
32
|
+
test('qcm drag', macro, { slide: qcmDragSlide, answers: [], expectedUiSlide: qcmDragUISlide });
|
|
33
|
+
test('qcm graphic', macro, {
|
|
34
|
+
slide: qcmGraphicSlide,
|
|
35
|
+
answers: [],
|
|
36
|
+
expectedUiSlide: qcmGraphicUISlide
|
|
37
|
+
});
|
|
38
|
+
test('text template', macro, {
|
|
39
|
+
slide: textTemplateSlide,
|
|
40
|
+
answers: [],
|
|
41
|
+
expectedUiSlide: textTemplateUISlide
|
|
42
|
+
});
|
|
34
43
|
test('select template', macro, {
|
|
35
44
|
slide: selectTemplateSlide,
|
|
45
|
+
answers: [],
|
|
36
46
|
expectedUiSlide: selectTemplateUISlide
|
|
37
47
|
});
|
|
38
|
-
test('free text', macro, { slide: freeTextSlide, expectedUiSlide: freeTextUISlide });
|
|
39
|
-
test('slider', macro, { slide: sliderSlide, expectedUiSlide: sliderUISlide });
|
|
48
|
+
test('free text', macro, { slide: freeTextSlide, answers: [], expectedUiSlide: freeTextUISlide });
|
|
49
|
+
test('slider', macro, { slide: sliderSlide, answers: [], expectedUiSlide: sliderUISlide });
|
|
40
50
|
test('should throw an error if the question type can not be handled', function (t) {
|
|
41
51
|
var faultySlide = __assign(__assign({}, qcmSlide), { question: { type: 'lol' } });
|
|
42
|
-
t.throws(function () { return _mapApiSlideToUi(faultySlide); });
|
|
52
|
+
t.throws(function () { return _mapApiSlideToUi(faultySlide, []); });
|
|
43
53
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coorpacademy/app-review",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
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.22.
|
|
43
|
+
"@coorpacademy/components": "10.22.10",
|
|
44
44
|
"@coorpacademy/redux-task": "^1.1.5",
|
|
45
45
|
"cross-fetch": "^3.1.5",
|
|
46
46
|
"jwt-decode": "^3.1.2",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"ts-node": "^10.8.1",
|
|
78
78
|
"typescript": "^4.7.4"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "508e3fdb30d727840bd9b13e9402c2970eb17731"
|
|
81
81
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import buildTask from '@coorpacademy/redux-task';
|
|
2
|
-
import
|
|
3
|
-
import {AnyAction} from 'redux';
|
|
2
|
+
import {Dispatch} from 'redux';
|
|
4
3
|
import type {StoreState} from '../../reducers';
|
|
5
4
|
import {Options, Skill} from '../../types/common';
|
|
6
5
|
|
|
@@ -8,17 +7,18 @@ export const SKILLS_FETCH_REQUEST = '@@skills/FETCH_REQUEST' as const;
|
|
|
8
7
|
export const SKILLS_FETCH_SUCCESS = '@@skills/FETCH_SUCCESS' as const;
|
|
9
8
|
export const SKILLS_FETCH_FAILURE = '@@skills/FETCH_FAILURE' as const;
|
|
10
9
|
|
|
11
|
-
export
|
|
10
|
+
export type ReceivedSkills = {
|
|
12
11
|
type: '@@skills/FETCH_SUCCESS';
|
|
13
12
|
payload: Skill[];
|
|
14
|
-
}
|
|
13
|
+
};
|
|
15
14
|
|
|
16
|
-
export
|
|
17
|
-
|
|
15
|
+
export const fetchSkills =
|
|
16
|
+
(token: string) =>
|
|
17
|
+
async (dispatch: Dispatch, getState: () => StoreState, {services}: Options): Promise<void> => {
|
|
18
|
+
const action = buildTask({
|
|
19
|
+
types: [SKILLS_FETCH_REQUEST, SKILLS_FETCH_SUCCESS, SKILLS_FETCH_FAILURE],
|
|
20
|
+
task: () => services.fetchSkills(token)
|
|
21
|
+
});
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
types: [SKILLS_FETCH_REQUEST, SKILLS_FETCH_SUCCESS, SKILLS_FETCH_FAILURE],
|
|
22
|
-
task: (dispatch: Dispatch, getState: () => StoreState, {services}: Options) =>
|
|
23
|
-
services.fetchSkills(token)
|
|
24
|
-
});
|
|
23
|
+
await dispatch(action);
|
|
24
|
+
};
|
|
@@ -1,45 +1,49 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {ThunkAction, ThunkDispatch} from 'redux-thunk';
|
|
1
|
+
import type {Dispatch} from 'redux';
|
|
3
2
|
import buildTask from '@coorpacademy/redux-task';
|
|
4
3
|
import get from 'lodash/fp/get';
|
|
5
4
|
import has from 'lodash/fp/has';
|
|
6
5
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
7
6
|
import type {StoreState} from '../../reducers';
|
|
8
|
-
import type {Options,
|
|
7
|
+
import type {Options, SlideFromAPI} from '../../types/common';
|
|
9
8
|
import {setCurrentSlide} from '../ui/slides';
|
|
10
9
|
|
|
11
10
|
export const SLIDE_FETCH_REQUEST = '@@slides/FETCH_REQUEST' as const;
|
|
12
11
|
export const SLIDE_FETCH_SUCCESS = '@@slides/FETCH_SUCCESS' as const;
|
|
13
12
|
export const SLIDE_FETCH_FAILURE = '@@slides/FETCH_FAILURE' as const;
|
|
14
13
|
|
|
15
|
-
export
|
|
14
|
+
export type FetchSlide = {
|
|
15
|
+
type: typeof SLIDE_FETCH_REQUEST;
|
|
16
|
+
meta: {slideRef: string};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ReceivedSlide = {
|
|
16
20
|
type: typeof SLIDE_FETCH_SUCCESS;
|
|
17
21
|
payload: SlideFromAPI;
|
|
18
|
-
}
|
|
22
|
+
meta: {slideRef: string};
|
|
23
|
+
};
|
|
19
24
|
|
|
20
|
-
export
|
|
21
|
-
|
|
25
|
+
export const fetchSlide =
|
|
26
|
+
(slideRef: string, token: string) =>
|
|
27
|
+
async (dispatch: Dispatch, getState: () => StoreState, {services}: Options): Promise<void> => {
|
|
28
|
+
const action = buildTask({
|
|
29
|
+
types: [SLIDE_FETCH_REQUEST, SLIDE_FETCH_SUCCESS, SLIDE_FETCH_FAILURE],
|
|
30
|
+
bailout: (state: StoreState): boolean => {
|
|
31
|
+
return has(`data.slide.${slideRef}`, state);
|
|
32
|
+
},
|
|
33
|
+
task: () => {
|
|
34
|
+
return services.fetchSlide(slideRef, token);
|
|
35
|
+
},
|
|
36
|
+
meta: {slideRef}
|
|
37
|
+
});
|
|
38
|
+
const response = await dispatch(action);
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return has(`data.slide.${slideRef}`, state);
|
|
32
|
-
},
|
|
33
|
-
task: (dispatch: Dispatch, getState: () => StoreState, {services}: Options) => {
|
|
34
|
-
const {ref: slideRef} = get('state.nextContent', progressionFromAPI);
|
|
35
|
-
return services.fetchSlide(slideRef, token).then((slideFromAPI: SlideFromAPI | void) => {
|
|
36
|
-
if (!slideFromAPI) throw new Error('Slide not found');
|
|
37
|
-
const state = getState();
|
|
38
|
-
const slides = get('data.progression.state.slides', state);
|
|
39
|
-
if (isEmpty(slides)) {
|
|
40
|
-
dispatch(setCurrentSlide(slideFromAPI));
|
|
41
|
-
}
|
|
42
|
-
return slideFromAPI;
|
|
43
|
-
});
|
|
40
|
+
if (response.type === SLIDE_FETCH_SUCCESS) {
|
|
41
|
+
const slideFromAPI = response.payload;
|
|
42
|
+
if (!slideFromAPI) throw new Error('Slide not found');
|
|
43
|
+
const state = getState();
|
|
44
|
+
const slides = get('data.progression.state.slides', state);
|
|
45
|
+
if (isEmpty(slides)) {
|
|
46
|
+
dispatch(setCurrentSlide(slideFromAPI));
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
|
-
}
|
|
49
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {ThunkAction, ThunkDispatch} from 'redux-thunk';
|
|
1
|
+
import type {Dispatch} from 'redux';
|
|
3
2
|
import buildTask from '@coorpacademy/redux-task';
|
|
4
3
|
import {Options, ProgressionFromAPI} from '../../types/common';
|
|
5
4
|
import type {StoreState} from '../../reducers';
|
|
@@ -9,27 +8,25 @@ export const POST_PROGRESSION_REQUEST = '@@progression/POST_REQUEST' as const;
|
|
|
9
8
|
export const POST_PROGRESSION_SUCCESS = '@@progression/POST_SUCCESS' as const;
|
|
10
9
|
export const POST_PROGRESSION_FAILURE = '@@progression/POST_FAILURE' as const;
|
|
11
10
|
|
|
12
|
-
export
|
|
11
|
+
export type ReceiveProgression = {
|
|
13
12
|
type: typeof POST_PROGRESSION_SUCCESS;
|
|
14
13
|
payload: ProgressionFromAPI;
|
|
15
|
-
}
|
|
14
|
+
};
|
|
16
15
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
StoreState,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
export const postProgression =
|
|
17
|
+
(skillRef: string, token: string) =>
|
|
18
|
+
async (dispatch: Dispatch, getState: () => StoreState, {services}: Options): Promise<void> => {
|
|
19
|
+
const action = buildTask({
|
|
20
|
+
types: [POST_PROGRESSION_REQUEST, POST_PROGRESSION_SUCCESS, POST_PROGRESSION_FAILURE],
|
|
21
|
+
task: () => {
|
|
22
|
+
return services.postProgression(skillRef, token);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const response = await dispatch(action);
|
|
23
26
|
|
|
24
|
-
type
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
types: [POST_PROGRESSION_REQUEST, POST_PROGRESSION_SUCCESS, POST_PROGRESSION_FAILURE],
|
|
29
|
-
task: (dispatch: Dispatch, getState: () => StoreState, {services}: Options) => {
|
|
30
|
-
return services.postProgression(skillRef, token).then((progression: ProgressionFromAPI) => {
|
|
31
|
-
dispatch(fetchSlide(progression, token));
|
|
32
|
-
return progression;
|
|
33
|
-
});
|
|
27
|
+
if (response.type === POST_PROGRESSION_SUCCESS) {
|
|
28
|
+
const progression = response.payload;
|
|
29
|
+
const slideRef = progression.state.nextContent.ref;
|
|
30
|
+
await dispatch(fetchSlide(slideRef, token));
|
|
34
31
|
}
|
|
35
|
-
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type {ExecutionContext} from 'ava';
|
|
2
|
+
import constant from 'lodash/fp/constant';
|
|
3
|
+
import {AnyAction, applyMiddleware, compose, createStore, Dispatch, Middleware, Store} from 'redux';
|
|
4
|
+
import thunk from 'redux-thunk';
|
|
5
|
+
import rootReducer, {StoreState} from '../../../reducers';
|
|
6
|
+
import {Services} from '../../../types/common';
|
|
7
|
+
|
|
8
|
+
const assertActionsMiddleware = (t: ExecutionContext, ACTIONS: AnyAction[]): Middleware =>
|
|
9
|
+
constant((next: Dispatch) => (action: AnyAction): unknown => {
|
|
10
|
+
const expectedAction = ACTIONS.shift();
|
|
11
|
+
if (!expectedAction) throw new Error(`Missing {type: "${action.type}"} action`);
|
|
12
|
+
t.deepEqual(action, expectedAction);
|
|
13
|
+
return next(action);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const createTestStore = (
|
|
17
|
+
t: ExecutionContext,
|
|
18
|
+
initialState: StoreState,
|
|
19
|
+
services: Services,
|
|
20
|
+
actions: AnyAction[]
|
|
21
|
+
): Store => {
|
|
22
|
+
const thunkMiddleware = thunk.withExtraArgument({services});
|
|
23
|
+
const enhancer = compose(applyMiddleware(thunkMiddleware, assertActionsMiddleware(t, actions)));
|
|
24
|
+
return createStore(rootReducer, initialState, enhancer);
|
|
25
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import {Services} from '../../../types/common';
|
|
3
|
+
import {
|
|
4
|
+
fetchSkills,
|
|
5
|
+
SKILLS_FETCH_FAILURE,
|
|
6
|
+
SKILLS_FETCH_REQUEST,
|
|
7
|
+
SKILLS_FETCH_SUCCESS
|
|
8
|
+
} from '../fetch-skills';
|
|
9
|
+
import {services as mockedServices} from '../../../test/util/services.mock';
|
|
10
|
+
import {StoreState} from '../../../reducers';
|
|
11
|
+
import {createTestStore} from './create-test-store';
|
|
12
|
+
|
|
13
|
+
const initialState: StoreState = {
|
|
14
|
+
data: {
|
|
15
|
+
progression: null,
|
|
16
|
+
slides: {},
|
|
17
|
+
skills: [],
|
|
18
|
+
token: '1234'
|
|
19
|
+
},
|
|
20
|
+
ui: {
|
|
21
|
+
currentSlideRef: '',
|
|
22
|
+
navigation: [],
|
|
23
|
+
answers: []
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
test('should dispatch SKILLS_FETCH_SUCCESS actions when fetchSkills return a list of skills', async t => {
|
|
28
|
+
const services: Services = {
|
|
29
|
+
...mockedServices,
|
|
30
|
+
fetchSkills: token => {
|
|
31
|
+
t.is(token, '1234');
|
|
32
|
+
return Promise.resolve([]);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const expectedActions = [
|
|
37
|
+
{type: SKILLS_FETCH_REQUEST},
|
|
38
|
+
{
|
|
39
|
+
type: SKILLS_FETCH_SUCCESS,
|
|
40
|
+
payload: []
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const {dispatch} = createTestStore(t, initialState, services, expectedActions);
|
|
45
|
+
|
|
46
|
+
await dispatch(fetchSkills('1234'));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should dispatch SKILLS_FETCH_FAILURE action when fetchSkills fails', async t => {
|
|
50
|
+
const services: Services = {
|
|
51
|
+
...mockedServices,
|
|
52
|
+
fetchSkills: token => {
|
|
53
|
+
t.is(token, '1234');
|
|
54
|
+
return Promise.reject(new Error('unexpected'));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const expectedActions = [
|
|
59
|
+
{type: SKILLS_FETCH_REQUEST},
|
|
60
|
+
{
|
|
61
|
+
type: SKILLS_FETCH_FAILURE,
|
|
62
|
+
payload: new Error('unexpected'),
|
|
63
|
+
error: true
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const {dispatch} = createTestStore(t, initialState, services, expectedActions);
|
|
68
|
+
|
|
69
|
+
await dispatch(fetchSkills('1234'));
|
|
70
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import {Services} from '../../../types/common';
|
|
3
|
+
import {
|
|
4
|
+
fetchSlide,
|
|
5
|
+
SLIDE_FETCH_FAILURE,
|
|
6
|
+
SLIDE_FETCH_REQUEST,
|
|
7
|
+
SLIDE_FETCH_SUCCESS
|
|
8
|
+
} from '../fetch-slide';
|
|
9
|
+
import {freeTextSlide} from '../../../views/slides/test/fixtures/free-text';
|
|
10
|
+
import {services as mockedServices} from '../../../test/util/services.mock';
|
|
11
|
+
import {StoreState} from '../../../reducers';
|
|
12
|
+
import {SET_CURRENT_SLIDE} from '../../ui/slides';
|
|
13
|
+
import {createTestStore} from './create-test-store';
|
|
14
|
+
|
|
15
|
+
const initialState: StoreState = {
|
|
16
|
+
data: {
|
|
17
|
+
progression: null,
|
|
18
|
+
slides: {},
|
|
19
|
+
skills: [],
|
|
20
|
+
token: '1234'
|
|
21
|
+
},
|
|
22
|
+
ui: {
|
|
23
|
+
currentSlideRef: '',
|
|
24
|
+
navigation: [],
|
|
25
|
+
answers: []
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
test('should dispatch FETCH_SUCCESS and SET_CURRENT_SLIDE actions when fetchSlide return a slide', async t => {
|
|
30
|
+
const services: Services = {
|
|
31
|
+
...mockedServices,
|
|
32
|
+
fetchSlide: (slideRef, token) => {
|
|
33
|
+
t.is(token, '1234');
|
|
34
|
+
t.is(slideRef, 'sli_VJYjJnJhg');
|
|
35
|
+
return Promise.resolve(freeTextSlide);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const expectedActions = [
|
|
40
|
+
{type: SLIDE_FETCH_REQUEST, meta: {slideRef: 'sli_VJYjJnJhg'}},
|
|
41
|
+
{
|
|
42
|
+
type: SLIDE_FETCH_SUCCESS,
|
|
43
|
+
meta: {slideRef: 'sli_VJYjJnJhg'},
|
|
44
|
+
payload: freeTextSlide
|
|
45
|
+
},
|
|
46
|
+
{type: SET_CURRENT_SLIDE, payload: freeTextSlide}
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const {dispatch} = createTestStore(t, initialState, services, expectedActions);
|
|
50
|
+
|
|
51
|
+
await dispatch(fetchSlide('sli_VJYjJnJhg', '1234'));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('should dispatch SLIDE_FETCH_FAILURE action when fetchSlide fails', async t => {
|
|
55
|
+
const services: Services = {
|
|
56
|
+
...mockedServices,
|
|
57
|
+
fetchSlide: (slideRef, token) => {
|
|
58
|
+
t.is(token, '1234');
|
|
59
|
+
t.is(slideRef, 'slide_ref');
|
|
60
|
+
return Promise.reject(new Error('error'));
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const expectedActions = [
|
|
65
|
+
{type: SLIDE_FETCH_REQUEST, meta: {slideRef: 'slide_ref'}},
|
|
66
|
+
{
|
|
67
|
+
type: SLIDE_FETCH_FAILURE,
|
|
68
|
+
meta: {slideRef: 'slide_ref'},
|
|
69
|
+
payload: new Error('error'),
|
|
70
|
+
error: true
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const {dispatch} = createTestStore(t, initialState, services, expectedActions);
|
|
75
|
+
|
|
76
|
+
await dispatch(fetchSlide('slide_ref', '1234'));
|
|
77
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import {ProgressionFromAPI, Services} from '../../../types/common';
|
|
3
|
+
import {
|
|
4
|
+
postProgression,
|
|
5
|
+
POST_PROGRESSION_REQUEST,
|
|
6
|
+
POST_PROGRESSION_SUCCESS,
|
|
7
|
+
POST_PROGRESSION_FAILURE
|
|
8
|
+
} from '../post-progression';
|
|
9
|
+
import {freeTextSlide} from '../../../views/slides/test/fixtures/free-text';
|
|
10
|
+
import {services as mockedServices} from '../../../test/util/services.mock';
|
|
11
|
+
import {StoreState} from '../../../reducers';
|
|
12
|
+
import {SLIDE_FETCH_REQUEST, SLIDE_FETCH_SUCCESS} from '../fetch-slide';
|
|
13
|
+
import {SET_CURRENT_SLIDE} from '../../ui/slides';
|
|
14
|
+
import {createTestStore} from './create-test-store';
|
|
15
|
+
|
|
16
|
+
const initialState: StoreState = {
|
|
17
|
+
data: {
|
|
18
|
+
progression: null,
|
|
19
|
+
slides: {},
|
|
20
|
+
skills: [],
|
|
21
|
+
token: '1234'
|
|
22
|
+
},
|
|
23
|
+
ui: {
|
|
24
|
+
currentSlideRef: '',
|
|
25
|
+
navigation: [],
|
|
26
|
+
answers: []
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
test('should dispatch POST_PROGRESSION_SUCCESS and SLIDE_FETCH_REQUEST actions when postProgression return a progression', async t => {
|
|
31
|
+
const progression: ProgressionFromAPI = {
|
|
32
|
+
_id: '62b1d1087aa12f00253f40ee',
|
|
33
|
+
content: {
|
|
34
|
+
ref: '_skill-ref',
|
|
35
|
+
type: 'skill'
|
|
36
|
+
},
|
|
37
|
+
engine: {
|
|
38
|
+
ref: 'review'
|
|
39
|
+
},
|
|
40
|
+
state: {
|
|
41
|
+
allAnswers: [],
|
|
42
|
+
isCorrect: true,
|
|
43
|
+
nextContent: {
|
|
44
|
+
ref: 'sli_VJYjJnJhg',
|
|
45
|
+
type: 'slide'
|
|
46
|
+
},
|
|
47
|
+
pendingSlides: [],
|
|
48
|
+
slides: [],
|
|
49
|
+
step: {
|
|
50
|
+
current: 1
|
|
51
|
+
},
|
|
52
|
+
stars: 0
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const services: Services = {
|
|
57
|
+
...mockedServices,
|
|
58
|
+
postProgression: (skillRef, token) => {
|
|
59
|
+
t.is(token, '1234');
|
|
60
|
+
t.is(skillRef, 'skill_12345');
|
|
61
|
+
return Promise.resolve(progression);
|
|
62
|
+
},
|
|
63
|
+
fetchSlide: (slideRef, token) => {
|
|
64
|
+
t.is(token, '1234');
|
|
65
|
+
t.is(slideRef, 'sli_VJYjJnJhg');
|
|
66
|
+
return Promise.resolve(freeTextSlide);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const expectedActions = [
|
|
71
|
+
{type: POST_PROGRESSION_REQUEST},
|
|
72
|
+
{
|
|
73
|
+
type: POST_PROGRESSION_SUCCESS,
|
|
74
|
+
payload: progression
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: SLIDE_FETCH_REQUEST,
|
|
78
|
+
meta: {
|
|
79
|
+
slideRef: 'sli_VJYjJnJhg'
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: SLIDE_FETCH_SUCCESS,
|
|
84
|
+
meta: {
|
|
85
|
+
slideRef: 'sli_VJYjJnJhg'
|
|
86
|
+
},
|
|
87
|
+
payload: freeTextSlide
|
|
88
|
+
},
|
|
89
|
+
{type: SET_CURRENT_SLIDE, payload: freeTextSlide}
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const {dispatch} = createTestStore(t, initialState, services, expectedActions);
|
|
93
|
+
|
|
94
|
+
await dispatch(postProgression('skill_12345', '1234'));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should dispatch POST_PROGRESSION_FAILURE action when postProgression fails', async t => {
|
|
98
|
+
const services: Services = {
|
|
99
|
+
...mockedServices,
|
|
100
|
+
postProgression: (skillRef, token) => {
|
|
101
|
+
t.is(token, '1234');
|
|
102
|
+
t.is(skillRef, 'skill_12345');
|
|
103
|
+
return Promise.reject(new Error('error'));
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const expectedActions = [
|
|
108
|
+
{type: POST_PROGRESSION_REQUEST},
|
|
109
|
+
{
|
|
110
|
+
type: POST_PROGRESSION_FAILURE,
|
|
111
|
+
payload: new Error('error'),
|
|
112
|
+
error: true
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
const {dispatch} = createTestStore(t, initialState, services, expectedActions);
|
|
117
|
+
|
|
118
|
+
await dispatch(postProgression('skill_12345', '1234'));
|
|
119
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {Dispatch} from 'redux';
|
|
2
|
+
|
|
3
|
+
export const EDIT_BASIC = '@@answer/EDIT_BASIC' as const;
|
|
4
|
+
export type EditBasicAction = {
|
|
5
|
+
type: typeof EDIT_BASIC;
|
|
6
|
+
payload: string[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const editAnswer =
|
|
10
|
+
(answer: string) =>
|
|
11
|
+
(dispatch: Dispatch): EditBasicAction => {
|
|
12
|
+
return dispatch({
|
|
13
|
+
type: EDIT_BASIC,
|
|
14
|
+
payload: [answer]
|
|
15
|
+
});
|
|
16
|
+
};
|
package/src/index.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, {useEffect, useState} from 'react';
|
|
2
2
|
import type {} from 'redux-thunk/extend-redux'; // https://github.com/reduxjs/redux-thunk/issues/333
|
|
3
3
|
import {AnyAction, Store} from 'redux';
|
|
4
|
-
import {
|
|
4
|
+
import {useSelector, useDispatch, Provider} from 'react-redux';
|
|
5
5
|
import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
|
|
6
6
|
import {TemplateContext} from '@coorpacademy/components/es/template/app-review/template-context';
|
|
7
7
|
|
|
@@ -11,43 +11,28 @@ import configureStore from './configure-store';
|
|
|
11
11
|
|
|
12
12
|
import type {AppOptions} from './types/common';
|
|
13
13
|
import type {StoreState} from './reducers';
|
|
14
|
-
import type {SlidesViewStaticProps} from './types/views/slides';
|
|
15
14
|
|
|
16
|
-
import {
|
|
17
|
-
import {validateSlide} from './actions/ui/slides';
|
|
18
|
-
|
|
19
|
-
import {navigateTo, navigateBack, ViewPath} from './actions/ui/navigation';
|
|
15
|
+
import {navigateTo, ViewPath} from './actions/ui/navigation';
|
|
20
16
|
import {storeToken} from './actions/data/token';
|
|
21
17
|
import {fetchSkills} from './actions/api/fetch-skills';
|
|
22
18
|
import {postProgression} from './actions/api/post-progression';
|
|
23
19
|
import {VIEWS} from './common';
|
|
24
20
|
import {mapStateToSlidesProps} from './views/slides';
|
|
25
|
-
import {mapStateToSkillsProps
|
|
26
|
-
|
|
27
|
-
type StaticProps = {
|
|
28
|
-
viewName: 'skills' | 'onboarding' | 'slides' | 'loader';
|
|
29
|
-
slides: SlidesViewStaticProps | null;
|
|
30
|
-
skills: SkillsProps | null;
|
|
31
|
-
};
|
|
21
|
+
import {mapStateToSkillsProps} from './views/skills';
|
|
32
22
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
navigateBack,
|
|
36
|
-
validateSlide
|
|
37
|
-
};
|
|
23
|
+
const ConnectedApp = (): JSX.Element => {
|
|
24
|
+
const dispatch = useDispatch();
|
|
38
25
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
slides: mapStateToSlidesProps(state),
|
|
46
|
-
skills: mapStateToSkillsProps(state)
|
|
26
|
+
const props = {
|
|
27
|
+
viewName: useSelector(
|
|
28
|
+
(state: StoreState) => state.ui.navigation[state.ui.navigation.length - 1]
|
|
29
|
+
),
|
|
30
|
+
slides: useSelector((state: StoreState) => mapStateToSlidesProps(state, dispatch)),
|
|
31
|
+
skills: useSelector((state: StoreState) => mapStateToSkillsProps(state))
|
|
47
32
|
};
|
|
48
|
-
};
|
|
49
33
|
|
|
50
|
-
|
|
34
|
+
return <AppReviewTemplate {...props} />;
|
|
35
|
+
};
|
|
51
36
|
|
|
52
37
|
const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
|
|
53
38
|
const [store, setStore] = useState<Store<StoreState, AnyAction> | null>(null);
|
|
@@ -109,7 +94,7 @@ const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
|
|
|
109
94
|
return (
|
|
110
95
|
<Provider store={store}>
|
|
111
96
|
<TemplateContext values={values}>
|
|
112
|
-
<
|
|
97
|
+
<ConnectedApp />
|
|
113
98
|
</TemplateContext>
|
|
114
99
|
</Provider>
|
|
115
100
|
);
|