From 75437272dd1c4c2da5621d0b1081b2e27a73b116 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:04:07 +0000 Subject: [PATCH 1/3] Initial plan From 94301a2988a97154577d982532ee720bde8b8f3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:15:18 +0000 Subject: [PATCH 2/3] Add comprehensive frontend documentation Co-authored-by: webmaxru <1560278+webmaxru@users.noreply.github.com> --- docs/frontend/README.md | 68 +++ docs/frontend/api-integration.md | 787 +++++++++++++++++++++++++++++ docs/frontend/architecture.md | 386 ++++++++++++++ docs/frontend/code-organization.md | 777 ++++++++++++++++++++++++++++ docs/frontend/components.md | 614 ++++++++++++++++++++++ docs/frontend/setup.md | 493 ++++++++++++++++++ docs/frontend/styling.md | 719 ++++++++++++++++++++++++++ docs/frontend/testing.md | 719 ++++++++++++++++++++++++++ frontend/README.md | 183 +++++-- 9 files changed, 4695 insertions(+), 51 deletions(-) create mode 100644 docs/frontend/README.md create mode 100644 docs/frontend/api-integration.md create mode 100644 docs/frontend/architecture.md create mode 100644 docs/frontend/code-organization.md create mode 100644 docs/frontend/components.md create mode 100644 docs/frontend/setup.md create mode 100644 docs/frontend/styling.md create mode 100644 docs/frontend/testing.md diff --git a/docs/frontend/README.md b/docs/frontend/README.md new file mode 100644 index 0000000..31befa3 --- /dev/null +++ b/docs/frontend/README.md @@ -0,0 +1,68 @@ +# Frontend Documentation + +Welcome to the OctoCAT Supply Chain Management frontend documentation. This guide provides comprehensive information about the React-based frontend application. + +## Table of Contents + +1. [Architecture Overview](./architecture.md) - Component structure, state management, routing, and API integration patterns +2. [Setup and Development](./setup.md) - Prerequisites, environment configuration, and development workflow +3. [Component Documentation](./components.md) - Detailed documentation of key components, props, and usage examples +4. [Styling Guidelines](./styling.md) - Tailwind CSS conventions, theme system, and responsive design approach +5. [API Integration](./api-integration.md) - API client configuration, error handling, and authentication flow +6. [Testing](./testing.md) - Testing strategy, tools, and example patterns +7. [Code Organization](./code-organization.md) - Folder structure, naming conventions, and best practices + +## Quick Start + +```bash +# Install dependencies +npm install + +# Start development server +npm run dev + +# Build for production +npm run build + +# Run linter +npm run lint +``` + +## Technology Stack + +- **React 18+** - UI library +- **TypeScript** - Type-safe JavaScript +- **Vite** - Build tool and dev server +- **Tailwind CSS** - Utility-first CSS framework +- **React Router v7** - Client-side routing +- **React Query** - Server state management +- **Axios** - HTTP client + +## Key Features + +- 🎨 Dark/Light theme support with Context API +- πŸ” Authentication system with role-based access +- πŸ“± Fully responsive design +- πŸš€ Fast development with Vite HMR +- 🎯 Type-safe with TypeScript +- β™Ώ Accessibility-focused components + +## Project Overview + +The frontend is a single-page application (SPA) that provides a modern user interface for the OctoCAT Supply Chain Management System. It communicates with the backend REST API to manage products, orders, suppliers, and other supply chain entities. + +For overall system architecture, refer to the [main architecture documentation](../architecture.md). + +## Getting Help + +- Check the detailed documentation pages for specific topics +- Review component examples in the codebase +- See [troubleshooting section in setup.md](./setup.md#troubleshooting) + +## Contributing + +When adding new features or components: +1. Follow the established [code organization](./code-organization.md) patterns +2. Adhere to the [styling guidelines](./styling.md) +3. Update relevant documentation +4. Add appropriate tests (see [testing guide](./testing.md)) diff --git a/docs/frontend/api-integration.md b/docs/frontend/api-integration.md new file mode 100644 index 0000000..5c5de02 --- /dev/null +++ b/docs/frontend/api-integration.md @@ -0,0 +1,787 @@ +# API Integration + +This guide covers how the frontend integrates with the backend REST API, including configuration, error handling, and authentication patterns. + +## Table of Contents + +- [API Configuration](#api-configuration) +- [Making API Requests](#making-api-requests) +- [React Query Integration](#react-query-integration) +- [Error Handling](#error-handling) +- [Authentication Flow](#authentication-flow) +- [API Endpoints](#api-endpoints) +- [Request/Response Patterns](#requestresponse-patterns) +- [Best Practices](#best-practices) + +--- + +## API Configuration + +### Configuration File + +**Location:** `src/api/config.ts` + +This file handles API base URL detection and provides centralized endpoint definitions. + +### Base URL Detection Logic + +The API URL is determined in the following order: + +1. **Runtime Configuration** (highest priority) + - Checks `window.RUNTIME_CONFIG.API_URL` + - Useful for Docker/production deployments + +2. **GitHub Codespaces Detection** + - Auto-detects Codespace hostname patterns + - Maps to port 3000 on the same codespace + +3. **Local Development** (fallback) + - Uses `http://localhost:3000` + - Protocol matches frontend (http/https) + +### Configuration Code + +```typescript +const getBaseUrl = () => { + // Check runtime configuration + if (typeof window !== 'undefined' && window.RUNTIME_CONFIG?.API_URL) { + return window.RUNTIME_CONFIG.API_URL; + } + + // Detect protocol + const protocol = typeof window !== 'undefined' ? window.location.protocol : 'https:'; + const protocolToUse = protocol.includes('https') ? 'https' : 'http'; + + // Detect GitHub Codespaces + if (typeof window !== 'undefined') { + const host = window.location.hostname; + const codespacesMatch = + host.match(/^(.*)-(\d+)\.app\.github\.dev$/) || + host.match(/^(.*)-(\d+)\.githubpreview\.dev$/); + if (codespacesMatch) { + return `${protocolToUse}://${codespacesMatch[1]}-3000.app.github.dev`; + } + } + + // Default to localhost + return `${protocolToUse}://localhost:3000`; +}; + +export const API_BASE_URL = getBaseUrl(); +``` + +### Endpoint Definitions + +```typescript +export const api = { + baseURL: API_BASE_URL, + endpoints: { + products: '/api/products', + suppliers: '/api/suppliers', + orders: '/api/orders', + branches: '/api/branches', + headquarters: '/api/headquarters', + deliveries: '/api/deliveries', + orderDetails: '/api/order-details', + orderDetailDeliveries: '/api/order-detail-deliveries', + }, +}; +``` + +### Environment-Specific Configuration + +**Production (Docker):** + +Create `public/runtime-config.js`: + +```javascript +window.RUNTIME_CONFIG = { + API_URL: 'https://api.your-domain.com' +}; +``` + +Include in `index.html`: + +```html + +``` + +**Local Development:** + +No configuration needed. Defaults to `http://localhost:3000`. + +**Codespaces:** + +Automatically detected and configured. + +--- + +## Making API Requests + +### Using Axios + +The application uses Axios for HTTP requests. + +**Installation:** +```bash +npm install axios +``` + +**Basic GET Request:** + +```typescript +import axios from 'axios'; +import { api } from '../api/config'; + +const fetchProducts = async () => { + const response = await axios.get(`${api.baseURL}${api.endpoints.products}`); + return response.data; +}; +``` + +**GET Request with ID:** + +```typescript +const fetchProduct = async (id: number) => { + const response = await axios.get(`${api.baseURL}${api.endpoints.products}/${id}`); + return response.data; +}; +``` + +**POST Request:** + +```typescript +const createProduct = async (productData: Partial) => { + const response = await axios.post( + `${api.baseURL}${api.endpoints.products}`, + productData + ); + return response.data; +}; +``` + +**PUT Request:** + +```typescript +const updateProduct = async (id: number, productData: Partial) => { + const response = await axios.put( + `${api.baseURL}${api.endpoints.products}/${id}`, + productData + ); + return response.data; +}; +``` + +**DELETE Request:** + +```typescript +const deleteProduct = async (id: number) => { + await axios.delete(`${api.baseURL}${api.endpoints.products}/${id}`); +}; +``` + +--- + +## React Query Integration + +### Overview + +React Query manages server state (fetching, caching, synchronization) with minimal boilerplate. + +**Installation:** +```bash +npm install react-query +``` + +### Setup + +**No setup required** - React Query is used directly in components without a provider in the current implementation. + +### Basic Query + +```typescript +import { useQuery } from 'react-query'; +import axios from 'axios'; +import { api } from '../api/config'; + +function Products() { + const { data, isLoading, error } = useQuery('products', async () => { + const response = await axios.get(`${api.baseURL}${api.endpoints.products}`); + return response.data; + }); + + if (isLoading) return
Loading...
; + if (error) return
Error loading products
; + + return
{/* Render products */}
; +} +``` + +### Query with Parameters + +```typescript +const fetchProduct = async (id: number) => { + const { data } = await axios.get(`${api.baseURL}${api.endpoints.products}/${id}`); + return data; +}; + +function ProductDetail({ productId }: { productId: number }) { + const { data: product, isLoading } = useQuery( + ['product', productId], // Query key includes parameter + () => fetchProduct(productId) + ); + + // Component logic +} +``` + +### Mutations + +For create, update, delete operations: + +```typescript +import { useMutation, useQueryClient } from 'react-query'; + +function ProductForm() { + const queryClient = useQueryClient(); + + const mutation = useMutation( + (newProduct: Product) => axios.post(`${api.baseURL}${api.endpoints.products}`, newProduct), + { + onSuccess: () => { + // Invalidate and refetch products query + queryClient.invalidateQueries('products'); + }, + } + ); + + const handleSubmit = (productData: Product) => { + mutation.mutate(productData); + }; + + return
{/* Form fields */}
; +} +``` + +### React Query Benefits + +- **Automatic Caching** - Avoids redundant network requests +- **Background Refetching** - Keeps data fresh +- **Loading & Error States** - Built-in state management +- **Request Deduplication** - Multiple components requesting same data = one request +- **Optimistic Updates** - Update UI before server response + +--- + +## Error Handling + +### Component-Level Error Handling + +**Display Error State:** + +```typescript +const { data, isLoading, error } = useQuery('products', fetchProducts); + +if (error) { + return ( +
+ Failed to fetch products. Please try again later. +
+ ); +} +``` + +### Try-Catch Error Handling + +For manual API calls (outside React Query): + +```typescript +const handleDelete = async (productId: number) => { + try { + await axios.delete(`${api.baseURL}${api.endpoints.products}/${productId}`); + alert('Product deleted successfully'); + fetchProducts(); // Refresh list + } catch (error) { + console.error('Error deleting product:', error); + alert('Failed to delete product'); + } +}; +``` + +### Axios Error Structure + +```typescript +try { + await axios.get('/api/endpoint'); +} catch (error) { + if (axios.isAxiosError(error)) { + console.error('Status:', error.response?.status); + console.error('Data:', error.response?.data); + console.error('Message:', error.message); + } +} +``` + +### HTTP Status Code Handling + +```typescript +try { + await axios.get(`${api.baseURL}${api.endpoints.products}/${id}`); +} catch (error) { + if (axios.isAxiosError(error)) { + if (error.response?.status === 404) { + alert('Product not found'); + } else if (error.response?.status === 500) { + alert('Server error. Please try again later.'); + } else { + alert('An error occurred'); + } + } +} +``` + +### Global Error Handling (Future Enhancement) + +Consider adding an Axios interceptor: + +```typescript +axios.interceptors.response.use( + (response) => response, + (error) => { + // Global error handling logic + if (error.response?.status === 401) { + // Redirect to login + } + return Promise.reject(error); + } +); +``` + +--- + +## Authentication Flow + +### Current Implementation + +The current authentication is **mock/client-side only** and suitable for demos. + +**How It Works:** + +1. User enters email and password +2. `AuthContext.login()` checks if email and password exist +3. Sets `isLoggedIn = true` +4. Sets `isAdmin = true` if email ends with `@github.com` +5. No server validation or session persistence + +**Code:** + +```typescript +// src/context/AuthContext.tsx + +const login = async (email: string, password: string) => { + if (email && password) { + setIsLoggedIn(true); + setIsAdmin(email.endsWith('@github.com')); + } +}; + +const logout = () => { + setIsLoggedIn(false); + setIsAdmin(false); +}; +``` + +### Real Authentication (Future Implementation) + +For production, implement proper authentication: + +**1. Login Endpoint:** + +```typescript +const login = async (email: string, password: string) => { + try { + const response = await axios.post(`${api.baseURL}/api/auth/login`, { + email, + password, + }); + + const { token, user } = response.data; + + // Store token in localStorage or httpOnly cookie + localStorage.setItem('authToken', token); + + setIsLoggedIn(true); + setIsAdmin(user.role === 'admin'); + } catch (error) { + console.error('Login failed:', error); + throw error; + } +}; +``` + +**2. Axios Interceptor for Token:** + +```typescript +axios.interceptors.request.use((config) => { + const token = localStorage.getItem('authToken'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; +}); +``` + +**3. Logout Endpoint:** + +```typescript +const logout = async () => { + try { + await axios.post(`${api.baseURL}/api/auth/logout`); + } finally { + localStorage.removeItem('authToken'); + setIsLoggedIn(false); + setIsAdmin(false); + } +}; +``` + +**4. Protected Route Check:** + +```typescript +useEffect(() => { + const token = localStorage.getItem('authToken'); + if (token) { + // Validate token with API + axios.get(`${api.baseURL}/api/auth/me`) + .then(response => { + setIsLoggedIn(true); + setIsAdmin(response.data.role === 'admin'); + }) + .catch(() => { + localStorage.removeItem('authToken'); + }); + } +}, []); +``` + +--- + +## API Endpoints + +### Available Endpoints + +All endpoints are prefixed with `/api/`: + +| Entity | Endpoint | Methods | +|--------|----------|---------| +| Products | `/api/products` | GET, POST | +| Products (single) | `/api/products/:id` | GET, PUT, DELETE | +| Suppliers | `/api/suppliers` | GET, POST | +| Suppliers (single) | `/api/suppliers/:id` | GET, PUT, DELETE | +| Orders | `/api/orders` | GET, POST | +| Orders (single) | `/api/orders/:id` | GET, PUT, DELETE | +| Branches | `/api/branches` | GET, POST | +| Branches (single) | `/api/branches/:id` | GET, PUT, DELETE | +| Headquarters | `/api/headquarters` | GET, POST | +| Headquarters (single) | `/api/headquarters/:id` | GET, PUT, DELETE | +| Deliveries | `/api/deliveries` | GET, POST | +| Deliveries (single) | `/api/deliveries/:id` | GET, PUT, DELETE | +| Order Details | `/api/order-details` | GET, POST | +| Order Details (single) | `/api/order-details/:id` | GET, PUT, DELETE | +| Order Detail Deliveries | `/api/order-detail-deliveries` | GET, POST | +| Order Detail Deliveries (single) | `/api/order-detail-deliveries/:id` | GET, PUT, DELETE | + +### Endpoint Usage Examples + +**Fetch all products:** +```typescript +GET ${api.baseURL}/api/products +``` + +**Fetch single product:** +```typescript +GET ${api.baseURL}/api/products/123 +``` + +**Create product:** +```typescript +POST ${api.baseURL}/api/products +Body: { name: "Product", price: 10.99, ... } +``` + +**Update product:** +```typescript +PUT ${api.baseURL}/api/products/123 +Body: { name: "Updated Product", ... } +``` + +**Delete product:** +```typescript +DELETE ${api.baseURL}/api/products/123 +``` + +--- + +## Request/Response Patterns + +### TypeScript Interfaces + +Define interfaces matching API responses: + +```typescript +interface Product { + productId: number; + name: string; + description: string; + price: number; + imgName: string; + sku: string; + unit: string; + supplierId: number; + discount?: number; +} + +interface Supplier { + supplierId: number; + name: string; + description: string; + contactPerson: string; + email: string; + phone: string; +} +``` + +### Response Handling + +**List Response:** + +```typescript +const fetchProducts = async (): Promise => { + const { data } = await axios.get(`${api.baseURL}${api.endpoints.products}`); + return data; // Assumes API returns array directly +}; +``` + +**Single Item Response:** + +```typescript +const fetchProduct = async (id: number): Promise => { + const { data } = await axios.get(`${api.baseURL}${api.endpoints.products}/${id}`); + return data; +}; +``` + +### Request Payload + +**Create/Update:** + +```typescript +const productData: Partial = { + name: 'New Product', + description: 'Description', + price: 29.99, + sku: 'SKU123', + unit: 'unit', + supplierId: 1, + imgName: 'product.png', +}; + +await axios.post(`${api.baseURL}${api.endpoints.products}`, productData); +``` + +--- + +## Best Practices + +### 1. Centralize API Calls + +Create dedicated functions for API calls: + +```typescript +// src/api/products.ts +export const productApi = { + getAll: () => axios.get(`${api.baseURL}${api.endpoints.products}`), + getById: (id: number) => axios.get(`${api.baseURL}${api.endpoints.products}/${id}`), + create: (data: Partial) => axios.post(`${api.baseURL}${api.endpoints.products}`, data), + update: (id: number, data: Partial) => axios.put(`${api.baseURL}${api.endpoints.products}/${id}`, data), + delete: (id: number) => axios.delete(`${api.baseURL}${api.endpoints.products}/${id}`), +}; +``` + +### 2. Use React Query for All Data Fetching + +Prefer React Query over manual `useEffect` + `useState`: + +❌ **Not Recommended:** +```typescript +const [products, setProducts] = useState([]); +const [loading, setLoading] = useState(false); + +useEffect(() => { + setLoading(true); + axios.get(url) + .then(res => setProducts(res.data)) + .finally(() => setLoading(false)); +}, []); +``` + +βœ… **Recommended:** +```typescript +const { data: products, isLoading } = useQuery('products', fetchProducts); +``` + +### 3. Handle Loading and Error States + +Always handle loading and error states: + +```typescript +if (isLoading) return ; +if (error) return ; +return ; +``` + +### 4. Type Safety + +Use TypeScript interfaces for all API data: + +```typescript +const { data } = useQuery('products', fetchProducts); +``` + +### 5. Consistent Error Messages + +Provide user-friendly error messages: + +```typescript +if (error) { + return
Unable to load products. Please try again later.
; +} +``` + +### 6. Optimistic Updates + +For better UX, update UI before API confirmation: + +```typescript +const mutation = useMutation(updateProduct, { + onMutate: async (newProduct) => { + // Cancel outgoing refetches + await queryClient.cancelQueries('products'); + + // Snapshot previous value + const previousProducts = queryClient.getQueryData('products'); + + // Optimistically update + queryClient.setQueryData('products', (old: Product[]) => + old.map(p => p.id === newProduct.id ? newProduct : p) + ); + + // Return context with snapshot + return { previousProducts }; + }, + onError: (err, newProduct, context) => { + // Rollback on error + queryClient.setQueryData('products', context.previousProducts); + }, +}); +``` + +### 7. Request Deduplication + +React Query automatically deduplicates requests, but for manual calls, track inflight requests: + +```typescript +let inflightRequest: Promise | null = null; + +const fetchProducts = async () => { + if (inflightRequest) return inflightRequest; + + inflightRequest = axios.get(url); + const result = await inflightRequest; + inflightRequest = null; + + return result; +}; +``` + +### 8. API Call Logging (Development) + +Log API calls during development: + +```typescript +const fetchProducts = async () => { + console.log('Fetching products from:', `${api.baseURL}${api.endpoints.products}`); + const response = await axios.get(`${api.baseURL}${api.endpoints.products}`); + console.log('Products received:', response.data); + return response.data; +}; +``` + +### 9. CORS Handling + +If encountering CORS issues: +- Ensure backend has CORS enabled +- Check API URL is correct +- For development, proxy can be configured in `vite.config.ts`: + +```typescript +export default defineConfig({ + server: { + proxy: { + '/api': 'http://localhost:3000' + } + } +}); +``` + +### 10. Timeout Configuration + +Set reasonable timeouts for API calls: + +```typescript +axios.create({ + baseURL: api.baseURL, + timeout: 10000, // 10 seconds +}); +``` + +--- + +## Debugging Tips + +### Check API URL + +```typescript +console.log('API Base URL:', API_BASE_URL); +``` + +### Network Tab + +- Open browser DevTools β†’ Network tab +- Filter by "Fetch/XHR" +- Inspect request/response details + +### React Query DevTools (Future Enhancement) + +Install and use React Query DevTools: + +```bash +npm install @tanstack/react-query-devtools +``` + +```typescript +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; + + + + + +``` + +--- + +## Related Documentation + +- [Setup Guide](./setup.md) - Environment configuration +- [Architecture](./architecture.md) - Overall system design +- [Backend API Documentation](../../api/api-swagger.json) - Full API specification diff --git a/docs/frontend/architecture.md b/docs/frontend/architecture.md new file mode 100644 index 0000000..3b15541 --- /dev/null +++ b/docs/frontend/architecture.md @@ -0,0 +1,386 @@ +# Frontend Architecture + +## Overview + +The frontend is built as a modern React single-page application (SPA) using TypeScript, Vite, and Tailwind CSS. The architecture follows a component-based approach with centralized state management for cross-cutting concerns. + +## Component Structure + +### High-Level Organization + +``` +src/ +β”œβ”€β”€ components/ # Reusable UI components +β”‚ β”œβ”€β”€ admin/ # Admin-specific components +β”‚ β”œβ”€β”€ entity/ # Domain entity components +β”‚ β”‚ └── product/ # Product-related components +β”‚ β”œβ”€β”€ About.tsx +β”‚ β”œβ”€β”€ Footer.tsx +β”‚ β”œβ”€β”€ Login.tsx +β”‚ β”œβ”€β”€ Navigation.tsx +β”‚ └── Welcome.tsx +β”œβ”€β”€ context/ # React Context providers +β”‚ β”œβ”€β”€ AuthContext.tsx +β”‚ β”œβ”€β”€ ThemeContext.tsx +β”‚ β”œβ”€β”€ themeContextUtils.tsx +β”‚ └── useTheme.tsx +β”œβ”€β”€ api/ # API configuration +β”‚ └── config.ts +β”œβ”€β”€ assets/ # Static assets (images, etc.) +β”œβ”€β”€ App.tsx # Root application component +β”œβ”€β”€ main.tsx # Application entry point +└── index.css # Global styles +``` + +### Component Patterns + +#### Page Components +Top-level components that represent entire pages/routes: +- `Welcome.tsx` - Landing page +- `About.tsx` - About page +- `Login.tsx` - Login page +- `Products.tsx` - Product listing page +- `AdminProducts.tsx` - Admin product management + +#### Layout Components +Structural components used across multiple pages: +- `Navigation.tsx` - Top navigation bar with theme toggle and auth controls +- `Footer.tsx` - Footer displayed on all pages + +#### Entity Components +Domain-specific components organized by entity type: +- `entity/product/Products.tsx` - Product list view +- `entity/product/ProductForm.tsx` - Product creation/editing form + +#### Admin Components +Protected components for administrative functions: +- `admin/AdminProducts.tsx` - Admin product management interface + +## State Management + +### Context API + +The application uses React Context API for managing global application state. Two primary contexts are implemented: + +#### 1. AuthContext + +**Purpose:** Manages authentication state and user authorization. + +**State:** +- `isLoggedIn: boolean` - Whether a user is authenticated +- `isAdmin: boolean` - Whether the logged-in user has admin privileges + +**Methods:** +- `login(email: string, password: string): Promise` - Authenticates user +- `logout(): void` - Clears authentication state + +**Usage:** +```typescript +import { useAuth } from '../context/AuthContext'; + +function MyComponent() { + const { isLoggedIn, isAdmin, login, logout } = useAuth(); + + // Use authentication state and methods +} +``` + +**Implementation Notes:** +- Currently uses client-side mock authentication (checks email domain) +- Admin access granted to `@github.com` email addresses +- State is not persisted across page refreshes (no session storage/cookies) + +#### 2. ThemeContext + +**Purpose:** Manages dark/light theme preferences. + +**State:** +- `darkMode: boolean` - Current theme mode + +**Methods:** +- `toggleTheme(): void` - Switches between dark and light themes + +**Usage:** +```typescript +import { useTheme } from '../context/ThemeContext'; + +function MyComponent() { + const { darkMode, toggleTheme } = useTheme(); + + return ( +
+ +
+ ); +} +``` + +**Implementation Notes:** +- Theme preference persisted in `localStorage` +- Adds `dark` or `light` class to `document.documentElement` for Tailwind +- Theme changes trigger smooth CSS transitions (300ms) + +### Local Component State + +For component-specific state (form inputs, UI toggles, local data), standard React `useState` and `useEffect` hooks are used: + +```typescript +const [adminMenuOpen, setAdminMenuOpen] = useState(false); +``` + +### Server State (React Query) + +React Query is used for managing server state (data fetching, caching, synchronization): + +```typescript +import { useQuery } from 'react-query'; + +const { data, isLoading, error } = useQuery('products', fetchProducts); +``` + +Benefits: +- Automatic caching and background refetching +- Built-in loading and error states +- Optimistic updates support +- Request deduplication + +## Routing Structure + +React Router v7 is used for client-side routing with the `BrowserRouter` strategy. + +### Route Configuration + +```typescript + + + } /> + } /> + } /> + } /> + } /> + + +``` + +### Route Hierarchy + +- `/` - Welcome/home page +- `/about` - About page +- `/products` - Public product listing +- `/login` - User login +- `/admin/products` - Admin product management (protected) + +### Navigation + +Navigation between routes uses the `Link` component: + +```typescript +import { Link } from 'react-router-dom'; + +View Products +``` + +### Protected Routes + +Admin routes check authentication state via `useAuth()`: + +```typescript +const { isAdmin } = useAuth(); + +if (!isAdmin) { + return ; +} +``` + +## API Integration Patterns + +### API Configuration + +The API client is configured in `src/api/config.ts` with intelligent URL detection: + +1. **Runtime Configuration** - Checks `window.RUNTIME_CONFIG.API_URL` +2. **Codespace Detection** - Auto-detects GitHub Codespaces environment +3. **Fallback** - Uses `http://localhost:3000` for local development + +### API Structure + +```typescript +export const api = { + baseURL: API_BASE_URL, + endpoints: { + products: '/api/products', + suppliers: '/api/suppliers', + orders: '/api/orders', + branches: '/api/branches', + headquarters: '/api/headquarters', + deliveries: '/api/deliveries', + orderDetails: '/api/order-details', + orderDetailDeliveries: '/api/order-detail-deliveries', + }, +}; +``` + +### Making API Calls + +Components use React Query with Axios for API calls: + +```typescript +import axios from 'axios'; +import { useQuery } from 'react-query'; +import { api } from '../api/config'; + +const fetchProducts = async () => { + const response = await axios.get(`${api.baseURL}${api.endpoints.products}`); + return response.data; +}; + +function Products() { + const { data, isLoading, error } = useQuery('products', fetchProducts); + + if (isLoading) return
Loading...
; + if (error) return
Error loading products
; + + return ; +} +``` + +### Error Handling + +API errors are handled at multiple levels: + +1. **React Query Error State** - Captured in query result +2. **Component-Level** - Display user-friendly error messages +3. **Global Error Boundary** - Catch unhandled errors (future enhancement) + +## Component Communication + +### Parent-Child Communication + +**Props Down:** +```typescript + +``` + +**Events Up:** +```typescript + +``` + +### Sibling Communication + +For sibling components, lift state to common parent or use Context: + +```typescript +function Parent() { + const [selectedProduct, setSelectedProduct] = useState(null); + + return ( + <> + + + + ); +} +``` + +### Cross-Component Communication + +Use Context API for truly global state: +- Authentication status β†’ AuthContext +- Theme preferences β†’ ThemeContext + +## Data Flow + +``` +User Interaction + ↓ +Component Event Handler + ↓ +State Update (useState/Context) + ↓ +Re-render with New State + ↓ +Optional: API Call via React Query + ↓ +Cache Update & Component Re-render +``` + +## Performance Considerations + +### Code Splitting + +Currently using single bundle. Future optimization: lazy load routes. + +```typescript +// Future enhancement +const AdminProducts = lazy(() => import('./components/admin/AdminProducts')); +``` + +### Memoization + +Use React.memo for expensive component renders: + +```typescript +export default React.memo(ProductCard); +``` + +### React Query Caching + +React Query automatically caches API responses: +- Reduces unnecessary network requests +- Provides instant data for repeated queries +- Background refetching keeps data fresh + +## TypeScript Integration + +### Type Safety + +All components use TypeScript for type safety: + +```typescript +interface Product { + id: number; + name: string; + description: string; + price: number; +} + +interface ProductCardProps { + product: Product; + onEdit?: (id: number) => void; +} + +function ProductCard({ product, onEdit }: ProductCardProps) { + // Component implementation +} +``` + +### Context Types + +Context providers have strongly typed values: + +```typescript +interface AuthContextType { + isLoggedIn: boolean; + isAdmin: boolean; + login: (email: string, password: string) => Promise; + logout: () => void; +} +``` + +## Future Architecture Enhancements + +Potential improvements for the architecture: + +1. **Lazy Loading** - Code split routes for faster initial load +2. **Error Boundaries** - Global error handling for better UX +3. **Service Layer** - Abstract API calls into dedicated services +4. **Form Management** - Integrate React Hook Form or Formik +5. **State Management** - Consider Zustand or Redux for complex state +6. **Testing** - Add comprehensive component and integration tests +7. **Accessibility** - Enhanced ARIA support and keyboard navigation +8. **i18n** - Internationalization support for multiple languages diff --git a/docs/frontend/code-organization.md b/docs/frontend/code-organization.md new file mode 100644 index 0000000..d956094 --- /dev/null +++ b/docs/frontend/code-organization.md @@ -0,0 +1,777 @@ +# Code Organization + +This guide explains the folder structure, naming conventions, and best practices for organizing code in the OctoCAT Supply frontend. + +## Table of Contents + +- [Directory Structure](#directory-structure) +- [File Naming Conventions](#file-naming-conventions) +- [Component Organization](#component-organization) +- [State Management](#state-management) +- [Utilities and Helpers](#utilities-and-helpers) +- [Assets Management](#assets-management) +- [Type Definitions](#type-definitions) +- [Best Practices for New Features](#best-practices-for-new-features) + +--- + +## Directory Structure + +### Overview + +``` +frontend/ +β”œβ”€β”€ public/ # Static assets served directly +β”‚ β”œβ”€β”€ copilot.png # Brand logos +β”‚ β”œβ”€β”€ hero-cat.png # Hero images +β”‚ └── *.png # Product images +β”œβ”€β”€ src/ # Source code +β”‚ β”œβ”€β”€ api/ # API configuration +β”‚ β”‚ └── config.ts # Base URL and endpoint definitions +β”‚ β”œβ”€β”€ assets/ # Imported assets (images, fonts) +β”‚ β”œβ”€β”€ components/ # React components +β”‚ β”‚ β”œβ”€β”€ admin/ # Admin-specific components +β”‚ β”‚ β”œβ”€β”€ entity/ # Domain entity components +β”‚ β”‚ β”‚ └── product/ # Product-related components +β”‚ β”‚ β”œβ”€β”€ About.tsx +β”‚ β”‚ β”œβ”€β”€ Footer.tsx +β”‚ β”‚ β”œβ”€β”€ Login.tsx +β”‚ β”‚ β”œβ”€β”€ Navigation.tsx +β”‚ β”‚ └── Welcome.tsx +β”‚ β”œβ”€β”€ context/ # React Context providers +β”‚ β”‚ β”œβ”€β”€ AuthContext.tsx +β”‚ β”‚ β”œβ”€β”€ ThemeContext.tsx +β”‚ β”‚ β”œβ”€β”€ themeContextUtils.tsx +β”‚ β”‚ └── useTheme.tsx +β”‚ β”œβ”€β”€ App.tsx # Root component with routing +β”‚ β”œβ”€β”€ main.tsx # Application entry point +β”‚ β”œβ”€β”€ index.css # Global styles +β”‚ └── vite-env.d.ts # TypeScript type declarations +β”œβ”€β”€ .gitignore +β”œβ”€β”€ Dockerfile +β”œβ”€β”€ eslint.config.js +β”œβ”€β”€ index.html # HTML entry point +β”œβ”€β”€ package.json +β”œβ”€β”€ postcss.config.js +β”œβ”€β”€ tailwind.config.js # Tailwind CSS configuration +β”œβ”€β”€ tsconfig.json # TypeScript configuration +β”œβ”€β”€ tsconfig.app.json +β”œβ”€β”€ tsconfig.node.json +└── vite.config.ts # Vite configuration +``` + +### Key Directories Explained + +**`public/`** +- Static assets served at root URL +- Not processed by Vite +- Use for: logos, favicons, product images +- Access: `/filename.png` (no `/public` prefix) + +**`src/`** +- All TypeScript/TSX source code +- Processed and bundled by Vite + +**`src/api/`** +- API client configuration +- Endpoint definitions +- Base URL detection logic + +**`src/assets/`** +- Assets imported in code (currently unused, but available) +- Use for: fonts, icons, images that need processing +- Access: `import logo from './assets/logo.svg'` + +**`src/components/`** +- React components +- Organized by feature/entity +- Includes layout and page components + +**`src/context/`** +- React Context providers +- Global state management +- Theme and authentication + +--- + +## File Naming Conventions + +### Components + +**Format:** `PascalCase.tsx` + +``` +Welcome.tsx βœ… Correct +Navigation.tsx βœ… Correct +ProductCard.tsx βœ… Correct +product-card.tsx ❌ Incorrect +productCard.tsx ❌ Incorrect +``` + +### Utilities and Helpers + +**Format:** `camelCase.ts` + +``` +formatting.ts βœ… Correct +apiHelpers.ts βœ… Correct +dateUtils.ts βœ… Correct +Formatting.ts ❌ Incorrect (use PascalCase only for components) +``` + +### Types + +**Format:** `PascalCase.ts` or `camelCase.types.ts` + +``` +types.ts βœ… Correct (if exporting multiple types) +Product.ts βœ… Correct (if single type/interface) +product.types.ts βœ… Correct +``` + +### Tests + +**Format:** `ComponentName.test.tsx` or `utilName.test.ts` + +``` +Welcome.test.tsx βœ… Correct +formatting.test.ts βœ… Correct +Welcome.spec.tsx βœ… Alternative +``` + +### Configuration Files + +**Format:** Lowercase with dots/dashes + +``` +vite.config.ts βœ… Correct +tailwind.config.js βœ… Correct +.eslintrc βœ… Correct +``` + +--- + +## Component Organization + +### Organizing by Feature/Entity + +Group related components together: + +``` +components/ +β”œβ”€β”€ entity/ +β”‚ β”œβ”€β”€ product/ +β”‚ β”‚ β”œβ”€β”€ Products.tsx # List view +β”‚ β”‚ β”œβ”€β”€ ProductCard.tsx # Individual card +β”‚ β”‚ β”œβ”€β”€ ProductForm.tsx # Create/edit form +β”‚ β”‚ └── ProductDetail.tsx # Detail view +β”‚ β”œβ”€β”€ order/ +β”‚ β”‚ β”œβ”€β”€ Orders.tsx +β”‚ β”‚ └── OrderForm.tsx +β”‚ └── supplier/ +β”‚ β”œβ”€β”€ Suppliers.tsx +β”‚ └── SupplierForm.tsx +β”œβ”€β”€ admin/ +β”‚ β”œβ”€β”€ AdminProducts.tsx +β”‚ β”œβ”€β”€ AdminOrders.tsx +β”‚ └── AdminDashboard.tsx +β”œβ”€β”€ About.tsx # Top-level pages +β”œβ”€β”€ Welcome.tsx +└── Login.tsx +``` + +### Component Structure + +**Basic Component Template:** + +```typescript +import { useState } from 'react'; +import { useTheme } from '../context/ThemeContext'; + +// 1. Type definitions +interface MyComponentProps { + title: string; + onAction: () => void; +} + +// 2. Component definition +export default function MyComponent({ title, onAction }: MyComponentProps) { + // 3. Hooks (context, state, effects) + const { darkMode } = useTheme(); + const [count, setCount] = useState(0); + + // 4. Event handlers + const handleClick = () => { + setCount(count + 1); + onAction(); + }; + + // 5. Render logic + return ( +
+

