// ECO-PANNEAU.FR - _react/guest/_guest_view.jsx // 1. - COMPOSANT PRINCIPAL : ACCÈS INVITÉ (NO-FRICTION) window.pano_GuestView = ({ token, showToast }) => { const { useState, useEffect } = React; // ZÉRO-DETTE : Utilisation de notre Hook abstrait ! const { isMounted, safeFetch } = window.pano_useSafeFetch(); // États globaux const [viewState, setViewState] = useState('loading'); // loading, pending, accepted, rejected, error const [guestData, setGuestData] = useState(null); const [panneau, setPanneau] = useState(null); const [errorMsg, setErrorMsg] = useState(null); // États UI (Modales et actions) const [isSaving, setIsSaving] = useState(false); const [showIdentityModal, setShowIdentityModal] = useState(false); const [showSignupWall, setShowSignupWall] = useState(false); const [identityForm, setIdentityForm] = useState({ name: '', company: '' }); // États Éditeur const [editingEntity, setEditingEntity] = useState(null); const [confirmDialog, setConfirmDialog] = useState(null); // Composants et Icônes const { LoaderIcon, AlertTriangleIcon, CheckCircleIcon, ShieldIcon, LogOutIcon, EyeIcon, MessageSquareIcon, UserIcon, BuildingIcon, FileTextIcon, LockIcon } = window.pano_getIcons(); const { ConfirmModal, Button, Modal, PanneauEditorForm, EntityEditorModal, TextLogo } = window.pano_getComponents(); // INITIALISATION : Récupération du jeton et du statut useEffect(() => { fetch(window.pano_CONFIG.apiBaseUrl + 'panneaux/collaborators/guest_access&token=' + encodeURIComponent(token) + '&_t=' + Date.now()) .then(r => r.json()) .then(d => { if (!isMounted.current) return; if (d.status === 'success') { setGuestData(d.data); setPanneau(d.data.panneau); setViewState(d.data.status); // 'pending', 'accepted', 'rejected' } else { setErrorMsg(d.message); setViewState('error'); } }) .catch((e) => { if (!isMounted.current) return; if (window.pano_logFallback) window.pano_logFallback("Erreur fetch guest: " + e.message); setErrorMsg("Erreur de connexion au serveur."); setViewState('error'); }); }, [token, isMounted]); // ACTIONS MÉTIER const handleAccept = async (e) => { e.preventDefault(); if (!identityForm.name.trim() || !identityForm.company.trim()) { showToast("Veuillez remplir tous les champs.", "error"); return; } const d = await safeFetch('panneaux/collaborators/guest_respond', { body: { token, action: 'accept', name: identityForm.name.trim(), company: identityForm.company.trim() }, setLoading: setIsSaving }); if (!isMounted.current) return; if (d && d.status === 'success') { setShowIdentityModal(false); setViewState('accepted'); showToast("Invitation acceptée. Vous pouvez maintenant éditer le panneau.", "success"); } }; const handleReject = () => { setConfirmDialog({ title: "Refuser l'invitation", message: "Êtes-vous sûr de vouloir refuser cette invitation ? Vous perdrez l'accès à ce panneau.", confirmText: "Oui, refuser", isDestructive: true, onConfirm: async () => { setConfirmDialog(null); const d = await safeFetch('panneaux/collaborators/guest_respond', { body: { token, action: 'reject' }, setLoading: setIsSaving }); if (!isMounted.current) return; if (d && d.status === 'success') setViewState('rejected'); } }); }; const handleSaveEditor = async () => { const pCible = panneau || {}; // Anti-conflit d'édition en mode délégué const detailsToSave = { ...pCible, ...(pCible.draft_data || {}), draft_data: {} }; const payload = { token: token, id: String(pCible.id), status: String(pCible.status), offerType: String(pCible.offerType), details: detailsToSave }; const d = await safeFetch('panneaux/collaborators/guest_update', { body: payload, setLoading: setIsSaving, successMessage: "Modifications enregistrées avec succès." }); // Si succès, l'UI reste sur place }; // --- VUES DE LA MACHINE À ÉTATS --- if (viewState === 'loading') { return (
Vérification de l'accès sécurisé...
{errorMsg}
Vous avez refusé l'accès à ce panneau. Le propriétaire du projet a été notifié.
Vous avez été invité sur un projet géré par eco-panneau.fr
{guestData.inviter_name} de la société {guestData.inviter_company} vous invite à participer au projet suivant :
{panneau?.location || "Emplacement non renseigné"}
{(panneau?.a1PdfId || panneau?.imageId) && (Projet : {panneau?.name} - {panneau?.location}
Pour des raisons de traçabilité légale, l'utilisation de la messagerie pour discuter avec l'équipe du chantier ou répondre aux riverains nécessite de s'authentifier.
Passez à la vitesse supérieure !