update edit lesson categories,
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { dayjs } from '@/lib/dayjs';
|
||||
|
||||
import type { CreateForm, LessonCategory } from './type';
|
||||
import type { CreateForm, LessonCategory } from './types';
|
||||
|
||||
export const defaultLessonCategory: LessonCategory = {
|
||||
isEmpty: false,
|
||||
@@ -14,6 +14,7 @@ export const defaultLessonCategory: LessonCategory = {
|
||||
description: 'default-description',
|
||||
remarks: 'default-remarks',
|
||||
//
|
||||
collectionId: '0000000000',
|
||||
createdAt: dayjs('2099-01-01').toDate(),
|
||||
//
|
||||
name: '',
|
||||
|
@@ -5,7 +5,7 @@ import * as React from 'react';
|
||||
import { useSelection } from '@/hooks/use-selection';
|
||||
import type { Selection } from '@/hooks/use-selection';
|
||||
|
||||
import type { LessonCategory } from './type';
|
||||
import type { LessonCategory } from './types';
|
||||
|
||||
// import type { LessonCategory } from './lesson-categories-table';
|
||||
// import type { LessonCategory } from '@/components/dashboard/lesson_category/interfaces';
|
||||
|
@@ -28,7 +28,7 @@ import type { ColumnDef } from '@/components/core/data-table';
|
||||
import ConfirmDeleteModal from './confirm-delete-modal';
|
||||
// import type { LessonCategory } from './interfaces.1ts';
|
||||
import { useLessonCategoriesSelection } from './lesson-categories-selection-context';
|
||||
import { LessonCategory } from './type';
|
||||
import { LessonCategory } from './types';
|
||||
|
||||
function columns(handleDeleteClick: (testId: string) => void): ColumnDef<LessonCategory>[] {
|
||||
return [
|
||||
@@ -43,7 +43,10 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef<LessonC
|
||||
variant="subtitle2"
|
||||
>
|
||||
<Stack direction="row" spacing={1} sx={{ alignItems: 'center' }}>
|
||||
<Avatar src={row.avatar} variant="rounded">
|
||||
<Avatar
|
||||
src={`http://127.0.0.1:8090/api/files/${row.collectionId}/${row.id}/${row.cat_image}`}
|
||||
variant="rounded"
|
||||
>
|
||||
<ImagesIcon size={32} />
|
||||
</Avatar>{' '}
|
||||
<div>
|
||||
@@ -72,9 +75,6 @@ function columns(handleDeleteClick: (testId: string) => void): ColumnDef<LessonC
|
||||
name: 'word-count',
|
||||
width: '100px',
|
||||
},
|
||||
|
||||
{ field: 'phone', name: 'Phone number', width: '100px' },
|
||||
|
||||
{
|
||||
formatter: (row): React.JSX.Element => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
|
@@ -3,8 +3,10 @@
|
||||
import * as React from 'react';
|
||||
import RouterLink from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { COL_LESSON_CATEGORIES, NS_LESSON_CATEGORY } from '@/constants';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Avatar } from '@mui/material';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { Avatar, Divider, MenuItem } from '@mui/material';
|
||||
// import Avatar from '@mui/material/Avatar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
@@ -12,7 +14,6 @@ import Card from '@mui/material/Card';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import FormHelperText from '@mui/material/FormHelperText';
|
||||
@@ -25,11 +26,13 @@ import Grid from '@mui/material/Unstable_Grid2';
|
||||
import { Camera as CameraIcon } from '@phosphor-icons/react/dist/ssr/Camera';
|
||||
// import axios from 'axios';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z as zod } from 'zod';
|
||||
|
||||
import { paths } from '@/paths';
|
||||
import { logger } from '@/lib/default-logger';
|
||||
import { Option } from '@/components/core/option';
|
||||
import { TextEditor } from '@/components/core/text-editor/text-editor';
|
||||
import { toast } from '@/components/core/toaster';
|
||||
|
||||
import { fileToBase64 } from './file-to-base64';
|
||||
@@ -71,6 +74,11 @@ const defaultValues = {
|
||||
|
||||
export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation(['common', 'lesson_category']);
|
||||
|
||||
const NS_DEFAULT = { ns: 'lesson_category' };
|
||||
|
||||
const [isCreating, setIsCreating] = React.useState<boolean>(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -81,7 +89,8 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
} = useForm<Values>({ defaultValues, resolver: zodResolver(schema) });
|
||||
|
||||
const onSubmit = React.useCallback(
|
||||
async (_: Values): Promise<void> => {
|
||||
async (values: Values): Promise<void> => {
|
||||
setIsCreating(true);
|
||||
try {
|
||||
// Make API request
|
||||
toast.success('Customer updated');
|
||||
@@ -115,19 +124,20 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
<CardContent>
|
||||
<Stack divider={<Divider />} spacing={4}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Account information</Typography>
|
||||
<Typography variant="h6">{t('create.typeInformation', NS_DEFAULT)}</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid xs={12}>
|
||||
<Stack direction="row" spacing={3} sx={{ alignItems: 'center' }}>
|
||||
<Box
|
||||
sx={{
|
||||
border: '1px dashed var(--mui-palette-divider)',
|
||||
borderRadius: '50%',
|
||||
borderRadius: '5%',
|
||||
display: 'inline-flex',
|
||||
p: '4px',
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
src={avatar}
|
||||
sx={{
|
||||
'--Avatar-size': '100px',
|
||||
@@ -143,8 +153,8 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
</Avatar>
|
||||
</Box>
|
||||
<Stack spacing={1} sx={{ alignItems: 'flex-start' }}>
|
||||
<Typography variant="subtitle1">Avatar</Typography>
|
||||
<Typography variant="caption">Min 400x400px, PNG or JPEG</Typography>
|
||||
<Typography variant="subtitle1">{t('create.avatar', NS_DEFAULT)}</Typography>
|
||||
<Typography variant="caption">{t('create.avatarRequirements', NS_DEFAULT)}</Typography>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
@@ -152,7 +162,7 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
}}
|
||||
variant="outlined"
|
||||
>
|
||||
Select
|
||||
{t('create.avatar_select', NS_DEFAULT)}
|
||||
</Button>
|
||||
<input hidden onChange={handleAvatarChange} ref={avatarInputRef} type="file" />
|
||||
</Stack>
|
||||
@@ -164,7 +174,7 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.name)} fullWidth>
|
||||
<InputLabel required>Name</InputLabel>
|
||||
<InputLabel required>{t('create.name', NS_DEFAULT)}</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.name ? <FormHelperText>{errors.name.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
@@ -213,25 +223,21 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Billing information</Typography>
|
||||
<Typography variant="h6">{t('create.detail-information', NS_DEFAULT)}</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="billingAddress.country"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.billingAddress?.country)} fullWidth>
|
||||
<InputLabel required>Country</InputLabel>
|
||||
<Select {...field}>
|
||||
<Option value="">Choose a country</Option>
|
||||
<Option value="us">United States</Option>
|
||||
<Option value="de">Germany</Option>
|
||||
<Option value="es">Spain</Option>
|
||||
</Select>
|
||||
{errors.billingAddress?.country ? (
|
||||
<FormHelperText>{errors.billingAddress?.country?.message}</FormHelperText>
|
||||
) : null}
|
||||
</FormControl>
|
||||
<Box>
|
||||
<Typography variant="subtitle1" color="text-secondary">
|
||||
{t('create.description', NS_DEFAULT)}
|
||||
</Typography>
|
||||
<Box sx={{ mt: '8px', '& .tiptap-container': { height: '400px' } }}>
|
||||
<TextEditor content="" placeholder="Write something" />
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
@@ -240,134 +246,14 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
control={control}
|
||||
name="billingAddress.state"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.billingAddress?.state)} fullWidth>
|
||||
<InputLabel required>State</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.billingAddress?.state ? (
|
||||
<FormHelperText>{errors.billingAddress?.state?.message}</FormHelperText>
|
||||
) : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="billingAddress.city"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.billingAddress?.city)} fullWidth>
|
||||
<InputLabel required>City</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.billingAddress?.city ? (
|
||||
<FormHelperText>{errors.billingAddress?.city?.message}</FormHelperText>
|
||||
) : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="billingAddress.zipCode"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.billingAddress?.zipCode)} fullWidth>
|
||||
<InputLabel required>Zip code</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.billingAddress?.zipCode ? (
|
||||
<FormHelperText>{errors.billingAddress?.zipCode?.message}</FormHelperText>
|
||||
) : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="billingAddress.line1"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.billingAddress?.line1)} fullWidth>
|
||||
<InputLabel required>Address</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.billingAddress?.line1 ? (
|
||||
<FormHelperText>{errors.billingAddress?.line1?.message}</FormHelperText>
|
||||
) : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="taxId"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.taxId)} fullWidth>
|
||||
<InputLabel>Tax ID</InputLabel>
|
||||
<OutlinedInput {...field} placeholder="e.g EU372054390" />
|
||||
{errors.taxId ? <FormHelperText>{errors.taxId.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Shipping information</Typography>
|
||||
<FormControlLabel control={<Checkbox defaultChecked />} label="Same as billing address" />
|
||||
</Stack>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Additional information</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="timezone"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.timezone)} fullWidth>
|
||||
<InputLabel required>Timezone</InputLabel>
|
||||
<Select {...field}>
|
||||
<Option value="">Select a timezone</Option>
|
||||
<Option value="new_york">US - New York</Option>
|
||||
<Option value="california">US - California</Option>
|
||||
<Option value="london">UK - London</Option>
|
||||
</Select>
|
||||
{errors.timezone ? <FormHelperText>{errors.timezone.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="language"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.language)} fullWidth>
|
||||
<InputLabel required>Language</InputLabel>
|
||||
<Select {...field}>
|
||||
<Option value="">Select a language</Option>
|
||||
<Option value="en">English</Option>
|
||||
<Option value="es">Spanish</Option>
|
||||
<Option value="de">German</Option>
|
||||
</Select>
|
||||
{errors.language ? <FormHelperText>{errors.language.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="currency"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.currency)} fullWidth>
|
||||
<InputLabel>Currency</InputLabel>
|
||||
<Select {...field}>
|
||||
<Option value="">Select a currency</Option>
|
||||
<Option value="USD">USD</Option>
|
||||
<Option value="EUR">EUR</Option>
|
||||
<Option value="RON">RON</Option>
|
||||
</Select>
|
||||
{errors.currency ? <FormHelperText>{errors.currency.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
<Box>
|
||||
<Typography variant="subtitle1" color="text.secondary">
|
||||
{t('create.remarks', NS_DEFAULT)}
|
||||
</Typography>
|
||||
<Box sx={{ mt: '8px', '& .tiptap-container': { height: '400px' } }}>
|
||||
<TextEditor content="" placeholder="Write something" />
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
@@ -377,11 +263,12 @@ export function LessonCategoryCreateForm(): React.JSX.Element {
|
||||
</CardContent>
|
||||
<CardActions sx={{ justifyContent: 'flex-end' }}>
|
||||
<Button color="secondary" component={RouterLink} href={paths.dashboard.lesson_categories.list}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" variant="contained">
|
||||
Create customer
|
||||
{t('create.cancelButton', NS_DEFAULT)}
|
||||
</Button>
|
||||
|
||||
<LoadingButton disabled={isCreating} loading={isCreating} type="submit" variant="contained">
|
||||
{t('create.createButton', NS_DEFAULT)}
|
||||
</LoadingButton>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</form>
|
||||
|
@@ -0,0 +1,334 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import RouterLink from 'next/link';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { COL_LESSON_CATEGORIES, NS_LESSON_CATEGORY } from '@/constants';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { Avatar, Divider, MenuItem } from '@mui/material';
|
||||
// import Avatar from '@mui/material/Avatar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
// import Checkbox from '@mui/material/Checkbox';
|
||||
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
// import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import FormHelperText from '@mui/material/FormHelperText';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import Select from '@mui/material/Select';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Grid from '@mui/material/Unstable_Grid2';
|
||||
import { Camera as CameraIcon } from '@phosphor-icons/react/dist/ssr/Camera';
|
||||
import type { RecordModel } from 'pocketbase';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z as zod } from 'zod';
|
||||
|
||||
import { paths } from '@/paths';
|
||||
import { logger } from '@/lib/default-logger';
|
||||
import { pb } from '@/lib/pb';
|
||||
import { Option } from '@/components/core/option';
|
||||
import { TextEditor } from '@/components/core/text-editor/text-editor';
|
||||
import { toast } from '@/components/core/toaster';
|
||||
import FormLoading from '@/components/loading';
|
||||
|
||||
import ErrorDisplay from '../error';
|
||||
import { defaultLessonCategory } from './_constants';
|
||||
import { fileToBase64 } from './file-to-base64';
|
||||
import { LessonCategory, EditFormProps } from './types';
|
||||
|
||||
const schema = zod.object({
|
||||
cat_name: zod.string().min(1, 'Name is required').max(255),
|
||||
type: zod.string().min(1, 'Name is required').max(255),
|
||||
pos: zod.number().min(1, 'Phone is required').max(15),
|
||||
visible: zod.string().max(255),
|
||||
description: zod.string().optional(),
|
||||
remarks: zod.string().optional(),
|
||||
});
|
||||
|
||||
type Values = zod.infer<typeof schema>;
|
||||
|
||||
const defaultValues = {
|
||||
cat_name: '',
|
||||
type: '',
|
||||
pos: 1,
|
||||
visible: 'visible',
|
||||
} satisfies Values;
|
||||
|
||||
export function LessonCategoryEditForm(): React.JSX.Element {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation(['common', 'lesson_category']);
|
||||
|
||||
const NS_DEFAULT = { ns: 'lesson_category' };
|
||||
const { cat_id: catId } = useParams<{ cat_id: string }>();
|
||||
//
|
||||
const [isUpdating, setIsUpdating] = React.useState<boolean>(false);
|
||||
const [showLoading, setShowLoading] = React.useState<boolean>(false);
|
||||
const [showError, setShowError] = React.useState<boolean>(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
watch,
|
||||
} = useForm<Values>({ defaultValues, resolver: zodResolver(schema) });
|
||||
|
||||
const onSubmit = React.useCallback(async (values: Values): Promise<void> => {
|
||||
// setIsUpdating(true);
|
||||
// const tempUpdate: LessonCategoryEditFormProps = {
|
||||
// name: values.cat_name,
|
||||
// type: values.type,
|
||||
// pos: values.pos,
|
||||
// visible: values.visible ? 'visible' : 'hidden',
|
||||
// };
|
||||
|
||||
|
||||
// pb.collection(COL_LESSON_CATEGORIES)
|
||||
// .update(catId, tempUpdate)
|
||||
// .then((res) => {
|
||||
// logger.debug(res);
|
||||
// toast.success(t('update.success', NS_DEFAULT));
|
||||
// setIsUpdating(false);
|
||||
// router.push(paths.dashboard.lesson_categories.list);
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// logger.error(err);
|
||||
// toast.error('Something went wrong!');
|
||||
// })
|
||||
// .finally(() => {
|
||||
// //
|
||||
// setIsUpdating(false);
|
||||
// });
|
||||
}, []);
|
||||
|
||||
const avatarInputRef = React.useRef<HTMLInputElement>(null);
|
||||
// const avatar = watch('avatar');
|
||||
|
||||
const handleAvatarChange = React.useCallback(
|
||||
async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
|
||||
if (file) {
|
||||
const url = await fileToBase64(file);
|
||||
// setValue('avatar', url);
|
||||
}
|
||||
},
|
||||
[setValue]
|
||||
);
|
||||
|
||||
const [textDescription, setTextDescription] = React.useState<string>('loading');
|
||||
const handleLoad = React.useCallback(
|
||||
(id: string) => {
|
||||
setShowLoading(true);
|
||||
pb.collection(COL_LESSON_CATEGORIES)
|
||||
.getOne(id)
|
||||
.then((model: RecordModel) => {
|
||||
const temp: LessonCategory = { ...defaultLessonCategory, ...model };
|
||||
reset(temp);
|
||||
setTextDescription(temp.description);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
toast(t('list.error', NS_DEFAULT));
|
||||
})
|
||||
.finally(() => {
|
||||
setShowLoading(false);
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[catId]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
handleLoad(catId);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [catId]);
|
||||
|
||||
if (showLoading) return <FormLoading />;
|
||||
if (showError)
|
||||
return (
|
||||
<ErrorDisplay
|
||||
message={t('error.unable-to-process-request', NS_DEFAULT)}
|
||||
code="500"
|
||||
details={t('error.detailed-error-information', NS_DEFAULT)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Stack divider={<Divider />} spacing={4}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">{t('edit.basic-info', NS_DEFAULT)}</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid xs={12}>
|
||||
<Stack direction="row" spacing={3} sx={{ alignItems: 'center' }}>
|
||||
<Box
|
||||
sx={{
|
||||
border: '1px dashed var(--mui-palette-divider)',
|
||||
borderRadius: '5%',
|
||||
display: 'inline-flex',
|
||||
p: '4px',
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
<Avatar
|
||||
src={avatar}
|
||||
sx={{
|
||||
'--Avatar-size': '100px',
|
||||
'--Icon-fontSize': 'var(--icon-fontSize-lg)',
|
||||
alignItems: 'center',
|
||||
bgcolor: 'var(--mui-palette-background-level1)',
|
||||
color: 'var(--mui-palette-text-primary)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
// TODO: resume me
|
||||
<CameraIcon fontSize="var(--Icon-fontSize)" />
|
||||
</Avatar>
|
||||
*/}
|
||||
</Box>
|
||||
<Stack spacing={1} sx={{ alignItems: 'flex-start' }}>
|
||||
<Typography variant="subtitle1">{t('edit.avatar', NS_DEFAULT)}</Typography>
|
||||
<Typography variant="caption">{t('edit.avatarRequirements', NS_DEFAULT)}</Typography>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
avatarInputRef.current?.click();
|
||||
}}
|
||||
variant="outlined"
|
||||
>
|
||||
{t('edit.select', NS_DEFAULT)}
|
||||
</Button>
|
||||
<input hidden onChange={handleAvatarChange} ref={avatarInputRef} type="file" />
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="cat_name"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.cat_name)} fullWidth>
|
||||
<InputLabel required>{t('edit.name', NS_DEFAULT)}</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.cat_name ? <FormHelperText>{errors.cat_name.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="pos"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.pos)} fullWidth>
|
||||
<InputLabel required>{t('edit.position', NS_DEFAULT)}</InputLabel>
|
||||
<OutlinedInput
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
type="number"
|
||||
/>
|
||||
|
||||
{errors.pos ? <FormHelperText>{errors.pos.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="visible"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.visible)} fullWidth>
|
||||
<InputLabel>{t('edit.visible', NS_DEFAULT)}</InputLabel>
|
||||
<Select {...field}>
|
||||
<MenuItem value="visible">{t('edit.visible', NS_DEFAULT)}</MenuItem>
|
||||
<MenuItem value="hidden">{t('edit.hidden', NS_DEFAULT)}</MenuItem>
|
||||
</Select>
|
||||
|
||||
{errors.visible ? <FormHelperText>{errors.visible.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">{t('create.detail-information', NS_DEFAULT)}</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field }) => {
|
||||
console.log({ field });
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="subtitle1" color="text-secondary">
|
||||
{t('create.description', NS_DEFAULT)}
|
||||
</Typography>
|
||||
<Box sx={{ mt: '8px', '& .tiptap-container': { height: '400px' } }}>
|
||||
{JSON.stringify({ field })}
|
||||
<TextEditor
|
||||
{...field}
|
||||
content={textDescription}
|
||||
onUpdate={({ editor }) => {
|
||||
console.log(editor.getHTML());
|
||||
field.onChange({ target: { value: editor.getHTML() } });
|
||||
}}
|
||||
placeholder={t('edit.write-something', NS_DEFAULT)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="billingAddress.state"
|
||||
render={({ field }) => (
|
||||
<Box>
|
||||
<Typography variant="subtitle1" color="text.secondary">
|
||||
{t('create.remarks', NS_DEFAULT)}
|
||||
</Typography>
|
||||
<Box sx={{ mt: '8px', '& .tiptap-container': { height: '400px' } }}>
|
||||
<TextEditor content="" placeholder="Write something" />
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<CardActions sx={{ justifyContent: 'flex-end' }}>
|
||||
<Button color="secondary" component={RouterLink} href={paths.dashboard.lesson_types.list}>
|
||||
{t('edit.cancelButton', NS_DEFAULT)}
|
||||
</Button>
|
||||
|
||||
<LoadingButton disabled={isUpdating} loading={isUpdating} type="submit" variant="contained">
|
||||
{t('edit.updateButton', NS_DEFAULT)}
|
||||
</LoadingButton>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</form>
|
||||
);
|
||||
}
|
@@ -0,0 +1,352 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import RouterLink from 'next/link';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { COL_LESSON_CATEGORIES, NS_LESSON_CATEGORY } from '@/constants';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { Avatar, Divider, MenuItem } from '@mui/material';
|
||||
// import Avatar from '@mui/material/Avatar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
// import Checkbox from '@mui/material/Checkbox';
|
||||
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
// import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import FormHelperText from '@mui/material/FormHelperText';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import Select from '@mui/material/Select';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Grid from '@mui/material/Unstable_Grid2';
|
||||
import { Camera as CameraIcon } from '@phosphor-icons/react/dist/ssr/Camera';
|
||||
import type { RecordModel } from 'pocketbase';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z as zod } from 'zod';
|
||||
|
||||
import { paths } from '@/paths';
|
||||
import { dayjs } from '@/lib/dayjs';
|
||||
import { logger } from '@/lib/default-logger';
|
||||
import { pb } from '@/lib/pb';
|
||||
import { Option } from '@/components/core/option';
|
||||
import { TextEditor } from '@/components/core/text-editor/text-editor';
|
||||
import { toast } from '@/components/core/toaster';
|
||||
import FormLoading from '@/components/loading';
|
||||
|
||||
import ErrorDisplay from '../error';
|
||||
import { defaultLessonCategory } from './_constants';
|
||||
import { fileToBase64 } from './file-to-base64';
|
||||
import { EditFormProps, LessonCategory } from './types';
|
||||
|
||||
// TODO: review this
|
||||
const schema = zod.object({
|
||||
cat_name: zod.string().min(1, 'name-is-required').max(255),
|
||||
//
|
||||
pos: zod.number().min(1, 'Phone is required').max(99),
|
||||
visible: zod.string().max(255),
|
||||
//
|
||||
description: zod.string().optional(),
|
||||
remarks: zod.string().optional(),
|
||||
});
|
||||
|
||||
type Values = zod.infer<typeof schema>;
|
||||
|
||||
const defaultValues = {
|
||||
cat_name: '',
|
||||
// cat_image: undefined,
|
||||
pos: 0,
|
||||
visible: 'hidden',
|
||||
// lesson_id: 'default-lesson-id',
|
||||
description: 'default-description',
|
||||
remarks: 'default-remarks',
|
||||
//
|
||||
} satisfies Values;
|
||||
|
||||
export function LessonCategoryEditForm(): React.JSX.Element {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation(['common', 'lesson_category']);
|
||||
|
||||
const NS_DEFAULT = { ns: 'lesson_category' };
|
||||
|
||||
const { cat_id: catId } = useParams<{ cat_id: string }>();
|
||||
//
|
||||
const [isUpdating, setIsUpdating] = React.useState<boolean>(false);
|
||||
const [showLoading, setShowLoading] = React.useState<boolean>(false);
|
||||
const [showError, setShowError] = React.useState<boolean>(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
watch,
|
||||
} = useForm<Values>({ defaultValues, resolver: zodResolver(schema) });
|
||||
|
||||
const onSubmit = React.useCallback(async (values: Values): Promise<void> => {
|
||||
setIsUpdating(true);
|
||||
const tempUpdate: EditFormProps = {
|
||||
cat_name: values.cat_name,
|
||||
pos: values.pos,
|
||||
visible: values.visible,
|
||||
description: values.description,
|
||||
remarks: values.remarks,
|
||||
};
|
||||
|
||||
pb.collection(COL_LESSON_CATEGORIES)
|
||||
.update(catId, tempUpdate)
|
||||
.then((res) => {
|
||||
logger.debug(res);
|
||||
toast.success(t('update.success', NS_DEFAULT));
|
||||
router.push(paths.dashboard.lesson_categories.list);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
toast.error('Something went wrong!');
|
||||
})
|
||||
.finally(() => {
|
||||
//
|
||||
setIsUpdating(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const avatarInputRef = React.useRef<HTMLInputElement>(null);
|
||||
// const avatar = watch('avatar');
|
||||
|
||||
const handleAvatarChange = React.useCallback(
|
||||
async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
|
||||
if (file) {
|
||||
const url = await fileToBase64(file);
|
||||
// setValue('avatar', url);
|
||||
}
|
||||
},
|
||||
[setValue]
|
||||
);
|
||||
|
||||
const [textDescription, setTextDescription] = React.useState<string>('loading');
|
||||
const [textRemarks, setTextRemarks] = React.useState<string>('loading');
|
||||
const handleLoad = React.useCallback(
|
||||
(id: string) => {
|
||||
setShowLoading(true);
|
||||
pb.collection(COL_LESSON_CATEGORIES)
|
||||
.getOne(id)
|
||||
.then((model: RecordModel) => {
|
||||
const temp: LessonCategory = { ...defaultLessonCategory, ...model };
|
||||
reset(temp);
|
||||
setTextDescription(temp.description);
|
||||
setTextRemarks(temp.remarks);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
toast(t('list.error', NS_DEFAULT));
|
||||
})
|
||||
.finally(() => {
|
||||
setShowLoading(false);
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[catId]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
handleLoad(catId);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [catId]);
|
||||
|
||||
if (showLoading) return <FormLoading />;
|
||||
if (showError)
|
||||
return (
|
||||
<ErrorDisplay
|
||||
message={t('error.unable-to-process-request', NS_DEFAULT)}
|
||||
code="500"
|
||||
details={t('error.detailed-error-information', NS_DEFAULT)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Stack divider={<Divider />} spacing={4}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">{t('edit.basic-info', NS_DEFAULT)}</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid xs={12}>
|
||||
<Stack direction="row" spacing={3} sx={{ alignItems: 'center' }}>
|
||||
<Box
|
||||
sx={{
|
||||
border: '1px dashed var(--mui-palette-divider)',
|
||||
borderRadius: '5%',
|
||||
display: 'inline-flex',
|
||||
p: '4px',
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
<Avatar
|
||||
src={avatar}
|
||||
sx={{
|
||||
'--Avatar-size': '100px',
|
||||
'--Icon-fontSize': 'var(--icon-fontSize-lg)',
|
||||
alignItems: 'center',
|
||||
bgcolor: 'var(--mui-palette-background-level1)',
|
||||
color: 'var(--mui-palette-text-primary)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
// TODO: resume me
|
||||
<CameraIcon fontSize="var(--Icon-fontSize)" />
|
||||
</Avatar>
|
||||
*/}
|
||||
</Box>
|
||||
<Stack spacing={1} sx={{ alignItems: 'flex-start' }}>
|
||||
<Typography variant="subtitle1">{t('edit.avatar', NS_DEFAULT)}</Typography>
|
||||
<Typography variant="caption">{t('edit.avatarRequirements', NS_DEFAULT)}</Typography>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
avatarInputRef.current?.click();
|
||||
}}
|
||||
variant="outlined"
|
||||
>
|
||||
{t('edit.select', NS_DEFAULT)}
|
||||
</Button>
|
||||
<input hidden onChange={handleAvatarChange} ref={avatarInputRef} type="file" />
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
disabled={isUpdating}
|
||||
control={control}
|
||||
name="cat_name"
|
||||
render={({ field }) => (
|
||||
<FormControl disabled={isUpdating} error={Boolean(errors.cat_name)} fullWidth>
|
||||
<InputLabel required>{t('edit.name', NS_DEFAULT)}</InputLabel>
|
||||
<OutlinedInput {...field} />
|
||||
{errors.cat_name ? <FormHelperText>{errors.cat_name.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
disabled={isUpdating}
|
||||
control={control}
|
||||
name="pos"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.pos)} fullWidth>
|
||||
<InputLabel required>{t('edit.position', NS_DEFAULT)}</InputLabel>
|
||||
<OutlinedInput
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
type="number"
|
||||
/>
|
||||
|
||||
{errors.pos ? <FormHelperText>{errors.pos.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
disabled={isUpdating}
|
||||
control={control}
|
||||
name="visible"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.visible)} fullWidth>
|
||||
<InputLabel>{t('edit.visible', NS_DEFAULT)}</InputLabel>
|
||||
<Select {...field}>
|
||||
<MenuItem value="visible">{t('edit.visible', NS_DEFAULT)}</MenuItem>
|
||||
<MenuItem value="hidden">{t('edit.hidden', NS_DEFAULT)}</MenuItem>
|
||||
</Select>
|
||||
|
||||
{errors.visible ? <FormHelperText>{errors.visible.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">{t('create.detail-information', NS_DEFAULT)}</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
disabled={isUpdating}
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="subtitle1" color="text-secondary">
|
||||
{t('create.description', NS_DEFAULT)}
|
||||
</Typography>
|
||||
<Box sx={{ mt: '8px', '& .tiptap-container': { height: '400px' } }}>
|
||||
<TextEditor
|
||||
{...field}
|
||||
content={textDescription}
|
||||
onUpdate={({ editor }) => {
|
||||
field.onChange({ target: { value: editor.getHTML() } });
|
||||
}}
|
||||
placeholder={t('edit.write-something', NS_DEFAULT)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12}>
|
||||
<Controller
|
||||
disabled={isUpdating}
|
||||
control={control}
|
||||
name="remarks"
|
||||
render={({ field }) => (
|
||||
<Box>
|
||||
<Typography variant="subtitle1" color="text.secondary">
|
||||
{t('create.remarks', NS_DEFAULT)}
|
||||
</Typography>
|
||||
<Box sx={{ mt: '8px', '& .tiptap-container': { height: '400px' } }}>
|
||||
<TextEditor
|
||||
content={textRemarks}
|
||||
onUpdate={({ editor }) => {
|
||||
field.onChange({ target: { value: editor.getText() } });
|
||||
}}
|
||||
hideToolbar={true}
|
||||
placeholder={t('edit.write-something', NS_DEFAULT)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<CardActions sx={{ justifyContent: 'flex-end' }}>
|
||||
<Button color="secondary" component={RouterLink} href={paths.dashboard.lesson_types.list}>
|
||||
{t('edit.cancelButton', NS_DEFAULT)}
|
||||
</Button>
|
||||
|
||||
<LoadingButton disabled={isUpdating} loading={isUpdating} type="submit" variant="contained">
|
||||
{t('edit.updateButton', NS_DEFAULT)}
|
||||
</LoadingButton>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</form>
|
||||
);
|
||||
}
|
@@ -10,6 +10,7 @@ export interface LessonCategory {
|
||||
lesson_id: string;
|
||||
description: string;
|
||||
remarks: string;
|
||||
collectionId: string;
|
||||
//
|
||||
name: string;
|
||||
avatar: string;
|
||||
@@ -26,3 +27,11 @@ export interface CreateForm {
|
||||
pos: number;
|
||||
visible: string;
|
||||
}
|
||||
|
||||
export interface EditFormProps {
|
||||
cat_name: string;
|
||||
pos: number;
|
||||
visible: string;
|
||||
description?: string;
|
||||
remarks?: string;
|
||||
}
|
@@ -60,6 +60,7 @@ const defaultValues = {
|
||||
export function LessonTypeCreateForm(): React.JSX.Element {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [isCreating, setIsCreating] = React.useState<boolean>(false);
|
||||
|
||||
const {
|
||||
@@ -79,7 +80,6 @@ export function LessonTypeCreateForm(): React.JSX.Element {
|
||||
pb.collection(COL_LESSON_TYPES)
|
||||
.create(data)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
logger.debug(res);
|
||||
toast.success(t('dashboard.lessonTypes.update.success'));
|
||||
setIsCreating(false);
|
||||
@@ -90,23 +90,6 @@ export function LessonTypeCreateForm(): React.JSX.Element {
|
||||
toast.error('Something went wrong!');
|
||||
setIsCreating(false);
|
||||
});
|
||||
|
||||
// const tempCreate: LessonTypeCreateForm = LessonTypeCreateFormDefault;
|
||||
// tempCreate.name = values.name;
|
||||
// tempCreate.type = values.type;
|
||||
// tempCreate.pos = 1;
|
||||
// tempCreate.visible = 'visible';
|
||||
|
||||
// createLessonType(tempCreate)
|
||||
// .then((res) => {
|
||||
// router.push(paths.dashboard.lesson_types.list);
|
||||
// toast.success(t('dashboard.lessonTypes.create.success'));
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// logger.error(err);
|
||||
// toast.error(t('dashboard.lessonTypes.create.error'));
|
||||
// setIsCreating(false);
|
||||
// });
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
@@ -6,7 +6,7 @@ import { useParams, useRouter } from 'next/navigation';
|
||||
import { COL_LESSON_TYPES } from '@/constants';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { MenuItem } from '@mui/material';
|
||||
import { Avatar, MenuItem } from '@mui/material';
|
||||
// import Avatar from '@mui/material/Avatar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
@@ -35,6 +35,7 @@ import { logger } from '@/lib/default-logger';
|
||||
import { pb } from '@/lib/pb';
|
||||
// import { Option } from '@/components/core/option';
|
||||
import { toast } from '@/components/core/toaster';
|
||||
import FormLoading from '@/components/loading';
|
||||
|
||||
// import { getLessonTypeById, updateLessonType } from './http-actions';
|
||||
// TODO: this may be wrong
|
||||
@@ -74,8 +75,9 @@ export function LessonTypeEditForm(): React.JSX.Element {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { typeId } = useParams<{ typeId: string }>();
|
||||
//
|
||||
const [isUpdating, setIsUpdating] = React.useState<boolean>(false);
|
||||
const [isLoading, setIsLoading] = React.useState<boolean>(false);
|
||||
const [showLoading, setShowLoading] = React.useState<boolean>(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -83,7 +85,7 @@ export function LessonTypeEditForm(): React.JSX.Element {
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
// watch,
|
||||
watch,
|
||||
} = useForm<Values>({ defaultValues, resolver: zodResolver(schema) });
|
||||
|
||||
const onSubmit = React.useCallback(async (values: Values): Promise<void> => {
|
||||
@@ -129,10 +131,10 @@ export function LessonTypeEditForm(): React.JSX.Element {
|
||||
(id: string) => {
|
||||
pb.collection(COL_LESSON_TYPES)
|
||||
.getOne(id)
|
||||
.then((lessonType: RecordModel) => {
|
||||
reset({ ...defaultLessonType, ...lessonType });
|
||||
.then((model: RecordModel) => {
|
||||
reset({ ...defaultLessonType, ...model });
|
||||
|
||||
setIsLoading(false);
|
||||
setShowLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
@@ -148,7 +150,7 @@ export function LessonTypeEditForm(): React.JSX.Element {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [typeId]);
|
||||
|
||||
if (isLoading) return <>loading</>;
|
||||
if (showLoading) return <FormLoading />;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
|
Reference in New Issue
Block a user