const { useState, useMemo, useEffect } = React;
const data = [
{ id: 1, dom: "Droit civil", sd: "Relations personnelles hors mariage", dem: "Infidélité dans un concubinage", mis: "Suspicion d'un fait constitutif d'infidélité dans une union de fait (préjudice existant)", cj: ["Art. 515.8 du Code civil", "Art. 1240 du Code civil"], jp: ["JP Civ. 30 mai 1838, Bouvier Juris. Générale V° Mariage, n°82 Sirey 1838, 1, 492 (Rupture de fiançailles)", "JP CA Reims n°05/01583 du 19/10/06"] },
{ id: 2, dom: "Droit civil", sd: "Relations personnelles hors mariage", dem: "Infidélité dans un PACS", mis: "Suspicion d'un fait constitutif d'infidélité entre partenaires de PACS", cj: ["Art. 515.1 à 7 du Code civil", "Art. 1104 du Code civil"], jp: [] },
{ id: 3, dom: "Droit civil", sd: "Relations personnelles hors mariage", dem: "Départ du domicile", mis: "Déterminer la cessation de vie commune dans le cadre d'un PACS", cj: ["Art. 515.4 du Code civil"], jp: [] },
{ id: 4, dom: "Droit civil", sd: "Mariage", dem: "Enquêtes de moralité", mis: "Suspicion d'un défaut de capacité ou d'empêchement légal au mariage", cj: ["Art. 144 du Code civil", "Art. 146 du Code civil", "Art. 161 du Code civil"], jp: [] },
{ id: 5, dom: "Droit civil", sd: "Mariage", dem: "Enquête sur la validité du mariage célébré", mis: "Suspicion de non-conformité de la cérémonie matrimoniale", cj: ["Art. 165 du Code civil", "Art. 180 du Code civil"], jp: [] },
{ id: 6, dom: "Droit civil", sd: "Divorce et séparation", dem: "Adultère", mis: "Suspicion de violation du devoir de fidélité", cj: ["Art. 212 du Code civil", "Art. 242 du Code civil"], jp: [] },
{ id: 7, dom: "Droit civil", sd: "Divorce et séparation", dem: "Départ du domicile", mis: "Déterminer la cessation de vie commune", cj: ["Art. 215 du Code civil", "Art. 237 et 238 du Code civil"], jp: [] },
{ id: 8, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Prestation compensatoire", mis: "Déterminer les conditions de vie des époux", cj: ["Art. 270 et 271 du Code civil"], jp: [] },
{ id: 9, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Pension alimentaire entre époux", mis: "Déterminer les conditions de vie des époux", cj: ["Art. 212 du Code civil", "Art. 255.6 du Code civil"], jp: [] },
{ id: 10, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Dommages et intérêts", mis: "Déterminer les conditions de vie des époux", cj: ["Art. 266 du Code civil"], jp: [] },
{ id: 11, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Enquête de patrimoine", mis: "Déterminer du patrimoine dans le cadre de la liquidation du régime matrimonial", cj: ["Art. 1467 du Code civil"], jp: [] },
{ id: 12, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Pension alimentaire enfants", mis: "Déterminer les conditions de vie d'un parent", cj: ["Art. 371.2 et 373.2.2 du Code civil"], jp: [] },
{ id: 13, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Garde d'enfants", mis: "Déterminer les conditions de vie d'un parent", cj: ["Art. 373.2.7 du Code civil"], jp: [] },
{ id: 14, dom: "Droit civil", sd: "Effets du divorce/de la séparation", dem: "Conditions de garde", mis: "Déterminer les carences éducatives", cj: ["Art. 371.4 du Code civil", "Art. 375 du Code civil"], jp: [] },
{ id: 15, dom: "Droit civil", sd: "Filiation / absence et successions", dem: "Enquête de moralité sur mineur", mis: "Déterminer les fréquentations d'un mineur", cj: ["Art. 371.1.2° du Code civil"], jp: [] },
{ id: 16, dom: "Droit civil", sd: "Filiation / absence et successions", dem: "Recherche de paternité", mis: "Déterminer une filiation", cj: ["Art. 327 du Code civil"], jp: [] },
{ id: 17, dom: "Droit civil", sd: "Filiation / absence et successions", dem: "Recherche d'héritiers", mis: "Procédure d'identification des ayants droit", cj: ["Art. 725 du Code civil", "Loi n°2014-617 du 13/06/2014"], jp: [] },
{ id: 18, dom: "Droit civil", sd: "Filiation / absence et successions", dem: "Recherche de personnes", mis: "Établir la disparition", cj: ["Art. 112 du Code civil", "Art. 1240 du Code civil"], jp: [] },
{ id: 19, dom: "Droit civil", sd: "Filiation / absence et successions", dem: "Recherche de débiteur", mis: "Localiser un débiteur", cj: ["Art. 1217 du Code civil"], jp: [] },
{ id: 20, dom: "Droit civil", sd: "Contrats juridiques", dem: "Enquête sur co-contractant", mis: "Suspicion de non respect des conditions de validité", cj: ["Art. 1112.1 du Code civil"], jp: [] },
{ id: 21, dom: "Droit civil", sd: "Contrats juridiques", dem: "Enquête sur les effets d'un contrat", mis: "Suspicion de défaillance d'exécution", cj: ["Art. 1103 du Code civil"], jp: [] },
{ id: 22, dom: "Droit civil", sd: "Faits juridiques", dem: "Responsabilité extra-contractuelle", mis: "Déterminer la responsabilité d'un tiers", cj: ["Art. 1240 du Code civil"], jp: [] },
{ id: 23, dom: "Droit penal des affaires", sd: "Détournements d'actifs", dem: "Vol interne ou externe", mis: "Suspicion d'actes de vols", cj: ["Art. 311-1 du Code penal"], jp: [] },
{ id: 24, dom: "Droit penal des affaires", sd: "Détournements d'actifs", dem: "Escroquerie", mis: "Suspicion d'escroquerie", cj: ["Art. 313-1 du Code penal"], jp: [] },
{ id: 25, dom: "Droit penal des affaires", sd: "Détournements d'actifs", dem: "Abus de confiance", mis: "Suspicion abus de confiance", cj: ["Art. 314-1 du Code penal"], jp: [] },
{ id: 26, dom: "Droit penal des affaires", sd: "Abus de biens sociaux", dem: "Abus de biens sociaux", mis: "Suspicion d'abus", cj: ["Art. L241-3 du Code du commerce"], jp: [] },
{ id: 27, dom: "Droit pénal", sd: "Vols et déprédations", dem: "Vandalisme et vol", mis: "Suspicion de destruction", cj: ["Art. 322-1 du Code penal"], jp: [] },
{ id: 28, dom: "Droit pénal", sd: "Contrefaçon", dem: "Contrefaçon", mis: "Suspicion de contrefaçons", cj: ["Art. L335-2 du CPI"], jp: [] },
{ id: 29, dom: "Droit pénal", sd: "Harcèlement", dem: "Harcèlement", mis: "Suspicion de harcèlement", cj: ["Art. 222-33 du Code pénal"], jp: [] },
{ id: 30, dom: "Droit pénal", sd: "Provocation de mineur", dem: "Provocation de mineur", mis: "Suspicion de mise en péril", cj: ["Art. 227-18 du Code pénal"], jp: [] },
{ id: 31, dom: "Droit pénal", sd: "Trouble de voisinage", dem: "Tapage", mis: "Suspicion de tapage nocturne", cj: ["Art. R623-2 du Code pénal"], jp: [] },
{ id: 32, dom: "Droit pénal", sd: "Révision de justice", dem: "Révision de décision", mis: "Révision de décision de justice", cj: ["Art. 622 du CPP"], jp: [] },
{ id: 33, dom: "Droit du travail", sd: "Relation de travail", dem: "Seconde relation de travail", mis: "Suspicion de travail illégal", cj: ["Art. L1237-3 du Code du travail"], jp: [] },
{ id: 34, dom: "Droit du travail", sd: "Exécution du contrat", dem: "Conditions de travail", mis: "Suspicion de non respect des obligations", cj: ["Art. L3121-27 du Code du travail"], jp: [] },
{ id: 35, dom: "Droit du travail", sd: "Exécution du contrat", dem: "Obligations du salarié", mis: "Suspicion de non respect de loyauté", cj: ["Art. L1222-1 du Code du travail"], jp: [] },
{ id: 36, dom: "Droit du travail", sd: "Concurrence déloyale", dem: "Concurrence déloyale", mis: "Suspicion d'actes de concurrence déloyal", cj: ["Art. 1240 du Code civil"], jp: ["Notions: dénigrement, parasitisme"] },
{ id: 37, dom: "Droit du travail", sd: "Concurrence déloyale", dem: "Clause de non concurrence", mis: "Suspicion de non-respect de clause", cj: ["Art. 1240 du Code civil"], jp: [] },
{ id: 38, dom: "Droit du travail", sd: "Suspension travail", dem: "Arrêt maladie", mis: "Suspicion de non respect de loyauté", cj: ["Art. L1222-1 du Code du travail"], jp: [] },
{ id: 39, dom: "Droit du travail", sd: "Vérification factuels", dem: "Constat commissaire", mis: "Préparation de constat", cj: ["Art. L621-1 du CSI"], jp: [] }
];
const L = ({ className }) => (
);
function App() {
const [t, setT] = useState('dark');
const [adm, setAdm] = useState(false);
const [s, setS] = useState('');
const [d, setD] = useState('tous');
const [sd, setSd] = useState('tous');
const [sel, setSel] = useState(null);
const [rip, setRip] = useState([]);
const [counters, setCounters] = useState({ domains: 0, subdomains: 0, cadres: 0 });
const [showScrollTop, setShowScrollTop] = useState(false);
const [cadresData, setCadresData] = useState(data);
const [authenticated, setAuthenticated] = useState(false);
const [showLoginModal, setShowLoginModal] = useState(false);
const [loginPassword, setLoginPassword] = useState('');
const [loginError, setLoginError] = useState('');
const [adminView, setAdminView] = useState('main');
const [editingCadre, setEditingCadre] = useState(null);
const [showEditModal, setShowEditModal] = useState(false);
const [isAddingNew, setIsAddingNew] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [cadreToDelete, setCadreToDelete] = useState(null);
const [formData, setFormData] = useState({ dom: '', sd: '', dem: '', mis: '', cj: [], jp: [], note: '' });
const [isCreatingDomain, setIsCreatingDomain] = useState(false);
const [isCreatingSubdomain, setIsCreatingSubdomain] = useState(false);
const [customDomain, setCustomDomain] = useState('');
const [customSubdomain, setCustomSubdomain] = useState('');
const [copiedMissionId, setCopiedMissionId] = useState(null);
const modalDomains = useMemo(() => {
return [...new Set(cadresData.map(c => c.dom).filter(d => d))].sort();
}, [cadresData]);
const modalSubdomains = useMemo(() => {
if (!formData.dom) return [];
return [...new Set(cadresData.filter(c => c.dom === formData.dom).map(c => c.sd).filter(s => s))].sort();
}, [cadresData, formData.dom]);
useEffect(() => {
const sv = localStorage.getItem('theme') || 'dark';
setT(sv);
// Charger les données depuis le serveur au démarrage
loadFromServer();
}, []);
useEffect(() => {
const totalDomains = new Set(cadresData.map(c => c.dom)).size;
const totalSubdomains = new Set(cadresData.map(c => c.sd)).size;
const totalCadres = cadresData.length;
const duration = 2800;
const startTime = performance.now();
const animate = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const easeOutCubic = 1 - Math.pow(1 - progress, 3);
setCounters({
domains: Math.round(easeOutCubic * totalDomains),
subdomains: Math.round(easeOutCubic * totalSubdomains),
cadres: Math.round(easeOutCubic * totalCadres)
});
if (progress < 1) {
requestAnimationFrame(animate);
}
};
requestAnimationFrame(animate);
const handleScroll = () => {
setShowScrollTop(window.scrollY > 300);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [cadresData]);
const tog = () => {
const nt = t === 'dark' ? 'light' : 'dark';
setT(nt);
localStorage.setItem('theme', nt);
};
const handleAdminToggle = () => {
if (authenticated) {
setAdm(!adm);
if (!adm) setAdminView('main');
} else {
setShowLoginModal(true);
}
};
const handleLogin = async (e) => {
e.preventDefault();
setLoginError('');
// Authentification serveur
const isAuthenticated = await authenticateServer(loginPassword);
if (isAuthenticated) {
setAuthenticated(true);
setShowLoginModal(false);
setLoginPassword('');
setAdm(true);
} else {
setLoginError('Mot de passe incorrect');
setLoginPassword('');
}
};
const handleLogout = () => {
setAuthenticated(false);
setAdm(false);
setAdminView('main');
};
// ========================================
// FONCTIONS SERVEUR (PHP Backend)
// ========================================
const loadFromServer = async () => {
try {
const timestamp = Date.now();
const response = await fetch(`load.php?t=${timestamp}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (Array.isArray(data)) {
setCadresData(data);
console.log(`✅ ${data.length} cadres chargés depuis le serveur`);
} else {
console.error('❌ Format de données invalide');
}
} catch (error) {
console.error('❌ Erreur chargement serveur:', error);
// Fallback sur les données locales en cas d'erreur
console.log('⚠️ Utilisation des données locales (fallback)');
}
};
const saveToServer = async (data) => {
console.log('🔵 [SAVE] Début de la sauvegarde...', {
nbCadres: data.length,
timestamp: new Date().toLocaleTimeString()
});
try {
const response = await fetch('save.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify(data)
});
console.log('🔵 [SAVE] Réponse reçue:', {
status: response.status,
ok: response.ok
});
if (!response.ok) {
const error = await response.json();
console.error('🔴 [SAVE] Erreur serveur:', error);
throw new Error(error.message || `HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('✅ [SAVE] Sauvegarde réussie:', result);
return true;
} catch (error) {
console.error('❌ [SAVE] Erreur sauvegarde serveur:', error);
alert('⚠️ Erreur de sauvegarde sur le serveur. Vérifiez votre connexion.');
return false;
}
};
const authenticateServer = async (password) => {
try {
const response = await fetch('auth.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({ password })
});
if (!response.ok) {
return false;
}
const result = await response.json();
return result.success === true;
} catch (error) {
console.error('❌ Erreur authentification serveur:', error);
return false;
}
};
const exportToCSV = () => {
const headers = ['ID', 'Domaine', 'Sous-domaine', 'Titre', 'Mission', 'Cadres Juridiques', 'URLs Cadres', 'Jurisprudences', 'URLs Jurisprudences', 'Note'];
const csvContent = [
headers.join(','),
...cadresData.map(c => {
const cjTexts = c.cj.map(cj => typeof cj === 'string' ? cj : cj.text).join(' | ');
const cjUrls = c.cj.map(cj => typeof cj === 'object' && cj.url ? cj.url : '').filter(u => u).join(' | ');
const jpTexts = c.jp.map(jp => typeof jp === 'string' ? jp : jp.text).join(' | ');
const jpUrls = c.jp.map(jp => typeof jp === 'object' && jp.url ? jp.url : '').filter(u => u).join(' | ');
return [
c.id,
`"${c.dom.replace(/"/g, '""')}"`,
`"${c.sd.replace(/"/g, '""')}"`,
`"${c.dem.replace(/"/g, '""')}"`,
`"${c.mis.replace(/"/g, '""')}"`,
`"${cjTexts.replace(/"/g, '""')}"`,
`"${cjUrls.replace(/"/g, '""')}"`,
`"${jpTexts.replace(/"/g, '""')}"`,
`"${jpUrls.replace(/"/g, '""')}"`,
`"${(c.note || '').replace(/"/g, '""')}"`
].join(',');
})
].join('\n');
const blob = new Blob(['\uFEFF' + csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `ONARP_Cadres_Juridiques_${new Date().toISOString().split('T')[0]}.csv`;
link.click();
};
const exportToJSON = () => {
const jsonContent = JSON.stringify(cadresData, null, 2);
const blob = new Blob([jsonContent], { type: 'application/json' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `ONARP_Cadres_Juridiques_${new Date().toISOString().split('T')[0]}.json`;
link.click();
};
const handleEditCadre = (cadre) => {
setIsAddingNew(false);
setEditingCadre(cadre);
setIsCreatingDomain(false);
setIsCreatingSubdomain(false);
setCustomDomain('');
setCustomSubdomain('');
const cjArray = Array.isArray(cadre.cj) && cadre.cj.length > 0
? cadre.cj.map(item => typeof item === 'string' ? { text: item, url: '' } : { text: item.text || '', url: item.url || '' })
: [];
const jpArray = Array.isArray(cadre.jp) && cadre.jp.length > 0
? cadre.jp.map(item => typeof item === 'string' ? { text: item, url: '' } : { text: item.text || '', url: item.url || '' })
: [];
setFormData({
dom: cadre.dom || '',
sd: cadre.sd || '',
dem: cadre.dem || '',
mis: cadre.mis || '',
cj: cjArray,
jp: jpArray,
note: cadre.note || ''
});
setShowEditModal(true);
};
const handleAddNewCadre = () => {
setIsAddingNew(true);
setEditingCadre(null);
setIsCreatingDomain(false);
setIsCreatingSubdomain(false);
setCustomDomain('');
setCustomSubdomain('');
setFormData({ dom: '', sd: '', dem: '', mis: '', cj: [], jp: [], note: '' });
setShowEditModal(true);
};
const handleSaveCadre = async () => {
const finalDomain = isCreatingDomain ? customDomain.trim() : formData.dom;
const finalSubdomain = isCreatingSubdomain ? customSubdomain.trim() : formData.sd;
if (!finalDomain || !finalSubdomain || !formData.dem || !formData.mis) {
alert('Veuillez remplir tous les champs obligatoires : Domaine, Sous-domaine, Titre et Mission');
return;
}
if (isAddingNew) {
const newId = Math.max(...cadresData.map(c => c.id), 0) + 1;
const newCadre = {
id: newId,
dom: finalDomain,
sd: finalSubdomain,
dem: formData.dem,
mis: formData.mis,
cj: formData.cj.map(item => item.url ? { text: item.text, url: item.url } : item.text),
jp: formData.jp.map(item => item.url ? { text: item.text, url: item.url } : item.text),
note: formData.note
};
const updatedData = [...cadresData, newCadre];
setCadresData(updatedData);
console.log('💾 [AJOUT] Appel saveToServer avec', updatedData.length, 'cadres');
await saveToServer(updatedData);
alert('✅ Nouveau cadre créé avec succès !');
} else {
const updatedCadre = {
...editingCadre,
dom: finalDomain,
sd: finalSubdomain,
dem: formData.dem,
mis: formData.mis,
cj: formData.cj.map(item => item.url ? { text: item.text, url: item.url } : item.text),
jp: formData.jp.map(item => item.url ? { text: item.text, url: item.url } : item.text),
note: formData.note
};
const updatedData = cadresData.map(c =>
c.id === editingCadre.id ? updatedCadre : c
);
setCadresData(updatedData);
console.log('💾 [MODIFICATION] Appel saveToServer avec', updatedData.length, 'cadres');
await saveToServer(updatedData);
if (sel?.id === editingCadre.id) {
setSel(updatedCadre);
}
alert('✅ Modifications sauvegardées avec succès !');
}
setShowEditModal(false);
setEditingCadre(null);
setIsAddingNew(false);
setIsCreatingDomain(false);
setIsCreatingSubdomain(false);
setCustomDomain('');
setCustomSubdomain('');
setAdminView('main');
};
const handleDeleteCadre = (cadreId) => {
const cadre = cadresData.find(c => c.id === cadreId);
if (!cadre) {
alert('Erreur : Cadre introuvable');
return;
}
setCadreToDelete(cadre);
setShowDeleteConfirm(true);
};
const confirmDelete = async () => {
if (cadreToDelete) {
const updatedData = cadresData.filter(c => c.id !== cadreToDelete.id);
setCadresData(updatedData);
console.log('💾 [SUPPRESSION] Appel saveToServer avec', updatedData.length, 'cadres');
await saveToServer(updatedData);
if (sel?.id === cadreToDelete.id) {
setSel(null);
}
setShowDeleteConfirm(false);
setCadreToDelete(null);
alert('✅ Cadre supprimé avec succès !');
}
};
const cancelDelete = () => {
setShowDeleteConfirm(false);
setCadreToDelete(null);
};
const addCjItem = () => {
setFormData({ ...formData, cj: [...formData.cj, { text: '', url: '' }] });
};
const addJpItem = () => {
setFormData({ ...formData, jp: [...formData.jp, { text: '', url: '' }] });
};
const removeCjItem = (index) => {
setFormData({ ...formData, cj: formData.cj.filter((_, i) => i !== index) });
};
const removeJpItem = (index) => {
setFormData({ ...formData, jp: formData.jp.filter((_, i) => i !== index) });
};
const updateCjItem = (index, field, value) => {
const newCj = [...formData.cj];
newCj[index][field] = value;
setFormData({ ...formData, cj: newCj });
};
const updateJpItem = (index, field, value) => {
const newJp = [...formData.jp];
newJp[index][field] = value;
setFormData({ ...formData, jp: newJp });
};
const moveCjItem = (index, direction) => {
if ((direction === 'up' && index === 0) || (direction === 'down' && index === formData.cj.length - 1)) return;
const newCj = [...formData.cj];
const newIndex = direction === 'up' ? index - 1 : index + 1;
[newCj[index], newCj[newIndex]] = [newCj[newIndex], newCj[index]];
setFormData({ ...formData, cj: newCj });
};
const moveJpItem = (index, direction) => {
if ((direction === 'up' && index === 0) || (direction === 'down' && index === formData.jp.length - 1)) return;
const newJp = [...formData.jp];
const newIndex = direction === 'up' ? index - 1 : index + 1;
[newJp[index], newJp[newIndex]] = [newJp[newIndex], newJp[index]];
setFormData({ ...formData, jp: newJp });
};
const handleRip = (e) => {
const x = e.clientX;
const y = e.clientY;
const id = Date.now();
setRip(prev => [...prev, { x, y, id }]);
setTimeout(() => setRip(prev => prev.filter(r => r.id !== id)), 1500);
};
const scrollToTop = () => {
const duration = 1500;
const start = window.pageYOffset;
const startTime = performance.now();
const animateScroll = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const easeInOutCubic = progress < 0.5
? 4 * progress * progress * progress
: 1 - Math.pow(-2 * progress + 2, 3) / 2;
window.scrollTo(0, start * (1 - easeInOutCubic));
if (progress < 1) {
requestAnimationFrame(animateScroll);
}
};
requestAnimationFrame(animateScroll);
};
const doms = useMemo(() => ['tous', ...new Set(cadresData.map(c => c.dom))], [cadresData]);
const sds = useMemo(() => {
if (d === 'tous') return [];
return ['tous', ...new Set(cadresData.filter(c => c.dom === d).map(c => c.sd))];
}, [d, cadresData]);
const filt = useMemo(() => {
return cadresData.filter(c => {
const md = d === 'tous' || c.dom === d;
const msd = sd === 'tous' || c.sd === sd;
const ms = !s || c.dem.toLowerCase().includes(s.toLowerCase()) || c.mis.toLowerCase().includes(s.toLowerCase());
return md && msd && ms;
});
}, [d, sd, s, cadresData]);
const btnClass = (active) => `relative px-5 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 ease-in-out hover:scale-105 active:scale-95 hover:shadow-lg hover:shadow-amber-500/30 hover:ring-2 hover:ring-amber-500/50 ${active ? t==='dark' ? 'bg-amber-500 text-slate-900 shadow-lg ring-2 ring-amber-400' : 'bg-amber-500 text-white shadow-lg ring-2 ring-amber-400' : t==='dark' ? 'bg-slate-700 hover:bg-slate-600 text-white border border-slate-600' : 'bg-[#F0EDE7] hover:bg-[#DDD9D3] text-gray-700 border border-gray-300'}`;
return (
{rip.map(r => (
))}
ONARP
Outil d'aide à la détermination du cadre juridique
{authenticated && (
)}
{counters.domains}
Domaines juridiques
{counters.subdomains}
Sous-domaines juridiques
{counters.cadres}
Cadres juridiques
{adm && (
)}
{adm ? (
{adminView === 'main' && (
)}
{adminView === 'export' && (
Exporter les données
)}
{adminView === 'modify' && (
Liste des cadres juridiques ({cadresData.length})
{cadresData.map(c => (
{sel?.id === c.id && (
Cadre juridique
{c.cj.map((x,i)=> {
const isObject = typeof x === 'object' && x !== null;
const text = isObject ? x.text : x;
const url = isObject ? x.url : null;
return url ? (
- {text}
) : (
- {text}
);
})}
{c.jp.length>0&&(
Jurisprudence
{c.jp.map((j,i)=> {
const isObject = typeof j === 'object' && j !== null;
const text = isObject ? j.text : j;
const url = isObject ? j.url : null;
return url ? (
- {text}
) : (
- {text}
);
})}
)}
{c.note && (
Note particulière
{c.note}
)}
)}
))}
)}
) : (
setS(e.target.value)} className={`w-full px-5 py-3 sm:py-4 pl-12 rounded-xl border focus:outline-none focus:border-amber-500 focus:ring-2 focus:ring-amber-500/50 transition-all duration-200 text-sm sm:text-base ${t==='dark'?'bg-slate-800/50 border-slate-700 text-white placeholder-slate-400':'bg-[#F5F2EC] border-gray-300 text-black placeholder-gray-400'}`}/>
{doms.map(dm=>(
))}
{sds.length > 0 && (
{sds.map(s=>(
))}
)}
{filt.length} cadre{filt.length>1?'s':''}
{filt.map(c=>(
setSel(sel?.id===c.id?null:c)} className={`p-4 sm:p-6 rounded-xl cursor-pointer border transition-all duration-300 hover:scale-[1.02] hover:shadow-xl hover:shadow-amber-500/20 hover:ring-2 hover:ring-amber-500/50 ${sel?.id===c.id?t==='dark'?'bg-slate-800 border-amber-500 shadow-xl ring-2 ring-amber-400':'bg-amber-50 border-amber-400 ring-2 ring-amber-400':t==='dark'?'bg-slate-800/50 border-slate-700':'bg-[#F0EDE7] border-gray-300'}`}>
{c.dom}
▼
{c.dem}
{c.sd}
{sel?.id===c.id&&(
Mission dévolue
{c.mis}
Cadre juridique
{c.cj.map((x,i)=> {
const isObject = typeof x === 'object' && x !== null;
const text = isObject ? x.text : x;
const url = isObject ? x.url : null;
return url ? (
-
{text}
) : (
- {text}
);
})}
{c.jp.length>0&&(
Jurisprudence
{c.jp.map((j,i)=> {
const isObject = typeof j === 'object' && j !== null;
const text = isObject ? j.text : j;
const url = isObject ? j.url : null;
return url ? (
-
{text}
) : (
- {text}
);
})}
)}
{c.note && (
Note particulière
{c.note}
)}
)}
))}
)}
{showLoginModal && (
Espace Administrateur
Authentification sécurisée requise
🛡️ Connexion sécurisée par ONARP
)}
{showEditModal && (editingCadre || isAddingNew) && (
e.stopPropagation()}>
{isAddingNew ? 'Ajouter un cadre juridique' : 'Éditer le cadre juridique'}
{!isCreatingDomain ? (
) : (
setCustomDomain(e.target.value)} placeholder="Ex: Droit administratif" className={`flex-1 px-3 sm:px-4 py-2 sm:py-3 rounded-lg border text-sm sm:text-base focus:outline-none focus:ring-2 focus:ring-amber-500/50 transition-all ${t==='dark'?'bg-slate-700 border-slate-600 text-white placeholder-slate-400':'bg-[#F5F2EC] border-gray-300 text-black placeholder-gray-400'}`} />
)}
{!isCreatingSubdomain ? (
) : (
setCustomSubdomain(e.target.value)} placeholder="Ex: Contentieux administratif" className={`flex-1 px-3 sm:px-4 py-2 sm:py-3 rounded-lg border text-sm sm:text-base focus:outline-none focus:ring-2 focus:ring-amber-500/50 transition-all ${t==='dark'?'bg-slate-700 border-slate-600 text-white placeholder-slate-400':'bg-[#F5F2EC] border-gray-300 text-black placeholder-gray-400'}`} />
)}
setFormData({...formData, dem: e.target.value})} className={`w-full px-3 sm:px-4 py-2 sm:py-3 rounded-lg border text-sm sm:text-base focus:outline-none focus:ring-2 focus:ring-amber-500/50 transition-all ${t==='dark'?'bg-slate-700 border-slate-600 text-white':'bg-[#F5F2EC] border-gray-300 text-black'}`} placeholder="Ex: Infidélité dans un concubinage" />
{formData.cj.map((item, index) => (
))}
{formData.jp.map((item, index) => (
))}
)}
{showDeleteConfirm && cadreToDelete && (
⚠️ Suppression définitive
Êtes-vous sûr de vouloir supprimer ce cadre juridique ?
{cadreToDelete.dem}
{cadreToDelete.dom}
⚠️ Cette action est irréversible
)}
{showScrollTop && (
)}
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render();