diff --git a/002_source/cms/src/app/dashboard/lesson_categories/create/page.tsx b/002_source/cms/src/app/dashboard/lesson_categories/create/page.tsx new file mode 100644 index 0000000..e69b0c4 --- /dev/null +++ b/002_source/cms/src/app/dashboard/lesson_categories/create/page.tsx @@ -0,0 +1,49 @@ +'use client'; + +import * as React from 'react'; + +import RouterLink from 'next/link'; +import Box from '@mui/material/Box'; +import Link from '@mui/material/Link'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { ArrowLeft as ArrowLeftIcon } from '@phosphor-icons/react/dist/ssr/ArrowLeft'; + +import { config } from '@/config'; +import { paths } from '@/paths'; +import { CustomerCreateForm } from '@/components/dashboard/lesson_category/lesson-category-create-form'; + + +export default function Page(): React.JSX.Element { + return ( + + + +
+ + + Lesson Categories + +
+
+ Create customer +
+
+ +
+
+ ); +} diff --git a/002_source/cms/src/components/dashboard/lesson_category/lesson-category-create-form.tsx b/002_source/cms/src/components/dashboard/lesson_category/lesson-category-create-form.tsx new file mode 100644 index 0000000..c8c4f35 --- /dev/null +++ b/002_source/cms/src/components/dashboard/lesson_category/lesson-category-create-form.tsx @@ -0,0 +1,398 @@ +'use client'; + +import * as React from 'react'; +import RouterLink from 'next/link'; +import { useRouter } from 'next/navigation'; +import { zodResolver } from '@hookform/resolvers/zod'; +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 Divider from '@mui/material/Divider'; +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 { Controller, useForm } from 'react-hook-form'; +import { z as zod } from 'zod'; + +import { paths } from '@/paths'; +import { logger } from '@/lib/default-logger'; +import { Option } from '@/components/core/option'; +import { toast } from '@/components/core/toaster'; + +function fileToBase64(file: Blob): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + resolve(reader.result as string); + }; + reader.onerror = () => { + reject(new Error('Error converting file to base64')); + }; + }); +} + +const schema = zod.object({ + avatar: zod.string().optional(), + 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(15), + company: zod.string().max(255), + 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), +}); + +type Values = zod.infer; + +const defaultValues = { + avatar: '', + name: '', + email: '', + phone: '', + company: '', + billingAddress: { country: '', state: '', city: '', zipCode: '', line1: '', line2: '' }, + taxId: '', + timezone: 'new_york', + language: 'en', + currency: 'USD', +} satisfies Values; + +export function CustomerCreateForm(): React.JSX.Element { + const router = useRouter(); + + const { + control, + handleSubmit, + formState: { errors }, + setValue, + watch, + } = useForm({ defaultValues, resolver: zodResolver(schema) }); + + const onSubmit = React.useCallback( + async (_: Values): Promise => { + try { + // Make API request + toast.success('Customer updated'); + router.push(paths.dashboard.lesson_categories.details('1')); + } catch (err) { + logger.error(err); + toast.error('Something went wrong!'); + } + }, + [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] + ); + + return ( +
+ + + } spacing={4}> + + Account information + + + + + + + + + + Avatar + Min 400x400px, PNG or JPEG + + + + + + + ( + + Name + + {errors.name ? {errors.name.message} : null} + + )} + /> + + + ( + + Email address + + {errors.email ? {errors.email.message} : null} + + )} + /> + + + ( + + Phone number + + {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 + + {errors.billingAddress?.line1 ? ( + {errors.billingAddress?.line1?.message} + ) : null} + + )} + /> + + + ( + + Tax ID + + {errors.taxId ? {errors.taxId.message} : null} + + )} + /> + + + + + Shipping information + } label="Same as billing address" /> + + + Additional information + + + ( + + Timezone + + {errors.timezone ? {errors.timezone.message} : null} + + )} + /> + + + ( + + Language + + {errors.language ? {errors.language.message} : null} + + )} + /> + + + ( + + Currency + + {errors.currency ? {errors.currency.message} : null} + + )} + /> + + + + + + + + + + +
+ ); +}