{title}

+ +
+ ); +} +``` + +### Component File Organization + +**Order within file:** + +1. Imports (React, third-party, local) +2. Type/Interface definitions +3. Constants +4. Component definition +5. Export default + +**Example:** + +```typescript +// 1. Imports +import { useState, useEffect } from 'react'; +import axios from 'axios'; +import { useQuery } from 'react-query'; +import { api } from '../../api/config'; +import { useTheme } from '../../context/ThemeContext'; + +// 2. Types +interface Product { + productId: number; + name: string; + price: number; +} + +// 3. Constants +const DEFAULT_SORT = 'name'; + +// 4. Component +export default function Products() { + // Component implementation +} +``` + +--- + +## State Management + +### Local State + +Use `useState` for component-specific state: + +```typescript +const [isOpen, setIsOpen] = useState(false); +const [formData, setFormData] = useState({ name: '', email: '' }); +``` + +**When to use:** +- UI state (modals, dropdowns, toggles) +- Form inputs +- Temporary data + +### Context State + +Use Context for state shared across multiple components: + +```typescript +// AuthContext for authentication state +const { isLoggedIn, isAdmin } = useAuth(); + +// ThemeContext for theme preferences +const { darkMode, toggleTheme } = useTheme(); +``` + +**When to use:** +- Authentication state +- Theme preferences +- User settings +- Language/locale + +### Server State (React Query) + +Use React Query for server data: + +```typescript +const { data, isLoading, error } = useQuery('products', fetchProducts); +``` + +**When to use:** +- Fetching from API +- Cached server data +- Background synchronization + +### Creating New Context + +**Template:** + +```typescript +// src/context/MyContext.tsx +import { createContext, useContext, useState, ReactNode } from 'react'; + +interface MyContextType { + value: string; + updateValue: (newValue: string) => void; +} + +const MyContext = createContext(null); + +export function MyProvider({ children }: { children: ReactNode }) { + const [value, setValue] = useState(''); + + const updateValue = (newValue: string) => { + setValue(newValue); + }; + + return ( + + {children} + + ); +} + +export function useMyContext() { + const context = useContext(MyContext); + if (!context) { + throw new Error('useMyContext must be used within MyProvider'); + } + return context; +} +``` + +--- + +## Utilities and Helpers + +### Creating Utility Functions + +Place in `src/utils/` (create directory if needed): + +``` +src/ +└── utils/ + β”œβ”€β”€ formatting.ts # Currency, date formatting + β”œβ”€β”€ validation.ts # Form validation + β”œβ”€β”€ api.ts # API helpers + └── storage.ts # localStorage helpers +``` + +**Example: Formatting Utilities** + +```typescript +// src/utils/formatting.ts + +export const formatCurrency = (amount: number): string => { + return `$${amount.toFixed(2)}`; +}; + +export const formatDate = (date: Date): string => { + return date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); +}; + +export const truncateText = (text: string, maxLength: number): string => { + if (text.length <= maxLength) return text; + return `${text.substring(0, maxLength)}...`; +}; +``` + +**Usage:** + +```typescript +import { formatCurrency, formatDate } from '../utils/formatting'; + +
+

