This commit is contained in:
louiscklaw
2025-04-29 22:55:21 +08:00
parent 9d3e832081
commit 51935d203a
9 changed files with 198 additions and 95 deletions

View File

@@ -1,5 +1,4 @@
import { useEffect } from 'react';
// import Helloworld from './Helloworld';
import React, { useEffect } from 'react';
import './style.css';
function CountDown({

View File

@@ -0,0 +1,20 @@
import React, { useState } from 'react';
import { alarmOutline, arrowBackCircleOutline } from 'ionicons/icons';
import { IonButton, IonContent, IonIcon, IonPage, useIonRouter } from '@ionic/react';
import { useAppStateContext } from '../../../contexts/AppState';
function CountDownDisplay() {
const { MATCHING_FRENZY_COUNT_DOWN_S } = useAppStateContext();
const [countdown_s, setCountDown_s] = useState<number>(MATCHING_FRENZY_COUNT_DOWN_S);
const [show_time_left_s, setShowTimeLeft] = useState<string>('0:00');
return (
<div>
<IonIcon icon={alarmOutline}></IonIcon>
{countdown_s > 0 ? show_time_left_s : 'times up'}
</div>
);
}
export default CountDownDisplay;

View File

@@ -3,47 +3,48 @@ import { alarmOutline, arrowBackCircleOutline } from 'ionicons/icons';
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import { LoadingScreen } from '../../components/LoadingScreen';
import { MATCHING_FRENZY_LINK, QUIZ_MAIN_MENU_LINK } from '../../constants';
import { MATCHING_FRENZY_LINK } from '../../constants';
import { useAppStateContext } from '../../contexts/AppState';
import { useMyIonQuizContext } from '../../contexts/MyIonQuiz';
import IMatchingFrenzyQuestion from '../../interfaces/IMatchingFrenzyQuestion';
import { listMatchingFrenzyContent } from '../../public_data/listMatchingFrenzyContent';
import { shuffleArray } from '../../utils/shuffleArray';
import CountDown from './CountDown';
import MatchingFrenzyCard from './MatchingFrenzyCard';
import PressStartToBegin from './PressStartToBegin';
import './style.css';
import ConfirmUserQuitQuiz from '../../components/ConfirmUserQuitQuiz';
import formatTimeDisplay from './formatTimeDisplay';
import fetchMFQuestions from '../../hooks/fetchMFQuestions';
import { usePocketBase } from '../../hooks/usePocketBase';
function MatchingFrenzyMatchRun() {
const [loading, setLoading] = useState<boolean>(true);
const router = useIonRouter();
const { p_route } = useParams<{ p_route: string }>();
const i_p_route = parseInt(p_route);
const [question_list, setQuestionList] = useState<IMatchingFrenzyQuestion[] | []>([]);
const { p_route: cat_id } = useParams<{ p_route: string }>();
let [start_match, setStartMatch] = useState(false);
let [test_random, setTestRandom] = useState(0);
const [show_confirm_user_exit, setShowConfirmUserExit] = useState<boolean>(false);
const { setMatchingFrenzyInProgress } = useAppStateContext();
const [question_list, setQuestionList] = useState<IMatchingFrenzyQuestion[]>([]);
const [current_question_meta, setCurrentQuestionMeta] = useState<IMatchingFrenzyQuestion | undefined>(undefined);
const [current_question, setCurrentQuestion] = useState(0);
const [num_correct, setNumCorrect] = useState(0);
const { setTabActive } = useAppStateContext();
const [answer_list, setAnswerList] = useState<string[]>([]);
const { MATCHING_FRENZY_COUNT_DOWN_S } = useAppStateContext();
const [countdown_s, setCountDown_s] = useState<number>(MATCHING_FRENZY_COUNT_DOWN_S);
const [show_time_left_s, setShowTimeLeft] = useState<string>('0:00');
const { setMatchingFrenzyInProgress } = useAppStateContext();
const { setMatchingFrenzyCurrentTest, setMatchingFrenzyResult, saveMatchingFrenzyResultToScoreBoard } =
useMyIonQuizContext();
const [num_correct, setNumCorrect] = useState(0);
const [answer_list, setAnswerList] = useState<string[]>([]);
let [start_match, setStartMatch] = useState(false);
let [test_random, setTestRandom] = useState(0);
// TODO: review useless
const i_p_route = parseInt(p_route);
const formatTimeDisplay = (s: number) => {
return `${Math.floor(s / 60)}:${(s % 60).toString().padStart(2, '0')}`;
function processStartMatch() {
setMatchingFrenzyInProgress(true);
setStartMatch(true);
}
const incNumCorrect = () => {
setNumCorrect(num_correct + 1);
};
const nextQuestion = () => {
@@ -71,15 +72,8 @@ function MatchingFrenzyMatchRun() {
setCurrentQuestionMeta(question_list[next_question_num]);
}
};
const incNumCorrect = () => {
setNumCorrect(num_correct + 1);
};
function processStartMatch() {
setMatchingFrenzyInProgress(true);
setStartMatch(true);
}
const { setMatchingFrenzyCurrentTest, setMatchingFrenzyResult, saveMatchingFrenzyResultToScoreBoard } =
useMyIonQuizContext();
useEffect(() => {
setShowTimeLeft(formatTimeDisplay(countdown_s));
@@ -102,9 +96,9 @@ function MatchingFrenzyMatchRun() {
}, [countdown_s]);
const [init_ans, setInitAns] = useState<string[]>([]);
useEffect(() => {
if (!current_question_meta) return;
let init_options = [...question_list.map((q) => q.word), ...answer_list, ...init_ans];
let all_answer_list = [...new Set(init_options)];
@@ -115,83 +109,73 @@ function MatchingFrenzyMatchRun() {
setAnswerList(shuffleArray([...sliced_shuffle_array, current_question_meta.word]));
}, [current_question_meta]);
const { user, pb } = usePocketBase();
useEffect(() => {
(async () => {
const res_json = await listMatchingFrenzyContent();
const cat_json = res_json[i_p_route];
const init_answer = cat_json.init_answer;
setInitAns(cat_json.init_answer);
fetchMFQuestions(cat_id, pb)
.then((result) => {
console.log(result);
const cat_json = result.items;
const init_answer = result.items[0].init_answer;
setInitAns(init_answer);
let temp = res_json[i_p_route].content;
let shuffled_temp = shuffleArray(temp);
let temp = result.items;
let shuffled_temp = shuffleArray(temp);
setQuestionList(shuffled_temp);
setCurrentQuestionMeta(cat_json.content[current_question]);
})();
setQuestionList(shuffled_temp);
setCurrentQuestionMeta(result.items[current_question] as unknown as IMatchingFrenzyQuestion);
setTabActive(QUIZ_MAIN_MENU_LINK);
setTestRandom(Math.random());
}, []);
const [show_confirm_user_exit, setShowConfirmUserExit] = useState<boolean>(false);
setLoading(false);
})
.catch((error) => {
console.error(error);
});
}, [cat_id]);
if (!current_question_meta) return <LoadingScreen />;
if (loading) return <LoadingScreen />;
return (
<>
<IonPage>
<IonContent fullscreen>
{start_match ? (
<>
<div>
<div
style={{
marginLeft: '1rem',
marginRight: '1rem',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div style={{ width: '33vw' }}>
<IonButton color="dark" fill="clear" shape="round" onClick={() => setShowConfirmUserExit(true)}>
<IonIcon slot="icon-only" size="large" icon={arrowBackCircleOutline}></IonIcon>
</IonButton>
</div>
<div>
<IonIcon icon={alarmOutline}></IonIcon>
{countdown_s > 0 ? show_time_left_s : 'times up'}
</div>
<div style={{ width: '33vw', display: 'flex', justifyContent: 'flex-end' }}>
Matches:{num_correct}
</div>
<div>
<div
style={{
marginLeft: '1rem',
marginRight: '1rem',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div style={{ width: '33vw' }}>
<IonButton color="dark" fill="clear" shape="round" onClick={() => setShowConfirmUserExit(true)}>
<IonIcon slot="icon-only" size="large" icon={arrowBackCircleOutline}></IonIcon>
</IonButton>
</div>
<div style={{ margin: '1rem' }}></div>
{/* */}
{/*
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', flexDirection: 'row', gap: '0.3rem' }}>
<IonIcon icon={alarmOutline}></IonIcon>
{countdown_s > 0 ? show_time_left_s : 'times up'}
</div>
<div>Matches:{num_correct}</div>
<div>
<IonIcon icon={alarmOutline}></IonIcon>
{countdown_s > 0 ? show_time_left_s : 'times up'}
</div>
*/}
<MatchingFrenzyCard
num_correct={num_correct}
incNumCorrect={incNumCorrect}
//
nextQuestion={nextQuestion}
question_meta={{
//
word_c: current_question_meta.word_c,
modal_answer: current_question_meta.word,
}}
shuffle_word_list={answer_list}
/>
<div style={{ width: '33vw', display: 'flex', justifyContent: 'flex-end' }}>Matches:{num_correct}</div>
</div>
</>
<div style={{ margin: '1rem' }}></div>
<MatchingFrenzyCard
num_correct={num_correct}
incNumCorrect={incNumCorrect}
//
nextQuestion={nextQuestion}
question_meta={{
//
word_c: current_question_meta.word_c,
modal_answer: current_question_meta.word,
}}
shuffle_word_list={answer_list}
/>
</div>
) : (
<PressStartToBegin processStartMatch={processStartMatch} />
)}
@@ -210,6 +194,7 @@ function MatchingFrenzyMatchRun() {
}
export default MatchingFrenzyMatchRun;
function isEndOfQuestionList(current_question: number, question_list: [] | IMatchingFrenzyQuestion[]) {
return current_question >= question_list.length - 1;
}

View File

@@ -0,0 +1,5 @@
const formatTimeDisplay = (s: number) => {
return `${Math.floor(s / 60)}:${(s % 60).toString().padStart(2, '0')}`;
};
export default formatTimeDisplay;