From c70e327438fc665647a5a2b373377f3fa11d51be Mon Sep 17 00:00:00 2001 From: sirin Date: Wed, 23 Oct 2024 00:29:20 +0700 Subject: [PATCH] feat: add edit profile functionality --- src/app/(user)/profile/[uid]/edit/page.tsx | 134 +++++++++++++++++++++ src/app/(user)/profile/[uid]/page.tsx | 5 +- src/lib/data/bucket/uploadAvatar.ts | 31 +++++ src/lib/data/profileMutate.ts | 48 ++++++++ src/types/schemas/profile.schema.ts | 27 +++++ 5 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 src/app/(user)/profile/[uid]/edit/page.tsx create mode 100644 src/lib/data/bucket/uploadAvatar.ts create mode 100644 src/lib/data/profileMutate.ts create mode 100644 src/types/schemas/profile.schema.ts diff --git a/src/app/(user)/profile/[uid]/edit/page.tsx b/src/app/(user)/profile/[uid]/edit/page.tsx new file mode 100644 index 0000000..e9fdf21 --- /dev/null +++ b/src/app/(user)/profile/[uid]/edit/page.tsx @@ -0,0 +1,134 @@ +"use client"; + +import { updateProfile } from "@/lib/data/profileMutate"; +import { useForm } from "react-hook-form"; +import { Form, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage } from "@/components/ui/form"; +import { z } from "zod"; +import { profileSchema } from "@/types/schemas/profile.schema"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Textarea } from "@/components/ui/textarea"; +import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; +import { uploadAvatar } from "@/lib/data/bucket/uploadAvatar"; +import toast from "react-hot-toast"; +import { useRouter } from "next/navigation"; +import { Separator } from "@/components/ui/separator"; + +export default function EditProfilePage({ params }: { params: { uid: string } }) { + const uid = params.uid; + const client = createSupabaseClient(); + const router = useRouter(); + + const profileForm = useForm>({ + resolver: zodResolver(profileSchema), + }); + + const onProfileSubmit = async (updates: z.infer) => { + const { avatars, username, full_name, bio } = updates; + + try { + let avatarUrl = null; + + if (avatars instanceof File) { + const avatarData = await uploadAvatar(client, avatars, uid); + avatarUrl = avatarData?.path + ? `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/avatars/${avatarData.path}` + : null; + } + + const result = await updateProfile(client, uid, { + username, + full_name, + bio, + ...(avatarUrl && { avatar_url: avatarUrl }), + }); + + if (result) { + toast.success("Profile updated successfully!"); + router.push(`/profile/${uid}`); + } else { + toast.error("No fields to update!"); + } + } catch (error) { + toast.error("Error updating profile!"); + console.error("Error updating profile:", error); + } + }; + + return ( +
+
+ Update Profile + +
+
+
+ + ( + + Avatar + + onChange(event.target.files && event.target.files[0])} + /> + + + + + )} + /> + ( + + Username + + + + This is your public display name. + + + )} + /> + ( + + Full Name + + + + This is your public full name. + + + )} + /> + ( + + Bio + +