Files
prayer-app/src/components/Profile.tsx
T

151 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState, useEffect } from 'react';
import { useAuth } from '@/context/AuthContext';
import { storage, db } from '@/lib/firebase';
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { doc, getDoc, updateDoc } from 'firebase/firestore';
import { useTheme } from 'next-themes';
interface UserProfile {
avatarUrl?: string;
theme?: string;
categories?: string[];
}
export default function Profile() {
const { user } = useAuth();
const { theme, setTheme } = useTheme();
const [profile, setProfile] = useState<UserProfile>({});
const [uploading, setUploading] = useState(false);
const [newCategory, setNewCategory] = useState('');
useEffect(() => {
if (user) {
loadProfile();
}
}, [user]);
const loadProfile = async () => {
if (!user) return;
try {
const docRef = doc(db, 'users', user.uid);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
setProfile(docSnap.data() as UserProfile);
}
} catch (error) {
console.error('Error loading profile:', error);
}
};
const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file || !user) return;
setUploading(true);
try {
const storageRef = ref(storage, `avatars/${user.uid}`);
await uploadBytes(storageRef, file);
const url = await getDownloadURL(storageRef);
await updateDoc(doc(db, 'users', user.uid), { avatarUrl: url });
setProfile(prev => ({ ...prev, avatarUrl: url }));
} catch (error) {
console.error('Error uploading avatar:', error);
} finally {
setUploading(false);
}
};
const handleThemeChange = async (newTheme: string) => {
setTheme(newTheme);
if (user) {
await updateDoc(doc(db, 'users', user.uid), { theme: newTheme });
setProfile(prev => ({ ...prev, theme: newTheme }));
}
};
const addCategory = async () => {
if (!newCategory.trim() || !user) return;
const updatedCategories = [...(profile.categories || []), newCategory.trim()];
await updateDoc(doc(db, 'users', user.uid), { categories: updatedCategories });
setProfile(prev => ({ ...prev, categories: updatedCategories }));
setNewCategory('');
};
const removeCategory = async (category: string) => {
if (!user) return;
const updatedCategories = (profile.categories || []).filter(c => c !== category);
await updateDoc(doc(db, 'users', user.uid), { categories: updatedCategories });
setProfile(prev => ({ ...prev, categories: updatedCategories }));
};
return (
<div className="max-w-md mx-auto mb-8 p-6 bg-gray-800 rounded-lg">
<h2 className="text-2xl font-bold mb-6">Profile</h2>
{/* Avatar */}
<div className="mb-6">
<label className="block mb-2 text-lg">Avatar</label>
{profile.avatarUrl && (
<img src={profile.avatarUrl} alt="Avatar" className="w-20 h-20 rounded-full mb-2" />
)}
<input
type="file"
accept="image/*"
onChange={handleAvatarUpload}
disabled={uploading}
className="w-full p-3 bg-gray-700 border border-gray-600 rounded"
/>
{uploading && <p className="text-sm text-gray-400 mt-1">Uploading...</p>}
</div>
{/* Theme */}
<div className="mb-6">
<label className="block mb-2 text-lg">Theme</label>
<select
value={theme}
onChange={(e) => handleThemeChange(e.target.value)}
className="w-full p-3 bg-gray-700 border border-gray-600 rounded"
>
<option value="dark">Dark</option>
<option value="light">Light</option>
<option value="system">System</option>
</select>
</div>
{/* Categories */}
<div className="mb-6">
<label className="block mb-2 text-lg">Prayer Categories</label>
<div className="flex gap-2 mb-2">
<input
type="text"
value={newCategory}
onChange={(e) => setNewCategory(e.target.value)}
placeholder="Add category"
className="flex-1 p-3 bg-gray-700 border border-gray-600 rounded"
/>
<button
onClick={addCategory}
className="px-4 py-3 bg-green-600 hover:bg-green-700 rounded"
>
Add
</button>
</div>
<div className="flex flex-wrap gap-2">
{(profile.categories || []).map(category => (
<span key={category} className="bg-gray-700 px-3 py-1 rounded flex items-center gap-2">
{category}
<button
onClick={() => removeCategory(category)}
className="text-red-400 hover:text-red-300"
>
×
</button>
</span>
))}
</div>
</div>
</div>
);
}