repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
Fastfood QR
stars
latest
clone command
git clone gitlawb://did:key:z6Mkfh4Y...QBEi/fastfood-qrgit clone gitlawb://did:key:z6Mkfh4Y.../fastfood-qr3042a875sync from playground22h ago| #1 | import { createContext, useContext, useState, useEffect, useMemo, useCallback, type ReactNode } from 'react'; |
| #2 | import type { Restaurant, Category, Product, CartItem } from './types'; |
| #3 | import { |
| #4 | initData, |
| #5 | loadRestaurants, saveRestaurants, |
| #6 | loadCategories, saveCategories as persistCategories, |
| #7 | loadProducts, saveProducts as persistProducts, |
| #8 | generateId, |
| #9 | } from './data'; |
| #10 | |
| #11 | interface AppState { |
| #12 | restaurants: Restaurant[]; |
| #13 | currentRestaurant: Restaurant | null; |
| #14 | categories: Category[]; |
| #15 | products: Product[]; |
| #16 | cart: CartItem[]; |
| #17 | isLoggedIn: boolean; |
| #18 | login: (email: string, password: string) => boolean; |
| #19 | logout: () => void; |
| #20 | setCurrentRestaurant: (r: Restaurant) => void; |
| #21 | addCategory: (name: string) => void; |
| #22 | updateCategory: (id: string, name: string) => void; |
| #23 | deleteCategory: (id: string) => void; |
| #24 | addProduct: (product: Omit<Product, 'id'>) => void; |
| #25 | updateProduct: (id: string, updates: Partial<Product>) => void; |
| #26 | deleteProduct: (id: string) => void; |
| #27 | updateRestaurant: (updates: Partial<Restaurant>) => void; |
| #28 | addToCart: (product: Product) => void; |
| #29 | removeFromCart: (productId: string) => void; |
| #30 | updateCartQuantity: (productId: string, quantity: number) => void; |
| #31 | clearCart: () => void; |
| #32 | } |
| #33 | |
| #34 | const AppContext = createContext<AppState | null>(null); |
| #35 | |
| #36 | export function useApp(): AppState { |
| #37 | const ctx = useContext(AppContext); |
| #38 | if (!ctx) throw new Error('useApp must be used within AppProvider'); |
| #39 | return ctx; |
| #40 | } |
| #41 | |
| #42 | export function AppProvider({ children }: { children: ReactNode }) { |
| #43 | const [restaurants, setRestaurants] = useState<Restaurant[]>([]); |
| #44 | const [currentRestaurant, setCurrentRestaurantState] = useState<Restaurant | null>(null); |
| #45 | const [categories, setCategories] = useState<Category[]>([]); |
| #46 | const [products, setProducts] = useState<Product[]>([]); |
| #47 | const [cart, setCart] = useState<CartItem[]>([]); |
| #48 | const [isLoggedIn, setIsLoggedIn] = useState(false); |
| #49 | |
| #50 | // Initialize data on mount |
| #51 | useEffect(() => { |
| #52 | initData(); |
| #53 | const allRestaurants = loadRestaurants(); |
| #54 | setRestaurants(allRestaurants); |
| #55 | }, []); |
| #56 | |
| #57 | // Load categories and products when current restaurant changes |
| #58 | useEffect(() => { |
| #59 | if (currentRestaurant) { |
| #60 | setCategories(loadCategories(currentRestaurant.id)); |
| #61 | setProducts(loadProducts(currentRestaurant.id)); |
| #62 | } |
| #63 | }, [currentRestaurant]); |
| #64 | |
| #65 | const setCurrentRestaurant = useCallback((r: Restaurant) => { |
| #66 | setCurrentRestaurantState(r); |
| #67 | }, []); |
| #68 | |
| #69 | const login = useCallback((email: string, password: string): boolean => { |
| #70 | const demoEmail = import.meta.env.APP_DEMO_EMAIL || 'demo@burgerhouse.com'; |
| #71 | const demoPassword = import.meta.env.APP_DEMO_PASSWORD || 'password123'; |
| #72 | const demoSlug = import.meta.env.APP_RESTAURANT_SLUG || 'burger-house'; |
| #73 | if (email === demoEmail && password === demoPassword) { |
| #74 | const allRestaurants = loadRestaurants(); |
| #75 | const burgerHouse = allRestaurants.find((r) => r.slug === demoSlug); |
| #76 | if (burgerHouse) { |
| #77 | setCurrentRestaurantState(burgerHouse); |
| #78 | setIsLoggedIn(true); |
| #79 | setCategories(loadCategories(burgerHouse.id)); |
| #80 | setProducts(loadProducts(burgerHouse.id)); |
| #81 | return true; |
| #82 | } |
| #83 | } |
| #84 | return false; |
| #85 | }, []); |
| #86 | |
| #87 | const logout = useCallback(() => { |
| #88 | setIsLoggedIn(false); |
| #89 | setCurrentRestaurantState(null); |
| #90 | setCategories([]); |
| #91 | setProducts([]); |
| #92 | setCart([]); |
| #93 | }, []); |
| #94 | |
| #95 | const addCategory = useCallback((name: string) => { |
| #96 | if (!currentRestaurant) return; |
| #97 | const newCat: Category = { |
| #98 | id: generateId(), |
| #99 | restaurantId: currentRestaurant.id, |
| #100 | name, |
| #101 | sortOrder: categories.length + 1, |
| #102 | }; |
| #103 | const updated = [...categories, newCat]; |
| #104 | setCategories(updated); |
| #105 | persistCategories(updated); |
| #106 | }, [currentRestaurant, categories]); |
| #107 | |
| #108 | const updateCategory = useCallback((id: string, name: string) => { |
| #109 | const updated = categories.map((c) => (c.id === id ? { ...c, name } : c)); |
| #110 | setCategories(updated); |
| #111 | persistCategories(updated); |
| #112 | }, [categories]); |
| #113 | |
| #114 | const deleteCategory = useCallback((id: string) => { |
| #115 | const updated = categories.filter((c) => c.id !== id); |
| #116 | setCategories(updated); |
| #117 | persistCategories(updated); |
| #118 | // Also remove products in this category |
| #119 | const updatedProducts = products.filter((p) => p.categoryId !== id); |
| #120 | setProducts(updatedProducts); |
| #121 | persistProducts(updatedProducts); |
| #122 | }, [categories, products]); |
| #123 | |
| #124 | const addProduct = useCallback((product: Omit<Product, 'id'>) => { |
| #125 | const newProduct: Product = { ...product, id: generateId() }; |
| #126 | const updated = [...products, newProduct]; |
| #127 | setProducts(updated); |
| #128 | persistProducts(updated); |
| #129 | }, [products]); |
| #130 | |
| #131 | const updateProduct = useCallback((id: string, updates: Partial<Product>) => { |
| #132 | const updated = products.map((p) => (p.id === id ? { ...p, ...updates } : p)); |
| #133 | setProducts(updated); |
| #134 | persistProducts(updated); |
| #135 | }, [products]); |
| #136 | |
| #137 | const deleteProduct = useCallback((id: string) => { |
| #138 | const updated = products.filter((p) => p.id !== id); |
| #139 | setProducts(updated); |
| #140 | persistProducts(updated); |
| #141 | setCart((prev) => prev.filter((item) => item.product.id !== id)); |
| #142 | }, [products]); |
| #143 | |
| #144 | const updateRestaurant = useCallback((updates: Partial<Restaurant>) => { |
| #145 | if (!currentRestaurant) return; |
| #146 | const updated = { ...currentRestaurant, ...updates }; |
| #147 | setCurrentRestaurantState(updated); |
| #148 | const allRestaurants = loadRestaurants().map((r) => |
| #149 | r.id === updated.id ? updated : r |
| #150 | ); |
| #151 | saveRestaurants(allRestaurants); |
| #152 | setRestaurants(allRestaurants); |
| #153 | }, [currentRestaurant]); |
| #154 | |
| #155 | const addToCart = useCallback((product: Product) => { |
| #156 | setCart((prev) => { |
| #157 | const existing = prev.find((item) => item.product.id === product.id); |
| #158 | if (existing) { |
| #159 | return prev.map((item) => |
| #160 | item.product.id === product.id |
| #161 | ? { ...item, quantity: item.quantity + 1 } |
| #162 | : item |
| #163 | ); |
| #164 | } |
| #165 | return [...prev, { product, quantity: 1 }]; |
| #166 | }); |
| #167 | }, []); |
| #168 | |
| #169 | const removeFromCart = useCallback((productId: string) => { |
| #170 | setCart((prev) => prev.filter((item) => item.product.id !== productId)); |
| #171 | }, []); |
| #172 | |
| #173 | const updateCartQuantity = useCallback((productId: string, quantity: number) => { |
| #174 | if (quantity <= 0) { |
| #175 | setCart((prev) => prev.filter((item) => item.product.id !== productId)); |
| #176 | } else { |
| #177 | setCart((prev) => |
| #178 | prev.map((item) => |
| #179 | item.product.id === productId ? { ...item, quantity } : item |
| #180 | ) |
| #181 | ); |
| #182 | } |
| #183 | }, []); |
| #184 | |
| #185 | const clearCart = useCallback(() => setCart([]), []); |
| #186 | |
| #187 | const value = useMemo<AppState>(() => ({ |
| #188 | restaurants, |
| #189 | currentRestaurant, |
| #190 | categories, |
| #191 | products, |
| #192 | cart, |
| #193 | isLoggedIn, |
| #194 | login, |
| #195 | logout, |
| #196 | setCurrentRestaurant, |
| #197 | addCategory, |
| #198 | updateCategory, |
| #199 | deleteCategory, |
| #200 | addProduct, |
| #201 | updateProduct, |
| #202 | deleteProduct, |
| #203 | updateRestaurant, |
| #204 | addToCart, |
| #205 | removeFromCart, |
| #206 | updateCartQuantity, |
| #207 | clearCart, |
| #208 | }), [ |
| #209 | restaurants, currentRestaurant, categories, products, cart, isLoggedIn, |
| #210 | login, logout, setCurrentRestaurant, |
| #211 | addCategory, updateCategory, deleteCategory, |
| #212 | addProduct, updateProduct, deleteProduct, |
| #213 | updateRestaurant, |
| #214 | addToCart, removeFromCart, updateCartQuantity, clearCart, |
| #215 | ]); |
| #216 | |
| #217 | return <AppContext.Provider value={value}>{children}</AppContext.Provider>; |
| #218 | } |
| #219 |