# Context Refactoring - Code Examples

## Example 1: Splitting HomeContext

### Current Structure (Problematic)
```javascript
// context/helpers/Home/HomeContext.js (1200+ lines, 50+ state variables)
const HomeProvider = props => {
  // Products state
  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);
  const [product, setProduct] = useState(null);
  
  // Categories state
  const [categories, setCategories] = useState([]);
  const [categoryList, setCategoryList] = useState([]);
  const [featuredCategories, setFeaturedCategories] = useState([]);
  
  // Home data state
  const [sliders, setSliders] = useState([]);
  const [bannerType, setBannerType] = useState('slider');
  const [featuredProducts, setFeaturedProducts] = useState([]);
  
  // Search state
  const [minPrice, setMinPrice] = useState(null);
  const [maxPrice, setMaxPrice] = useState(null);
  const [filteredCategories, setFilteredCategories] = useState([]);
  
  // ... 40+ more state variables
  
  return (
    <Context.Provider value={{
      // 80+ properties in context value
      products, filteredProducts, product,
      categories, categoryList, featuredCategories,
      sliders, bannerType, featuredProducts,
      minPrice, maxPrice, filteredCategories,
      // ... etc
    }}>
      {props.children}
    </Context.Provider>
  );
};
```

### Proposed Structure (Improved)

#### 1. ProductContext
```javascript
// context/helpers/product/ProductContext.js
import { createContext, useContext, useState, useMemo } from 'react';
import { useDomain } from '../domain/DomainContext';
import { handleError, handleAPIResponse } from '../../utils/errorHandler';

const ProductContext = createContext(null);

export const ProductProvider = ({ children }) => {
  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);
  const [product, setProduct] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const { getEndpointData } = useDomain();

  const getProductDetails = async (id, versionId = 1) => {
    setIsLoading(true);
    try {
      const params = new URLSearchParams();
      params.append('productId', id);
      params.append('versionId', versionId);
      
      const { API_URL, requestOptions } = await getEndpointData(
        'catalog/productpagedata',
        'GET',
        params
      );
      
      const response = await fetch(API_URL, requestOptions);
      const data = await response.json();
      
      if (handleAPIResponse(data, { context: 'Get Product Details' })) {
        return null;
      }
      
      setProduct(data);
      return data;
    } catch (error) {
      handleError(error, { context: 'Get Product Details' });
      return null;
    } finally {
      setIsLoading(false);
    }
  };

  // Memoize context value
  const contextValue = useMemo(
    () => ({
      products,
      filteredProducts,
      product,
      isLoading,
      setProducts,
      setFilteredProducts,
      getProductDetails,
    }),
    [products, filteredProducts, product, isLoading]
  );

  return (
    <ProductContext.Provider value={contextValue}>
      {children}
    </ProductContext.Provider>
  );
};

export const useProduct = () => {
  const context = useContext(ProductContext);
  if (!context) {
    throw new Error('useProduct must be used within ProductProvider');
  }
  return context;
};
```

#### 2. CategoryContext
```javascript
// context/helpers/category/CategoryContext.js
import { createContext, useContext, useState, useMemo } from 'react';
import { useDomain } from '../domain/DomainContext';
import { handleError, handleAPIResponse } from '../../utils/errorHandler';

const CategoryContext = createContext(null);

export const CategoryProvider = ({ children }) => {
  const [categories, setCategories] = useState([]);
  const [categoryList, setCategoryList] = useState([]);
  const [featuredCategories, setFeaturedCategories] = useState([]);
  const [category, setCategory] = useState({});
  const [isLoading, setIsLoading] = useState(false);
  const { getEndpointData } = useDomain();

  const getCategories = async () => {
    setIsLoading(true);
    try {
      const { API_URL, requestOptions } = await getEndpointData(
        'catalog/getcategorylist',
        'GET'
      );
      
      const response = await fetch(API_URL, requestOptions);
      const data = await response.json();
      
      if (handleAPIResponse(data, { context: 'Get Categories' })) {
        return;
      }
      
      setCategoryList(data.categoryData);
      setCategories(data.categoryChildren);
    } catch (error) {
      handleError(error, { context: 'Get Categories' });
    } finally {
      setIsLoading(false);
    }
  };

  const contextValue = useMemo(
    () => ({
      categories,
      categoryList,
      featuredCategories,
      category,
      isLoading,
      setFeaturedCategories,
      getCategories,
      setCategory,
    }),
    [categories, categoryList, featuredCategories, category, isLoading]
  );

  return (
    <CategoryContext.Provider value={contextValue}>
      {children}
    </CategoryContext.Provider>
  );
};

export const useCategory = () => {
  const context = useContext(CategoryContext);
  if (!context) {
    throw new Error('useCategory must be used within CategoryProvider');
  }
  return context;
};
```

