```
add new hooks for fetching QuizCRQuestions and categories, update related components to use the new hooks, and refactor SelectCategory page to use the new API ```
This commit is contained in:
30
002_source/ionic_mobile/src/hooks/fetchCRQuestions.tsx
Normal file
30
002_source/ionic_mobile/src/hooks/fetchCRQuestions.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { idCard } from 'ionicons/icons';
|
||||||
|
import { QuizCRQuestion } from '../types/QuizCRQuestion';
|
||||||
|
import { usePocketBase } from './usePocketBase';
|
||||||
|
import { QueryClient } from '@tanstack/react-query';
|
||||||
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
staleTime: Infinity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchCRQuestions = async (cat_id: string, pb: PocketBase) => {
|
||||||
|
const response = await queryClient.fetchQuery({
|
||||||
|
queryKey: ['fetchData', cat_id],
|
||||||
|
staleTime: 60 * 1000,
|
||||||
|
queryFn: async () => {
|
||||||
|
return await pb.collection('QuizCRQuestions').getList<QuizCRQuestion>(1, 9999, {
|
||||||
|
filter: `cat_id = "${cat_id}"`,
|
||||||
|
$autoCancel: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default fetchCRQuestions;
|
@@ -0,0 +1,38 @@
|
|||||||
|
// CR = ConnectiveRevision
|
||||||
|
import { usePocketBase } from './usePocketBase.tsx';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import IListeningPracticeCategory from '../interfaces/IListeningPracticeCategory.tsx';
|
||||||
|
|
||||||
|
const useListQuizCRCategories = () => {
|
||||||
|
const { user, pb } = usePocketBase();
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [
|
||||||
|
'useListQuizConnectiveRevisionContent',
|
||||||
|
'feeds',
|
||||||
|
'all',
|
||||||
|
user?.id || '',
|
||||||
|
//
|
||||||
|
],
|
||||||
|
staleTime: 60 * 1000,
|
||||||
|
queryFn: async ({
|
||||||
|
queryKey,
|
||||||
|
}: {
|
||||||
|
queryKey: [
|
||||||
|
'useListQuizConnectiveRevisionContent',
|
||||||
|
'feeds',
|
||||||
|
'all',
|
||||||
|
string | null,
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}) => {
|
||||||
|
console.log('calling useListQuizConnectiveRevisionContent');
|
||||||
|
return await pb.collection('LessonsCategories').getList<IListeningPracticeCategory>(1, 9999, {
|
||||||
|
sort: 'pos',
|
||||||
|
$autoCancel: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// enabled: !!user?.id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useListQuizCRCategories;
|
@@ -0,0 +1,26 @@
|
|||||||
|
import { usePocketBase } from './usePocketBase.tsx';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { QuizCRQuestion } from '../types/QuizCRQuestion.ts/index.ts';
|
||||||
|
|
||||||
|
const useListQuizCRQuestionByCRCategoryId = (CRCategoryId: string) => {
|
||||||
|
const { user, pb } = usePocketBase();
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['useListQuizCRQuestionByCRCategoryId', 'feeds', 'all', user?.id || '', CRCategoryId],
|
||||||
|
staleTime: 60 * 1000,
|
||||||
|
queryFn: async ({
|
||||||
|
queryKey,
|
||||||
|
}: {
|
||||||
|
queryKey: ['useListQuizCRQuestionByCRCategoryId', 'feeds', 'all', string | null, string];
|
||||||
|
}) => {
|
||||||
|
console.log('calling useListQuizCRQuestionByCRCategoryId');
|
||||||
|
return await pb.collection('QuizCRQuestions').getList<QuizCRQuestion>(1, 9999, {
|
||||||
|
filter: `cat_id = "${CRCategoryId}"`,
|
||||||
|
sort: 'id',
|
||||||
|
$autoCancel: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// enabled: !!user?.id && !!CRCategoryId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useListQuizCRQuestionByCRCategoryId;
|
@@ -5,7 +5,9 @@ interface IConnectivesRevisionCategory {
|
|||||||
test_i: number;
|
test_i: number;
|
||||||
cat_info: string;
|
cat_info: string;
|
||||||
cat_name: string;
|
cat_name: string;
|
||||||
content: IConnectivesRevisionQuestion[] | [];
|
content?: IConnectivesRevisionQuestion[] | [];
|
||||||
|
//
|
||||||
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default IConnectivesRevisionCategory;
|
export default IConnectivesRevisionCategory;
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// abonded
|
||||||
interface IQuestionMeta {
|
interface IQuestionMeta {
|
||||||
question_idx: number;
|
question_idx: number;
|
||||||
question_fh: string;
|
question_fh: string;
|
||||||
|
@@ -155,7 +155,7 @@ const QuizContent: React.FC<IQuestionCard> = ({
|
|||||||
>
|
>
|
||||||
{answer_list.map((connective, idx) => {
|
{answer_list.map((connective, idx) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div key={idx}>
|
||||||
<IonButton
|
<IonButton
|
||||||
color={'dark'}
|
color={'dark'}
|
||||||
ref={button_refs[idx]}
|
ref={button_refs[idx]}
|
||||||
|
@@ -8,11 +8,15 @@ import { useMyIonQuizContext } from '../../contexts/MyIonQuiz';
|
|||||||
import { listConectivesRevisionContent } from '../../public_data/listConectivesRevisionContent';
|
import { listConectivesRevisionContent } from '../../public_data/listConectivesRevisionContent';
|
||||||
import { shuffleArray } from '../../utils/shuffleArray';
|
import { shuffleArray } from '../../utils/shuffleArray';
|
||||||
import QuizContent from './QuizContent';
|
import QuizContent from './QuizContent';
|
||||||
|
import fetchCRQuestions from '../../hooks/fetchCRQuestions';
|
||||||
|
import { usePocketBase } from '../../hooks/usePocketBase';
|
||||||
|
|
||||||
function ConnectiveRevisionQuizRun() {
|
function ConnectiveRevisionQuizRun() {
|
||||||
const router = useIonRouter();
|
const router = useIonRouter();
|
||||||
const { p_route } = useParams<{ p_route: string }>();
|
const { p_route: cat_id } = useParams<{ p_route: string }>();
|
||||||
const i_p_route = parseInt(p_route);
|
|
||||||
|
// NOTE: abonded, should be updated with `i_cat_id` when done
|
||||||
|
const i_p_route = parseInt(cat_id);
|
||||||
|
|
||||||
const { setTabActive } = useAppStateContext();
|
const { setTabActive } = useAppStateContext();
|
||||||
const [question_list, setQuestionList] = useState<IQuestionJson[] | []>([]);
|
const [question_list, setQuestionList] = useState<IQuestionJson[] | []>([]);
|
||||||
@@ -22,6 +26,9 @@ function ConnectiveRevisionQuizRun() {
|
|||||||
const [isOpenCorrectAnswer, setIsOpenCorrectAnswer] = useState(false);
|
const [isOpenCorrectAnswer, setIsOpenCorrectAnswer] = useState(false);
|
||||||
const [isOpenWrongAnswer, setIsOpenWrongAnswer] = useState(false);
|
const [isOpenWrongAnswer, setIsOpenWrongAnswer] = useState(false);
|
||||||
const [answer_list, setAnswerList] = useState<string[]>(['but', 'and', 'or', 'of', 'with']);
|
const [answer_list, setAnswerList] = useState<string[]>(['but', 'and', 'or', 'of', 'with']);
|
||||||
|
|
||||||
|
const { user, pb } = usePocketBase();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setConnectiveRevisionCurrentTest,
|
setConnectiveRevisionCurrentTest,
|
||||||
setConnectiveRevisionProgress,
|
setConnectiveRevisionProgress,
|
||||||
@@ -79,19 +86,19 @@ function ConnectiveRevisionQuizRun() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const res_json = await listConectivesRevisionContent();
|
const res_json = await fetchCRQuestions(cat_id, pb);
|
||||||
let temp_init_ans = res_json[i_p_route].init_ans;
|
let temp_init_ans: string[] = res_json.items[0].init_answer;
|
||||||
|
|
||||||
setInitAnswer(temp_init_ans);
|
setInitAnswer(temp_init_ans);
|
||||||
let temp = res_json[i_p_route].content;
|
let temp = res_json.items;
|
||||||
let shuffled_temp = shuffleArray(temp);
|
let shuffled_temp = shuffleArray(temp);
|
||||||
// let shuffled_temp = temp;
|
// let shuffled_temp = temp;
|
||||||
setQuestionList(shuffled_temp);
|
setQuestionList(shuffled_temp);
|
||||||
|
|
||||||
let question_meta_current = res_json[i_p_route].content[0];
|
let question_meta_current = res_json.items[0] as unknown as IQuestionMeta;
|
||||||
setCurrentQuestionMeta({
|
setCurrentQuestionMeta({
|
||||||
question_idx: current_question_idx,
|
|
||||||
...question_meta_current,
|
...question_meta_current,
|
||||||
|
question_idx: current_question_idx,
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
setTabActive(QUIZ_MAIN_MENU_LINK);
|
setTabActive(QUIZ_MAIN_MENU_LINK);
|
||||||
@@ -113,31 +120,7 @@ function ConnectiveRevisionQuizRun() {
|
|||||||
total_questions_num={question_list.length}
|
total_questions_num={question_list.length}
|
||||||
answer_list={answer_list}
|
answer_list={answer_list}
|
||||||
quiz_idx={i_p_route + 1}
|
quiz_idx={i_p_route + 1}
|
||||||
//
|
|
||||||
/>
|
/>
|
||||||
{/* */}
|
|
||||||
{/* <CorrectAnswerToast isOpen={isOpenCorrectAnswer} dismiss={() => setIsOpenCorrectAnswer(false)} /> */}
|
|
||||||
{/* */}
|
|
||||||
{/* <WrongAnswerToast
|
|
||||||
correct_answer={current_question_meta.modal_ans}
|
|
||||||
isOpen={isOpenWrongAnswer}
|
|
||||||
dismiss={() => setIsOpenWrongAnswer(false)}
|
|
||||||
/> */}
|
|
||||||
{/*
|
|
||||||
<IonToast
|
|
||||||
isOpen={isOpenCorrectAnswer}
|
|
||||||
message='This answer is correct'
|
|
||||||
onDidDismiss={() => setIsOpenCorrectAnswer(false)}
|
|
||||||
duration={1000 - 100}
|
|
||||||
color='success'
|
|
||||||
></IonToast>
|
|
||||||
<IonToast
|
|
||||||
isOpen={isOpenWrongAnswer}
|
|
||||||
message='This answer is wrong'
|
|
||||||
onDidDismiss={() => setIsOpenWrongAnswer(false)}
|
|
||||||
duration={1000 - 100}
|
|
||||||
color='danger'
|
|
||||||
></IonToast> */}
|
|
||||||
</IonContent>
|
</IonContent>
|
||||||
</IonPage>
|
</IonPage>
|
||||||
</>
|
</>
|
||||||
|
@@ -8,6 +8,7 @@ import { ConnectiveRevisionAllResult } from '../../contexts/ConnectiveRevisionRa
|
|||||||
import { useMyIonQuizContext } from '../../contexts/MyIonQuiz';
|
import { useMyIonQuizContext } from '../../contexts/MyIonQuiz';
|
||||||
import IConnectivesRevisionCategory from '../../interfaces/IConnectivesRevisionCategory';
|
import IConnectivesRevisionCategory from '../../interfaces/IConnectivesRevisionCategory';
|
||||||
import { listConectivesRevisionContent } from '../../public_data/listConectivesRevisionContent';
|
import { listConectivesRevisionContent } from '../../public_data/listConectivesRevisionContent';
|
||||||
|
import useListQuizCRCategories from '../../hooks/useListQuizCRCategories';
|
||||||
|
|
||||||
function ConnectiveRevisionSelectCategory() {
|
function ConnectiveRevisionSelectCategory() {
|
||||||
const PAGE_TITLE = 'Connective Revision';
|
const PAGE_TITLE = 'Connective Revision';
|
||||||
@@ -17,12 +18,12 @@ function ConnectiveRevisionSelectCategory() {
|
|||||||
let [categories, setCategories] = useState<IConnectivesRevisionCategory[] | []>([]);
|
let [categories, setCategories] = useState<IConnectivesRevisionCategory[] | []>([]);
|
||||||
let { setTabActive, setConnectiveRevisionInProgress } = useAppStateContext();
|
let { setTabActive, setConnectiveRevisionInProgress } = useAppStateContext();
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
listConectivesRevisionContent().then((res_json) => {
|
// listConectivesRevisionContent().then((res_json) => {
|
||||||
setCategories(res_json);
|
// setCategories(res_json);
|
||||||
setLoading(false);
|
// setLoading(false);
|
||||||
});
|
// });
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
let { loadConnectiveRevisionScoreBoard } = useMyIonQuizContext();
|
let { loadConnectiveRevisionScoreBoard } = useMyIonQuizContext();
|
||||||
let [scoreboard_meta, setScoreboardMeta] = useState<ConnectiveRevisionAllResult>();
|
let [scoreboard_meta, setScoreboardMeta] = useState<ConnectiveRevisionAllResult>();
|
||||||
@@ -36,6 +37,14 @@ function ConnectiveRevisionSelectCategory() {
|
|||||||
setTabActive(QUIZ_MAIN_MENU_LINK);
|
setTabActive(QUIZ_MAIN_MENU_LINK);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
let result = useListQuizCRCategories();
|
||||||
|
useEffect(() => {
|
||||||
|
if (result.status === 'success') {
|
||||||
|
setCategories(result.data.items);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [result]);
|
||||||
|
|
||||||
if (loading) return <LoadingScreen />;
|
if (loading) return <LoadingScreen />;
|
||||||
if (!scoreboard_meta) return <LoadingScreen />;
|
if (!scoreboard_meta) return <LoadingScreen />;
|
||||||
|
|
||||||
@@ -87,9 +96,7 @@ function ConnectiveRevisionSelectCategory() {
|
|||||||
</div>
|
</div>
|
||||||
<div>{'Question Bank'}</div>
|
<div>{'Question Bank'}</div>
|
||||||
<div style={{ width: '80vw' }}>
|
<div style={{ width: '80vw' }}>
|
||||||
{categories
|
{categories.map((item, idx) => (
|
||||||
.map((item) => item.cat_name)
|
|
||||||
.map((item_name, idx) => (
|
|
||||||
<div style={{ margin: '0.9rem 0 0.9rem' }} key={idx}>
|
<div style={{ margin: '0.9rem 0 0.9rem' }} key={idx}>
|
||||||
<IonButton
|
<IonButton
|
||||||
color="dark"
|
color="dark"
|
||||||
@@ -97,7 +104,7 @@ function ConnectiveRevisionSelectCategory() {
|
|||||||
expand="block"
|
expand="block"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setConnectiveRevisionInProgress(true);
|
setConnectiveRevisionInProgress(true);
|
||||||
router.push(`${CONNECTIVE_REVISION_LINK}/r/${idx}`, 'none', 'replace');
|
router.push(`${CONNECTIVE_REVISION_LINK}/r/${item.id}`, 'none', 'replace');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -108,7 +115,7 @@ function ConnectiveRevisionSelectCategory() {
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>{item_name}</div>
|
<div>{item.cat_name}</div>
|
||||||
<div>
|
<div>
|
||||||
{scoreboard_meta[idx.toString()] || 0}
|
{scoreboard_meta[idx.toString()] || 0}
|
||||||
{'%'}
|
{'%'}
|
||||||
|
33
002_source/ionic_mobile/src/types/QuizCRQuestion.ts
Normal file
33
002_source/ionic_mobile/src/types/QuizCRQuestion.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Represents a Connectives Revision Quiz Question
|
||||||
|
*/
|
||||||
|
export interface QuizCRQuestion {
|
||||||
|
/** Unique identifier */
|
||||||
|
id: string;
|
||||||
|
/** Creation timestamp */
|
||||||
|
created: Date;
|
||||||
|
/** Last update timestamp */
|
||||||
|
updated: Date;
|
||||||
|
/** First half of the question */
|
||||||
|
question_fh: string;
|
||||||
|
/** Second half of the question */
|
||||||
|
question_sh: string;
|
||||||
|
/** Modal answer text */
|
||||||
|
modal_ans: string;
|
||||||
|
/** Initial answer text */
|
||||||
|
init_answer: string[];
|
||||||
|
/** Category ID reference */
|
||||||
|
cat_id: string;
|
||||||
|
/** Additional options in JSON format */
|
||||||
|
options: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expanded QuizCRQuestion with related category data
|
||||||
|
*/
|
||||||
|
export interface QuizCRQuestionExpanded extends QuizCRQuestion {
|
||||||
|
/** Category name */
|
||||||
|
cat_name?: string;
|
||||||
|
/** Category image */
|
||||||
|
cat_image?: string;
|
||||||
|
}
|
Reference in New Issue
Block a user