diff --git a/backend/app/routes/api.py b/backend/app/routes/api.py
index bfa1cda..feb26ba 100644
--- a/backend/app/routes/api.py
+++ b/backend/app/routes/api.py
@@ -1,3 +1,5 @@
+import time
+
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token, create_refresh_token
from app import db
@@ -76,7 +78,12 @@ def get_current_user():
@api_bp.route("/products", methods=["GET"])
def get_products():
"""Get all products"""
+
+
+ # time.sleep(5) # This adds a 5 second delay
+
products = Product.query.filter_by(is_active=True).all()
+
return jsonify([product.to_dict() for product in products]), 200
diff --git a/docs/usage_rules_frontend.md b/docs/usage_rules_frontend.md
index 824fbef..4d23693 100644
--- a/docs/usage_rules_frontend.md
+++ b/docs/usage_rules_frontend.md
@@ -54,6 +54,145 @@ function Products() {
}
```
+### API Integration with Loaders and Toasts
+- **ALWAYS** create custom hooks for API operations that integrate loader and toast logic
+- **NEVER** handle errors in components when the hook already shows toasts
+- Custom hooks should use `useLoader` and `useToast` for consistent UX
+- Hooks should return data, refetch function, and optionally error state for debugging
+- Components should NOT display error UI when toasts are already shown
+
+```jsx
+// ✅ CORRECT - Custom hook with loader and toast integration
+import { useState, useEffect } from "react"
+import useApi from "./useApi"
+import { useLoader } from "../context/loaders/useLoader"
+import { useToast } from "../context/toasts/useToast"
+
+function useProducts() {
+ const [products, setProducts] = useState([])
+ const [error, setError] = useState(null)
+
+ const { getProducts } = useApi()
+ const { withLoader } = useLoader()
+ const { addNotification } = useToast()
+
+ const fetchProducts = async () => {
+ try {
+ setError(null)
+
+ // Use withLoader to show loading state
+ const data = await withLoader(
+ () => getProducts(),
+ 'Loading products...'
+ )
+
+ setProducts(data)
+
+ // Show success toast
+ addNotification({
+ type: 'success',
+ title: 'Products Loaded',
+ message: `Successfully loaded ${data.length} products.`,
+ duration: 3000,
+ })
+
+ return data
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to load products'
+ setError(errorMessage)
+
+ // Show error toast
+ addNotification({
+ type: 'error',
+ title: 'Error Loading Products',
+ message: errorMessage,
+ duration: 5000,
+ })
+
+ return []
+ }
+ }
+
+ useEffect(() => {
+ fetchProducts()
+ }, [])
+
+ return {
+ products,
+ error, // For debugging, not for UI display
+ loading: false, // Loading is handled by global loader
+ refetch: fetchProducts,
+ }
+}
+
+export default useProducts
+```
+
+```jsx
+// ✅ CORRECT - Component using the custom hook
+function Products() {
+ const { products, refetch } = useProducts()
+
+ // Note: No error UI here - toast is already shown by the hook
+
+ return (
+
+
Products
+
+ {products.map(product => (
+
+ ))}
+
+ )
+}
+```
+
+```jsx
+// ❌ WRONG - Handling errors in component when toast already shown
+function Products() {
+ const { products, error, refetch } = useProducts()
+
+ // BAD PRACTICE: This duplicates the error message already shown in toast
+ if (error) {
+ return (
+
+
Failed to load products
+
+
+ )
+ }
+
+ return (
+
+ {products.map(product => (
+
+ ))}
+
+ )
+}
+```
+
+**Why this is bad practice:**
+1. **Duplicate UI**: Users see the same error message twice (toast + component error UI)
+2. **Inconsistent UX**: Some operations show toasts, others show component error messages
+3. **Confusing Experience**: Users don't know which error message to act on
+4. **Redundant Code**: You're writing error handling twice (in hook and component)
+5. **Maintenance Issue**: If you change error handling in hook, component UI doesn't update
+
+**The error state in hooks is for:**
+- Debugging purposes
+- Conditional rendering based on error type (rare cases)
+- Logging or analytics
+- NOT for displaying error UI to users
+
+**Benefits of this pattern:**
+1. **Consistent UX**: All errors shown via toasts in the same place (top-right)
+2. **Separation of Concerns**: Hook handles data fetching, component handles rendering
+3. **Global Loading**: Loader covers entire app, preventing double-submissions
+4. **Auto-Cleanup**: `withLoader` ensures loader is hidden even on errors
+5. **Clean Components**: Components focus on displaying data, not handling errors
+```
+
## Code Style
### Formatting
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 5d0428d..a539c36 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -3,6 +3,8 @@ import { ModalProvider } from './context/modals/useModal'
import { ModalRoot } from './context/modals/ModalRoot'
import { ToastProvider } from './context/toasts/useToast'
import { ToastRoot } from './context/toasts/ToastRoot'
+import { LoaderProvider } from './context/loaders/useLoader'
+import { LoaderRoot } from './context/loaders/LoaderRoot'
import Cart from './pages/Cart'
import { Navbar } from './components/Navbar'
import { Home } from './pages/Home'
@@ -13,25 +15,29 @@ import { Orders } from './pages/Orders'
const App = () => {
return (
-
-
-