{formatCurrency(product.price)}

+

{formatDate(order.createdAt)}

+
+``` + +--- + +## Assets Management + +### Public Assets + +Place in `public/` directory: + +``` +public/ +β”œβ”€β”€ copilot.png # Brand logo +β”œβ”€β”€ hero-cat.png # Hero image +β”œβ”€β”€ product-1.png # Product images +β”œβ”€β”€ product-2.png +└── favicon.ico +``` + +**Access in code:** + +```typescript +Logo +{product.name} +``` + +### Imported Assets + +Place in `src/assets/` (if need processing): + +``` +src/ +└── assets/ + β”œβ”€β”€ logo.svg + └── icon-cart.svg +``` + +**Access in code:** + +```typescript +import logo from './assets/logo.svg'; + +Logo +``` + +### When to Use Each + +**Use `public/`:** +- Assets referenced by name in data (e.g., product images) +- Favicons, manifests +- Large images that don't need optimization + +**Use `src/assets/`:** +- Icons imported in code +- Assets needing optimization +- SVGs used as React components + +--- + +## Type Definitions + +### Component Props + +Define interfaces inline or in separate file: + +```typescript +// Inline (for single component) +interface ProductCardProps { + product: Product; + onEdit?: (id: number) => void; + darkMode: boolean; +} + +export default function ProductCard({ product, onEdit, darkMode }: ProductCardProps) { + // Component +} +``` + +### Shared Types + +Create `src/types/` directory for shared types: + +```typescript +// src/types/product.ts +export interface Product { + productId: number; + name: string; + description: string; + price: number; + imgName: string; + sku: string; + unit: string; + supplierId: number; + discount?: number; +} + +// src/types/supplier.ts +export interface Supplier { + supplierId: number; + name: string; + contactPerson: string; + email: string; + phone: string; +} + +// src/types/index.ts +export * from './product'; +export * from './supplier'; +``` + +**Usage:** + +```typescript +import { Product, Supplier } from '../types'; +``` + +### API Response Types + +Match backend API responses: + +```typescript +// src/types/api.ts +export interface ApiResponse { + data: T; + message?: string; + error?: string; +} + +export interface PaginatedResponse { + data: T[]; + total: number; + page: number; + pageSize: number; +} +``` + +--- + +## Best Practices for New Features + +### 1. Plan Component Structure + +Before coding, plan: +- What components are needed? +- How will they be organized? +- What state is local vs. shared? + +### 2. Start with Types + +Define TypeScript interfaces first: + +```typescript +// 1. Define data types +interface Order { + orderId: number; + branchId: number; + orderDate: Date; + totalAmount: number; +} + +// 2. Define component props +interface OrderListProps { + orders: Order[]; + onOrderClick: (id: number) => void; +} + +// 3. Build component +export default function OrderList({ orders, onOrderClick }: OrderListProps) { + // Component implementation +} +``` + +### 3. Create Reusable Components + +Extract repeated UI into components: + +```typescript +// Instead of repeating button styles: + + +// Create Button component: + +``` + +### 4. Organize by Feature + +Group related files: + +``` +components/ +└── entity/ + └── order/ + β”œβ”€β”€ Orders.tsx # List view + β”œβ”€β”€ OrderCard.tsx # Card component + β”œβ”€β”€ OrderForm.tsx # Create/edit form + β”œβ”€β”€ OrderDetail.tsx # Detail view + └── orderHelpers.ts # Order-specific utilities +``` + +### 5. Follow Existing Patterns + +Study existing components for: +- How theme context is used +- How API calls are made +- How errors are handled +- How loading states are shown + +### 6. Add Documentation + +Document complex components: + +```typescript +/** + * ProductCard displays a product with image, details, and quantity selector. + * + * @param product - Product data to display + * @param onAddToCart - Callback when user adds to cart + * @param darkMode - Whether dark mode is enabled + * + * @example + * console.log(id, qty)} + * darkMode={true} + * /> + */ +export default function ProductCard({ ... }: ProductCardProps) { + // Component +} +``` + +### 7. Keep Components Small + +**Guidelines:** +- Single responsibility +- < 200 lines of code (ideal: < 150) +- Extract large JSX blocks into sub-components +- Extract complex logic into hooks or utilities + +### 8. Write Tests + +Add tests alongside components: + +``` +components/ +└── entity/ + └── order/ + β”œβ”€β”€ Orders.tsx + β”œβ”€β”€ Orders.test.tsx # Tests + β”œβ”€β”€ OrderForm.tsx + └── OrderForm.test.tsx +``` + +--- + +## Example: Adding a New Feature + +### Scenario: Add Supplier Management + +**1. Plan Structure:** + +``` +components/ +└── entity/ + └── supplier/ + β”œβ”€β”€ Suppliers.tsx # List page + β”œβ”€β”€ SupplierCard.tsx # Display card + β”œβ”€β”€ SupplierForm.tsx # Create/edit form + └── SupplierDetail.tsx # Detail view +``` + +**2. Define Types:** + +```typescript +// src/types/supplier.ts +export interface Supplier { + supplierId: number; + name: string; + description: string; + contactPerson: string; + email: string; + phone: string; +} +``` + +**3. Create API Functions:** + +```typescript +// src/api/suppliers.ts +import axios from 'axios'; +import { api } from './config'; +import { Supplier } from '../types'; + +export const supplierApi = { + getAll: () => axios.get(`${api.baseURL}${api.endpoints.suppliers}`), + getById: (id: number) => axios.get(`${api.baseURL}${api.endpoints.suppliers}/${id}`), + create: (data: Omit) => + axios.post(`${api.baseURL}${api.endpoints.suppliers}`, data), + update: (id: number, data: Partial) => + axios.put(`${api.baseURL}${api.endpoints.suppliers}/${id}`, data), + delete: (id: number) => + axios.delete(`${api.baseURL}${api.endpoints.suppliers}/${id}`), +}; +``` + +**4. Build Components:** + +```typescript +// src/components/entity/supplier/Suppliers.tsx +import { useQuery } from 'react-query'; +import { supplierApi } from '../../../api/suppliers'; +import SupplierCard from './SupplierCard'; + +export default function Suppliers() { + const { data: suppliers, isLoading, error } = useQuery( + 'suppliers', + () => supplierApi.getAll().then(res => res.data) + ); + + if (isLoading) return
Loading...
; + if (error) return
Error loading suppliers
; + + return ( +
+ {suppliers?.map(supplier => ( + + ))} +
+ ); +} +``` + +**5. Add Route:** + +```typescript +// src/App.tsx +} /> +``` + +**6. Add Navigation Link:** + +```typescript +// src/components/Navigation.tsx +Suppliers +``` + +**7. Write Tests:** + +```typescript +// src/components/entity/supplier/Suppliers.test.tsx +import { render, screen } from '@testing-library/react'; +import Suppliers from './Suppliers'; + +describe('Suppliers', () => { + it('renders supplier list', async () => { + render(); + // Test implementation + }); +}); +``` + +--- + +## Code Quality Checklist + +Before submitting code: + +- [ ] TypeScript types defined +- [ ] Component follows naming conventions +- [ ] Theme context integrated (darkMode support) +- [ ] Responsive design implemented +- [ ] Error handling in place +- [ ] Loading states handled +- [ ] Accessibility attributes added +- [ ] No console errors or warnings +- [ ] Linter passes (`npm run lint`) +- [ ] Tests written and passing +- [ ] Documentation updated (if needed) + +--- + +## Resources + +- [React Best Practices](https://react.dev/learn) +- [TypeScript Handbook](https://www.typescriptlang.org/docs/) +- [Project README](../../README.md) +- [Architecture Documentation](./architecture.md) diff --git a/docs/frontend/components.md b/docs/frontend/components.md new file mode 100644 index 0000000..98b489a --- /dev/null +++ b/docs/frontend/components.md @@ -0,0 +1,614 @@ +# Component Documentation + +This guide documents the key components in the OctoCAT Supply frontend application. + +## Table of Contents + +- [Context Providers](#context-providers) + - [AuthContext](#authcontext) + - [ThemeContext](#themecontext) +- [Layout Components](#layout-components) + - [Navigation](#navigation) + - [Footer](#footer) +- [Page Components](#page-components) + - [Welcome](#welcome) + - [About](#about) + - [Login](#login) +- [Entity Components](#entity-components) + - [Products](#products) + - [ProductForm](#productform) +- [Admin Components](#admin-components) + - [AdminProducts](#adminproducts) + +--- + +## Context Providers + +### AuthContext + +**Location:** `src/context/AuthContext.tsx` + +**Purpose:** Manages authentication state and provides authentication methods across the application. + +**Context Value:** + +```typescript +interface AuthContextType { + isLoggedIn: boolean; // Whether user is authenticated + isAdmin: boolean; // Whether user has admin privileges + login: (email: string, password: string) => Promise; + logout: () => void; +} +``` + +**Usage:** + +```typescript +import { useAuth } from '../context/AuthContext'; + +function MyComponent() { + const { isLoggedIn, isAdmin, login, logout } = useAuth(); + + if (!isLoggedIn) { + return
Please log in
; + } + + return ( +
+ {isAdmin && } + +
+ ); +} +``` + +**Implementation Notes:** +- Currently uses mock authentication (client-side only) +- Admin access granted to `@github.com` email addresses +- State not persisted across page refreshes +- Should be wrapped at the app root level + +**Provider Usage:** + +```typescript + + + +``` + +--- + +### ThemeContext + +**Location:** `src/context/ThemeContext.tsx` + +**Purpose:** Manages dark/light theme preference with localStorage persistence. + +**Context Value:** + +```typescript +interface ThemeContextType { + darkMode: boolean; // Current theme mode (true = dark, false = light) + toggleTheme: () => void; // Function to switch themes +} +``` + +**Usage:** + +```typescript +import { useTheme } from '../context/ThemeContext'; + +function MyComponent() { + const { darkMode, toggleTheme } = useTheme(); + + return ( +
+ +
+ ); +} +``` + +**Features:** +- Persists preference in `localStorage` (key: `'theme'`) +- Adds `'dark'` or `'light'` class to `document.documentElement` +- Smooth transitions between themes (300ms) +- Initializes from localStorage on mount + +**Provider Usage:** + +```typescript + + + +``` + +--- + +## Layout Components + +### Navigation + +**Location:** `src/components/Navigation.tsx` + +**Purpose:** Top navigation bar with branding, links, theme toggle, and auth controls. + +**Props:** None (uses contexts) + +**Features:** +- Responsive design (mobile hamburger menu) +- Theme toggle button +- Conditional rendering based on auth state +- Admin menu for authenticated admins +- Sticky positioning with backdrop blur + +**Key Elements:** +- Logo and branding +- Main navigation links (Home, Products, About) +- Theme toggle +- Login/Logout button +- Admin dropdown (when authenticated as admin) + +**Usage:** + +```typescript + +``` + +**Responsive Behavior:** +- Desktop (β‰₯768px): Full horizontal navigation +- Mobile (<768px): Hamburger menu (if implemented) + +--- + +### Footer + +**Location:** `src/components/Footer.tsx` + +**Purpose:** Site-wide footer with links and copyright information. + +**Props:** None (uses ThemeContext) + +**Features:** +- Adapts to current theme +- Contains company information +- Social/contact links + +**Usage:** + +```typescript +