some experimental features introduced

This commit is contained in:
Hikmet 2023-07-25 12:02:57 +03:00
parent 89ef8b6abf
commit 21e5a40810
9 changed files with 325 additions and 0 deletions

View File

@ -118,6 +118,7 @@ export class DndSetting {
};
}
console.warn("no user data");
const blanks: Map<string, Blank> = new Map(
Array.from(answers, ([key, answer]) => [key, { answer, reply: null }])
);

View File

@ -0,0 +1,32 @@
import { UserExerciseLocalRepository } from "../../repositories/interfaces/user_exercise_loca_repository";
export abstract class Exercise<Q> {
constructor(readonly activityId: string, readonly questions: Q[]) {}
abstract get grade(): number;
saveLocally(userExerciseLocalRepo: UserExerciseLocalRepository) {
userExerciseLocalRepo.saveUserActivityDataLocally({
activityId: this.activityId,
grade: this.grade,
exerciseData: this,
});
}
protected abstract createFrom(
activityId: string,
questions: Q[]
): Exercise<Q>;
getLocalVersion(userExerciseLocalRepo: UserExerciseLocalRepository) {
const localData = userExerciseLocalRepo.getLocalUserActivityData({
activityId: this.activityId,
});
if (localData) {
return this.createFrom(this.activityId, localData.exerciseData);
}
return null;
}
}

View File

@ -0,0 +1,86 @@
import { Exercise } from "./exercise";
export class FillInBlanksQuestion {
constructor(
readonly id: string,
readonly rawQuestion: Map<
string,
{
type: "text" | "blank";
value: string;
}
>,
readonly replies: Map<string, string>
) {}
static fromPure(
id: string,
rawQuestion: Map<
string,
{
type: "text" | "blank";
value: string;
}
>
) {
return new FillInBlanksQuestion(id, rawQuestion, new Map());
}
static from(obj: FillInBlanksQuestion) {
return new FillInBlanksQuestion(obj.id, obj.rawQuestion, obj.replies);
}
get answers(): Map<string, { type: "blank"; value: string }> {
return new Map(
Array.from(this.rawQuestion).filter(
([qKey, question]) => question.type === "blank"
)
) as Map<string, { type: "blank"; value: string }>;
}
toJSON() {
return {
id: this.id,
rawQuestion: Array.from(this.rawQuestion),
replies: Array.from(this.replies),
};
}
}
export class FillInBlanksExercise extends Exercise<FillInBlanksQuestion> {
constructor(
readonly activityId: string,
readonly questions: FillInBlanksQuestion[]
) {
super(activityId, questions);
}
get grade(): number {
let correct = 0;
let total = 0;
this.questions.forEach((question) => {
question.answers.forEach((val, key) => {
const answer = val.value;
if (question.replies.get(key) === answer) correct++;
total++;
});
});
return (correct / total) * 100;
}
get answers() {
return this.questions
.map((question) => question.answers)
.reduce(
(accumulator, current) =>
new Map([...Array.from(accumulator), ...Array.from(current)]),
new Map()
);
}
protected createFrom(activityId: string, questions: FillInBlanksQuestion[]) {
return new FillInBlanksExercise(activityId, questions);
}
}

View File

@ -0,0 +1,49 @@
import { Exercise } from "./exercise";
export class MultipleChoiceQuestion {
constructor(
readonly id: string,
readonly question: string,
readonly choices: [string, string, string, string],
readonly answer: 0 | 1 | 2 | 3,
readonly reply: 0 | 1 | 2 | 3
) {}
static from(obj: MultipleChoiceQuestion) {
return new MultipleChoiceQuestion(
obj.id,
obj.question,
obj.choices,
obj.answer,
obj.reply
);
}
}
export class MultipleChoiceExercise extends Exercise<MultipleChoiceQuestion> {
constructor(
readonly activityId: string,
readonly questions: MultipleChoiceQuestion[]
) {
super(activityId, questions);
}
get grade(): number {
let correct = 0;
let total = 0;
this.questions.forEach((question) => {
if (question.answer === question.reply) correct++;
total++;
});
return (correct / total) * 100;
}
protected createFrom(
activityId: string,
questions: MultipleChoiceQuestion[]
) {
return new MultipleChoiceExercise(activityId, questions);
}
}

