From 06d8cd010bbad16214db8aa4be940b88457fb45c Mon Sep 17 00:00:00 2001 From: aoengin Date: Sun, 24 Nov 2024 21:36:30 +0300 Subject: [PATCH 1/8] feat: Integrating Quiz Solution Logic with Backend with error handling --- .../app/(tabs)/quizzes/quizQuestion.tsx | 374 ++++++++++-------- 1 file changed, 213 insertions(+), 161 deletions(-) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx index b1f361fe..0b420ea3 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx @@ -1,132 +1,205 @@ import React, { useState, useEffect } from 'react'; import { TouchableOpacity, StyleSheet, Text, View } from 'react-native'; -import {router} from "expo-router" -import { QuizResultsProps } from './quizResults'; +import { useLocalSearchParams, router } from 'expo-router'; +import TokenManager from '@/app/TokenManager'; import { Shadow } from 'react-native-shadow-2'; import { Dimensions, useColorScheme } from 'react-native'; - - const { width, height } = Dimensions.get('window'); - -const mockQuiz = {questions: [ - { - question: 'kuzu', - type: 1, - choice1: 'lamp', - choice2: 'cow', - choice3: 'chimp', - choice4: 'lamb', - correctChoice: 4, - }, - { - question: 'dairy', - type: 2, - choice1: 'süt ürünleri', - choice2: 'et', - choice3: 'mısır', - choice4: 'buğday', - correctChoice: 1, - }, - { - question: 'mercimek', - type: 1, - choice1: 'chickpeas', - choice2: 'lentils', - choice3: 'beans', - choice4: 'legumes', - correctChoice: 2, - }, -], quizName: "Foods", tags: ['#B1']}; - export type QuizQuestion = { - question: string, - type: number, - choice1: string, - choice2: string, - choice3: string, - choice4: string, - correctChoice: number, - + question_number: number; + question: string; + choices: string[]; + previous_answer: number | null; }; -export type QuizQuestionProps = { +export type QuizData = { + quiz_progress_id: number; + quiz_title: string; + question_count: number; questions: QuizQuestion[]; - quizName: string, - tags: string[], -} - +}; const QuizQuestion = () => { - const colorScheme = useColorScheme(); // Get the system theme - const styles = getStyles(colorScheme); // Dynamically generate styles - const props: QuizQuestionProps = mockQuiz; - const questionCount = props.questions.length - const [selectedChoices, setSelectedChoices] = useState(Array(questionCount).fill(0)); + const colorScheme = useColorScheme(); + const styles = getStyles(colorScheme); + const quizId = useLocalSearchParams().quizId; + const [quizData, setQuizData] = useState(null); + const [selectedChoices, setSelectedChoices] = useState([]); const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); - const isDark = colorScheme === 'dark'; - const handleOptionSelect = (option: number) => { - const newChoices = [...selectedChoices]; - newChoices[currentQuestionIndex] = option; - setSelectedChoices(newChoices); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + + useEffect(() => { + const fetchQuiz = async () => { + try { + if (error) + { return; } + + setLoading(true); + const response = await TokenManager.authenticatedFetch(`/quiz/start/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ quiz_id: Number(quizId) }), + }); + + const data = await response.json(); + if (response.ok) { + setQuizData(data); + setSelectedChoices(Array(data.question_count).fill(null)); + } else { + setError(data.error || 'Failed to fetch quiz data'); + } + } catch (error: any) { + setError(error.message || 'Unknown error'); + } finally { + setLoading(false); + } + }; + + fetchQuiz(); + }, [quizId]); + + const handleCancel = () => { + router.back(); }; - const handleNext = () => { - setCurrentQuestionIndex(prev => prev + 1); + const handleOptionSelect = (choiceIndex: number) => { + const updatedChoices = [...selectedChoices]; + updatedChoices[currentQuestionIndex] = choiceIndex; + setSelectedChoices(updatedChoices); }; - const getScore = () => { - let score = 0 - for(let i=0; i => { + try { + const response = await TokenManager.authenticatedFetch(`/quiz/submit/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ quiz_progress_id: quizProgressId }), + }); + + const data = await response.json(); + + if (response.ok) { + return { success: true, resultUrl: data.result_url }; + } else { + return { success: false, error: data.error || 'Failed to submit quiz.' }; } + } catch (error: any) { + console.error('Unexpected error:', error.message); + return { success: false, error: error.message || 'Unknown error occurred' }; } - return score; }; + + + const submitAnswer = async (quizProgressId: number, questionNumber: number, answer: number) => { + try { + const response = await TokenManager.authenticatedFetch(`/quiz/question/solve/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + quiz_progress_id: quizProgressId, + question_number: questionNumber, + answer: answer + 1, + }), + }); - const handleFinish = () => { - router.dismissAll(); - const resultsProps: QuizResultsProps = { - quizResultsProps: { - quizName: props.quizName, - tags: props.tags, - maxScore: props.questions.length, - score: getScore(), - }, - recommendationProps: { - tags: ['#A2'], - name: 'Furniture', - author: 'Kaan', - desc: "A simple quiz about furniture." + const data = await response.json(); + if (response.ok) { + return true; + } else { + console.error('Error submitting answer:', data); + return false; } + } catch (error: any) { + console.error('Unexpected error:', error.message); + return false; } - router.push({ - pathname: '/(tabs)/quizzes/quizResults', - params: {'props': JSON.stringify(resultsProps)} - }); }; - const handlePrevious = () => { - setCurrentQuestionIndex(prev => prev - 1); + const handleNext = async () => { + const currentAnswer = selectedChoices[currentQuestionIndex]; + if (currentAnswer === null || quizData === null) { + return; + } + console.log(currentAnswer); + const success = await submitAnswer( + quizData.quiz_progress_id, + currentQuestionIndex + 1, + currentAnswer + 1 + ); + + if (success) { + setCurrentQuestionIndex((prev) => prev + 1); + } else { + console.error('Failed to submit answer. Check logs.'); + } }; - const handleCancel = () => { - router.dismissAll(); - router.push('/(tabs)/quizzes/'); + const handleFinish = async () => { + const currentAnswer = selectedChoices[currentQuestionIndex]; + + if (currentAnswer === null || quizData === null) { + alert('Please select an answer before finishing the quiz.'); + return; + } + + console.log(currentAnswer); + console.log(currentQuestionIndex); + const success = await submitAnswer( + quizData.quiz_progress_id, + currentQuestionIndex + 1, + currentAnswer + 1 + ); + + + + if (success) { + const result = await submitQuiz(quizData.quiz_progress_id); + if (result.success) { + router.push( + { + pathname:'/(tabs)/quizzes/quizResults', + params: { resultUrl: result.resultUrl, quizId: quizId }, + }); + } else { + console.error('Failed to submit quiz:', result.error); + alert('Failed to submit quiz.' + result.error); + } + router.push( + { + pathname:'/(tabs)/quizzes/quizResults', + params: { resultUrl: result.resultUrl, quizId: quizId }, + }); + } else { + console.error('Failed to submit answer. Check logs.'); + } }; + if (loading) return Loading...; + if (error) return Error: {error}; + + const currentQuestion = quizData?.questions[currentQuestionIndex]; + const questionCount = quizData?.question_count || 0; + return ( - - - Cancel Quiz - + + + Cancel Quiz + @@ -134,87 +207,55 @@ const QuizQuestion = () => { - - - {props.questions[currentQuestionIndex].question} - - - - - handleOptionSelect(1)} - > - {props.questions[currentQuestionIndex].choice1} - - + + + {currentQuestion?.question || 'No question available'} - - - handleOptionSelect(2)} - > - {props.questions[currentQuestionIndex].choice2} - - + + {currentQuestion?.choices.map((choice, index) => ( + + + handleOptionSelect(index)} + > + {choice} + + + + ))} + - - - handleOptionSelect(3)} - > - {props.questions[currentQuestionIndex].choice3} - - - - + - handleOptionSelect(4)} - > - {props.questions[currentQuestionIndex].choice4} - + setCurrentQuestionIndex((prev) => prev - 1)} + disabled={currentQuestionIndex === 0} + > + Previous + - - - - - - - Previous - - - { currentQuestionIndex == questionCount-1 ? - + {currentQuestionIndex === questionCount - 1 ? ( + Finish - - : - + + + ) : ( + Next - - } + + )} @@ -352,6 +393,17 @@ export const getStyles = (colorScheme: any) => { elevation: 3, shadowColor: isDark ? 'black' : 'black', }, + loadingText: { + textAlign: 'center', + color: isDark ? '#fff' : '#000', + marginTop: 10, + }, + errorText: { + color: 'red', + fontSize: 16, + textAlign: 'center', + marginBottom: 16, + }, }); }; From 9473b0cc7e98ce62afe6cceafc89615507ff8f06 Mon Sep 17 00:00:00 2001 From: aoengin Date: Sun, 24 Nov 2024 21:40:19 +0300 Subject: [PATCH 2/8] refactor: pass quizId to quiz questions --- mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx index 283add7f..9d163235 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx @@ -145,6 +145,7 @@ const QuizDetails = () => { router.navigate('/(tabs)/quizzes/quizQuestion')} + router.push({ pathname: '/(tabs)/quizzes/quizQuestion', params: { quizId: id } })} > Take Quiz From f33dcf8b7dd2ce5e67a8eed4d2be0c774ba76ca0 Mon Sep 17 00:00:00 2001 From: aoengin Date: Sun, 24 Nov 2024 21:44:46 +0300 Subject: [PATCH 3/8] refactor: change formatted quiz details to align with changes on backend + naming changes --- .../app/(tabs)/quizzes/quizDetails.tsx | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx index 9d163235..56f3cc42 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizDetails.tsx @@ -65,24 +65,26 @@ const QuizDetails = () => { const data = await response.json(); - + if (response.ok) { const formattedQuizDetails = { - id: data.id, - title: data.title, - description: data.description, - author: data.author.username, - tags: data.tags, - level: data.level, - question_count: data.question_count, - created_at: data.created_at, - times_taken: data.times_taken, - like_count: data.like_count, - average_score: data.average_score, - is_bookmarked: data.is_bookmarked, - is_liked: data.is_liked, + id: data.quiz.id, + title: data.quiz.title, + description: data.quiz.description, + author: data.quiz.author.username, + tags: data.quiz.tags, + level: data.quiz.level, + question_count: data.quiz.question_count, + created_at: data.quiz.created_at, + times_taken: data.quiz.times_taken, + like_count: data.quiz.like_count, + average_score: data.quiz.average_score, + is_bookmarked: data.quiz.is_bookmarked, + is_liked: data.quiz.is_liked, + is_solved: data.is_solved, + quiz_result_id: data.quiz_result_id, // This could be null }; - + setQuizDetails(formattedQuizDetails); setError(null); } else { @@ -128,11 +130,10 @@ const QuizDetails = () => { {quizDetails.title} - Stats {'\n'} Times Taken: {quizDetails.times_taken || 0} {'\n'} Number of Questions: {quizDetails.question_count || 0} {'\n'} Average Score: {quizDetails.average_score || 'N/A'} {'\n'} - Tags: {quizDetails.level || 'N/A'} + Level: {quizDetails.level || 'N/A'} {/* Bookmark button in the bottom right corner */} @@ -143,8 +144,6 @@ const QuizDetails = () => { - router.navigate('/(tabs)/quizzes/quizQuestion')} router.push({ pathname: '/(tabs)/quizzes/quizQuestion', params: { quizId: id } })} > Take Quiz From faa27f5da55e44f4f63e8a07516c41ffb68692de Mon Sep 17 00:00:00 2001 From: aoengin Date: Mon, 25 Nov 2024 00:45:20 +0300 Subject: [PATCH 4/8] fix: a bug with question and answer numbers are fixed --- mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx index 0b420ea3..7e1f40dd 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizQuestion.tsx @@ -108,7 +108,7 @@ const QuizQuestion = () => { }, body: JSON.stringify({ quiz_progress_id: quizProgressId, - question_number: questionNumber, + question_number: questionNumber + 1, answer: answer + 1, }), }); @@ -135,8 +135,8 @@ const QuizQuestion = () => { console.log(currentAnswer); const success = await submitAnswer( quizData.quiz_progress_id, - currentQuestionIndex + 1, - currentAnswer + 1 + currentQuestionIndex, + currentAnswer ); if (success) { @@ -158,8 +158,8 @@ const QuizQuestion = () => { console.log(currentQuestionIndex); const success = await submitAnswer( quizData.quiz_progress_id, - currentQuestionIndex + 1, - currentAnswer + 1 + currentQuestionIndex, + currentAnswer ); From 5716e172a20fe343b5ef171f77c9992c4fe8d7da Mon Sep 17 00:00:00 2001 From: aoengin Date: Mon, 25 Nov 2024 00:46:28 +0300 Subject: [PATCH 5/8] fix: a bug with quiz creation and correct answer is fixed --- .../quizzes/quizCreationQuestionList.tsx | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizCreationQuestionList.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizCreationQuestionList.tsx index e4e4dff0..71eb677c 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizCreationQuestionList.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizCreationQuestionList.tsx @@ -21,8 +21,6 @@ type QuizDetails = { tags: string[]; }; -let uniqueQuestionKey = 0; - const QuizCreationQuestionList = () => { const [questions, setQuestions] = useState([]); @@ -59,20 +57,21 @@ const QuizCreationQuestionList = () => { const colorScheme = useColorScheme(); const styles = getStyles(colorScheme); - const { question, answers, correctAnswer, selectedType, index } = useLocalSearchParams(); - + const { question, answers, correctAnswer, selectedType, index, trigger } = useLocalSearchParams(); const parsedAnswers = Array.isArray(answers) ? answers.join(', ') : answers ? JSON.parse(answers) : []; + const key = questions.length === 0 ? 0 : questions[questions.length - 1].id + 1; + + useEffect(() => { if (question && answers && correctAnswer && selectedType) { const newQuestion = { - id: index !== undefined ? questions[Number(index)].id : uniqueQuestionKey, + id: index !== undefined ? questions[Number(index)].id : key, name: Array.isArray(question) ? question[0] : question, correctAnswer: Array.isArray(correctAnswer) ? correctAnswer[0] : correctAnswer, answers: parsedAnswers, type: Array.isArray(selectedType) ? selectedType[0] : selectedType }; - console.log(newQuestion); if (index !== undefined) { setQuestions((prevQuestions) => { @@ -83,18 +82,19 @@ const QuizCreationQuestionList = () => { }); return; } - uniqueQuestionKey++; - setQuestions((prevQuestions) => [...prevQuestions, newQuestion]); + + const newQuest = { ...newQuestion }; + setQuestions((prevQuestions) => [...prevQuestions, newQuest]); saveQuestions(questions); } - }, [question, answers, correctAnswer, selectedType]); + }, [question, answers, correctAnswer, selectedType, trigger]); const handleAddQuestion = () => { - router.navigate('/(tabs)/quizzes/quizCreationInfo'); + router.navigate({pathname: '/(tabs)/quizzes/quizCreationInfo', params: { "trigger": key }}); }; const handleUpdateQuestion = (index: number) => { - router.navigate({pathname: '/(tabs)/quizzes/quizCreationInfo', params: { "initialQuestion": questions[index].name , "initialAnswers": JSON.stringify(questions[index].answers), "initialCorrectAnswer": questions[index].correctAnswer, "type": questions[index].type, "index": index}}); + router.navigate({pathname: '/(tabs)/quizzes/quizCreationInfo', params: { "initialQuestion": questions[index].name , "initialAnswers": JSON.stringify(questions[index].answers), "initialCorrectAnswer": Number(questions[index].correctAnswer), "type": questions[index].type, "index": index, "trigger": key + 50}}); }; const handleCreateQuiz = async () => { @@ -110,7 +110,6 @@ const QuizCreationQuestionList = () => { const formattedTags = [{"name": quizDetails["level"]}]; - console.log(formattedTags); return { quiz: { @@ -126,14 +125,13 @@ const QuizCreationQuestionList = () => { choice2: q.answers[1], choice3: q.answers[2], choice4: q.answers[3], - correct_choice: q.answers.indexOf(q.correctAnswer) + 1, + correct_choice: Number(q.correctAnswer) + 1, })), }; }; const createQuiz = async () => { const quizData = prepareQuizData(); - console.log('Quiz data:', quizData); if (!quizData) return; // Ensure data is prepared try { @@ -151,7 +149,6 @@ const QuizCreationQuestionList = () => { alert('Failed to create quiz. Please try again.'); } else { const result = await response.json(); - console.log('Quiz created successfully:', result); alert('Quiz created successfully!'); await clearQuizDetails(); await clearQuestions(); From 31fb27f19f18ceb2231995be690c82fadc3bedaa Mon Sep 17 00:00:00 2001 From: aoengin Date: Mon, 25 Nov 2024 00:46:48 +0300 Subject: [PATCH 6/8] fix: quiz creation bug --- .../bulingo/app/(tabs)/quizzes/quizCreationInfo.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizCreationInfo.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizCreationInfo.tsx index b6693247..7dda4b74 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizCreationInfo.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizCreationInfo.tsx @@ -10,7 +10,7 @@ const QuizCreationInfo = () => { const [newAnswer, setNewAnswer] = useState(''); const [selectedAnswerIndex, setSelectedAnswerIndex] = useState(null); const [selectedType, setSelectedType] = useState('Type II'); - const [correctAnswerIndex, setCorrectAnswerIndex] = useState(null) + const [correctAnswerIndex, setCorrectAnswerIndex] = useState(null) const isButtonDisabled = () => { const nonEmptyAnswers = answers.filter(answer => answer.trim() !== ""); @@ -22,13 +22,16 @@ const QuizCreationInfo = () => { const styles = getStyles(colorScheme); // get params from the previous screen - const { initialQuestion, initialAnswers, initialCorrectAnswer, type, index} = useLocalSearchParams(); + const { initialQuestion, initialAnswers, initialCorrectAnswer, type, index, trigger} = useLocalSearchParams(); + + + useEffect(() => { if (initialQuestion && initialAnswers && initialCorrectAnswer) { setQuestion(Array.isArray(initialQuestion) ? initialQuestion[0] : initialQuestion); setAnswers(JSON.parse(Array.isArray(initialAnswers) ? initialAnswers[0] : initialAnswers)); - setCorrectAnswerIndex(JSON.parse(Array.isArray(initialAnswers) ? initialAnswers[0] : initialAnswers).indexOf(initialCorrectAnswer)); + setCorrectAnswerIndex(Number(initialCorrectAnswer)); setSelectedType(type instanceof Array ? type[0] : type); } }, [initialQuestion, initialAnswers, initialCorrectAnswer]); @@ -65,7 +68,7 @@ const QuizCreationInfo = () => { }; const handleAddQuestion = () => { - router.navigate({ pathname: '/(tabs)/quizzes/quizCreationQuestionList', params: { question: question, answers: JSON.stringify(answers), correctAnswer: correctAnswerIndex, selectedType: selectedType, index: index } }); + router.navigate({ pathname: '/(tabs)/quizzes/quizCreationQuestionList', params: { question: question, answers: JSON.stringify(answers), correctAnswer: correctAnswerIndex, selectedType: selectedType, index: index, trigger: trigger} }); }; const handleTypeSelect = (type: string) => { From e05d8b697f2dbdd979c2b33299df3b05e53ad32c Mon Sep 17 00:00:00 2001 From: aoengin Date: Mon, 25 Nov 2024 01:15:04 +0300 Subject: [PATCH 7/8] feat: connect quiz results to the backend --- .../app/(tabs)/quizzes/quizResults.tsx | 151 +++++++++++++----- 1 file changed, 109 insertions(+), 42 deletions(-) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx index 03290014..4cacd418 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx @@ -1,49 +1,103 @@ -import React, {useState} from 'react'; -import {Image, StyleSheet, Text, View, TouchableOpacity, useColorScheme} from 'react-native'; +import React, { useState, useEffect } from 'react'; +import { Image, StyleSheet, Text, View, TouchableOpacity, useColorScheme } from 'react-native'; import { useLocalSearchParams } from "expo-router"; -import {router} from "expo-router"; +import { router } from "expo-router"; import { Shadow } from 'react-native-shadow-2'; - import { Dimensions } from 'react-native'; +import TokenManager from '@/app/TokenManager'; const { width, height } = Dimensions.get('window'); -export type QuizResultsProps = { - quizResultsProps: QuizResultsCardProps, - recommendationProps: QuizCardProps, -}; + const QuizResults = () => { - const rawProps = useLocalSearchParams<{'props': string}>(); - const props: QuizResultsProps = JSON.parse(rawProps.props); + const { resultUrl, quizId } = useLocalSearchParams<{ resultUrl: string, quizId: string }>(); const colorScheme = useColorScheme(); const styles = getStyles(colorScheme); + const [quizResult, setQuizResult] = useState<{ + quiz: { id: number; title: string }; + score: number; + time_taken: number; + level: string; + question_count: number; + } | null>(null); + + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchQuizResult = async () => { + console.log(resultUrl); + try { + const response = await TokenManager.authenticatedFetch(resultUrl, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (response.ok) { + const data = await response.json(); + setQuizResult(data); + } else { + const errorData = await response.json(); + setError(errorData.detail || 'Failed to fetch quiz result.'); + } + } catch (err: any) { + setError(err.message || 'Unknown error occurred'); + } finally { + setLoading(false); + } + }; + + fetchQuizResult(); + }, [resultUrl]); + + return ( + {loading ? ( + Loading... + ) : error ? ( + Error: {error} + ) : ( - - + {quizResult ? ( + - + ) : ( + No results found for this quiz. + )} + Recommended Quiz - + {recommendedQuiz ? ( + + ) : ( + No recommendations available. + )} - {router.push("/(tabs)/quizzes/quizQuestion")}}> + {router.push( + { + pathname:'/(tabs)/quizzes/quizQuestion', + params: { quizId: quizId }, + });}}> Retake Quiz @@ -56,8 +110,9 @@ const QuizResults = () => { - - + + )} + ); }; @@ -67,6 +122,7 @@ export type QuizResultsCardProps = { maxScore: number, tags: string[], styles?: any, + id?: number, } export const QuizResultsCard = (props: QuizResultsCardProps) => { @@ -106,20 +162,21 @@ export const QuizResultsCard = (props: QuizResultsCardProps) => { ); }; -export type QuizCardProps = { - name?: string, - desc?: string, - author?: string, - tags: string[], - styles?: any, -}; - -export const QuizCard = (props: QuizCardProps) => { +export const QuizCard = (props: { + name: string; + desc: string; + author: string; + tags: string[]; + styles: any; + id?: number; +}) => { const { styles } = props.styles; return ( router.navigate('/(tabs)/quizzes/quizDetails')} + onPress={() => router.navigate({ + pathname: '/(tabs)/quizzes/quizDetails', + params:{id : props?.id},})} > {props.name} @@ -141,8 +198,7 @@ export const QuizCard = (props: QuizCardProps) => { ); }; - -const getStyles = (colorScheme:any) => { +const getStyles = (colorScheme: any) => { const isDark = colorScheme === 'dark'; return StyleSheet.create({ @@ -176,7 +232,7 @@ const getStyles = (colorScheme:any) => { alignItems: 'center', }, resultsTitle: { - fontSize: 32, + fontSize: 25, fontWeight: 'bold', textAlign: 'center', color: isDark ? '#fff' : '#000', @@ -363,7 +419,18 @@ const getStyles = (colorScheme:any) => { resizeMode: 'contain', tintColor: isDark ? '#fff' : '#000', }, + loadingText: { + textAlign: 'center', + color: isDark ? '#fff' : '#000', + marginTop: 10, + }, + errorText: { + color: 'red', + fontSize: 16, + textAlign: 'center', + marginBottom: 16, + }, }); }; -export default QuizResults; \ No newline at end of file +export default QuizResults; From 4bf331eb697ca6b58a647b7d55e9f02e2bb0888b Mon Sep 17 00:00:00 2001 From: aoengin Date: Mon, 25 Nov 2024 01:15:29 +0300 Subject: [PATCH 8/8] feat: add random quiz recommendation --- .../app/(tabs)/quizzes/quizResults.tsx | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx b/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx index 4cacd418..c204370d 100644 --- a/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx +++ b/mobile/bulingo/app/(tabs)/quizzes/quizResults.tsx @@ -26,6 +26,16 @@ const QuizResults = () => { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [recommendedQuiz, setRecommendedQuiz] = useState<{ + id: number; + title: string; + description: string; + author : string; + level: string; + likes: number; + liked: boolean; + } | null>(null); + useEffect(() => { const fetchQuizResult = async () => { console.log(resultUrl); @@ -55,6 +65,49 @@ const QuizResults = () => { }, [resultUrl]); + useEffect(() => { + const fetchQuizzes = async () => { + try { + const response = await TokenManager.authenticatedFetch(`/feed/quiz/`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + + const data = await response.json(); + console.log(data); + if (response.ok) { + const formattedResults = data.map((quiz: any) => ({ + id: Number(quiz.id), + title: quiz.title, + description: quiz.description, + author: quiz.author.username, + level: quiz.level, + likes: quiz.like_count, + liked: quiz.is_liked, + })); + let randomInt = 0 + let retryCount = 3; + + while(formattedResults[randomInt].id === Number(quizId) && retryCount > 0) { + randomInt = Math.floor(Math.random() * formattedResults.length); + retryCount--; + }; + + setRecommendedQuiz(formattedResults[randomInt]); + setError(null); + } else { + setError('Failed to fetch quizzes. Please try again. Error: ' + data.message || JSON.stringify(data)); + } + } catch (error: any) { + setError('An error occurred while fetching quizzes. Please try again. Error: ' + (error.message || 'Unknown error')); + } + }; + + fetchQuizzes(); + }, []); + return ( {loading ? (