@quesmed/types 2.6.209 → 2.6.210
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/dist/cjs/models/Marksheet.d.ts +9 -1
- package/dist/cjs/models/Marksheet.js +7 -1
- package/dist/cjs/models/Question.d.ts +2 -2
- package/dist/cjs/resolvers/fragments/marksheet.js +4 -0
- package/dist/cjs/resolvers/fragments/record.d.ts +0 -1
- package/dist/cjs/resolvers/fragments/record.js +14 -19
- package/dist/cjs/resolvers/mutation/restricted/marksheet.d.ts +2 -0
- package/dist/cjs/resolvers/mutation/restricted/marksheet.js +10 -0
- package/dist/cjs/resolvers/mutation/restricted/mockTest.d.ts +3 -0
- package/dist/cjs/resolvers/query/admin/record.js +2 -2
- package/dist/cjs/resolvers/query/restricted/analytics.js +2 -0
- package/dist/cjs/resolvers/subscription/marksheet.d.ts +6 -4
- package/dist/cjs/resolvers/subscription/marksheet.js +2 -0
- package/dist/cjs/utils/evaluateMark.d.ts +14 -0
- package/dist/cjs/utils/evaluateMark.js +310 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +1 -0
- package/dist/mjs/models/Marksheet.d.ts +9 -1
- package/dist/mjs/models/Marksheet.js +6 -0
- package/dist/mjs/models/Question.d.ts +2 -2
- package/dist/mjs/resolvers/fragments/marksheet.js +4 -0
- package/dist/mjs/resolvers/fragments/record.d.ts +0 -1
- package/dist/mjs/resolvers/fragments/record.js +13 -18
- package/dist/mjs/resolvers/mutation/restricted/marksheet.d.ts +2 -0
- package/dist/mjs/resolvers/mutation/restricted/marksheet.js +10 -0
- package/dist/mjs/resolvers/mutation/restricted/mockTest.d.ts +3 -0
- package/dist/mjs/resolvers/query/admin/record.js +2 -2
- package/dist/mjs/resolvers/query/restricted/analytics.js +2 -0
- package/dist/mjs/resolvers/subscription/marksheet.d.ts +6 -4
- package/dist/mjs/resolvers/subscription/marksheet.js +2 -0
- package/dist/mjs/utils/evaluateMark.d.ts +14 -0
- package/dist/mjs/utils/evaluateMark.js +306 -0
- package/dist/mjs/utils/index.d.ts +1 -0
- package/dist/mjs/utils/index.js +1 -0
- package/package.json +1 -1
|
@@ -76,6 +76,7 @@ export interface IMarksheet {
|
|
|
76
76
|
isTestMarksheet: boolean;
|
|
77
77
|
correct?: number;
|
|
78
78
|
incorrect?: number;
|
|
79
|
+
partial?: number;
|
|
79
80
|
totalQuestions?: number;
|
|
80
81
|
sessionId: string;
|
|
81
82
|
passingMark: number;
|
|
@@ -93,7 +94,12 @@ export interface IMarksheet {
|
|
|
93
94
|
builderConfig?: IBuildConfigData;
|
|
94
95
|
entitlementId: EProductType | EEntitlementType;
|
|
95
96
|
}
|
|
96
|
-
export type IMarksheetMarkJSONB = string | [string] | [IQuestionQAAnswer] | [string[], string[]] | [IPrescribeMark] | null;
|
|
97
|
+
export type IMarksheetMarkJSONB = string | [string] | string[] | [IQuestionQAAnswer] | [string[], string[]] | [IPrescribeMark] | [string, string, string] | [string, string] | [string, string][] | null;
|
|
98
|
+
export declare enum EMarkResult {
|
|
99
|
+
Incorrect = 0,
|
|
100
|
+
Correct = 1,
|
|
101
|
+
Partial = 2
|
|
102
|
+
}
|
|
97
103
|
export interface IMarksheetMark {
|
|
98
104
|
id: Id;
|
|
99
105
|
createdAt: number | Date;
|
|
@@ -110,6 +116,8 @@ export interface IMarksheetMark {
|
|
|
110
116
|
marksheet?: IMarksheet;
|
|
111
117
|
isAnswered: boolean;
|
|
112
118
|
striked: number[];
|
|
119
|
+
score: number;
|
|
120
|
+
result: EMarkResult;
|
|
113
121
|
}
|
|
114
122
|
export interface IPreBuildMarksheetRef {
|
|
115
123
|
createdAt: number | Date;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EMarksheetAction = exports.EMarksheetType = exports.EStudyAction = exports.MARKSHEET_SOURCE = exports.EMarksheetState = void 0;
|
|
3
|
+
exports.EMarkResult = exports.EMarksheetAction = exports.EMarksheetType = exports.EStudyAction = exports.MARKSHEET_SOURCE = exports.EMarksheetState = void 0;
|
|
4
4
|
var EMarksheetState;
|
|
5
5
|
(function (EMarksheetState) {
|
|
6
6
|
EMarksheetState[EMarksheetState["LOBBY"] = 0] = "LOBBY";
|
|
@@ -50,3 +50,9 @@ var EMarksheetAction;
|
|
|
50
50
|
EMarksheetAction[EMarksheetAction["ANSWER_SELECTED"] = 15] = "ANSWER_SELECTED";
|
|
51
51
|
EMarksheetAction[EMarksheetAction["MARK_CHECK_UNCHECK"] = 16] = "MARK_CHECK_UNCHECK";
|
|
52
52
|
})(EMarksheetAction = exports.EMarksheetAction || (exports.EMarksheetAction = {}));
|
|
53
|
+
var EMarkResult;
|
|
54
|
+
(function (EMarkResult) {
|
|
55
|
+
EMarkResult[EMarkResult["Incorrect"] = 0] = "Incorrect";
|
|
56
|
+
EMarkResult[EMarkResult["Correct"] = 1] = "Correct";
|
|
57
|
+
EMarkResult[EMarkResult["Partial"] = 2] = "Partial";
|
|
58
|
+
})(EMarkResult = exports.EMarkResult || (exports.EMarkResult = {}));
|
|
@@ -77,7 +77,7 @@ export interface IQuestionCommentLike {
|
|
|
77
77
|
comment: IQuestionComment;
|
|
78
78
|
likeTrueDislikeFalse: boolean;
|
|
79
79
|
}
|
|
80
|
-
export type IQuestionAnswer = string | [string] | [IQuestionQAAnswer] | [string[], string[]] |
|
|
80
|
+
export type IQuestionAnswer = string | [string] | [IQuestionQAAnswer] | [string[], string[]] | IPrescribeAnswer[] | [string, string][] | [string, string, string] | string[] | [string, string];
|
|
81
81
|
export type IQuestionAll = IQuestion | IQuestionSBA | IQuestionQA | IQuestionMultiQ | IQuestionPrescribe | IQuestionEMQ | IQuestionSelect3 | IQuestionRanking | IQuestionSjtTwoAnswer;
|
|
82
82
|
export interface IQuestion {
|
|
83
83
|
id: Id;
|
|
@@ -207,7 +207,7 @@ export interface IQuestionSjtTwoAnswer extends IQuestion {
|
|
|
207
207
|
sjtTwoAnswer: [string, string];
|
|
208
208
|
}
|
|
209
209
|
export interface IQuestionPrescribe extends IQuestion {
|
|
210
|
-
answer:
|
|
210
|
+
answer: IPrescribeAnswer[];
|
|
211
211
|
prescribeAnswer: IPrescribeAnswer[];
|
|
212
212
|
}
|
|
213
213
|
export type IPrescribeAnswerData = {
|
|
@@ -15,6 +15,8 @@ exports.MARKSHEET_MARK_FIELDS = (0, client_1.gql) `
|
|
|
15
15
|
isAnswered
|
|
16
16
|
striked
|
|
17
17
|
mark
|
|
18
|
+
result
|
|
19
|
+
score
|
|
18
20
|
questionId
|
|
19
21
|
question {
|
|
20
22
|
...QuestionFields
|
|
@@ -144,5 +146,7 @@ exports.NEW_MARK_FIELDS = (0, client_1.gql) `
|
|
|
144
146
|
questionChoiceId
|
|
145
147
|
mark
|
|
146
148
|
isAnswered
|
|
149
|
+
result
|
|
150
|
+
score
|
|
147
151
|
}
|
|
148
152
|
`;
|
|
@@ -3,7 +3,6 @@ export declare const JOB_REMARK_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
|
3
3
|
export declare const JOB_ASSET_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
4
4
|
export declare const JOB_RECORD_METRICS_SUMMARY_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
5
5
|
export declare const JOB_RECORD_CHOICE_SUMMARY_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
6
|
-
export declare const JOB_RECORD_STATISTICS_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
7
6
|
export declare const JOB_RECORD_QUESTION_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
8
7
|
export declare const JOB_RECORD_CHAPTER_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
9
8
|
export declare const JOB_RECORD_STATION_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JOB_RECORD_FRAGMENT = exports.JOB_RECORD_STATUS_FRAGMENT = exports.JOB_RECORD_MOCK_TEST_FRAGMENT = exports.JOB_RECORD_STATION_FRAGMENT = exports.JOB_RECORD_CHAPTER_FRAGMENT = exports.JOB_RECORD_QUESTION_FRAGMENT = exports.
|
|
3
|
+
exports.JOB_RECORD_FRAGMENT = exports.JOB_RECORD_STATUS_FRAGMENT = exports.JOB_RECORD_MOCK_TEST_FRAGMENT = exports.JOB_RECORD_STATION_FRAGMENT = exports.JOB_RECORD_CHAPTER_FRAGMENT = exports.JOB_RECORD_QUESTION_FRAGMENT = exports.JOB_RECORD_CHOICE_SUMMARY_FRAGMENT = exports.JOB_RECORD_METRICS_SUMMARY_FRAGMENT = exports.JOB_ASSET_FRAGMENT = exports.JOB_REMARK_FRAGMENT = exports.JOB_USER_FRAGMENT = void 0;
|
|
4
4
|
const client_1 = require("@apollo/client");
|
|
5
5
|
exports.JOB_USER_FRAGMENT = (0, client_1.gql) `
|
|
6
6
|
fragment JobUser on User {
|
|
@@ -63,10 +63,6 @@ exports.JOB_RECORD_METRICS_SUMMARY_FRAGMENT = (0, client_1.gql) `
|
|
|
63
63
|
correct
|
|
64
64
|
incorrect
|
|
65
65
|
percentage
|
|
66
|
-
commentCount
|
|
67
|
-
likes
|
|
68
|
-
dislikes
|
|
69
|
-
public
|
|
70
66
|
}
|
|
71
67
|
`;
|
|
72
68
|
exports.JOB_RECORD_CHOICE_SUMMARY_FRAGMENT = (0, client_1.gql) `
|
|
@@ -78,18 +74,18 @@ exports.JOB_RECORD_CHOICE_SUMMARY_FRAGMENT = (0, client_1.gql) `
|
|
|
78
74
|
questionId
|
|
79
75
|
}
|
|
80
76
|
`;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
`;
|
|
77
|
+
// export const JOB_RECORD_STATISTICS_FRAGMENT = gql`
|
|
78
|
+
// ${JOB_RECORD_METRICS_SUMMARY_FRAGMENT}
|
|
79
|
+
// ${JOB_RECORD_CHOICE_SUMMARY_FRAGMENT}
|
|
80
|
+
// fragment JobRecordStatistics on JobRecord {
|
|
81
|
+
// metricsSummary {
|
|
82
|
+
// ...JobRecordMetricsSummary
|
|
83
|
+
// }
|
|
84
|
+
// choiceSummary {
|
|
85
|
+
// ...JobRecordChoiceSummary
|
|
86
|
+
// }
|
|
87
|
+
// }
|
|
88
|
+
// `;
|
|
93
89
|
exports.JOB_RECORD_QUESTION_FRAGMENT = (0, client_1.gql) `
|
|
94
90
|
fragment JobRecordQuestion on JobRecordQuestion {
|
|
95
91
|
question
|
|
@@ -170,7 +166,6 @@ exports.JOB_RECORD_FRAGMENT = (0, client_1.gql) `
|
|
|
170
166
|
${exports.JOB_RECORD_CHAPTER_FRAGMENT}
|
|
171
167
|
${exports.JOB_RECORD_STATION_FRAGMENT}
|
|
172
168
|
${exports.JOB_RECORD_MOCK_TEST_FRAGMENT}
|
|
173
|
-
${exports.JOB_RECORD_STATISTICS_FRAGMENT}
|
|
174
169
|
${exports.JOB_ASSET_FRAGMENT}
|
|
175
170
|
fragment JobRecord on JobRecord {
|
|
176
171
|
id
|
|
@@ -208,6 +203,6 @@ exports.JOB_RECORD_FRAGMENT = (0, client_1.gql) `
|
|
|
208
203
|
updatedAt
|
|
209
204
|
publishedAt
|
|
210
205
|
...JobRecordStatus
|
|
211
|
-
...JobRecordStatistics
|
|
206
|
+
# ...JobRecordStatistics
|
|
212
207
|
}
|
|
213
208
|
`;
|
|
@@ -190,6 +190,7 @@ export declare const optimisticModifyMarksheetBuilderConfig: (marksheetId: numbe
|
|
|
190
190
|
isTestMarksheet: boolean;
|
|
191
191
|
correct?: number | undefined;
|
|
192
192
|
incorrect?: number | undefined;
|
|
193
|
+
partial?: number | undefined;
|
|
193
194
|
totalQuestions?: number | undefined;
|
|
194
195
|
sessionId: string;
|
|
195
196
|
passingMark: number;
|
|
@@ -283,6 +284,7 @@ export declare const optimisticEndMarksheet: (marksheet: IMarksheet) => {
|
|
|
283
284
|
isTestMarksheet: boolean;
|
|
284
285
|
correct?: number | undefined;
|
|
285
286
|
incorrect?: number | undefined;
|
|
287
|
+
partial?: number | undefined;
|
|
286
288
|
totalQuestions?: number | undefined;
|
|
287
289
|
sessionId: string;
|
|
288
290
|
passingMark: number;
|
|
@@ -70,6 +70,8 @@ exports.SAVE_MARKSHEET = (0, client_1.gql) `
|
|
|
70
70
|
state
|
|
71
71
|
marks {
|
|
72
72
|
isAnswered
|
|
73
|
+
result
|
|
74
|
+
score
|
|
73
75
|
id
|
|
74
76
|
marksheetId
|
|
75
77
|
questionChoiceId
|
|
@@ -103,6 +105,8 @@ const updateMarksheets = (cache, result, options) => {
|
|
|
103
105
|
mark: marksheet.mark,
|
|
104
106
|
questionChoiceId: marksheet.choiceId,
|
|
105
107
|
isAnswered: true,
|
|
108
|
+
result: 0,
|
|
109
|
+
score: 0,
|
|
106
110
|
},
|
|
107
111
|
fragment: marksheet_1.NEW_MARK_FIELDS,
|
|
108
112
|
});
|
|
@@ -123,6 +127,8 @@ const optimisticSaveMarksheets = (marksheet, marksheetInput, questionIndex) => {
|
|
|
123
127
|
questionChoiceId: choiceId ?? null,
|
|
124
128
|
isAnswered: true,
|
|
125
129
|
mark: mark || null,
|
|
130
|
+
result: 0,
|
|
131
|
+
score: 0,
|
|
126
132
|
};
|
|
127
133
|
const updatedMarks = [
|
|
128
134
|
...marks.slice(0, questionIndex),
|
|
@@ -345,6 +351,8 @@ exports.MODIFY_MARKSHEET_MARK = (0, client_1.gql) `
|
|
|
345
351
|
questionChoiceId
|
|
346
352
|
timeTaken
|
|
347
353
|
mark
|
|
354
|
+
result
|
|
355
|
+
score
|
|
348
356
|
isAnswered
|
|
349
357
|
striked
|
|
350
358
|
}
|
|
@@ -453,6 +461,8 @@ exports.TOGGLE_STRIKE_OPTIONS = (0, client_1.gql) `
|
|
|
453
461
|
index
|
|
454
462
|
isAnswered
|
|
455
463
|
mark
|
|
464
|
+
result
|
|
465
|
+
score
|
|
456
466
|
marksheetId
|
|
457
467
|
question {
|
|
458
468
|
id
|
|
@@ -29,6 +29,8 @@ export declare const optimisticToggleFlaggedQuestion: (mark: IMarksheetMark, fla
|
|
|
29
29
|
marksheet?: IMarksheet | undefined;
|
|
30
30
|
isAnswered: boolean;
|
|
31
31
|
striked: number[];
|
|
32
|
+
score: number;
|
|
33
|
+
result: import("../../../models").EMarkResult;
|
|
32
34
|
};
|
|
33
35
|
};
|
|
34
36
|
};
|
|
@@ -64,6 +66,7 @@ export declare const optimisticEndMockTest: (marksheet: IMarksheet) => {
|
|
|
64
66
|
isTestMarksheet: boolean;
|
|
65
67
|
correct?: number | undefined;
|
|
66
68
|
incorrect?: number | undefined;
|
|
69
|
+
partial?: number | undefined;
|
|
67
70
|
totalQuestions?: number | undefined;
|
|
68
71
|
sessionId: string;
|
|
69
72
|
passingMark: number;
|
|
@@ -5,9 +5,9 @@ const client_1 = require("@apollo/client");
|
|
|
5
5
|
const fragments_1 = require("../../fragments");
|
|
6
6
|
exports.GET_JOB_RECORDS = (0, client_1.gql) `
|
|
7
7
|
${fragments_1.JOB_RECORD_FRAGMENT}
|
|
8
|
-
query GetJobRecords($jobId: ID
|
|
8
|
+
query GetJobRecords($jobId: ID!) {
|
|
9
9
|
admin {
|
|
10
|
-
getJobRecords(jobId: $jobId
|
|
10
|
+
getJobRecords(jobId: $jobId) {
|
|
11
11
|
...JobRecord
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EMarksheetAction, EMarksheetState, Id,
|
|
1
|
+
import { EMarksheetAction, EMarksheetState, Id, IMarksheetMark, IUser } from '../../models';
|
|
2
2
|
import { IBuildConfigData, IPreBuildMarksheet } from '../mutation/restricted';
|
|
3
3
|
import { RootData } from '../types';
|
|
4
4
|
export interface IMarksheetGroupMember {
|
|
@@ -58,12 +58,14 @@ export interface IMarksheetMarkData {
|
|
|
58
58
|
newMarkId?: Id;
|
|
59
59
|
markIndex?: number;
|
|
60
60
|
questionChoiceId?: Id;
|
|
61
|
-
mark?:
|
|
61
|
+
mark?: IMarksheetMark['mark'];
|
|
62
62
|
isAnswered?: boolean;
|
|
63
|
-
|
|
63
|
+
score?: IMarksheetMark['score'];
|
|
64
|
+
result?: IMarksheetMark['result'];
|
|
65
|
+
timeTaken?: IMarksheetMark['timeTaken'];
|
|
64
66
|
updatedAt?: Date;
|
|
65
67
|
user: IUser;
|
|
66
|
-
striked?:
|
|
68
|
+
striked?: IMarksheetMark['striked'];
|
|
67
69
|
}
|
|
68
70
|
export type IOnMarksheetMarkChangeData = RootData<IMarksheetMarkData, 'onMarksheetMarkChange'>;
|
|
69
71
|
export declare const ON_MARKSHEET_MARK_CHANGE_KEY = "ON_MARKSHEET_CHANGE_KEY";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EMarkResult, EPsaSectionType, EQuestionType, IMarksheetMarkJSONB, IQuestionAnswer } from '../models';
|
|
2
|
+
export interface IEvaluateMarkData {
|
|
3
|
+
score: number;
|
|
4
|
+
result: EMarkResult;
|
|
5
|
+
}
|
|
6
|
+
export declare function evaluateMark({ mark, answer, questionTypeId, psaSectionId, choices, }: {
|
|
7
|
+
mark: IMarksheetMarkJSONB;
|
|
8
|
+
answer: IQuestionAnswer;
|
|
9
|
+
questionTypeId: EQuestionType;
|
|
10
|
+
psaSectionId: EPsaSectionType | null;
|
|
11
|
+
choices?: Array<{
|
|
12
|
+
label: string;
|
|
13
|
+
}>;
|
|
14
|
+
}): IEvaluateMarkData;
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.evaluateMark = void 0;
|
|
4
|
+
const models_1 = require("../models");
|
|
5
|
+
const object_1 = require("./object");
|
|
6
|
+
function isPrescribeAnswer(data) {
|
|
7
|
+
return Object(data).hasOwnProperty('dose');
|
|
8
|
+
}
|
|
9
|
+
function mapPrescribeMarkToAnswer(obj) {
|
|
10
|
+
if (isPrescribeAnswer(obj)) {
|
|
11
|
+
return {
|
|
12
|
+
drugId: obj.drug.value,
|
|
13
|
+
doseId: obj.dose.value,
|
|
14
|
+
durationId: obj.duration.value,
|
|
15
|
+
frequencyId: obj.frequency.value,
|
|
16
|
+
routeId: obj.route.value,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
drugId: obj.drugId,
|
|
21
|
+
doseId: obj.doseId,
|
|
22
|
+
durationId: obj.durationId,
|
|
23
|
+
frequencyId: obj.frequencyId,
|
|
24
|
+
routeId: obj.routeId,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function createHashMap(arr) {
|
|
28
|
+
const map = new Map();
|
|
29
|
+
for (const innerArr of arr) {
|
|
30
|
+
const sortedInnerArr = innerArr.slice().sort();
|
|
31
|
+
const key = sortedInnerArr.join('|');
|
|
32
|
+
map.set(key, (map.get(key) || 0) + 1);
|
|
33
|
+
}
|
|
34
|
+
return map;
|
|
35
|
+
}
|
|
36
|
+
function deepParse(data) {
|
|
37
|
+
let parsed = data;
|
|
38
|
+
while (typeof parsed === 'string') {
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(parsed);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
function evaluateMark({ mark, answer, questionTypeId, psaSectionId, choices, }) {
|
|
49
|
+
const data = {
|
|
50
|
+
score: 0,
|
|
51
|
+
result: models_1.EMarkResult.Incorrect,
|
|
52
|
+
};
|
|
53
|
+
if (!mark || !answer) {
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const flatAnswer = answer[0];
|
|
58
|
+
const jsonAnswer = deepParse(mark);
|
|
59
|
+
const flatAttempt = jsonAnswer[0];
|
|
60
|
+
switch (questionTypeId) {
|
|
61
|
+
case models_1.EQuestionType.SINGLE_BEST_ANSWER:
|
|
62
|
+
case models_1.EQuestionType.SBA_WITH_MULTIPLE_CHOICES:
|
|
63
|
+
case models_1.EQuestionType.VERBAL_VERACITY:
|
|
64
|
+
case models_1.EQuestionType.VERBAL_READING_COMPREHENSION:
|
|
65
|
+
case models_1.EQuestionType.DECISION_MAKING_SBA:
|
|
66
|
+
case models_1.EQuestionType.QUANTITATIVE_REASONING_SBA: {
|
|
67
|
+
if (flatAnswer === flatAttempt) {
|
|
68
|
+
data.score = psaSectionId ? 2 : 1;
|
|
69
|
+
data.result = models_1.EMarkResult.Correct;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
data.score = 0;
|
|
73
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case models_1.EQuestionType.QUESTION_ANSWER: {
|
|
78
|
+
const normalizedAnswer = flatAnswer.dose
|
|
79
|
+
.toLowerCase()
|
|
80
|
+
.replace(/\s/g, '');
|
|
81
|
+
const normalizedAttempt = flatAttempt
|
|
82
|
+
? flatAttempt.toLowerCase().replace(/\s/g, '')
|
|
83
|
+
: '';
|
|
84
|
+
if (normalizedAnswer === normalizedAttempt) {
|
|
85
|
+
// for psa section, we give 2 marks for correct answer
|
|
86
|
+
data.score = psaSectionId ? 2 : 1;
|
|
87
|
+
data.result = models_1.EMarkResult.Correct;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
data.score = 0;
|
|
91
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case models_1.EQuestionType.MULTIPLE_ANSWERS: {
|
|
96
|
+
const [answerA, answerB] = answer.map((x) => x.sort());
|
|
97
|
+
let [attemptA, attemptB] = [[], []];
|
|
98
|
+
if (Array.isArray(jsonAnswer) &&
|
|
99
|
+
jsonAnswer.length === 2 &&
|
|
100
|
+
Array.isArray(jsonAnswer[0]) &&
|
|
101
|
+
Array.isArray(jsonAnswer[1])) {
|
|
102
|
+
[attemptA, attemptB] = jsonAnswer.map((x) => x.sort());
|
|
103
|
+
}
|
|
104
|
+
const isAMatch = answerA.length === attemptA.length &&
|
|
105
|
+
attemptA.every((x, i) => x === answerA[i]);
|
|
106
|
+
const isBMatch = answerB.length === attemptB.length &&
|
|
107
|
+
attemptB.every((x, i) => x === answerB[i]);
|
|
108
|
+
if (isAMatch && isBMatch) {
|
|
109
|
+
data.score = 4;
|
|
110
|
+
data.result = models_1.EMarkResult.Correct;
|
|
111
|
+
}
|
|
112
|
+
else if (isAMatch || isBMatch) {
|
|
113
|
+
data.score = 2;
|
|
114
|
+
data.result = models_1.EMarkResult.Partial;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
data.score = 0;
|
|
118
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case models_1.EQuestionType.DECISION_MAKING_YES_NO: {
|
|
123
|
+
const [answerA, answerB] = answer.map((x) => [...x].sort());
|
|
124
|
+
let [attemptA, attemptB] = [[], []];
|
|
125
|
+
if (Array.isArray(jsonAnswer) &&
|
|
126
|
+
jsonAnswer.length === 2 &&
|
|
127
|
+
Array.isArray(jsonAnswer[0]) &&
|
|
128
|
+
Array.isArray(jsonAnswer[1])) {
|
|
129
|
+
[attemptA, attemptB] = jsonAnswer.map((x) => [...x].sort());
|
|
130
|
+
}
|
|
131
|
+
// Count correct matches
|
|
132
|
+
let correctCount = 0;
|
|
133
|
+
// Count matches in A
|
|
134
|
+
correctCount += attemptA.filter((x) => answerA.includes(x)).length;
|
|
135
|
+
// Count matches in B
|
|
136
|
+
correctCount += attemptB.filter((x) => answerB.includes(x)).length;
|
|
137
|
+
const totalStatements = answerA.length + answerB.length;
|
|
138
|
+
if (correctCount === totalStatements) {
|
|
139
|
+
// 5 / 5
|
|
140
|
+
data.score = 2;
|
|
141
|
+
data.result = models_1.EMarkResult.Correct;
|
|
142
|
+
}
|
|
143
|
+
else if (correctCount === totalStatements - 1) {
|
|
144
|
+
// 4 / 5
|
|
145
|
+
data.score = 1;
|
|
146
|
+
data.result = models_1.EMarkResult.Partial;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// 3 or fewer
|
|
150
|
+
data.score = 0;
|
|
151
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case models_1.EQuestionType.PRESCRIPTION_ANSWER: {
|
|
156
|
+
let foundCorrect = false;
|
|
157
|
+
if (typeof flatAttempt === 'object' &&
|
|
158
|
+
Object.keys(flatAttempt).length > 0) {
|
|
159
|
+
const answers = answer.map(mapPrescribeMarkToAnswer);
|
|
160
|
+
const attempt = mapPrescribeMarkToAnswer(flatAttempt);
|
|
161
|
+
foundCorrect = answers.some((ans) => (0, object_1.compareObjects)(ans, attempt));
|
|
162
|
+
}
|
|
163
|
+
if (foundCorrect) {
|
|
164
|
+
data.score = 1;
|
|
165
|
+
data.result = models_1.EMarkResult.Correct;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
data.score = 0;
|
|
169
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
170
|
+
}
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
case models_1.EQuestionType.EXTENDED_MATCHING_ANSWER: {
|
|
174
|
+
const extendedAnswer = answer;
|
|
175
|
+
const attempt = jsonAnswer;
|
|
176
|
+
if (extendedAnswer.length !== attempt.length) {
|
|
177
|
+
data.score = 0;
|
|
178
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const map1 = createHashMap(extendedAnswer);
|
|
182
|
+
const map2 = createHashMap(attempt);
|
|
183
|
+
let isCorrect = true;
|
|
184
|
+
for (const [key, value] of map1) {
|
|
185
|
+
if (map2.get(key) !== value) {
|
|
186
|
+
isCorrect = false;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (isCorrect) {
|
|
191
|
+
data.score = 1;
|
|
192
|
+
data.result = models_1.EMarkResult.Correct;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
data.score = 0;
|
|
196
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case models_1.EQuestionType.SELECT_THREE_ANSWER: {
|
|
202
|
+
const threeAnswer = answer;
|
|
203
|
+
const attempt = jsonAnswer;
|
|
204
|
+
if (threeAnswer.length !== 3) {
|
|
205
|
+
data.score = 0;
|
|
206
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
const answerSet = new Set(threeAnswer);
|
|
210
|
+
let isCorrect = true;
|
|
211
|
+
for (const attemptLabel of attempt) {
|
|
212
|
+
if (!answerSet.has(attemptLabel)) {
|
|
213
|
+
isCorrect = false;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (isCorrect) {
|
|
218
|
+
data.score = 1;
|
|
219
|
+
data.result = models_1.EMarkResult.Correct;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
data.score = 0;
|
|
223
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case models_1.EQuestionType.RANKING_ANSWER: {
|
|
229
|
+
// Duplicate logic to Extended Matching, but they have different scoring systems
|
|
230
|
+
// which we may add at a later point
|
|
231
|
+
const rankAnswer = answer;
|
|
232
|
+
const attempt = jsonAnswer;
|
|
233
|
+
if (rankAnswer.length !== attempt.length) {
|
|
234
|
+
data.score = 0;
|
|
235
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
let isCorrect = true;
|
|
239
|
+
for (let i = 0; i < rankAnswer.length; i++) {
|
|
240
|
+
if (rankAnswer[i] !== attempt[i]) {
|
|
241
|
+
isCorrect = false;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (isCorrect) {
|
|
246
|
+
data.score = 1;
|
|
247
|
+
data.result = models_1.EMarkResult.Correct;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
data.score = 0;
|
|
251
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
case models_1.EQuestionType.SJT_TWO_ANSWERS: {
|
|
257
|
+
const twoAnswer = answer;
|
|
258
|
+
const attempt = jsonAnswer;
|
|
259
|
+
if (twoAnswer.length === 2 &&
|
|
260
|
+
attempt.length === 2 &&
|
|
261
|
+
twoAnswer.join(',') === attempt.join(',')) {
|
|
262
|
+
data.score = 1;
|
|
263
|
+
data.result = models_1.EMarkResult.Correct;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
data.score = 0;
|
|
267
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
268
|
+
}
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
case models_1.EQuestionType.SJT_SINGLE_CHOICE: {
|
|
272
|
+
const answer = flatAnswer;
|
|
273
|
+
const attempt = flatAttempt;
|
|
274
|
+
if (!choices) {
|
|
275
|
+
data.score = 0;
|
|
276
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
const options = choices.map((o) => o.label);
|
|
280
|
+
const answerIndex = options.indexOf(answer);
|
|
281
|
+
const attemptIndex = options.indexOf(attempt);
|
|
282
|
+
if (answerIndex === -1 || attemptIndex === -1) {
|
|
283
|
+
data.score = 0;
|
|
284
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
const distance = Math.abs(answerIndex - attemptIndex);
|
|
288
|
+
if (distance === 0) {
|
|
289
|
+
data.score = 1;
|
|
290
|
+
data.result = models_1.EMarkResult.Correct;
|
|
291
|
+
}
|
|
292
|
+
else if (distance === 1) {
|
|
293
|
+
data.score = 0.5;
|
|
294
|
+
data.result = models_1.EMarkResult.Partial;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
data.score = 0;
|
|
298
|
+
data.result = models_1.EMarkResult.Incorrect;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch (e) {
|
|
306
|
+
console.error(e);
|
|
307
|
+
}
|
|
308
|
+
return data;
|
|
309
|
+
}
|
|
310
|
+
exports.evaluateMark = evaluateMark;
|
package/dist/cjs/utils/index.js
CHANGED
|
@@ -19,6 +19,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
exports.printDuration = exports.Uuid4 = void 0;
|
|
21
21
|
__exportStar(require("./commonFunctions"), exports);
|
|
22
|
+
__exportStar(require("./evaluateMark"), exports);
|
|
22
23
|
__exportStar(require("./lightgallery"), exports);
|
|
23
24
|
__exportStar(require("./object"), exports);
|
|
24
25
|
__exportStar(require("./offlineLink"), exports);
|
|
@@ -76,6 +76,7 @@ export interface IMarksheet {
|
|
|
76
76
|
isTestMarksheet: boolean;
|
|
77
77
|
correct?: number;
|
|
78
78
|
incorrect?: number;
|
|
79
|
+
partial?: number;
|
|
79
80
|
totalQuestions?: number;
|
|
80
81
|
sessionId: string;
|
|
81
82
|
passingMark: number;
|
|
@@ -93,7 +94,12 @@ export interface IMarksheet {
|
|
|
93
94
|
builderConfig?: IBuildConfigData;
|
|
94
95
|
entitlementId: EProductType | EEntitlementType;
|
|
95
96
|
}
|
|
96
|
-
export type IMarksheetMarkJSONB = string | [string] | [IQuestionQAAnswer] | [string[], string[]] | [IPrescribeMark] | null;
|
|
97
|
+
export type IMarksheetMarkJSONB = string | [string] | string[] | [IQuestionQAAnswer] | [string[], string[]] | [IPrescribeMark] | [string, string, string] | [string, string] | [string, string][] | null;
|
|
98
|
+
export declare enum EMarkResult {
|
|
99
|
+
Incorrect = 0,
|
|
100
|
+
Correct = 1,
|
|
101
|
+
Partial = 2
|
|
102
|
+
}
|
|
97
103
|
export interface IMarksheetMark {
|
|
98
104
|
id: Id;
|
|
99
105
|
createdAt: number | Date;
|
|
@@ -110,6 +116,8 @@ export interface IMarksheetMark {
|
|
|
110
116
|
marksheet?: IMarksheet;
|
|
111
117
|
isAnswered: boolean;
|
|
112
118
|
striked: number[];
|
|
119
|
+
score: number;
|
|
120
|
+
result: EMarkResult;
|
|
113
121
|
}
|
|
114
122
|
export interface IPreBuildMarksheetRef {
|
|
115
123
|
createdAt: number | Date;
|
|
@@ -47,3 +47,9 @@ export var EMarksheetAction;
|
|
|
47
47
|
EMarksheetAction[EMarksheetAction["ANSWER_SELECTED"] = 15] = "ANSWER_SELECTED";
|
|
48
48
|
EMarksheetAction[EMarksheetAction["MARK_CHECK_UNCHECK"] = 16] = "MARK_CHECK_UNCHECK";
|
|
49
49
|
})(EMarksheetAction || (EMarksheetAction = {}));
|
|
50
|
+
export var EMarkResult;
|
|
51
|
+
(function (EMarkResult) {
|
|
52
|
+
EMarkResult[EMarkResult["Incorrect"] = 0] = "Incorrect";
|
|
53
|
+
EMarkResult[EMarkResult["Correct"] = 1] = "Correct";
|
|
54
|
+
EMarkResult[EMarkResult["Partial"] = 2] = "Partial";
|
|
55
|
+
})(EMarkResult || (EMarkResult = {}));
|
|
@@ -77,7 +77,7 @@ export interface IQuestionCommentLike {
|
|
|
77
77
|
comment: IQuestionComment;
|
|
78
78
|
likeTrueDislikeFalse: boolean;
|
|
79
79
|
}
|
|
80
|
-
export type IQuestionAnswer = string | [string] | [IQuestionQAAnswer] | [string[], string[]] |
|
|
80
|
+
export type IQuestionAnswer = string | [string] | [IQuestionQAAnswer] | [string[], string[]] | IPrescribeAnswer[] | [string, string][] | [string, string, string] | string[] | [string, string];
|
|
81
81
|
export type IQuestionAll = IQuestion | IQuestionSBA | IQuestionQA | IQuestionMultiQ | IQuestionPrescribe | IQuestionEMQ | IQuestionSelect3 | IQuestionRanking | IQuestionSjtTwoAnswer;
|
|
82
82
|
export interface IQuestion {
|
|
83
83
|
id: Id;
|
|
@@ -207,7 +207,7 @@ export interface IQuestionSjtTwoAnswer extends IQuestion {
|
|
|
207
207
|
sjtTwoAnswer: [string, string];
|
|
208
208
|
}
|
|
209
209
|
export interface IQuestionPrescribe extends IQuestion {
|
|
210
|
-
answer:
|
|
210
|
+
answer: IPrescribeAnswer[];
|
|
211
211
|
prescribeAnswer: IPrescribeAnswer[];
|
|
212
212
|
}
|
|
213
213
|
export type IPrescribeAnswerData = {
|
|
@@ -12,6 +12,8 @@ export const MARKSHEET_MARK_FIELDS = gql `
|
|
|
12
12
|
isAnswered
|
|
13
13
|
striked
|
|
14
14
|
mark
|
|
15
|
+
result
|
|
16
|
+
score
|
|
15
17
|
questionId
|
|
16
18
|
question {
|
|
17
19
|
...QuestionFields
|
|
@@ -141,5 +143,7 @@ export const NEW_MARK_FIELDS = gql `
|
|
|
141
143
|
questionChoiceId
|
|
142
144
|
mark
|
|
143
145
|
isAnswered
|
|
146
|
+
result
|
|
147
|
+
score
|
|
144
148
|
}
|
|
145
149
|
`;
|
|
@@ -3,7 +3,6 @@ export declare const JOB_REMARK_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
|
3
3
|
export declare const JOB_ASSET_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
4
4
|
export declare const JOB_RECORD_METRICS_SUMMARY_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
5
5
|
export declare const JOB_RECORD_CHOICE_SUMMARY_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
6
|
-
export declare const JOB_RECORD_STATISTICS_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
7
6
|
export declare const JOB_RECORD_QUESTION_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
8
7
|
export declare const JOB_RECORD_CHAPTER_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
9
8
|
export declare const JOB_RECORD_STATION_FRAGMENT: import("@apollo/client").DocumentNode;
|
|
@@ -60,10 +60,6 @@ export const JOB_RECORD_METRICS_SUMMARY_FRAGMENT = gql `
|
|
|
60
60
|
correct
|
|
61
61
|
incorrect
|
|
62
62
|
percentage
|
|
63
|
-
commentCount
|
|
64
|
-
likes
|
|
65
|
-
dislikes
|
|
66
|
-
public
|
|
67
63
|
}
|
|
68
64
|
`;
|
|
69
65
|
export const JOB_RECORD_CHOICE_SUMMARY_FRAGMENT = gql `
|
|
@@ -75,18 +71,18 @@ export const JOB_RECORD_CHOICE_SUMMARY_FRAGMENT = gql `
|
|
|
75
71
|
questionId
|
|
76
72
|
}
|
|
77
73
|
`;
|
|
78
|
-
export const JOB_RECORD_STATISTICS_FRAGMENT = gql
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`;
|
|
74
|
+
// export const JOB_RECORD_STATISTICS_FRAGMENT = gql`
|
|
75
|
+
// ${JOB_RECORD_METRICS_SUMMARY_FRAGMENT}
|
|
76
|
+
// ${JOB_RECORD_CHOICE_SUMMARY_FRAGMENT}
|
|
77
|
+
// fragment JobRecordStatistics on JobRecord {
|
|
78
|
+
// metricsSummary {
|
|
79
|
+
// ...JobRecordMetricsSummary
|
|
80
|
+
// }
|
|
81
|
+
// choiceSummary {
|
|
82
|
+
// ...JobRecordChoiceSummary
|
|
83
|
+
// }
|
|
84
|
+
// }
|
|
85
|
+
// `;
|
|
90
86
|
export const JOB_RECORD_QUESTION_FRAGMENT = gql `
|
|
91
87
|
fragment JobRecordQuestion on JobRecordQuestion {
|
|
92
88
|
question
|
|
@@ -167,7 +163,6 @@ export const JOB_RECORD_FRAGMENT = gql `
|
|
|
167
163
|
${JOB_RECORD_CHAPTER_FRAGMENT}
|
|
168
164
|
${JOB_RECORD_STATION_FRAGMENT}
|
|
169
165
|
${JOB_RECORD_MOCK_TEST_FRAGMENT}
|
|
170
|
-
${JOB_RECORD_STATISTICS_FRAGMENT}
|
|
171
166
|
${JOB_ASSET_FRAGMENT}
|
|
172
167
|
fragment JobRecord on JobRecord {
|
|
173
168
|
id
|
|
@@ -205,6 +200,6 @@ export const JOB_RECORD_FRAGMENT = gql `
|
|
|
205
200
|
updatedAt
|
|
206
201
|
publishedAt
|
|
207
202
|
...JobRecordStatus
|
|
208
|
-
...JobRecordStatistics
|
|
203
|
+
# ...JobRecordStatistics
|
|
209
204
|
}
|
|
210
205
|
`;
|
|
@@ -190,6 +190,7 @@ export declare const optimisticModifyMarksheetBuilderConfig: (marksheetId: numbe
|
|
|
190
190
|
isTestMarksheet: boolean;
|
|
191
191
|
correct?: number | undefined;
|
|
192
192
|
incorrect?: number | undefined;
|
|
193
|
+
partial?: number | undefined;
|
|
193
194
|
totalQuestions?: number | undefined;
|
|
194
195
|
sessionId: string;
|
|
195
196
|
passingMark: number;
|
|
@@ -283,6 +284,7 @@ export declare const optimisticEndMarksheet: (marksheet: IMarksheet) => {
|
|
|
283
284
|
isTestMarksheet: boolean;
|
|
284
285
|
correct?: number | undefined;
|
|
285
286
|
incorrect?: number | undefined;
|
|
287
|
+
partial?: number | undefined;
|
|
286
288
|
totalQuestions?: number | undefined;
|
|
287
289
|
sessionId: string;
|
|
288
290
|
passingMark: number;
|
|
@@ -67,6 +67,8 @@ export const SAVE_MARKSHEET = gql `
|
|
|
67
67
|
state
|
|
68
68
|
marks {
|
|
69
69
|
isAnswered
|
|
70
|
+
result
|
|
71
|
+
score
|
|
70
72
|
id
|
|
71
73
|
marksheetId
|
|
72
74
|
questionChoiceId
|
|
@@ -100,6 +102,8 @@ export const updateMarksheets = (cache, result, options) => {
|
|
|
100
102
|
mark: marksheet.mark,
|
|
101
103
|
questionChoiceId: marksheet.choiceId,
|
|
102
104
|
isAnswered: true,
|
|
105
|
+
result: 0,
|
|
106
|
+
score: 0,
|
|
103
107
|
},
|
|
104
108
|
fragment: NEW_MARK_FIELDS,
|
|
105
109
|
});
|
|
@@ -119,6 +123,8 @@ export const optimisticSaveMarksheets = (marksheet, marksheetInput, questionInde
|
|
|
119
123
|
questionChoiceId: choiceId ?? null,
|
|
120
124
|
isAnswered: true,
|
|
121
125
|
mark: mark || null,
|
|
126
|
+
result: 0,
|
|
127
|
+
score: 0,
|
|
122
128
|
};
|
|
123
129
|
const updatedMarks = [
|
|
124
130
|
...marks.slice(0, questionIndex),
|
|
@@ -335,6 +341,8 @@ export const MODIFY_MARKSHEET_MARK = gql `
|
|
|
335
341
|
questionChoiceId
|
|
336
342
|
timeTaken
|
|
337
343
|
mark
|
|
344
|
+
result
|
|
345
|
+
score
|
|
338
346
|
isAnswered
|
|
339
347
|
striked
|
|
340
348
|
}
|
|
@@ -441,6 +449,8 @@ export const TOGGLE_STRIKE_OPTIONS = gql `
|
|
|
441
449
|
index
|
|
442
450
|
isAnswered
|
|
443
451
|
mark
|
|
452
|
+
result
|
|
453
|
+
score
|
|
444
454
|
marksheetId
|
|
445
455
|
question {
|
|
446
456
|
id
|
|
@@ -29,6 +29,8 @@ export declare const optimisticToggleFlaggedQuestion: (mark: IMarksheetMark, fla
|
|
|
29
29
|
marksheet?: IMarksheet | undefined;
|
|
30
30
|
isAnswered: boolean;
|
|
31
31
|
striked: number[];
|
|
32
|
+
score: number;
|
|
33
|
+
result: import("../../../models").EMarkResult;
|
|
32
34
|
};
|
|
33
35
|
};
|
|
34
36
|
};
|
|
@@ -64,6 +66,7 @@ export declare const optimisticEndMockTest: (marksheet: IMarksheet) => {
|
|
|
64
66
|
isTestMarksheet: boolean;
|
|
65
67
|
correct?: number | undefined;
|
|
66
68
|
incorrect?: number | undefined;
|
|
69
|
+
partial?: number | undefined;
|
|
67
70
|
totalQuestions?: number | undefined;
|
|
68
71
|
sessionId: string;
|
|
69
72
|
passingMark: number;
|
|
@@ -2,9 +2,9 @@ import { gql } from '@apollo/client';
|
|
|
2
2
|
import { JOB_RECORD_FRAGMENT } from '../../fragments';
|
|
3
3
|
export const GET_JOB_RECORDS = gql `
|
|
4
4
|
${JOB_RECORD_FRAGMENT}
|
|
5
|
-
query GetJobRecords($jobId: ID
|
|
5
|
+
query GetJobRecords($jobId: ID!) {
|
|
6
6
|
admin {
|
|
7
|
-
getJobRecords(jobId: $jobId
|
|
7
|
+
getJobRecords(jobId: $jobId) {
|
|
8
8
|
...JobRecord
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EMarksheetAction, EMarksheetState, Id,
|
|
1
|
+
import { EMarksheetAction, EMarksheetState, Id, IMarksheetMark, IUser } from '../../models';
|
|
2
2
|
import { IBuildConfigData, IPreBuildMarksheet } from '../mutation/restricted';
|
|
3
3
|
import { RootData } from '../types';
|
|
4
4
|
export interface IMarksheetGroupMember {
|
|
@@ -58,12 +58,14 @@ export interface IMarksheetMarkData {
|
|
|
58
58
|
newMarkId?: Id;
|
|
59
59
|
markIndex?: number;
|
|
60
60
|
questionChoiceId?: Id;
|
|
61
|
-
mark?:
|
|
61
|
+
mark?: IMarksheetMark['mark'];
|
|
62
62
|
isAnswered?: boolean;
|
|
63
|
-
|
|
63
|
+
score?: IMarksheetMark['score'];
|
|
64
|
+
result?: IMarksheetMark['result'];
|
|
65
|
+
timeTaken?: IMarksheetMark['timeTaken'];
|
|
64
66
|
updatedAt?: Date;
|
|
65
67
|
user: IUser;
|
|
66
|
-
striked?:
|
|
68
|
+
striked?: IMarksheetMark['striked'];
|
|
67
69
|
}
|
|
68
70
|
export type IOnMarksheetMarkChangeData = RootData<IMarksheetMarkData, 'onMarksheetMarkChange'>;
|
|
69
71
|
export declare const ON_MARKSHEET_MARK_CHANGE_KEY = "ON_MARKSHEET_CHANGE_KEY";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EMarkResult, EPsaSectionType, EQuestionType, IMarksheetMarkJSONB, IQuestionAnswer } from '../models';
|
|
2
|
+
export interface IEvaluateMarkData {
|
|
3
|
+
score: number;
|
|
4
|
+
result: EMarkResult;
|
|
5
|
+
}
|
|
6
|
+
export declare function evaluateMark({ mark, answer, questionTypeId, psaSectionId, choices, }: {
|
|
7
|
+
mark: IMarksheetMarkJSONB;
|
|
8
|
+
answer: IQuestionAnswer;
|
|
9
|
+
questionTypeId: EQuestionType;
|
|
10
|
+
psaSectionId: EPsaSectionType | null;
|
|
11
|
+
choices?: Array<{
|
|
12
|
+
label: string;
|
|
13
|
+
}>;
|
|
14
|
+
}): IEvaluateMarkData;
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { EMarkResult, EQuestionType, } from '../models';
|
|
2
|
+
import { compareObjects } from './object';
|
|
3
|
+
function isPrescribeAnswer(data) {
|
|
4
|
+
return Object(data).hasOwnProperty('dose');
|
|
5
|
+
}
|
|
6
|
+
function mapPrescribeMarkToAnswer(obj) {
|
|
7
|
+
if (isPrescribeAnswer(obj)) {
|
|
8
|
+
return {
|
|
9
|
+
drugId: obj.drug.value,
|
|
10
|
+
doseId: obj.dose.value,
|
|
11
|
+
durationId: obj.duration.value,
|
|
12
|
+
frequencyId: obj.frequency.value,
|
|
13
|
+
routeId: obj.route.value,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
drugId: obj.drugId,
|
|
18
|
+
doseId: obj.doseId,
|
|
19
|
+
durationId: obj.durationId,
|
|
20
|
+
frequencyId: obj.frequencyId,
|
|
21
|
+
routeId: obj.routeId,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function createHashMap(arr) {
|
|
25
|
+
const map = new Map();
|
|
26
|
+
for (const innerArr of arr) {
|
|
27
|
+
const sortedInnerArr = innerArr.slice().sort();
|
|
28
|
+
const key = sortedInnerArr.join('|');
|
|
29
|
+
map.set(key, (map.get(key) || 0) + 1);
|
|
30
|
+
}
|
|
31
|
+
return map;
|
|
32
|
+
}
|
|
33
|
+
function deepParse(data) {
|
|
34
|
+
let parsed = data;
|
|
35
|
+
while (typeof parsed === 'string') {
|
|
36
|
+
try {
|
|
37
|
+
parsed = JSON.parse(parsed);
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
export function evaluateMark({ mark, answer, questionTypeId, psaSectionId, choices, }) {
|
|
46
|
+
const data = {
|
|
47
|
+
score: 0,
|
|
48
|
+
result: EMarkResult.Incorrect,
|
|
49
|
+
};
|
|
50
|
+
if (!mark || !answer) {
|
|
51
|
+
return data;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const flatAnswer = answer[0];
|
|
55
|
+
const jsonAnswer = deepParse(mark);
|
|
56
|
+
const flatAttempt = jsonAnswer[0];
|
|
57
|
+
switch (questionTypeId) {
|
|
58
|
+
case EQuestionType.SINGLE_BEST_ANSWER:
|
|
59
|
+
case EQuestionType.SBA_WITH_MULTIPLE_CHOICES:
|
|
60
|
+
case EQuestionType.VERBAL_VERACITY:
|
|
61
|
+
case EQuestionType.VERBAL_READING_COMPREHENSION:
|
|
62
|
+
case EQuestionType.DECISION_MAKING_SBA:
|
|
63
|
+
case EQuestionType.QUANTITATIVE_REASONING_SBA: {
|
|
64
|
+
if (flatAnswer === flatAttempt) {
|
|
65
|
+
data.score = psaSectionId ? 2 : 1;
|
|
66
|
+
data.result = EMarkResult.Correct;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
data.score = 0;
|
|
70
|
+
data.result = EMarkResult.Incorrect;
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case EQuestionType.QUESTION_ANSWER: {
|
|
75
|
+
const normalizedAnswer = flatAnswer.dose
|
|
76
|
+
.toLowerCase()
|
|
77
|
+
.replace(/\s/g, '');
|
|
78
|
+
const normalizedAttempt = flatAttempt
|
|
79
|
+
? flatAttempt.toLowerCase().replace(/\s/g, '')
|
|
80
|
+
: '';
|
|
81
|
+
if (normalizedAnswer === normalizedAttempt) {
|
|
82
|
+
// for psa section, we give 2 marks for correct answer
|
|
83
|
+
data.score = psaSectionId ? 2 : 1;
|
|
84
|
+
data.result = EMarkResult.Correct;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
data.score = 0;
|
|
88
|
+
data.result = EMarkResult.Incorrect;
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case EQuestionType.MULTIPLE_ANSWERS: {
|
|
93
|
+
const [answerA, answerB] = answer.map((x) => x.sort());
|
|
94
|
+
let [attemptA, attemptB] = [[], []];
|
|
95
|
+
if (Array.isArray(jsonAnswer) &&
|
|
96
|
+
jsonAnswer.length === 2 &&
|
|
97
|
+
Array.isArray(jsonAnswer[0]) &&
|
|
98
|
+
Array.isArray(jsonAnswer[1])) {
|
|
99
|
+
[attemptA, attemptB] = jsonAnswer.map((x) => x.sort());
|
|
100
|
+
}
|
|
101
|
+
const isAMatch = answerA.length === attemptA.length &&
|
|
102
|
+
attemptA.every((x, i) => x === answerA[i]);
|
|
103
|
+
const isBMatch = answerB.length === attemptB.length &&
|
|
104
|
+
attemptB.every((x, i) => x === answerB[i]);
|
|
105
|
+
if (isAMatch && isBMatch) {
|
|
106
|
+
data.score = 4;
|
|
107
|
+
data.result = EMarkResult.Correct;
|
|
108
|
+
}
|
|
109
|
+
else if (isAMatch || isBMatch) {
|
|
110
|
+
data.score = 2;
|
|
111
|
+
data.result = EMarkResult.Partial;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
data.score = 0;
|
|
115
|
+
data.result = EMarkResult.Incorrect;
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case EQuestionType.DECISION_MAKING_YES_NO: {
|
|
120
|
+
const [answerA, answerB] = answer.map((x) => [...x].sort());
|
|
121
|
+
let [attemptA, attemptB] = [[], []];
|
|
122
|
+
if (Array.isArray(jsonAnswer) &&
|
|
123
|
+
jsonAnswer.length === 2 &&
|
|
124
|
+
Array.isArray(jsonAnswer[0]) &&
|
|
125
|
+
Array.isArray(jsonAnswer[1])) {
|
|
126
|
+
[attemptA, attemptB] = jsonAnswer.map((x) => [...x].sort());
|
|
127
|
+
}
|
|
128
|
+
// Count correct matches
|
|
129
|
+
let correctCount = 0;
|
|
130
|
+
// Count matches in A
|
|
131
|
+
correctCount += attemptA.filter((x) => answerA.includes(x)).length;
|
|
132
|
+
// Count matches in B
|
|
133
|
+
correctCount += attemptB.filter((x) => answerB.includes(x)).length;
|
|
134
|
+
const totalStatements = answerA.length + answerB.length;
|
|
135
|
+
if (correctCount === totalStatements) {
|
|
136
|
+
// 5 / 5
|
|
137
|
+
data.score = 2;
|
|
138
|
+
data.result = EMarkResult.Correct;
|
|
139
|
+
}
|
|
140
|
+
else if (correctCount === totalStatements - 1) {
|
|
141
|
+
// 4 / 5
|
|
142
|
+
data.score = 1;
|
|
143
|
+
data.result = EMarkResult.Partial;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// 3 or fewer
|
|
147
|
+
data.score = 0;
|
|
148
|
+
data.result = EMarkResult.Incorrect;
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case EQuestionType.PRESCRIPTION_ANSWER: {
|
|
153
|
+
let foundCorrect = false;
|
|
154
|
+
if (typeof flatAttempt === 'object' &&
|
|
155
|
+
Object.keys(flatAttempt).length > 0) {
|
|
156
|
+
const answers = answer.map(mapPrescribeMarkToAnswer);
|
|
157
|
+
const attempt = mapPrescribeMarkToAnswer(flatAttempt);
|
|
158
|
+
foundCorrect = answers.some((ans) => compareObjects(ans, attempt));
|
|
159
|
+
}
|
|
160
|
+
if (foundCorrect) {
|
|
161
|
+
data.score = 1;
|
|
162
|
+
data.result = EMarkResult.Correct;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
data.score = 0;
|
|
166
|
+
data.result = EMarkResult.Incorrect;
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case EQuestionType.EXTENDED_MATCHING_ANSWER: {
|
|
171
|
+
const extendedAnswer = answer;
|
|
172
|
+
const attempt = jsonAnswer;
|
|
173
|
+
if (extendedAnswer.length !== attempt.length) {
|
|
174
|
+
data.score = 0;
|
|
175
|
+
data.result = EMarkResult.Incorrect;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const map1 = createHashMap(extendedAnswer);
|
|
179
|
+
const map2 = createHashMap(attempt);
|
|
180
|
+
let isCorrect = true;
|
|
181
|
+
for (const [key, value] of map1) {
|
|
182
|
+
if (map2.get(key) !== value) {
|
|
183
|
+
isCorrect = false;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (isCorrect) {
|
|
188
|
+
data.score = 1;
|
|
189
|
+
data.result = EMarkResult.Correct;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
data.score = 0;
|
|
193
|
+
data.result = EMarkResult.Incorrect;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case EQuestionType.SELECT_THREE_ANSWER: {
|
|
199
|
+
const threeAnswer = answer;
|
|
200
|
+
const attempt = jsonAnswer;
|
|
201
|
+
if (threeAnswer.length !== 3) {
|
|
202
|
+
data.score = 0;
|
|
203
|
+
data.result = EMarkResult.Incorrect;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const answerSet = new Set(threeAnswer);
|
|
207
|
+
let isCorrect = true;
|
|
208
|
+
for (const attemptLabel of attempt) {
|
|
209
|
+
if (!answerSet.has(attemptLabel)) {
|
|
210
|
+
isCorrect = false;
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (isCorrect) {
|
|
215
|
+
data.score = 1;
|
|
216
|
+
data.result = EMarkResult.Correct;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
data.score = 0;
|
|
220
|
+
data.result = EMarkResult.Incorrect;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case EQuestionType.RANKING_ANSWER: {
|
|
226
|
+
// Duplicate logic to Extended Matching, but they have different scoring systems
|
|
227
|
+
// which we may add at a later point
|
|
228
|
+
const rankAnswer = answer;
|
|
229
|
+
const attempt = jsonAnswer;
|
|
230
|
+
if (rankAnswer.length !== attempt.length) {
|
|
231
|
+
data.score = 0;
|
|
232
|
+
data.result = EMarkResult.Incorrect;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
let isCorrect = true;
|
|
236
|
+
for (let i = 0; i < rankAnswer.length; i++) {
|
|
237
|
+
if (rankAnswer[i] !== attempt[i]) {
|
|
238
|
+
isCorrect = false;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (isCorrect) {
|
|
243
|
+
data.score = 1;
|
|
244
|
+
data.result = EMarkResult.Correct;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
data.score = 0;
|
|
248
|
+
data.result = EMarkResult.Incorrect;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case EQuestionType.SJT_TWO_ANSWERS: {
|
|
254
|
+
const twoAnswer = answer;
|
|
255
|
+
const attempt = jsonAnswer;
|
|
256
|
+
if (twoAnswer.length === 2 &&
|
|
257
|
+
attempt.length === 2 &&
|
|
258
|
+
twoAnswer.join(',') === attempt.join(',')) {
|
|
259
|
+
data.score = 1;
|
|
260
|
+
data.result = EMarkResult.Correct;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
data.score = 0;
|
|
264
|
+
data.result = EMarkResult.Incorrect;
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
case EQuestionType.SJT_SINGLE_CHOICE: {
|
|
269
|
+
const answer = flatAnswer;
|
|
270
|
+
const attempt = flatAttempt;
|
|
271
|
+
if (!choices) {
|
|
272
|
+
data.score = 0;
|
|
273
|
+
data.result = EMarkResult.Incorrect;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
const options = choices.map((o) => o.label);
|
|
277
|
+
const answerIndex = options.indexOf(answer);
|
|
278
|
+
const attemptIndex = options.indexOf(attempt);
|
|
279
|
+
if (answerIndex === -1 || attemptIndex === -1) {
|
|
280
|
+
data.score = 0;
|
|
281
|
+
data.result = EMarkResult.Incorrect;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
const distance = Math.abs(answerIndex - attemptIndex);
|
|
285
|
+
if (distance === 0) {
|
|
286
|
+
data.score = 1;
|
|
287
|
+
data.result = EMarkResult.Correct;
|
|
288
|
+
}
|
|
289
|
+
else if (distance === 1) {
|
|
290
|
+
data.score = 0.5;
|
|
291
|
+
data.result = EMarkResult.Partial;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
data.score = 0;
|
|
295
|
+
data.result = EMarkResult.Incorrect;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch (e) {
|
|
303
|
+
console.error(e);
|
|
304
|
+
}
|
|
305
|
+
return data;
|
|
306
|
+
}
|
package/dist/mjs/utils/index.js
CHANGED