[+] Finalize

This commit is contained in:
2023-12-06 06:46:40 -05:00
parent 1574fcce0c
commit 2da4bb213e
9 changed files with 107 additions and 98 deletions
@@ -17,6 +17,7 @@ export default function VerbalPronunciationExercise({q, chapter, onSubmit}: Verb
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [correct, setCorrect] = useState(""); const [correct, setCorrect] = useState("");
const [reason, setReason] = useState(""); const [reason, setReason] = useState("");
const [userAnswer, setUserAnswer] = useState("");
const handleSubmit = () => { const handleSubmit = () => {
if (answered) { if (answered) {
@@ -46,7 +47,8 @@ export default function VerbalPronunciationExercise({q, chapter, onSubmit}: Verb
const audioFile = new File([blob], "audio.wav", { type: 'audio/wav' }); const audioFile = new File([blob], "audio.wav", { type: 'audio/wav' });
const text = await speechToText(audioFile); const text = await speechToText(audioFile);
const aiMark = await getAIMarking(q.question, text.toLowerCase(), "", chapter, language); setUserAnswer(text);
const aiMark = await getAIMarking(`Please pronounce the following: ${q.question}`, text.toLowerCase(), "", chapter, language);
setAnswered(true); setAnswered(true);
setCorrect(aiMark.correct); setCorrect(aiMark.correct);
setReason(aiMark.reason); setReason(aiMark.reason);
@@ -73,14 +75,14 @@ export default function VerbalPronunciationExercise({q, chapter, onSubmit}: Verb
<div className='flex backdrop:flex-row justify-center w-full'> <div className='flex backdrop:flex-row justify-center w-full'>
<Icon icon="mdi:microphone" className="microphone h-20 w-20 mx-auto"/> <Icon icon="mdi:microphone" className="microphone h-20 w-20 mx-auto"/>
<button className={`record-btn mx-auto ${isRecording ? 'red' : ''}`} onClick={handleRecord}> <button className={`record-btn mx-auto ${isRecording ? 'red' : ''}`} onClick={handleRecord}>
{isRecording ? 'Stop Recording' {isRecording ? 'Stop Recording'
: loading ? : loading ?
<ClipLoader <ClipLoader
color="white" color="white"
loading={loading} loading={loading}
aria-label="Loading Spinner" aria-label="Loading Spinner"
data-testid="loader" data-testid="loader"
/> : /> :
'Record'} 'Record'}
</button> </button>
</div> </div>
@@ -88,24 +90,25 @@ export default function VerbalPronunciationExercise({q, chapter, onSubmit}: Verb
) )
} else { } else {
return ( return (
<div className=' flex-row flex-wrap w-full'> <div className='flex flex-wrap w-full gap-5'>
<h3>{correct}</h3> <div className="font-bold">{correct ? "Correct!" : "Incorrect"}</div>
<p>{reason}</p> <div>{reason}</div>
<button className='record-btn w-full bottom-0 relative' onClick={(e) => handleSubmit()}>Continue</button> <button className='green w-full' onClick={() => handleSubmit()}>{!answered ? "Submit" : "Continue"}</button>
</div> {answered && !correct && <button className='red w-full' onClick={() => handleSubmit()}>I was right</button>}
</div>
) )
} }
} }
return ( return <div className="v-layout flex justify-center h-full">
<div> <div className="font-bold">Say the following</div>
<div className="v-layout page-pad flex justify-center"> <div className='box'>
<h1 className="text-center">Say the following</h1> {q.question}
<div className='round box h-min no-shadow relative min-h-[60px] flex items-center justify-center'>
{q.question}
</div>
{ResponseSection(correct, reason)}
</div>
</div> </div>
) {userAnswer && <div className='flex items-center gap-3'>
<Icon icon="mdi:microphone"/> {userAnswer}
</div>}
<div className="flex-1"></div>
{ResponseSection(correct, reason)}
</div>
} }
@@ -52,41 +52,40 @@ export default function VerbalQuestionsExercise({q, chapter, onSubmit}: VerbalQu
} }
const ResponseSection = (correct: string | null, reason: string | null) => { const ResponseSection = (correct: string | null, reason: string | null) => {
if (!answered) { if (!answered) {
return ( return (
<div className='w-full h-32'> <div className='w-full h-36'>
<div className=' flex-row flex-wrap w-full h-full'> <div className=' flex-row flex-wrap w-full h-full'>
{remainingWords.map((word, index) => ( {remainingWords.map((word, index) => (
<span <span
key={index} key={index}
className="border-gray-300 border-2 m-1 p-1 px-3 rounded-xl inline-block cursor-pointer" className="border-gray-300 border-2 m-1 p-1 px-3 rounded-xl inline-block cursor-pointer"
onClick={(event) => handleWordBankClick(word)}> onClick={() => handleWordBankClick(word)}>
{word} {word}
</span> </span>
))} ))}
</div> </div>
<button className='green' onClick={(e) => handleSubmit()}> <button className='green' onClick={() => handleSubmit()}>
{loading ? <ClipLoader {loading ? <ClipLoader
color="white" color="white"
loading={loading} loading={loading}
aria-label="Loading Spinner" aria-label="Loading Spinner"
data-testid="loader" data-testid="loader"
/> : !answered ? "Submit" : "Continue"} /> : !answered ? "Submit" : "Continue"}
</button> </button>
</div> </div>
) )
} else { } else {
return ( return <div className='flex flex-wrap w-full gap-5'>
<div className=' flex-row flex-wrap border-b-4 w-full h-36'> <div className="font-bold">{correct ? "Correct!" : "Incorrect"}</div>
<h3>{correct}</h3> <div>{reason}</div>
<p>{reason}</p> <button className='green w-full' onClick={() => handleSubmit()}>{!answered ? "Submit" : "Continue"}</button>
<button className='green w-full' onClick={(e) => handleSubmit()}>{!answered ? "Submit" : "Continue"}</button> {answered && !correct && <button className='red w-full' onClick={() => handleSubmit()}>I was right</button>}
</div> </div>
)
}
} }
}
return ( return (
<div className='v-layout space-y-8 items-center w-full'> <div className='v-layout space-y-8 items-center w-full'>
+7 -5
View File
@@ -43,11 +43,12 @@ export default function VideoExercise({q, chapter, onSubmit}: VideoQuestionProps
} }
return ( return (
<div className='v-layout space-y-8 items-center w-full'> <div className='v-layout w-full h-full non-center'>
<div className="box"> <div className="box">
{q.question} {q.question}
</div> </div>
<video src={q.clipUrl} controls className='video-player'></video> <video src={q.clipUrl} controls className='video-player'></video>
<div className="flex-1"></div>
<div className='flex-col w-full'> <div className='flex-col w-full'>
{!answered ? {!answered ?
<div className="v-layout"> <div className="v-layout">
@@ -57,10 +58,11 @@ export default function VideoExercise({q, chapter, onSubmit}: VideoQuestionProps
{loading ? <ClipLoader color="white" loading={loading} /> : "Submit"} {loading ? <ClipLoader color="white" loading={loading} /> : "Submit"}
</button> </button>
</div> : </div> :
<div className='flex-col w-full'> <div className='flex flex-wrap w-full gap-5'>
<h3>{correct}</h3> <div className="font-bold">{correct ? "Correct!" : "Incorrect"}</div>
<p>{reason}</p> <div>{reason}</div>
<button className='green w-full' onClick={() => handleSubmit()}>Continue</button> <button className='green w-full' onClick={() => handleSubmit()}>{!answered ? "Submit" : "Continue"}</button>
{answered && !correct && <button className='red w-full' onClick={() => handleSubmit()}>I was right</button>}
</div> </div>
} }
</div> </div>
@@ -80,13 +80,12 @@ export default function WrittenQuestionExercise({q, chapter, onSubmit}: WrittenQ
) )
} else { } else {
return ( return <div className='flex flex-wrap w-full gap-5'>
<div className=' flex-row flex-wrap border-b-4 w-full h-36'> <div className="font-bold">{correct ? "Correct!" : "Incorrect"}</div>
<h3>{correct}</h3> <div>{reason}</div>
<p>{reason}</p> <button className='green w-full' onClick={() => handleSubmit()}>{!answered ? "Submit" : "Continue"}</button>
<button className='green w-full' onClick={() => handleSubmit()}>{!answered ? "Submit" : "Continue"}</button> {answered && !correct && <button className='red w-full' onClick={() => handleSubmit()}>I was right</button>}
</div> </div>
)
} }
} }
@@ -1,5 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import {VocabularyQuestion} from "../logic/CourseData"; import {VocabularyQuestion} from "../logic/CourseData";
import {Icon} from "@iconify/react";
interface WrittenVocabularyProps { interface WrittenVocabularyProps {
q: VocabularyQuestion q: VocabularyQuestion
@@ -19,23 +20,30 @@ export default function WrittenQuestionExercise({q, onSubmit}: WrittenVocabulary
} }
return ( return (
<div className='v-layout space-y-8 items-center w-full'> <div className='v-layout gap-5 h-full'>
<div className='round box h-min no-shadow relative min-h-[60px] flex items-center justify-center mx-5'> <div className="font-bold">Recall the following word</div>
<div className='box text-center'>
{q.question} {q.question}
</div> </div>
<div className=' flex-col flex-wrap w-full'> <div className="flex-1 flex justify-center items-center w-full">
{answered ? {answered &&
<div className='flex-col w-full'> <div className='flex flex-col gap-3 w-full'>
<h3>{q.pronunciation}</h3> <div className="font-bold">{q.pronunciation}</div>
<p>{q.description}</p> <div>{q.description}</div>
<p>{q.example}</p> <div className="text-yellow-600 flex items-center gap-3"><Icon icon="fa:star"/>{q.example}</div>
<div className='flex-row'> </div>
<button className='green my-4' onClick={(e) => handleSubmit()}>I got it!</button> }
<button className='red' onClick={(e) => handleSubmit()}>I forgot</button> </div>
</div> <div className="mb-5">
</div> {answered ?
: <>
<button className='white' onClick={(e) => handleSubmit()}>Show Meaning</button> <button className='green my-4' onClick={(e) => handleSubmit()}>I got it!</button>
<button className='red' onClick={(e) => handleSubmit()}>I forgot</button>
</> :
<>
<div className="text-gray-400 text-sm mb-5">Please click "show meaning" after you have tried to recall the meaning of the word</div>
<button className='white' onClick={(e) => handleSubmit()}>Show Meaning</button>
</>
} }
</div> </div>
</div> </div>
+14 -15
View File
@@ -59,14 +59,6 @@ export const chapters_jp: Chapter[] = [
name: 'Order food', name: 'Order food',
steps: [{ steps: [{
questions: [ questions: [
{
question: 'What did Yui come to the club meeting for?',
clipUrl: window.location.origin + "/video/cake.mp4",
description: "This is a clip from the anime 'K-On'. Yui is a member of the light music club. She came to the club meeting to eat cake.",
expected: 'ケーキ or cake',
type: 'video',
},
{ {
question: 'Translate this sentence: すしをください', question: 'Translate this sentence: すしをください',
wordBank: ['I', 'sushi', 'cookies', 'want', 'please', 'give', 'rice', 'some', 'yesterday'], wordBank: ['I', 'sushi', 'cookies', 'want', 'please', 'give', 'rice', 'some', 'yesterday'],
@@ -89,10 +81,17 @@ export const chapters_jp: Chapter[] = [
type: 'verbal-question', type: 'verbal-question',
}, },
{ {
question: 'Please say: すしをたくさんあります', question: 'すしをたくさんあります',
translation: 'There is a lot of sushi', translation: 'There is a lot of sushi',
type: 'verbal-pronunciation', type: 'verbal-pronunciation',
}, },
{
question: 'What is the following song about?',
clipUrl: window.location.origin + "/video/dango.mp4",
description: "This is the song 'Dango Daikazoku' from the anime 'Clannad'. It is about a family of dango.",
expected: '団子 or dango',
type: 'video',
}
] ]
}, },
{ {
@@ -122,17 +121,17 @@ export const chapters_jp: Chapter[] = [
type: 'verbal-question', type: 'verbal-question',
}, },
{ {
question: 'Please say: 刺身おください', question: '刺身おください',
translation: 'Please give me sashimi', translation: 'Please give me sashimi',
type: 'verbal-pronunciation', type: 'verbal-pronunciation',
}, },
{ {
question: 'What is the following song about?', question: 'What did Yui come to the club meeting for?',
clipUrl: window.location.origin + "/video/dango.mp4", clipUrl: window.location.origin + "/video/cake.mp4",
description: "This is the song 'Dango Daikazoku' from the anime 'Clannad'. It is about a family of dango.", description: "This is a clip from the anime 'K-On'. Yui is a member of the light music club. She came to the club meeting to eat cake.",
expected: '団子 or dango', expected: 'ケーキ or cake',
type: 'video', type: 'video',
} },
] ]
}] }]
} }
+2 -1
View File
@@ -2,6 +2,7 @@ import NavBar from "../components/NavBar"
import React, { useState } from 'react'; import React, { useState } from 'react';
import { generateFakeUsers } from '../logic/fakeUsers'; import { generateFakeUsers } from '../logic/fakeUsers';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import {getLanguage} from "../logic/sdk";
export default function CollabLearning() { export default function CollabLearning() {
@@ -45,7 +46,7 @@ export default function CollabLearning() {
<div className="v-layout p-6"> <div className="v-layout p-6">
<div className="flex flex-col flex-1"> <div className="flex flex-col flex-1">
<h1>Chat</h1> <h1>Chat</h1>
<p className="subtext">Find people fluent in your taget language to Chat!</p> <p className="subtext">Find people fluent in {getLanguage().name} to Chat!</p>
<p className="subtext">Help them learn a language you know!</p> <p className="subtext">Help them learn a language you know!</p>
<p className="font-bold pt-10">Interests</p> <p className="font-bold pt-10">Interests</p>
<div className="tags"> <div className="tags">
+2 -4
View File
@@ -53,10 +53,8 @@ export default function Lesson()
return ( return (
<div className="v-layout page-pad non-center"> <div className="v-layout page-pad non-center">
<Progress percent={currQuestion / questions.length * 100} back={handleNavigateBack}/> <Progress percent={currQuestion / questions.length * 100} back={handleNavigateBack}/>
<div className="p-5"> <div className="p-5 h-full">
<div className="flex flex-col flex-1 mb-8 items-center"> {renderQuestion(currQuestion)}
{renderQuestion(currQuestion)}
</div>
</div> </div>
</div> </div>
) )
+1 -1
View File
@@ -17,7 +17,7 @@ export default function Review() {
return ( return (
<div className="layout-v page-pad"> <div className="layout-v page-pad">
<h1>Review Page</h1> <h1>Daily Review</h1>
<h2>Written</h2> <h2>Written</h2>
<div className="flex flex-col flex-1 mb-8 gap-3"> <div className="flex flex-col flex-1 mb-8 gap-3">
{writtenReview.map(lesson => ( {writtenReview.map(lesson => (