project-standalo-sonic-cloud/app/profile/page.tsx

151 lines
4.4 KiB
TypeScript

'use client'
import { ProfileForm, ProfileFormData } from '@/components/ProfileForm'
import { AvatarUpload } from '@/components/AvatarUpload'
import { useState, useEffect } from 'react'
export default function ProfilePage() {
const [user, setUser] = useState<any>(null)
const [loading, setLoading] = useState(true)
const [isUpdatingProfile, setIsUpdatingProfile] = useState(false)
const [isUploadingAvatar, setIsUploadingAvatar] = useState(false)
useEffect(() => {
fetchCurrentUser()
}, [])
const fetchCurrentUser = async () => {
try {
const res = await fetch('/api/users/me')
if (res.ok) {
const data = await res.json()
setUser(data.user)
}
} catch (error) {
console.error('Failed to fetch user:', error)
} finally {
setLoading(false)
}
}
const handleAvatarUpload = async (file: File) => {
setIsUploadingAvatar(true)
try {
// In a real app, upload to cloud storage and get URL
// For now, create a local blob URL as placeholder
const avatarUrl = URL.createObjectURL(file)
const res = await fetch('/api/users/me', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ avatarUrl }),
})
if (res.ok) {
const data = await res.json()
setUser(data.user)
}
} catch (error) {
console.error('Failed to upload avatar:', error)
} finally {
setIsUploadingAvatar(false)
}
}
const handleProfileSubmit = async (data: ProfileFormData) => {
setIsUpdatingProfile(true)
try {
const res = await fetch('/api/users/me', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
displayName: data.username,
bio: data.bio,
}),
})
if (res.ok) {
const result = await res.json()
setUser(result.user)
}
} catch (error) {
console.error('Failed to update profile:', error)
} finally {
setIsUpdatingProfile(false)
}
}
if (loading) {
return (
<main className="min-h-screen bg-zinc-950 flex items-center justify-center">
<p className="text-zinc-400">Loading profile...</p>
</main>
)
}
if (!user) {
return (
<main className="min-h-screen bg-zinc-950 flex items-center justify-center">
<div className="text-center">
<p className="text-xl text-zinc-400 mb-4">Please log in to view your profile</p>
<a
href="/login"
className="px-6 py-3 bg-purple-600 hover:bg-purple-700 text-white font-semibold rounded-lg inline-block"
>
Log In
</a>
</div>
</main>
)
}
return (
<main className="min-h-screen bg-zinc-950">
<div className="max-w-4xl mx-auto px-4 py-8">
{/* Header */}
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-4">Profile Settings</h1>
<p className="text-xl text-zinc-400">
Manage your account and preferences
</p>
</div>
{/* Avatar Section */}
<div className="bg-zinc-900 rounded-lg p-8 mb-6">
<h2 className="text-2xl font-semibold text-white mb-6">Profile Picture</h2>
<AvatarUpload
currentAvatarUrl={user.avatarUrl}
onUpload={handleAvatarUpload}
isLoading={isUploadingAvatar}
/>
</div>
{/* Profile Form */}
<div className="bg-zinc-900 rounded-lg p-8">
<h2 className="text-2xl font-semibold text-white mb-6">Account Information</h2>
<ProfileForm
initialData={{
username: user.displayName || user.username || '',
email: user.email || '',
bio: user.bio || '',
}}
onSubmit={handleProfileSubmit}
isLoading={isUpdatingProfile}
/>
</div>
{/* Danger Zone */}
<div className="bg-zinc-900 rounded-lg p-8 mt-6 border border-red-900/50">
<h2 className="text-2xl font-semibold text-white mb-4">Danger Zone</h2>
<p className="text-zinc-400 mb-4">
Once you delete your account, there is no going back. Please be certain.
</p>
<button className="px-6 py-3 bg-red-600 hover:bg-red-700 text-white font-semibold rounded-lg transition-colors">
Delete Account
</button>
</div>
</div>
</main>
)
}