'use client'; import * as React from 'react'; import RouterLink from 'next/link'; import { useParams, useRouter } from 'next/navigation'; // import { COL_TEACHERS, COL_USER_METAS } from '@/constants'; import { zodResolver } from '@hookform/resolvers/zod'; import { LoadingButton } from '@mui/lab'; // 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 Divider from '@mui/material/Divider'; import FormControl from '@mui/material/FormControl'; import FormHelperText from '@mui/material/FormHelperText'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; 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 { 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 { base64ToFile, fileToBase64 } from '@/lib/file-to-base64'; import { pb } from '@/lib/pb'; import { toast } from '@/components/core/toaster'; import FormLoading from '@/components/loading'; // import ErrorDisplay from '../../error'; import ErrorDisplay from '../error'; import isDevelopment from '@/lib/check-is-development'; // TODO: review this const schema = zod.object({ name: zod.string().min(1, 'Name is required').max(255), email: zod.string().email('Must be a valid email').min(1, 'Email is required').max(255), phone: zod.string().min(1, 'Phone is required').max(25), company: zod.string().max(255).optional(), billingAddress: zod.object({ country: zod.string().min(1, 'Country is required').max(255), state: zod.string().min(1, 'State is required').max(255), city: zod.string().min(1, 'City is required').max(255), zipCode: zod.string().min(1, 'Zip code is required').max(255), line1: zod.string().min(1, 'Street line 1 is required').max(255), line2: zod.string().max(255).optional(), }), taxId: zod.string().max(255).optional(), timezone: zod.string().min(1, 'Timezone is required').max(255), language: zod.string().min(1, 'Language is required').max(255), currency: zod.string().min(1, 'Currency is required').max(255), avatar: zod.string().optional(), }); type Values = zod.infer; const defaultValues = { name: '', email: '', phone: '', company: '', billingAddress: { country: '', state: '', city: '', zipCode: '', line1: '', line2: '', }, taxId: '', timezone: '', language: '', currency: '', avatar: '', } satisfies Values; export function TeacherEditForm(): React.JSX.Element { const router = useRouter(); const { t } = useTranslation(['lp_categories']); const { id: teacherId } = useParams<{ id: string }>(); // const [isUpdating, setIsUpdating] = React.useState(false); const [showLoading, setShowLoading] = React.useState(false); // const [showError, setShowError] = React.useState({ show: false, detail: '' }); const { control, handleSubmit, formState: { errors }, setValue, reset, watch, } = useForm({ defaultValues, resolver: zodResolver(schema) }); const onSubmit = React.useCallback( async (values: Values): Promise => { setIsUpdating(true); const updateData = { name: values.name, email: values.email, phone: values.phone, company: values.company, billingAddress: values.billingAddress, taxId: values.taxId, timezone: values.timezone, language: values.language, currency: values.currency, avatar: values.avatar ? await base64ToFile(values.avatar) : null, }; try { await pb.collection(COL_USER_METAS).update(teacherId, updateData); toast.success('Teacher updated successfully'); router.push(paths.dashboard.teachers.list); } catch (error) { logger.error(error); toast.error('Failed to update teacher'); } finally { setIsUpdating(false); } }, [teacherId, router] ); const avatarInputRef = React.useRef(null); const avatar = watch('avatar'); const handleAvatarChange = React.useCallback( async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { const url = await fileToBase64(file); setValue('avatar', url); } }, [setValue] ); // TODO: need to align with save form // use trycatch const [textDescription, setTextDescription] = React.useState(''); const [textRemarks, setTextRemarks] = React.useState(''); // load existing data when user arrive const loadExistingData = React.useCallback( async (id: string) => { setShowLoading(true); try { const result = await pb.collection(COL_USER_METAS).getOne(id); reset({ ...defaultValues, ...result }); console.log({ result }); if (result.avatar) { const fetchResult = await fetch( `http://127.0.0.1:8090/api/files/${result.collectionId}/${result.id}/${result.avatar}` ); const blob = await fetchResult.blob(); const url = await fileToBase64(blob); setValue('avatar', url); } } catch (error) { logger.error(error); toast.error('Failed to load teacher data'); setShowError({ show: true, detail: JSON.stringify(error, null, 2) }); } finally { setShowLoading(false); } }, [reset, setValue] ); React.useEffect(() => { void loadExistingData(teacherId); // eslint-disable-next-line react-hooks/exhaustive-deps }, [teacherId]); if (showLoading) return ; if (showError.show) return ( ); return (
} spacing={4} > {t('edit.basic-info')} {t('edit.avatar')} {t('edit.avatarRequirements')} ( Name {errors.name ? {errors.name.message} : null} )} /> ( Email {errors.email ? {errors.email.message} : null} )} /> ( Phone {errors.phone ? {errors.phone.message} : null} )} /> ( Company {errors.company ? {errors.company.message} : null} )} /> {/* */} Billing Information ( Country {errors.billingAddress?.country ? ( {errors.billingAddress.country.message} ) : null} )} /> ( State {errors.billingAddress?.state ? ( {errors.billingAddress.state.message} ) : null} )} /> ( City {errors.billingAddress?.city ? ( {errors.billingAddress.city.message} ) : null} )} /> ( Zip Code {errors.billingAddress?.zipCode ? ( {errors.billingAddress.zipCode.message} ) : null} )} /> ( Address Line 1 {errors.billingAddress?.line1 ? ( {errors.billingAddress.line1.message} ) : null} )} /> ( Tax ID {errors.taxId ? {errors.taxId.message} : null} )} /> Additional Information ( Timezone {errors.timezone ? {errors.timezone.message} : null} )} /> ( Language {errors.language ? {errors.language.message} : null} )} /> ( Currency {errors.currency ? {errors.currency.message} : null} )} /> {t('edit.updateButton')}
{JSON.stringify({ errors }, null, 2)}
); }