updat build ok,

This commit is contained in:
louiscklaw
2025-04-16 12:22:39 +08:00
parent 3569518c0b
commit 08e5677c0b
6 changed files with 108 additions and 31 deletions

View File

@@ -1,3 +1,9 @@
need to fix local storage error need to fix local storage error
page right (next page) button is not working page right (next page) button is not working
in the middle of clone lesson type to lesson category
- [ ] listing page
- [ ] delete button on each row
- [ ] create page
- [ ] edit
- [ ] delete

View File

@@ -1,6 +1,9 @@
'use client'; 'use client';
import * as React from 'react'; import * as React from 'react';
import { useRouter } from 'next/navigation';
import { COL_LESSON_CATEGORIES } from '@/constants';
import { LoadingButton } from '@mui/lab';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import Card from '@mui/material/Card'; import Card from '@mui/material/Card';
@@ -8,13 +11,24 @@ import Divider from '@mui/material/Divider';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus'; import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus';
import type { ListResult, RecordModel } from 'pocketbase';
import { useTranslation } from 'react-i18next';
import type { LessonCategory } from '@/components/dashboard/lesson_category/interfaces'; import { paths } from '@/paths';
import { logger } from '@/lib/default-logger';
import { pb } from '@/lib/pb';
import { toast } from '@/components/core/toaster';
import {
defaultLessonCategory,
type emptyLessonCategory,
type LessonCategory,
} from '@/components/dashboard/lesson_category/interfaces';
import { LessonCategoriesFilters } from '@/components/dashboard/lesson_category/lesson-categories-filters'; import { LessonCategoriesFilters } from '@/components/dashboard/lesson_category/lesson-categories-filters';
import type { Filters } 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'; import { LessonCategoriesPagination } from '@/components/dashboard/lesson_category/lesson-categories-pagination';
import { LessonCategoriesSelectionProvider } from '@/components/dashboard/lesson_category/lesson-categories-selection-context'; import { LessonCategoriesSelectionProvider } from '@/components/dashboard/lesson_category/lesson-categories-selection-context';
import { LessonCategoriesTable } from '@/components/dashboard/lesson_category/lesson-categories-table'; import { LessonCategoriesTable } from '@/components/dashboard/lesson_category/lesson-categories-table';
import FormLoading from '@/components/loading';
import { lessonCategoriesSampleData } from './lesson-categories-sample-data'; import { lessonCategoriesSampleData } from './lesson-categories-sample-data';
@@ -23,19 +37,51 @@ interface PageProps {
email?: string; email?: string;
phone?: string; phone?: string;
sortDir?: 'asc' | 'desc'; sortDir?: 'asc' | 'desc';
status?: string; spStatus?: string;
name?: string; spName?: string;
visible?: string; spVisible?: string;
type?: string; spType?: string;
// //
}; };
} }
export default function Page({ searchParams }: PageProps): React.JSX.Element { export default function Page({ searchParams }: PageProps): React.JSX.Element {
const { email, phone, sortDir, status } = searchParams; const { t } = useTranslation();
const { email, phone, sortDir, spStatus } = searchParams;
const router = useRouter();
const [recordCount, setRecordCount] = React.useState<number>(0);
const [rowsPerPage, setRowsPerPage] = React.useState<number>(5);
const [currentPage, setCurrentPage] = React.useState<number>(1);
const sortedLessonCategories = applySort(lessonCategoriesSampleData, sortDir); const sortedLessonCategories = applySort(lessonCategoriesSampleData, sortDir);
const filteredLessonCategories = applyFilters(sortedLessonCategories, { email, phone, status }); const filteredLessonCategories = applyFilters(sortedLessonCategories, { email, phone, status: spStatus });
//
const [isLoadingAddPage, setIsLoadingAddPage] = React.useState<boolean>(false);
const [lessonCategoriesData, setLessonCategoriesData] = React.useState<LessonCategory[]>([]);
const reloadRows = () => {
pb.collection(COL_LESSON_CATEGORIES)
.getList(currentPage, rowsPerPage, {})
.then((lessonCategories: ListResult<RecordModel>) => {
// console.log(lessonTypes);
const { items, page, perPage, totalItems, totalPages } = lessonCategories;
const tempLessonCategories: LessonCategory[] = items.map((item) => {
return { ...defaultLessonCategory, ...item };
});
setLessonCategoriesData(tempLessonCategories);
setRecordCount(totalItems);
})
.catch((err) => {
logger.error(err);
toast(t('dashboard.lessonTypes.list.error'));
});
};
React.useEffect(() => {
reloadRows();
}, []);
if (lessonCategoriesData.length < 1) return <FormLoading />;
return ( return (
<Box <Box
@@ -49,17 +95,25 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element {
<Stack spacing={4}> <Stack spacing={4}>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={3} sx={{ alignItems: 'flex-start' }}> <Stack direction={{ xs: 'column', sm: 'row' }} spacing={3} sx={{ alignItems: 'flex-start' }}>
<Box sx={{ flex: '1 1 auto' }}> <Box sx={{ flex: '1 1 auto' }}>
<Typography variant="h4">Lesson Categories</Typography> <Typography variant="h4">{t('Lesson Categories')}</Typography>
</Box> </Box>
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}> <Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button startIcon={<PlusIcon />} variant="contained"> <LoadingButton
Add loading={isLoadingAddPage}
</Button> onClick={(): void => {
setIsLoadingAddPage(true);
router.push(paths.dashboard.lesson_categories.create);
}}
startIcon={<PlusIcon />}
variant="contained"
>
{t('dashboard.lessonCategories.add')}
</LoadingButton>
</Box> </Box>
</Stack> </Stack>
<LessonCategoriesSelectionProvider lessonCategories={filteredLessonCategories}> <LessonCategoriesSelectionProvider lessonCategories={filteredLessonCategories}>
<Card> <Card>
<LessonCategoriesFilters filters={{ email, phone, status }} sortDir={sortDir} /> <LessonCategoriesFilters filters={{ email, phone, status: spStatus }} sortDir={sortDir} />
<Divider /> <Divider />
<Box sx={{ overflowX: 'auto' }}> <Box sx={{ overflowX: 'auto' }}>
<LessonCategoriesTable rows={filteredLessonCategories} /> <LessonCategoriesTable rows={filteredLessonCategories} />

View File

@@ -11,7 +11,6 @@ import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus'; import { Plus as PlusIcon } from '@phosphor-icons/react/dist/ssr/Plus';
import type { ListResult, RecordModel } from 'pocketbase'; import type { ListResult, RecordModel } from 'pocketbase';
import PocketBase from 'pocketbase';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { paths } from '@/paths'; import { paths } from '@/paths';
@@ -88,19 +87,6 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element {
logger.error(err); logger.error(err);
toast(t('dashboard.lessonTypes.list.error')); toast(t('dashboard.lessonTypes.list.error'));
}); });
// pb.collection(COL_LESSON_TYPES)
// .getFullList()
// .then((lessonTypes: RecordModel[]) => {
// const tempLessonTypes: LessonType[] = lessonTypes.map((lt) => {
// return safeAssignment(lt);
// });
// setLessonTypesData(tempLessonTypes);
// })
// .catch((err) => {
// logger.error(err);
// toast(t('dashboard.lessonTypes.list.error'));
// });
}; };
React.useEffect(() => { React.useEffect(() => {
@@ -178,7 +164,7 @@ function applySort(row: LessonType[], sortDir: 'asc' | 'desc' | undefined): Less
function applyFilters( function applyFilters(
row: LessonType[], row: LessonType[],
{ email, phone, spStatus: status, spName: name, spVisible: visible }: Filters { email, phone, spStatus: status, spName: name, spVisible }: Filters
): LessonType[] { ): LessonType[] {
return row.filter((item) => { return row.filter((item) => {
if (email) { if (email) {
@@ -205,8 +191,8 @@ function applyFilters(
} }
} }
if (visible) { if (spVisible) {
if (!item.visible?.toLowerCase().includes(visible.toLowerCase())) { if (!item.visible?.toLowerCase().includes(spVisible.toLowerCase())) {
return false; return false;
} }
} }

View File

@@ -1,4 +1,18 @@
import { dayjs } from '@/lib/dayjs';
export interface LessonCategory { export interface LessonCategory {
id: string;
isEmpty?: boolean;
name: string;
avatar?: string;
email: string;
phone?: string;
quota: number;
status: 'pending' | 'active' | 'blocked' | 'NA';
createdAt: Date;
}
export interface DBLessonCategory {
id: string; id: string;
name: string; name: string;
avatar?: string; avatar?: string;
@@ -8,3 +22,18 @@ export interface LessonCategory {
status: 'pending' | 'active' | 'blocked'; status: 'pending' | 'active' | 'blocked';
createdAt: Date; createdAt: Date;
} }
export const defaultLessonCategory: LessonCategory = {
isEmpty: true,
id: '',
name: '',
email: '',
quota: -Infinity,
status: 'NA',
createdAt: dayjs('2099-01-01').toDate(),
};
export const emptyLessonCategory: LessonCategory = {
...defaultLessonCategory,
isEmpty: true,
};

View File

@@ -20,7 +20,7 @@ import { dayjs } from '@/lib/dayjs';
import { DataTable } from '@/components/core/data-table'; import { DataTable } from '@/components/core/data-table';
import type { ColumnDef } from '@/components/core/data-table'; import type { ColumnDef } from '@/components/core/data-table';
import { LessonCategory } from './interfaces'; import type { LessonCategory } from './interfaces';
import { useLessonCategoriesSelection } from './lesson-categories-selection-context'; import { useLessonCategoriesSelection } from './lesson-categories-selection-context';
const columns = [ const columns = [
@@ -73,6 +73,7 @@ const columns = [
active: { label: 'Active', icon: <CheckCircleIcon color="var(--mui-palette-success-main)" weight="fill" /> }, active: { label: 'Active', icon: <CheckCircleIcon color="var(--mui-palette-success-main)" weight="fill" /> },
blocked: { label: 'Blocked', icon: <MinusIcon color="var(--mui-palette-error-main)" /> }, blocked: { label: 'Blocked', icon: <MinusIcon color="var(--mui-palette-error-main)" /> },
pending: { label: 'Pending', icon: <ClockIcon color="var(--mui-palette-warning-main)" weight="fill" /> }, pending: { label: 'Pending', icon: <ClockIcon color="var(--mui-palette-warning-main)" weight="fill" /> },
NA: { label: 'NA', icon: <ClockIcon color="var(--mui-palette-warning-main)" weight="fill" /> },
} as const; } as const;
const { label, icon } = mapping[row.status] ?? { label: 'Unknown', icon: null }; const { label, icon } = mapping[row.status] ?? { label: 'Unknown', icon: null };

View File

@@ -1,5 +1,6 @@
const COL_LESSON_TYPES = 'LessonsTypes'; const COL_LESSON_TYPES = 'LessonsTypes';
const COL_LESSON_CATEGORIES = 'LessonsCategories';
const NO_VALUE = 'NO_VALUE'; const NO_VALUE = 'NO_VALUE';
const NO_NUM = -Infinity; const NO_NUM = -Infinity;
export { COL_LESSON_TYPES, NO_VALUE, NO_NUM }; export { COL_LESSON_TYPES, NO_VALUE, NO_NUM, COL_LESSON_CATEGORIES };