testforce-engine 0.0.1-alpha
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/README.md +3 -0
- package/dist/index.d.mts +183 -0
- package/dist/index.d.ts +183 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +29 -0
package/README.md
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
|
|
3
|
+
declare enum TestType {
|
|
4
|
+
QUIZ = "QUIZ",
|
|
5
|
+
TEST = "TEST"
|
|
6
|
+
}
|
|
7
|
+
declare enum TestHeirarchyLevel {
|
|
8
|
+
TEST = "TEST",
|
|
9
|
+
SECTION = "SECTION",
|
|
10
|
+
QUESTION = "QUESTION"
|
|
11
|
+
}
|
|
12
|
+
declare enum QuestionType {
|
|
13
|
+
SINGLE = "SINGLE",
|
|
14
|
+
MULTIPLE = "MULTIPLE",
|
|
15
|
+
INTEGER = "INTEGER"
|
|
16
|
+
}
|
|
17
|
+
declare enum TestStatus {
|
|
18
|
+
START = "Start",
|
|
19
|
+
PAUSED = "Paused",
|
|
20
|
+
REATTEMPT = "Reattempt",
|
|
21
|
+
NOT_STARTED = "NotStarted",
|
|
22
|
+
ENDED = "Ended"
|
|
23
|
+
}
|
|
24
|
+
interface Test {
|
|
25
|
+
name: string;
|
|
26
|
+
type: TestType;
|
|
27
|
+
sections: Section[];
|
|
28
|
+
duration: number;
|
|
29
|
+
sectionsHide: boolean;
|
|
30
|
+
timerLevel: TestHeirarchyLevel;
|
|
31
|
+
_id: string;
|
|
32
|
+
createdAt: string;
|
|
33
|
+
updatedAt: string;
|
|
34
|
+
__v: number;
|
|
35
|
+
isPublished: boolean;
|
|
36
|
+
startDate: Date;
|
|
37
|
+
numberOfQuestions: number;
|
|
38
|
+
isNegativeMarkingEnabled: boolean;
|
|
39
|
+
positiveMarks: number;
|
|
40
|
+
negativeMarks: number;
|
|
41
|
+
marksLevel: TestHeirarchyLevel;
|
|
42
|
+
totalMarks: number;
|
|
43
|
+
totalTime: number;
|
|
44
|
+
channelId: string;
|
|
45
|
+
testMappingId: string;
|
|
46
|
+
status: TestStatus;
|
|
47
|
+
lastVisitedQuestionId: string;
|
|
48
|
+
timeTaken: Record<string, any>;
|
|
49
|
+
}
|
|
50
|
+
interface Section {
|
|
51
|
+
name: string;
|
|
52
|
+
duration: number;
|
|
53
|
+
_id: string;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
updatedAt: string;
|
|
56
|
+
questions: Question[];
|
|
57
|
+
isNegativeMarkingEnabled: boolean;
|
|
58
|
+
positiveMarks: number;
|
|
59
|
+
negativeMarks: number;
|
|
60
|
+
testId: string;
|
|
61
|
+
}
|
|
62
|
+
interface Question {
|
|
63
|
+
_id: string;
|
|
64
|
+
text: string;
|
|
65
|
+
options: Option[];
|
|
66
|
+
type: QuestionType;
|
|
67
|
+
solution: string[];
|
|
68
|
+
sectionId: string;
|
|
69
|
+
testId: string;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
updatedAt: string;
|
|
72
|
+
__v: number;
|
|
73
|
+
solutionDescription?: string;
|
|
74
|
+
displayOrder: number;
|
|
75
|
+
duration: number;
|
|
76
|
+
questionResponse: SolutionDetails$1;
|
|
77
|
+
}
|
|
78
|
+
interface SolutionDetails$1 {
|
|
79
|
+
markedSolution?: string[];
|
|
80
|
+
markedForReview?: boolean;
|
|
81
|
+
timeTaken?: number;
|
|
82
|
+
}
|
|
83
|
+
interface Option {
|
|
84
|
+
text: string;
|
|
85
|
+
_id: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
declare enum AttemptStatus {
|
|
89
|
+
ATTEMPTED = "ATTEMPTED",
|
|
90
|
+
NOT_ATTEMPTED = "NOT_ATTEMPTED",
|
|
91
|
+
NOT_VISITED = "NOT_VISITED",
|
|
92
|
+
MARKED_FOR_REVIEW = "MARKED_FOR_REVIEW",
|
|
93
|
+
ATTEMPTED_AND_MARKED_FOR_REVIEW = "ATTEMPTED_AND_MARKED_FOR_REVIEW",
|
|
94
|
+
ACITVE_QUESTION = "ACITVE_QUESTION"
|
|
95
|
+
}
|
|
96
|
+
interface UserSettings {
|
|
97
|
+
selectedFilter?: AttemptStatus;
|
|
98
|
+
}
|
|
99
|
+
interface SolutionDetails {
|
|
100
|
+
markedSolution?: string[];
|
|
101
|
+
markedForReview?: boolean;
|
|
102
|
+
timeTaken?: number;
|
|
103
|
+
isSaved?: boolean;
|
|
104
|
+
}
|
|
105
|
+
interface SubmitTest {
|
|
106
|
+
payload: Record<string, any>;
|
|
107
|
+
pause: boolean;
|
|
108
|
+
autoSubmit: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
declare const TestEngineProvider: ({ test, submitTest, ...props }: {
|
|
112
|
+
test: Test;
|
|
113
|
+
isSolution?: boolean;
|
|
114
|
+
submitTest: React.Dispatch<SubmitTest>;
|
|
115
|
+
} & PropsWithChildren) => React.JSX.Element;
|
|
116
|
+
|
|
117
|
+
declare const useTestEngine: () => {
|
|
118
|
+
currentSection: Section | undefined;
|
|
119
|
+
currentQuestion: Question | undefined;
|
|
120
|
+
handleSubmitTest: (pause?: boolean, autoSubmit?: boolean) => Promise<Record<string, any>>;
|
|
121
|
+
handleUpdateTestDetails: (value: Test) => void;
|
|
122
|
+
handleUpdateQuestionCoordinates: (value: {
|
|
123
|
+
currentQuestionIndex: number;
|
|
124
|
+
currentSectionIndex: number;
|
|
125
|
+
}) => Promise<void>;
|
|
126
|
+
handleUpdateSolutions: (value: Record<string, SolutionDetails>) => void;
|
|
127
|
+
handleUpdateCurrentAnswer: (value: SolutionDetails) => void;
|
|
128
|
+
handleUpdateUserSettings: (value: UserSettings) => void;
|
|
129
|
+
handleResetLocal: () => Promise<void>;
|
|
130
|
+
test: Test | undefined;
|
|
131
|
+
solutions: Record<string, SolutionDetails>;
|
|
132
|
+
currentQuestionIndex: number;
|
|
133
|
+
currentSectionIndex: number;
|
|
134
|
+
currentQuestionAnswer: SolutionDetails | undefined;
|
|
135
|
+
userSettings: UserSettings | undefined;
|
|
136
|
+
isSolution?: boolean;
|
|
137
|
+
submitting?: boolean;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
declare const useTestEngineBody: () => {
|
|
141
|
+
isQuizAnswer: boolean;
|
|
142
|
+
handleClearResponse: () => void;
|
|
143
|
+
handleSelectOption: (optionId: string) => void;
|
|
144
|
+
handleIntegerInputChange: (val: string) => void;
|
|
145
|
+
handleMarkForReview: () => void;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
declare const useTestEngineFooter: () => {
|
|
149
|
+
handleNext: () => void;
|
|
150
|
+
handlePrevious: () => void;
|
|
151
|
+
handleSaveAnswer: () => void;
|
|
152
|
+
handleMarkForReview: () => void;
|
|
153
|
+
isLastQuestion: boolean;
|
|
154
|
+
isFirstQuestion: boolean;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
declare const useTestQuestionStatus: ({ includeAllSections, }?: {
|
|
158
|
+
includeAllSections?: boolean;
|
|
159
|
+
}) => {
|
|
160
|
+
getQuestionStatus: (qi: number, si: number) => AttemptStatus.ATTEMPTED | AttemptStatus.NOT_ATTEMPTED | AttemptStatus.NOT_VISITED | AttemptStatus.MARKED_FOR_REVIEW | AttemptStatus.ATTEMPTED_AND_MARKED_FOR_REVIEW;
|
|
161
|
+
questionStatusMap: Record<AttemptStatus, {
|
|
162
|
+
count: number;
|
|
163
|
+
}>;
|
|
164
|
+
getAnsweredQuestionStatus: (i: number, si: number) => AttemptStatus.ATTEMPTED | AttemptStatus.NOT_ATTEMPTED | AttemptStatus.NOT_VISITED;
|
|
165
|
+
areArraysEqual: (a: string[], b: string[]) => boolean;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
type QuestionStatusType = "correct" | "incorrect" | "skipped";
|
|
169
|
+
declare const useTestSolutionBody: () => {
|
|
170
|
+
correctAnswer: string;
|
|
171
|
+
currentAnswerMarks: string | number;
|
|
172
|
+
currentQuestionStatus: QuestionStatusType;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
declare const useTestTimer: () => {
|
|
176
|
+
timer: number;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
declare const useQuestionStopWatch: (type?: "web" | "app") => {
|
|
180
|
+
questionStopWatch: number;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export { AttemptStatus, type SubmitTest, TestEngineProvider, useQuestionStopWatch, useTestEngine, useTestEngineBody, useTestEngineFooter, useTestQuestionStatus, useTestSolutionBody, useTestTimer };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
|
|
3
|
+
declare enum TestType {
|
|
4
|
+
QUIZ = "QUIZ",
|
|
5
|
+
TEST = "TEST"
|
|
6
|
+
}
|
|
7
|
+
declare enum TestHeirarchyLevel {
|
|
8
|
+
TEST = "TEST",
|
|
9
|
+
SECTION = "SECTION",
|
|
10
|
+
QUESTION = "QUESTION"
|
|
11
|
+
}
|
|
12
|
+
declare enum QuestionType {
|
|
13
|
+
SINGLE = "SINGLE",
|
|
14
|
+
MULTIPLE = "MULTIPLE",
|
|
15
|
+
INTEGER = "INTEGER"
|
|
16
|
+
}
|
|
17
|
+
declare enum TestStatus {
|
|
18
|
+
START = "Start",
|
|
19
|
+
PAUSED = "Paused",
|
|
20
|
+
REATTEMPT = "Reattempt",
|
|
21
|
+
NOT_STARTED = "NotStarted",
|
|
22
|
+
ENDED = "Ended"
|
|
23
|
+
}
|
|
24
|
+
interface Test {
|
|
25
|
+
name: string;
|
|
26
|
+
type: TestType;
|
|
27
|
+
sections: Section[];
|
|
28
|
+
duration: number;
|
|
29
|
+
sectionsHide: boolean;
|
|
30
|
+
timerLevel: TestHeirarchyLevel;
|
|
31
|
+
_id: string;
|
|
32
|
+
createdAt: string;
|
|
33
|
+
updatedAt: string;
|
|
34
|
+
__v: number;
|
|
35
|
+
isPublished: boolean;
|
|
36
|
+
startDate: Date;
|
|
37
|
+
numberOfQuestions: number;
|
|
38
|
+
isNegativeMarkingEnabled: boolean;
|
|
39
|
+
positiveMarks: number;
|
|
40
|
+
negativeMarks: number;
|
|
41
|
+
marksLevel: TestHeirarchyLevel;
|
|
42
|
+
totalMarks: number;
|
|
43
|
+
totalTime: number;
|
|
44
|
+
channelId: string;
|
|
45
|
+
testMappingId: string;
|
|
46
|
+
status: TestStatus;
|
|
47
|
+
lastVisitedQuestionId: string;
|
|
48
|
+
timeTaken: Record<string, any>;
|
|
49
|
+
}
|
|
50
|
+
interface Section {
|
|
51
|
+
name: string;
|
|
52
|
+
duration: number;
|
|
53
|
+
_id: string;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
updatedAt: string;
|
|
56
|
+
questions: Question[];
|
|
57
|
+
isNegativeMarkingEnabled: boolean;
|
|
58
|
+
positiveMarks: number;
|
|
59
|
+
negativeMarks: number;
|
|
60
|
+
testId: string;
|
|
61
|
+
}
|
|
62
|
+
interface Question {
|
|
63
|
+
_id: string;
|
|
64
|
+
text: string;
|
|
65
|
+
options: Option[];
|
|
66
|
+
type: QuestionType;
|
|
67
|
+
solution: string[];
|
|
68
|
+
sectionId: string;
|
|
69
|
+
testId: string;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
updatedAt: string;
|
|
72
|
+
__v: number;
|
|
73
|
+
solutionDescription?: string;
|
|
74
|
+
displayOrder: number;
|
|
75
|
+
duration: number;
|
|
76
|
+
questionResponse: SolutionDetails$1;
|
|
77
|
+
}
|
|
78
|
+
interface SolutionDetails$1 {
|
|
79
|
+
markedSolution?: string[];
|
|
80
|
+
markedForReview?: boolean;
|
|
81
|
+
timeTaken?: number;
|
|
82
|
+
}
|
|
83
|
+
interface Option {
|
|
84
|
+
text: string;
|
|
85
|
+
_id: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
declare enum AttemptStatus {
|
|
89
|
+
ATTEMPTED = "ATTEMPTED",
|
|
90
|
+
NOT_ATTEMPTED = "NOT_ATTEMPTED",
|
|
91
|
+
NOT_VISITED = "NOT_VISITED",
|
|
92
|
+
MARKED_FOR_REVIEW = "MARKED_FOR_REVIEW",
|
|
93
|
+
ATTEMPTED_AND_MARKED_FOR_REVIEW = "ATTEMPTED_AND_MARKED_FOR_REVIEW",
|
|
94
|
+
ACITVE_QUESTION = "ACITVE_QUESTION"
|
|
95
|
+
}
|
|
96
|
+
interface UserSettings {
|
|
97
|
+
selectedFilter?: AttemptStatus;
|
|
98
|
+
}
|
|
99
|
+
interface SolutionDetails {
|
|
100
|
+
markedSolution?: string[];
|
|
101
|
+
markedForReview?: boolean;
|
|
102
|
+
timeTaken?: number;
|
|
103
|
+
isSaved?: boolean;
|
|
104
|
+
}
|
|
105
|
+
interface SubmitTest {
|
|
106
|
+
payload: Record<string, any>;
|
|
107
|
+
pause: boolean;
|
|
108
|
+
autoSubmit: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
declare const TestEngineProvider: ({ test, submitTest, ...props }: {
|
|
112
|
+
test: Test;
|
|
113
|
+
isSolution?: boolean;
|
|
114
|
+
submitTest: React.Dispatch<SubmitTest>;
|
|
115
|
+
} & PropsWithChildren) => React.JSX.Element;
|
|
116
|
+
|
|
117
|
+
declare const useTestEngine: () => {
|
|
118
|
+
currentSection: Section | undefined;
|
|
119
|
+
currentQuestion: Question | undefined;
|
|
120
|
+
handleSubmitTest: (pause?: boolean, autoSubmit?: boolean) => Promise<Record<string, any>>;
|
|
121
|
+
handleUpdateTestDetails: (value: Test) => void;
|
|
122
|
+
handleUpdateQuestionCoordinates: (value: {
|
|
123
|
+
currentQuestionIndex: number;
|
|
124
|
+
currentSectionIndex: number;
|
|
125
|
+
}) => Promise<void>;
|
|
126
|
+
handleUpdateSolutions: (value: Record<string, SolutionDetails>) => void;
|
|
127
|
+
handleUpdateCurrentAnswer: (value: SolutionDetails) => void;
|
|
128
|
+
handleUpdateUserSettings: (value: UserSettings) => void;
|
|
129
|
+
handleResetLocal: () => Promise<void>;
|
|
130
|
+
test: Test | undefined;
|
|
131
|
+
solutions: Record<string, SolutionDetails>;
|
|
132
|
+
currentQuestionIndex: number;
|
|
133
|
+
currentSectionIndex: number;
|
|
134
|
+
currentQuestionAnswer: SolutionDetails | undefined;
|
|
135
|
+
userSettings: UserSettings | undefined;
|
|
136
|
+
isSolution?: boolean;
|
|
137
|
+
submitting?: boolean;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
declare const useTestEngineBody: () => {
|
|
141
|
+
isQuizAnswer: boolean;
|
|
142
|
+
handleClearResponse: () => void;
|
|
143
|
+
handleSelectOption: (optionId: string) => void;
|
|
144
|
+
handleIntegerInputChange: (val: string) => void;
|
|
145
|
+
handleMarkForReview: () => void;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
declare const useTestEngineFooter: () => {
|
|
149
|
+
handleNext: () => void;
|
|
150
|
+
handlePrevious: () => void;
|
|
151
|
+
handleSaveAnswer: () => void;
|
|
152
|
+
handleMarkForReview: () => void;
|
|
153
|
+
isLastQuestion: boolean;
|
|
154
|
+
isFirstQuestion: boolean;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
declare const useTestQuestionStatus: ({ includeAllSections, }?: {
|
|
158
|
+
includeAllSections?: boolean;
|
|
159
|
+
}) => {
|
|
160
|
+
getQuestionStatus: (qi: number, si: number) => AttemptStatus.ATTEMPTED | AttemptStatus.NOT_ATTEMPTED | AttemptStatus.NOT_VISITED | AttemptStatus.MARKED_FOR_REVIEW | AttemptStatus.ATTEMPTED_AND_MARKED_FOR_REVIEW;
|
|
161
|
+
questionStatusMap: Record<AttemptStatus, {
|
|
162
|
+
count: number;
|
|
163
|
+
}>;
|
|
164
|
+
getAnsweredQuestionStatus: (i: number, si: number) => AttemptStatus.ATTEMPTED | AttemptStatus.NOT_ATTEMPTED | AttemptStatus.NOT_VISITED;
|
|
165
|
+
areArraysEqual: (a: string[], b: string[]) => boolean;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
type QuestionStatusType = "correct" | "incorrect" | "skipped";
|
|
169
|
+
declare const useTestSolutionBody: () => {
|
|
170
|
+
correctAnswer: string;
|
|
171
|
+
currentAnswerMarks: string | number;
|
|
172
|
+
currentQuestionStatus: QuestionStatusType;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
declare const useTestTimer: () => {
|
|
176
|
+
timer: number;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
declare const useQuestionStopWatch: (type?: "web" | "app") => {
|
|
180
|
+
questionStopWatch: number;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export { AttemptStatus, type SubmitTest, TestEngineProvider, useQuestionStopWatch, useTestEngine, useTestEngineBody, useTestEngineFooter, useTestQuestionStatus, useTestSolutionBody, useTestTimer };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var ne=Object.create;var F=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var ie=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var ue=(n,e)=>{for(var t in e)F(n,t,{get:e[t],enumerable:!0})},G=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of re(e))!oe.call(n,s)&&s!==t&&F(n,s,{get:()=>e[s],enumerable:!(r=se(e,s))||r.enumerable});return n};var v=(n,e,t)=>(t=n!=null?ne(ie(n)):{},G(e||!n||!n.__esModule?F(t,"default",{value:n,enumerable:!0}):t,n)),ae=n=>G(F({},"__esModule",{value:!0}),n);var Ae={};ue(Ae,{AttemptStatus:()=>P,TestEngineProvider:()=>z,useQuestionStopWatch:()=>te,useTestEngine:()=>D,useTestEngineBody:()=>L,useTestEngineFooter:()=>j,useTestQuestionStatus:()=>Q,useTestSolutionBody:()=>X,useTestTimer:()=>ee});module.exports=ae(Ae);var Z=require("react");var B=v(require("react")),P=(o=>(o.ATTEMPTED="ATTEMPTED",o.NOT_ATTEMPTED="NOT_ATTEMPTED",o.NOT_VISITED="NOT_VISITED",o.MARKED_FOR_REVIEW="MARKED_FOR_REVIEW",o.ATTEMPTED_AND_MARKED_FOR_REVIEW="ATTEMPTED_AND_MARKED_FOR_REVIEW",o.ACITVE_QUESTION="ACITVE_QUESTION",o))(P||{});var q={test:void 0,solutions:{},currentQuestionIndex:0,currentSectionIndex:0,currentQuestionAnswer:{},userSettings:{},isSolution:!1,submitting:!1},w=B.default.createContext([q,()=>{},()=>{}]);w.displayName="TestEngineContext";var K=(n,e)=>{switch(e.type){case"UPDATE_TEST":return{...n,test:e.value};case"UPDATE_SOLUTIONS":return{...n,solutions:e.value};case"UPDATE_CURRENT_ANSWER":return{...n,currentQuestionAnswer:e.value};case"UPDATE_USER_SETTINGS":return{...n,userSettings:e.value};case"UPDATE_TEST_SUBMITTING":return{...n,submitting:e.value};case"UPDATE_QUESTION_COORDINATES":return{...n,currentSectionIndex:e.value.currentSectionIndex,currentQuestionIndex:e.value.currentQuestionIndex}}};var O=v(require("react"));var J=require("react-native-mmkv"),ce=()=>{if(!(typeof navigator<"u"&&navigator.product==="ReactNative")&&typeof window<"u"&&window.localStorage)return{getItem:e=>localStorage.getItem(e)?JSON.parse(localStorage.getItem(e)):null,setItem:(e,t)=>localStorage.setItem(e,JSON.stringify(t)),removeItem:e=>localStorage.removeItem(e)};{let e=new J.MMKV({id:"testforce-engine"});return{getItem:t=>{try{let r=e.getString(t);return r?JSON.parse(r):null}catch(r){return console.log(r),null}},setItem:(t,r)=>{try{e.set(t,JSON.stringify(r))}catch(s){console.log(s)}},removeItem:t=>{try{e.delete(t)}catch(r){console.log(r)}}}}},l=ce();var de=({test:n,submitTest:e,...t})=>{let[r,s]=O.default.useState(!1),[u,o]=O.default.useReducer(K,{...q,test:n,isSolution:t.isSolution}),c=async()=>{let T=await l.getItem(`${n?._id}-test-initiated`),_=await l.getItem(`${n._id}-solutions`)||{};o(T?{type:"UPDATE_SOLUTIONS",value:_}:{type:"UPDATE_SOLUTIONS",value:n?.sections?.reduce((i,S)=>(S.questions?.forEach(a=>{a.questionResponse&&(i[a._id]={...a.questionResponse})}),i),{})||{}});let d=await l.getItem(`${n._id}-currentSectionIndex`)||0,E=await l.getItem(`${n._id}-currentQuestionIndex`)||0;o({type:"UPDATE_QUESTION_COORDINATES",value:{currentSectionIndex:d,currentQuestionIndex:E}}),s(!0)};return(0,Z.useEffect)(()=>{c()},[]),r?O.default.createElement(w.Provider,{value:[u,o,e],...t}):O.default.createElement(O.default.Fragment,null)},z=de;var A=v(require("react"));var me=()=>{let n=A.default.useContext(w);if(n===void 0)throw new Error("useTestEngine must be use within TestEngineProvider");let[e,t,r]=n,s=A.default.useMemo(()=>e.test?.sections[e.currentSectionIndex],[e.currentSectionIndex]),u=A.default.useMemo(()=>s?.questions[e.currentQuestionIndex],[e.currentQuestionIndex,s]);A.default.useEffect(()=>{u&&(e.solutions[u._id]?c({...e.solutions[u._id],isSaved:!0}):(e.isSolution||i({...e.solutions,[u._id]:{}}),c({}))),l.setItem(`${e.test?._id}-currentSectionIndex`,e.currentSectionIndex),l.setItem(`${e.test?._id}-currentQuestionIndex`,e.currentQuestionIndex)},[e.currentSectionIndex,e.currentQuestionIndex]);let o=A.default.useCallback(m=>t({type:"UPDATE_TEST",value:m}),[t]),c=A.default.useCallback(m=>t({type:"UPDATE_CURRENT_ANSWER",value:m}),[t]),T=A.default.useCallback(async m=>(await _(),t({type:"UPDATE_QUESTION_COORDINATES",value:m})),[t]),_=async()=>{let m=await l.getItem(`${e?.test?._id}-timers`)||{};e.test?.sections.forEach(b=>{b.questions?.forEach(R=>{m[R._id]&&!e.solutions[R._id]&&(e.solutions[R._id]={}),e.solutions[R._id]&&(e.solutions[R._id].timeTaken=m[R._id])})})},d=A.default.useCallback(m=>t({type:"UPDATE_USER_SETTINGS",value:m}),[t]),E=A.default.useCallback(m=>t({type:"UPDATE_TEST_SUBMITTING",value:m}),[t]);A.default.useEffect(()=>{e.isSolution||l.setItem(`${e.test?._id}-solutions`,e.solutions)},[e.solutions]);let i=A.default.useCallback(m=>t({type:"UPDATE_SOLUTIONS",value:m}),[t]),S=A.default.useCallback(async()=>{if(!await l.getItem(`${e.test?._id}-test-initiated`)&&e.test?.status==="Paused"){let b=await l.getItem(`${e?.test?._id}-timers`)||{},R={};e.test?.sections?.forEach((p,g)=>{p.questions?.forEach((I,N)=>{I._id===e.test?.lastVisitedQuestionId&&T({currentSectionIndex:g,currentQuestionIndex:N}),I.questionResponse&&(R[I._id]=JSON.stringify(I.questionResponse.timeTaken||0))})}),l.setItem(`${e?.test?._id}-timers`,{...b,...R})}e?.isSolution||l.setItem(`${e.test?._id}-test-initiated`,"true")},[]);A.default.useEffect(()=>{S()},[]);let a=async()=>{await l.removeItem(`${e.test?._id}-currentQuestionIndex`),await l.removeItem(`${e.test?._id}-currentSectionIndex`),await l.removeItem(`${e.test?._id}-solutions`),await l.removeItem(`${e.test?._id}-test-initiated`),await l.removeItem(`${e?.test?._id}-timers`)},f=A.default.useCallback(async(m=!1,b=!1)=>{E(!0);let R=await l.getItem(`${e.test?._id}-solutions`)||{},p=await l.getItem(`${e?.test?._id}-timers`)||{},g=[];e.test?.sections.forEach(N=>{N.questions.forEach(h=>{let C={questionId:h._id};R[h._id]&&(C.markedSolution=R[h._id].markedSolution||[],C.timeTaken=parseInt(p[h._id]||0),C.markedForReview=R[h._id].markedForReview||!1,g.push(C))})});let I={submittedBy:b?"autoSubmit":"user",questionResponses:g,testMappingId:e.test?.testMappingId,type:m?"Pause":"Submit",testId:e.test?._id};return m&&(I.lastVisitedQuestionId=u?._id),e.test?.timerLevel==="TEST"&&e.test.type==="TEST"&&m&&p[e?.test?._id]&&(I.timeTaken={[e.test?._id]:p[e?.test?._id]}),g.length||delete I.questionResponses,await a(),E(!1),r({payload:I,pause:m,autoSubmit:b}),I},[u]);return A.default.useMemo(()=>({...e,currentSection:s,currentQuestion:u,handleSubmitTest:f,handleUpdateTestDetails:o,handleUpdateQuestionCoordinates:T,handleUpdateSolutions:i,handleUpdateCurrentAnswer:c,handleUpdateUserSettings:d,handleResetLocal:a}),[e,s,u,f,o,T,i,c,d,a])},D=me;var k=v(require("react"));var Ee=()=>{let{currentQuestion:n,currentQuestionAnswer:e,test:t,solutions:r,isSolution:s,handleUpdateCurrentAnswer:u,handleUpdateSolutions:o}=D(),c=k.default.useMemo(()=>t?.type==="QUIZ"&&!!r[n?._id]?.markedSolution?.length,[t,r,n]),T=(0,k.useCallback)(()=>{u({...e,markedSolution:[],isSaved:!1}),o({...r,[n?._id]:{...e,markedSolution:[]}})},[e,n,r,u,o]),_=(0,k.useCallback)(i=>{if(!(s||c))if(e?.markedSolution?.includes(i)){let S=e.markedSolution.filter(a=>a!==i);return S?.length===0?T():u({...e,markedSolution:S,isSaved:!1})}else{if(n?.type==="SINGLE")return u({...e,markedSolution:[i],isSaved:!1});{let S=e?.markedSolution?.length?e?.markedSolution:[];return u({...e,markedSolution:[...S,i],isSaved:!1})}}},[s,c,n,e,u,T]),d=(0,k.useCallback)(i=>{s||c||(u({...e,markedSolution:i?[i]:[],isSaved:!1}),i||T())},[s,c,u,e,T]),E=(0,k.useCallback)(()=>{u({...e,markedForReview:!e?.markedForReview}),o({...r,[n._id]:{...r[n._id],markedForReview:!e?.markedForReview}})},[u,o,e,r,n]);return{isQuizAnswer:c,handleClearResponse:T,handleSelectOption:_,handleIntegerInputChange:d,handleMarkForReview:E}},L=Ee;var y=require("react");var W=v(require("react"));var fe=({includeAllSections:n}={})=>{let{currentQuestionIndex:e,solutions:t,currentSectionIndex:r,test:s,isSolution:u}=D(),[o,c]=W.default.useState({MARKED_FOR_REVIEW:{count:0},ATTEMPTED:{count:0},ATTEMPTED_AND_MARKED_FOR_REVIEW:{count:0},NOT_ATTEMPTED:{count:0},NOT_VISITED:{count:0},ACITVE_QUESTION:{count:0}}),T=()=>{let i={...o};Object.values(i).forEach(S=>S.count=0),n?s?.sections?.forEach((S,a)=>{S?.questions?.forEach((f,U)=>{let m=u||s.type==="QUIZ"?E(U,a):_(U,a);i[m].count+=1})}):s?.sections[r]?.questions.forEach((S,a)=>{let f=u||s.type==="QUIZ"?E(a,r):_(a,r);i[f].count+=1}),c(i)};W.default.useEffect(()=>{T()},[e,t,r]);let _=(i,S)=>{let a=s?.sections[S]?.questions[i],f;return t[a?._id]&&t[a?._id].markedSolution?.length&&t[a?._id].markedForReview?f="ATTEMPTED_AND_MARKED_FOR_REVIEW":t[a?._id]&&t[a?._id].markedForReview?f="MARKED_FOR_REVIEW":t[a?._id]&&t[a?._id].markedSolution?.length?f="ATTEMPTED":t[a?._id]?f="NOT_ATTEMPTED":f="NOT_VISITED",f};function d(i,S){let a=i.slice().sort(),f=S.slice().sort();if(a.length!==f.length)return!1;for(let U=0;U<a.length;U++)if(a[U]!==f[U])return!1;return!0}let E=(i,S)=>{let a=s?.sections[S]?.questions[i],f;return t[a?._id]&&t[a?._id].markedSolution?.length?d(t[a?._id].markedSolution,a.solution)?f="ATTEMPTED":f="NOT_ATTEMPTED":f="NOT_VISITED",f};return{getQuestionStatus:_,questionStatusMap:o,getAnsweredQuestionStatus:E,areArraysEqual:d}},Q=fe;var Ie=()=>{let{handleUpdateQuestionCoordinates:n,currentQuestionIndex:e,currentSectionIndex:t,currentSection:r,currentQuestionAnswer:s,handleUpdateSolutions:u,solutions:o,currentQuestion:c,handleUpdateCurrentAnswer:T,test:_,userSettings:d}=D(),{getAnsweredQuestionStatus:E}=Q(),[i,S]=(0,y.useState)([]);(0,y.useEffect)(()=>{if(d?.selectedFilter){let p=r?.questions?.map((g,I)=>{if(d?.selectedFilter===E(I,t))return I})?.filter(g=>g!==void 0);S(p),p?.length&&n({currentSectionIndex:t,currentQuestionIndex:p[0]||0})}else S([])},[d?.selectedFilter,r]);let a=()=>{s?.isSaved||(delete s?.isSaved,u({...o,[c?._id]:{...s}}))},f=()=>{if(d?.selectedFilter){let I=i?.findIndex(N=>N===e);I>=0&&i[I+1]>=0&&n({currentSectionIndex:t,currentQuestionIndex:i[I+1]});return}let p=r?.questions[e+1]?t:_?.sections[t+1]?t+1:t,g=r?.questions[e+1]?e+1:0;n({currentSectionIndex:p,currentQuestionIndex:g})},U=()=>{if(d?.selectedFilter){let I=i?.findIndex(N=>N===e);I>=0&&i[I-1]>=0&&n({currentSectionIndex:t,currentQuestionIndex:i[I-1]});return}let p=r?.questions[e-1]?t:_?.sections[t-1]?t-1:t,g=r?.questions[e-1]?e-1:_.sections[p]?.questions?.length-1;n({currentSectionIndex:p,currentQuestionIndex:g})},m=(0,y.useMemo)(()=>{if(d?.selectedFilter){let p=i?.findIndex(g=>g===e);return!i[p+1]}return!_?.sections[t+1]&&!r?.questions[e+1]},[t,e,i,d?.selectedFilter]),b=(0,y.useMemo)(()=>d?.selectedFilter?i?.findIndex(g=>g===e)<=0:t===0&&e===0,[t,e,i,d?.selectedFilter]);return{handleNext:f,handlePrevious:U,handleSaveAnswer:a,handleMarkForReview:()=>{T({...s,markedForReview:!s?.markedForReview}),u({...o,[c._id]:{...o[c._id],markedForReview:!s?.markedForReview}})},isLastQuestion:m,isFirstQuestion:b}},j=Ie;var $=v(require("react"));var H={1:{label:"A"},2:{label:"B"},3:{label:"C"},4:{label:"D"}},_e=()=>{let{currentQuestionIndex:n,test:e,currentSection:t,currentSectionIndex:r,currentQuestion:s}=D(),{getAnsweredQuestionStatus:u}=Q(),o=$.default.useMemo(()=>u(n,r)==="ATTEMPTED"?"correct":u(n,r)==="NOT_ATTEMPTED"?"incorrect":"skipped",[n,r]),c=$.default.useMemo(()=>{switch(o){case"correct":return e?.marksLevel==="TEST"?"+"+e.positiveMarks:"+"+t?.positiveMarks;case"incorrect":return e?.marksLevel==="TEST"?e.isNegativeMarkingEnabled?"-"+e.negativeMarks:0:t?.isNegativeMarkingEnabled?"-"+t?.negativeMarks:0;case"skipped":return 0}},[o,r,n]);return{correctAnswer:$.default.useMemo(()=>{if(!s)return"";if(s.type==="INTEGER")return s.solution[0];if(s.type==="SINGLE"){let _=s.options.findIndex(d=>d._id===s.solution[0]);return H[_+1]?.label||""}return s.type==="MULTIPLE"?s.solution.map(d=>{let E=s.options.findIndex(i=>i._id===d);return H[E+1]?.label||""}).join(", "):""},[s]),currentAnswerMarks:c,currentQuestionStatus:o}},X=_e;var V=v(require("react"));var pe=()=>{let{test:n,handleSubmitTest:e}=D(),t=V.default.useRef(null),[r,s]=V.default.useState(n?.timeTaken?.[n?._id]??n?.duration??0),u=async c=>{let T=await l.getItem(`${n?._id}-timers`);if(c<=0){e(!1,!0);return}T[n._id]=c+"",l.setItem(`${n?._id}-timers`,T),s(c),t.current=setTimeout(()=>{u(c-1)},1e3)},o=async()=>{let c=await l.getItem(`${n?._id}-timers`);c||(await l.setItem(`${n?._id}-timers`,{}),c={});let T=parseInt(c?.[n?._id]||n?.timeTaken?.[n?._id]||n?.duration||0);u(T)};return V.default.useEffect(()=>(o(),()=>{t.current&&clearTimeout(t.current)}),[]),{timer:r}},ee=pe;var M=v(require("react"));var ge=n=>{let e=n==="app"?950:1e3,{currentQuestion:t,solutions:r,test:s}=D(),{isQuizAnswer:u}=L(),o=M.default.useRef(null),[c,T]=M.default.useState(0),_=async E=>{if(!t)return;let i=await l.getItem(`${s?._id}-timers`);if((r[t?._id]?.markedSolution||[])?.length===0)i[t?._id]=E+"",l.setItem(`${s?._id}-timers`,i),T(E);else{clearTimeout(o.current);return}o.current=setTimeout(()=>{_(E+1)},e)},d=async()=>{o.current&&(clearTimeout(o.current),o.current=null);let E=await l.getItem(`${s?._id}-timers`);E||(await l.setItem(`${s?._id}-timers`,{}),E={});let i=parseInt(E?.[t?._id]||s?.timeTaken?.[t?._id]||0);T(i),_(i)};return M.default.useEffect(()=>(t?._id&&d(),()=>{o.current&&(clearTimeout(o.current),o.current=null)}),[t]),M.default.useEffect(()=>{o.current===null&&setTimeout(()=>{o.current===null&&d()},e)},[r]),M.default.useEffect(()=>{u&&(clearTimeout(o.current),o.current=null)},[u]),{questionStopWatch:c}},te=ge;0&&(module.exports={AttemptStatus,TestEngineProvider,useQuestionStopWatch,useTestEngine,useTestEngineBody,useTestEngineFooter,useTestQuestionStatus,useTestSolutionBody,useTestTimer});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useEffect as Y}from"react";import K from"react";var P=(i=>(i.ATTEMPTED="ATTEMPTED",i.NOT_ATTEMPTED="NOT_ATTEMPTED",i.NOT_VISITED="NOT_VISITED",i.MARKED_FOR_REVIEW="MARKED_FOR_REVIEW",i.ATTEMPTED_AND_MARKED_FOR_REVIEW="ATTEMPTED_AND_MARKED_FOR_REVIEW",i.ACITVE_QUESTION="ACITVE_QUESTION",i))(P||{});var C={test:void 0,solutions:{},currentQuestionIndex:0,currentSectionIndex:0,currentQuestionAnswer:{},userSettings:{},isSolution:!1,submitting:!1},y=K.createContext([C,()=>{},()=>{}]);y.displayName="TestEngineContext";var V=(n,e)=>{switch(e.type){case"UPDATE_TEST":return{...n,test:e.value};case"UPDATE_SOLUTIONS":return{...n,solutions:e.value};case"UPDATE_CURRENT_ANSWER":return{...n,currentQuestionAnswer:e.value};case"UPDATE_USER_SETTINGS":return{...n,userSettings:e.value};case"UPDATE_TEST_SUBMITTING":return{...n,submitting:e.value};case"UPDATE_QUESTION_COORDINATES":return{...n,currentSectionIndex:e.value.currentSectionIndex,currentQuestionIndex:e.value.currentQuestionIndex}}};import O from"react";import{MMKV as J}from"react-native-mmkv";var Z=()=>{if(!(typeof navigator<"u"&&navigator.product==="ReactNative")&&typeof window<"u"&&window.localStorage)return{getItem:e=>localStorage.getItem(e)?JSON.parse(localStorage.getItem(e)):null,setItem:(e,t)=>localStorage.setItem(e,JSON.stringify(t)),removeItem:e=>localStorage.removeItem(e)};{let e=new J({id:"testforce-engine"});return{getItem:t=>{try{let o=e.getString(t);return o?JSON.parse(o):null}catch(o){return console.log(o),null}},setItem:(t,o)=>{try{e.set(t,JSON.stringify(o))}catch(s){console.log(s)}},removeItem:t=>{try{e.delete(t)}catch(o){console.log(o)}}}}},l=Z();var j=({test:n,submitTest:e,...t})=>{let[o,s]=O.useState(!1),[u,i]=O.useReducer(V,{...C,test:n,isSolution:t.isSolution}),c=async()=>{let T=await l.getItem(`${n?._id}-test-initiated`),_=await l.getItem(`${n._id}-solutions`)||{};i(T?{type:"UPDATE_SOLUTIONS",value:_}:{type:"UPDATE_SOLUTIONS",value:n?.sections?.reduce((r,S)=>(S.questions?.forEach(a=>{a.questionResponse&&(r[a._id]={...a.questionResponse})}),r),{})||{}});let d=await l.getItem(`${n._id}-currentSectionIndex`)||0,E=await l.getItem(`${n._id}-currentQuestionIndex`)||0;i({type:"UPDATE_QUESTION_COORDINATES",value:{currentSectionIndex:d,currentQuestionIndex:E}}),s(!0)};return Y(()=>{c()},[]),o?O.createElement(y.Provider,{value:[u,i,e],...t}):O.createElement(O.Fragment,null)},H=j;import A from"react";var ee=()=>{let n=A.useContext(y);if(n===void 0)throw new Error("useTestEngine must be use within TestEngineProvider");let[e,t,o]=n,s=A.useMemo(()=>e.test?.sections[e.currentSectionIndex],[e.currentSectionIndex]),u=A.useMemo(()=>s?.questions[e.currentQuestionIndex],[e.currentQuestionIndex,s]);A.useEffect(()=>{u&&(e.solutions[u._id]?c({...e.solutions[u._id],isSaved:!0}):(e.isSolution||r({...e.solutions,[u._id]:{}}),c({}))),l.setItem(`${e.test?._id}-currentSectionIndex`,e.currentSectionIndex),l.setItem(`${e.test?._id}-currentQuestionIndex`,e.currentQuestionIndex)},[e.currentSectionIndex,e.currentQuestionIndex]);let i=A.useCallback(m=>t({type:"UPDATE_TEST",value:m}),[t]),c=A.useCallback(m=>t({type:"UPDATE_CURRENT_ANSWER",value:m}),[t]),T=A.useCallback(async m=>(await _(),t({type:"UPDATE_QUESTION_COORDINATES",value:m})),[t]),_=async()=>{let m=await l.getItem(`${e?.test?._id}-timers`)||{};e.test?.sections.forEach(v=>{v.questions?.forEach(R=>{m[R._id]&&!e.solutions[R._id]&&(e.solutions[R._id]={}),e.solutions[R._id]&&(e.solutions[R._id].timeTaken=m[R._id])})})},d=A.useCallback(m=>t({type:"UPDATE_USER_SETTINGS",value:m}),[t]),E=A.useCallback(m=>t({type:"UPDATE_TEST_SUBMITTING",value:m}),[t]);A.useEffect(()=>{e.isSolution||l.setItem(`${e.test?._id}-solutions`,e.solutions)},[e.solutions]);let r=A.useCallback(m=>t({type:"UPDATE_SOLUTIONS",value:m}),[t]),S=A.useCallback(async()=>{if(!await l.getItem(`${e.test?._id}-test-initiated`)&&e.test?.status==="Paused"){let v=await l.getItem(`${e?.test?._id}-timers`)||{},R={};e.test?.sections?.forEach((p,g)=>{p.questions?.forEach((I,N)=>{I._id===e.test?.lastVisitedQuestionId&&T({currentSectionIndex:g,currentQuestionIndex:N}),I.questionResponse&&(R[I._id]=JSON.stringify(I.questionResponse.timeTaken||0))})}),l.setItem(`${e?.test?._id}-timers`,{...v,...R})}e?.isSolution||l.setItem(`${e.test?._id}-test-initiated`,"true")},[]);A.useEffect(()=>{S()},[]);let a=async()=>{await l.removeItem(`${e.test?._id}-currentQuestionIndex`),await l.removeItem(`${e.test?._id}-currentSectionIndex`),await l.removeItem(`${e.test?._id}-solutions`),await l.removeItem(`${e.test?._id}-test-initiated`),await l.removeItem(`${e?.test?._id}-timers`)},f=A.useCallback(async(m=!1,v=!1)=>{E(!0);let R=await l.getItem(`${e.test?._id}-solutions`)||{},p=await l.getItem(`${e?.test?._id}-timers`)||{},g=[];e.test?.sections.forEach(N=>{N.questions.forEach(k=>{let h={questionId:k._id};R[k._id]&&(h.markedSolution=R[k._id].markedSolution||[],h.timeTaken=parseInt(p[k._id]||0),h.markedForReview=R[k._id].markedForReview||!1,g.push(h))})});let I={submittedBy:v?"autoSubmit":"user",questionResponses:g,testMappingId:e.test?.testMappingId,type:m?"Pause":"Submit",testId:e.test?._id};return m&&(I.lastVisitedQuestionId=u?._id),e.test?.timerLevel==="TEST"&&e.test.type==="TEST"&&m&&p[e?.test?._id]&&(I.timeTaken={[e.test?._id]:p[e?.test?._id]}),g.length||delete I.questionResponses,await a(),E(!1),o({payload:I,pause:m,autoSubmit:v}),I},[u]);return A.useMemo(()=>({...e,currentSection:s,currentQuestion:u,handleSubmitTest:f,handleUpdateTestDetails:i,handleUpdateQuestionCoordinates:T,handleUpdateSolutions:r,handleUpdateCurrentAnswer:c,handleUpdateUserSettings:d,handleResetLocal:a}),[e,s,u,f,i,T,r,c,d,a])},D=ee;import ne,{useCallback as w}from"react";var se=()=>{let{currentQuestion:n,currentQuestionAnswer:e,test:t,solutions:o,isSolution:s,handleUpdateCurrentAnswer:u,handleUpdateSolutions:i}=D(),c=ne.useMemo(()=>t?.type==="QUIZ"&&!!o[n?._id]?.markedSolution?.length,[t,o,n]),T=w(()=>{u({...e,markedSolution:[],isSaved:!1}),i({...o,[n?._id]:{...e,markedSolution:[]}})},[e,n,o,u,i]),_=w(r=>{if(!(s||c))if(e?.markedSolution?.includes(r)){let S=e.markedSolution.filter(a=>a!==r);return S?.length===0?T():u({...e,markedSolution:S,isSaved:!1})}else{if(n?.type==="SINGLE")return u({...e,markedSolution:[r],isSaved:!1});{let S=e?.markedSolution?.length?e?.markedSolution:[];return u({...e,markedSolution:[...S,r],isSaved:!1})}}},[s,c,n,e,u,T]),d=w(r=>{s||c||(u({...e,markedSolution:r?[r]:[],isSaved:!1}),r||T())},[s,c,u,e,T]),E=w(()=>{u({...e,markedForReview:!e?.markedForReview}),i({...o,[n._id]:{...o[n._id],markedForReview:!e?.markedForReview}})},[u,i,e,o,n]);return{isQuizAnswer:c,handleClearResponse:T,handleSelectOption:_,handleIntegerInputChange:d,handleMarkForReview:E}},F=se;import{useEffect as ie,useMemo as G,useState as oe}from"react";import W from"react";var re=({includeAllSections:n}={})=>{let{currentQuestionIndex:e,solutions:t,currentSectionIndex:o,test:s,isSolution:u}=D(),[i,c]=W.useState({MARKED_FOR_REVIEW:{count:0},ATTEMPTED:{count:0},ATTEMPTED_AND_MARKED_FOR_REVIEW:{count:0},NOT_ATTEMPTED:{count:0},NOT_VISITED:{count:0},ACITVE_QUESTION:{count:0}}),T=()=>{let r={...i};Object.values(r).forEach(S=>S.count=0),n?s?.sections?.forEach((S,a)=>{S?.questions?.forEach((f,b)=>{let m=u||s.type==="QUIZ"?E(b,a):_(b,a);r[m].count+=1})}):s?.sections[o]?.questions.forEach((S,a)=>{let f=u||s.type==="QUIZ"?E(a,o):_(a,o);r[f].count+=1}),c(r)};W.useEffect(()=>{T()},[e,t,o]);let _=(r,S)=>{let a=s?.sections[S]?.questions[r],f;return t[a?._id]&&t[a?._id].markedSolution?.length&&t[a?._id].markedForReview?f="ATTEMPTED_AND_MARKED_FOR_REVIEW":t[a?._id]&&t[a?._id].markedForReview?f="MARKED_FOR_REVIEW":t[a?._id]&&t[a?._id].markedSolution?.length?f="ATTEMPTED":t[a?._id]?f="NOT_ATTEMPTED":f="NOT_VISITED",f};function d(r,S){let a=r.slice().sort(),f=S.slice().sort();if(a.length!==f.length)return!1;for(let b=0;b<a.length;b++)if(a[b]!==f[b])return!1;return!0}let E=(r,S)=>{let a=s?.sections[S]?.questions[r],f;return t[a?._id]&&t[a?._id].markedSolution?.length?d(t[a?._id].markedSolution,a.solution)?f="ATTEMPTED":f="NOT_ATTEMPTED":f="NOT_VISITED",f};return{getQuestionStatus:_,questionStatusMap:i,getAnsweredQuestionStatus:E,areArraysEqual:d}},Q=re;var ue=()=>{let{handleUpdateQuestionCoordinates:n,currentQuestionIndex:e,currentSectionIndex:t,currentSection:o,currentQuestionAnswer:s,handleUpdateSolutions:u,solutions:i,currentQuestion:c,handleUpdateCurrentAnswer:T,test:_,userSettings:d}=D(),{getAnsweredQuestionStatus:E}=Q(),[r,S]=oe([]);ie(()=>{if(d?.selectedFilter){let p=o?.questions?.map((g,I)=>{if(d?.selectedFilter===E(I,t))return I})?.filter(g=>g!==void 0);S(p),p?.length&&n({currentSectionIndex:t,currentQuestionIndex:p[0]||0})}else S([])},[d?.selectedFilter,o]);let a=()=>{s?.isSaved||(delete s?.isSaved,u({...i,[c?._id]:{...s}}))},f=()=>{if(d?.selectedFilter){let I=r?.findIndex(N=>N===e);I>=0&&r[I+1]>=0&&n({currentSectionIndex:t,currentQuestionIndex:r[I+1]});return}let p=o?.questions[e+1]?t:_?.sections[t+1]?t+1:t,g=o?.questions[e+1]?e+1:0;n({currentSectionIndex:p,currentQuestionIndex:g})},b=()=>{if(d?.selectedFilter){let I=r?.findIndex(N=>N===e);I>=0&&r[I-1]>=0&&n({currentSectionIndex:t,currentQuestionIndex:r[I-1]});return}let p=o?.questions[e-1]?t:_?.sections[t-1]?t-1:t,g=o?.questions[e-1]?e-1:_.sections[p]?.questions?.length-1;n({currentSectionIndex:p,currentQuestionIndex:g})},m=G(()=>{if(d?.selectedFilter){let p=r?.findIndex(g=>g===e);return!r[p+1]}return!_?.sections[t+1]&&!o?.questions[e+1]},[t,e,r,d?.selectedFilter]),v=G(()=>d?.selectedFilter?r?.findIndex(g=>g===e)<=0:t===0&&e===0,[t,e,r,d?.selectedFilter]);return{handleNext:f,handlePrevious:b,handleSaveAnswer:a,handleMarkForReview:()=>{T({...s,markedForReview:!s?.markedForReview}),u({...i,[c._id]:{...i[c._id],markedForReview:!s?.markedForReview}})},isLastQuestion:m,isFirstQuestion:v}},ae=ue;import L from"react";var B={1:{label:"A"},2:{label:"B"},3:{label:"C"},4:{label:"D"}},ce=()=>{let{currentQuestionIndex:n,test:e,currentSection:t,currentSectionIndex:o,currentQuestion:s}=D(),{getAnsweredQuestionStatus:u}=Q(),i=L.useMemo(()=>u(n,o)==="ATTEMPTED"?"correct":u(n,o)==="NOT_ATTEMPTED"?"incorrect":"skipped",[n,o]),c=L.useMemo(()=>{switch(i){case"correct":return e?.marksLevel==="TEST"?"+"+e.positiveMarks:"+"+t?.positiveMarks;case"incorrect":return e?.marksLevel==="TEST"?e.isNegativeMarkingEnabled?"-"+e.negativeMarks:0:t?.isNegativeMarkingEnabled?"-"+t?.negativeMarks:0;case"skipped":return 0}},[i,o,n]);return{correctAnswer:L.useMemo(()=>{if(!s)return"";if(s.type==="INTEGER")return s.solution[0];if(s.type==="SINGLE"){let _=s.options.findIndex(d=>d._id===s.solution[0]);return B[_+1]?.label||""}return s.type==="MULTIPLE"?s.solution.map(d=>{let E=s.options.findIndex(r=>r._id===d);return B[E+1]?.label||""}).join(", "):""},[s]),currentAnswerMarks:c,currentQuestionStatus:i}},le=ce;import $ from"react";var de=()=>{let{test:n,handleSubmitTest:e}=D(),t=$.useRef(null),[o,s]=$.useState(n?.timeTaken?.[n?._id]??n?.duration??0),u=async c=>{let T=await l.getItem(`${n?._id}-timers`);if(c<=0){e(!1,!0);return}T[n._id]=c+"",l.setItem(`${n?._id}-timers`,T),s(c),t.current=setTimeout(()=>{u(c-1)},1e3)},i=async()=>{let c=await l.getItem(`${n?._id}-timers`);c||(await l.setItem(`${n?._id}-timers`,{}),c={});let T=parseInt(c?.[n?._id]||n?.timeTaken?.[n?._id]||n?.duration||0);u(T)};return $.useEffect(()=>(i(),()=>{t.current&&clearTimeout(t.current)}),[]),{timer:o}},Te=de;import M from"react";var me=n=>{let e=n==="app"?950:1e3,{currentQuestion:t,solutions:o,test:s}=D(),{isQuizAnswer:u}=F(),i=M.useRef(null),[c,T]=M.useState(0),_=async E=>{if(!t)return;let r=await l.getItem(`${s?._id}-timers`);if((o[t?._id]?.markedSolution||[])?.length===0)r[t?._id]=E+"",l.setItem(`${s?._id}-timers`,r),T(E);else{clearTimeout(i.current);return}i.current=setTimeout(()=>{_(E+1)},e)},d=async()=>{i.current&&(clearTimeout(i.current),i.current=null);let E=await l.getItem(`${s?._id}-timers`);E||(await l.setItem(`${s?._id}-timers`,{}),E={});let r=parseInt(E?.[t?._id]||s?.timeTaken?.[t?._id]||0);T(r),_(r)};return M.useEffect(()=>(t?._id&&d(),()=>{i.current&&(clearTimeout(i.current),i.current=null)}),[t]),M.useEffect(()=>{i.current===null&&setTimeout(()=>{i.current===null&&d()},e)},[o]),M.useEffect(()=>{u&&(clearTimeout(i.current),i.current=null)},[u]),{questionStopWatch:c}},Se=me;export{P as AttemptStatus,H as TestEngineProvider,Se as useQuestionStopWatch,D as useTestEngine,F as useTestEngineBody,ae as useTestEngineFooter,Q as useTestQuestionStatus,le as useTestSolutionBody,Te as useTestTimer};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "testforce-engine",
|
|
3
|
+
"version": "0.0.1-alpha",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsup",
|
|
10
|
+
"prepare": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@babel/runtime": "^7.26.9",
|
|
17
|
+
"@react-native-async-storage/async-storage": "^2.1.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/react": "18.3.1",
|
|
21
|
+
"tsup": "^8.3.6",
|
|
22
|
+
"typescript": "^5.7.3"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"react": "18.3.1",
|
|
26
|
+
"react-native": "0.76.9",
|
|
27
|
+
"react-native-mmkv": "3.2.0"
|
|
28
|
+
}
|
|
29
|
+
}
|