2026-05-25 17:39:38 -04:00
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
import { useStore } from '../stores/store';
|
|
|
|
|
import { api } from '../stores/api';
|
|
|
|
|
|
|
|
|
|
export default function JournalActions() {
|
|
|
|
|
const { setPage } = useStore();
|
|
|
|
|
const [actions, setActions] = useState([]);
|
2026-05-31 10:59:41 -04:00
|
|
|
const [historique, setHistorique] = useState([]);
|
|
|
|
|
const [tab, setTab] = useState('historique');
|
2026-05-25 17:39:38 -04:00
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
|
const [error, setError] = useState('');
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-05-31 10:59:41 -04:00
|
|
|
Promise.all([
|
|
|
|
|
api.get('/journal/historique?limite=100'),
|
|
|
|
|
api.get('/journal/actions?limite=100'),
|
|
|
|
|
])
|
|
|
|
|
.then(([hist, acts]) => { setHistorique(hist); setActions(acts); })
|
2026-05-25 17:39:38 -04:00
|
|
|
.catch((e) => setError(e.message))
|
|
|
|
|
.finally(() => setLoading(false));
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const formatDate = (value) => new Date(value).toLocaleString('fr-CA', {
|
|
|
|
|
dateStyle: 'medium',
|
|
|
|
|
timeStyle: 'short',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-gray-100">
|
|
|
|
|
<div className="bg-aa-blue text-white p-4 flex items-center gap-3">
|
|
|
|
|
<button onClick={() => setPage('accueil')} className="text-2xl">←</button>
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-lg font-bold">Journal</h1>
|
|
|
|
|
<p className="text-sm text-blue-100">Changements enregistrés</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="p-4 space-y-3">
|
2026-05-31 10:59:41 -04:00
|
|
|
<div className="grid grid-cols-2 gap-2">
|
|
|
|
|
<button onClick={() => setTab('historique')} className={`p-3 rounded-xl text-sm font-bold ${tab === 'historique' ? 'bg-aa-blue text-white' : 'bg-white text-gray-600'}`}>
|
|
|
|
|
Historique
|
|
|
|
|
</button>
|
|
|
|
|
<button onClick={() => setTab('technique')} className={`p-3 rounded-xl text-sm font-bold ${tab === 'technique' ? 'bg-aa-blue text-white' : 'bg-white text-gray-600'}`}>
|
|
|
|
|
Technique
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
2026-05-25 17:39:38 -04:00
|
|
|
{loading && <p className="text-gray-500 text-center py-8">Chargement...</p>}
|
|
|
|
|
{error && <div className="bg-red-50 text-red-600 p-3 rounded-xl text-sm">{error}</div>}
|
2026-05-31 10:59:41 -04:00
|
|
|
{!loading && tab === 'historique' && historique.length === 0 && (
|
2026-05-25 17:39:38 -04:00
|
|
|
<p className="text-gray-500 text-center py-8">Aucun changement journalisé.</p>
|
|
|
|
|
)}
|
2026-05-31 10:59:41 -04:00
|
|
|
{!loading && tab === 'technique' && actions.length === 0 && (
|
|
|
|
|
<p className="text-gray-500 text-center py-8">Aucune action technique journalisée.</p>
|
|
|
|
|
)}
|
|
|
|
|
{tab === 'historique' && historique.map((item) => (
|
|
|
|
|
<div key={item.id} className="bg-white rounded-2xl p-4 shadow-sm">
|
|
|
|
|
<div className="flex items-start justify-between gap-3">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-bold text-gray-800">{item.raison}</p>
|
|
|
|
|
<p className="text-xs text-gray-400 mt-1">{formatDate(item.cree_le)}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<span className="text-xs font-bold rounded-full bg-blue-50 text-blue-700 px-2 py-1">
|
|
|
|
|
{item.action}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mt-3 text-xs text-gray-500 space-y-1">
|
|
|
|
|
<p>Membre: {item.membre_prenom || item.membre_id || '—'}</p>
|
|
|
|
|
<p>Objet: {item.table_cible} · {item.objet_id}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
{tab === 'technique' && actions.map((action) => (
|
2026-05-25 17:39:38 -04:00
|
|
|
<div key={action.id} className="bg-white rounded-2xl p-4 shadow-sm">
|
|
|
|
|
<div className="flex items-start justify-between gap-3">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-bold text-gray-800">{action.methode} {action.chemin}</p>
|
|
|
|
|
<p className="text-xs text-gray-400 mt-1">{formatDate(action.cree_le)}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<span className="text-xs font-bold rounded-full bg-gray-100 text-gray-600 px-2 py-1">
|
|
|
|
|
{action.statut_http}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mt-3 text-xs text-gray-500 space-y-1">
|
|
|
|
|
<p>Membre: {action.membre_id}</p>
|
|
|
|
|
{action.admin_id && <p>Admin: {action.admin_id}</p>}
|
|
|
|
|
{action.adresse_ip && <p>IP: {action.adresse_ip}</p>}
|
|
|
|
|
{action.details?.impersonification && (
|
|
|
|
|
<p className="text-amber-700 font-medium">Action faite en impersonification</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|