import React, { useState, useEffect, useRef } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, onAuthStateChanged, updateProfile, signInWithCustomToken } from 'firebase/auth'; import { getFirestore, collection, addDoc, query, onSnapshot, orderBy, serverTimestamp, doc, setDoc, getDoc, deleteDoc } from 'firebase/firestore'; import { MessageSquare, Plus, LogOut, User, Search, Send, ArrowLeft, Users, Trash2, Smile } from 'lucide-react'; // --- Firebase Initialization --- const firebaseConfig = JSON.parse(__firebase_config); const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; // --- Constants & Helpers --- const AVATAR_COLORS = ['#EF4444', '#F59E0B', '#10B981', '#3B82F6', '#6366F1', '#8B5CF6', '#EC4899']; const getRandomColor = () => AVATAR_COLORS[Math.floor(Math.random() * AVATAR_COLORS.length)]; // --- Main Component --- export default function App() { const [user, setUser] = useState(null); // Auth user const [userProfile, setUserProfile] = useState(null); // Firestore profile const [view, setView] = useState('loading'); // loading, auth, home, chat const [currentRoom, setCurrentRoom] = useState(null); const [rooms, setRooms] = useState([]); const [loading, setLoading] = useState(true); // 1. Auth & Initial Load useEffect(() => { const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (err) { console.error("Auth error:", err); } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => { if (firebaseUser) { setUser(firebaseUser); // Check for existing profile in Firestore const userRef = doc(db, 'artifacts', appId, 'users', firebaseUser.uid, 'profile', 'data'); const userSnap = await getDoc(userRef); if (userSnap.exists()) { setUserProfile(userSnap.data()); setView('home'); } else { setView('auth'); // Need to register } } else { setUser(null); setView('loading'); } setLoading(false); }); return () => unsubscribe(); }, []); // 2. Fetch Rooms (Only when logged in) useEffect(() => { if (!user) return; const roomsRef = collection(db, 'artifacts', appId, 'public', 'data', 'rooms'); // Note: Simple query to avoid index requirements const q = query(roomsRef); const unsubscribe = onSnapshot(q, (snapshot) => { const roomData = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); // Client-side sort by createdAt (desc) roomData.sort((a, b) => (b.createdAt?.seconds || 0) - (a.createdAt?.seconds || 0)); setRooms(roomData); }, (err) => console.error("Room fetch error:", err)); return () => unsubscribe(); }, [user]); // --- Actions --- const handleRegister = async (username) => { if (!user) return; const color = getRandomColor(); const profileData = { uid: user.uid, username: username, color: color, createdAt: serverTimestamp() }; // Save public profile await setDoc(doc(db, 'artifacts', appId, 'users', user.uid, 'profile', 'data'), profileData); setUserProfile(profileData); setView('home'); }; const handleCreateRoom = async (name, desc) => { if (!user) return; await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'rooms'), { name, description: desc, createdBy: user.uid, creatorName: userProfile.username, createdAt: serverTimestamp(), memberCount: 0 }); }; const handleLogout = async () => { // In this demo environment, we just reload to reset anonymous session effectively window.location.reload(); }; // --- Rendering Views --- if (loading) { return (

Connecting to BloxChat Server...

); } return (
{view === 'auth' && } {view === 'home' && ( { setCurrentRoom(room); setView('chat'); }} onCreateRoom={handleCreateRoom} onLogout={handleLogout} /> )} {view === 'chat' && currentRoom && ( { setCurrentRoom(null); setView('home'); }} /> )}
); } // --- Sub-Components --- function AuthScreen({ onRegister }) { const [name, setName] = useState(''); const handleSubmit = (e) => { e.preventDefault(); if (name.trim().length > 0) onRegister(name.trim()); }; return (

BloxChat

Create an identity to start chatting.

setName(e.target.value)} className="w-full bg-gray-100 dark:bg-black/20 border-2 border-transparent focus:border-blue-500 rounded-xl px-4 py-3 text-lg font-bold outline-none transition-all" placeholder="CoolUser123" />
); } function Dashboard({ user, rooms, onJoinRoom, onCreateRoom, onLogout }) { const [showCreate, setShowCreate] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const filteredRooms = rooms.filter(r => r.name.toLowerCase().includes(searchTerm.toLowerCase()) ); return (
{/* Header */}

BloxChat

setSearchTerm(e.target.value)} className="w-full bg-white dark:bg-[#1e2024] border border-gray-200 dark:border-gray-800 rounded-full pl-10 pr-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none transition" />
{user.username}
{user.username[0].toUpperCase()}
{/* Room Grid */}

Active Experiences

{filteredRooms.length === 0 ? (

No rooms found. Be the first to create one!

) : ( filteredRooms.map(room => ( onJoinRoom(room)} /> )) )}
{/* Create Modal */} {showCreate && setShowCreate(false)} onCreate={onCreateRoom} />}
); } function RoomCard({ room, onClick }) { // Generate a consistent gradient based on room name const getGradient = (str) => { const sum = str.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); const gradients = [ 'from-emerald-400 to-cyan-500', 'from-blue-400 to-indigo-500', 'from-purple-400 to-pink-500', 'from-orange-400 to-red-500' ]; return gradients[sum % gradients.length]; }; return (
Live

{room.name}

{room.description}

By {room.creatorName || 'Unknown'}
); } function CreateRoomModal({ onClose, onCreate }) { const [name, setName] = useState(''); const [desc, setDesc] = useState(''); const handleSubmit = (e) => { e.preventDefault(); if(name && desc) { onCreate(name, desc); onClose(); } }; return (

Create New Experience

setName(e.target.value)} />