import React, { useState, useEffect, useRef } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from 'firebase/auth'; import { getFirestore, collection, onSnapshot, addDoc, deleteDoc, doc, setLogLevel } from 'firebase/firestore'; import { ArrowRight, Facebook, Instagram, MapPin, Plus, Trash2, X } from 'lucide-react'; // --- Firebase Configuration --- // These variables are provided by the environment. const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-paleteria-app'; // --- Main App Component --- export default function App() { const [db, setDb] = useState(null); const [auth, setAuth] = useState(null); const [userId, setUserId] = useState(null); const [isAuthReady, setIsAuthReady] = useState(false); // --- Component State --- const [inventory, setInventory] = useState([]); const [showAddForm, setShowAddForm] = useState(false); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); // --- Initialize Firebase and Authentication --- useEffect(() => { try { const app = initializeApp(firebaseConfig); const firestoreDb = getFirestore(app); const firebaseAuth = getAuth(app); setLogLevel('debug'); // For detailed console logs setDb(firestoreDb); setAuth(firebaseAuth); const unsubscribe = onAuthStateChanged(firebaseAuth, async (user) => { if (user) { setUserId(user.uid); } else { // If no user, try custom token or fall back to anonymous sign-in try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(firebaseAuth, __initial_auth_token); } else { await signInAnonymously(firebaseAuth); } } catch (authError) { console.error("Authentication Error:", authError); setError("Could not connect to authentication service."); } } setIsAuthReady(true); }); return () => unsubscribe(); } catch (e) { console.error("Firebase Initialization Error:", e); setError("Failed to initialize the application. Please check the configuration."); setIsLoading(false); } }, []); // --- Firestore Real-time Data Fetching --- useEffect(() => { if (isAuthReady && db && userId) { setIsLoading(true); const productsCollectionPath = `artifacts/${appId}/users/${userId}/products`; const productsCollection = collection(db, productsCollectionPath); const unsubscribe = onSnapshot(productsCollection, (snapshot) => { const productsData = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setInventory(productsData); setIsLoading(false); }, (err) => { console.error("Firestore Snapshot Error:", err); setError("Failed to load inventory. Please try again later."); setIsLoading(false); }); return () => unsubscribe(); } else if (isAuthReady && !userId) { // Handle case where authentication is ready but no user is signed in setIsLoading(false); setError("Authentication failed. Inventory cannot be loaded."); } }, [isAuthReady, db, userId]); // --- Event Handlers --- const handleAddItem = async (item) => { if (!db || !userId) return; try { const productsCollectionPath = `artifacts/${appId}/users/${userId}/products`; await addDoc(collection(db, productsCollectionPath), item); setShowAddForm(false); } catch (e) { console.error("Error adding document: ", e); setError("Failed to add item."); } }; const handleDeleteItem = async (id) => { if (!db || !userId) return; // Using a custom modal for confirmation would be better, but window.confirm is used for simplicity. // In a real app, replace this with a UI component to avoid browser blocking dialogs. if (window.confirm("Are you sure you want to delete this item?")) { try { const productDocPath = `artifacts/${appId}/users/${userId}/products/${id}`; await deleteDoc(doc(db, productDocPath)); } catch (e) { console.error("Error deleting document: ", e); setError("Failed to delete item."); } } }; return (
{/* --- Header --- */}
{/* --- Hero Section --- */} {/* --- Main Content --- */}
{/* --- Inventory Section --- */} setShowAddForm(true)} isLoading={isLoading} error={error} /> {/* --- Location Section --- */}
{/* --- Footer --- */}
); } // --- Sub-components --- const Header = () => (
Frosty Paleteria
); const Hero = () => (

Cool, Refreshing, Authentic

Experience the best paletas, ice cream, and aguas frescas in town.

View Our Menu
); const InventorySection = ({ inventory, onDeleteItem, onShowAddForm, isLoading, error }) => (

Nuestro MenĂș

Handcrafted with the finest ingredients.

{error &&
{error}
} {isLoading ? (

Loading Inventory...

) : inventory.length === 0 && !error ? (

Your inventory is empty.

Click "Add Item" to build your menu!

) : (
{inventory.map(item => ( onDeleteItem(item.id)} /> ))}
)}
); const ProductCard = ({ item, onDelete }) => (
{item.name} { e.target.onerror = null; e.target.src='https://placehold.co/600x400/e74c3c/ffffff?text=Error'; }} />

{item.name}

{item.description}

${parseFloat(item.price).toFixed(2)}
); const LocationSection = () => (

VisĂ­tanos

We are waiting for you!

Our Location

123 Calle del Sabor

Frutaville, TX 75001

Hours

Monday - Saturday: 9:00 AM - 8:00 PM

Sunday: 10:00 AM - 6:00 PM

Google Maps will be here

); const Footer = () => ( ); const AddProductModal = ({ onClose, onAddItem }) => { const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [price, setPrice] = useState(''); const [imageUrl, setImageUrl] = useState(''); const modalRef = useRef(); const handleSubmit = (e) => { e.preventDefault(); if (!name || !price) { // A simple validation, ideally should be a more user-friendly notification return; } onAddItem({ name, description, price, imageUrl }); }; // Close modal on outside click useEffect(() => { const handleClickOutside = (event) => { if (modalRef.current && !modalRef.current.contains(event.target)) { onClose(); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [onClose]); return (

Add New Item

setName(e.target.value)} className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" required />
setPrice(e.target.value)} step="0.01" className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" required />
setImageUrl(e.target.value)} className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" />
); };