#### 3. HomeDataContext
```javascript
// context/helpers/home/HomeDataContext.js
import { createContext, useContext, useState, useMemo } from 'react';
import { useDomain } from '../domain/DomainContext';
import { handleError, handleAPIResponse } from '../../utils/errorHandler';

const HomeDataContext = createContext(null);

export const HomeDataProvider = ({ children }) => {
  const [sliders, setSliders] = useState([]);
  const [bannerType, setBannerType] = useState('slider');
  const [videoUrl, setVideoUrl] = useState('');
  const [featuredProducts, setFeaturedProducts] = useState([]);
  const [newProducts, setNewProducts] = useState([]);
  const [onSaleProducts, setOnSaleProducts] = useState([]);
  const [flashDeals, setFlashDeals] = useState([]);
  const [ads, setAds] = useState([]);
  const [promotions, setPromotions] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const { getEndpointData } = useDomain();

  const getHomeData = async () => {
    setIsLoading(true);
    try {
      const { API_URL, requestOptions } = await getEndpointData(
        'catalog/homepage',
        'GET'
      );
      
      const response = await fetch(API_URL, requestOptions);
      const data = await response.json();
      
      if (handleAPIResponse(data, { context: 'Get Home Data' })) {
        return;
      }
      
      // Process data
      if (data.bannerImages) setSliders(data.bannerImages);
      if (data.bannerType) setBannerType(data.bannerType);
      if (data.videoUrl) setVideoUrl(data.videoUrl);
      
      // Process carousel data
      if (data.carousel) {
        const featured = data.carousel.find(c => c.type === 'featured');
        const newProduct = data.carousel.find(c => c.type === 'new');
        const onSale = data.carousel.find(c => c.type === 'special');
        
        if (featured) setFeaturedProducts(featured);
        if (newProduct) setNewProducts(newProduct);
        if (onSale) setOnSaleProducts(onSale);
      }
      
      if (data.flashDeals) setFlashDeals(data.flashDeals);
      if (data.ads) setAds(data.ads);
      if (data.promotions) setPromotions(data.promotions);
    } catch (error) {
      handleError(error, { context: 'Get Home Data' });
    } finally {
      setIsLoading(false);
    }
  };

  const contextValue = useMemo(
    () => ({
      sliders,
      bannerType,
      videoUrl,
      featuredProducts,
      newProducts,
      onSaleProducts,
      flashDeals,
      ads,
      promotions,
      isLoading,
      getHomeData,
    }),
    [
      sliders,
      bannerType,
      videoUrl,
      featuredProducts,
      newProducts,
      onSaleProducts,
      flashDeals,
      ads,
      promotions,
      isLoading,
    ]
  );

  return (
    <HomeDataContext.Provider value={contextValue}>
      {children}
    </HomeDataContext.Provider>
  );
};

export const useHomeData = () => {
  const context = useContext(HomeDataContext);
  if (!context) {
    throw new Error('useHomeData must be used within HomeDataProvider');
  }
  return context;
};
```

## Example 2: Creating Shared Utilities

### User Utility
```javascript
// context/utils/userUtils.js
/**
 * Get user from localStorage
 * @returns {Object|null} User object or null
 */
export function getUser() {
  if (typeof window === 'undefined') return null;
  
  try {
    const user = localStorage.getItem('user');
    return user ? JSON.parse(user) : null;
  } catch (error) {
    console.error('Error getting user from localStorage:', error);
    return null;
  }
}

/**
 * Set user in localStorage
 * @param {Object} user - User object to store
 */
export function setUser(user) {
  if (typeof window === 'undefined') return;
  
  try {
    localStorage.setItem('user', JSON.stringify(user));
  } catch (error) {
    console.error('Error setting user in localStorage:', error);
  }
}

/**
 * Remove user from localStorage
 */
export function removeUser() {
  if (typeof window === 'undefined') return;
  
  try {
    localStorage.removeItem('user');
  } catch (error) {
    console.error('Error removing user from localStorage:', error);
  }
}
```

