import React, { useState, useEffect, useRef } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, doc, setDoc, onSnapshot, collection, query, addDoc, serverTimestamp, updateDoc } from 'firebase/firestore'; import { Send, User, Edit3, Check, X, AlertTriangle, ShieldCheck } from 'lucide-react'; /** * IMPORTANTE: Sostituisci i valori qui sotto con quelli della tua Firebase Console. * Senza questi, l'app su Cloudflare non sa a quale database collegarsi. */ const CF_FIREBASE_CONFIG = { apiKey: "IL_TUO_API_KEY", authDomain: "IL_TUO_PROGETTO.firebaseapp.com", projectId: "IL_TUO_ID_PROGETTO", storageBucket: "IL_TUO_PROGETTO.appspot.com", messagingSenderId: "IL_TUO_SENDER_ID", appId: "IL_TUO_APP_ID" }; const firebaseConfig = (typeof __firebase_config !== 'undefined' && __firebase_config) ? JSON.parse(__firebase_config) : CF_FIREBASE_CONFIG; const appId = typeof __app_id !== 'undefined' ? __app_id : 'vibe-chat-cf'; // Inizializzazione protetta let db, auth; try { const app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); } catch (e) { console.error("Firebase init error:", e); } export default function App() { const [user, setUser] = useState(null); const [profile, setProfile] = useState(null); const [messages, setMessages] = useState([]); const [inputText, setInputText] = useState(''); const [isEditing, setIsEditing] = useState(false); const [newName, setNewName] = useState(''); const [connError, setConnError] = useState(null); const scrollRef = useRef(null); // RULE 3: Auth prima di ogni operazione useEffect(() => { if (!auth) { setConnError("Configurazione Firebase mancante."); return; } const initAuth = async () => { try { // Proviamo il token custom fornito dall'ambiente, altrimenti anonimo if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { const { signInWithCustomToken } = await import('firebase/auth'); await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (err) { console.error("Auth error:", err); setConnError("Errore di autenticazione. Verifica di aver abilitato 'Anonymous Auth' su Firebase."); } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, (u) => { setUser(u); }); return () => unsubscribe(); }, []); // Sincronizzazione dati protetta (solo dopo auth) useEffect(() => { if (!user || !db) return; // RULE 1: Percorso privato corretto const profileRef = doc(db, 'artifacts', appId, 'users', user.uid, 'profile', 'info'); const unsubProfile = onSnapshot(profileRef, (snap) => { if (snap.exists()) { const data = snap.data(); setProfile(data); setNewName(data.name || ''); } else { const initial = { name: `User_${user.uid.substring(0, 4)}`, uid: user.uid, createdAt: serverTimestamp() }; setDoc(profileRef, initial).catch(e => { console.error("SetDoc error:", e); setConnError("Errore permessi profilo. Verifica le Security Rules."); }); } }, (err) => { console.error("Profile onSnapshot error:", err); setConnError("Errore permessi lettura profilo."); }); // RULE 1: Percorso pubblico corretto const msgsRef = collection(db, 'artifacts', appId, 'public', 'data', 'messages'); const unsubMsgs = onSnapshot(msgsRef, (snap) => { const list = snap.docs.map(d => ({ id: d.id, ...d.data() })); // RULE 2: Ordinamento in memoria const sorted = list.sort((a, b) => { const timeA = a.time?.seconds || 0; const timeB = b.time?.seconds || 0; return timeA - timeB; }); setMessages(sorted); setTimeout(() => scrollRef.current?.scrollIntoView({ behavior: 'smooth' }), 100); }, (err) => { console.error("Messages onSnapshot error:", err); // Non blocchiamo l'intera app per i messaggi, ma logghiamo }); return () => { unsubProfile(); unsubMsgs(); }; }, [user]); const sendMessage = async (e) => { e.preventDefault(); if (!inputText.trim() || !user || !profile) return; const text = inputText; setInputText(''); try { // Assicurati che il percorso sia esattamente quello delle regole await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'messages'), { text, sender: profile.name || 'Anonimo', uid: user.uid, time: serverTimestamp() }); } catch (e) { console.error("Send error:", e); setConnError("Invio fallito. Controlla le regole di scrittura 'public/data'."); } }; const updateProfile = async () => { if (!newName.trim() || !user) return; try { const profileRef = doc(db, 'artifacts', appId, 'users', user.uid, 'profile', 'info'); await updateDoc(profileRef, { name: newName.trim() }); setIsEditing(false); } catch (e) { console.error("Update profile error:", e); setConnError("Aggiornamento profilo fallito. Controlla i permessi 'users/uid'."); } }; if (connError) return (
{connError}
Cosa fare adesso:
1. Vai nella Console Firebase > Firestore > Rules
2. Incolla queste regole:
{`match /artifacts/${appId}/public/data/messages/{d} {
allow read, write: if request.auth != null;
}
match /artifacts/${appId}/users/{uid}/profile/info {
allow read, write: if request.auth != null && request.auth.uid == uid;
}`}