= ({
};
export default LessonContainer;
+
+// useEffect(() => {
+// listLessonCategories().then((cats: any) => {
+// console.log({ cats });
+// setLessonContent(cats);
+// setActiveLessonIdx(test_active_lesson_idx);
+// setLoading(false);
+// });
+// }, []);
+
+// useEffect(() => {
+// if (loading) return;
+// console.log('active_category changed', active_lesson_idx);
+// let selected_category = lesson_contents[test_active_lesson_idx];
+// setSelectedContent(selected_category['content']);
+// }, [active_lesson_idx, loading, test_active_lesson_idx]);
diff --git a/002_source/ionic_mobile/src/pages/Lesson/WordPage/index.tsx b/002_source/ionic_mobile/src/pages/Lesson/WordPage/index.tsx
index 5bede82..e2af3e6 100644
--- a/002_source/ionic_mobile/src/pages/Lesson/WordPage/index.tsx
+++ b/002_source/ionic_mobile/src/pages/Lesson/WordPage/index.tsx
@@ -36,8 +36,8 @@ import { UseQueryResult } from '@tanstack/react-query';
import { ListResult } from 'pocketbase';
import LessonsTypes from '../../../types/LessonsTypes';
-function WordPage(): React.JSX.Element {
- const [loading, setLoading] = useState(true);
+const WordPage: React.FC = () => {
+ const [loading, setLoading] = useState
(true);
const router = useIonRouter();
const modal = useRef(null);
@@ -45,6 +45,7 @@ function WordPage(): React.JSX.Element {
const [open_remove_modal, setOpenRemoveModal] = useState(false);
const [lesson_info, setLessonInfo] = useState(undefined);
+
const [cat_info, setCatInfo] = useState(undefined);
const [word_info, setWordInfo] = useState(undefined);
@@ -322,6 +323,6 @@ function WordPage(): React.JSX.Element {
{/* */}
>
);
-}
+};
export default WordPage;
diff --git a/002_source/ionic_mobile/src/pages/Lesson/index.tsx b/002_source/ionic_mobile/src/pages/Lesson/index.tsx
index a189692..309fb14 100644
--- a/002_source/ionic_mobile/src/pages/Lesson/index.tsx
+++ b/002_source/ionic_mobile/src/pages/Lesson/index.tsx
@@ -28,48 +28,19 @@ import LessonContainer from './LessonContainer';
import useHelloworld from '../../hooks/useHelloworld';
import useListAllLessonTypes from '../../hooks/useListAllLessonTypes';
import LessonsTypes, { LessonsType } from '../../types/LessonsTypes';
+import useListCategoriesByLessonId from '../../hooks/useListCategoriesByLessonId';
const Lesson: React.FC = () => {
const { act_category } = useParams<{ act_category: string }>();
const { t, i18n } = useTranslation(); // not passing any namespace will use the defaultNS (by default set to 'translation')
-
+ let router = useIonRouter();
let [loading, setLoading] = useState(true);
- let { lesson_contents: lesson_content, setLessonContent } = useMyIonStore();
let [active_lesson_idx, setActiveLessonIdx] = useState(0);
let [selected_content, setSelectedContent] = useState([]);
- // useEffect(() => {
- // listLessonCategories().then((cats: any) => {
- // console.log({ cats });
- // setLessonContent(cats);
- // setActiveLessonIdx(0);
- // setLoading(false);
- // });
- // }, []);
-
- useEffect(() => {
- if (loading) return;
- console.log('active_category changed', active_lesson_idx);
- let selected_category = lesson_content[active_lesson_idx];
- setSelectedContent(selected_category['content']);
- }, [active_lesson_idx, loading]);
-
- let router = useIonRouter();
- useEffect(() => {
- if (lesson_content.length > 0) {
- if (act_category == undefined) {
- router.push(`${LESSON_LINK}/a/${lesson_content[0].name}`, undefined, 'replace');
- } else {
- setActiveLessonIdx(
- lesson_content.findIndex((cat: any) => cat.name.toLowerCase() === act_category?.toLowerCase()),
- );
- }
- } else {
- }
- }, [act_category, lesson_content]);
-
const lessonTypesQuery = useListAllLessonTypes();
const [lessonTypes, setLessonTypes] = useState([]);
+
useEffect(() => {
if (lessonTypesQuery.status === 'success') {
const { data: tempLessonTypes } = lessonTypesQuery;
@@ -82,10 +53,8 @@ const Lesson: React.FC = () => {
}
}, [lessonTypesQuery]);
+ // return {JSON.stringify({ lessonTypes }, null, 2)}
;
if (loading) return ;
- if (lessonTypes.length === 0) return ;
-
- // return {JSON.stringify({ t: lessonTypes }, null, 2)}
;
return (
@@ -140,10 +109,12 @@ const Lesson: React.FC = () => {
{/* */}
-
+ {/* FIX: */}
+ {lessonTypes[active_lesson_idx]?.id ? (
+
+ ) : (
+ <>loading (id undefined)>
+ )}
{/* */}
@@ -156,3 +127,58 @@ const Lesson: React.FC = () => {
};
export default Lesson;
+
+// let { lesson_contents: lesson_content, setLessonContent } = useMyIonStore();
+
+// // TODO: remove me
+// // useEffect(() => {
+// // listLessonCategories().then((cats: any) => {
+// // console.log({ cats });
+// // setLessonContent(cats);
+// // setActiveLessonIdx(0);
+// // setLoading(false);
+// // });
+// // }, []);
+
+// useEffect(() => {
+// if (loading) return;
+// console.log('active_category changed', lesson_content[active_lesson_idx]);
+// // FIX:
+// // let selected_category = lesson_content[active_lesson_idx];
+// // setSelectedContent(selected_category['content']);
+
+// // let categories = await getCategoryByLessonType(lessonType)
+// //
+// // useListCategoriesByLessonType(lessonType)
+// }, [active_lesson_idx, loading]);
+
+// useEffect(() => {
+// if (lesson_content.length > 0) {
+// if (act_category == undefined) {
+// router.push(`${LESSON_LINK}/a/${lesson_content[0].name}`, undefined, 'replace');
+// } else {
+// setActiveLessonIdx(
+// lesson_content.findIndex((cat: any) => cat.name.toLowerCase() === act_category?.toLowerCase()),
+// );
+// }
+// } else {
+// }
+// }, [act_category, lesson_content]);
+
+// const lessonTypesQuery = useListAllLessonTypes();
+// const [lessonTypes, setLessonTypes] = useState
([]);
+// useEffect(() => {
+// if (lessonTypesQuery.status === 'success') {
+// const { data: tempLessonTypes } = lessonTypesQuery;
+// console.log({ tempLessonTypes });
+// if (tempLessonTypes) {
+// setLessonTypes(tempLessonTypes);
+// }
+
+// setLoading(false);
+// }
+// }, [lessonTypesQuery]);
+
+// if (loading) return ;
+// // return {JSON.stringify({ t: lessonTypes }, null, 2)}
;
+// if (lessonTypes.length === 0) return ;
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/AudioControls.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/AudioControls.tsx
similarity index 100%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/AudioControls.tsx
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/AudioControls.tsx
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/CorrectionCard.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/CorrectionCard.tsx
similarity index 100%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/CorrectionCard.tsx
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/CorrectionCard.tsx
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/CorrectionRoute.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/CorrectionRoute.tsx
similarity index 98%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/CorrectionRoute.tsx
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/CorrectionRoute.tsx
index b6a46f3..4714188 100644
--- a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/CorrectionRoute.tsx
+++ b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/CorrectionRoute.tsx
@@ -16,6 +16,9 @@ import CorrectionCard from './CorrectionCard';
import './style.css';
const CorrectionRoute: React.FC = () => {
+ // TODO: not yet implemented
+ return <>not yet implemented>;
+
const router = useIonRouter();
const { p_route } = useParams<{ p_route: string }>();
const i_p_route = parseInt(p_route);
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/ListeningPracticeQuestionCard.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/ListeningPracticeQuestionCard.tsx
similarity index 100%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/ListeningPracticeQuestionCard.tsx
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/ListeningPracticeQuestionCard.tsx
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/index.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/index.tsx
similarity index 83%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/index.tsx
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/index.tsx
index ed3c47a..8459d09 100644
--- a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/index.tsx
+++ b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/index.tsx
@@ -10,8 +10,10 @@ import IListeningPracticeQuestion from '../../../interfaces/IListeningPracticeQu
import { listQuizListeningPracticeContent } from '../../../public_data/listQuizListeningPracticeContent';
import { shuffleArray } from '../../../utils/shuffleArray';
import ListeningPracticeQuestionCard from './ListeningPracticeQuestionCard';
+import useListQuizLPQuestionByLPCategoryId from '../../../hooks/useListQuizLPQuestionByLPCategoryId';
const QuestionRoute: React.FC = () => {
+ const router = useIonRouter();
const { p_route } = useParams<{ p_route: string }>();
const i_p_route = parseInt(p_route);
const [question_list, setQuestionList] = useState([]);
@@ -26,7 +28,7 @@ const QuestionRoute: React.FC = () => {
const { listening_practice_correction_list, setListeningPracticeCorrectionList } = useMyIonQuizContext();
const [question_finished, setQuestionFinished] = useState(false);
- const router = useIonRouter();
+ let [answer_list, setAnswerList] = useState([]);
const nextQuestion = () => {
if (current_question_idx >= question_list.length - 1) {
setQuestionFinished(true);
@@ -64,21 +66,27 @@ const QuestionRoute: React.FC = () => {
myIonMetricIncFullMarkCount();
};
- let [answer_list, setAnswerList] = useState([]);
-
+ let [questionList, setLPQuestionList] = useState([]);
useEffect(() => {
- (async () => {
- const res_json = await listQuizListeningPracticeContent();
-
- let init_answer = res_json[i_p_route].init_answer;
- let temp = res_json[i_p_route].content;
+ if (questionList.length > 0) {
+ let temp = questionList;
+ let init_answer = temp[0].init_answer;
let shuffled_temp = shuffleArray(temp);
-
+ //
setQuestionList(shuffled_temp);
- setAnswerList([...new Set([...init_answer, ...temp.map((t: IListeningPracticeQuestion) => t.word)])]);
- setCurrentQuestionMeta(res_json[i_p_route].content[current_question_idx]);
- })();
- }, []);
+ setAnswerList([...new Set([...init_answer, ...temp.map((t) => t.word)])]);
+ setCurrentQuestionMeta(temp[current_question_idx] as unknown as IListeningPracticeQuestion);
+ // console.log({ t: result.data.items[0] });
+ }
+ }, [questionList]);
+
+ let result = useListQuizLPQuestionByLPCategoryId(p_route);
+ useEffect(() => {
+ if (result.status === 'success') {
+ //
+ setLPQuestionList(result.data.items);
+ }
+ }, [result]);
if (!current_question_meta) return ;
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/style.css b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/style.css
similarity index 100%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/style.css
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/style.css
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/Route/test.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/test.tsx
similarity index 100%
rename from 002_source/ionic_mobile/src/pages/ListeningPractice/Route/test.tsx
rename to 002_source/ionic_mobile/src/pages/ListeningPractice/QuestionRoute/test.tsx
diff --git a/002_source/ionic_mobile/src/pages/ListeningPractice/index.tsx b/002_source/ionic_mobile/src/pages/ListeningPractice/index.tsx
index 8c90371..6c47532 100644
--- a/002_source/ionic_mobile/src/pages/ListeningPractice/index.tsx
+++ b/002_source/ionic_mobile/src/pages/ListeningPractice/index.tsx
@@ -8,6 +8,7 @@ import { useAppStateContext } from '../../contexts/AppState';
import IListeningPracticeCategory from '../../interfaces/IListeningPracticeCategory';
import { listQuizListeningPracticeContent } from '../../public_data/listQuizListeningPracticeContent';
import { useTranslation } from 'react-i18next';
+import useListQuizListeningPracticeContent from '../../hooks/useListQuizListeningPracticeContent';
// import { listQuizListeningPracticeContent } from '../../public_data/listQuizListeningPracticeContent';
@@ -17,19 +18,27 @@ const ListeningPractice: React.FC = () => {
let [categories, setCategories] = useState([]);
let { show_confirm_user_exit, setShowConfirmUserExit, setTabActive } = useAppStateContext();
+ // useEffect(() => {
+ // listQuizListeningPracticeContent().then((res_json: any) => {
+ // setCategories(res_json);
+ // DEBUG ? console.log({ res_json }) : '';
+ // setLoading(false);
+ // });
+ // setTabActive(QUIZ_MAIN_MENU_LINK);
+ // }, []);
+
+ let result = useListQuizListeningPracticeContent();
useEffect(() => {
- listQuizListeningPracticeContent().then((res_json: any) => {
- setCategories(res_json);
- DEBUG ? console.log({ res_json }) : '';
+ if (result.status == 'success') {
+ setCategories(result.data.items);
setLoading(false);
- });
- setTabActive(QUIZ_MAIN_MENU_LINK);
- }, []);
+ }
+ }, [result]);
let { setListeningPracticeInProgress } = useAppStateContext();
let router = useIonRouter();
function startListeningPractice(idx: number) {
- let url = `${LISTENING_PRACTICE_LINK}/r/${idx}`;
+ let url = `${LISTENING_PRACTICE_LINK}/r/${categories[idx].id}`;
setListeningPracticeInProgress(true);
router.push(url, 'none', 'replace');
}
@@ -38,6 +47,8 @@ const ListeningPractice: React.FC = () => {
if (loading) return ;
+ // return <>{JSON.stringify({ categories }, null, 2)}>;
+
return (
diff --git a/002_source/ionic_mobile/src/pages/MatchingFrenzy/SelectCategory.tsx b/002_source/ionic_mobile/src/pages/MatchingFrenzy/SelectCategory.tsx
index 6a61477..cf3c7f8 100644
--- a/002_source/ionic_mobile/src/pages/MatchingFrenzy/SelectCategory.tsx
+++ b/002_source/ionic_mobile/src/pages/MatchingFrenzy/SelectCategory.tsx
@@ -6,23 +6,38 @@ import { DEBUG, MATCHING_FRENZY_LINK, QUIZ_MAIN_MENU_LINK } from '../../constant
import { useAppStateContext } from '../../contexts/AppState';
import IMatchingFrenzyCategory from '../../interfaces/IMatchingFrenzyCategory';
import { listMatchingFrenzyContent } from '../../public_data/listMatchingFrenzyContent';
+import useListMatchingFrenzyCategories from '../../hooks/useListMatchingFrenzyContent';
function MatchingFrenzySelectCategory() {
const PAGE_TITLE = 'Matching Frenzy';
const router = useIonRouter();
const [loading, setLoading] = useState(true);
const [categories, setCategories] = useState([]);
+ const [loadedCategories, setLoadedCategories] = useState([]);
const { setTabActive } = useAppStateContext();
- useEffect(() => {
- listMatchingFrenzyContent().then((res_json: any) => {
- setCategories(res_json);
- DEBUG ? console.log({ res_json }) : '';
- setLoading(false);
- });
+ // useEffect(() => {
+ // listMatchingFrenzyContent().then((res_json: any) => {
+ // setCategories(res_json);
+ // DEBUG ? console.log({ res_json }) : '';
+ // setLoading(false);
+ // });
- setTabActive(QUIZ_MAIN_MENU_LINK);
- }, []);
+ // setTabActive(QUIZ_MAIN_MENU_LINK);
+ // }, []);
+
+ let [temp, setTemp] = useState();
+ let result = useListMatchingFrenzyCategories();
+ useEffect(() => {
+ if (result.status === 'success') {
+ // setCategories(result.data.items);
+ // setTemp(result.data.items)
+ setLoadedCategories(result.data.items);
+ setLoading(false);
+ }
+ }, [result]);
+
+ // return <>helloworld>;
if (loading) return ;
@@ -75,23 +90,26 @@ function MatchingFrenzySelectCategory() {
- {categories
+ {loadedCategories
.map((item) => item.cat_name)
- .map((item_name, idx) => (
-
- {
- router.push(`${MATCHING_FRENZY_LINK}/r/${idx}`);
- }}
- >
- {item_name}
-
-
- ))}
+ .map((item_name, idx) => {
+ let mf_idx = loadedCategories[idx].id;
+ return (
+
+ {
+ router.push(`${MATCHING_FRENZY_LINK}/r/${mf_idx}`);
+ }}
+ >
+ {item_name}
+
+
+ );
+ })}
diff --git a/002_source/ionic_mobile/src/types/CategoryTypes.ts b/002_source/ionic_mobile/src/types/CategoryTypes.ts
new file mode 100644
index 0000000..2bd1b5d
--- /dev/null
+++ b/002_source/ionic_mobile/src/types/CategoryTypes.ts
@@ -0,0 +1,8 @@
+export interface CategoryType {
+ id: string;
+ name: string;
+ lessonType: string;
+ created: string;
+ updated: string;
+ // Add other fields as needed based on actual database schema
+}
diff --git a/002_source/ionic_mobile/src/types/MatchingFrenzyCategory.d.ts b/002_source/ionic_mobile/src/types/MatchingFrenzyCategory.d.ts
new file mode 100644
index 0000000..0f4538d
--- /dev/null
+++ b/002_source/ionic_mobile/src/types/MatchingFrenzyCategory.d.ts
@@ -0,0 +1,16 @@
+type MatchingFrenzyCategory = {
+ //
+ id: string;
+ collectionId: string;
+ //
+ cat_name: string;
+ cat_image_url?: string;
+ cat_image?: string;
+ pos: number;
+ visible: string;
+ lesson_id: string;
+ description: string;
+ remarks: string;
+ slug: string;
+ init_answer: any;
+};
diff --git a/002_source/ionic_mobile/src/types/QuizLPQuestion.d.ts b/002_source/ionic_mobile/src/types/QuizLPQuestion.d.ts
new file mode 100644
index 0000000..0403535
--- /dev/null
+++ b/002_source/ionic_mobile/src/types/QuizLPQuestion.d.ts
@@ -0,0 +1,20 @@
+// QuizLPQuestion
+type QuizLPQuestion = {
+ //
+ id: string;
+ collectionId: string;
+ //
+ word: string;
+ //
+ cat_name: string;
+ cat_image_url?: string;
+ cat_image?: string;
+ pos: number;
+ visible: string;
+ lesson_id: string;
+ description: string;
+ remarks: string;
+ slug: string;
+ init_answer: any;
+ //
+};
diff --git a/002_source/ionic_mobile/src/types/QuizLPQuestion.dbml b/002_source/ionic_mobile/src/types/QuizLPQuestion.dbml
new file mode 100644
index 0000000..89fcd57
--- /dev/null
+++ b/002_source/ionic_mobile/src/types/QuizLPQuestion.dbml
@@ -0,0 +1,22 @@
+Table QuizLPQuestion {
+ id string [primary key]
+ collectionId string
+ createdAt datetime
+
+ questionText text
+ audioUrl string
+ options json
+ correctAnswer integer
+ LPCategoryId string [ref: > QuizLPCategory.id]
+ difficulty enum('easy', 'medium', 'hard')
+ explanation text [null]
+ status enum('draft', 'published', 'archived')
+
+ indexes {
+ LPCategoryId
+ status
+ createdAt
+ }
+
+ Note: 'Stores listening practice quiz questions'
+}
diff --git a/002_source/ionic_mobile/src/types/_GUIDELINES.md b/002_source/ionic_mobile/src/types/_GUIDELINES.md
new file mode 100644
index 0000000..1324714
--- /dev/null
+++ b/002_source/ionic_mobile/src/types/_GUIDELINES.md
@@ -0,0 +1,3 @@
+# GUIDELINES
+
+- please follow to the `schema.dbml` when you draft types related to db
diff --git a/002_source/ionic_mobile/src/utils/getImage.ts b/002_source/ionic_mobile/src/utils/getImage.ts
new file mode 100644
index 0000000..330fe1d
--- /dev/null
+++ b/002_source/ionic_mobile/src/utils/getImage.ts
@@ -0,0 +1,6 @@
+import { POCKETBASE_URL } from '../constants';
+
+export function getImage(collectionId: string, recordId: string, fileName: string) {
+ console.log({ collectionId, recordId, fileName });
+ return `${POCKETBASE_URL}/api/files/${collectionId}/${recordId}/${fileName}`;
+}