import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, doc, setDoc, onSnapshot, collection, query, getDocs } from 'firebase/firestore'; import { ShoppingCart, ShoppingBag, Trash2, Loader, X, ServerCrash } from 'lucide-react'; // --- Global Variables (Provided by Canvas Environment) --- // We must use these global variables for Firebase configuration and authentication. const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : null; const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-ecommerce-app'; // --- Utility Functions --- /** * Initializes Firebase, authenticates the user, and sets up auth state listener. * @param {function} setDb - React setter for Firestore instance. * @param {function} setAuth - React setter for Auth instance. * @param {function} setUserId - React setter for user ID. * @param {function} setIsAuthReady - React setter for auth readiness state. */ const initializeFirebase = async (setDb, setAuth, setUserId, setIsAuthReady) => { try { if (!firebaseConfig) { console.error("Firebase configuration is missing."); return; } const app = initializeApp(firebaseConfig); const dbInstance = getFirestore(app); const authInstance = getAuth(app); setDb(dbInstance); setAuth(authInstance); // 1. Initial Authentication if (initialAuthToken) { await signInWithCustomToken(authInstance, initialAuthToken); } else { await signInAnonymously(authInstance); } // 2. Auth State Listener const unsubscribe = onAuthStateChanged(authInstance, (user) => { const currentUserId = user?.uid || crypto.randomUUID(); setUserId(currentUserId); setIsAuthReady(true); console.log("Firebase Auth State Changed. User ID:", currentUserId); }); return () => unsubscribe(); } catch (error) { console.error("Error initializing Firebase:", error); setIsAuthReady(true); // Still mark as ready even on failure to avoid infinite loading } }; /** * Ensures the public product collection has initial data. * @param {object} db - Firestore instance. */ const initializeProducts = async (db) => { const collectionPath = `/artifacts/${appId}/public/data/products`; const productsRef = collection(db, collectionPath); const snapshot = await getDocs(productsRef); if (snapshot.empty) { console.log("Product collection empty. Seeding initial data."); const initialProducts = [ { id: "p101", name: "Laptop Gaming Pro", price: 12500, description: "Powerful performance for competitive gaming.", imageUrl: "https://placehold.co/150x150/007AFF/ffffff?text=Laptop", category: "Electronics" }, { id: "p102", name: "Wireless Headset X", price: 799, description: "Noise-cancelling, all-day comfort.", imageUrl: "https://placehold.co/150x150/FF3B30/ffffff?text=Headset", category: "Accessories" }, { id: "p103", name: "Mechanical Keyboard", price: 450, description: "Tactile keys for fast typing.", imageUrl: "https://placehold.co/150x150/FF9500/ffffff?text=Keyboard", category: "Accessories" }, { id: "p104", name: "Smartwatch Elite", price: 2100, description: "Health tracking and notifications.", imageUrl: "https://placehold.co/150x150/34C759/ffffff?text=Watch", category: "Wearables" }, { id: "p105", name: "Portable Speaker", price: 550, description: "Deep bass and 10 hours battery life.", imageUrl: "https://placehold.co/150x150/007AFF/ffffff?text=Speaker", category: "Audio" }, ]; for (const product of initialProducts) { const productDocRef = doc(db, collectionPath, product.id); await setDoc(productDocRef, product); } } }; // --- Components --- /** * Product Card component to display product information and add to cart action. */ const ProductCard = React.memo(({ product, addItemToCart }) => (
{product.name} { e.target.onerror = null; e.target.src = "https://placehold.co/150x150/A2A2A7/ffffff?text=Image+Error"; }} />

{product.name}

{product.description}

{product.price.toLocaleString('en-US', { style: 'currency', currency: 'MAD', minimumFractionDigits: 0 })}
)); /** * Sidebar component for the Shopping Cart. */ const Cart = React.memo(({ cartItems, removeItemFromCart, isCartOpen, toggleCart }) => { const cartTotal = useMemo(() => cartItems.reduce((acc, item) => acc + item.price * item.quantity, 0), [cartItems] ); return (

عربة التسوق

{cartItems.length === 0 ? (

العربة فارغة حالياً.

أضف بعض المنتجات لتبدأ التسوق.

) : (
{cartItems.map(item => (
{item.name}

{item.name}

{item.quantity} x {item.price.toLocaleString('en-US', { style: 'currency', currency: 'MAD', minimumFractionDigits: 0 })}

))}
)}
المجموع الكلي: {cartTotal.toLocaleString('en-US', { style: 'currency', currency: 'MAD', minimumFractionDigits: 0 })}

هذا نموذج، عملية الدفع غير فعالة.

); }); // --- Main App Component --- const App = () => { // Firebase State const [db, setDb] = useState(null); const [auth, setAuth] = useState(null); const [userId, setUserId] = useState(null); const [isAuthReady, setIsAuthReady] = useState(false); // Application State const [products, setProducts] = useState([]); const [cartItems, setCartItems] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isCartOpen, setIsCartOpen] = useState(false); const [error, setError] = useState(null); // 1. Firebase Initialization Effect useEffect(() => { initializeFirebase(setDb, setAuth, setUserId, setIsAuthReady); }, []); // 2. Data Fetching and Initialization Effect useEffect(() => { if (!db || !isAuthReady) return; const fetchProducts = async () => { try { await initializeProducts(db); // Seed data if needed const collectionPath = `/artifacts/${appId}/public/data/products`; const productsQuery = query(collection(db, collectionPath)); // Setup real-time listener for products const unsubscribe = onSnapshot(productsQuery, (snapshot) => { const fetchedProducts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data(), price: Number(doc.data().price) || 0 // Ensure price is a number })); setProducts(fetchedProducts); setIsLoading(false); }, (err) => { console.error("Firestore listen failed:", err); setError("حدث خطأ أثناء تحميل المنتجات من قاعدة البيانات."); setIsLoading(false); }); return () => unsubscribe(); } catch (e) { console.error("Failed to initialize or fetch data:", e); setError("فشل في تهيئة قاعدة البيانات. تحقق من الإعدادات."); setIsLoading(false); } }; fetchProducts(); }, [db, isAuthReady]); // Re-run when DB is ready // --- Cart Management Logic --- const addItemToCart = useCallback((product) => { setCartItems(prevItems => { const existingItem = prevItems.find(item => item.id === product.id); if (existingItem) { return prevItems.map(item => item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item ); } else { return [...prevItems, { ...product, quantity: 1 }]; } }); // Open cart automatically when an item is added if (!isCartOpen) setIsCartOpen(true); }, [isCartOpen]); const removeItemFromCart = useCallback((productId) => { setCartItems(prevItems => prevItems.filter(item => item.id !== productId)); }, []); const toggleCart = useCallback(() => { setIsCartOpen(prev => !prev); }, []); // --- Rendering Logic --- if (error) { return (

خطأ فادح في النظام

{error}

المرجو مراجعة الـ Console للتفاصيل التقنية.

); } return (
{/* Overlay for when cart is open */} {isCartOpen &&
} {/* Header */}
متجرنا (E-Store)
ID المستخدم: {userId || 'جار التحميل...'}
{/* Main Content (Product Grid) */}

كتالوج المنتجات

{isLoading ? (

جاري تحميل المنتجات...

) : (
{products.map(product => ( ))}
)} {products.length === 0 && !isLoading && (

لا توجد منتجات حالياً. قد يكون النظام يعمل على تهيئة قاعدة البيانات.

)}
{/* Shopping Cart Sidebar */}
); }; export default App;