diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/_examples/001_clone.md b/002_source/cms/_AI_WORKSPACE_obsoleted/_examples/001_clone.md deleted file mode 100644 index f508e25..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/_examples/001_clone.md +++ /dev/null @@ -1,18 +0,0 @@ -please review and update all tsx files in folder `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/db/Users` to make it handle `user` record thanks - ---- - -please modify and update `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/students/edit/[customerId]/page.tsx.draft` to handle `Student` record thanks, -modify comments/variables/paths/functions name please - ---- - -please help to update the tsx files inside folder `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/components/dashboard/student` to handle the `student` record - -## steps - -- list all `tsx` files inside directory, remember the list -- clone the original `.tsx` files to `.tsx.draft` -- do all your modification within `.tsx.draft` files, leave `original.tsx` unchange - ---- diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/_examples/003_update_dbml_from_schema.md b/002_source/cms/_AI_WORKSPACE_obsoleted/_examples/003_update_dbml_from_schema.md deleted file mode 100644 index c75e8e2..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/_examples/003_update_dbml_from_schema.md +++ /dev/null @@ -1,33 +0,0 @@ -Hi, i need your help. - -## task - -i am working on a `dbml` file -i got a `schema.json` which is exported from pocketbase -and i want to update it to my current `dbml` file (one way process for documentation usage) - -## Rules - -- the collection from `json` file started with `_` can be ignored. they are system collection and should not appear in `dbml` -- one collection from `json` file mapped with one table in `dbml` file -- the `presentable` field from `json` file should be ignored. -- the `id` of collection in `json` file should be jod down in the comment of `dbml` file as an reference. -- you can find the comments in `schema.dbml` contains `pb_xxx` and that is the reference to the table in `schema.json` file. - -## steps - -- list the collection - -## information - -json file: `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema.json` -dbml file: `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema.dbml` - -## FAQ - -1. 对于json中有但dbml中没有的表,应该如何处理? 添加为新表 -1. 是否需要保留dbml文件中现有的注释和关系定义? 完全保留 -1. 字段类型映射是否有特殊规则? 沒有 -1. please keep the existing comment - -thanks diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/0010_FAQ.md b/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/0010_FAQ.md deleted file mode 100644 index 78ce37a..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/0010_FAQ.md +++ /dev/null @@ -1,7 +0,0 @@ -# FAQ - -Q: where is `dbml` file ? -A: dbml file located in `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema.dbml` - -Q: when file not found, do i need to search it in `_ignore_this_directory` ? -A: No, you just stop there and voice out. diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/001_greetings.md b/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/001_greetings.md deleted file mode 100644 index 21dcb1f..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/001_greetings.md +++ /dev/null @@ -1,8 +0,0 @@ -Hi, i will send you the guideline, -plesae read it, prepare yourself and i will tell you the task afterwards - -please read and understand the markdown files in directory -`/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/_AI_WORKSPACE/greetings`, -it provides background information of project i want you to help. - -thanks diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/002_guideline.md b/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/002_guideline.md deleted file mode 100644 index 6a94824..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/002_guideline.md +++ /dev/null @@ -1,28 +0,0 @@ -# guideline - -## principles - -- at any time, please keep your answer, solution, explaination simple and short (K.I.S.S. or 大道至簡) -- please divide the problem into small parts -- if you found youself cannot understand the problem, please stop and ask how to do -- if you found youself cannot solve the problem, plesae stop and ask how to do -- review the whole solution before you reply to user -- if code syntax is already there, do follow (e.g. naming convention, syntax) the existing code -- no need to explain the reason until you are told to do so -- no need to show me the code change, at the end just simple summary in point form is ok - -## highlighted project directories and their meanings - -- `_ignore_this_directory` please ignore this directory and any files inside it - -- `001_documentation` documentation of this project -- `002_source` source code of this project -- `002_source/cms` home of Context management system of this project -- `002_source/ionic` home of mobile client of this project -- `002_source/pocketbase` home of pocketbase home directory this project -- `003_test` e2e test of this project (not yet implemented) -- `004_marketing` marketing page of this project (not yet implemented) -- `005_references` opensource refence of this project -- `006_lab` my test (POC) of this project -- `README.md` Readme of this project -- `TODO.md` todo list of this project diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/003_knowledgebase.md b/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/003_knowledgebase.md deleted file mode 100644 index ad12950..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/003_knowledgebase.md +++ /dev/null @@ -1,12 +0,0 @@ -# Knowledgebase - -you can answer the question with below knowledge: - -## frameworks and stacks - -- if code syntax is already there, do follow (e.g. naming convention, syntax) the existing code -- make use of MCP `Context7` when you troubleshoot the problem with below topics: - - [pocketbase javascript SDK](https://context7.com/pocketbase/js-sdk/llms.txt) - - [DBML](https://context7.com/holistics/dbml/llms.txt) - - [ionic framework](https://context7.com/ionic-team/ionic-framework/llms.txt) - - [nextjs 14 app router](https://context7.com/nextjsargentina/next.js-docs/llms.txt) diff --git a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/013_DB.md b/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/013_DB.md deleted file mode 100644 index 1b15799..0000000 --- a/002_source/cms/_AI_WORKSPACE_obsoleted/greetings/013_DB.md +++ /dev/null @@ -1,48 +0,0 @@ -# AI GUIDELINE - -## getting started - -Imagine there is a: - -1. developer (provide the modification) -2. QA engineer (provide the feedback, and testing) -3. software engineer -4. technical writer - -they will: - -- conclude and integrate the ideas from developer and QA engineer -- make decision to modify the code accordingly. - -## project background and initial setup - -- **IMPORTANT**: No need to reply me what you are going on and your digest in this phase. - No need to show me your code plan - Just reply me "OK" when done - -- base_dir=`/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project` - -- `schema.dbml` - - read `/001_documentation/Requirements/REQ0006/schema.dbml` - this is file in `dbml` format stating the main database structure - -- `schema.json` - - read `/002_source/cms/src/db/schema.json` - this is the file of current pocketbase schema - -- look into the md files in folder `/002_source/ionic_mobile/_AI_WORKSPACE/001_guideline` - -- if the directory user provided contins `_GUIDELINES.md`, please read the file - -- read the files, remember and link up the ideas in file stated above, i will tell them the task afterwards - -- please review at least 3 times after you modified the code - -## frameworks documentation and samples - -- react -- ionic and capacitor -- pocketbase -- tanstack/react-query -- vite -- typescript diff --git a/002_source/cms/public/locales/de/teachers.json b/002_source/cms/public/locales/de/teachers.json new file mode 100644 index 0000000..8ac3124 --- /dev/null +++ b/002_source/cms/public/locales/de/teachers.json @@ -0,0 +1,3 @@ +{ + "back-to-list": "Teachers" +} diff --git a/002_source/cms/public/locales/de/translation.json b/002_source/cms/public/locales/de/translation.json index e3e4482..ec3d519 100644 --- a/002_source/cms/public/locales/de/translation.json +++ b/002_source/cms/public/locales/de/translation.json @@ -1,3 +1,6 @@ { - "languageChanged": "Sprache geändert" + "languageChanged": "Sprache geändert", + "teachers": { + "back-to-list": "Lehrer" + } } diff --git a/002_source/cms/public/locales/dev/common.json b/002_source/cms/public/locales/dev/common.json index eeedd40..7eab942 100644 --- a/002_source/cms/public/locales/dev/common.json +++ b/002_source/cms/public/locales/dev/common.json @@ -1,3 +1,4 @@ { - "hello": "world" -} \ No newline at end of file + "hello": "world", + "teachers": "teachers" +} diff --git a/002_source/cms/public/locales/dev/teachers.json b/002_source/cms/public/locales/dev/teachers.json new file mode 100644 index 0000000..8ac3124 --- /dev/null +++ b/002_source/cms/public/locales/dev/teachers.json @@ -0,0 +1,3 @@ +{ + "back-to-list": "Teachers" +} diff --git a/002_source/cms/public/locales/en/teachers.json b/002_source/cms/public/locales/en/teachers.json new file mode 100644 index 0000000..8ac3124 --- /dev/null +++ b/002_source/cms/public/locales/en/teachers.json @@ -0,0 +1,3 @@ +{ + "back-to-list": "Teachers" +} diff --git a/002_source/cms/public/locales/en/translation.json b/002_source/cms/public/locales/en/translation.json index 069eb58..edaaf49 100644 --- a/002_source/cms/public/locales/en/translation.json +++ b/002_source/cms/public/locales/en/translation.json @@ -1,3 +1,7 @@ { - "languageChanged": "Language changed" + "languageChanged": "Language changed", + "teachers": { + "nav-title": "teachers", + "back-to-list": "Teachers" + } } diff --git a/002_source/cms/public/locales/es/teachers.json b/002_source/cms/public/locales/es/teachers.json new file mode 100644 index 0000000..8ac3124 --- /dev/null +++ b/002_source/cms/public/locales/es/teachers.json @@ -0,0 +1,3 @@ +{ + "back-to-list": "Teachers" +} diff --git a/002_source/cms/public/locales/es/translation.json b/002_source/cms/public/locales/es/translation.json index 1a632be..ef15bd9 100644 --- a/002_source/cms/public/locales/es/translation.json +++ b/002_source/cms/public/locales/es/translation.json @@ -1,3 +1,6 @@ { - "languageChanged": "Idioma cambiado" + "languageChanged": "Idioma cambiado", + "teachers": { + "back-to-list": "Profesores" + } } diff --git a/002_source/cms/src/app/dashboard/students/create/_PROMPT.md b/002_source/cms/src/app/dashboard/students/create/_PROMPT.md new file mode 100644 index 0000000..8a841ff --- /dev/null +++ b/002_source/cms/src/app/dashboard/students/create/_PROMPT.md @@ -0,0 +1,3 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/students/create/page.tsx.draft` to handle `Student` record thanks, modify comments/variables/paths/functions name please + +e.g. why `lessonCategories` still exist ? diff --git a/002_source/cms/src/app/dashboard/students/edit/[customerId]/_PROMPT.md b/002_source/cms/src/app/dashboard/students/edit/[customerId]/_PROMPT.md new file mode 100644 index 0000000..b66946e --- /dev/null +++ b/002_source/cms/src/app/dashboard/students/edit/[customerId]/_PROMPT.md @@ -0,0 +1 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/students/edit/[customerId]/page.tsx.draft` to handle `Student` record thanks, modify comments/variables/paths/functions name please \ No newline at end of file diff --git a/002_source/cms/src/app/dashboard/students/list/_PROMPT.md b/002_source/cms/src/app/dashboard/students/list/_PROMPT.md new file mode 100644 index 0000000..08ecda8 --- /dev/null +++ b/002_source/cms/src/app/dashboard/students/list/_PROMPT.md @@ -0,0 +1,3 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/students/list/page.tsx.draft` to handle `Student` record thanks, modify comments/variables/paths/functions name please + +e.g. why `lessonCategories` still exist ? diff --git a/002_source/cms/src/app/dashboard/students/list/page.tsx b/002_source/cms/src/app/dashboard/students/list/page.tsx index fd68afb..9797d60 100644 --- a/002_source/cms/src/app/dashboard/students/list/page.tsx +++ b/002_source/cms/src/app/dashboard/students/list/page.tsx @@ -3,11 +3,10 @@ // RULES: // contains list page for students (Students) -// contain definition to collection only // import * as React from 'react'; import { useRouter } from 'next/navigation'; -import { COL_STUDENTS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; import { LoadingButton } from '@mui/lab'; import Box from '@mui/material/Box'; import Card from '@mui/material/Card'; @@ -38,8 +37,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { const { email, phone, sortDir, status } = searchParams; - const [lessonCategoriesData, setLessonCategoriesData] = React.useState([]); - // + const [studentsData, setStudentsData] = React.useState([]); const [isLoadingAddPage, setIsLoadingAddPage] = React.useState(false); const [showLoading, setShowLoading] = React.useState(true); @@ -51,24 +49,31 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { const [currentPage, setCurrentPage] = React.useState(0); // const [recordCount, setRecordCount] = React.useState(0); - const [listOption, setListOption] = React.useState({}); + const [listOption, setListOption] = React.useState({ filter: '' }); + const [listSort, setListSort] = React.useState({}); + function isListOptionChanged(): boolean { + return JSON.stringify(listOption) === JSON.stringify({ filter: '' }); + } // const reloadRows = async (): Promise => { try { + const listOptionTeacherOnly = isListOptionChanged() + ? { filter: `role = "student"` } + : { filter: [listOption.filter, `role = "student"`].join(' && ') }; + const models: ListResult = await pb - .collection(COL_STUDENTS) - .getList(currentPage + 1, rowsPerPage, listOption); + .collection(COL_USER_METAS) + .getList(currentPage + 1, rowsPerPage, listOptionTeacherOnly); const { items, totalItems } = models; - const tempLessonTypes: Student[] = items.map((lt) => { + const tempStudents: Student[] = items.map((lt) => { return { ...defaultStudent, ...lt }; }); - setLessonCategoriesData(tempLessonTypes); + setStudentsData(tempStudents); setRecordCount(totalItems); - setF(tempLessonTypes); + setF(tempStudents); } catch (error) { - // logger.error(error); setShowError({ // @@ -110,11 +115,12 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { if (email) { tempFilter.push(`email ~ "%${email}%"`); } + if (phone) { tempFilter.push(`phone ~ "%${phone}%"`); } - let preFinalListOption = {}; + let preFinalListOption = { filter: '' }; if (tempFilter.length > 0) { preFinalListOption = { filter: tempFilter.join(' && ') }; } @@ -158,7 +164,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { loading={isLoadingAddPage} onClick={(): void => { setIsLoadingAddPage(true); - router.push(paths.dashboard.customers.create); + router.push(paths.dashboard.students.create); }} startIcon={} variant="contained" @@ -167,11 +173,11 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { - + diff --git a/002_source/cms/src/app/dashboard/students/view/[customerId]/BasicDetailCard.tsx b/002_source/cms/src/app/dashboard/students/view/[id]/BasicDetailCard.tsx similarity index 97% rename from 002_source/cms/src/app/dashboard/students/view/[customerId]/BasicDetailCard.tsx rename to 002_source/cms/src/app/dashboard/students/view/[id]/BasicDetailCard.tsx index e64427e..dc23bc3 100644 --- a/002_source/cms/src/app/dashboard/students/view/[customerId]/BasicDetailCard.tsx +++ b/002_source/cms/src/app/dashboard/students/view/[id]/BasicDetailCard.tsx @@ -17,10 +17,10 @@ import { PropertyList } from '@/components/core/property-list'; import type { Student } from '@/components/dashboard/student/type.d'; export default function BasicDetailCard({ - lpModel: model, + studentRecord: model, handleEditClick, }: { - lpModel: Student; + studentRecord: Student; handleEditClick: () => void; }): React.JSX.Element { const { t } = useTranslation(); diff --git a/002_source/cms/src/app/dashboard/students/view/[customerId]/TitleCard.tsx b/002_source/cms/src/app/dashboard/students/view/[id]/TitleCard.tsx similarity index 72% rename from 002_source/cms/src/app/dashboard/students/view/[customerId]/TitleCard.tsx rename to 002_source/cms/src/app/dashboard/students/view/[id]/TitleCard.tsx index 9be2807..33aba02 100644 --- a/002_source/cms/src/app/dashboard/students/view/[customerId]/TitleCard.tsx +++ b/002_source/cms/src/app/dashboard/students/view/[id]/TitleCard.tsx @@ -13,13 +13,11 @@ import type { Student } from '@/components/dashboard/student/type.d'; // import type { CrCategory } from '@/components/dashboard/cr/categories/type'; -function getImageUrlFrRecord(record: Student): string { - // TODO: fix this - // `http://127.0.0.1:8090/api/files/${'record.collectionId'}/${'record.id'}/${'record.cat_image'}`; - return 'getImageUrlFrRecord(helloworld)'; +function getImageUrlForStudent(student: Student): string { + return `http://127.0.0.1:8090/api/files/${student.collectionId}/${student.id}/${student.avatar}`; } -export default function SampleTitleCard({ lpModel }: { lpModel: Student }): React.JSX.Element { +export default function SampleTitleCard({ studentRecord }: { studentRecord: Student }): React.JSX.Element { const { t } = useTranslation(); return ( @@ -31,7 +29,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: Student }): Reac > {t('empty')} @@ -42,7 +40,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: Student }): Reac spacing={2} sx={{ alignItems: 'center', flexWrap: 'wrap' }} > - {lpModel.email} + {studentRecord.name || studentRecord.email} } - label={lpModel.quota} + label={studentRecord.status} size="small" variant="outlined" /> - - {lpModel.status} -
diff --git a/002_source/cms/src/app/dashboard/students/view/[id]/_PROMPT.md b/002_source/cms/src/app/dashboard/students/view/[id]/_PROMPT.md new file mode 100644 index 0000000..b1fd110 --- /dev/null +++ b/002_source/cms/src/app/dashboard/students/view/[id]/_PROMPT.md @@ -0,0 +1,3 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/students/view/[customerId]/page.tsx.draft` to handle `Student` record thanks, modify comments/variables/paths/functions name please + +e.g. update `lpModel` names diff --git a/002_source/cms/src/app/dashboard/students/view/[customerId]/page.tsx b/002_source/cms/src/app/dashboard/students/view/[id]/page.tsx similarity index 85% rename from 002_source/cms/src/app/dashboard/students/view/[customerId]/page.tsx rename to 002_source/cms/src/app/dashboard/students/view/[id]/page.tsx index 5362910..bcc3ce4 100644 --- a/002_source/cms/src/app/dashboard/students/view/[customerId]/page.tsx +++ b/002_source/cms/src/app/dashboard/students/view/[id]/page.tsx @@ -30,29 +30,29 @@ import BasicDetailCard from './BasicDetailCard'; import TitleCard from './TitleCard'; import { defaultStudent } from '@/components/dashboard/student/_constants'; import type { Student } from '@/components/dashboard/student/type.d'; -import { COL_STUDENTS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; export default function Page(): React.JSX.Element { const { t } = useTranslation(); const router = useRouter(); // - const { customerId } = useParams<{ customerId: string }>(); + const { id: studentId } = useParams<{ id: string }>(); // const [showLoading, setShowLoading] = React.useState(true); const [showError, setShowError] = React.useState({ show: false, detail: '' }); // - const [showLessonCategory, setShowLessonCategory] = React.useState(defaultStudent); + const [studentRecord, setStudentRecord] = React.useState(defaultStudent); function handleEditClick(): void { - router.push(paths.dashboard.students.edit(showLessonCategory.id)); + router.push(paths.dashboard.students.edit(studentRecord.id)); } React.useEffect(() => { - if (customerId) { - pb.collection(COL_STUDENTS) - .getOne(customerId) + if (studentId) { + pb.collection(COL_USER_METAS) + .getOne(studentId) .then((model: RecordModel) => { - setShowLessonCategory({ ...defaultStudent, ...model }); + setStudentRecord({ ...defaultStudent, ...model }); }) .catch((err) => { logger.error(err); @@ -64,9 +64,9 @@ export default function Page(): React.JSX.Element { setShowLoading(false); }); } - }, [customerId]); + }, [studentId]); - // return <>{JSON.stringify({ showError, showLessonCategory }, null, 2)}; + // return <>{JSON.stringify({ showError, studentRecord }, null, 2)}; if (showLoading) return ; if (showError.show) @@ -106,7 +106,7 @@ export default function Page(): React.JSX.Element { spacing={3} sx={{ alignItems: 'flex-start' }} > - + diff --git a/002_source/cms/src/app/dashboard/teachers/list/_PROMPT.md b/002_source/cms/src/app/dashboard/teachers/list/_PROMPT.md new file mode 100644 index 0000000..3e3b1e2 --- /dev/null +++ b/002_source/cms/src/app/dashboard/teachers/list/_PROMPT.md @@ -0,0 +1,3 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/teachers/list/page.tsx.draft` to handle `Teacher` record thanks, modify comments/variables/paths/functions name please + +e.g. why `lessonCategories` still exist ? diff --git a/002_source/cms/src/app/dashboard/teachers/list/page.tsx b/002_source/cms/src/app/dashboard/teachers/list/page.tsx index 326c32e..c16289d 100644 --- a/002_source/cms/src/app/dashboard/teachers/list/page.tsx +++ b/002_source/cms/src/app/dashboard/teachers/list/page.tsx @@ -37,7 +37,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { const { email, phone, sortDir, status } = searchParams; - const [lessonCategoriesData, setLessonCategoriesData] = React.useState([]); + const [teacherData, setTeacherData] = React.useState([]); const [isLoadingAddPage, setIsLoadingAddPage] = React.useState(false); const [showLoading, setShowLoading] = React.useState(true); @@ -53,7 +53,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { const [listSort, setListSort] = React.useState({}); function isListOptionChanged() { - return JSON.stringify(listOption) === '{}'; + return JSON.stringify(listOption) === JSON.stringify({ filter: '' }); } // const reloadRows = async (): Promise => { @@ -62,6 +62,8 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { ? { filter: `role = "teacher"` } : { filter: [listOption.filter, `role = "teacher"`].join(' && ') }; + console.log({ listOptionTeacherOnly }); + const models: ListResult = await pb .collection(COL_USER_METAS) .getList(currentPage + 1, rowsPerPage, listOptionTeacherOnly); @@ -70,12 +72,13 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { return { ...defaultTeacher, ...lt }; }); - setLessonCategoriesData(tempTeacher); + setTeacherData(tempTeacher); setRecordCount(totalItems); setF(tempTeacher); } catch (error) { logger.error(error); setShowError({ + // show: true, detail: JSON.stringify(error, null, 2), }); @@ -100,8 +103,8 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { }, [currentPage, rowsPerPage, listOption]); React.useEffect(() => { - let tempFilter = [], - tempSortDir = ''; + let tempFilter = []; + let tempSortDir = ''; if (status) { tempFilter.push(`status = "${status}"`); @@ -119,7 +122,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { tempFilter.push(`phone ~ "%${phone}%"`); } - let preFinalListOption = {}; + let preFinalListOption = { filter: '' }; if (tempFilter.length > 0) { preFinalListOption = { filter: tempFilter.join(' && ') }; } @@ -176,7 +179,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { @@ -205,5 +208,11 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { } interface PageProps { - searchParams: { email?: string; phone?: string; sortDir?: 'asc' | 'desc'; status?: string }; + searchParams: { + email?: string; + phone?: string; + sortDir?: 'asc' | 'desc'; + status?: string; + // + }; } diff --git a/002_source/cms/src/app/dashboard/teachers/list/page.tsx.notworking b/002_source/cms/src/app/dashboard/teachers/list/page.tsx.notworking new file mode 100644 index 0000000..33d7590 --- /dev/null +++ b/002_source/cms/src/app/dashboard/teachers/list/page.tsx.notworking @@ -0,0 +1,216 @@ +// src/app/dashboard/teachers/list/page.tsx +'use client'; + +// RULES: +// contains list page for teachers (Teachers) +// +import * as React from 'react'; +import { useRouter } from 'next/navigation'; +import { COL_USER_METAS } from '@/constants'; +import { LoadingButton } from '@mui/lab'; +import Box from '@mui/material/Box'; +import Card from '@mui/material/Card'; +import Divider from '@mui/material/Divider'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus'; +import type { ListResult, RecordModel } from 'pocketbase'; + +import { TeachersFilters } from '@/components/dashboard/teacher/teachers-filters'; +import { TeachersPagination } from '@/components/dashboard/teacher/teachers-pagination'; +import { TeachersSelectionProvider } from '@/components/dashboard/teacher/teachers-selection-context'; +import { TeachersTable } from '@/components/dashboard/teacher/teachers-table'; +import type { Teacher } from '@/components/dashboard/teacher/type.d'; +import { useTranslation } from 'react-i18next'; + +import { paths } from '@/paths'; +import isDevelopment from '@/lib/check-is-development'; +import { logger } from '@/lib/default-logger'; +import { pb } from '@/lib/pb'; +import ErrorDisplay from '@/components/dashboard/error'; +import { defaultTeacher } from '@/components/dashboard/teacher/_constants'; +import FormLoading from '@/components/loading'; + +export default function Page({ searchParams }: PageProps): React.JSX.Element { + const { t } = useTranslation(['teachers']); + const router = useRouter(); + + const { email, phone, sortDir, status } = searchParams; + + const [teacherData, setTeacherData] = React.useState([]); + + const [isLoadingAddPage, setIsLoadingAddPage] = React.useState(false); + const [showLoading, setShowLoading] = React.useState(true); + const [showError, setShowError] = React.useState({ show: false, detail: '' }); + // + const [rowsPerPage, setRowsPerPage] = React.useState(5); + // + const [f, setF] = React.useState([]); + const [currentPage, setCurrentPage] = React.useState(0); + // + const [recordCount, setRecordCount] = React.useState(0); + const [listOption, setListOption] = React.useState({ filter: '' }); + const [listSort, setListSort] = React.useState({}); + + function isListOptionChanged() { + return JSON.stringify(listOption) === '{}'; + } + // + const reloadRows = async (): Promise => { + try { + const listOptionTeacherOnly = isListOptionChanged() + ? { filter: `role = "teacher"` } + : { filter: [listOption.filter, `role = "teacher"`].join(' && ') }; + + const models: ListResult = await pb + .collection(COL_USER_METAS) + .getList(currentPage + 1, rowsPerPage, listOptionTeacherOnly); + const { items, totalItems } = models; + const tempTeacher: Teacher[] = items.map((lt) => { + return { ...defaultTeacher, ...lt }; + }); + + setTeacherData(tempTeacher); + setRecordCount(totalItems); + setF(tempTeacher); + } catch (error) { + logger.error(error); + setShowError({ + // + show: true, + detail: JSON.stringify(error, null, 2), + }); + } finally { + setShowLoading(false); + } + }; + + const [lastListOption, setLastListOption] = React.useState({}); + const isFirstRun = React.useRef(false); + React.useEffect(() => { + if (!isFirstRun.current) { + isFirstRun.current = true; + } else if (JSON.stringify(listOption) !== JSON.stringify(lastListOption)) { + // reset page number as tab changes + setLastListOption(listOption); + setCurrentPage(0); + void reloadRows(); + } else { + void reloadRows(); + } + }, [currentPage, rowsPerPage, listOption]); + + React.useEffect(() => { + const tempFilter = []; + let tempSortDir = ''; + + if (status) { + tempFilter.push(`status = "${status}"`); + } + + if (sortDir) { + tempSortDir = `-created`; + } + + if (email) { + tempFilter.push(`email ~ "%${email}%"`); + } + + if (phone) { + tempFilter.push(`phone ~ "%${phone}%"`); + } + + let preFinalListOption = { filter: '' }; + if (tempFilter.length > 0) { + preFinalListOption = { filter: tempFilter.join(' && ') }; + } + if (tempSortDir.length > 0) { + preFinalListOption = { ...preFinalListOption, sort: tempSortDir }; + } + setListOption(preFinalListOption); + }, [sortDir, email, phone, status]); + + if (showLoading) return ; + + if (showError.show) + return ( + + ); + + return ( + + + + + {t('list.title')} + + + { + setIsLoadingAddPage(true); + router.push(paths.dashboard.teachers.create); + }} + startIcon={} + variant="contained" + > + {t('list.add')} + + + + + + + + + + + + + + + + +
{JSON.stringify(f, null, 2)}
+
+
+ ); +} + +interface PageProps { + searchParams: { + email?: string; + phone?: string; + sortDir?: 'asc' | 'desc'; + status?: string; + // + }; +} diff --git a/002_source/cms/src/app/dashboard/teachers/view/[id]/TitleCard.tsx b/002_source/cms/src/app/dashboard/teachers/view/[id]/TitleCard.tsx index 263056c..066caab 100644 --- a/002_source/cms/src/app/dashboard/teachers/view/[id]/TitleCard.tsx +++ b/002_source/cms/src/app/dashboard/teachers/view/[id]/TitleCard.tsx @@ -9,18 +9,15 @@ import Typography from '@mui/material/Typography'; import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown'; import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle'; import { useTranslation } from 'react-i18next'; -import type { Customer } from '@/components/dashboard/customer/type.d'; import { Teacher } from '@/components/dashboard/teacher/type.d'; // import type { CrCategory } from '@/components/dashboard/cr/categories/type'; -function getImageUrlFrRecord(record: Teacher): string { - // TODO: fix this - // `http://127.0.0.1:8090/api/files/${'record.collectionId'}/${'record.id'}/${'record.cat_image'}`; - return `http://127.0.0.1:8090/api/files/${record.collectionId}/${record.id}/${record.avatar}`; +function getImageUrlFrRecord(teacher: Teacher): string { + return `http://127.0.0.1:8090/api/files/${teacher.collectionId}/${teacher.id}/${teacher.avatar}`; } -export default function SampleTitleCard({ lpModel }: { lpModel: Customer }): React.JSX.Element { +export default function SampleTitleCard({ teacherRecord }: { teacherRecord: Teacher }): React.JSX.Element { const { t } = useTranslation(); return ( @@ -32,7 +29,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: Customer }): Rea > {t('empty')} @@ -43,7 +40,7 @@ export default function SampleTitleCard({ lpModel }: { lpModel: Customer }): Rea spacing={2} sx={{ alignItems: 'center', flexWrap: 'wrap' }} > - {lpModel.email} + {teacherRecord.name || teacherRecord.email} } - label={lpModel.quota} + label={teacherRecord.status} size="small" variant="outlined" />
- - {lpModel.status} -
diff --git a/002_source/cms/src/app/dashboard/teachers/view/[id]/_PROMPT.md b/002_source/cms/src/app/dashboard/teachers/view/[id]/_PROMPT.md new file mode 100644 index 0000000..d148073 --- /dev/null +++ b/002_source/cms/src/app/dashboard/teachers/view/[id]/_PROMPT.md @@ -0,0 +1,3 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/app/dashboard/teachers/view/[id]/TitleCard.tsx.draft` to handle `Teacher` record thanks, modify comments/variables/paths/functions name please + +e.g. why `lessonCategories` still exist ? diff --git a/002_source/cms/src/app/dashboard/teachers/view/[id]/page.tsx b/002_source/cms/src/app/dashboard/teachers/view/[id]/page.tsx index 308840a..9f4b729 100644 --- a/002_source/cms/src/app/dashboard/teachers/view/[id]/page.tsx +++ b/002_source/cms/src/app/dashboard/teachers/view/[id]/page.tsx @@ -107,7 +107,7 @@ export default function Page(): React.JSX.Element { spacing={3} sx={{ alignItems: 'flex-start' }} > - + (); + // + const [showLoading, setShowLoading] = React.useState(true); + const [showError, setShowError] = React.useState({ show: false, detail: '' }); + // + const [teacherData, setTeacherData] = React.useState(defaultTeacher); + + function handleEditClick(): void { + router.push(paths.dashboard.teachers.edit(teacherData.id)); + } + + React.useEffect(() => { + if (id) { + pb.collection(COL_USER_METAS) + .getOne(id) + .then((model: RecordModel) => { + setTeacherData({ ...defaultTeacher, ...model }); + }) + .catch((err) => { + logger.error(err); + toast(t('list.error')); + + setShowError({ show: true, detail: JSON.stringify(err) }); + }) + .finally(() => { + setShowLoading(false); + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [id]); + + // return <>{JSON.stringify({ showError, showLessonCategory }, null, 2)}; + + if (showLoading) return ; + if (showError.show) + return ( + + ); + + return ( + + + +
+ + + {t('back-to-list')} + +
+ + + +
+ + + + + + + + + + + + + + + +
+
+ ); +} diff --git a/002_source/cms/src/components/dashboard/layout/config.ts b/002_source/cms/src/components/dashboard/layout/config.ts index e3ffd62..14aca33 100644 --- a/002_source/cms/src/components/dashboard/layout/config.ts +++ b/002_source/cms/src/components/dashboard/layout/config.ts @@ -123,7 +123,7 @@ export const layoutConfig = { }, { key: 'teachers', - title: 'teachers', + title: 'teachers.nav-title', icon: 'users', items: [ { key: 'teachers', title: 'List', href: paths.dashboard.teachers.list }, @@ -138,8 +138,8 @@ export const layoutConfig = { icon: 'users', items: [ { key: 'students', title: 'List students', href: paths.dashboard.students.list }, - { key: 'students:create', title: 'Create student', href: paths.dashboard.students.create }, - { key: 'students:details', title: 'Student details', href: paths.dashboard.students.view('1') }, + // { key: 'students:create', title: 'Create student', href: paths.dashboard.students.create }, + // { key: 'students:details', title: 'Student details', href: paths.dashboard.students.view('1') }, ], }, // { diff --git a/002_source/cms/src/components/dashboard/student/_PROMPT.md b/002_source/cms/src/components/dashboard/student/_PROMPT.md new file mode 100644 index 0000000..586c2c8 --- /dev/null +++ b/002_source/cms/src/components/dashboard/student/_PROMPT.md @@ -0,0 +1 @@ +this `tsx` file is clone from elsewhere, please understand, modify and update the content of `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/components/dashboard/student/confirm-delete-modal.tsx.draft` to handle `Student` record thanks, modify comments/variables/paths/functions name please diff --git a/002_source/cms/src/components/dashboard/student/confirm-delete-modal.tsx b/002_source/cms/src/components/dashboard/student/confirm-delete-modal.tsx index 8c344c1..f9d22ea 100644 --- a/002_source/cms/src/components/dashboard/student/confirm-delete-modal.tsx +++ b/002_source/cms/src/components/dashboard/student/confirm-delete-modal.tsx @@ -83,12 +83,12 @@ export default function ConfirmDeleteModal({ - {t('Delete Lesson Type ?')} + {t('Delete Student ?')} - {t('Are you sure you want to delete lesson type ?')} + {t('Are you sure you want to delete this student record?')} { const fetchCount = async (): Promise => { try { - const tc = await getAllCustomersCount(); + const tc = await getAllStudentsCount(); setTotalCount(tc); const bc = await GetBlockedCount(); diff --git a/002_source/cms/src/components/dashboard/student/students-selection-context.tsx b/002_source/cms/src/components/dashboard/student/students-selection-context.tsx index e0892f6..c7c158b 100644 --- a/002_source/cms/src/components/dashboard/student/students-selection-context.tsx +++ b/002_source/cms/src/components/dashboard/student/students-selection-context.tsx @@ -25,12 +25,12 @@ export const StudentsSelectionContext = React.createContext customers.map((customer) => customer.id), [customers]); const selection = useSelection(customerIds); diff --git a/002_source/cms/src/components/dashboard/student/students-table.tsx b/002_source/cms/src/components/dashboard/student/students-table.tsx index 031b3de..1a5b556 100644 --- a/002_source/cms/src/components/dashboard/student/students-table.tsx +++ b/002_source/cms/src/components/dashboard/student/students-table.tsx @@ -39,7 +39,10 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef - {' '} +
void): ColumnDef { - // eslint-disable-next-line react-hooks/rules-of-hooks - const mapping = { active: { label: 'Active', @@ -172,7 +173,7 @@ export interface StudentsTableProps { } export function StudentsTable({ rows, reloadRows }: StudentsTableProps): React.JSX.Element { - const { t } = useTranslation(['customers']); + const { t } = useTranslation(['students']); const { deselectAll, deselectOne, selectAll, selectOne, selected } = useStudentsSelection(); const [idToDelete, setIdToDelete] = React.useState(''); @@ -213,7 +214,7 @@ export function StudentsTable({ rows, reloadRows }: StudentsTableProps): React.J variant="body2" > {/* TODO: update this */} - {t('no-record-found')} + {t('no-student-found')} ) : null} diff --git a/002_source/cms/src/components/dashboard/teacher/teachers-table.tsx b/002_source/cms/src/components/dashboard/teacher/teachers-table.tsx index ce215ae..f1c4bb2 100644 --- a/002_source/cms/src/components/dashboard/teacher/teachers-table.tsx +++ b/002_source/cms/src/components/dashboard/teacher/teachers-table.tsx @@ -144,7 +144,7 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef @@ -167,13 +167,13 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef void; } -export function TeachersTable({ rows, reloadRows }: CustomersTableProps): React.JSX.Element { - const { t } = useTranslation(['customers']); +export function TeachersTable({ rows, reloadRows }: TeachersTableProps): React.JSX.Element { + const { t } = useTranslation(['teachers']); const { deselectAll, deselectOne, selectAll, selectOne, selected } = useTeachersSelection(); const [idToDelete, setIdToDelete] = React.useState(''); diff --git a/002_source/cms/src/db/Students/Delete.tsx b/002_source/cms/src/db/Students/Delete.tsx index a9406ae..9f29ed9 100644 --- a/002_source/cms/src/db/Students/Delete.tsx +++ b/002_source/cms/src/db/Students/Delete.tsx @@ -1,6 +1,6 @@ import { pb } from '@/lib/pb'; -import { COL_STUDENTS } from '@/constants'; +import { COL_STUDENTS, COL_USER_METAS } from '@/constants'; export async function deleteStudent(id: string): Promise { - return pb.collection(COL_STUDENTS).delete(id); + return pb.collection(COL_USER_METAS).delete(id); } diff --git a/002_source/cms/src/db/Students/GetActiveCount.tsx b/002_source/cms/src/db/Students/GetActiveCount.tsx index c36fbca..58eb51b 100644 --- a/002_source/cms/src/db/Students/GetActiveCount.tsx +++ b/002_source/cms/src/db/Students/GetActiveCount.tsx @@ -1,9 +1,9 @@ -import { COL_STUDENTS } from '@/constants'; +import { COL_STUDENTS, COL_USER_METAS } from '@/constants'; import { pb } from '@/lib/pb'; export default async function GetActiveCount(): Promise { - const { totalItems: count } = await pb.collection(COL_STUDENTS).getList(1, 1, { - filter: 'status = "active"', + const { totalItems: count } = await pb.collection(COL_USER_METAS).getList(1, 1, { + filter: 'status = "active" && role = "student"', }); return count; } diff --git a/002_source/cms/src/db/Students/GetAllCount.tsx b/002_source/cms/src/db/Students/GetAllCount.tsx index 91f84cc..1bcae29 100644 --- a/002_source/cms/src/db/Students/GetAllCount.tsx +++ b/002_source/cms/src/db/Students/GetAllCount.tsx @@ -1,7 +1,10 @@ import { pb } from '@/lib/pb'; -import { COL_STUDENTS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; export async function getAllStudentsCount(): Promise { - const result = await pb.collection(COL_STUDENTS).getList(1, 1); + const result = await pb.collection(COL_USER_METAS).getList(1, 1, { + filter: `role = "student"`, + // + }); return result.totalItems; } diff --git a/002_source/cms/src/db/Students/GetBlockedCount.tsx b/002_source/cms/src/db/Students/GetBlockedCount.tsx index eca70b6..0dbceb6 100644 --- a/002_source/cms/src/db/Students/GetBlockedCount.tsx +++ b/002_source/cms/src/db/Students/GetBlockedCount.tsx @@ -1,9 +1,9 @@ -import { COL_STUDENTS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; import { pb } from '@/lib/pb'; export default async function GetBlockedCount(): Promise { - const { totalItems: count } = await pb.collection(COL_STUDENTS).getList(1, 1, { - filter: 'status = "blocked"', + const { totalItems: count } = await pb.collection(COL_USER_METAS).getList(1, 1, { + filter: 'status = "blocked" && role = "student"', }); return count; } diff --git a/002_source/cms/src/db/Students/GetPendingCount.tsx b/002_source/cms/src/db/Students/GetPendingCount.tsx index b7f3d7d..29bfd09 100644 --- a/002_source/cms/src/db/Students/GetPendingCount.tsx +++ b/002_source/cms/src/db/Students/GetPendingCount.tsx @@ -1,9 +1,9 @@ -import { COL_STUDENTS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; import { pb } from '@/lib/pb'; export default async function GetPendingCount(): Promise { - const { totalItems: count } = await pb.collection(COL_STUDENTS).getList(1, 1, { - filter: 'status = "pending"', + const { totalItems: count } = await pb.collection(COL_USER_METAS).getList(1, 1, { + filter: 'status = "pending" && role = "student"', }); return count; } diff --git a/002_source/cms/src/db/Teachers/GetAllCount.tsx b/002_source/cms/src/db/Teachers/GetAllCount.tsx index 06a50e6..3cf566e 100644 --- a/002_source/cms/src/db/Teachers/GetAllCount.tsx +++ b/002_source/cms/src/db/Teachers/GetAllCount.tsx @@ -2,6 +2,9 @@ import { pb } from '@/lib/pb'; import { COL_USER_METAS } from '@/constants'; export async function getAllTeachersCount(): Promise { - const result = await pb.collection(COL_USER_METAS).getList(1, 1, { filter: `role = "teacher"` }); + const result = await pb.collection(COL_USER_METAS).getList(1, 1, { + filter: `role = "teacher"`, + // + }); return result.totalItems; } diff --git a/002_source/cms/src/db/Teachers/GetBlockedCount.tsx b/002_source/cms/src/db/Teachers/GetBlockedCount.tsx index 67b983b..54875c4 100644 --- a/002_source/cms/src/db/Teachers/GetBlockedCount.tsx +++ b/002_source/cms/src/db/Teachers/GetBlockedCount.tsx @@ -1,8 +1,8 @@ -import { COL_TEACHERS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; import { pb } from '@/lib/pb'; export default async function GetBlockedCount(): Promise { - const { totalItems: count } = await pb.collection(COL_TEACHERS).getList(1, 1, { + const { totalItems: count } = await pb.collection(COL_USER_METAS).getList(1, 1, { filter: 'status = "blocked"', }); return count; diff --git a/002_source/cms/src/db/Teachers/GetPendingCount.tsx b/002_source/cms/src/db/Teachers/GetPendingCount.tsx index d6661ca..8b286a1 100644 --- a/002_source/cms/src/db/Teachers/GetPendingCount.tsx +++ b/002_source/cms/src/db/Teachers/GetPendingCount.tsx @@ -1,9 +1,9 @@ -import { COL_CUSTOMERS } from '@/constants'; +import { COL_USER_METAS } from '@/constants'; import { pb } from '@/lib/pb'; export default async function GetPendingCount(): Promise { - const { totalItems: count } = await pb.collection(COL_CUSTOMERS).getList(1, 1, { - filter: 'status = "pending"', + const { totalItems: count } = await pb.collection(COL_USER_METAS).getList(1, 1, { + filter: 'status = "pending" && role = "teacher"', }); return count; } diff --git a/002_source/cms/src/paths.ts b/002_source/cms/src/paths.ts index 59ca640..9830cb3 100644 --- a/002_source/cms/src/paths.ts +++ b/002_source/cms/src/paths.ts @@ -140,6 +140,7 @@ export const paths = { list: '/dashboard/teachers/list', create: '/dashboard/teachers/create', details: (id: string) => `/dashboard/teachers/view/${id}`, + view: (id: string) => `/dashboard/students/view/${id}`, edit: (id: string) => `/dashboard/teachers/edit/${id}`, mail: { list: (id: string) => `/dashboard/teachers/mail/${id}/list`,