catchup-library-web 1.11.0 → 1.11.1
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/package.json
CHANGED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import DropdownActivityContent from "./DropdownActivityContent";
|
|
3
|
+
import FillInTheBlanksActivityContent from "./FillInTheBlanksActivityContent";
|
|
4
|
+
import GroupingActivityContent from "./GroupingActivityContent";
|
|
5
|
+
import MatchingActivityContent from "./MatchingActivityContent";
|
|
6
|
+
import MCMAActivityContent from "./MCMAActivityContent";
|
|
7
|
+
import MCSAActivityContent from "./MCSAActivityContent";
|
|
8
|
+
import OpenEndedActivityContent from "./OpenEndedActivityContent";
|
|
9
|
+
import OrderingActivityContent from "./OrderingActivityContent";
|
|
10
|
+
import SelectionBox from "../boxes/SelectionBox";
|
|
11
|
+
import TrueFalseActivityContent from "./TrueFalseActivityContent";
|
|
12
|
+
import ActivitySolutionContent from "./solution-content/ActivitySolutionContent";
|
|
13
|
+
import ActivityEvaluationRubricContent from "./evaluation-rubric-content/ActivityEvaluationRubricContent";
|
|
14
|
+
import DividerLine from "../dividers/DividerLine";
|
|
15
|
+
import i18n from "../../language/i18n";
|
|
16
|
+
import { constructActivityAnswerMap } from "../../utilization/CatchtivityUtilization";
|
|
17
|
+
import { IActivityPreviewByAnswerDataProps } from "../../properties/ActivityProperties";
|
|
18
|
+
import ActivityEmptyContent from "./empty-content/ActivityEmptyContent";
|
|
19
|
+
|
|
20
|
+
const ActivityPreviewByAnswerData = ({
|
|
21
|
+
data,
|
|
22
|
+
showType = true,
|
|
23
|
+
showDescription = true,
|
|
24
|
+
lockedType = null,
|
|
25
|
+
typeOptionList = [],
|
|
26
|
+
showSolution = false,
|
|
27
|
+
showEvaluationRubric = false,
|
|
28
|
+
showTaxonomy = true,
|
|
29
|
+
isFullScreen = false,
|
|
30
|
+
showCorrectAnswer = false,
|
|
31
|
+
}: IActivityPreviewByAnswerDataProps) => {
|
|
32
|
+
const [key, setKey] = useState(new Date().getTime());
|
|
33
|
+
const [selectedType, setSelectedType] = useState<string | null>(null);
|
|
34
|
+
const [optionList, setOptionList] = useState<any[]>([]);
|
|
35
|
+
// Define proper types for answer data
|
|
36
|
+
interface AnswerItem {
|
|
37
|
+
type: string;
|
|
38
|
+
isEmpty?: boolean;
|
|
39
|
+
answerMap?: any;
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface Answer {
|
|
44
|
+
data: AnswerItem[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const [answer, setAnswer] = useState<Answer>({ data: [] });
|
|
48
|
+
|
|
49
|
+
// Reset component when data changes
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!data) return;
|
|
52
|
+
setKey(new Date().getTime());
|
|
53
|
+
}, [data]);
|
|
54
|
+
|
|
55
|
+
// Helper function to check if answer map exists for a specific type
|
|
56
|
+
const checkAnswerMapExists = (type: string): AnswerItem | null => {
|
|
57
|
+
if (data && data.answerMap && Array.isArray(data.answerMap)) {
|
|
58
|
+
const foundAnswer = data.answerMap.find(
|
|
59
|
+
(answer: any) => answer.type === type
|
|
60
|
+
);
|
|
61
|
+
return foundAnswer || null;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Helper function to retrieve taxonomy name from activity type
|
|
67
|
+
const retrieveTaxonomyNameFromActivityType = (type: string) => {
|
|
68
|
+
if (!data) return "";
|
|
69
|
+
|
|
70
|
+
let taxonomyMap = { name: "" };
|
|
71
|
+
|
|
72
|
+
const taxonomyMapNames: { [key: string]: string } = {
|
|
73
|
+
ORDERING: "orderingTaxonomyMap",
|
|
74
|
+
DROPDOWN: "dropdownTaxonomyMap",
|
|
75
|
+
MCSA: "MCSATaxonomyMap",
|
|
76
|
+
MCMA: "MCMATaxonomyMap",
|
|
77
|
+
MATCHING: "matchingTaxonomyMap",
|
|
78
|
+
GROUPING: "groupingTaxonomyMap",
|
|
79
|
+
FILL_IN_THE_BLANKS: "fillInTheBlanksTaxonomyMap",
|
|
80
|
+
OPEN_ENDED: "openEndedTaxonomyMap",
|
|
81
|
+
TRUE_FALSE: "trueFalseTaxonomyMap",
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const mapName = taxonomyMapNames[type];
|
|
85
|
+
if (mapName && data[mapName]) {
|
|
86
|
+
try {
|
|
87
|
+
taxonomyMap = JSON.parse(data[mapName]);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error(`Error parsing taxonomy map for ${type}:`, error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return taxonomyMap.name || "";
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Construct answer data based on available activity types
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!data) return;
|
|
99
|
+
|
|
100
|
+
const constructAnswerBasedOnData = () => {
|
|
101
|
+
const newAnswer: Answer = { data: [] };
|
|
102
|
+
|
|
103
|
+
const activityTypes = [
|
|
104
|
+
{ type: "ORDERING", materialMap: "orderingMaterialMap" },
|
|
105
|
+
{ type: "DROPDOWN", materialMap: "dropdownMaterialMap" },
|
|
106
|
+
{ type: "MCSA", materialMap: "MCSAMaterialMap" },
|
|
107
|
+
{ type: "MCMA", materialMap: "MCMAMaterialMap" },
|
|
108
|
+
{ type: "MATCHING", materialMap: "matchingMaterialMap" },
|
|
109
|
+
{ type: "GROUPING", materialMap: "groupingMaterialMap" },
|
|
110
|
+
{
|
|
111
|
+
type: "FILL_IN_THE_BLANKS",
|
|
112
|
+
materialMap: "fillInTheBlanksMaterialMap",
|
|
113
|
+
},
|
|
114
|
+
{ type: "OPEN_ENDED", materialMap: "openEndedMaterialMap" },
|
|
115
|
+
{ type: "TRUE_FALSE", materialMap: "trueFalseMaterialMap" },
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
activityTypes.forEach(({ type, materialMap }) => {
|
|
119
|
+
if (data[materialMap]) {
|
|
120
|
+
const foundAnswer = checkAnswerMapExists(type);
|
|
121
|
+
const answerItem: AnswerItem =
|
|
122
|
+
foundAnswer ||
|
|
123
|
+
constructActivityAnswerMap(
|
|
124
|
+
{ type },
|
|
125
|
+
JSON.parse(JSON.stringify(data))
|
|
126
|
+
);
|
|
127
|
+
newAnswer.data.push(answerItem);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
setAnswer(newAnswer);
|
|
132
|
+
|
|
133
|
+
// Set initial selected type
|
|
134
|
+
if (newAnswer.data.length > 0) {
|
|
135
|
+
if (
|
|
136
|
+
lockedType &&
|
|
137
|
+
newAnswer.data.find((item: AnswerItem) => item.type === lockedType)
|
|
138
|
+
) {
|
|
139
|
+
setSelectedType(lockedType);
|
|
140
|
+
} else {
|
|
141
|
+
setSelectedType(newAnswer.data[0].type);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
constructAnswerBasedOnData();
|
|
147
|
+
}, [data, lockedType]);
|
|
148
|
+
|
|
149
|
+
// Set up option list for type selection
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (!data || !answer.data.length) return;
|
|
152
|
+
|
|
153
|
+
let currentTypeOptionList =
|
|
154
|
+
typeOptionList ||
|
|
155
|
+
answer.data.map((item) => ({
|
|
156
|
+
id: item.type,
|
|
157
|
+
text: i18n.t(item.type),
|
|
158
|
+
}));
|
|
159
|
+
|
|
160
|
+
if (lockedType) {
|
|
161
|
+
currentTypeOptionList = currentTypeOptionList.filter(
|
|
162
|
+
(typeOption: any) => typeOption.id === lockedType
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (showTaxonomy) {
|
|
167
|
+
setOptionList(
|
|
168
|
+
currentTypeOptionList.map((typeOption: any) => ({
|
|
169
|
+
...typeOption,
|
|
170
|
+
subText: i18n.t(retrieveTaxonomyNameFromActivityType(typeOption.id)),
|
|
171
|
+
}))
|
|
172
|
+
);
|
|
173
|
+
} else {
|
|
174
|
+
setOptionList(currentTypeOptionList);
|
|
175
|
+
}
|
|
176
|
+
}, [data, answer.data, lockedType, typeOptionList, showTaxonomy]);
|
|
177
|
+
|
|
178
|
+
// Render the appropriate activity content based on selected type
|
|
179
|
+
const RenderSelectedActivityContent = () => {
|
|
180
|
+
const commonProps = {
|
|
181
|
+
answer,
|
|
182
|
+
data,
|
|
183
|
+
canAnswerQuestion: () => true,
|
|
184
|
+
changeAnswer: (newAnswer: Answer) =>
|
|
185
|
+
setAnswer(JSON.parse(JSON.stringify(newAnswer))),
|
|
186
|
+
isPreview: true,
|
|
187
|
+
showCorrectAnswer,
|
|
188
|
+
isFullScreen,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
switch (selectedType) {
|
|
192
|
+
case "ORDERING":
|
|
193
|
+
return data.orderingBodyMap && data.orderingMaterialMap ? (
|
|
194
|
+
<OrderingActivityContent {...commonProps} />
|
|
195
|
+
) : null;
|
|
196
|
+
|
|
197
|
+
case "DROPDOWN":
|
|
198
|
+
return data.dropdownBodyMap && data.dropdownMaterialMap ? (
|
|
199
|
+
<DropdownActivityContent {...commonProps} />
|
|
200
|
+
) : null;
|
|
201
|
+
|
|
202
|
+
case "MCSA":
|
|
203
|
+
return data.MCSABodyMap && data.MCSAMaterialMap ? (
|
|
204
|
+
<MCSAActivityContent {...commonProps} />
|
|
205
|
+
) : null;
|
|
206
|
+
|
|
207
|
+
case "MCMA":
|
|
208
|
+
return data.MCMABodyMap && data.MCMAMaterialMap ? (
|
|
209
|
+
<MCMAActivityContent {...commonProps} />
|
|
210
|
+
) : null;
|
|
211
|
+
|
|
212
|
+
case "MATCHING":
|
|
213
|
+
return data.matchingBodyMap && data.matchingMaterialMap ? (
|
|
214
|
+
<MatchingActivityContent {...commonProps} />
|
|
215
|
+
) : null;
|
|
216
|
+
|
|
217
|
+
case "GROUPING":
|
|
218
|
+
return data.groupingBodyMap && data.groupingMaterialMap ? (
|
|
219
|
+
<GroupingActivityContent {...commonProps} />
|
|
220
|
+
) : null;
|
|
221
|
+
|
|
222
|
+
case "FILL_IN_THE_BLANKS":
|
|
223
|
+
return data.fillInTheBlanksBodyMap &&
|
|
224
|
+
data.fillInTheBlanksMaterialMap ? (
|
|
225
|
+
<FillInTheBlanksActivityContent {...commonProps} />
|
|
226
|
+
) : null;
|
|
227
|
+
|
|
228
|
+
case "OPEN_ENDED":
|
|
229
|
+
return data.openEndedBodyMap ? (
|
|
230
|
+
<OpenEndedActivityContent
|
|
231
|
+
{...commonProps}
|
|
232
|
+
showMaterialContent={true}
|
|
233
|
+
/>
|
|
234
|
+
) : null;
|
|
235
|
+
|
|
236
|
+
case "TRUE_FALSE":
|
|
237
|
+
return data.trueFalseBodyMap && data.trueFalseMaterialMap ? (
|
|
238
|
+
<TrueFalseActivityContent {...commonProps} />
|
|
239
|
+
) : null;
|
|
240
|
+
|
|
241
|
+
default:
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
if (!data) return null;
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<div key={key}>
|
|
250
|
+
{showType && optionList.length > 0 ? (
|
|
251
|
+
<div className="mb-4">
|
|
252
|
+
{showDescription ? (
|
|
253
|
+
<div className="my-2">
|
|
254
|
+
<p className="font-semibold text-lg">
|
|
255
|
+
{i18n.t("activity_template")}
|
|
256
|
+
</p>
|
|
257
|
+
</div>
|
|
258
|
+
) : null}
|
|
259
|
+
|
|
260
|
+
<SelectionBox
|
|
261
|
+
optionList={optionList}
|
|
262
|
+
selectedId={selectedType}
|
|
263
|
+
handleSelectOnClick={(itemId) => {
|
|
264
|
+
setSelectedType(itemId);
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
) : null}
|
|
269
|
+
|
|
270
|
+
<DividerLine />
|
|
271
|
+
|
|
272
|
+
<div className="flex flex-col my-2 w-full p-5">
|
|
273
|
+
{answer?.data[0]?.isEmpty ? <ActivityEmptyContent /> : null}
|
|
274
|
+
|
|
275
|
+
{selectedType ? (
|
|
276
|
+
<div key={selectedType}>{RenderSelectedActivityContent()}</div>
|
|
277
|
+
) : null}
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
{selectedType && showSolution ? (
|
|
281
|
+
<div className="my-4">
|
|
282
|
+
<ActivitySolutionContent
|
|
283
|
+
activityTemplateType={selectedType}
|
|
284
|
+
data={data}
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
) : null}
|
|
288
|
+
|
|
289
|
+
{selectedType && showEvaluationRubric ? (
|
|
290
|
+
<div className="my-4">
|
|
291
|
+
<ActivityEvaluationRubricContent
|
|
292
|
+
activityTemplateType={selectedType}
|
|
293
|
+
data={data}
|
|
294
|
+
/>
|
|
295
|
+
</div>
|
|
296
|
+
) : null}
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export default ActivityPreviewByAnswerData;
|
|
@@ -228,3 +228,16 @@ export interface IActivityPreviewByDataProps {
|
|
|
228
228
|
showEvaluationRubric: boolean;
|
|
229
229
|
isFullScreen: boolean;
|
|
230
230
|
}
|
|
231
|
+
|
|
232
|
+
export interface IActivityPreviewByAnswerDataProps {
|
|
233
|
+
data: any;
|
|
234
|
+
showType?: boolean;
|
|
235
|
+
showDescription?: boolean;
|
|
236
|
+
lockedType?: string | null;
|
|
237
|
+
typeOptionList?: any[];
|
|
238
|
+
showSolution?: boolean;
|
|
239
|
+
showEvaluationRubric?: boolean;
|
|
240
|
+
showTaxonomy?: boolean;
|
|
241
|
+
isFullScreen?: boolean;
|
|
242
|
+
showCorrectAnswer?: boolean;
|
|
243
|
+
}
|