Initial commit
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
'use client';
|
||||
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState, FormEvent } from 'react';
|
||||
import { getAuth, updateProfile, updatePassword } from 'firebase/auth';
|
||||
import { app } from '@/lib/firebase';
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { user, isLoading } = useAuth();
|
||||
const router = useRouter();
|
||||
const [name, setName] = useState('');
|
||||
const [currentPassword, setCurrentPassword] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && !user) {
|
||||
router.push('/auth');
|
||||
}
|
||||
if (user) {
|
||||
setName(user.name || '');
|
||||
}
|
||||
}, [user, isLoading, router]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-[#050316] text-white">
|
||||
<div className="animate-pulse text-2xl">Loading...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
const handleUpdateProfile = async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSaving(true);
|
||||
setMessage(null);
|
||||
|
||||
try {
|
||||
const auth = getAuth(app);
|
||||
if (auth.currentUser && name !== user.name) {
|
||||
await updateProfile(auth.currentUser, { displayName: name });
|
||||
setMessage({ type: 'success', text: 'Profile updated successfully!' });
|
||||
}
|
||||
} catch (error: any) {
|
||||
setMessage({ type: 'error', text: error.message || 'Failed to update profile' });
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangePassword = async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSaving(true);
|
||||
setMessage(null);
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
setMessage({ type: 'error', text: 'Passwords do not match' });
|
||||
setSaving(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
setMessage({ type: 'error', text: 'Password must be at least 6 characters' });
|
||||
setSaving(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const auth = getAuth(app);
|
||||
if (auth.currentUser) {
|
||||
await updatePassword(auth.currentUser, newPassword);
|
||||
setMessage({ type: 'success', text: 'Password changed successfully!' });
|
||||
setCurrentPassword('');
|
||||
setNewPassword('');
|
||||
setConfirmPassword('');
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.code === 'auth/requires-recent-login') {
|
||||
setMessage({ type: 'error', text: 'Please log out and log back in to change your password' });
|
||||
} else {
|
||||
setMessage({ type: 'error', text: error.message || 'Failed to change password' });
|
||||
}
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#050316] text-white">
|
||||
{/* Navigation */}
|
||||
<nav className="border-b border-white/10 bg-white/5 backdrop-blur-sm">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center h-16">
|
||||
<div className="flex items-center space-x-8">
|
||||
<h1 className="text-2xl font-bold">HolaCompi</h1>
|
||||
<button
|
||||
onClick={() => router.push('/dashboard')}
|
||||
className="text-gray-400 hover:text-white transition-colors"
|
||||
>
|
||||
← Back to Dashboard
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold mb-2">Account Settings</h2>
|
||||
<p className="text-gray-400">Manage your profile and account preferences</p>
|
||||
</div>
|
||||
|
||||
{/* Success/Error Message */}
|
||||
{message && (
|
||||
<div
|
||||
className={`rounded-lg px-4 py-3 ${
|
||||
message.type === 'success'
|
||||
? 'bg-green-500/10 border border-green-500/20 text-green-400'
|
||||
: 'bg-red-500/10 border border-red-500/20 text-red-400'
|
||||
}`}
|
||||
>
|
||||
{message.text}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Account Info */}
|
||||
<div className="bg-white/5 rounded-2xl border border-white/10 p-6">
|
||||
<h3 className="text-xl font-semibold mb-4">Account Information</h3>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<label className="text-sm text-gray-400">Email</label>
|
||||
<p className="text-white">{user.email}</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-gray-400">User ID</label>
|
||||
<p className="text-white font-mono text-xs">{user.uid}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Profile Settings */}
|
||||
<div className="bg-white/5 rounded-2xl border border-white/10 p-6">
|
||||
<h3 className="text-xl font-semibold mb-4">Profile Settings</h3>
|
||||
<form onSubmit={handleUpdateProfile} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm mb-2">Display Name</label>
|
||||
<input
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full rounded-lg px-4 py-3 bg-black/30 border border-white/10 text-white outline-none focus:border-purple-400 transition-colors"
|
||||
placeholder="Enter your name"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={saving || name === user.name}
|
||||
className="px-6 py-2.5 rounded-lg bg-purple-500 hover:bg-purple-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{saving ? 'Saving...' : 'Save Changes'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Change Password */}
|
||||
<div className="bg-white/5 rounded-2xl border border-white/10 p-6">
|
||||
<h3 className="text-xl font-semibold mb-4">Change Password</h3>
|
||||
<form onSubmit={handleChangePassword} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm mb-2">New Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
className="w-full rounded-lg px-4 py-3 bg-black/30 border border-white/10 text-white outline-none focus:border-purple-400 transition-colors"
|
||||
placeholder="Enter new password (min 6 characters)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm mb-2">Confirm New Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
className="w-full rounded-lg px-4 py-3 bg-black/30 border border-white/10 text-white outline-none focus:border-purple-400 transition-colors"
|
||||
placeholder="Confirm new password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={saving}
|
||||
className="px-6 py-2.5 rounded-lg bg-red-500 hover:bg-red-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{saving ? 'Changing...' : 'Change Password'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user