Ts changes weren't staged, it compiles still doesnt build building
This commit is contained in:
@@ -78,6 +78,7 @@ export const UnderlineQuestion: React.FC<UnderlineQuestionProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
validateQuestion(question);
|
validateQuestion(question);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [question]);
|
}, [question]);
|
||||||
|
|
||||||
const handlePromptChange = (value: string) => {
|
const handlePromptChange = (value: string) => {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const useSectionEdit = ({
|
|||||||
|
|
||||||
const handleEdit = useCallback(() => {
|
const handleEdit = useCallback(() => {
|
||||||
setEditing(true);
|
setEditing(true);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [sectionId, setEditing, updateRoot]);
|
}, [sectionId, setEditing, updateRoot]);
|
||||||
|
|
||||||
const handleSave = useCallback(() => {
|
const handleSave = useCallback(() => {
|
||||||
@@ -41,17 +42,20 @@ const useSectionEdit = ({
|
|||||||
setEditing(false);
|
setEditing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [setEditing, updateRoot, onSave, sectionId]);
|
}, [setEditing, updateRoot, onSave, sectionId]);
|
||||||
|
|
||||||
const handleDiscard = useCallback(() => {
|
const handleDiscard = useCallback(() => {
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
onDiscard?.();
|
onDiscard?.();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [setEditing, updateRoot, onDiscard, sectionId]);
|
}, [setEditing, updateRoot, onDiscard, sectionId]);
|
||||||
|
|
||||||
const modeHandle = useCallback(() => {
|
const modeHandle = useCallback(() => {
|
||||||
setEditing(!editing);
|
setEditing(!editing);
|
||||||
onMode?.();
|
onMode?.();
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [setEditing, editing, updateRoot, onMode, sectionId]);
|
}, [setEditing, editing, updateRoot, onMode, sectionId]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ReadingPart } from '@/interfaces/exam';
|
|||||||
import { defaultSectionSettings } from '@/stores/examEditor/defaults';
|
import { defaultSectionSettings } from '@/stores/examEditor/defaults';
|
||||||
|
|
||||||
const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
|
const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
|
||||||
const {currentModule, dispatch} = useExamEditorStore();
|
const { currentModule, dispatch } = useExamEditorStore();
|
||||||
|
|
||||||
const examInputRef = useRef<HTMLInputElement>(null);
|
const examInputRef = useRef<HTMLInputElement>(null);
|
||||||
const solutionsInputRef = useRef<HTMLInputElement>(null);
|
const solutionsInputRef = useRef<HTMLInputElement>(null);
|
||||||
@@ -38,14 +38,14 @@ const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImport = useCallback( async () => {
|
const handleImport = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
if (!examFile) {
|
if (!examFile) {
|
||||||
toast.error('Exam file is required');
|
toast.error('Exam file is required');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({type: "UPDATE_MODULE", payload: {updates: {importing: true}, module}})
|
dispatch({ type: "UPDATE_MODULE", payload: { updates: { importing: true }, module } })
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('exercises', examFile);
|
formData.append('exercises', examFile);
|
||||||
@@ -76,7 +76,8 @@ const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
|
|||||||
const newSectionsStates = data.parts.map(
|
const newSectionsStates = data.parts.map(
|
||||||
(part: ReadingPart, index: number) => defaultSectionSettings(module, index + 1, part)
|
(part: ReadingPart, index: number) => defaultSectionSettings(module, index + 1, part)
|
||||||
);
|
);
|
||||||
dispatch({type: "UPDATE_MODULE", payload: {
|
dispatch({
|
||||||
|
type: "UPDATE_MODULE", payload: {
|
||||||
updates: {
|
updates: {
|
||||||
sections: newSectionsStates,
|
sections: newSectionsStates,
|
||||||
minTimer: data.minTimer,
|
minTimer: data.minTimer,
|
||||||
@@ -84,19 +85,21 @@ const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
|
|||||||
importing: false,
|
importing: false,
|
||||||
},
|
},
|
||||||
module
|
module
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(`An unknown error has occured while import ${module} exam!`);
|
toast.error(`An unknown error has occured while import ${module} exam!`);
|
||||||
} finally {
|
} finally {
|
||||||
dispatch({type: "UPDATE_MODULE", payload: {updates: {importing: false}, module}})
|
dispatch({ type: "UPDATE_MODULE", payload: { updates: { importing: false }, module } })
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [
|
}, [
|
||||||
examFile,
|
examFile,
|
||||||
solutionsFile,
|
solutionsFile,
|
||||||
dispatch,
|
dispatch,
|
||||||
module
|
currentModule
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { capitalize } from "lodash";
|
|||||||
import { Difficulty } from "@/interfaces/exam";
|
import { Difficulty } from "@/interfaces/exam";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { ModuleState } from "@/stores/examEditor/types";
|
import { ModuleState, SectionState } from "@/stores/examEditor/types";
|
||||||
import { Module } from "@/interfaces";
|
import { Module } from "@/interfaces";
|
||||||
import useExamEditorStore from "@/stores/examEditor";
|
import useExamEditorStore from "@/stores/examEditor";
|
||||||
import WritingSettings from "./SettingsEditor/writing";
|
import WritingSettings from "./SettingsEditor/writing";
|
||||||
@@ -38,8 +38,8 @@ const ExamEditor: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentSections = sections;
|
const currentSections = sections;
|
||||||
const currentLabels = sectionLabels;
|
const currentLabels = sectionLabels;
|
||||||
let updatedSections;
|
let updatedSections: SectionState[];
|
||||||
let updatedLabels;
|
let updatedLabels: any;
|
||||||
|
|
||||||
if (numberOfParts > currentSections.length) {
|
if (numberOfParts > currentSections.length) {
|
||||||
const newSections = [...currentSections];
|
const newSections = [...currentSections];
|
||||||
@@ -76,6 +76,7 @@ const ExamEditor: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [numberOfParts]);
|
}, [numberOfParts]);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export default function TrueFalseSolution({prompt, type, id, questions, userSolu
|
|||||||
{userSolutions &&
|
{userSolutions &&
|
||||||
questions.map((question, index) => {
|
questions.map((question, index) => {
|
||||||
const userSolution = userSolutions.find((x) => x.id === question.id.toString());
|
const userSolution = userSolutions.find((x) => x.id === question.id.toString());
|
||||||
const solution = question.solution.toString().toLowerCase() as Solution;
|
const solution = question?.solution?.toString().toLowerCase() as Solution;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={question.id.toString()} className="flex flex-col gap-4">
|
<div key={question.id.toString()} className="flex flex-col gap-4">
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ interface Props {
|
|||||||
|
|
||||||
const UserDisplay = (displayUser: User) => (
|
const UserDisplay = (displayUser: User) => (
|
||||||
<div className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300">
|
<div className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300">
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img src={displayUser.profilePicture} alt={displayUser.name} className="rounded-full w-10 h-10" />
|
<img src={displayUser.profilePicture} alt={displayUser.name} className="rounded-full w-10 h-10" />
|
||||||
<div className="flex flex-col gap-1 items-start">
|
<div className="flex flex-col gap-1 items-start">
|
||||||
<span>{displayUser.name}</span>
|
<span>{displayUser.name}</span>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
FilterFn,
|
FilterFn,
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
import { UserImport } from "./IUserImport";
|
import { UserImport } from "../interfaces/IUserImport";
|
||||||
|
|
||||||
const globalFilterFn: FilterFn<any> = (row, columnId, filterValue: string) => {
|
const globalFilterFn: FilterFn<any> = (row, columnId, filterValue: string) => {
|
||||||
const value = row.getValue(columnId);
|
const value = row.getValue(columnId);
|
||||||
@@ -198,23 +198,27 @@ export default function Listening({ exam, showSolutions = false, preview = false
|
|||||||
|
|
||||||
const renderAudioPlayer = () => (
|
const renderAudioPlayer = () => (
|
||||||
<div className="flex flex-col gap-8 w-full bg-mti-gray-seasalt rounded-xl py-8 px-16">
|
<div className="flex flex-col gap-8 w-full bg-mti-gray-seasalt rounded-xl py-8 px-16">
|
||||||
{exam.parts[partIndex].audio ? (
|
{exam?.parts[partIndex]?.audio?.source ? (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col w-full gap-2">
|
<div className="flex flex-col w-full gap-2">
|
||||||
<h4 className="text-xl font-semibold">Please listen to the following audio attentively.</h4>
|
<h4 className="text-xl font-semibold">Please listen to the following audio attentively.</h4>
|
||||||
<span className="text-base">
|
<span className="text-base">
|
||||||
{exam.parts[partIndex].audio.repeatableTimes > 0
|
{(() => {
|
||||||
? `You will only be allowed to listen to the audio ${exam.parts[partIndex].audio.repeatableTimes - timesListened} time(s).`
|
const audioRepeatTimes = exam?.parts[partIndex]?.audio?.repeatableTimes;
|
||||||
: "You may listen to the audio as many times as you would like."}
|
return audioRepeatTimes && audioRepeatTimes > 0
|
||||||
|
? `You will only be allowed to listen to the audio ${audioRepeatTimes - timesListened} time(s).`
|
||||||
|
: "You may listen to the audio as many times as you would like.";
|
||||||
|
})()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl flex flex-col gap-4 items-center w-full h-fit">
|
<div className="rounded-xl flex flex-col gap-4 items-center w-full h-fit">
|
||||||
<AudioPlayer
|
<AudioPlayer
|
||||||
key={partIndex}
|
key={partIndex}
|
||||||
src={exam.parts[partIndex].audio.source}
|
src={exam?.parts[partIndex]?.audio?.source ?? ''}
|
||||||
color="listening"
|
color="listening"
|
||||||
onEnd={() => setTimesListened((prev) => prev + 1)}
|
onEnd={() => setTimesListened((prev) => prev + 1)}
|
||||||
disabled={timesListened === exam.parts[partIndex].audio.repeatableTimes}
|
disabled={exam?.parts[partIndex]?.audio?.repeatableTimes != null &&
|
||||||
|
timesListened === exam.parts[partIndex]?.audio?.repeatableTimes}
|
||||||
disablePause
|
disablePause
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default function Writing({ exam, showSolutions = false, preview = false,
|
|||||||
const {
|
const {
|
||||||
userSolutions,
|
userSolutions,
|
||||||
exerciseIndex,
|
exerciseIndex,
|
||||||
|
hasExamEnded,
|
||||||
setBgColor,
|
setBgColor,
|
||||||
setUserSolutions,
|
setUserSolutions,
|
||||||
setHasExamEnded,
|
setHasExamEnded,
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import ReactDatePicker from "react-datepicker";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import countryCodes from "country-codes-list";
|
import countryCodes from "country-codes-list";
|
||||||
import { User, Type as UserType } from "@/interfaces/user";
|
import { User, Type as UserType } from "@/interfaces/user";
|
||||||
import { Type, UserImport } from "./IUserImport";
|
import { Type, UserImport } from "../../../interfaces/IUserImport";
|
||||||
import UserTable from "./UserTable";
|
import UserTable from "../../../components/UserTable";
|
||||||
import { EntityWithRoles } from "@/interfaces/entity";
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
import Select from "@/components/Low/Select";
|
import Select from "@/components/Low/Select";
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import Modal from "@/components/Modal";
|
|||||||
import {checkAccess} from "@/utils/permissions";
|
import {checkAccess} from "@/utils/permissions";
|
||||||
import useGroups from "@/hooks/useGroups";
|
import useGroups from "@/hooks/useGroups";
|
||||||
import Button from "@/components/Low/Button";
|
import Button from "@/components/Low/Button";
|
||||||
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
|
|
||||||
const searchFields = [["module"], ["id"], ["createdBy"]];
|
const searchFields = [["module"], ["id"], ["createdBy"]];
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ const ExamOwnerSelector = ({options, exam, onSave}: {options: User[]; exam: Exam
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ExamList({user}: {user: User}) {
|
export default function ExamList({user, entities}: {user: User; entities: EntityWithRoles[];}) {
|
||||||
const [selectedExam, setSelectedExam] = useState<Exam>();
|
const [selectedExam, setSelectedExam] = useState<Exam>();
|
||||||
|
|
||||||
const {exams, reload} = useExams();
|
const {exams, reload} = useExams();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ async function get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
queryParams.delete('module');
|
queryParams.delete('module');
|
||||||
|
|
||||||
const result = await axios.get(`${process.env.BACKEND_URL}/${endpoint}${queryParams.size > 0 ? `?${queryParams.toString()}` : ""}`, {
|
const result = await axios.get(`${process.env.BACKEND_URL}/${endpoint}${Array.from(queryParams.entries()).length > 0 ? `?${queryParams.toString()}` : ""}`, {
|
||||||
headers: { Authorization: `Bearer ${process.env.BACKEND_JWT}` },
|
headers: { Authorization: `Bearer ${process.env.BACKEND_JWT}` },
|
||||||
});
|
});
|
||||||
res.status(200).json(result.data);
|
res.status(200).json(result.data);
|
||||||
|
|||||||
Reference in New Issue
Block a user