"use client"; import type React from "react"; import type { User } from "@/src/models/users/users.model"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { Loader2, ImageIcon } from "lucide-react"; import { Form, FormControl, FormField, FormItem, FormMessage, } from "@/app/_components/ui/form"; import { Input } from "@/app/_components/ui/input"; import { Button } from "@/app/_components/ui/button"; import { Avatar, AvatarFallback, AvatarImage, } from "@/app/_components/ui/avatar"; import { Label } from "@/app/_components/ui/label"; import { Separator } from "@/app/_components/ui/separator"; import { Switch } from "@/app/_components/ui/switch"; import { useRef, useState } from "react"; import { createClient } from "@/utils/supabase/client"; import { ScrollArea } from "@/app/_components/ui/scroll-area"; const profileFormSchema = z.object({ preferred_name: z.string().nullable().optional(), avatar: z.string().nullable().optional(), }); type ProfileFormValues = z.infer; interface ProfileSettingsProps { user: User | null; } export function ProfileSettings({ user }: ProfileSettingsProps) { const [isUploading, setIsUploading] = useState(false); const fileInputRef = useRef(null); const supabase = createClient(); // Use profile data with fallbacks const preferredName = user?.profile?.first_name || ""; const userEmail = user?.email || ""; const userAvatar = user?.profile?.avatar || ""; const form = useForm({ resolver: zodResolver(profileFormSchema), defaultValues: { preferred_name: preferredName || "", avatar: userAvatar || "", }, }); const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file || !user?.id) return; try { setIsUploading(true); // Upload to Supabase Storage const fileExt = file.name.split(".").pop(); const fileName = `${user.id}-${Date.now()}.${fileExt}`; const filePath = `avatars/${fileName}`; const { error: uploadError, data } = await supabase.storage .from("profiles") .upload(filePath, file, { upsert: true, contentType: file.type, }); if (uploadError) throw uploadError; // Get the public URL const { data: { publicUrl }, } = supabase.storage.from("profiles").getPublicUrl(filePath); // Update the form value form.setValue("avatar", publicUrl); } catch (error) { console.error("Error uploading avatar:", error); } finally { setIsUploading(false); } }; const handleAvatarClick = () => { fileInputRef.current?.click(); }; async function onSubmit(data: ProfileFormValues) { try { if (!user?.id) return; // Update profile in database const { error } = await supabase .from("profiles") .update({ first_name: data.preferred_name, avatar: data.avatar, }) .eq("user_id", user.id); if (error) throw error; } catch (error) { console.error("Error updating profile:", error); } } return (

Account

{preferredName?.[0]?.toUpperCase() || userEmail?.[0]?.toUpperCase()}
{isUploading ? ( ) : ( )}
( )} />
{/* */}

Account security

{userEmail}

Set a permanent password to login to your account.

Add an additional layer of security to your account during login.

Securely sign-in with on-device biometric authentication.

Support

Grant temporary access to your account for support purposes.

Permanently delete the account and remove access from all workspaces.

); }