### API Client Utility
```javascript
// context/utils/apiClient.js
import { handleError, handleAPIResponse, fetchWithTimeout } from './errorHandler';

/**
 * Create a standardized API client
 * @param {Function} getEndpointData - Function to get endpoint data
 * @returns {Object} API client with request method
 */
export function createAPIClient(getEndpointData) {
  /**
   * Make an API request
   * @param {string} endpoint - API endpoint
   * @param {string} method - HTTP method
   * @param {URLSearchParams} params - URL parameters
   * @param {Object} options - Request options
   * @returns {Promise<Object|null>} Response data or null on error
   */
  const request = async (endpoint, method = 'GET', params = null, options = {}) => {
    try {
      // Get endpoint data
      const { API_URL, requestOptions } = await getEndpointData(
        endpoint,
        method,
        params
      );

      // Make request with timeout
      const response = await fetchWithTimeout(
        API_URL,
        {
          ...requestOptions,
          method,
          body: method !== 'GET' && params ? params : undefined,
        },
        options.timeout || 15000
      );

      // Parse response
      let data;
      const contentType = response.headers.get('content-type');
      
      if (contentType?.includes('application/json')) {
        data = await response.json();
      } else {
        const text = await response.text();
        data = JSON.parse(text);
      }

      // Handle API response errors
      if (handleAPIResponse(data, {
        context: options.context || endpoint,
        fallbackMessage: options.fallbackMessage,
        showToast: options.showToast !== false,
      })) {
        return null;
      }

      return data;
    } catch (error) {
      handleError(error, {
        context: options.context || endpoint,
        fallbackMessage: options.fallbackMessage,
        showToast: options.showToast !== false,
      });
      return null;
    }
  };

  return { request };
}
```

## Example 3: Standardizing Context Creation

### Context Factory
```javascript
// context/utils/contextFactory.js
import { createContext, useContext, useMemo } from 'react';

/**
 * Create a standardized context with provider and hook
 * @param {string} name - Context name (e.g., 'Product')
 * @param {Function} createProviderValue - Function to create provider value
 * @returns {Object} Context, Provider, and hook
 */
export function createContextFactory(name, createProviderValue) {
  const Context = createContext(null);

  const Provider = ({ children, ...props }) => {
    const value = createProviderValue(props);
    
    // Memoize context value
    const contextValue = useMemo(() => value, [JSON.stringify(value)]);

    return (
      <Context.Provider value={contextValue}>
        {children}
      </Context.Provider>
    );
  };

  const useHook = () => {
    const context = useContext(Context);
    
    if (!context) {
      throw new Error(
        `use${name} must be used within ${name}Provider`
      );
    }
    
    return context;
  };

  return {
    Context,
    Provider,
    useHook,
  };
}
```

### Usage Example
```javascript
// context/helpers/currency/CurrencyContext.js
import { createContextFactory } from '../../utils/contextFactory';
import { useState, useMemo } from 'react';

const { Provider, useHook } = createContextFactory('Currency', () => {
  const [selectedCurr, setSelectedCurr] = useState({
    currency: 'USD',
    symbol: '$',
    value: 1,
  });

  return {
    selectedCurr,
    setSelectedCurr,
  };
});

export const CurrencyProvider = Provider;
export const useCurrency = useHook;
```

## Example 4: Optimizing Provider Nesting

