import React, { useState, useEffect, createContext, useContext } from 'react';
import { initializeApp } from 'firebase/app';
import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth';
import { getFirestore, collection, query, onSnapshot, doc, setDoc, updateDoc, deleteDoc, getDoc, addDoc, where, getDocs } from 'firebase/firestore';
// Firebase Context to provide db, auth, and userId to components
const FirebaseContext = createContext(null);
const App = () => {
const [db, setDb] = useState(null);
const [auth, setAuth] = useState(null);
const [userId, setUserId] = useState(null);
const [isAuthReady, setIsAuthReady] = useState(false);
// Initialize Firebase and set up auth listener
useEffect(() => {
try {
const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {};
const app = initializeApp(firebaseConfig);
const firestoreDb = getFirestore(app);
const firebaseAuth = getAuth(app);
setDb(firestoreDb);
setAuth(firebaseAuth);
const unsubscribe = onAuthStateChanged(firebaseAuth, async (user) => {
if (user) {
setUserId(user.uid);
} else {
// Sign in anonymously if no user is found
try {
if (typeof __initial_auth_token !== 'undefined') {
await signInWithCustomToken(firebaseAuth, __initial_auth_token);
} else {
await signInAnonymously(firebaseAuth);
}
} catch (error) {
console.error("Error signing in anonymously:", error);
}
}
setIsAuthReady(true); // Mark auth as ready after initial check
});
return () => unsubscribe();
} catch (error) {
console.error("Failed to initialize Firebase:", error);
}
}, []);
if (!isAuthReady) {
return (
);
}
return (
);
};
const Header = () => {
const { userId } = useContext(FirebaseContext);
return (
);
};
const Footer = () => {
return (
);
};
const MainContent = () => {
const [view, setView] = useState('products'); // 'products', 'cart', 'checkout'
const navigateTo = (newView) => {
setView(newView);
};
return (
{view === 'products' && }
{view === 'cart' && }
{view === 'checkout' && }
);
};
const ProductList = ({ navigateTo }) => {
const { db, userId } = useContext(FirebaseContext);
const [products, setProducts] = useState([]);
const [cartItems, setCartItems] = useState({}); // {productId: quantity}
const [message, setMessage] = useState('');
const [showModal, setShowModal] = useState(false);
// Fetch products from Firestore
useEffect(() => {
if (!db || !userId) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const productsCollectionRef = collection(db, `artifacts/${appId}/public/data/products`);
const q = query(productsCollectionRef);
const unsubscribe = onSnapshot(q, (snapshot) => {
const fetchedProducts = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
setProducts(fetchedProducts);
}, (error) => {
console.error("Error fetching products:", error);
setMessage("Error loading products.");
setShowModal(true);
});
return () => unsubscribe();
}, [db, userId]);
// Fetch cart items from Firestore
useEffect(() => {
if (!db || !userId) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const cartDocRef = doc(db, `artifacts/${appId}/users/${userId}/cart/current`);
const unsubscribe = onSnapshot(cartDocRef, (docSnap) => {
if (docSnap.exists()) {
const data = docSnap.data();
// Ensure data.items is an object, default to empty if not
setCartItems(data.items || {});
} else {
setCartItems({});
}
}, (error) => {
console.error("Error fetching cart:", error);
setMessage("Error loading cart.");
setShowModal(true);
});
return () => unsubscribe();
}, [db, userId]);
const addToCart = async (product) => {
if (!db || !userId) {
setMessage("Please wait for authentication to complete.");
setShowModal(true);
return;
}
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const cartDocRef = doc(db, `artifacts/${appId}/users/${userId}/cart/current`);
try {
const newQuantity = (cartItems[product.id] || 0) + 1;
const updatedCartItems = {
...cartItems,
[product.id]: newQuantity
};
await setDoc(cartDocRef, { items: updatedCartItems }, { merge: true });
setMessage(`${product.name} added to cart!`);
setShowModal(true);
} catch (error) {
console.error("Error adding to cart:", error);
setMessage("Failed to add to cart.");
setShowModal(true);
}
};
// Function to seed initial products (run once for testing)
const seedProducts = async () => {
if (!db) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const productsCollectionRef = collection(db, `artifacts/${appId}/public/data/products`);
const initialProducts = [
{ name: "Wireless Headphones", price: 99.99, description: "High-fidelity sound with noise cancellation.", imageUrl: "https://placehold.co/300x200/FFD700/000000?text=Headphones" },
{ name: "Smartwatch", price: 199.99, description: "Track your fitness and receive notifications.", imageUrl: "https://placehold.co/300x200/ADD8E6/000000?text=Smartwatch" },
{ name: "Portable Bluetooth Speaker", price: 49.99, description: "Powerful sound in a compact design.", imageUrl: "https://placehold.co/300x200/90EE90/000000?text=Speaker" },
{ name: "Gaming Mouse", price: 59.99, description: "Precision and speed for serious gamers.", imageUrl: "https://placehold.co/300x200/FFA07A/000000?text=Gaming+Mouse" },
];
try {
for (const product of initialProducts) {
// Check if product already exists to avoid duplicates
const q = query(productsCollectionRef, where("name", "==", product.name));
const querySnapshot = await getDocs(q);
if (querySnapshot.empty) {
await addDoc(productsCollectionRef, product);
}
}
setMessage("Products seeded successfully!");
setShowModal(true);
} catch (error) {
console.error("Error seeding products:", error);
setMessage("Failed to seed products.");
setShowModal(true);
}
};
return (
Our Products
{products.length === 0 ? (
No products available.
) : (
products.map((product) => (

{ e.target.onerror = null; e.target.src = `https://placehold.co/300x200/CCCCCC/000000?text=Image+Error`; }}
/>
{product.name}
{product.description}
${product.price.toFixed(2)}
))
)}
{showModal && (
setShowModal(false)} />
)}
);
};
const ShoppingCart = ({ navigateTo }) => {
const { db, userId } = useContext(FirebaseContext);
const [cartItems, setCartItems] = useState({}); // {productId: quantity}
const [products, setProducts] = useState([]); // To get product details
const [message, setMessage] = useState('');
const [showModal, setShowModal] = useState(false);
// Fetch products (needed to display product names/prices in cart)
useEffect(() => {
if (!db || !userId) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const productsCollectionRef = collection(db, `artifacts/${appId}/public/data/products`);
const unsubscribe = onSnapshot(productsCollectionRef, (snapshot) => {
const fetchedProducts = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
setProducts(fetchedProducts);
}, (error) => {
console.error("Error fetching products for cart:", error);
setMessage("Error loading product details for cart.");
setShowModal(true);
});
return () => unsubscribe();
}, [db, userId]);
// Fetch cart items
useEffect(() => {
if (!db || !userId) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const cartDocRef = doc(db, `artifacts/${appId}/users/${userId}/cart/current`);
const unsubscribe = onSnapshot(cartDocRef, (docSnap) => {
if (docSnap.exists()) {
setCartItems(docSnap.data().items || {});
} else {
setCartItems({});
}
}, (error) => {
console.error("Error fetching cart:", error);
setMessage("Error loading cart.");
setShowModal(true);
});
return () => unsubscribe();
}, [db, userId]);
const updateCartItemQuantity = async (productId, newQuantity) => {
if (!db || !userId) {
setMessage("Please wait for authentication to complete.");
setShowModal(true);
return;
}
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const cartDocRef = doc(db, `artifacts/${appId}/users/${userId}/cart/current`);
try {
const updatedCartItems = { ...cartItems };
if (newQuantity <= 0) {
delete updatedCartItems[productId];
} else {
updatedCartItems[productId] = newQuantity;
}
await setDoc(cartDocRef, { items: updatedCartItems }, { merge: true });
} catch (error) {
console.error("Error updating cart quantity:", error);
setMessage("Failed to update cart quantity.");
setShowModal(true);
}
};
const getProductDetails = (productId) => {
return products.find(p => p.id === productId);
};
const calculateTotal = () => {
let total = 0;
for (const productId in cartItems) {
const product = getProductDetails(productId);
if (product) {
total += product.price * cartItems[productId];
}
}
return total;
};
const totalItems = Object.values(cartItems).reduce((sum, qty) => sum + qty, 0);
return (
Your Shopping Cart
{totalItems === 0 ? (
Your cart is empty.
) : (
<>
{Object.entries(cartItems).map(([productId, quantity]) => {
const product = getProductDetails(productId);
if (!product) return null; // Product might not be loaded yet or deleted
return (

{ e.target.onerror = null; e.target.src = `https://placehold.co/80x80/CCCCCC/000000?text=Image`; }}
/>
{product.name}
${product.price.toFixed(2)}
{quantity}
${(product.price * quantity).toFixed(2)}
);
})}
Total:
${calculateTotal().toFixed(2)}
>
)}
{showModal && (
setShowModal(false)} />
)}
);
};
const Checkout = ({ navigateTo }) => {
const { db, userId } = useContext(FirebaseContext);
const [cartItems, setCartItems] = useState({});
const [products, setProducts] = useState([]);
const [message, setMessage] = useState('');
const [showModal, setShowModal] = useState(false);
// Fetch products
useEffect(() => {
if (!db || !userId) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const productsCollectionRef = collection(db, `artifacts/${appId}/public/data/products`);
const unsubscribe = onSnapshot(productsCollectionRef, (snapshot) => {
const fetchedProducts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
setProducts(fetchedProducts);
});
return () => unsubscribe();
}, [db, userId]);
// Fetch cart items
useEffect(() => {
if (!db || !userId) return;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const cartDocRef = doc(db, `artifacts/${appId}/users/${userId}/cart/current`);
const unsubscribe = onSnapshot(cartDocRef, (docSnap) => {
if (docSnap.exists()) {
setCartItems(docSnap.data().items || {});
} else {
setCartItems({});
}
});
return () => unsubscribe();
}, [db, userId]);
const getProductDetails = (productId) => {
return products.find(p => p.id === productId);
};
const calculateTotal = () => {
let total = 0;
for (const productId in cartItems) {
const product = getProductDetails(productId);
if (product) {
total += product.price * cartItems[productId];
}
}
return total;
};
const handlePlaceOrder = async () => {
if (!db || !userId) {
setMessage("Please wait for authentication to complete.");
setShowModal(true);
return;
}
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const ordersCollectionRef = collection(db, `artifacts/${appId}/users/${userId}/orders`);
const cartDocRef = doc(db, `artifacts/${appId}/users/${userId}/cart/current`);
if (Object.keys(cartItems).length === 0) {
setMessage("Your cart is empty. Please add items before checking out.");
setShowModal(true);
return;
}
try {
const orderDetails = {
userId: userId,
items: cartItems,
total: calculateTotal(),
orderDate: new Date().toISOString(),
status: 'Pending',
};
await addDoc(ordersCollectionRef, orderDetails); // Add order to orders collection
await deleteDoc(cartDocRef); // Clear the cart
setMessage("Order placed successfully! Thank you for your purchase.");
setShowModal(true);
// Optionally navigate to an order confirmation page or products page after a delay
setTimeout(() => navigateTo('products'), 2000);
} catch (error) {
console.error("Error placing order:", error);
setMessage("Failed to place order. Please try again.");
setShowModal(true);
}
};
return (
Checkout
Order Summary
{Object.keys(cartItems).length === 0 ? (
No items in cart for checkout.
) : (
{Object.entries(cartItems).map(([productId, quantity]) => {
const product = getProductDetails(productId);
if (!product) return null;
return (
-
{product.name} x {quantity}
${(product.price * quantity).toFixed(2)}
);
})}
)}
Total:
${calculateTotal().toFixed(2)}
{showModal && (
setShowModal(false)} />
)}
);
};
const MessageModal = ({ message, onClose }) => {
return (
);
};
export default App;