diff options
author | 2025-04-29 10:47:43 +0530 | |
---|---|---|
committer | 2025-04-29 10:47:43 +0530 | |
commit | a2e0a65b2599267efe94d665d6305f59b225bbd5 (patch) | |
tree | e2cef2031e3f7655e0c5f419020a3f1064c3b7b8 /frontend/src/context | |
parent | 570bf0f3f065d583d6f94ecfc61aae93ba3e43de (diff) | |
download | restaurant-master.tar.gz restaurant-master.tar.bz2 restaurant-master.zip |
Diffstat (limited to 'frontend/src/context')
-rw-r--r-- | frontend/src/context/auth-context.js | 126 | ||||
-rw-r--r-- | frontend/src/context/cart-context.js | 120 | ||||
-rw-r--r-- | frontend/src/context/theme-context.js | 54 |
3 files changed, 300 insertions, 0 deletions
diff --git a/frontend/src/context/auth-context.js b/frontend/src/context/auth-context.js new file mode 100644 index 0000000..d67b345 --- /dev/null +++ b/frontend/src/context/auth-context.js @@ -0,0 +1,126 @@ +import { createContext, useContext, useState, useEffect } from 'react'; +import { useRouter } from 'next/navigation'; +import { Sonner, toast } from 'sonner'; +import * as authApi from '@/lib/api/auth'; + +// Create auth context +const AuthContext = createContext(); + +export const AuthProvider = ({ children }) => { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + const router = useRouter(); + + // Check if user is logged in on initial load + useEffect(() => { + const checkAuth = async () => { + try { + const currentUser = authApi.getCurrentUser(); + if (currentUser) { + setUser(currentUser); + } + } catch (error) { + console.error('Authentication check failed:', error); + } finally { + setLoading(false); + } + }; + + checkAuth(); + }, []); + + // Login user + const login = async (credentials) => { + try { + setLoading(true); + const data = await authApi.login(credentials); + setUser(data.user); + + toast.success('Login successful!'); + + // Redirect based on role + if (data.user.role === 'admin') { + router.push('/admin'); + } else if (data.user.role === 'staff') { + router.push('/staff'); + } else { + router.push('/'); + } + + return data; + } catch (error) { + toast.error(error.message || 'Login failed'); + throw error; + } finally { + setLoading(false); + } + }; + + // Register user + const register = async (userData) => { + try { + setLoading(true); + const data = await authApi.register(userData); + setUser(data.user); + + toast.success('Registration successful!'); + router.push('/'); + + return data; + } catch (error) { + toast.error(error.message || 'Registration failed'); + throw error; + } finally { + setLoading(false); + } + }; + + // Logout user + const logout = () => { + authApi.logout(); + setUser(null); + router.push('/login'); + toast.success('Logged out successfully'); + }; + + // Get user profile + const getProfile = async () => { + try { + setLoading(true); + const data = await authApi.getProfile(); + setUser(data.user); + return data.user; + } catch (error) { + console.error('Failed to get user profile:', error); + throw error; + } finally { + setLoading(false); + } + }; + + return ( + <AuthContext.Provider + value={{ + user, + loading, + isAuthenticated: !!user, + login, + register, + logout, + getProfile, + }} + > + {children} + <Sonner position="top-right" /> + </AuthContext.Provider> + ); +}; + +// Custom hook to use auth context +export const useAuth = () => { + const context = useContext(AuthContext); + if (!context) { + throw new Error('useAuth must be used within an AuthProvider'); + } + return context; +};
\ No newline at end of file diff --git a/frontend/src/context/cart-context.js b/frontend/src/context/cart-context.js new file mode 100644 index 0000000..8d173b7 --- /dev/null +++ b/frontend/src/context/cart-context.js @@ -0,0 +1,120 @@ +import { createContext, useContext, useState, useEffect } from 'react'; +import { toast } from 'sonner'; + +const CartContext = createContext(); + +export const CartProvider = ({ children }) => { + const [items, setItems] = useState([]); + const [total, setTotal] = useState(0); + + // Load cart from localStorage on initial load + useEffect(() => { + if (typeof window !== 'undefined') { + const savedCart = localStorage.getItem('cart'); + if (savedCart) { + try { + const parsedCart = JSON.parse(savedCart); + setItems(parsedCart); + calculateTotal(parsedCart); + } catch (error) { + console.error('Failed to parse cart from localStorage:', error); + } + } + } + }, []); + + // Save cart to localStorage whenever it changes + useEffect(() => { + if (typeof window !== 'undefined') { + localStorage.setItem('cart', JSON.stringify(items)); + calculateTotal(items); + } + }, [items]); + + // Calculate total price + const calculateTotal = (cartItems) => { + const sum = cartItems.reduce((acc, item) => acc + item.price * item.quantity, 0); + setTotal(sum); + }; + + // Add item to cart + const addItem = (item) => { + setItems((prevItems) => { + // Check if item already exists in cart + const existingItemIndex = prevItems.findIndex((i) => i.id === item.id); + + if (existingItemIndex !== -1) { + // Item exists, update quantity + const updatedItems = [...prevItems]; + updatedItems[existingItemIndex] = { + ...updatedItems[existingItemIndex], + quantity: updatedItems[existingItemIndex].quantity + 1, + }; + toast.success(`Added another ${item.name} to your cart`); + return updatedItems; + } else { + // Item doesn't exist, add new item + toast.success(`Added ${item.name} to your cart`); + return [...prevItems, { ...item, quantity: 1 }]; + } + }); + }; + + // Remove item from cart + const removeItem = (itemId) => { + setItems((prevItems) => { + const itemToRemove = prevItems.find((item) => item.id === itemId); + if (itemToRemove) { + toast.success(`Removed ${itemToRemove.name} from your cart`); + } + return prevItems.filter((item) => item.id !== itemId); + }); + }; + + // Update item quantity + const updateQuantity = (itemId, quantity) => { + if (quantity < 1) return; + + setItems((prevItems) => + prevItems.map((item) => + item.id === itemId ? { ...item, quantity } : item + ) + ); + }; + + // Clear cart + const clearCart = () => { + setItems([]); + toast.success('Cart cleared'); + }; + + // Get cart item count + const getItemCount = () => { + return items.reduce((count, item) => count + item.quantity, 0); + }; + + return ( + <CartContext.Provider + value={{ + items, + total, + addItem, + removeItem, + updateQuantity, + clearCart, + getItemCount, + }} + > + {children} + </CartContext.Provider> + ); +}; + +// Custom hook to use cart context +export const useCart = () => { + const context = useContext(CartContext); + if (!context) { + throw new Error('useCart must be used within a CartProvider'); + } + return context; +};
\ No newline at end of file diff --git a/frontend/src/context/theme-context.js b/frontend/src/context/theme-context.js new file mode 100644 index 0000000..655d1b9 --- /dev/null +++ b/frontend/src/context/theme-context.js @@ -0,0 +1,54 @@ +import { createContext, useContext, useState, useEffect } from 'react'; + +const ThemeContext = createContext(); + +export const ThemeProvider = ({ children }) => { + const [theme, setTheme] = useState('light'); + + // Initialize theme from localStorage or system preference + useEffect(() => { + // Check if we're in a browser environment + if (typeof window !== 'undefined') { + const savedTheme = localStorage.getItem('theme'); + + // Use saved theme or system preference + if (savedTheme) { + setTheme(savedTheme); + document.documentElement.classList.toggle('dark', savedTheme === 'dark'); + } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + setTheme('dark'); + document.documentElement.classList.add('dark'); + } + } + }, []); + + // Update theme in localStorage and toggle dark class + const updateTheme = (newTheme) => { + if (typeof window !== 'undefined') { + localStorage.setItem('theme', newTheme); + document.documentElement.classList.toggle('dark', newTheme === 'dark'); + setTheme(newTheme); + } + }; + + // Toggle between light and dark theme + const toggleTheme = () => { + const newTheme = theme === 'light' ? 'dark' : 'light'; + updateTheme(newTheme); + }; + + return ( + <ThemeContext.Provider value={{ theme, toggleTheme }}> + {children} + </ThemeContext.Provider> + ); +}; + +// Custom hook to use theme context +export const useTheme = () => { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +};
\ No newline at end of file |