feat: completer Settings.tsx - ContactsSection + export default Settings
This commit is contained in:
@@ -579,18 +579,11 @@ function ContactsSection() {
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<button onClick={() => setOpen(!open)}
|
||||
className="flex items-center justify-between w-full p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-9 h-9 rounded-xl bg-violet-50 flex items-center justify-center">
|
||||
<svg className="w-5 h-5 text-violet-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className="font-semibold text-sm text-gray-900">Contacts / Invités</p>
|
||||
<p className="font-semibold text-sm text-gray-900">Contacts</p>
|
||||
<p className="text-xs text-gray-400">{contacts.length} contact{contacts.length !== 1 ? 's' : ''}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -602,57 +595,63 @@ function ContactsSection() {
|
||||
|
||||
{open && (
|
||||
<div className="border-t border-gray-50">
|
||||
{/* Bouton import */}
|
||||
<div className="px-4 pt-3 pb-2 flex gap-2">
|
||||
<input ref={fileRef} type="file" accept=".csv,.xls,.xlsx"
|
||||
onChange={handleFileImport} className="hidden" />
|
||||
<button
|
||||
onClick={() => fileRef.current?.click()}
|
||||
disabled={importing}
|
||||
className="btn-secondary py-2 text-sm flex items-center gap-2">
|
||||
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
|
||||
</svg>
|
||||
{importing ? 'Import en cours…' : 'Importer CSV / Excel'}
|
||||
</button>
|
||||
<p className="text-xs text-gray-400 self-center">Colonnes : Nom, Société (optionnel)</p>
|
||||
</div>
|
||||
|
||||
{/* Liste des contacts */}
|
||||
{contacts.length > 0 && (
|
||||
<div className="px-4 pb-2 max-h-64 overflow-y-auto space-y-1">
|
||||
{contacts.length === 0 && (
|
||||
<p className="px-4 py-3 text-sm text-gray-400">Aucun contact enregistré.</p>
|
||||
)}
|
||||
{contacts.map(c => (
|
||||
<div key={c.id} className="flex items-center gap-3 py-1.5 border-b border-gray-50 last:border-0">
|
||||
<div key={c.id} className="flex items-center gap-3 px-4 py-2.5 border-b border-gray-50 last:border-0">
|
||||
<div className="flex-1 min-w-0">
|
||||
<span className="text-sm font-medium text-gray-900">{c.name}</span>
|
||||
{c.company && <span className="ml-2 text-xs text-gray-400">{c.company}</span>}
|
||||
<p className="text-sm font-medium text-gray-900 truncate">{c.name}</p>
|
||||
{c.company && <p className="text-xs text-gray-400 truncate">{c.company}</p>}
|
||||
</div>
|
||||
<button onClick={() => del.mutate(c.id)}
|
||||
className="p-1 text-gray-300 hover:text-red-400 shrink-0">
|
||||
<button onClick={() => del.mutate(c.id)} className="p-1.5 text-gray-300 hover:text-red-500 transition-colors">
|
||||
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Ajout manuel */}
|
||||
<div className="px-4 pb-4 pt-2 space-y-2 border-t border-gray-50">
|
||||
<p className="text-xs font-semibold text-gray-400 uppercase tracking-wide">Ajouter manuellement</p>
|
||||
<div className="flex gap-2">
|
||||
<input className="form-input text-sm py-2 flex-1" placeholder="Nom *"
|
||||
value={newName} onChange={e => setNewName(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter' && newName.trim()) { e.preventDefault(); add.mutate({ name: newName.trim(), company: newCompany.trim() }); }}} />
|
||||
<input className="form-input text-sm py-2 flex-1" placeholder="Société (optionnel)"
|
||||
value={newCompany} onChange={e => setNewCompany(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter' && newName.trim()) { e.preventDefault(); add.mutate({ name: newName.trim(), company: newCompany.trim() }); }}} />
|
||||
{/* Formulaire ajout manuel */}
|
||||
<div className="p-4 space-y-2 border-t border-gray-50">
|
||||
<p className="text-xs font-semibold text-gray-400 uppercase tracking-wide">Ajouter un contact</p>
|
||||
<input
|
||||
className="form-input text-sm"
|
||||
placeholder="Nom *"
|
||||
value={newName}
|
||||
onChange={e => setNewName(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
className="form-input text-sm"
|
||||
placeholder="Société"
|
||||
value={newCompany}
|
||||
onChange={e => setNewCompany(e.target.value)}
|
||||
/>
|
||||
<div className="flex gap-2 pt-1">
|
||||
<button
|
||||
onClick={() => { if (newName.trim()) add.mutate({ name: newName.trim(), company: newCompany.trim() }); }}
|
||||
onClick={() => { if (newName.trim()) { add.mutate({ name: newName.trim(), company: newCompany.trim() }); } }}
|
||||
disabled={!newName.trim() || add.isPending}
|
||||
className="px-4 py-2 bg-indigo-600 text-white text-sm font-semibold rounded-xl disabled:opacity-40">
|
||||
+
|
||||
className="btn-primary py-2 text-sm"
|
||||
>
|
||||
{add.isPending ? 'Ajout…' : 'Ajouter'}
|
||||
</button>
|
||||
|
||||
{/* Import CSV */}
|
||||
<input
|
||||
ref={fileRef}
|
||||
type="file"
|
||||
accept=".csv,.xlsx,.xls"
|
||||
className="hidden"
|
||||
onChange={handleFileImport}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => fileRef.current?.click()}
|
||||
disabled={importing}
|
||||
className="btn-secondary py-2 text-sm"
|
||||
>
|
||||
{importing ? 'Import…' : 'Importer CSV/Excel'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -662,18 +661,18 @@ function ContactsSection() {
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Page principale ─────────────────────────────────────────
|
||||
// ─── Page Paramètres (assemblage) ────────────────────────────
|
||||
|
||||
export default function Settings() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-xl font-bold text-gray-900">Paramètres</h2>
|
||||
<div className="space-y-3">
|
||||
<h1 className="text-xl font-bold text-gray-900 mb-4">Paramètres</h1>
|
||||
<PasswordSection />
|
||||
<SmtpSection />
|
||||
<CompaniesSection />
|
||||
<CategoriesSection />
|
||||
<ContactsSection />
|
||||
<GraphSection />
|
||||
<ContactsSection />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user