// ECO-PANNEAU.FR - __react/socle/_socle_editeur_infos.jsx window.pano_PanneauEditorInfos = ({ panneau, setPanneau, lockedFields = [], validationErrors = [], settings, uiPrefs = {} }) => { // 1. - SÉCURITÉ ANTI-FUITE DE MÉMOIRE (Memory Leak) ET CORRUPTION D'ÉTAT const isMounted = React.useRef(true); React.useEffect(() => { return () => { isMounted.current = false; }; }, []); // 2. - Composants et Icônes const { AlertBox, Button } = window.pano_getComponents(); const { InfoIcon, LockIcon, MapPinIcon, CalendarIcon, UploadCloudIcon, CheckCircleIcon, Trash2Icon, PlusIcon } = window.pano_getIcons(); // 3. - Logique de verrouillage const isFieldLocked = (fieldId) => lockedFields.includes(fieldId); // 4. - Actions métier const handleFileUpload = async (e, type) => { const file = e.target.files[0]; if (e.target) e.target.value = null; if (!file) return; const uploadImage = (urlField, idField) => { const reader = new FileReader(); reader.onload = async (event) => { if (!isMounted.current) return; const base64Url = event.target.result; setPanneau(prev => ({ ...prev, [urlField]: base64Url })); try { const fileObj = await window.pano_uploadFile(file, 'image', null, false, false, panneau.client_uid, panneau.id); if (!isMounted.current) return; setPanneau(prev => ({ ...prev, [idField]: fileObj.id || fileObj })); } catch (err) { if (!isMounted.current) return; if (window.pano_showToast) window.pano_showToast(err, "error"); else if (window.pano_logFallback) window.pano_logFallback("Erreur d'upload d'image ignorée."); setPanneau(prev => ({ ...prev, [urlField]: '' })); } }; reader.readAsDataURL(file); }; if (type === 'image') { uploadImage('imageUrl', 'imageId'); } else if (type === 'logo') { uploadImage('maitreOuvrageLogoUrl', 'maitreOuvrageLogoId'); } else if (type === 'logo_architecte') { uploadImage('architecteLogoUrl', 'architecteLogoId'); } else if (type === 'pdf') { try { const fileObj = await window.pano_uploadFile(file, 'pdf', null, false, false, panneau.client_uid, panneau.id); if (!isMounted.current) return; setPanneau(prev => ({ ...prev, pdfId: fileObj.id || fileObj, pdfNumPages: fileObj.numPages || 1 })); } catch (err) { if (!isMounted.current) return; if (window.pano_showToast) window.pano_showToast(err, "error"); else if (window.pano_logFallback) window.pano_logFallback("Erreur d'upload PDF ignorée."); } } }; // 4.1 - Gestion des arrêtés modificatifs const addModificatif = () => { if (isFieldLocked('permitNumber')) return; const currentArr = panneau.modificatifs || []; const newUid = 'mod_' + Date.now() + '_' + Math.floor(Math.random() * 1000); const newPanneau = { ...panneau, modificatifs: [...currentArr, { _uid: newUid, label: '', date: '', id: '', numPages: 1 }] }; delete newPanneau.modifiedPermits; setPanneau(newPanneau); }; const updateModificatif = (uid, field, value) => { if (isFieldLocked('permitNumber')) return; const currentArr = panneau.modificatifs || []; const newArr = currentArr.map((p, i) => { const pUid = p._uid || p.id || i; return pUid === uid ? { ...p, [field]: value } : p; }); const newPanneau = { ...panneau, modificatifs: newArr }; delete newPanneau.modifiedPermits; setPanneau(newPanneau); }; const removeModificatif = (uid) => { if (isFieldLocked('permitNumber')) return; const currentArr = panneau.modificatifs || []; const newArr = currentArr.filter((p, i) => (p._uid || p.id || i) !== uid); const newPanneau = { ...panneau, modificatifs: newArr }; delete newPanneau.modifiedPermits; setPanneau(newPanneau); }; const handleModificatifUpload = async (e, uid) => { const file = e.target.files[0]; if (e.target) e.target.value = null; if (!file) return; try { const fileObj = await window.pano_uploadFile(file, 'pdf', null, false, false, panneau.client_uid, panneau.id); if (!isMounted.current) return; const currentArr = panneau.modificatifs || []; const newArr = currentArr.map((p, i) => { const pUid = p._uid || p.id || i; return pUid === uid ? { ...p, id: fileObj.id || fileObj, numPages: fileObj.numPages || 1 } : p; }); const newPanneau = { ...panneau, modificatifs: newArr }; delete newPanneau.modifiedPermits; setPanneau(newPanneau); } catch (err) { if (!isMounted.current) return; if (window.pano_showToast) window.pano_showToast(err, "error"); else if (window.pano_logFallback) window.pano_logFallback("Erreur d'upload modificatif ignorée."); } }; const showContactRow = uiPrefs.simp_opt_schedule !== false || uiPrefs.simp_opt_emergency !== false || uiPrefs.simp_opt_link !== false; // 5. - Rendu UI return (
{lockedFields.length > 0 && ( Certains champs ont été verrouillés par le propriétaire du projet. )} {/* 5.1 - Le projet */}

1. Le projet

