"use client" import { useState, useEffect } from "react" import Link from "next/link" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Separator } from "@/components/ui/separator" import { Switch } from "@/components/ui/switch" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Badge } from "@/components/ui/badge" import { ProtectedRoute } from "@/components/protected-route" import { useAuth } from "@/contexts/supabase-auth-context" import { ArrowLeft, Camera, Save, Calendar, MapPin, LinkIcon, Bell, Shield, MessageSquare, Search, Tag, User, Plus, Clock, Settings, CheckCircle, FileText } from "lucide-react" import { supabase } from "@/lib/supabase"; import { swal } from "@/lib/sweetalert"; import Cropper from "react-easy-crop"; import { getCroppedImg } from "@/lib/crop"; export default function ProfilePage() { const { user } = useAuth() // Use actual user data or fallback to mock data const userData = user; const [userBuilds, setUserBuilds] = useState([]); const [pageLoading, setPageLoading] = useState(true); const [uploading, setUploading] = useState(false); const [avatarUrl, setAvatarUrl] = useState(user?.avatar_url || ""); const [isEditing, setIsEditing] = useState(false) const [profileData, setProfileData] = useState({ username: userData?.user_name || "", email: userData?.email || "", bio: userData?.bio || "", location: userData?.location || "", website: userData?.website || "", joinDate: userData?.created_at ? new Date(userData.created_at) : new Date(), }); const [notifications, setNotifications] = useState({ emailUpdates: true, buildLikes: true, comments: true, followers: false, newsletter: true, }) const [privacy, setPrivacy] = useState({ profilePublic: true, showBuilds: true, showActivity: false, showEmail: false, }) const [imageSrc, setImageSrc] = useState(null); const [crop, setCrop] = useState({ x: 0, y: 0 }); const [zoom, setZoom] = useState(1); const [croppedAreaPixels, setCroppedAreaPixels] = useState(null); const [followers, setFollowers] = useState(0); const [following, setFollowing] = useState(0); // Support tickets state const [tickets, setTickets] = useState([]); const [ticketSearchTerm, setTicketSearchTerm] = useState(""); const [ticketStatusFilter, setTicketStatusFilter] = useState("all"); const [ticketTypeFilter, setTicketTypeFilter] = useState("all"); useEffect(() => { const loadEverything = async () => { if (!user) return; try { setPageLoading(true); // Fetch followers count const followersQuery = supabase .from("followers") .select("*", { count: "exact", head: true }) .eq("user_id", user.user_id); // Fetch following count const followingQuery = supabase .from("followers") .select("*", { count: "exact", head: true }) .eq("follower_user_id", user.user_id); // Fetch builds const buildsQuery = supabase .from("builds") .select("*") .eq("user_id", user.user_id) .order("date_created", { ascending: false }); // Load tickets from localStorage const ticketsPromise = new Promise((resolve) => { if (typeof window === "undefined") return resolve([]); const savedTickets = localStorage.getItem("buildmate-support-tickets"); if (!savedTickets) return resolve([]); try { const parsed = JSON.parse(savedTickets); const userTickets = parsed.filter((ticket: any) => ticket.userId === user.user_id || !ticket.userId ); resolve( userTickets.map((ticket: any) => ({ ...ticket, replies: Array.isArray(ticket.replies) ? ticket.replies.length : typeof ticket.replies === "number" ? ticket.replies : 0, })) ); } catch { resolve([]); } }); // Wait for ALL of them const [ { count: followersCount }, { count: followingCount }, { data: buildsData }, ticketsData ] = await Promise.all([ followersQuery, followingQuery, buildsQuery, ticketsPromise ]); setFollowers(followersCount || 0); setFollowing(followingCount || 0); setUserBuilds(buildsData || []); setTickets(ticketsData || []); } catch (err) { console.error("Failed to load profile page:", err); } finally { setPageLoading(false); // ✅ ONLY finishes when everything is done } }; loadEverything(); }, [user]); // When file is selected const handleFileChange = async (event: React.ChangeEvent) => { if (!event.target.files || event.target.files.length === 0) return; const file = event.target.files[0]; const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { setImageSrc(reader.result as string); }; }; // Called when crop is done const onCropComplete = (_croppedArea: any, croppedPixels: any) => { setCroppedAreaPixels(croppedPixels); }; // Upload cropped image const handleUpload = async () => { if (!imageSrc || !user?.supabase_id) { swal.warning("No image", "Please select an image to upload."); return; } if (!croppedAreaPixels) { swal.warning("Crop required", "Please crop the image first."); return; } setUploading(true); try { const croppedBlob = await getCroppedImg(imageSrc, croppedAreaPixels); const fileExt = "png"; // or extract from original file const fileName = `${user.supabase_id}-${Date.now()}.${fileExt}`; const filePath = `avatars/${fileName}`; // Delete old avatar if exists if (user.avatar_url) { const oldFileName = user.avatar_url.split("/").pop(); if (oldFileName) { await supabase.storage.from("profile_pictures").remove([`avatars/${oldFileName}`]); } } // Upload new avatar const { data: uploadData, error: uploadError } = await supabase.storage .from("profile_pictures") .upload(filePath, croppedBlob, { cacheControl: "3600", upsert: true, }); if (uploadError) { throw new Error(uploadError.message || "Failed to upload image"); } // Get public URL const { data: urlData } = supabase.storage.from("profile_pictures").getPublicUrl(filePath); setAvatarUrl(urlData.publicUrl); // Update user table const { error: updateError } = await supabase .from("users") .update({ avatar_url: urlData.publicUrl }) .eq("user_id", user.user_id); if (updateError) { throw new Error(updateError.message || "Failed to update profile"); } // Clear crop state setImageSrc(null); setCrop({ x: 0, y: 0 }); setZoom(1); setCroppedAreaPixels(null); swal.success("Avatar updated", "Avatar updated successfully!"); } catch (err: any) { console.error("Upload error:", err); swal.error("Upload failed", err.message || "Failed to upload avatar. Please try again."); } finally { setUploading(false); } }; useEffect(() => { if (!user) return; setAvatarUrl(user.avatar_url || ""); setProfileData({ username: user.user_name || "", email: user.email || "", bio: user.bio || "", location: user.location || "", website: user.website || "", joinDate: user.created_at ? new Date(user.created_at) : new Date(), }); }, [user]); const handleSave = async () => { if (!user) return; // Update auth email (only if changed) if (profileData.email !== user.email) { await supabase.auth.updateUser({ email: profileData.email, }); } // Update user table const { error } = await supabase .from("users") .update({ user_name: profileData.username, bio: profileData.bio, location: profileData.location, website: profileData.website, // email: profileData.email, }) .eq("user_id", user.user_id); if (error) { console.error("Failed to update profile:", error); } else { console.log("Profile updated successfully!"); } setIsEditing(false); }; useEffect(() => { if (!user) return; setAvatarUrl(user.avatar_url || ""); setProfileData((prev) => ({ ...prev, username: user.user_name || "", email: user.email || "", joinDate: user.created_at ? new Date(user.created_at) : new Date(), })); }, [user]); // Load tickets from localStorage useEffect(() => { if (typeof window !== 'undefined') { const savedTickets = localStorage.getItem('buildmate-support-tickets'); if (savedTickets) { try { const parsedTickets = JSON.parse(savedTickets); // Filter tickets for current user const userTickets = parsedTickets.filter((ticket: any) => ticket.userId === user?.user_id || !ticket.userId ); setTickets(userTickets.map((ticket: any) => ({ ...ticket, replies: Array.isArray(ticket.replies) ? ticket.replies.length : (typeof ticket.replies === 'number' ? ticket.replies : 0) }))); } catch (e) { console.error('Error loading tickets from localStorage:', e); } } } }, [user]); if (!user) { return (

Please log in

) } return (
{/* Profile Overview */}
{avatarUrl ? ( ) : ( {userData.user_name ? userData.user_name.charAt(0).toUpperCase() : "?"} )} {imageSrc && (
{/* Buttons outside cropper area */}
)}
{profileData.username} {profileData.email}

{profileData.bio}

{profileData.location}
Joined {profileData.joinDate.toLocaleDateString()}

{pageLoading ? "..." : userBuilds.length}

Builds

{following}

Following

{followers}

Followers

{/* View Public Profile Button */}
{/* Settings */}
{/* Profile Information */}
Profile Information Update your personal information and bio
setProfileData((prev) => ({ ...prev, username: e.target.value }))} disabled={!isEditing} />
{/*
setProfileData((prev) => ({ ...prev, email: e.target.value }))} disabled={!isEditing} />
*/}