fix
This commit is contained in:
@@ -510,6 +510,7 @@ export default function Communication() {
|
||||
const { user, isAdmin } = useAuth();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const [notifMenuPos, setNotifMenuPos] = useState(null); // { x, y }
|
||||
|
||||
const [tab, setTab] = useState('support'); // 'support' | 'notifications'
|
||||
const [showBroadcastForm, setShowBroadcastForm] = useState(false);
|
||||
@@ -718,6 +719,16 @@ export default function Communication() {
|
||||
setBcSending(false);
|
||||
};
|
||||
|
||||
// ── Supprimer toutes les notifications ────────────────────────────────────
|
||||
const deleteAllNotifs = async () => {
|
||||
try {
|
||||
await Promise.all(notifs.map(n => api.del(`/notifications/${n.id}`)));
|
||||
setNotifs([]);
|
||||
setSelectedNotif(null);
|
||||
window.dispatchEvent(new CustomEvent('notif:refresh'));
|
||||
} catch { /* silencieux */ }
|
||||
};
|
||||
|
||||
// ── Supprimer une notification ────────────────────────────────────────────
|
||||
const deleteNotif = async (id) => {
|
||||
try {
|
||||
@@ -787,26 +798,26 @@ export default function Communication() {
|
||||
</div>
|
||||
{/* Colonne 2 — Dossier + filtres */}
|
||||
<div className="comm-topbar-2">
|
||||
<span className="comm-topbar-folder">{tab === 'support' ? 'Support' : 'Notifications'}</span>
|
||||
<div className="comm-topbar-filters">
|
||||
<span className="comm-topbar-folder" style={{ fontSize: 15, fontWeight: 700 }}>{tab === 'support' ? 'Support' : 'Notifications'}</span>
|
||||
{tab === 'support' && (
|
||||
<>
|
||||
<div className="comm-topbar-filters">
|
||||
{[['all','Tous'],['open','Ouverts'],['resolved','Résolus']].map(([v,l]) => (
|
||||
<button key={v} className={`comm-topbar-filter-btn${ticketFilter === v ? ' active' : ''}`} onClick={() => setTicketFilter(v)}>{l}</button>
|
||||
))}
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
{tab === 'notifications' && (
|
||||
<>
|
||||
{[['all','Tous'],['unread','Non lus']].map(([v,l]) => (
|
||||
<button key={v} className={`comm-topbar-filter-btn${notifFilter === v ? ' active' : ''}`} onClick={() => { setNotifFilter(v); setNotifPage(0); }}>{l}</button>
|
||||
))}
|
||||
{unreadCount > 0 && (
|
||||
<button className="comm-topbar-action-btn" onClick={markAllRead}>Tout marquer lu</button>
|
||||
<button
|
||||
className="btn-icon-sm"
|
||||
style={{ marginLeft: 'auto', flexShrink: 0 }}
|
||||
onClick={e => {
|
||||
const r = e.currentTarget.getBoundingClientRect();
|
||||
setNotifMenuPos({ x: r.right, y: r.bottom + 4 });
|
||||
}}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg>
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* Colonne 3 — Toolbar contextuelle */}
|
||||
<div className="comm-topbar-3">
|
||||
@@ -822,20 +833,13 @@ export default function Communication() {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{tab === 'notifications' && selectedNotif && (
|
||||
{tab === 'notifications' && selectedNotif && !selectedNotif.read && (
|
||||
<div style={{ display: 'flex', gap: 6, marginLeft: 'auto' }}>
|
||||
{!selectedNotif.read && (
|
||||
<button className="btn btn-sm btn-ghost" onClick={async () => {
|
||||
await api.patch(`/notifications/${selectedNotif.id}/read`);
|
||||
setNotifs(prev => prev.map(n => n.id === selectedNotif.id ? { ...n, read: 1 } : n));
|
||||
setSelectedNotif(prev => ({ ...prev, read: 1 }));
|
||||
}}>Marquer lu</button>
|
||||
)}
|
||||
{selectedNotif.link && (
|
||||
<button className="btn btn-sm btn-primary" onClick={() => navigate(selectedNotif.link)}>
|
||||
Voir le détail →
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -972,7 +976,14 @@ export default function Communication() {
|
||||
return (
|
||||
<>
|
||||
<div className="comm-list-header">
|
||||
<span style={{ fontWeight: 600, fontSize: 14 }}>Notifications</span>
|
||||
<div className="comm-topbar-filters">
|
||||
{[['all','Tous'],['unread','Non lus']].map(([v,l]) => (
|
||||
<button key={v} className={`comm-topbar-filter-btn${notifFilter === v ? ' active' : ''}`} onClick={() => { setNotifFilter(v); setNotifPage(0); }}>{l}</button>
|
||||
))}
|
||||
{unreadCount > 0 && (
|
||||
<button className="comm-topbar-action-btn" style={{ marginLeft: 'auto' }} onClick={markAllRead}>Tout marquer lu</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="comm-list-scroll">
|
||||
{notifs.length === 0 && (
|
||||
@@ -991,6 +1002,8 @@ export default function Communication() {
|
||||
<div className="comm-list-row-body">
|
||||
<div className="comm-list-row-top">
|
||||
<span className="comm-list-row-name">{n.title}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{
|
||||
fontSize: 11, padding: '2px 7px', borderRadius: 99, fontWeight: 600,
|
||||
background: (TYPE_META[n.type] ?? TYPE_META.info).bg,
|
||||
@@ -1322,6 +1335,42 @@ export default function Communication() {
|
||||
</div>{/* end comm-wrap */}
|
||||
</div>{/* end comm-page */}
|
||||
|
||||
{/* ── Menu ⋮ notifications ── */}
|
||||
{notifMenuPos && (
|
||||
<>
|
||||
<div style={{ position: 'fixed', inset: 0, zIndex: 299 }} onClick={() => setNotifMenuPos(null)} />
|
||||
<div style={{
|
||||
position: 'fixed', left: notifMenuPos.x, top: notifMenuPos.y,
|
||||
transform: 'translateX(-100%) translateY(4px)',
|
||||
zIndex: 300,
|
||||
background: 'var(--surface)', border: '1px solid var(--border)',
|
||||
borderRadius: 8, boxShadow: '0 4px 20px rgba(0,0,0,0.15)',
|
||||
padding: '4px 0', minWidth: 180,
|
||||
}}>
|
||||
{unreadCount > 0 && (
|
||||
<button
|
||||
style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 14px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 'var(--fs-sm)', color: 'var(--text)', textAlign: 'left' }}
|
||||
onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
|
||||
onMouseLeave={e => e.currentTarget.style.background = 'none'}
|
||||
onClick={() => { markAllRead(); setNotifMenuPos(null); }}
|
||||
>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
Tout marquer lu
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 14px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 'var(--fs-sm)', color: 'var(--danger)', textAlign: 'left' }}
|
||||
onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
|
||||
onMouseLeave={e => e.currentTarget.style.background = 'none'}
|
||||
onClick={() => { deleteAllNotifs(); setNotifMenuPos(null); }}
|
||||
>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>
|
||||
Tout supprimer
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* ── Lightbox image ── */}
|
||||
{lightbox && (
|
||||
<div className="comm-lightbox" onClick={() => setLightbox(null)}>
|
||||
|
||||
Reference in New Issue
Block a user