update,
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
import * as React from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { COL_LESSON_CATEGORIES } from '@/constants';
|
||||
import GetAllCount from '@/db/LessonCategories/GetAllCount';
|
||||
import GetHiddenCount from '@/db/LessonCategories/GetHiddenCount';
|
||||
import GetVisibleCount from '@/db/LessonCategories/GetVisibleCount';
|
||||
import Button from '@mui/material/Button';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Divider from '@mui/material/Divider';
|
||||
@@ -13,25 +17,23 @@ import Stack from '@mui/material/Stack';
|
||||
import Tab from '@mui/material/Tab';
|
||||
import Tabs from '@mui/material/Tabs';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { paths } from '@/paths';
|
||||
import { pb } from '@/lib/pb';
|
||||
import { FilterButton, FilterPopover, useFilterContext } from '@/components/core/filter-button';
|
||||
import { Option } from '@/components/core/option';
|
||||
|
||||
import { useLessonCategoriesSelection } from './lesson-categories-selection-context';
|
||||
|
||||
// The tabs should be generated using API data.
|
||||
const tabs = [
|
||||
{ label: 'All', value: '', count: 5 },
|
||||
{ label: 'Active', value: 'active', count: 3 },
|
||||
{ label: 'Pending', value: 'pending', count: 1 },
|
||||
{ label: 'Blocked', value: 'blocked', count: 1 },
|
||||
] as const;
|
||||
import { LessonCategory } from './types';
|
||||
|
||||
export interface Filters {
|
||||
email?: string;
|
||||
phone?: string;
|
||||
status?: string;
|
||||
name?: string;
|
||||
visible?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export type SortDir = 'asc' | 'desc';
|
||||
@@ -39,18 +41,47 @@ export type SortDir = 'asc' | 'desc';
|
||||
export interface LessonCategoriesFiltersProps {
|
||||
filters?: Filters;
|
||||
sortDir?: SortDir;
|
||||
fullData: LessonCategory[];
|
||||
}
|
||||
|
||||
export function LessonCategoriesFilters({
|
||||
filters = {},
|
||||
sortDir = 'desc',
|
||||
fullData,
|
||||
}: LessonCategoriesFiltersProps): React.JSX.Element {
|
||||
const { email, phone, status } = filters;
|
||||
const { t } = useTranslation();
|
||||
const { email, phone, status, name, visible, type } = filters;
|
||||
|
||||
const [totalCount, setTotalCount] = React.useState<number>(0);
|
||||
const [visibleCount, setVisibleCount] = React.useState<number>(0);
|
||||
const [hiddenCount, setHiddenCount] = React.useState<number>(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<void> => {
|
||||
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 (
|
||||
<div>
|
||||
<Tabs onChange={handleStatusChange} sx={{ px: 3 }} value={status ?? ''} variant="scrollable">
|
||||
<Tabs onChange={handleVisibleChange} sx={{ px: 3 }} value={visible ?? ''} variant="scrollable">
|
||||
{tabs.map((tab) => (
|
||||
<Tab
|
||||
icon={<Chip label={tab.count} size="small" variant="soft" />}
|
||||
@@ -129,50 +211,124 @@ export function LessonCategoriesFilters({
|
||||
<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' }}>
|
||||
<FilterButton
|
||||
displayValue={email}
|
||||
label="Email"
|
||||
displayValue={name}
|
||||
label={t('Name')}
|
||||
onFilterApply={(value) => {
|
||||
handleEmailChange(value as string);
|
||||
handleNameChange(value as string);
|
||||
}}
|
||||
onFilterDelete={() => {
|
||||
handleEmailChange();
|
||||
handleNameChange();
|
||||
}}
|
||||
popover={<EmailFilterPopover />}
|
||||
value={email}
|
||||
popover={<NameFilterPopover />}
|
||||
value={name}
|
||||
/>
|
||||
|
||||
<FilterButton
|
||||
displayValue={phone}
|
||||
label="Phone number"
|
||||
displayValue={type}
|
||||
label={t('Type')}
|
||||
onFilterApply={(value) => {
|
||||
handlePhoneChange(value as string);
|
||||
handleTypeChange(value as string);
|
||||
}}
|
||||
onFilterDelete={() => {
|
||||
handlePhoneChange();
|
||||
handleTypeChange();
|
||||
}}
|
||||
popover={<PhoneFilterPopover />}
|
||||
value={phone}
|
||||
popover={<TypeFilterPopover />}
|
||||
value={type}
|
||||
/>
|
||||
{hasFilters ? <Button onClick={handleClearFilters}>Clear filters</Button> : null}
|
||||
|
||||
{hasFilters ? <Button onClick={handleClearFilters}>{t('Clear filters')}</Button> : null}
|
||||
</Stack>
|
||||
{selection.selectedAny ? (
|
||||
<Stack direction="row" spacing={2} sx={{ alignItems: 'center' }}>
|
||||
<Typography color="text.secondary" variant="body2">
|
||||
{selection.selected.size} selected
|
||||
{selection.selected.size} {t('selected')}
|
||||
</Typography>
|
||||
<Button color="error" variant="contained">
|
||||
Delete
|
||||
{t('Delete')}
|
||||
</Button>
|
||||
</Stack>
|
||||
) : null}
|
||||
<Select name="sort" onChange={handleSortChange} sx={{ maxWidth: '100%', width: '120px' }} value={sortDir}>
|
||||
<Option value="desc">Newest</Option>
|
||||
<Option value="asc">Oldest</Option>
|
||||
<Option value="desc">{t('Newest')}</Option>
|
||||
<Option value="asc">{t('Oldest')}</Option>
|
||||
</Select>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TypeFilterPopover(): React.JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const { anchorEl, onApply, onClose, open, value: initialValue } = useFilterContext();
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
|
||||
React.useEffect(() => {
|
||||
setValue((initialValue as string | undefined) ?? '');
|
||||
}, [initialValue]);
|
||||
|
||||
return (
|
||||
<FilterPopover anchorEl={anchorEl} onClose={onClose} open={open} title={t('Filter by type')}>
|
||||
<FormControl>
|
||||
<OutlinedInput
|
||||
onChange={(event) => {
|
||||
setValue(event.target.value);
|
||||
}}
|
||||
onKeyUp={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
onApply(value);
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onApply(value);
|
||||
}}
|
||||
variant="contained"
|
||||
>
|
||||
{t('Apply')}
|
||||
</Button>
|
||||
</FilterPopover>
|
||||
);
|
||||
}
|
||||
|
||||
function NameFilterPopover(): React.JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const { anchorEl, onApply, onClose, open, value: initialValue } = useFilterContext();
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
|
||||
React.useEffect(() => {
|
||||
setValue((initialValue as string | undefined) ?? '');
|
||||
}, [initialValue]);
|
||||
|
||||
return (
|
||||
<FilterPopover anchorEl={anchorEl} onClose={onClose} open={open} title={t('Filter by name')}>
|
||||
<FormControl>
|
||||
<OutlinedInput
|
||||
onChange={(event) => {
|
||||
setValue(event.target.value);
|
||||
}}
|
||||
onKeyUp={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
onApply(value);
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onApply(value);
|
||||
}}
|
||||
variant="contained"
|
||||
>
|
||||
{t('Apply')}
|
||||
</Button>
|
||||
</FilterPopover>
|
||||
);
|
||||
}
|
||||
|
||||
function EmailFilterPopover(): React.JSX.Element {
|
||||
const { anchorEl, onApply, onClose, open, value: initialValue } = useFilterContext();
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
|
@@ -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
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Typography color="text.secondary" sx={{ textAlign: 'center' }} variant="body2">
|
||||
{/* TODO: use hyphen here */}
|
||||
{t('No lesson categories found')}
|
||||
{t('no-lesson-categories-found')}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : null}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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';
|
||||
|
@@ -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<void> => {
|
||||
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}
|
||||
/>
|
||||
|
||||
{/*
|
||||
<FilterButton
|
||||
displayValue={email}
|
||||
label="Email"
|
||||
onFilterApply={(value) => {
|
||||
handleEmailChange(value as string);
|
||||
}}
|
||||
onFilterDelete={() => {
|
||||
handleEmailChange();
|
||||
}}
|
||||
popover={<EmailFilterPopover />}
|
||||
value={email}
|
||||
/>
|
||||
*/}
|
||||
|
||||
{/*
|
||||
<FilterButton
|
||||
displayValue={phone}
|
||||
label="Phone number"
|
||||
onFilterApply={(value) => {
|
||||
handlePhoneChange(value as string);
|
||||
}}
|
||||
onFilterDelete={() => {
|
||||
handlePhoneChange();
|
||||
}}
|
||||
popover={<PhoneFilterPopover />}
|
||||
value={phone}
|
||||
/>
|
||||
*/}
|
||||
|
||||
{hasFilters ? <Button onClick={handleClearFilters}>{t('Clear filters')}</Button> : null}
|
||||
</Stack>
|
||||
{selection.selectedAny ? (
|
||||
|
@@ -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;
|
||||
|
@@ -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<LessonType>[] {
|
||||
return [
|
||||
@@ -132,7 +134,6 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef<LessonT
|
||||
name: 'Created at',
|
||||
width: '100px',
|
||||
},
|
||||
|
||||
{
|
||||
formatter: (row): React.JSX.Element => (
|
||||
<Stack direction="row" spacing={1}>
|
||||
@@ -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
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Typography color="text.secondary" sx={{ textAlign: 'center' }} variant="body2">
|
||||
{/* TODO: use hyphen here */}
|
||||
{t('No lesson types found')}
|
||||
{t('no-lesson-types-found')}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : null}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user