Skip to content
Extraits de code Groupes Projets
languageTest.svelte 5,52 ko
Newer Older
  • Learn to ignore specific revisions
  • Brieuc Dubois's avatar
    Brieuc Dubois a validé
    <script lang="ts">
    	import { sendTestEntryTaskGapfillAPI, sendTestEntryTaskQcmAPI } from '$lib/api/tests';
    	import { t } from '$lib/services/i18n';
    	import type { TestTask } from '$lib/types/tests';
    	import {
    		TestTaskQuestion,
    		TestTaskQuestionGapfill,
    		TestTaskQuestionQcm,
    		TestTaskQuestionQcmType
    	} from '$lib/types/testTaskQuestions';
    	import type User from '$lib/types/user';
    	import Gapfill from '../surveys/gapfill.svelte';
    
    	let {
    		languageTest,
    		user,
    		code,
    		rid,
    		study_id,
    		onFinish = () => {}
    	}: {
    		languageTest: TestTask;
    		user: User | null;
    		code: string | null;
    		rid: string | null;
    		study_id: number;
    		onFinish: Function;
    	} = $props();
    
    	function getSortedQuestions(questions: TestTaskQuestion[]) {
    		return questions.sort(() => Math.random() - 0.5);
    	}
    
    	let nAnswers = $state(1);
    
    	let startTime = new Date().getTime();
    
    	let currentGroupId = $state(0);
    	let currentGroup = $derived(languageTest.groups[currentGroupId]);
    
    	let questions = $derived(
    		currentGroup.randomize ? getSortedQuestions(currentGroup.questions) : currentGroup.questions
    	);
    
    	let currentQuestionId = $state(0);
    	let currentQuestion = $derived(questions[currentQuestionId]);
    	let currentQuestionParts = $derived(
    		currentQuestion instanceof TestTaskQuestionGapfill ? currentQuestion.parts : null
    	);
    
    	let soundPlayer: HTMLAudioElement | null = $state(null);
    
    	function setGroupId(id: number) {
    		currentGroupId = id;
    		if (currentGroup.id < 1100) {
    			setQuestionId(0);
    		}
    	}
    
    	function setQuestionId(id: number) {
    		currentQuestionId = id;
    		if (soundPlayer) soundPlayer.load();
    		nAnswers += 1;
    	}
    
    	async function nextGroup() {
    		if (currentGroupId < languageTest.groups.length - 1) {
    			setGroupId(currentGroupId + 1);
    			//special group id for end of survey questions
    		} else {
    			console.log('END');
    			onFinish();
    		}
    	}
    
    	async function sendGap() {
    		if (
    			!currentGroup.demo &&
    			currentQuestion instanceof TestTaskQuestionGapfill &&
    			currentQuestionParts
    		) {
    			const gapTexts = currentQuestionParts
    				.filter((part) => part.gap !== null)
    				.map((part) => part.gap)
    				.join('|');
    
    			if (
    				!(await sendTestEntryTaskGapfillAPI(
    					fetch,
    					code || user?.email || '',
    					rid,
    					user?.id || null,
    					languageTest.id,
    					study_id,
    					currentGroup.id,
    					questions[currentQuestionId].id,
    					(new Date().getTime() - startTime) / 1000,
    					gapTexts
    				))
    			) {
    				return;
    			}
    		}
    		if (currentQuestionId < questions.length - 1) {
    			setQuestionId(currentQuestionId + 1);
    			startTime = new Date().getTime();
    		} else {
    			nextGroup();
    		}
    	}
    
    	async function selectOption(option: number) {
    		if (!currentGroup.demo) {
    			if (
    				!(await sendTestEntryTaskQcmAPI(
    					fetch,
    					code || user?.email || '',
    					rid,
    					user?.id || null,
    					languageTest.id,
    					study_id,
    					currentGroup.id,
    					questions[currentQuestionId].id,
    					(new Date().getTime() - startTime) / 1000,
    					option
    				))
    			) {
    				return;
    			}
    		}
    		if (currentQuestionId < questions.length - 1) {
    			setQuestionId(currentQuestionId + 1);
    			startTime = new Date().getTime();
    		} else {
    			nextGroup();
    		}
    	}
    </script>
    
    <div class="text-center">{nAnswers}/{languageTest.numQuestions}</div>
    
    {#if currentQuestion instanceof TestTaskQuestionGapfill && currentQuestionParts}
    	<div class="mx-auto mt-16 center flex flex-col text-xl">
    		<div>
    			{#each currentQuestionParts as part (part)}
    				{#if part.gap !== null}
    					<Gapfill length={part.text.length} onInput={(text) => (part.gap = text)} />
    				{:else}
    					{part.text}
    				{/if}
    			{/each}
    		</div>
    		<button class="button mt-8" onclick={sendGap}>{$t('button.next')}</button>
    	</div>
    {:else if currentQuestion instanceof TestTaskQuestionQcm}
    	<div class="mx-auto mt-16 text-center">
    		{#if currentQuestion.type === TestTaskQuestionQcmType.text}
    
    Brieuc Dubois's avatar
    Brieuc Dubois a validé
    			<p class="text-center font-bold py-4 px-6 m-auto max-w-5xl">{@html currentQuestion.value}</p>
    
    Brieuc Dubois's avatar
    Brieuc Dubois a validé
    		{:else if currentQuestion.type === TestTaskQuestionQcmType.image}
    			<img src={currentQuestion.value} alt="Question" />
    		{:else if currentQuestion.type === TestTaskQuestionQcmType.audio}
    			<audio bind:this={soundPlayer} controls autoplay class="rounded-lg mx-auto">
    				<source src={currentQuestion.value} type="audio/mpeg" />
    				Your browser does not support the audio element.
    			</audio>
    		{/if}
    	</div>
    
    	<div class="mt-16 w-max">
    		<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4">
    			{#each currentQuestion.optionsRandomized as option (option)}
    				<div
    					class="h-48 w-48 overflow-hidden rounded-lg border border-black"
    					onclick={() => selectOption(option.index)}
    					role="button"
    					onkeydown={() => selectOption(option.index)}
    					tabindex="0"
    				>
    					{#if option.type === TestTaskQuestionQcmType.text}
    						<span
    							class="flex items-center justify-center h-full w-full text-2xl transition-transform duration-200 ease-in-out transform hover:scale-105"
    						>
    							{option.value}
    						</span>
    					{:else if option.type === TestTaskQuestionQcmType.image}
    						<img
    							src={option.value}
    							alt="Option {option}"
    							class="object-cover h-full w-full transition-transform duration-200 ease-in-out transform hover:scale-105"
    						/>
    					{:else if option.type === TestTaskQuestionQcmType.audio}
    						<audio
    							controls
    							class="w-full"
    							onclick={(e) => {
    								e.preventDefault();
    								e.stopPropagation();
    							}}
    						>
    							<source src={option.value} type="audio/mpeg" />
    							Your browser does not support the audio element.
    						</audio>
    					{/if}
    				</div>
    			{/each}
    		</div>
    	</div>
    {:else}
    	Nop
    {/if}