some buggy parts of the exercises fixed.

This commit is contained in:
Hikmet 2023-07-23 10:40:49 +03:00
parent f1a1c7cdda
commit 89cca4620a
22 changed files with 69 additions and 95 deletions

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { DragIntoBlanksExercise } from "./drag_into_blanks_exercise";
import { Layout } from "./layout";
import { MultipleChoiceExercise } from "./multiple_choice_exercise";
@ -13,7 +13,13 @@ import {
TrueFalseQuestion,
} from "@/core/models/entities/question";
export function Activity({ activity }: { activity: IActivity<any> }) {
export function Activity({
activity,
closeActivity,
}: {
activity: IActivity<any>;
closeActivity: VoidFunction;
}) {
const {
title,
textContent,
@ -24,16 +30,16 @@ export function Activity({ activity }: { activity: IActivity<any> }) {
activityType,
questions,
} = activity;
const [isFormLocked, setIsFormLocked] = useState(false);
const [replies, setReplies] = useState<any[]>(
new Array(questions.length).fill(undefined)
);
const [replies, setReplies] = useState<any[]>([]);
useEffect(() => setReplies([]), [activityType]);
const handleFinishClick = () => {
setIsFormLocked(true);
};
const handleReattemptClick = () => {
setReplies(new Array(questions.length).fill(undefined));
setReplies([]);
setIsFormLocked(false);
};
@ -48,6 +54,7 @@ export function Activity({ activity }: { activity: IActivity<any> }) {
isFormLocked={isFormLocked}
handleReattemptClick={handleReattemptClick}
handleFinishClick={handleFinishClick}
closeActivity={closeActivity}
>
{activityType === "true-false" ? (
<TrueFalseExercise

View File

@ -15,6 +15,7 @@ export function Layout({
handleFinishClick,
isFormLocked,
handleReattemptClick,
closeActivity,
}: {
children: ReactNode;
title: Activity<any>["title"];
@ -24,8 +25,9 @@ export function Layout({
image: Activity<any>["image"];
youtubeVideoUrl: Activity<any>["youtubeVideoUrl"];
isFormLocked: boolean;
handleReattemptClick: () => void;
handleFinishClick: () => void;
handleReattemptClick: VoidFunction;
handleFinishClick: VoidFunction;
closeActivity: VoidFunction;
}) {
return (
<section className={styles["container"]} aria-label="aktivite">
@ -79,7 +81,7 @@ export function Layout({
<button className="simple" onClick={handleReattemptClick}>
Tekrar Çöz
</button>
<button className="simple" onClick={() => {}}>
<button className="simple" onClick={closeActivity}>
Bitir
</button>
</div>

View File

@ -1,17 +1,17 @@
import { MultipleChoiceQuestion } from "@/core/models/entities/question";
import styles from "./styles.module.scss";
import { Dispatch, SetStateAction } from "react";
import { Dispatch, SetStateAction, useState } from "react";
export function MultipleChoiceExercise({
replies,
setReplies,
isFormLocked,
exercise,
replies,
setReplies,
}: {
replies: number[];
setReplies: Dispatch<SetStateAction<number[]>>;
isFormLocked: boolean;
exercise: MultipleChoiceQuestion[];
replies: number[];
setReplies: Dispatch<SetStateAction<number[]>>;
}) {
return (
<ol className={`simple multiple-choice`}>
@ -36,13 +36,14 @@ export function MultipleChoiceExercise({
<div key={`${choice}-${i}`} className={"choice"}>
<input
disabled={isFormLocked}
onClick={() =>
onChange={() =>
setReplies((prev) => {
const newReplies = [...prev];
newReplies[index] = i;
return newReplies;
})
}
checked={replies[index] === i}
type="radio"
id={`choice-${index}-${i}`}
name={`choice-${index}`}

View File

@ -1,17 +1,17 @@
import styles from "./styles.module.scss";
import { Dispatch, SetStateAction } from "react";
import { Dispatch, SetStateAction, useState } from "react";
import { TrueFalseQuestion } from "@/core/models/entities/question";
export function TrueFalseExercise({
replies,
setReplies,
exercise,
isFormLocked,
replies,
setReplies,
}: {
replies: boolean[];
setReplies: Dispatch<SetStateAction<boolean[]>>;
isFormLocked: boolean;
exercise: TrueFalseQuestion[];
replies: boolean[];
setReplies: Dispatch<SetStateAction<boolean[]>>;
}) {
return (
<section
@ -45,13 +45,13 @@ export function TrueFalseExercise({
name={`true-false-${i}`}
disabled={isFormLocked}
checked={reply === true}
onClick={() =>
onChange={() => {
setReplies((prev) => {
const newReplies = [...prev];
newReplies[i] = true;
return newReplies;
})
}
});
}}
/>
</div>
<div className={styles["radio-button"]}>
@ -60,13 +60,13 @@ export function TrueFalseExercise({
name={`true-false-${i}`}
disabled={isFormLocked}
checked={reply === false}
onClick={() =>
onChange={() => {
setReplies((prev) => {
const newReplies = [...prev];
newReplies[i] = false;
return newReplies;
})
}
});
}}
/>
</div>
</div>

View File

@ -1,6 +1,4 @@
import { IViewModel } from "@/features/activity_editor/model/view_model";
import styles from "./styles.module.scss";
import { Dispatch, SetStateAction, useRef, useState } from "react";
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
import { FillInBlanksQuestion } from "@/core/models/entities/question";
export function TypeInBlanksExercise({
@ -9,8 +7,8 @@ export function TypeInBlanksExercise({
isFormLocked,
exercise,
}: {
replies: { [index: number]: string }[];
setReplies: Dispatch<SetStateAction<{ [index: number]: string }[]>>;
replies: Map<string, string>[];
setReplies: Dispatch<SetStateAction<Map<string, string>[]>>;
isFormLocked: boolean;
exercise: FillInBlanksQuestion[];
}) {
@ -25,7 +23,10 @@ export function TypeInBlanksExercise({
return <p key={pieceKey}>{pieceValue}</p>;
}
const reply = replies[index][i];
const replyMap = replies[index] as
| Map<string, string>
| undefined;
const reply = replyMap?.get(pieceKey);
const isCorrect =
reply !== undefined && reply !== null
? item.check(pieceKey, reply)
@ -34,16 +35,21 @@ export function TypeInBlanksExercise({
return (
<input
type="text"
style={{ width: "10rem" }}
className={`basic ${
isFormLocked ? (isCorrect ? "success" : "error") : ""
}`}
key={pieceKey}
disabled={isFormLocked}
value={replies[index][i]}
value={replyMap?.get(pieceKey) ?? ""}
onChange={(e) => {
setReplies((prev) => {
const newReplies = [...prev];
newReplies[index][i] = e.target.value;
const newReplyMap = new Map(
newReplies[index] ?? new Map()
);
newReplyMap.set(pieceKey, e.target.value);
newReplies[index] = newReplyMap;
return newReplies;
});
}}

View File

@ -2,10 +2,10 @@ import { Paper } from "@mui/material";
import TrueOrFalseExercise from "./true_or_false_exercise";
import FillOrDragExercise from "./type_or_drag_exercise";
import useViewModelContext from "@/features/activity_editor/view_model";
import { MultipleChoiceExerciseForm } from "../multiple_choice_exercise_form";
import { PairTextsWithImagesExerciseForm } from "../pair_texts_with_images_exercise_form";
import { MultipleChoiceExerciseForm } from "./multiple_choice_exercise_form";
import { PairTextsWithImagesExerciseForm } from "./pair_texts_with_images_exercise_form";
export default function Activity() {
export default function ExerciseEditor() {
const { activityType } = useViewModelContext()!;
return (

View File

@ -6,12 +6,12 @@ import {
PhotoLibraryOutlined,
} from "@mui/icons-material";
import { useState } from "react";
import useViewModelContext from "@/features/activity_editor/view_model";
import { nanoid } from "nanoid";
import { SimpleQuestion } from "@/core/models/entities/question";
import { Fab } from "@mui/material";
import { AltEditDialog } from "@/features/edit_dialog/index.alt";
import { Testable } from "@/core/models/entities/testable";
import useViewModelContext from "@/features/activity_editor/view_model";
interface ImageCard {
question: string;

View File

@ -1,12 +1,12 @@
import { FormControl, InputLabel, MenuItem, Select } from "@mui/material";
import styles from "../styles.module.scss";
import useViewModelContext from "../../view_model";
import Activity from "./activity";
import { Activity as IActivity } from "@/core/models/entities/learning_unit";
import { MediaTester } from "@/core/components/media_tester";
import YouTube from "react-youtube";
import { NextImageContainer } from "@/core/components/next_image_container";
import getYouTubeID from "get-youtube-id";
import ExerciseEditor from "./exercise_editor";
const activityTypeMap = {
"true-false": "Doğru yanlış",
@ -155,7 +155,7 @@ export default function EditorForm() {
placeholder="ses.mp3"
/>
</section>
<Activity />
<ExerciseEditor />
</div>
);
}

View File

@ -5,10 +5,7 @@ import { Activity } from "@/features/activity";
import useViewModelContext from "../view_model";
import { useMemo } from "react";
import { Activity as IActivity } from "@/core/models/entities/learning_unit";
import {
FillInBlanksQuestion,
TrueFalseQuestion,
} from "@/core/models/entities/question";
import { FillInBlanksQuestion } from "@/core/models/entities/question";
import { ExerciseConverter } from "../services/exercise_converter";
export default function View() {
@ -79,7 +76,7 @@ export default function View() {
<div className={styles["content"]}>
<EditorForm />
<div className={styles["simple-container"]}>
<Activity activity={activity} />
<Activity closeActivity={() => {}} activity={activity} />
</div>
</div>
</div>

View File

@ -4,7 +4,6 @@ import { Dispatch, SetStateAction, useEffect, useState } from "react";
import {
DeleteOutline,
DesignServices,
RssFeed,
WarningAmber,
} from "@mui/icons-material";
import { useAdminViewModelContext } from "../theme_page/view_model/context_providers/admin_view_model";
@ -24,8 +23,7 @@ export function ThemeSideBar({
// context state
const { themeTitle, themeExplanation, themeImage, themeYoutubeVideoUrl } =
useBaseViewModelContext()!;
const { saveTheme, deleteTheme, publishChanges } =
useAdminViewModelContext()!;
const { saveTheme, deleteTheme } = useAdminViewModelContext()!;
// component state
const [modified, setModified] = useState(false);
@ -98,10 +96,6 @@ export function ThemeSideBar({
>
<header>
<h3>Tema Editörü</h3>
<button onClick={publishChanges} className="simple">
<span>Değişiklikleri Yayınla</span>
<RssFeed />
</button>
</header>
<div className={"main"}>
{modified && (

View File

@ -14,7 +14,7 @@ export function AppBar({ home }: { home: "/admin" | "/" }) {
<img src="/header-logo.png" alt="" />
</Link>
<nav>
<a className="simple" href="#">
<a className="simple" href={`${home}#temalar`}>
Temalar
</a>
<a

View File

@ -13,7 +13,7 @@ export function ThemesSection({
createNewThemeButton?: ReactNode;
}) {
return (
<article className={styles["themes"]}>
<article id="temalar" className={styles["themes"]}>
<div>
<h4>Temel Lazca</h4>
<section aria-label="temalar">

View File

@ -37,5 +37,4 @@ export interface AdminViewModel {
youtubeVideoUrl: string;
}) => Promise<void>;
deleteTheme: () => Promise<void>;
publishChanges: () => Promise<void>;
}

View File

@ -21,7 +21,9 @@ export default function ActivityDialog({
maxWidth="md"
scroll="body"
>
{activeActivity && <Activity activity={activeActivity} />}
{activeActivity && (
<Activity closeActivity={closeActivity} activity={activeActivity} />
)}
</Dialog>
);
}

View File

@ -10,7 +10,9 @@ import { TabBar } from "./tab_bar";
import { ReactNode } from "react";
import dynamic from "next/dynamic";
const ActivityDialog = dynamic(() => import("./activity_dialog"));
const ActivityDialog = dynamic(() => import("./activity_dialog"), {
ssr: false,
});
export function View({
home,

View File

@ -322,34 +322,6 @@ export function useAdminViewModel(): AdminViewModel {
});
};
const publishChanges = async () => {
setStalling(true);
const resObj = await fetch(`/api/admin/temalar/${themeId}`, {
method: "POST",
body: JSON.stringify({ type: "publishChanges" }),
headers: {
"Content-Type": "application/json",
},
});
const res = (await resObj.json()) as StatusResponse;
setStalling(false);
if (res.status === "error") {
setSnackbar({
severity: res.status,
message: res.message,
visible: true,
});
return;
}
setSnackbar({
severity: res.status,
message: res.message,
visible: true,
});
};
return {
stalling,
snackbar,
@ -364,6 +336,5 @@ export function useAdminViewModel(): AdminViewModel {
// theme actions
saveTheme,
deleteTheme,
publishChanges,
};
}

View File

@ -4,18 +4,14 @@ import { Theme } from "@/core/models/entities/learning_unit";
import TP from "@/features/theme_page";
export default function ThemePage({ themeData }: { themeData: Theme }) {
console.debug("ThemePage---", Date.now());
return <TP home="/" theme={Theme.from(themeData)} />;
}
export async function getStaticProps(context: GetServerSidePropsContext) {
console.debug("getStaticProps---", Date.now());
console.log("/temalar/[theme] -> getStaticProps");
const path = context.params as unknown as { theme: string };
const themeRepository = new ThemeReposityImplementation();
console.debug("getStaticProps-1--", Date.now());
const themeData = await themeRepository.getThemeData(path.theme);
console.debug("getStaticProps-2--", Date.now());
return {
props: {
@ -26,11 +22,8 @@ export async function getStaticProps(context: GetServerSidePropsContext) {
}
export async function getStaticPaths() {
console.debug("getStaticPaths---", Date.now());
const themeRepository = new ThemeReposityImplementation();
console.debug("getStaticPaths-1--", Date.now());
const result = await themeRepository.getThemeIds();
console.debug("getStaticPaths-2--", Date.now());
if (result.status === "success" && result.data) {
const themePaths = result.data.map((item) => ({ params: { theme: item } }));