setPanneau({...panneau, name: e.target.value})} placeholder="Ex: Construction de 12 logements collectifs" className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold ${ isFieldLocked('name') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : validationErrors.some(e => e.includes('nom du chantier')) ? 'border-red-300 focus:border-red-500 bg-red-50' : 'border-slate-200 focus:border-emerald-500' }`} />
{uiPrefs.simp_opt_description !== false && (
)}
setPanneau({...panneau, location: e.target.value})} placeholder="Numéro, Rue, Code Postal, Ville" className={`w-full border-2 rounded-xl p-3 pl-10 outline-none transition font-bold ${ isFieldLocked('location') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : validationErrors.some(e => e.includes('adresse du panneau')) ? 'border-red-300 focus:border-red-500 bg-red-50' : 'border-slate-200 focus:border-emerald-500' }`} />
{showContactRow && (
{uiPrefs.simp_opt_schedule !== false && (
{isFieldLocked('noiseSchedule') && } setPanneau({...panneau, noiseSchedule: e.target.value})} placeholder="Horaires bruyants (Ex: Lun-Ven 8h-17h)" className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold text-sm ${ isFieldLocked('noiseSchedule') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
)} {uiPrefs.simp_opt_emergency !== false && (
{isFieldLocked('emergencyPhone') && } setPanneau({...panneau, emergencyPhone: e.target.value})} placeholder="Téléphone d'urgence (24/7)" className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold text-sm ${ isFieldLocked('emergencyPhone') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
)} {uiPrefs.simp_opt_link !== false && (
{isFieldLocked('promoterLink') && } setPanneau({...panneau, promoterLink: e.target.value})} placeholder="Lien vers le site du promoteur (https://...)" className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold text-sm ${ isFieldLocked('promoterLink') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
)}
)} {uiPrefs.simp_opt_image !== false && (
{(panneau.imageUrl || panneau.imageId) && (
Aperçu {!isFieldLocked('imageId') && (
)}
)}
{/* 5.2 - L'autorisation (PDF et permis) */} {uiPrefs.simp_opt_hide_legal !== true && (

2. L'autorisation

setPanneau({...panneau, permitNumber: e.target.value})} placeholder="PC 000 000 00 00000" className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold uppercase ${ isFieldLocked('permitNumber') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
setPanneau({...panneau, permitDate: e.target.value})} className={`w-full border-2 rounded-xl p-3 pl-10 outline-none transition font-bold ${ isFieldLocked('permitNumber') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
setPanneau({...panneau, mairie: e.target.value})} placeholder="Mairie de..." className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold ${ isFieldLocked('permitNumber') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
{panneau.pdfId && (
PDF uploadé
{!isFieldLocked('pdfId') && (
)}
{!isFieldLocked('permitNumber') && ( )}
{(panneau.modificatifs || []).map((mod, index) => { const uid = mod._uid || mod.id || index; return (
updateModificatif(uid, 'label', e.target.value)} className={`flex-1 border border-slate-200 rounded-lg p-2 text-sm outline-none transition font-bold ${ isFieldLocked('permitNumber') ? 'bg-slate-100 text-slate-500 cursor-not-allowed' : 'focus:border-emerald-500' }`} /> updateModificatif(uid, 'date', e.target.value)} className={`w-36 border border-slate-200 rounded-lg p-2 text-sm outline-none transition font-bold ${ isFieldLocked('permitNumber') ? 'bg-slate-100 text-slate-500 cursor-not-allowed' : 'focus:border-emerald-500' }`} />
{mod.id && !mod.id.startsWith('mod_') && (
PDF lié
)}
{!isFieldLocked('permitNumber') && (
); })}
)} {/* 5.3 - Acteurs principaux */}

3. Acteurs principaux

setPanneau({...panneau, maitreOuvrage: e.target.value})} placeholder="Nom ou Société du bénéficiaire" className={`w-full border-2 rounded-xl p-3 outline-none transition font-bold ${ isFieldLocked('maitreOuvrage') ? 'bg-slate-50 border-slate-200 text-slate-500 cursor-not-allowed' : 'border-slate-200 focus:border-emerald-500' }`} />
{(panneau.maitreOuvrageLogoUrl || panneau.maitreOuvrageLogoId) && (
Logo Propriétaire {!isFieldLocked('maitreOuvrage') && (
)}
setPanneau({...panneau, architecte: e.target.value})} placeholder="Nom de l'architecte" className="w-full border-2 border-slate-200 rounded-xl p-3 focus:border-emerald-500 outline-none transition font-bold" />
{(panneau.architecteLogoUrl || panneau.architecteLogoId) && (
Logo Architecte
)}
{/* 5.4 - Dimensions */}

4. Surfaces et dimensions

setPanneau({...panneau, superficieTerrain: e.target.value})} className="w-full border-2 border-slate-200 rounded-xl p-2.5 pr-8 focus:border-emerald-500 outline-none transition font-bold text-sm" />
setPanneau({...panneau, surfacePlancher: e.target.value})} className="w-full border-2 border-slate-200 rounded-xl p-2.5 pr-8 focus:border-emerald-500 outline-none transition font-bold text-sm" />
setPanneau({...panneau, hauteur: e.target.value})} className="w-full border-2 border-slate-200 rounded-xl p-2.5 pr-8 focus:border-emerald-500 outline-none transition font-bold text-sm" /> m
setPanneau({...panneau, surfaceDemolir: e.target.value})} className="w-full border-2 border-slate-200 rounded-xl p-2.5 pr-8 focus:border-emerald-500 outline-none transition font-bold text-sm" />
); }; /* EOF ========== [__react/socle/_socle_editeur_infos.jsx] */