'use client'; import * as React from 'react'; import RouterLink from 'next/link'; import { useRouter } from 'next/navigation'; import { 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 CardHeader from '@mui/material/CardHeader'; import FormControl from '@mui/material/FormControl'; import FormHelperText from '@mui/material/FormHelperText'; import InputAdornment from '@mui/material/InputAdornment'; import InputLabel from '@mui/material/InputLabel'; import Link from '@mui/material/Link'; 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 { Camera as CameraIcon } from '@phosphor-icons/react/dist/ssr/Camera'; import { User as UserIcon } from '@phosphor-icons/react/dist/ssr/User'; 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 { fileToBase64 } from '@/lib/file-to-base64'; import getImageUrlFromFile from '@/lib/get-image-url-from-file.ts'; import { pb } from '@/lib/pb'; import { useUser } from '@/hooks/use-user'; import { Option } from '@/components/core/option'; import { toast } from '@/components/core/toaster'; import FormLoading from '@/components/loading'; import ErrorDisplay from '../../error'; 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 AccountDetails(): React.JSX.Element { const router = useRouter(); const { t } = useTranslation(); const { user, isLoading } = useUser(); const [isUpdating, setIsUpdating] = React.useState(false); const [showLoading, setShowLoading] = React.useState(false); const [showError, setShowError] = React.useState({ show: false, detail: '' }); 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_CUSTOMERS).update(customerId, updateData); // toast.success('Customer updated successfully'); // router.push(paths.dashboard.students.list); // } catch (error) { // logger.error(error); // toast.error('Failed to update customer'); // } finally { // setIsUpdating(false); // } }, [router] ); const { control, handleSubmit, formState: { errors }, setValue, reset, watch, } = useForm({ defaultValues, resolver: zodResolver(schema) }); const loadExistingData = React.useCallback(async () => { setShowLoading(true); if (user) { try { const result = await pb.collection(COL_USER_METAS).getOne(user.id); reset({ ...defaultValues, ...result }); console.log({ result }); if (result.avatar) { // TODO: remove me // const fetchResult = await fetch( // `http://127.0.0.1:8090/api/files/${result.collectionId}/${result.id}/${result.avatar}` // ); const fetchResult = await fetch(getImageUrlFromFile(result.collectionId, result.id, result.avatar)); const blob = await fetchResult.blob(); const url = await fileToBase64(blob); setValue('avatar', url); } } catch (error) { logger.error(error); // TODO: add i18n here toast.error('Failed to load customer data'); setShowError({ show: true, detail: JSON.stringify(error, null, 2) }); } finally { setShowLoading(false); } } }, [user, reset, setValue]); React.useEffect(() => { void loadExistingData(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (showLoading) return ; if (!user) return <>loading; if (showError.show) return ( ); return (
} title="Basic details" /> {t('select')} ( Name {errors.name ? {errors.name.message} : null} )} /> ( Email {errors.email ? {errors.email.message} : null} )} /> ( Phone {errors.phone ? {errors.phone.message} : null} )} /> Title Biography (optional) 0/200 characters {/* */} {t('edit.updateButton')}
); }