@quesmed/types 2.6.208 → 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/models/Video.d.ts +2 -0
- 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/query/restricted/video.js +2 -0
- package/dist/cjs/resolvers/query/video.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/models/Video.d.ts +2 -0
- 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/query/restricted/video.js +2 -0
- package/dist/mjs/resolvers/query/video.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;
|
|
@@ -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