import React, { createContext, useContext, useState, useEffect } from 'react'; import { useColorScheme, Platform } from 'react-native'; import { Theme } from '../constants/theme'; import { storage } from '../utils/storage'; import { useAppConfig } from './ConfigContext'; type ThemeMode = 'light' | 'dark' | 'system'; interface ThemeContextType { mode: ThemeMode; setMode: (mode: ThemeMode) => void; colors: typeof Theme.dark; isDark: boolean; } const ThemeContext = createContext(undefined); // Storage helper is now imported from utils/storage export function ThemeProvider({ children }: { children: React.ReactNode }) { const systemColorScheme = useColorScheme(); const [mode, setRawMode] = useState('light'); const { config } = useAppConfig(); useEffect(() => { loadTheme(); }, []); const loadTheme = async () => { const savedMode = await storage.get('theme_mode'); if (savedMode) { setRawMode(savedMode as ThemeMode); } }; const setMode = async (newMode: ThemeMode) => { setRawMode(newMode); await storage.save('theme_mode', newMode); }; const isDark = mode === 'system' ? systemColorScheme === 'dark' : mode === 'dark'; // Layer admin-controlled brand colors and logo on top of the static design tokens // so consumers always receive the full palette (surfaceLight, glass, accent, etc). const baseColors = isDark ? Theme.dark : Theme.light; const colors = { ...baseColors, primary: config?.branding?.theme_color_primary || baseColors.primary, accent: config?.branding?.theme_color_primary || baseColors.accent, secondary: config?.branding?.theme_color_secondary || baseColors.secondary, logo: config?.branding?.logo_url || null, } as typeof Theme.dark & { logo: string | null }; return ( {children} ); } export function useAppTheme() { const context = useContext(ThemeContext); if (context === undefined) { // Fallback safely instead of crashing — return the full design-token palette return { mode: 'light', setMode: () => {}, isDark: false, colors: { ...Theme.light, logo: null } }; } return context; }