"use client"; import Image from "next/image"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { toast } from "sonner"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { PasswordInput } from "@/components/ui/password-input"; import { signUp, signIn } from "@/lib/auth-client"; import { useRouter } from "next/navigation"; import { useState, useEffect, ChangeEvent } from "react"; import { z } from "zod"; import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons"; import { Loader2, X } from "lucide-react"; const signUpSchema = z .object({ firstName: z.string().min(1, "First name is required"), lastName: z.string().min(1, "Last name is required"), email: z.string().email("Invalid email address"), image: z .instanceof(File) .optional() .refine((file) => !file || file.type.startsWith("image/"), { message: "Invalid file type. Only images are allowed.", path: ["image"], }), password: z.string().min(6, "Password must be at least 6 characters"), passwordConfirmation: z .string() .min(6, "Password must be at least 6 characters"), }) .refine((data) => data.password === data.passwordConfirmation, { message: "Passwords do not match", path: ["passwordConfirmation"], }); type FormDataType = z.infer; type ErrorsType = Partial>; type TouchedType = Partial>; export function SignUp() { const [formData, setFormData] = useState({ firstName: "", lastName: "", email: "", password: "", image: undefined, passwordConfirmation: "", }); const [errors, setErrors] = useState({}); const [isValid, setIsValid] = useState(false); const [touched, setTouched] = useState({}); const [loading, setLoading] = useState(false); const [image, setImage] = useState(null); const [imagePreview, setImagePreview] = useState(null); const router = useRouter(); useEffect(() => { const validationResult = signUpSchema.safeParse(formData); if (!validationResult.success) { const newErrors: ErrorsType = {}; validationResult.error.errors.forEach((err) => { if (err.path[0]) newErrors[err.path[0] as keyof FormDataType] = err.message; }); setErrors(newErrors); setIsValid(false); } else { setErrors({}); setIsValid(true); } }, [formData]); const handleChange = (e: ChangeEvent) => { const { id, value } = e.target; setFormData((prev) => ({ ...prev, [id]: value })); setTouched((prev) => ({ ...prev, [id]: true })); }; const handleImageChange = (e: ChangeEvent) => { const file = e.target.files?.[0] || null; setImage(file); setFormData((prev) => ({ ...prev, image: file || undefined })); if (file) { const reader = new FileReader(); reader.onload = () => setImagePreview(reader.result as string); reader.readAsDataURL(file); } else { setImagePreview(null); } }; return ( Sign Up Enter your information to create an account
{touched.firstName && errors.firstName && (

{errors.firstName}

)}
{touched.lastName && errors.lastName && (

{errors.lastName}

)}
{touched.email && errors.email && (

{errors.email}

)}
{touched.password && errors.password && (

{errors.password}

)}
{touched.passwordConfirmation && errors.passwordConfirmation && (

{errors.passwordConfirmation}

)}
{imagePreview && (
Profile preview
)} {imagePreview && ( { setImage(null); setImagePreview(null); }} /> )}
); } async function convertImageToBase64(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result as string); reader.onerror = reject; reader.readAsDataURL(file); }); }