Reverted Level to only utas placement test exercises, Speaking, bug fixes, placeholder

This commit is contained in:
Carlos-Mesquita
2024-11-10 04:24:23 +00:00
parent c507eae507
commit 322d7905c3
39 changed files with 1251 additions and 279 deletions

View File

@@ -24,6 +24,7 @@ export default function InteractiveSpeaking({
userSolutions,
onNext,
onBack,
preview = false
}: InteractiveSpeakingExercise & CommonProps) {
const [recordingDuration, setRecordingDuration] = useState(0);
const [isRecording, setIsRecording] = useState(false);
@@ -298,9 +299,15 @@ export default function InteractiveSpeaking({
<Button color="purple" variant="outline" isLoading={isLoading} onClick={back} className="max-w-[200px] self-end w-full">
Back
</Button>
<Button color="purple" disabled={!mediaBlob} isLoading={isLoading} onClick={next} className="max-w-[200px] self-end w-full">
{preview ? (
<Button color="purple" isLoading={isLoading} onClick={next} className="max-w-[200px] self-end w-full">
{questionIndex + 1 < prompts.length ? "Next Prompt" : "Submit"}
</Button>
) : (
<Button color="purple" disabled={!mediaBlob} isLoading={isLoading} onClick={next} className="max-w-[200px] self-end w-full">
{questionIndex + 1 < prompts.length ? "Next Prompt" : "Submit"}
</Button>
)}
</div>
</div>
</div>

View File

@@ -1,20 +1,20 @@
import {SpeakingExercise} from "@/interfaces/exam";
import {CommonProps} from ".";
import {Fragment, useEffect, useState} from "react";
import {BsCheckCircleFill, BsMicFill, BsPauseCircle, BsPlayCircle, BsTrashFill} from "react-icons/bs";
import { SpeakingExercise } from "@/interfaces/exam";
import { CommonProps } from ".";
import { Fragment, useEffect, useState } from "react";
import { BsCheckCircleFill, BsMicFill, BsPauseCircle, BsPlayCircle, BsTrashFill } from "react-icons/bs";
import dynamic from "next/dynamic";
import Button from "../Low/Button";
import useExamStore from "@/stores/examStore";
import {downloadBlob} from "@/utils/evaluation";
import { downloadBlob } from "@/utils/evaluation";
import axios from "axios";
import Modal from "../Modal";
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
const Waveform = dynamic(() => import("../Waveform"), { ssr: false });
const ReactMediaRecorder = dynamic(() => import("react-media-recorder").then((mod) => mod.ReactMediaRecorder), {
ssr: false,
});
export default function Speaking({id, title, text, video_url, type, prompts, suffix, userSolutions, onNext, onBack}: SpeakingExercise & CommonProps) {
export default function Speaking({ id, title, text, video_url, type, prompts, suffix, userSolutions, onNext, onBack, preview = false }: SpeakingExercise & CommonProps) {
const [recordingDuration, setRecordingDuration] = useState(0);
const [isRecording, setIsRecording] = useState(false);
const [mediaBlob, setMediaBlob] = useState<string>();
@@ -28,7 +28,7 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
const saveToStorage = async () => {
if (mediaBlob && mediaBlob.startsWith("blob")) {
const blobBuffer = await downloadBlob(mediaBlob);
const audioFile = new File([blobBuffer], "audio.wav", {type: "audio/wav"});
const audioFile = new File([blobBuffer], "audio.wav", { type: "audio/wav" });
const seed = Math.random().toString().replace("0.", "");
@@ -42,8 +42,8 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
},
};
const response = await axios.post<{path: string}>("/api/storage/insert", formData, config);
if (audioURL) await axios.post("/api/storage/delete", {path: audioURL});
const response = await axios.post<{ path: string }>("/api/storage/insert", formData, config);
if (audioURL) await axios.post("/api/storage/delete", { path: audioURL });
return response.data.path;
}
@@ -52,7 +52,7 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
useEffect(() => {
if (userSolutions.length > 0) {
const {solution} = userSolutions[0] as {solution?: string};
const { solution } = userSolutions[0] as { solution?: string };
if (solution && !mediaBlob) setMediaBlob(solution);
if (solution && !solution.startsWith("blob")) setAudioURL(solution);
}
@@ -79,8 +79,8 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
const next = async () => {
onNext({
exercise: id,
solutions: mediaBlob ? [{id, solution: mediaBlob}] : [],
score: {correct: 0, total: 100, missing: 0},
solutions: mediaBlob ? [{ id, solution: mediaBlob }] : [],
score: { correct: 0, total: 100, missing: 0 },
type,
});
};
@@ -88,8 +88,8 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
const back = async () => {
onBack({
exercise: id,
solutions: mediaBlob ? [{id, solution: mediaBlob}] : [],
score: {correct: 0, total: 100, missing: 0},
solutions: mediaBlob ? [{ id, solution: mediaBlob }] : [],
score: { correct: 0, total: 100, missing: 0 },
type,
});
};
@@ -115,6 +115,8 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
}
};
console.log(preview);
return (
<div className="flex flex-col gap-4 mt-4 w-full">
<div className="flex justify-between w-full gap-8">
@@ -189,7 +191,7 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
<ReactMediaRecorder
audio
onStop={(blob) => setMediaBlob(blob)}
render={({status, startRecording, stopRecording, pauseRecording, resumeRecording, clearBlobUrl, mediaBlobUrl}) => (
render={({ status, startRecording, stopRecording, pauseRecording, resumeRecording, clearBlobUrl, mediaBlobUrl }) => (
<div className="w-full p-4 px-8 bg-transparent border-2 border-mti-gray-platinum rounded-2xl flex-col gap-8 items-center">
<p className="text-base font-normal">Record your answer:</p>
<div className="flex gap-8 items-center justify-center py-8">
@@ -307,9 +309,15 @@ export default function Speaking({id, title, text, video_url, type, prompts, suf
<Button color="purple" variant="outline" isLoading={isLoading} onClick={back} className="max-w-[200px] self-end w-full">
Back
</Button>
<Button color="purple" isLoading={isLoading} disabled={!mediaBlob} onClick={next} className="max-w-[200px] self-end w-full">
Next
</Button>
{preview ? (
<Button color="purple" isLoading={isLoading} onClick={next} className="max-w-[200px] self-end w-full">
Next
</Button>
) : (
<Button color="purple" isLoading={isLoading} disabled={!mediaBlob} onClick={next} className="max-w-[200px] self-end w-full">
Next
</Button>
)}
</div>
</div>
</div>