update,
This commit is contained in:
@@ -58,3 +58,4 @@ NEXT_PUBLIC_MAPBOX_API_KEY=
|
|||||||
# Google Tag Manager
|
# Google Tag Manager
|
||||||
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=
|
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=
|
||||||
|
|
||||||
|
NEXT_PUBLIC_POCKETBASE_URL=http://localhost:8090
|
@@ -38,3 +38,5 @@ NEXT_PUBLIC_MAPBOX_API_KEY=
|
|||||||
|
|
||||||
# Google Tag Manager
|
# Google Tag Manager
|
||||||
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=
|
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=
|
||||||
|
|
||||||
|
NEXT_PUBLIC_POCKETBASE_URL=http://localhost:8090
|
5
002_source/cms/src/app/dashboard/lesson_types/db.ts
Normal file
5
002_source/cms/src/app/dashboard/lesson_types/db.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import PocketBase, { RecordModel } from 'pocketbase';
|
||||||
|
|
||||||
|
export function Helloworld(): string {
|
||||||
|
return 'helloworld';
|
||||||
|
}
|
@@ -9,12 +9,15 @@ 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 { 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';
|
||||||
import { logger } from '@/lib/default-logger';
|
import { logger } from '@/lib/default-logger';
|
||||||
import { toast } from '@/components/core/toaster';
|
import { toast } from '@/components/core/toaster';
|
||||||
import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType';
|
import type { LessonType } from '@/components/dashboard/lesson_type/ILessonType';
|
||||||
|
import { safeAssignment } from '@/components/dashboard/lesson_type/interfaces';
|
||||||
import { LessonTypesFilters } from '@/components/dashboard/lesson_type/lesson-types-filters';
|
import { LessonTypesFilters } from '@/components/dashboard/lesson_type/lesson-types-filters';
|
||||||
import type { Filters } 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 { LessonTypesPagination } from '@/components/dashboard/lesson_type/lesson-types-pagination';
|
||||||
@@ -22,46 +25,55 @@ import { LessonTypesSelectionProvider } from '@/components/dashboard/lesson_type
|
|||||||
import { LessonTypesTable } from '@/components/dashboard/lesson_type/lesson-types-table';
|
import { LessonTypesTable } from '@/components/dashboard/lesson_type/lesson-types-table';
|
||||||
import FormLoading from '@/components/loading';
|
import FormLoading from '@/components/loading';
|
||||||
|
|
||||||
|
import { Helloworld } from './db';
|
||||||
|
|
||||||
|
const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
searchParams: {
|
searchParams: {
|
||||||
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 { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { email, phone, sortDir, status, name, visible, type } = searchParams;
|
const { email, phone, sortDir, spStatus, spName, spVisible, spType } = searchParams;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [isLoadingAddPage, setIsLoadingAddPage] = React.useState<boolean>(false);
|
const [isLoadingAddPage, setIsLoadingAddPage] = React.useState<boolean>(false);
|
||||||
const [lessonTypesData, setLessonTypesData] = React.useState<LessonType[]>([]);
|
const [lessonTypesData, setLessonTypesData] = React.useState<LessonType[]>([]);
|
||||||
|
// const [recordModel, setRecordModel] = React.useState<RecordModel[]>([]);
|
||||||
const sortedLessonTypes = applySort(lessonTypesData, sortDir);
|
const sortedLessonTypes = applySort(lessonTypesData, sortDir);
|
||||||
const filteredLessonTypes = applyFilters(sortedLessonTypes, {
|
const filteredLessonTypes = applyFilters(sortedLessonTypes, {
|
||||||
email,
|
email,
|
||||||
phone,
|
phone,
|
||||||
status,
|
spStatus,
|
||||||
name,
|
spName,
|
||||||
type,
|
spType,
|
||||||
visible,
|
spVisible,
|
||||||
//
|
//
|
||||||
});
|
});
|
||||||
|
|
||||||
const reloadRows = () => {
|
const reloadRows = () => {
|
||||||
// listLessonTypes()
|
pb.collection('LessonsTypes')
|
||||||
// .then((lessonTypes: LessonType[]) => {
|
.getFullList()
|
||||||
// setLessonTypesData(lessonTypes);
|
.then((lessonTypes: RecordModel[]) => {
|
||||||
// })
|
const tempLessonTypes: LessonType[] = lessonTypes.map((lt) => {
|
||||||
// .catch((err) => {
|
return safeAssignment(lt);
|
||||||
// logger.error(err);
|
});
|
||||||
// toast(t('dashboard.lessonTypes.list.error'));
|
setLessonTypesData(tempLessonTypes);
|
||||||
// });
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
logger.error(err);
|
||||||
|
toast(t('dashboard.lessonTypes.list.error'));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -102,7 +114,7 @@ export default function Page({ searchParams }: PageProps): React.JSX.Element {
|
|||||||
<LessonTypesSelectionProvider lessonTypes={filteredLessonTypes}>
|
<LessonTypesSelectionProvider lessonTypes={filteredLessonTypes}>
|
||||||
<Card>
|
<Card>
|
||||||
<LessonTypesFilters
|
<LessonTypesFilters
|
||||||
filters={{ email, phone, status, name, visible, type }}
|
filters={{ email, phone, spStatus, spName, spVisible, spType }}
|
||||||
fullData={lessonTypesData}
|
fullData={lessonTypesData}
|
||||||
sortDir={sortDir}
|
sortDir={sortDir}
|
||||||
/>
|
/>
|
||||||
@@ -131,7 +143,10 @@ function applySort(row: LessonType[], sortDir: 'asc' | 'desc' | undefined): Less
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyFilters(row: LessonType[], { email, phone, status, name, visible }: Filters): LessonType[] {
|
function applyFilters(
|
||||||
|
row: LessonType[],
|
||||||
|
{ email, phone, spStatus: status, spName: name, spVisible: visible }: Filters
|
||||||
|
): LessonType[] {
|
||||||
return row.filter((item) => {
|
return row.filter((item) => {
|
||||||
if (email) {
|
if (email) {
|
||||||
if (!item.email?.toLowerCase().includes(email.toLowerCase())) {
|
if (!item.email?.toLowerCase().includes(email.toLowerCase())) {
|
||||||
|
@@ -1,3 +1,9 @@
|
|||||||
|
import type { RecordModel } from 'pocketbase';
|
||||||
|
|
||||||
|
import { dayjs } from '@/lib/dayjs';
|
||||||
|
|
||||||
|
import type { LessonType } from './ILessonType';
|
||||||
|
|
||||||
export interface LessonTypeEditFormProps {
|
export interface LessonTypeEditFormProps {
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
@@ -23,3 +29,41 @@ export const LessonTypeCreateFormDefault: LessonTypeCreateForm = {
|
|||||||
pos: 1,
|
pos: 1,
|
||||||
visible: 'visible',
|
visible: 'visible',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defaultLessonType: 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 function safeAssignment(inTemp: LessonType | RecordModel): LessonType {
|
||||||
|
const { id, name, type, pos, visible, createdAt, email, quota, status } = { ...defaultLessonType, ...inTemp };
|
||||||
|
const oCreatedAt = dayjs(createdAt).toDate();
|
||||||
|
|
||||||
|
const output: LessonType = {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
pos,
|
||||||
|
visible,
|
||||||
|
createdAt: oCreatedAt,
|
||||||
|
email,
|
||||||
|
quota,
|
||||||
|
status,
|
||||||
|
};
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
@@ -19,16 +19,16 @@ import { paths } from '@/paths';
|
|||||||
import { FilterButton, FilterPopover, useFilterContext } from '@/components/core/filter-button';
|
import { FilterButton, FilterPopover, useFilterContext } from '@/components/core/filter-button';
|
||||||
import { Option } from '@/components/core/option';
|
import { Option } from '@/components/core/option';
|
||||||
|
|
||||||
import { LessonType } from './ILessonType';
|
import type { LessonType } from './ILessonType';
|
||||||
import { useLessonTypesSelection } from './lesson-types-selection-context';
|
import { useLessonTypesSelection } from './lesson-types-selection-context';
|
||||||
|
|
||||||
export interface Filters {
|
export interface Filters {
|
||||||
email?: string;
|
email?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
status?: string;
|
spStatus?: string;
|
||||||
name?: string;
|
spName?: string;
|
||||||
visible?: string;
|
spVisible?: string;
|
||||||
type?: string;
|
spType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SortDir = 'asc' | 'desc';
|
export type SortDir = 'asc' | 'desc';
|
||||||
@@ -45,7 +45,7 @@ export function LessonTypesFilters({
|
|||||||
fullData,
|
fullData,
|
||||||
}: LessonTypesFiltersProps): React.JSX.Element {
|
}: LessonTypesFiltersProps): React.JSX.Element {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { email, phone, status, name, visible, type } = filters;
|
const { email, phone, spStatus: status, spName, spVisible, spType } = filters;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -81,8 +81,8 @@ export function LessonTypesFilters({
|
|||||||
searchParams.set('sortDir', newSortDir);
|
searchParams.set('sortDir', newSortDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFilters.status) {
|
if (newFilters.spStatus) {
|
||||||
searchParams.set('status', newFilters.status);
|
searchParams.set('status', newFilters.spStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFilters.email) {
|
if (newFilters.email) {
|
||||||
@@ -93,16 +93,16 @@ export function LessonTypesFilters({
|
|||||||
searchParams.set('phone', newFilters.phone);
|
searchParams.set('phone', newFilters.phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFilters.name) {
|
if (newFilters.spName) {
|
||||||
searchParams.set('name', newFilters.name);
|
searchParams.set('name', newFilters.spName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFilters.type) {
|
if (newFilters.spType) {
|
||||||
searchParams.set('type', newFilters.type);
|
searchParams.set('type', newFilters.spType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFilters.visible) {
|
if (newFilters.spVisible) {
|
||||||
searchParams.set('visible', newFilters.visible);
|
searchParams.set('visible', newFilters.spVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
router.push(`${paths.dashboard.lesson_types.list}?${searchParams.toString()}`);
|
router.push(`${paths.dashboard.lesson_types.list}?${searchParams.toString()}`);
|
||||||
@@ -116,28 +116,28 @@ export function LessonTypesFilters({
|
|||||||
|
|
||||||
const handleStatusChange = React.useCallback(
|
const handleStatusChange = React.useCallback(
|
||||||
(_: React.SyntheticEvent, value: string) => {
|
(_: React.SyntheticEvent, value: string) => {
|
||||||
updateSearchParams({ ...filters, status: value }, sortDir);
|
updateSearchParams({ ...filters, spStatus: value }, sortDir);
|
||||||
},
|
},
|
||||||
[updateSearchParams, filters, sortDir]
|
[updateSearchParams, filters, sortDir]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleVisibleChange = React.useCallback(
|
const handleVisibleChange = React.useCallback(
|
||||||
(_: React.SyntheticEvent, value: string) => {
|
(_: React.SyntheticEvent, value: string) => {
|
||||||
updateSearchParams({ ...filters, visible: value }, sortDir);
|
updateSearchParams({ ...filters, spVisible: value }, sortDir);
|
||||||
},
|
},
|
||||||
[updateSearchParams, filters, sortDir]
|
[updateSearchParams, filters, sortDir]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleNameChange = React.useCallback(
|
const handleNameChange = React.useCallback(
|
||||||
(value?: string) => {
|
(value?: string) => {
|
||||||
updateSearchParams({ ...filters, name: value }, sortDir);
|
updateSearchParams({ ...filters, spName: value }, sortDir);
|
||||||
},
|
},
|
||||||
[updateSearchParams, filters, sortDir]
|
[updateSearchParams, filters, sortDir]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTypeChange = React.useCallback(
|
const handleTypeChange = React.useCallback(
|
||||||
(value?: string) => {
|
(value?: string) => {
|
||||||
updateSearchParams({ ...filters, type: value }, sortDir);
|
updateSearchParams({ ...filters, spType: value }, sortDir);
|
||||||
},
|
},
|
||||||
[updateSearchParams, filters, sortDir]
|
[updateSearchParams, filters, sortDir]
|
||||||
);
|
);
|
||||||
@@ -163,11 +163,11 @@ export function LessonTypesFilters({
|
|||||||
[updateSearchParams, filters]
|
[updateSearchParams, filters]
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasFilters = status || email || phone || visible || name || type;
|
const hasFilters = status || email || phone || spVisible || spName || spType;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Tabs onChange={handleVisibleChange} sx={{ px: 3 }} value={visible ?? ''} variant="scrollable">
|
<Tabs onChange={handleVisibleChange} sx={{ px: 3 }} value={spVisible ?? ''} variant="scrollable">
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
<Tab
|
<Tab
|
||||||
icon={<Chip label={tab.count} size="small" variant="soft" />}
|
icon={<Chip label={tab.count} size="small" variant="soft" />}
|
||||||
@@ -184,7 +184,7 @@ export function LessonTypesFilters({
|
|||||||
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flexWrap: 'wrap', px: 3, py: 2 }}>
|
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flexWrap: 'wrap', px: 3, py: 2 }}>
|
||||||
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flex: '1 1 auto', flexWrap: 'wrap' }}>
|
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flex: '1 1 auto', flexWrap: 'wrap' }}>
|
||||||
<FilterButton
|
<FilterButton
|
||||||
displayValue={name}
|
displayValue={spName}
|
||||||
label={t('Name')}
|
label={t('Name')}
|
||||||
onFilterApply={(value) => {
|
onFilterApply={(value) => {
|
||||||
handleNameChange(value as string);
|
handleNameChange(value as string);
|
||||||
@@ -193,11 +193,11 @@ export function LessonTypesFilters({
|
|||||||
handleNameChange();
|
handleNameChange();
|
||||||
}}
|
}}
|
||||||
popover={<NameFilterPopover />}
|
popover={<NameFilterPopover />}
|
||||||
value={name}
|
value={spName}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FilterButton
|
<FilterButton
|
||||||
displayValue={type}
|
displayValue={spType}
|
||||||
label={t('Type')}
|
label={t('Type')}
|
||||||
onFilterApply={(value) => {
|
onFilterApply={(value) => {
|
||||||
handleTypeChange(value as string);
|
handleTypeChange(value as string);
|
||||||
@@ -206,7 +206,7 @@ export function LessonTypesFilters({
|
|||||||
handleTypeChange();
|
handleTypeChange();
|
||||||
}}
|
}}
|
||||||
popover={<TypeFilterPopover />}
|
popover={<TypeFilterPopover />}
|
||||||
value={type}
|
value={spType}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
|
3
002_source/cms/src/lib/pb.ts
Normal file
3
002_source/cms/src/lib/pb.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
|
export const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);
|
Reference in New Issue
Block a user