Skip to content

Context Providers

React context providers for global state management in Lager Guru.

Overview

Lager Guru uses React Context API for global state management. Context providers wrap the application and provide shared state to all child components.

AuthProvider

Provides authentication state and methods throughout the application.

Source: src/contexts/AuthContext.tsx

State

typescript
{
  user: User | null;           // Current authenticated user
  session: Session | null;      // Current session
  userRole: UserRole | null;    // User role (admin, driver, worker)
  loading: boolean;             // Loading state
}

Methods

typescript
{
  signIn: (email: string, password: string) => Promise<{ error: any }>;
  signUp: (email: string, password: string, fullName: string) => Promise<{ error: any }>;
  signOut: () => Promise<void>;
}

Usage

Wrap the app:

typescript
import { AuthProvider } from '@/contexts/AuthContext';

function App() {
  return (
    <AuthProvider>
      <Router>
        {/* Your app components */}
      </Router>
    </AuthProvider>
  );
}

Consume in components:

typescript
import { useAuth } from '@/contexts/AuthContext';

function MyComponent() {
  const { user, userRole, signOut } = useAuth();
  
  if (!user) {
    return <div>Please log in</div>;
  }
  
  return (
    <div>
      <p>Welcome, {user.email}</p>
      <p>Role: {userRole}</p>
      <button onClick={signOut}>Sign Out</button>
    </div>
  );
}

Features

  • Automatic session management
  • User role fetching
  • Profile synchronization
  • Automatic redirect on auth state change
  • Query cache invalidation on sign out

BrandingProvider

Manages application branding (colors, logos, themes).

Source: src/contexts/BrandingContext.tsx

State

typescript
{
  branding: Branding;           // Current branding configuration
  setBranding: (b: Branding) => void;  // Update branding
}

Branding Interface

typescript
interface Branding {
  primaryColor: string;
  accentColor: string;
  logoUrl?: string;
  companyName?: string;
}

Usage

Wrap the app:

typescript
import { BrandingProvider } from '@/contexts/BrandingContext';

function App() {
  return (
    <BrandingProvider>
      <AuthProvider>
        {/* Rest of app */}
      </AuthProvider>
    </BrandingProvider>
  );
}

Consume in components:

typescript
import { useBranding } from '@/contexts/BrandingContext';

function ThemedComponent() {
  const { branding } = useBranding();
  
  return (
    <div style={{ 
      backgroundColor: branding.primaryColor,
      color: branding.accentColor 
    }}>
      <img src={branding.logoUrl} alt="Logo" />
    </div>
  );
}

Features

  • Loads branding from configuration
  • Applies CSS variables for theming
  • Supports dynamic branding updates
  • Tenant-specific branding support

LanguageContext

Manages application language and translations.

Source: src/contexts/LanguageContext.tsx

State

typescript
{
  language: string;             // Current language code (e.g., 'en', 'de', 'bg')
  setLanguage: (lang: string) => void;  // Change language
  t: (key: string) => string;   // Translation function
}

Usage

Wrap the app:

typescript
import { LanguageProvider } from '@/contexts/LanguageContext';

function App() {
  return (
    <LanguageProvider>
      <BrandingProvider>
        {/* Rest of app */}
      </BrandingProvider>
    </LanguageProvider>
  );
}

Consume in components:

typescript
import { useLanguage } from '@/contexts/LanguageContext';

function TranslatedComponent() {
  const { language, setLanguage, t } = useLanguage();
  
  return (
    <div>
      <h1>{t('welcome.title')}</h1>
      <select value={language} onChange={e => setLanguage(e.target.value)}>
        <option value="en">English</option>
        <option value="de">Deutsch</option>
        <option value="bg">Български</option>
      </select>
    </div>
  );
}

Supported Languages

  • English (en)
  • German (de)
  • Bulgarian (bg)

Provider Hierarchy

Context providers should be nested in the following order:

typescript
function App() {
  return (
    <LanguageProvider>
      <BrandingProvider>
        <AuthProvider>
          <QueryClientProvider client={queryClient}>
            <Router>
              {/* Your app components */}
            </Router>
          </QueryClientProvider>
        </AuthProvider>
      </BrandingProvider>
    </LanguageProvider>
  );
}

Order Matters

  1. LanguageProvider (outermost) - Language doesn't depend on other contexts
  2. BrandingProvider - Branding may use language for translations
  3. AuthProvider - Authentication may use branding for UI
  4. QueryClientProvider - React Query for data fetching
  5. Router - Routing depends on auth state

Custom Context Pattern

To create a new context provider:

typescript
import { createContext, useContext, useState, ReactNode } from 'react';

// 1. Define context type
interface MyContextType {
  value: string;
  setValue: (v: string) => void;
}

// 2. Create context
const MyContext = createContext<MyContextType | undefined>(undefined);

// 3. Create provider component
export const MyProvider = ({ children }: { children: ReactNode }) => {
  const [value, setValue] = useState<string>('');
  
  return (
    <MyContext.Provider value={{ value, setValue }}>
      {children}
    </MyContext.Provider>
  );
};

// 4. Create hook for consuming context
export const useMyContext = () => {
  const context = useContext(MyContext);
  if (context === undefined) {
    throw new Error('useMyContext must be used within MyProvider');
  }
  return context;
};

Best Practices

  1. Always check context existence: Throw error if hook used outside provider
  2. Minimize re-renders: Use useMemo and useCallback for expensive operations
  3. Separate concerns: Don't mix unrelated state in one context
  4. Type safety: Always define TypeScript interfaces for context values
  5. Provider order: Place providers in logical dependency order

Released under Commercial License