diff --git a/002_source/cms/.env.development b/002_source/cms/.env.development index c71db6f..c142266 100644 --- a/002_source/cms/.env.development +++ b/002_source/cms/.env.development @@ -58,4 +58,4 @@ NEXT_PUBLIC_MAPBOX_API_KEY= # Google Tag Manager NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID= -NEXT_PUBLIC_POCKETBASE_URL=http://localhost:8090 \ No newline at end of file +NEXT_PUBLIC_POCKETBASE_URL=http://localhost:8090 diff --git a/002_source/cms/.gitignore b/002_source/cms/.gitignore index 8187db3..fd8f49e 100644 --- a/002_source/cms/.gitignore +++ b/002_source/cms/.gitignore @@ -1,3 +1,6 @@ +.env +.env.production + **/*.draft **/~* **/*copy*.tsx diff --git a/002_source/cms/package.json b/002_source/cms/package.json index 4b06495..bea3684 100644 --- a/002_source/cms/package.json +++ b/002_source/cms/package.json @@ -9,7 +9,7 @@ "scripts": { "dev": "next dev", "build": "rm -rf .next && next build", - "build:w": "pnpx nodemon --ext ts,tsx,json,mjs,js,jsx --delay 1 --exec \"pnpm run build\"", + "build:w": "pnpx nodemon --ext ts,tsx,json,mjs,js,jsx --delay 15 --exec \"pnpm run build\"", "start": "next start", "lint": "next lint --quiet", "lint:fix": "next lint --fix", @@ -116,4 +116,4 @@ "protobufjs" ] } -} +} \ No newline at end of file diff --git a/002_source/cms/public/locales/dev/common.json b/002_source/cms/public/locales/dev/common.json index d78d762..0735b9c 100644 --- a/002_source/cms/public/locales/dev/common.json +++ b/002_source/cms/public/locales/dev/common.json @@ -113,7 +113,6 @@ "connective_revision": "連接詞 (Connective Revision)", "settings": "設定", "students": "學生", - "dashboard.lessonCategories.add": "新增課程分類", "dashboard.lessonCategories.title": "課程分類", "dashboard.lessonCategorys.edit.name": "課程分類名稱", "dashboard.lessonCategorys.edit.position": "課程分類順序", @@ -132,4 +131,4 @@ "detailed-error-information": "詳細錯誤資訊" }, "name-is-required": "名稱為必填" -} +} \ No newline at end of file diff --git a/002_source/cms/public/locales/dev/lesson_category.json b/002_source/cms/public/locales/dev/lesson_category.json index be2303d..0449768 100644 --- a/002_source/cms/public/locales/dev/lesson_category.json +++ b/002_source/cms/public/locales/dev/lesson_category.json @@ -59,11 +59,12 @@ "message": "請建立課程類型", "create": "建立課程類型" }, - "error": "課程類型載入失敗" + "error": "課程類型載入失敗", + "add": "新增課程分類" }, "view": { "basic-details": "基本資訊" }, "Delete Lesson Type ?": "刪除課程類型?", "Are you sure you want to delete lesson type ?": "確定要刪除課程類型嗎?" -} +} \ No newline at end of file diff --git a/002_source/cms/src/app/dashboard/lesson_categories/.vscode/settings.json b/002_source/cms/src/app/dashboard/lesson_categories/.vscode/settings.json deleted file mode 100644 index 23830fb..0000000 --- a/002_source/cms/src/app/dashboard/lesson_categories/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "git.ignoreLimitWarning": true -} diff --git a/002_source/cms/src/app/dashboard/lesson_categories/page.tsx b/002_source/cms/src/app/dashboard/lesson_categories/page.tsx index 283bb5b..6359206 100644 --- a/002_source/cms/src/app/dashboard/lesson_categories/page.tsx +++ b/002_source/cms/src/app/dashboard/lesson_categories/page.tsx @@ -19,7 +19,6 @@ import { pb } from '@/lib/pb'; import { toast } from '@/components/core/toaster'; import ErrorDisplay from '@/components/dashboard/error'; import { defaultLessonCategory } from '@/components/dashboard/lesson_category/_constants'; -// import { defaultLessonCategory, type LessonCategory } from '@/components/dashboard/lesson_category/interfaces'; import { LessonCategoriesFilters } from '@/components/dashboard/lesson_category/lesson-categories-filters'; import type { Filters } from '@/components/dashboard/lesson_category/lesson-categories-filters'; import { LessonCategoriesPagination } from '@/components/dashboard/lesson_category/lesson-categories-pagination'; @@ -30,38 +29,27 @@ import FormLoading from '@/components/loading'; // import { lessonCategoriesSampleData } from './lesson-categories-sample-data'; -interface PageProps { - searchParams: { - email?: string; - phone?: string; - sortDir?: 'asc' | 'desc'; - spStatus?: string; - spName?: string; - spVisible?: string; - spType?: string; - // - }; -} - export default function Page({ searchParams }: PageProps): React.JSX.Element { - const { t } = useTranslation(['common']); - const { email, phone, sortDir, spStatus } = searchParams; + const { t } = useTranslation(['lesson_category']); + const { email, phone, sortDir, status, name, visible, type } = searchParams; const router = useRouter(); + const [lessonCategoriesData, setLessonCategoriesData] = React.useState([]); + // - const [recordCount, setRecordCount] = React.useState(0); + const [isLoadingAddPage, setIsLoadingAddPage] = React.useState(false); + const [showLoading, setShowLoading] = React.useState(true); + const [showError, setShowError] = React.useState(false); const [rowsPerPage, setRowsPerPage] = React.useState(5); + // + const [f, setF] = React.useState([]); const [currentPage, setCurrentPage] = React.useState(1); // - const [showError, setShowError] = React.useState(false); - const [showLoading, setShowLoading] = React.useState(true); - - // - const [isLoadingAddPage, setIsLoadingAddPage] = React.useState(false); - const [lessonCategoriesData, setLessonCategoriesData] = React.useState([]); + const [recordCount, setRecordCount] = React.useState(0); const sortedLessonCategories = applySort(lessonCategoriesData, sortDir); - const filteredLessonCategories = applyFilters(sortedLessonCategories, { email, phone, status: spStatus }); + const filteredLessonCategories = applyFilters(sortedLessonCategories, { email, phone, status: status }); + // const reloadRows = () => { setShowLoading(true); @@ -116,7 +104,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { - {t('dashboard.lessonCategorys.list.title')} + {t('list.title')} } variant="contained" > - {t('dashboard.lessonCategories.add')} + {t('list.add')} - + - + @@ -183,3 +175,16 @@ function applyFilters(row: LessonCategory[], { email, phone, status }: Filters): return true; }); } + +interface PageProps { + searchParams: { + email?: string; + phone?: string; + sortDir?: 'asc' | 'desc'; + status?: string; + name?: string; + visible?: string; + type?: string; + // + }; +} diff --git a/002_source/cms/src/app/dashboard/lesson_types/[type_id]/page.tsx b/002_source/cms/src/app/dashboard/lesson_types/[type_id]/page.tsx index 0413d4f..72bb39e 100644 --- a/002_source/cms/src/app/dashboard/lesson_types/[type_id]/page.tsx +++ b/002_source/cms/src/app/dashboard/lesson_types/[type_id]/page.tsx @@ -37,14 +37,15 @@ import { PropertyItem } from '@/components/core/property-item'; import { PropertyList } from '@/components/core/property-list'; import { toast } from '@/components/core/toaster'; import ErrorDisplay from '@/components/dashboard/error'; -import { defaultLessonType } from '@/components/dashboard/lesson_type/_constants'; +import { defaultLessonType, LessonTypeDefaultValue } from '@/components/dashboard/lesson_type/_constants'; // import { getLessonTypeById } from '@/components/dashboard/lesson_type/http-actions'; -import { LessonTypeDefaultValue, type LessonType } from '@/components/dashboard/lesson_type/ILessonType'; +// import { LessonTypeDefaultValue, type LessonType } from '@/components/dashboard/lesson_type/ILessonType'; // import { defaultLessonType } from '@/components/dashboard/lesson_type/interfaces'; import { Notifications } from '@/components/dashboard/lesson_type/notifications'; import { Payments } from '@/components/dashboard/lesson_type/payments'; import type { Address } from '@/components/dashboard/lesson_type/shipping-address'; import { ShippingAddress } from '@/components/dashboard/lesson_type/shipping-address'; +import { type LessonType } from '@/components/dashboard/lesson_type/types'; import FormLoading from '@/components/loading'; export default function Page(): React.JSX.Element { @@ -58,7 +59,7 @@ export default function Page(): React.JSX.Element { // const [showLessonType, setShowLessonType] = React.useState(LessonTypeDefaultValue); - function handleEditClick() { + function handleEditClick(): void { router.push(paths.dashboard.lesson_types.edit(showLessonType.id)); } diff --git a/002_source/cms/src/app/dashboard/lesson_types/lesson-types-data.tsx b/002_source/cms/src/app/dashboard/lesson_types/lesson-types-data.tsx index cf88d17..1efe9cf 100644 --- a/002_source/cms/src/app/dashboard/lesson_types/lesson-types-data.tsx +++ b/002_source/cms/src/app/dashboard/lesson_types/lesson-types-data.tsx @@ -1,5 +1,7 @@ import { dayjs } from '@/lib/dayjs'; -import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType'; +import { LessonType } from '@/components/dashboard/lesson_type/types'; + +// import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType'; // import { helloworld } from '@/components/dashboard/lesson_type/helloworld'; // export const metadata = { title: `List | Customers | Dashboard | ${config.site.name}` } satisfies Metadata; diff --git a/002_source/cms/src/app/dashboard/lesson_types/lesson-types-sample-data.tsx b/002_source/cms/src/app/dashboard/lesson_types/lesson-types-sample-data.tsx index 1d2deed..8a059ac 100644 --- a/002_source/cms/src/app/dashboard/lesson_types/lesson-types-sample-data.tsx +++ b/002_source/cms/src/app/dashboard/lesson_types/lesson-types-sample-data.tsx @@ -1,5 +1,7 @@ import { dayjs } from '@/lib/dayjs'; -import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType'; +import { LessonType } from '@/components/dashboard/lesson_type/types'; + +// import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType'; // import { helloworld } from '@/components/dashboard/lesson_type/helloworld'; // export const metadata = { title: `List | Customers | Dashboard | ${config.site.name}` } satisfies Metadata; diff --git a/002_source/cms/src/app/dashboard/lesson_types/page.tsx b/002_source/cms/src/app/dashboard/lesson_types/page.tsx index 51ea887..b02cca6 100644 --- a/002_source/cms/src/app/dashboard/lesson_types/page.tsx +++ b/002_source/cms/src/app/dashboard/lesson_types/page.tsx @@ -19,28 +19,31 @@ import { pb } from '@/lib/pb'; import { toast } from '@/components/core/toaster'; import ErrorDisplay from '@/components/dashboard/error'; import { defaultLessonType } from '@/components/dashboard/lesson_type/_constants'; -import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType'; +// import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType'; // import { defaultLessonType, emptyLessonType, safeAssignment } from '@/components/dashboard/lesson_type/interfaces'; import { LessonTypesFilters } from '@/components/dashboard/lesson_type/lesson-types-filters'; import type { Filters } from '@/components/dashboard/lesson_type/lesson-types-filters'; import { LessonTypesPagination } from '@/components/dashboard/lesson_type/lesson-types-pagination'; import { LessonTypesSelectionProvider } from '@/components/dashboard/lesson_type/lesson-types-selection-context'; import { LessonTypesTable } from '@/components/dashboard/lesson_type/lesson-types-table'; +import type { LessonType } from '@/components/dashboard/lesson_type/types'; import FormLoading from '@/components/loading'; export default function Page({ searchParams }: PageProps): React.JSX.Element { - const { t } = useTranslation(); + const { t } = useTranslation(['lesson_type']); const { email, phone, sortDir, status, name, visible, type } = searchParams; const router = useRouter(); const [lessonTypesData, setLessonTypesData] = React.useState([]); + // const [isLoadingAddPage, setIsLoadingAddPage] = React.useState(false); const [showLoading, setShowLoading] = React.useState(true); const [showError, setShowError] = React.useState(false); 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({}); @@ -117,7 +120,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element { - {t('Lesson Types')} + {t('list.title')} (0); + const [visibleCount, setVisibleCount] = React.useState(0); + const [hiddenCount, setHiddenCount] = React.useState(0); const router = useRouter(); const selection = useLessonCategoriesSelection(); + function getVisible(): number { + return fullData.reduce((count, item: LessonCategory) => { + return item.visible === 'visible' ? count + 1 : count; + }, 0); + } + + function getHidden(): number { + return fullData.reduce((count, item: LessonCategory) => { + return item.visible === 'hidden' ? count + 1 : count; + }, 0); + } + + // The tabs should be generated using API data. + const tabs = [ + { label: t('All'), value: '', count: totalCount }, + // { label: 'Active', value: 'active', count: 3 }, + // { label: 'Pending', value: 'pending', count: 1 }, + // { label: 'Blocked', value: 'blocked', count: 1 }, + { label: t('visible'), value: 'visible', count: visibleCount }, + { label: t('hidden'), value: 'hidden', count: hiddenCount }, + ] as const; + const updateSearchParams = React.useCallback( (newFilters: Filters, newSortDir: SortDir): void => { const searchParams = new URLSearchParams(); @@ -71,6 +102,18 @@ export function LessonCategoriesFilters({ searchParams.set('phone', newFilters.phone); } + if (newFilters.name) { + searchParams.set('name', newFilters.name); + } + + if (newFilters.type) { + searchParams.set('type', newFilters.type); + } + + if (newFilters.visible) { + searchParams.set('visible', newFilters.visible); + } + router.push(`${paths.dashboard.lesson_categories.list}?${searchParams.toString()}`); }, [router] @@ -87,6 +130,27 @@ export function LessonCategoriesFilters({ [updateSearchParams, filters, sortDir] ); + const handleVisibleChange = React.useCallback( + (_: React.SyntheticEvent, value: string) => { + updateSearchParams({ ...filters, visible: value }, sortDir); + }, + [updateSearchParams, filters, sortDir] + ); + + const handleNameChange = React.useCallback( + (value?: string) => { + updateSearchParams({ ...filters, name: value }, sortDir); + }, + [updateSearchParams, filters, sortDir] + ); + + const handleTypeChange = React.useCallback( + (value?: string) => { + updateSearchParams({ ...filters, type: value }, sortDir); + }, + [updateSearchParams, filters, sortDir] + ); + const handleEmailChange = React.useCallback( (value?: string) => { updateSearchParams({ ...filters, email: value }, sortDir); @@ -108,11 +172,29 @@ export function LessonCategoriesFilters({ [updateSearchParams, filters] ); - const hasFilters = status || email || phone; + React.useEffect(() => { + const fetchCount = async (): Promise => { + try { + const tc = await GetAllCount(); + setTotalCount(tc); + + const vc = await GetVisibleCount(); + setVisibleCount(vc); + + const hc = await GetHiddenCount(); + setHiddenCount(hc); + } catch (error) { + // + } + }; + void fetchCount(); + }, []); + + const hasFilters = status || email || phone || visible || name || type; return (
- + {tabs.map((tab) => ( } @@ -129,50 +211,124 @@ export function LessonCategoriesFilters({ { - handleEmailChange(value as string); + handleNameChange(value as string); }} onFilterDelete={() => { - handleEmailChange(); + handleNameChange(); }} - popover={} - value={email} + popover={} + value={name} /> + { - handlePhoneChange(value as string); + handleTypeChange(value as string); }} onFilterDelete={() => { - handlePhoneChange(); + handleTypeChange(); }} - popover={} - value={phone} + popover={} + value={type} /> - {hasFilters ? : null} + + {hasFilters ? : null} {selection.selectedAny ? ( - {selection.selected.size} selected + {selection.selected.size} {t('selected')} ) : null}
); } +function TypeFilterPopover(): React.JSX.Element { + const { t } = useTranslation(); + const { anchorEl, onApply, onClose, open, value: initialValue } = useFilterContext(); + const [value, setValue] = React.useState(''); + + React.useEffect(() => { + setValue((initialValue as string | undefined) ?? ''); + }, [initialValue]); + + return ( + + + { + setValue(event.target.value); + }} + onKeyUp={(event) => { + if (event.key === 'Enter') { + onApply(value); + } + }} + value={value} + /> + + + + ); +} + +function NameFilterPopover(): React.JSX.Element { + const { t } = useTranslation(); + const { anchorEl, onApply, onClose, open, value: initialValue } = useFilterContext(); + const [value, setValue] = React.useState(''); + + React.useEffect(() => { + setValue((initialValue as string | undefined) ?? ''); + }, [initialValue]); + + return ( + + + { + setValue(event.target.value); + }} + onKeyUp={(event) => { + if (event.key === 'Enter') { + onApply(value); + } + }} + value={value} + /> + + + + ); +} + function EmailFilterPopover(): React.JSX.Element { const { anchorEl, onApply, onClose, open, value: initialValue } = useFilterContext(); const [value, setValue] = React.useState(''); diff --git a/002_source/cms/src/components/dashboard/lesson_category/lesson-categories-table.tsx b/002_source/cms/src/components/dashboard/lesson_category/lesson-categories-table.tsx index 539e10a..06c1ccb 100644 --- a/002_source/cms/src/components/dashboard/lesson_category/lesson-categories-table.tsx +++ b/002_source/cms/src/components/dashboard/lesson_category/lesson-categories-table.tsx @@ -145,7 +145,7 @@ export interface LessonCategoriesTableProps { } export function LessonCategoriesTable({ rows, reloadRows }: LessonCategoriesTableProps): React.JSX.Element { - const { t } = useTranslation(); + const { t } = useTranslation(['lesson_category']); const { deselectAll, deselectOne, selectAll, selectOne, selected } = useLessonCategoriesSelection(); const [idToDelete, setIdToDelete] = React.useState(''); @@ -177,7 +177,7 @@ export function LessonCategoriesTable({ rows, reloadRows }: LessonCategoriesTabl {/* TODO: use hyphen here */} - {t('No lesson categories found')} + {t('no-lesson-categories-found')} ) : null} diff --git a/002_source/cms/src/components/dashboard/lesson_type/ILessonType.tsx b/002_source/cms/src/components/dashboard/lesson_type/ILessonType.tsx index 6ed77fb..7d99c7f 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/ILessonType.tsx +++ b/002_source/cms/src/components/dashboard/lesson_type/ILessonType.tsx @@ -2,58 +2,3 @@ // please use src/components/dashboard/lesson_type/interfaces.ts for defining new interfaces import { dayjs } from '@/lib/dayjs'; - -export interface LessonType { - id: string; - isEmpty?: boolean; - name: string; - type: string; - pos: number; - visible: 'visible' | 'hidden'; - createdAt: Date; - // - // original - // id: string; - // name: string; - // - avatar?: string; - email: string; - phone?: string; - quota: number; - status: 'pending' | 'active' | 'blocked'; - // createdAt: Date; -} - -export const LessonTypeDefaultValue: LessonType = { - id: 'string', - name: 'string', - type: 'string', - pos: 1, - visible: 'visible', - createdAt: dayjs().toDate(), - // - // original - // id: 'string', - // name: 'string', - // - avatar: 'string', - email: 'string', - phone: 'string', - quota: 1, - status: 'pending', - // createdAt: Date; -}; - -export interface DBLessonType { - id: string; - name: string; - type: string; - pos: number; - visible: 'visible' | 'hidden'; - createdAt: Date; - created: 'string'; -} - -export interface Helloworld { - id: string; -} diff --git a/002_source/cms/src/components/dashboard/lesson_type/_constants.ts b/002_source/cms/src/components/dashboard/lesson_type/_constants.ts index df21cea..20af999 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/_constants.ts +++ b/002_source/cms/src/components/dashboard/lesson_type/_constants.ts @@ -3,8 +3,8 @@ import type { RecordModel } from 'pocketbase'; import { dayjs } from '@/lib/dayjs'; -import type { LessonType } from './ILessonType'; -import type { CreateForm } from './types'; +// import type { LessonType } from './ILessonType'; +import type { CreateForm, LessonType } from './types'; export const LessonTypeCreateFormDefault: CreateForm = { name: '', @@ -55,3 +55,23 @@ export function safeAssignment(inTemp: LessonType | RecordModel): LessonType { }; return output; } + +export const LessonTypeDefaultValue: LessonType = { + id: 'string', + name: 'string', + type: 'string', + pos: 1, + visible: 'visible', + createdAt: dayjs().toDate(), + // + // original + // id: 'string', + // name: 'string', + // + avatar: 'string', + email: 'string', + phone: 'string', + quota: 1, + status: 'pending', + // createdAt: Date; +}; diff --git a/002_source/cms/src/components/dashboard/lesson_type/lesson-type-edit-form.tsx b/002_source/cms/src/components/dashboard/lesson_type/lesson-type-edit-form.tsx index 6eab9ba..5ff741e 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/lesson-type-edit-form.tsx +++ b/002_source/cms/src/components/dashboard/lesson_type/lesson-type-edit-form.tsx @@ -40,7 +40,7 @@ import FormLoading from '@/components/loading'; import { defaultLessonType } from './_constants'; // import { getLessonTypeById, updateLessonType } from './http-actions'; // TODO: this may be wrong -import type { LessonType } from './ILessonType'; +// import type { LessonType } from './ILessonType'; import { LessonTypeEditFormProps } from './types'; // import { defaultLessonType, type LessonTypeEditFormProps } from './interfaces'; diff --git a/002_source/cms/src/components/dashboard/lesson_type/lesson-types-filters.tsx b/002_source/cms/src/components/dashboard/lesson_type/lesson-types-filters.tsx index 4025589..794aa46 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/lesson-types-filters.tsx +++ b/002_source/cms/src/components/dashboard/lesson_type/lesson-types-filters.tsx @@ -3,6 +3,9 @@ import * as React from 'react'; import { useRouter } from 'next/navigation'; import { COL_LESSON_TYPES } from '@/constants'; +import GetAllCount from '@/db/LessonTypes/GetAllCount'; +import GetHiddenCount from '@/db/LessonTypes/GetHiddenCount'; +import GetVisibleCount from '@/db/LessonTypes/GetVisibleCount'; import Button from '@mui/material/Button'; import Chip from '@mui/material/Chip'; import Divider from '@mui/material/Divider'; @@ -21,8 +24,9 @@ import { pb } from '@/lib/pb'; import { FilterButton, FilterPopover, useFilterContext } from '@/components/core/filter-button'; import { Option } from '@/components/core/option'; -import type { LessonType } from './ILessonType'; +// import type { LessonType } from './ILessonType'; import { useLessonTypesSelection } from './lesson-types-selection-context'; +import { LessonType } from './types'; export interface Filters { email?: string; @@ -172,17 +176,13 @@ export function LessonTypesFilters({ React.useEffect(() => { const fetchCount = async (): Promise => { try { - const { totalItems: tc } = await pb.collection(COL_LESSON_TYPES).getList(1, 9999); + const tc = await GetAllCount(); setTotalCount(tc); - const { totalItems: vc } = await pb - .collection(COL_LESSON_TYPES) - .getList(1, 9999, { filter: 'visible = "visible"' }); + const vc = await GetVisibleCount(); setVisibleCount(vc); - const { totalItems: hc } = await pb - .collection(COL_LESSON_TYPES) - .getList(1, 9999, { filter: 'visible = "hidden"' }); + const hc = await GetHiddenCount(); setHiddenCount(hc); } catch (error) { // @@ -237,36 +237,6 @@ export function LessonTypesFilters({ value={type} /> - {/* - { - handleEmailChange(value as string); - }} - onFilterDelete={() => { - handleEmailChange(); - }} - popover={} - value={email} - /> - */} - - {/* - { - handlePhoneChange(value as string); - }} - onFilterDelete={() => { - handlePhoneChange(); - }} - popover={} - value={phone} - /> - */} - {hasFilters ? : null}
{selection.selectedAny ? ( diff --git a/002_source/cms/src/components/dashboard/lesson_type/lesson-types-selection-context.tsx b/002_source/cms/src/components/dashboard/lesson_type/lesson-types-selection-context.tsx index e492466..be6fdb6 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/lesson-types-selection-context.tsx +++ b/002_source/cms/src/components/dashboard/lesson_type/lesson-types-selection-context.tsx @@ -5,7 +5,9 @@ import * as React from 'react'; import { useSelection } from '@/hooks/use-selection'; import type { Selection } from '@/hooks/use-selection'; -import { LessonType } from './ILessonType'; +import { LessonType } from './types'; + +// import { LessonType } from './ILessonType'; function noop(): void { return undefined; diff --git a/002_source/cms/src/components/dashboard/lesson_type/lesson-types-table.tsx b/002_source/cms/src/components/dashboard/lesson_type/lesson-types-table.tsx index 1e784bf..40bae84 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/lesson-types-table.tsx +++ b/002_source/cms/src/components/dashboard/lesson_type/lesson-types-table.tsx @@ -13,6 +13,7 @@ import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle'; import { Clock as ClockIcon } from '@phosphor-icons/react/dist/ssr/Clock'; +import { Images as ImagesIcon } from '@phosphor-icons/react/dist/ssr/Images'; import { Minus as MinusIcon } from '@phosphor-icons/react/dist/ssr/Minus'; import { PencilSimple as PencilSimpleIcon } from '@phosphor-icons/react/dist/ssr/PencilSimple'; import { TrashSimple as TrashSimpleIcon } from '@phosphor-icons/react/dist/ssr/TrashSimple'; @@ -25,8 +26,9 @@ import { DataTable } from '@/components/core/data-table'; import type { ColumnDef } from '@/components/core/data-table'; import ConfirmDeleteModal from './confirm-delete-modal'; -import type { LessonType } from './ILessonType'; +// import type { LessonType } from './ILessonType'; import { useLessonTypesSelection } from './lesson-types-selection-context'; +import { LessonType } from './types'; function columns(handleDeleteClick: (testId: string) => void): ColumnDef[] { return [ @@ -132,7 +134,6 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef ( @@ -169,7 +170,7 @@ export interface LessonTypesTableProps { } export function LessonTypesTable({ rows, reloadRows }: LessonTypesTableProps): React.JSX.Element { - const { t } = useTranslation(); + const { t } = useTranslation(['lesson_type']); const { deselectAll, deselectOne, selectAll, selectOne, selected } = useLessonTypesSelection(); const [idToDelete, setIdToDelete] = React.useState(''); @@ -201,7 +202,7 @@ export function LessonTypesTable({ rows, reloadRows }: LessonTypesTableProps): R {/* TODO: use hyphen here */} - {t('No lesson types found')} + {t('no-lesson-types-found')} ) : null} diff --git a/002_source/cms/src/components/dashboard/lesson_type/types.d.ts b/002_source/cms/src/components/dashboard/lesson_type/types.d.ts index aa17528..0b7096c 100644 --- a/002_source/cms/src/components/dashboard/lesson_type/types.d.ts +++ b/002_source/cms/src/components/dashboard/lesson_type/types.d.ts @@ -4,7 +4,8 @@ import type { RecordModel } from 'pocketbase'; import { dayjs } from '@/lib/dayjs'; import { defaultLessonType } from './_constants'; -import type { LessonType } from './ILessonType'; + +// import type { LessonType } from './ILessonType'; export interface LessonTypeEditFormProps { name: string; @@ -42,3 +43,38 @@ export function safeAssignment(inTemp: LessonType | RecordModel): LessonType { }; return output; } + +export interface LessonType { + id: string; + isEmpty?: boolean; + name: string; + type: string; + pos: number; + visible: 'visible' | 'hidden'; + createdAt: Date; + // + // original + // id: string; + // name: string; + // + avatar?: string; + email: string; + phone?: string; + quota: number; + status: 'pending' | 'active' | 'blocked'; + // createdAt: Date; +} + +export interface DBLessonType { + id: string; + name: string; + type: string; + pos: number; + visible: 'visible' | 'hidden'; + createdAt: Date; + created: 'string'; +} + +export interface Helloworld { + id: string; +} diff --git a/002_source/cms/src/db/DB_AI_GUIDELINE.MD b/002_source/cms/src/db/DB_AI_GUIDELINE.MD index d18d21e..111eed4 100644 --- a/002_source/cms/src/db/DB_AI_GUIDELINE.MD +++ b/002_source/cms/src/db/DB_AI_GUIDELINE.MD @@ -12,6 +12,10 @@ please read, remember and link up the ideas, i will tell you the task afterwards working directory: `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/db` +clone `GetVisibleCount.tsx` and `GetHiddenCount.tsx` from `LessonTypes` to `LessonCategories` and update it + +please draft `GetHiddenCount.tsx` for COL_LESSON_TYPES and `status = hidden` + pleaes clone the `tsx` files from `LessonTypes` and `LessonCategories` to `UserMetas` and update the content when you draft coding, review file and append with `.tsx.draft` diff --git a/002_source/cms/src/db/GetHiddenCount.tsx b/002_source/cms/src/db/GetHiddenCount.tsx new file mode 100644 index 0000000..e69de29 diff --git a/002_source/cms/src/db/LessonCategories/GetAllCount.tsx b/002_source/cms/src/db/LessonCategories/GetAllCount.tsx index 11d838a..4f482bd 100644 --- a/002_source/cms/src/db/LessonCategories/GetAllCount.tsx +++ b/002_source/cms/src/db/LessonCategories/GetAllCount.tsx @@ -4,8 +4,6 @@ import { COL_LESSON_CATEGORIES } from '@/constants'; import { pb } from '@/lib/pb'; export default async function GetAllCount(): Promise { - const { totalItems: count } = await pb - .collection(COL_LESSON_CATEGORIES) - .getList(1, 9999, { filter: 'visible = "visible"' }); + const { totalItems: count } = await pb.collection(COL_LESSON_CATEGORIES).getList(1, 9999, {}); return count; } diff --git a/002_source/cms/src/db/LessonCategories/GetHiddenCount.tsx b/002_source/cms/src/db/LessonCategories/GetHiddenCount.tsx new file mode 100644 index 0000000..6360d0f --- /dev/null +++ b/002_source/cms/src/db/LessonCategories/GetHiddenCount.tsx @@ -0,0 +1,14 @@ +// REQ0006 +import { COL_LESSON_CATEGORIES } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetHiddenCount(): Promise { + try { + const result = await pb.collection(COL_LESSON_CATEGORIES).getList(1, 9999, { filter: 'visible = "hidden"' }); + const { totalItems: count } = result; + return count; + } catch (error) { + return 0; + } +} diff --git a/002_source/cms/src/db/LessonCategories/GetVisibleCount.tsx b/002_source/cms/src/db/LessonCategories/GetVisibleCount.tsx new file mode 100644 index 0000000..ff87b3f --- /dev/null +++ b/002_source/cms/src/db/LessonCategories/GetVisibleCount.tsx @@ -0,0 +1,14 @@ +// REQ0006 +import { COL_LESSON_CATEGORIES } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetVisibleCount(): Promise { + try { + const result = await pb.collection(COL_LESSON_CATEGORIES).getList(1, 9999, { filter: 'visible = "visible"' }); + const { totalItems: count } = result; + return count; + } catch (error) { + return 0; + } +} diff --git a/002_source/cms/src/db/LessonTypes/GetAllCount.tsx b/002_source/cms/src/db/LessonTypes/GetAllCount.tsx index 00127b1..16899e2 100644 --- a/002_source/cms/src/db/LessonTypes/GetAllCount.tsx +++ b/002_source/cms/src/db/LessonTypes/GetAllCount.tsx @@ -5,7 +5,7 @@ import { pb } from '@/lib/pb'; export default async function GetAllCount(): Promise { try { - const result = await pb.collection(COL_LESSON_TYPES).getList(1, 9999, { filter: 'visible = "visible"' }); + const result = await pb.collection(COL_LESSON_TYPES).getList(1, 9999, {}); const { totalItems: count } = result; return count; } catch (error) { diff --git a/002_source/cms/src/db/LessonTypes/GetHiddenCount.tsx b/002_source/cms/src/db/LessonTypes/GetHiddenCount.tsx new file mode 100644 index 0000000..b59ad55 --- /dev/null +++ b/002_source/cms/src/db/LessonTypes/GetHiddenCount.tsx @@ -0,0 +1,14 @@ +// REQ0006 +import { COL_LESSON_TYPES } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetHiddenCount(): Promise { + try { + const result = await pb.collection(COL_LESSON_TYPES).getList(1, 9999, { filter: 'visible = "hidden"' }); + const { totalItems: count } = result; + return count; + } catch (error) { + return 0; + } +} diff --git a/002_source/cms/src/db/LessonTypes/GetVisibleCount.tsx b/002_source/cms/src/db/LessonTypes/GetVisibleCount.tsx new file mode 100644 index 0000000..e627da0 --- /dev/null +++ b/002_source/cms/src/db/LessonTypes/GetVisibleCount.tsx @@ -0,0 +1,14 @@ +// REQ0006 +import { COL_LESSON_TYPES } from '@/constants'; + +import { pb } from '@/lib/pb'; + +export default async function GetVisibleCount(): Promise { + try { + const result = await pb.collection(COL_LESSON_TYPES).getList(1, 9999, { filter: 'visible = "visible"' }); + const { totalItems: count } = result; + return count; + } catch (error) { + return 0; + } +} diff --git a/002_source/cms/src/paths.ts b/002_source/cms/src/paths.ts index 5acd6e9..7bb9de1 100644 --- a/002_source/cms/src/paths.ts +++ b/002_source/cms/src/paths.ts @@ -93,6 +93,12 @@ export const paths = { create: '/dashboard/customers/create', details: (customerId: string) => `/dashboard/customers/${customerId}`, }, + students: { + list: '/dashboard/students', + create: '/dashboard/students/create', + details: (studentId: string) => `/dashboard/students/${studentId}`, + edit: (studentId: string) => `/dashboard/students/edit/${studentId}`, + }, eCommerce: '/dashboard/e-commerce', fileStorage: '/dashboard/file-storage', invoices: {