### Before (Problematic)
```javascript
// pages/_app.js
export default function App({ Component, pageProps }) {
  return (
    <>
      <DomainContextProvider>
        <SettingProvider>
          <AuthProvider>
            <AddressProvider>
              <HomeContextProvider>
                <CompareContextProvider>
                  <CurrencyContextProvider>
                    <CartContextProvider>
                      <WishlistContextProvider>
                        <FilterProvider>
                          <OrderProvider>
                            <CheckoutProvider>
                              <Layout>
                                <Component {...pageProps} />
                              </Layout>
                            </CheckoutProvider>
                          </OrderProvider>
                        </FilterProvider>
                      </WishlistContextProvider>
                    </CartContextProvider>
                  </CurrencyContextProvider>
                </CompareContextProvider>
              </HomeContextProvider>
            </AddressProvider>
          </AuthProvider>
        </SettingProvider>
      </DomainContextProvider>
      <Toaster />
      <ToastContainer />
    </>
  );
}
```

### After (Improved)
```javascript
// context/providers/AppProviders.jsx
import { useMemo } from 'react';
import DomainContextProvider from '../helpers/domain/DomainContext';
import SettingProvider from '../helpers/theme-setting/SettingProvider';
import { AuthProvider } from '../helpers/auth';
import AddressProvider from '../helpers/address/AddressContext';
import { ProductProvider } from '../helpers/product/ProductContext';
import { CategoryProvider } from '../helpers/category/CategoryContext';
import { HomeDataProvider } from '../helpers/home/HomeDataContext';
import { CompareContextProvider } from '../helpers/Compare/CompareContext';
import { CurrencyContextProvider } from '../helpers/Currency/CurrencyContext';
import CartContextProvider from '../helpers/cart/CartContext';
import { WishlistContextProvider } from '../helpers/wishlist/WishlistContext';
import FilterProvider from '../helpers/filter/FilterProvider';
import OrderProvider from '../helpers/order/OrderContext';
import CheckoutProvider from '../helpers/checkout/CheckoutContext';

/**
 * Consolidated app providers
 * Memoized to prevent unnecessary re-renders
 */
export function AppProviders({ children }) {
  // Memoize to prevent re-creation on every render
  const providers = useMemo(() => children, [children]);

  return (
    <DomainContextProvider>
      <SettingProvider>
        <AuthProvider>
          <AddressProvider>
            <ProductProvider>
              <CategoryProvider>
                <HomeDataProvider>
                  <CompareContextProvider>
                    <CurrencyContextProvider>
                      <CartContextProvider>
                        <WishlistContextProvider>
                          <FilterProvider>
                            <OrderProvider>
                              <CheckoutProvider>
                                {providers}
                              </CheckoutProvider>
                            </OrderProvider>
                          </FilterProvider>
                        </WishlistContextProvider>
                      </CartContextProvider>
                    </CurrencyContextProvider>
                  </CompareContextProvider>
                </HomeDataProvider>
              </CategoryProvider>
            </ProductProvider>
          </AddressProvider>
        </AuthProvider>
      </SettingProvider>
    </DomainContextProvider>
  );
}
```

```javascript
// pages/_app.js
import { AppProviders } from '@/context/providers/AppProviders';
import Layout from '@/components/layout/Layout';

export default function App({ Component, pageProps }) {
  return (
    <>
      <AppProviders>
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </AppProviders>
      <Toaster />
      <ToastContainer />
    </>
  );
}
```

## Example 5: Adding Memoization to Existing Context

### Before
```javascript
// context/helpers/cart/CartContext.js
return (
  <Context.Provider
    value={{
      ...props,
      addToCart,
      removeFromCart,
      updateQty,
      isLoading,
      // ... 10+ more properties
    }}>
    {props.children}
  </Context.Provider>
);
```

### After
```javascript
// context/helpers/cart/CartContext.js
import { useMemo } from 'react';

const CartProvider = props => {
  // ... state and functions ...

  // Memoize context value
  const contextValue = useMemo(
    () => ({
      addToCart,
      removeFromCart,
      updateQty,
      emptyCart,
      applyCoupon,
      removeCoupon,
      isLoading,
      quantity,
      stock,
    }),
    [
      addToCart,
      removeFromCart,
      updateQty,
      emptyCart,
      applyCoupon,
      removeCoupon,
      isLoading,
      quantity,
      stock,
    ]
  );

  return (
    <Context.Provider value={contextValue}>
      {props.children}
    </Context.Provider>
  );
};
```

---

**Note**: These examples show the pattern. Actual implementation may vary based on specific needs.
