204 lines
12 KiB
TypeScript
204 lines
12 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|
import { UserProfile, UserPreferences } from '../types';
|
|
import { User, Settings, Globe, Shield, Bell, Save, Camera, Target, Flame, Layout } from 'lucide-react';
|
|
|
|
interface UserProfileSettingsProps {
|
|
user: UserProfile;
|
|
onUpdate: (updates: Partial<UserProfile>) => void;
|
|
onBack: () => void;
|
|
}
|
|
|
|
const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ user, onUpdate, onBack }) => {
|
|
// DEBUG: Check props
|
|
console.log("[UserProfileSettings DEBUG] PROPS RECEIVED:", {
|
|
user,
|
|
userId: user?.id,
|
|
hasOnUpdate: !!onUpdate,
|
|
hasOnBack: !!onBack
|
|
});
|
|
|
|
const [activeTab, setActiveTab] = useState<'profile' | 'preferences' | 'account'>('profile');
|
|
const [formData, setFormData] = useState({
|
|
name: user.name,
|
|
bio: user.bio || '',
|
|
email: user.email,
|
|
theme: user.preferences.theme,
|
|
dailyWordGoal: user.preferences.dailyWordGoal
|
|
});
|
|
|
|
const handleSave = () => {
|
|
onUpdate({
|
|
name: formData.name,
|
|
bio: formData.bio,
|
|
email: formData.email,
|
|
preferences: {
|
|
...user.preferences,
|
|
theme: formData.theme,
|
|
dailyWordGoal: formData.dailyWordGoal
|
|
}
|
|
});
|
|
alert("Profil mis à jour !");
|
|
};
|
|
|
|
return (
|
|
<div className="h-full bg-slate-50 overflow-y-auto p-8 font-sans">
|
|
<div className="max-w-4xl mx-auto">
|
|
<div className="flex justify-between items-center mb-10">
|
|
<div>
|
|
<h1 className="text-3xl font-black text-slate-900">Mon Compte</h1>
|
|
<p className="text-slate-500">Gérez vos informations personnelles et préférences d'écriture.</p>
|
|
</div>
|
|
<button onClick={onBack} className="bg-white border border-slate-200 px-4 py-2 rounded-lg text-sm font-bold hover:bg-slate-50 transition-colors">Fermer</button>
|
|
</div>
|
|
|
|
<div className="flex flex-col md:flex-row gap-8">
|
|
{/* Sidebar Navigation */}
|
|
<div className="w-full md:w-64 space-y-1">
|
|
<button
|
|
onClick={() => setActiveTab('profile')}
|
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-bold transition-all ${activeTab === 'profile' ? 'bg-slate-900 text-white shadow-lg' : 'text-slate-500 hover:bg-white hover:text-slate-900'}`}
|
|
>
|
|
<User size={18} /> Profil Public
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('preferences')}
|
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-bold transition-all ${activeTab === 'preferences' ? 'bg-slate-900 text-white shadow-lg' : 'text-slate-500 hover:bg-white hover:text-slate-900'}`}
|
|
>
|
|
<Layout size={18} /> Interface & Écriture
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('account')}
|
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-bold transition-all ${activeTab === 'account' ? 'bg-slate-900 text-white shadow-lg' : 'text-slate-500 hover:bg-white hover:text-slate-900'}`}
|
|
>
|
|
<Shield size={18} /> Sécurité & Plan
|
|
</button>
|
|
</div>
|
|
|
|
{/* Main Content Pane */}
|
|
<div className="flex-1 bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
|
|
{activeTab === 'profile' && (
|
|
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-300">
|
|
<div className="flex items-center gap-6 pb-8 border-b border-slate-100">
|
|
<div className="relative group">
|
|
<img src={user.avatar} className="w-24 h-24 rounded-full object-cover border-4 border-slate-50 shadow-md" alt="Avatar" />
|
|
<button className="absolute inset-0 bg-black/40 text-white rounded-full opacity-0 group-hover:opacity-100 flex items-center justify-center transition-opacity">
|
|
<Camera size={20} />
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<h3 className="font-bold text-slate-900 text-lg">{user.name}</h3>
|
|
<p className="text-slate-400 text-sm">Membre depuis Janvier 2024</p>
|
|
<div className="mt-2 flex gap-4">
|
|
<div className="flex items-center gap-1.5 text-xs font-bold text-orange-500">
|
|
<Flame size={14} fill="currentColor" /> {user.stats.writingStreak} jours de streak
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-6">
|
|
<div className="space-y-1">
|
|
<label className="text-xs font-black text-slate-400 uppercase tracking-widest">Nom affiché</label>
|
|
<input
|
|
type="text"
|
|
value={formData.name}
|
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
className="w-full p-3 bg-slate-50 border border-slate-200 rounded-xl outline-none focus:ring-2 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="text-xs font-black text-slate-400 uppercase tracking-widest">Bio / Citation inspirante</label>
|
|
<textarea
|
|
value={formData.bio}
|
|
onChange={(e) => setFormData({ ...formData, bio: e.target.value })}
|
|
className="w-full p-3 bg-slate-50 border border-slate-200 rounded-xl outline-none focus:ring-2 focus:ring-blue-500 h-24 resize-none"
|
|
placeholder="Partagez quelques mots sur votre style..."
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === 'preferences' && (
|
|
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-300">
|
|
<div className="grid grid-cols-1 gap-8">
|
|
<div className="space-y-3">
|
|
<label className="text-xs font-black text-slate-400 uppercase tracking-widest flex items-center gap-2">
|
|
<Target size={14} /> Objectif quotidien de mots
|
|
</label>
|
|
<div className="flex items-center gap-4">
|
|
<input
|
|
type="range" min="0" max="5000" step="100"
|
|
value={formData.dailyWordGoal}
|
|
onChange={(e) => setFormData({ ...formData, dailyWordGoal: parseInt(e.target.value) })}
|
|
className="flex-1 accent-blue-600"
|
|
/>
|
|
<span className="font-mono font-bold text-blue-600 bg-blue-50 px-3 py-1 rounded-lg">{formData.dailyWordGoal}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<label className="text-xs font-black text-slate-400 uppercase tracking-widest flex items-center gap-2">
|
|
Thème de l'éditeur
|
|
</label>
|
|
<div className="grid grid-cols-3 gap-3">
|
|
{['light', 'sepia', 'dark'].map((t) => (
|
|
<button
|
|
key={t}
|
|
onClick={() => setFormData({ ...formData, theme: t as any })}
|
|
className={`p-4 rounded-xl border-2 transition-all flex flex-col items-center gap-2 ${formData.theme === t ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-slate-100 hover:border-slate-200 text-slate-500'}`}
|
|
>
|
|
<div className={`w-8 h-8 rounded-full border border-slate-200 ${t === 'light' ? 'bg-white' : t === 'sepia' ? 'bg-[#f4ecd8]' : 'bg-slate-900'}`} />
|
|
<span className="text-[10px] font-bold uppercase">{t}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === 'account' && (
|
|
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-300">
|
|
<div className="p-4 bg-blue-50 border border-blue-100 rounded-xl flex justify-between items-center">
|
|
<div>
|
|
<h4 className="font-bold text-blue-900">Plan {user.subscription.plan.toUpperCase()}</h4>
|
|
<p className="text-xs text-blue-700">Prochaine facturation le 15 Mars 2024</p>
|
|
</div>
|
|
<button className="bg-blue-600 text-white px-4 py-2 rounded-lg text-xs font-bold hover:bg-blue-700 shadow-md shadow-blue-200">Gérer</button>
|
|
</div>
|
|
|
|
<div className="space-y-1">
|
|
<label className="text-xs font-black text-slate-400 uppercase tracking-widest">Email du compte</label>
|
|
<input
|
|
type="email"
|
|
value={formData.email}
|
|
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
|
className="w-full p-3 bg-slate-50 border border-slate-200 rounded-xl outline-none focus:ring-2 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
|
|
<div className="pt-4">
|
|
<button className="text-red-500 text-sm font-bold hover:underline">Supprimer mon compte définitivement</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="mt-12 pt-8 border-t border-slate-100 flex justify-end">
|
|
<button
|
|
onClick={handleSave}
|
|
className="bg-slate-900 text-white px-8 py-3 rounded-xl font-bold flex items-center gap-2 hover:bg-blue-600 transition-all shadow-xl hover:shadow-blue-200"
|
|
>
|
|
<Save size={18} /> Sauvegarder les modifications
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default UserProfileSettings;
|