View File

@ -0,0 +1,39 @@
import { Exercise } from "./exercise";
export class SimpleQuestion {
constructor(
readonly id: string,
readonly question: string,
readonly answer: string,
readonly reply: string
) {}
static from(obj: SimpleQuestion) {
return new SimpleQuestion(obj.id, obj.question, obj.answer, obj.reply);
}
}
export class SimpleExercise extends Exercise<SimpleQuestion> {
constructor(
readonly activityId: string,
readonly questions: SimpleQuestion[]
) {
super(activityId, questions);
}
get grade(): number {
let correct = 0;
let total = 0;
this.questions.forEach((question) => {
if (question.answer === question.reply) correct++;
total++;
});
return (correct / total) * 100;
}
protected createFrom(activityId: string, questions: SimpleQuestion[]) {
return new SimpleExercise(activityId, questions);
}
}

View File

@ -82,6 +82,12 @@ export function DragIntoBlanksExercise({
dndSetting.getBoardItemContainingTheLocation(
blankKey
);
console.log(
"la",
blankKey,
boardItemEntry,
dndSetting.check(blankKey)
);
const isCorrect = dndSetting.check(blankKey);
return (

View File

@ -0,0 +1,21 @@
import { Item } from "./item";
export class Blank {
constructor(
readonly id: string,
readonly answer: string,
readonly item: Item | null
) {}
static from(obj: Blank) {
return new Blank(obj.id, obj.answer, obj.item);
}
static empty(obj: Blank) {
return new Blank(obj.id, obj.answer, null);
}
static fill(obj: Blank, item: Item) {
return new Blank(obj.id, obj.answer, item);
}
}

View File

@ -0,0 +1,7 @@
export class Item {
constructor(readonly id: string, readonly value: string) {}
static from(obj: Item) {
return new Item(obj.id, obj.value);
}
}

View File

@ -0,0 +1,84 @@
import { useState } from "react";
import { Item } from "./item";
import { Blank } from "./blank";
export function useDndSetting({
boardData,
blanksData,
}: {
boardData: Item[];
blanksData: Blank[];
}) {
const [board, setBoard] = useState<Item[]>(boardData);
const [blanks, setBlanks] = useState<Blank[]>(blanksData);
const [draggedItem, setDraggedItem] = useState<Item | null>(null);
const startDragging = (item: Item) => {
setDraggedItem(item);
};
const stopDragging = (
action: { type: "on-space" } | { type: "on-blank"; blankId: Blank["id"] }
) => {
if (!draggedItem) return;
// <remove dragged item from both board and blanks just in case>
setBlanks((prev) => {
return prev.map((blank) => {
if (blank.item?.id === draggedItem.id) return Blank.empty(blank);
return Blank.from(blank);
});
});
setBoard((prev) => {
return prev.filter((item) => item.id !== draggedItem.id);
});
// </remove dragged item from both board and blanks just in case>
if (action.type === "on-blank") {
const blankIndex = blanks.findIndex(
(blank) => blank.id === action.blankId
);
if (blankIndex === -1) return;
// <remove the predecessor if it exists>
const blankItem = blanks[blankIndex].item;
if (blankItem) {
setBlanks((prev) => {
return prev.map((blank) => {
if (blank.item?.id === blankItem.id) return Blank.empty(blank);
return Blank.from(blank);
});
});
setBoard((prev) => [...prev, Item.from(blankItem)]);
}
// </remove the predecessor if it exists>
// place the successor finally
setBlanks((prev) => {
const newBlanks = [...prev];
newBlanks[blankIndex] = Blank.fill(
newBlanks[blankIndex],
Item.from(draggedItem)
);
return newBlanks;
});
} else if (action.type === "on-space") {
setBoard((prev) => {
return [...prev, Item.from(draggedItem)];
});
}
setDraggedItem(null);
};
return {
setBoard,
board,
setBlanks,
blanks,
setDraggedItem,
draggedItem,
startDragging,
stopDragging,
};
}