Created the InteractiveSpeaking exercise
This commit is contained in:
124
src/components/Solutions/InteractiveSpeaking.tsx
Normal file
124
src/components/Solutions/InteractiveSpeaking.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import {InteractiveSpeakingExercise} from "@/interfaces/exam";
|
||||
import {CommonProps} from ".";
|
||||
import {useEffect, useState} from "react";
|
||||
import Button from "../Low/Button";
|
||||
import dynamic from "next/dynamic";
|
||||
import axios from "axios";
|
||||
import {speakingReverseMarking} from "@/utils/score";
|
||||
|
||||
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
||||
|
||||
export default function InteractiveSpeaking({
|
||||
id,
|
||||
type,
|
||||
title,
|
||||
text,
|
||||
prompts,
|
||||
userSolutions,
|
||||
onNext,
|
||||
onBack,
|
||||
}: InteractiveSpeakingExercise & CommonProps) {
|
||||
const [solutionsURL, setSolutionsURL] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (userSolutions && userSolutions.length > 0) {
|
||||
Promise.all(userSolutions[0].solution.map((x) => axios.post(`/api/speaking`, {path: x.answer}, {responseType: "arraybuffer"}))).then(
|
||||
(values) => {
|
||||
setSolutionsURL(
|
||||
values.map(({data}) => {
|
||||
const blob = new Blob([data], {type: "audio/wav"});
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
return url;
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}, [userSolutions]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col h-full w-full gap-8 mb-20">
|
||||
<div className="flex flex-col w-full gap-8 bg-mti-gray-smoke rounded-xl py-8 pb-12 px-16">
|
||||
<div className="flex flex-col gap-3">
|
||||
<span className="font-semibold">{title}</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<span className="font-bold">You should talk about the following things:</span>
|
||||
<div className="grid grid-cols-3 gap-6 text-center">
|
||||
{prompts.map((x, index) => (
|
||||
<div className="italic flex flex-col gap-2 text-sm" key={index}>
|
||||
<video key={index} controls className="">
|
||||
<source src={x.video_url} />
|
||||
</video>
|
||||
<span>{x.text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full h-full flex flex-col gap-8">
|
||||
<div className="flex items-center gap-8">
|
||||
{solutionsURL.map((x, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="w-full min-w-[460px] p-4 px-8 bg-transparent border-2 border-mti-gray-platinum rounded-2xl flex-col gap-8 items-center">
|
||||
<div className="flex gap-8 items-center justify-center py-8">
|
||||
<Waveform audio={x} waveColor="#FCDDEC" progressColor="#EF5DA8" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{userSolutions && userSolutions.length > 0 && (
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div className="flex gap-4 px-1">
|
||||
{Object.keys(userSolutions[0].evaluation!.task_response).map((key) => (
|
||||
<div className="bg-ielts-speaking text-ielts-speaking-light rounded-xl px-4 py-2" key={key}>
|
||||
{key}: Level {userSolutions[0].evaluation!.task_response[key]}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="w-full h-full min-h-fit cursor-text px-7 py-8 bg-mti-gray-smoke rounded-3xl">
|
||||
{userSolutions[0].evaluation!.comment}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
|
||||
<Button
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
onBack({
|
||||
exercise: id,
|
||||
solutions: userSolutions,
|
||||
score: {total: 100, missing: 0, correct: speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
|
||||
type,
|
||||
})
|
||||
}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
color="purple"
|
||||
onClick={() =>
|
||||
onNext({
|
||||
exercise: id,
|
||||
solutions: userSolutions,
|
||||
score: {total: 100, missing: 0, correct: speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
|
||||
type,
|
||||
})
|
||||
}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user