@coorpacademy/app-review 0.1.20 → 0.1.21-alpha.8
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/index.js +1 -4
- package/es/services/fetch-correction.d.ts +2 -0
- package/es/services/fetch-correction.js +14 -0
- package/es/services/fetch-slide.js +1 -2
- package/es/services/test/fetch-correction.test.d.ts +1 -0
- package/es/services/test/fetch-correction.test.js +39 -0
- package/es/test/util/services.mock.js +3 -0
- package/es/types/common.d.ts +8 -0
- package/lib/index.js +1 -4
- package/lib/services/fetch-correction.d.ts +2 -0
- package/lib/services/fetch-correction.js +58 -0
- package/lib/services/fetch-slide.js +2 -5
- package/lib/services/test/fetch-correction.test.d.ts +1 -0
- package/lib/services/test/fetch-correction.test.js +95 -0
- package/lib/test/util/services.mock.js +3 -0
- package/lib/types/common.d.ts +8 -0
- package/package.json +5 -4
- package/src/index.tsx +1 -6
- package/src/services/fetch-correction.ts +26 -0
- package/src/services/fetch-slide.ts +1 -2
- package/src/services/test/fetch-correction.test.ts +55 -0
- package/src/test/util/services.mock.ts +3 -0
- package/src/types/common.ts +10 -0
package/es/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import { useSelector, useDispatch, Provider } from 'react-redux';
|
|
3
3
|
import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
|
|
4
|
-
import { TemplateContext } from '@coorpacademy/components/es/template/app-review/template-context';
|
|
5
4
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
6
5
|
import get from 'lodash/fp/get';
|
|
7
6
|
import configureStore from './configure-store';
|
|
@@ -66,9 +65,7 @@ const AppReview = ({ options }) => {
|
|
|
66
65
|
}, [isProgressionCreated, options, store]);
|
|
67
66
|
if (!store)
|
|
68
67
|
return null;
|
|
69
|
-
const { templateContext: values } = options;
|
|
70
68
|
return (React.createElement(Provider, { store: store },
|
|
71
|
-
React.createElement(
|
|
72
|
-
React.createElement(ConnectedApp, null))));
|
|
69
|
+
React.createElement(ConnectedApp, null)));
|
|
73
70
|
};
|
|
74
71
|
export default AppReview;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import crossFetch from 'cross-fetch';
|
|
2
|
+
import decode from 'jwt-decode';
|
|
3
|
+
import { toJSON } from './tools/fetch-responses';
|
|
4
|
+
export const fetchCorrection = async (slideRef, token, progressionId, answer) => {
|
|
5
|
+
const { host } = decode(token);
|
|
6
|
+
const response = await crossFetch(`${host}/api/v2/progressions/${progressionId}/answers/${slideRef}`, {
|
|
7
|
+
method: 'post',
|
|
8
|
+
headers: { authorization: token },
|
|
9
|
+
body: JSON.stringify({
|
|
10
|
+
answer
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
return toJSON(response);
|
|
14
|
+
};
|
|
@@ -6,6 +6,5 @@ export const fetchSlide = async (slideRef, token) => {
|
|
|
6
6
|
const response = await crossFetch(`${host}/api/v2/slide/${slideRef}/parentContentTitle`, {
|
|
7
7
|
headers: { authorization: token }
|
|
8
8
|
});
|
|
9
|
-
|
|
10
|
-
return slide;
|
|
9
|
+
return toJSON(response);
|
|
11
10
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import nock from 'nock';
|
|
3
|
+
import { fetchCorrection } from '../fetch-correction';
|
|
4
|
+
const progressionId = '123456789123';
|
|
5
|
+
const slideRef = 'sli_123546';
|
|
6
|
+
const answer = ['Lister vos tâches pour vous libérer l’esprit', '15 jours à Bora Bora'];
|
|
7
|
+
const correction = {
|
|
8
|
+
correctAnswer: ['15 jours à Bora Bora'],
|
|
9
|
+
corrections: [
|
|
10
|
+
{
|
|
11
|
+
answer: answer[0],
|
|
12
|
+
isCorrect: false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
answer: answer[1],
|
|
16
|
+
isCorrect: true
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
};
|
|
20
|
+
test.before(() => {
|
|
21
|
+
nock('http://localhost:3000')
|
|
22
|
+
.post(`/api/v2/progressions/${progressionId}/answers/${slideRef}`, JSON.stringify({
|
|
23
|
+
answer
|
|
24
|
+
}))
|
|
25
|
+
.reply(200, correction);
|
|
26
|
+
});
|
|
27
|
+
test.after(() => {
|
|
28
|
+
nock.cleanAll();
|
|
29
|
+
});
|
|
30
|
+
test('should fetch the correction of the slide for the specified progression successfully', async (t) => {
|
|
31
|
+
const token = process.env.API_TEST_TOKEN || '';
|
|
32
|
+
const response = await fetchCorrection(slideRef, token, progressionId, answer);
|
|
33
|
+
t.deepEqual(correction, response);
|
|
34
|
+
});
|
|
35
|
+
test('should reject if a bad token is passed', async (t) => {
|
|
36
|
+
const badToken = 'token is not a jwt';
|
|
37
|
+
const error = await t.throwsAsync(() => fetchCorrection(slideRef, badToken, progressionId, answer));
|
|
38
|
+
t.is(error?.message, "Invalid token specified: Cannot read properties of undefined (reading 'replace')");
|
|
39
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import get from 'lodash/fp/get';
|
|
2
|
+
import { qcmDragSlide } from '../../views/slides/test/fixtures/qcm-drag';
|
|
2
3
|
import { qcmSlide } from '../../views/slides/test/fixtures/qcm';
|
|
3
4
|
import { qcmGraphicSlide } from '../../views/slides/test/fixtures/qcm-graphic';
|
|
4
5
|
import { freeTextSlide } from '../../views/slides/test/fixtures/free-text';
|
|
@@ -21,6 +22,8 @@ const getSlideFixture = (ref) => {
|
|
|
21
22
|
return freeTextSlide;
|
|
22
23
|
case templateSlide.universalRef:
|
|
23
24
|
return templateSlide;
|
|
25
|
+
case qcmDragSlide.universalRef:
|
|
26
|
+
return qcmDragSlide;
|
|
24
27
|
default:
|
|
25
28
|
return sliderSlide;
|
|
26
29
|
}
|
package/es/types/common.d.ts
CHANGED
|
@@ -110,6 +110,14 @@ export declare type ProgressionFromAPI = {
|
|
|
110
110
|
engine: ReviewEngine;
|
|
111
111
|
state: ProgressionState;
|
|
112
112
|
};
|
|
113
|
+
export declare type CorrectedChoice = {
|
|
114
|
+
answer: string;
|
|
115
|
+
isCorrect: boolean;
|
|
116
|
+
};
|
|
117
|
+
export declare type CorrectionFromAPI = {
|
|
118
|
+
correctAnswer: string[];
|
|
119
|
+
corrections: CorrectedChoice[];
|
|
120
|
+
};
|
|
113
121
|
export declare type Skill = {
|
|
114
122
|
skillRef: string;
|
|
115
123
|
slidesToReview: number;
|
package/lib/index.js
CHANGED
|
@@ -12,7 +12,6 @@ var __assign = (this && this.__assign) || function () {
|
|
|
12
12
|
import React, { useEffect, useState } from 'react';
|
|
13
13
|
import { useSelector, useDispatch, Provider } from 'react-redux';
|
|
14
14
|
import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
|
|
15
|
-
import { TemplateContext } from '@coorpacademy/components/es/template/app-review/template-context';
|
|
16
15
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
17
16
|
import get from 'lodash/fp/get';
|
|
18
17
|
import configureStore from './configure-store';
|
|
@@ -78,9 +77,7 @@ var AppReview = function (_a) {
|
|
|
78
77
|
}, [isProgressionCreated, options, store]);
|
|
79
78
|
if (!store)
|
|
80
79
|
return null;
|
|
81
|
-
var values = options.templateContext;
|
|
82
80
|
return (React.createElement(Provider, { store: store },
|
|
83
|
-
React.createElement(
|
|
84
|
-
React.createElement(ConnectedApp, null))));
|
|
81
|
+
React.createElement(ConnectedApp, null)));
|
|
85
82
|
};
|
|
86
83
|
export default AppReview;
|
|
@@ -0,0 +1,58 @@
|
|
|
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 crossFetch from 'cross-fetch';
|
|
38
|
+
import decode from 'jwt-decode';
|
|
39
|
+
import { toJSON } from './tools/fetch-responses';
|
|
40
|
+
export var fetchCorrection = function (slideRef, token, progressionId, answer) { return __awaiter(void 0, void 0, void 0, function () {
|
|
41
|
+
var host, response;
|
|
42
|
+
return __generator(this, function (_a) {
|
|
43
|
+
switch (_a.label) {
|
|
44
|
+
case 0:
|
|
45
|
+
host = decode(token).host;
|
|
46
|
+
return [4 /*yield*/, crossFetch("".concat(host, "/api/v2/progressions/").concat(progressionId, "/answers/").concat(slideRef), {
|
|
47
|
+
method: 'post',
|
|
48
|
+
headers: { authorization: token },
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
answer: answer
|
|
51
|
+
})
|
|
52
|
+
})];
|
|
53
|
+
case 1:
|
|
54
|
+
response = _a.sent();
|
|
55
|
+
return [2 /*return*/, toJSON(response)];
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}); };
|
|
@@ -38,7 +38,7 @@ import crossFetch from 'cross-fetch';
|
|
|
38
38
|
import decode from 'jwt-decode';
|
|
39
39
|
import { toJSON } from './tools/fetch-responses';
|
|
40
40
|
export var fetchSlide = function (slideRef, token) { return __awaiter(void 0, void 0, void 0, function () {
|
|
41
|
-
var host, response
|
|
41
|
+
var host, response;
|
|
42
42
|
return __generator(this, function (_a) {
|
|
43
43
|
switch (_a.label) {
|
|
44
44
|
case 0:
|
|
@@ -48,10 +48,7 @@ export var fetchSlide = function (slideRef, token) { return __awaiter(void 0, vo
|
|
|
48
48
|
})];
|
|
49
49
|
case 1:
|
|
50
50
|
response = _a.sent();
|
|
51
|
-
return [
|
|
52
|
-
case 2:
|
|
53
|
-
slide = (_a.sent());
|
|
54
|
-
return [2 /*return*/, slide];
|
|
51
|
+
return [2 /*return*/, toJSON(response)];
|
|
55
52
|
}
|
|
56
53
|
});
|
|
57
54
|
}); };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
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 nock from 'nock';
|
|
39
|
+
import { fetchCorrection } from '../fetch-correction';
|
|
40
|
+
var progressionId = '123456789123';
|
|
41
|
+
var slideRef = 'sli_123546';
|
|
42
|
+
var answer = ['Lister vos tâches pour vous libérer l’esprit', '15 jours à Bora Bora'];
|
|
43
|
+
var correction = {
|
|
44
|
+
correctAnswer: ['15 jours à Bora Bora'],
|
|
45
|
+
corrections: [
|
|
46
|
+
{
|
|
47
|
+
answer: answer[0],
|
|
48
|
+
isCorrect: false
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
answer: answer[1],
|
|
52
|
+
isCorrect: true
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
};
|
|
56
|
+
test.before(function () {
|
|
57
|
+
nock('http://localhost:3000')
|
|
58
|
+
.post("/api/v2/progressions/".concat(progressionId, "/answers/").concat(slideRef), JSON.stringify({
|
|
59
|
+
answer: answer
|
|
60
|
+
}))
|
|
61
|
+
.reply(200, correction);
|
|
62
|
+
});
|
|
63
|
+
test.after(function () {
|
|
64
|
+
nock.cleanAll();
|
|
65
|
+
});
|
|
66
|
+
test('should fetch the correction of the slide for the specified progression successfully', function (t) { return __awaiter(void 0, void 0, void 0, function () {
|
|
67
|
+
var token, response;
|
|
68
|
+
return __generator(this, function (_a) {
|
|
69
|
+
switch (_a.label) {
|
|
70
|
+
case 0:
|
|
71
|
+
token = process.env.API_TEST_TOKEN || '';
|
|
72
|
+
return [4 /*yield*/, fetchCorrection(slideRef, token, progressionId, answer)];
|
|
73
|
+
case 1:
|
|
74
|
+
response = _a.sent();
|
|
75
|
+
t.deepEqual(correction, response);
|
|
76
|
+
return [2 /*return*/];
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}); });
|
|
80
|
+
test('should reject if a bad token is passed', function (t) { return __awaiter(void 0, void 0, void 0, function () {
|
|
81
|
+
var badToken, error;
|
|
82
|
+
return __generator(this, function (_a) {
|
|
83
|
+
switch (_a.label) {
|
|
84
|
+
case 0:
|
|
85
|
+
badToken = 'token is not a jwt';
|
|
86
|
+
return [4 /*yield*/, t.throwsAsync(function () {
|
|
87
|
+
return fetchCorrection(slideRef, badToken, progressionId, answer);
|
|
88
|
+
})];
|
|
89
|
+
case 1:
|
|
90
|
+
error = _a.sent();
|
|
91
|
+
t.is(error === null || error === void 0 ? void 0 : error.message, "Invalid token specified: Cannot read properties of undefined (reading 'replace')");
|
|
92
|
+
return [2 /*return*/];
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}); });
|
|
@@ -11,6 +11,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
};
|
|
12
12
|
var _a;
|
|
13
13
|
import get from 'lodash/fp/get';
|
|
14
|
+
import { qcmDragSlide } from '../../views/slides/test/fixtures/qcm-drag';
|
|
14
15
|
import { qcmSlide } from '../../views/slides/test/fixtures/qcm';
|
|
15
16
|
import { qcmGraphicSlide } from '../../views/slides/test/fixtures/qcm-graphic';
|
|
16
17
|
import { freeTextSlide } from '../../views/slides/test/fixtures/free-text';
|
|
@@ -33,6 +34,8 @@ var getSlideFixture = function (ref) {
|
|
|
33
34
|
return freeTextSlide;
|
|
34
35
|
case templateSlide.universalRef:
|
|
35
36
|
return templateSlide;
|
|
37
|
+
case qcmDragSlide.universalRef:
|
|
38
|
+
return qcmDragSlide;
|
|
36
39
|
default:
|
|
37
40
|
return sliderSlide;
|
|
38
41
|
}
|
package/lib/types/common.d.ts
CHANGED
|
@@ -110,6 +110,14 @@ export declare type ProgressionFromAPI = {
|
|
|
110
110
|
engine: ReviewEngine;
|
|
111
111
|
state: ProgressionState;
|
|
112
112
|
};
|
|
113
|
+
export declare type CorrectedChoice = {
|
|
114
|
+
answer: string;
|
|
115
|
+
isCorrect: boolean;
|
|
116
|
+
};
|
|
117
|
+
export declare type CorrectionFromAPI = {
|
|
118
|
+
correctAnswer: string[];
|
|
119
|
+
corrections: CorrectedChoice[];
|
|
120
|
+
};
|
|
113
121
|
export declare type Skill = {
|
|
114
122
|
skillRef: string;
|
|
115
123
|
slidesToReview: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coorpacademy/app-review",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21-alpha.8+d10426e39",
|
|
4
4
|
"description": "",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16.15.0"
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"./package.json": "./package.json"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@coorpacademy/components": "10.22.
|
|
45
|
-
"@coorpacademy/redux-task": "
|
|
44
|
+
"@coorpacademy/components": "10.22.15-alpha.8+d10426e39",
|
|
45
|
+
"@coorpacademy/redux-task": "1.1.5",
|
|
46
46
|
"cross-fetch": "^3.1.5",
|
|
47
47
|
"jwt-decode": "^3.1.2",
|
|
48
48
|
"react-redux": "^8.0.1",
|
|
@@ -77,5 +77,6 @@
|
|
|
77
77
|
"react-dom": "^17.0.2",
|
|
78
78
|
"ts-node": "^10.9.1",
|
|
79
79
|
"typescript": "^4.7.4"
|
|
80
|
-
}
|
|
80
|
+
},
|
|
81
|
+
"gitHead": "d10426e390835b81b9b692661522c08ead9db231"
|
|
81
82
|
}
|
package/src/index.tsx
CHANGED
|
@@ -3,7 +3,6 @@ import type {} from 'redux-thunk/extend-redux'; // https://github.com/reduxjs/re
|
|
|
3
3
|
import {AnyAction, Store} from 'redux';
|
|
4
4
|
import {useSelector, useDispatch, Provider} from 'react-redux';
|
|
5
5
|
import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
|
|
6
|
-
import {TemplateContext} from '@coorpacademy/components/es/template/app-review/template-context';
|
|
7
6
|
|
|
8
7
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
9
8
|
import get from 'lodash/fp/get';
|
|
@@ -87,13 +86,9 @@ const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
|
|
|
87
86
|
|
|
88
87
|
if (!store) return null;
|
|
89
88
|
|
|
90
|
-
const {templateContext: values} = options;
|
|
91
|
-
|
|
92
89
|
return (
|
|
93
90
|
<Provider store={store}>
|
|
94
|
-
<
|
|
95
|
-
<ConnectedApp />
|
|
96
|
-
</TemplateContext>
|
|
91
|
+
<ConnectedApp />
|
|
97
92
|
</Provider>
|
|
98
93
|
);
|
|
99
94
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import crossFetch from 'cross-fetch';
|
|
2
|
+
import decode from 'jwt-decode';
|
|
3
|
+
|
|
4
|
+
import {CorrectionFromAPI, JWT} from '../types/common';
|
|
5
|
+
import {toJSON} from './tools/fetch-responses';
|
|
6
|
+
|
|
7
|
+
export const fetchCorrection = async (
|
|
8
|
+
slideRef: string,
|
|
9
|
+
token: string,
|
|
10
|
+
progressionId: string,
|
|
11
|
+
answer: string[]
|
|
12
|
+
): Promise<CorrectionFromAPI | void> => {
|
|
13
|
+
const {host}: JWT = decode(token);
|
|
14
|
+
const response = await crossFetch(
|
|
15
|
+
`${host}/api/v2/progressions/${progressionId}/answers/${slideRef}`,
|
|
16
|
+
{
|
|
17
|
+
method: 'post',
|
|
18
|
+
headers: {authorization: token},
|
|
19
|
+
body: JSON.stringify({
|
|
20
|
+
answer
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return toJSON<CorrectionFromAPI>(response);
|
|
26
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import nock from 'nock';
|
|
3
|
+
import {CorrectionFromAPI} from '../../types/common';
|
|
4
|
+
import {fetchCorrection} from '../fetch-correction';
|
|
5
|
+
|
|
6
|
+
const progressionId = '123456789123';
|
|
7
|
+
const slideRef = 'sli_123546';
|
|
8
|
+
const answer = ['Lister vos tâches pour vous libérer l’esprit', '15 jours à Bora Bora'];
|
|
9
|
+
|
|
10
|
+
const correction: CorrectionFromAPI = {
|
|
11
|
+
correctAnswer: ['15 jours à Bora Bora'],
|
|
12
|
+
corrections: [
|
|
13
|
+
{
|
|
14
|
+
answer: answer[0],
|
|
15
|
+
isCorrect: false
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
answer: answer[1],
|
|
19
|
+
isCorrect: true
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
test.before(() => {
|
|
25
|
+
nock('http://localhost:3000')
|
|
26
|
+
.post(
|
|
27
|
+
`/api/v2/progressions/${progressionId}/answers/${slideRef}`,
|
|
28
|
+
JSON.stringify({
|
|
29
|
+
answer
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
.reply(200, correction);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test.after(() => {
|
|
36
|
+
nock.cleanAll();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should fetch the correction of the slide for the specified progression successfully', async t => {
|
|
40
|
+
const token = process.env.API_TEST_TOKEN || '';
|
|
41
|
+
const response = await fetchCorrection(slideRef, token, progressionId, answer);
|
|
42
|
+
t.deepEqual(correction, response);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should reject if a bad token is passed', async t => {
|
|
46
|
+
const badToken = 'token is not a jwt';
|
|
47
|
+
const error = await t.throwsAsync(() =>
|
|
48
|
+
fetchCorrection(slideRef, badToken, progressionId, answer)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
t.is(
|
|
52
|
+
error?.message,
|
|
53
|
+
"Invalid token specified: Cannot read properties of undefined (reading 'replace')"
|
|
54
|
+
);
|
|
55
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import get from 'lodash/fp/get';
|
|
2
|
+
import {qcmDragSlide} from '../../views/slides/test/fixtures/qcm-drag';
|
|
2
3
|
import {qcmSlide} from '../../views/slides/test/fixtures/qcm';
|
|
3
4
|
import {qcmGraphicSlide} from '../../views/slides/test/fixtures/qcm-graphic';
|
|
4
5
|
import {freeTextSlide} from '../../views/slides/test/fixtures/free-text';
|
|
@@ -31,6 +32,8 @@ const getSlideFixture = (ref: string): SlideFromAPI => {
|
|
|
31
32
|
return freeTextSlide;
|
|
32
33
|
case templateSlide.universalRef:
|
|
33
34
|
return templateSlide;
|
|
35
|
+
case qcmDragSlide.universalRef:
|
|
36
|
+
return qcmDragSlide;
|
|
34
37
|
default:
|
|
35
38
|
return sliderSlide;
|
|
36
39
|
}
|
package/src/types/common.ts
CHANGED
|
@@ -131,6 +131,16 @@ export type ProgressionFromAPI = {
|
|
|
131
131
|
state: ProgressionState;
|
|
132
132
|
};
|
|
133
133
|
|
|
134
|
+
export type CorrectedChoice = {
|
|
135
|
+
answer: string;
|
|
136
|
+
isCorrect: boolean;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export type CorrectionFromAPI = {
|
|
140
|
+
correctAnswer: string[];
|
|
141
|
+
corrections: CorrectedChoice[];
|
|
142
|
+
};
|
|
143
|
+
|
|
134
144
|
export type Skill = {
|
|
135
145
|
skillRef: string;
|
|
136
146
|
slidesToReview: number;
|