Files
SBC/web/src/pages/Annuaire.jsx
T

117 lines
5.8 KiB
React

import { useMemo, useState } from 'react';
import { usePublicData } from '../lib/usePublic.js';
import MemberModal from '../components/MemberModal.jsx';
import { associationSettings } from '../lib/siteSettings.js';
export default function Annuaire() {
const { data } = usePublicData();
const [search, setSearch] = useState('');
const [category, setCategory] = useState('Toutes');
const [detail, setDetail] = useState(null);
const members = data?.members ?? [];
const categories = data?.categories ?? [];
const settings = associationSettings(data?.content);
const filtered = useMemo(() => {
const q = search.trim().toLowerCase();
return members.filter((m) => {
const matchCat = category === 'Toutes' || (m.categorie || 'Non classée') === category;
const matchText = !q || `${m.nom} ${m.dirigeant} ${m.secteur} ${m.categorie || ''} ${m.adresse || ''}`.toLowerCase().includes(q);
return matchCat && matchText;
});
}, [members, search, category]);
const chips = ['Toutes', ...categories.map((c) => c.name)];
return (
<main>
<section style={{ background: '#fff', borderBottom: '1px solid var(--border)' }}>
<div className="container" style={{ padding: '70px 32px 60px' }}>
<div className="kicker" style={{ marginBottom: 16 }}>Annuaire des membres</div>
<h1 className="serif" style={{ fontWeight: 500, fontSize: 'clamp(36px, 5vw, 54px)', lineHeight: 1.05, marginBottom: 18 }}>
{members.length} entreprises, un réseau.
</h1>
<p style={{ fontSize: 17, lineHeight: 1.6, color: 'var(--gray)', maxWidth: 600 }}>
Découvrez les entreprises membres de {settings.association_name} et prenez contact directement avec leurs dirigeants.
</p>
</div>
</section>
<section className="container" style={{ padding: '44px 32px 100px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap', marginBottom: 14 }}>
<div style={{ position: 'relative', flex: 1, minWidth: 260 }}>
<span style={{ position: 'absolute', left: 16, top: '50%', transform: 'translateY(-50%)', color: 'var(--gray-light)', fontSize: 15 }}>⌕</span>
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Rechercher une entreprise, un dirigeant, un secteur…"
maxLength={120}
style={{ width: '100%', padding: '14px 16px 14px 42px', border: '1px solid var(--input-border)', borderRadius: 3, background: '#fff' }}
/>
</div>
<span style={{ fontSize: 13.5, color: 'var(--gray-light)', whiteSpace: 'nowrap' }}>
{filtered.length} entreprise{filtered.length > 1 ? 's' : ''}
</span>
</div>
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 36 }}>
{chips.map((c) => (
<button key={c} className={`chip${category === c ? ' active' : ''}`} onClick={() => setCategory(c)}>
{c}
</button>
))}
</div>
<div className="grid-3">
{filtered.map((m) => (
<article
key={m.id}
className="card directory-member-card"
style={{ padding: 26, display: 'flex', flexDirection: 'column' }}
role="button"
tabIndex={0}
aria-label={`Voir la fiche de ${m.nom}`}
onClick={() => setDetail(m)}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
setDetail(m);
}
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 16 }}>
<div className={m.logo_path ? '' : 'placeholder-pattern'} style={{ width: 64, height: 64, flexShrink: 0, borderRadius: 4, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'monospace', fontSize: 9, color: '#a8a099', overflow: 'hidden', background: m.logo_path ? '#fff' : undefined }}>
{m.logo_path ? <img src={m.logo_path} alt="" style={{ width: '100%', height: '100%', objectFit: 'contain' }} /> : 'logo'}
</div>
<div>
<div className="serif" style={{ fontSize: 20, fontWeight: 600, lineHeight: 1.15 }}>{m.nom}</div>
<div style={{ fontSize: 11, letterSpacing: '.08em', textTransform: 'uppercase', color: 'var(--red)', fontWeight: 600, marginTop: 5 }}>{m.secteur}</div>
</div>
</div>
<div style={{ marginBottom: 16 }}>
<span className="badge-cat">{m.categorie || 'Non classée'}</span>
</div>
<p style={{ fontSize: 14, lineHeight: 1.6, color: 'var(--gray)', flex: 1, marginBottom: 20 }}>{m.presentation}</p>
<div style={{ paddingTop: 18, borderTop: '1px solid var(--border-soft)' }}>
<span style={{ fontSize: 13, color: 'var(--gray-light)' }}>{m.dirigeant}</span>
</div>
</article>
))}
</div>
{filtered.length === 0 && (
<div style={{ textAlign: 'center', padding: '80px 20px', color: 'var(--gray-light)' }}>
<div className="serif" style={{ fontSize: 26, color: 'var(--ink)', marginBottom: 10 }}>Aucune entreprise trouvée</div>
<p style={{ fontSize: 15, marginBottom: 24 }}>Essayez d'autres mots-clés ou réinitialisez les filtres.</p>
<button className="btn btn-dark btn-sm" style={{ fontSize: 14, padding: '12px 24px' }} onClick={() => { setSearch(''); setCategory('Toutes'); }}>
Réinitialiser
</button>
</div>
)}
</section>
<MemberModal member={detail} onClose={() => setDetail(null)} />
</main>
);
}