122 lines
3.8 KiB
TypeScript
122 lines
3.8 KiB
TypeScript
import React, {
|
|
createContext,
|
|
useContext,
|
|
useEffect,
|
|
useState,
|
|
ReactNode,
|
|
} from 'react';
|
|
import { themeService } from '../../features/system/services/systemSettingsService';
|
|
|
|
type ThemeLayoutMode = 'dark' | 'light';
|
|
|
|
type ThemeSettings = {
|
|
theme_primary_color: string;
|
|
theme_primary_light: string;
|
|
theme_primary_dark: string;
|
|
theme_primary_accent: string;
|
|
theme_layout_mode: ThemeLayoutMode;
|
|
};
|
|
|
|
type ThemeContextValue = {
|
|
theme: ThemeSettings;
|
|
isLoading: boolean;
|
|
refreshTheme: () => Promise<void>;
|
|
};
|
|
|
|
const defaultTheme: ThemeSettings = {
|
|
theme_primary_color: '#d4af37',
|
|
theme_primary_light: '#f5d76e',
|
|
theme_primary_dark: '#c9a227',
|
|
theme_primary_accent: '#e8c547',
|
|
theme_layout_mode: 'dark',
|
|
};
|
|
|
|
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
|
|
|
|
export const useTheme = () => {
|
|
const context = useContext(ThemeContext);
|
|
if (!context) {
|
|
throw new Error('useTheme must be used within ThemeProvider');
|
|
}
|
|
return context;
|
|
};
|
|
|
|
interface ThemeProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
|
|
const [theme, setTheme] = useState<ThemeSettings>(defaultTheme);
|
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
|
|
const loadTheme = async () => {
|
|
try {
|
|
setIsLoading(true);
|
|
const response = await themeService.getThemeSettings();
|
|
if (response.data) {
|
|
const themeData: ThemeSettings = {
|
|
theme_primary_color: response.data.theme_primary_color || defaultTheme.theme_primary_color,
|
|
theme_primary_light: response.data.theme_primary_light || defaultTheme.theme_primary_light,
|
|
theme_primary_dark: response.data.theme_primary_dark || defaultTheme.theme_primary_dark,
|
|
theme_primary_accent: response.data.theme_primary_accent || defaultTheme.theme_primary_accent,
|
|
theme_layout_mode: (response.data.theme_layout_mode === 'light' ? 'light' : 'dark') as ThemeLayoutMode,
|
|
};
|
|
setTheme(themeData);
|
|
|
|
// Apply CSS variables for colors
|
|
document.documentElement.style.setProperty('--luxury-gold', themeData.theme_primary_color);
|
|
document.documentElement.style.setProperty('--luxury-gold-light', themeData.theme_primary_light);
|
|
document.documentElement.style.setProperty('--luxury-gold-dark', themeData.theme_primary_dark);
|
|
document.documentElement.style.setProperty('--luxury-gold-accent', themeData.theme_primary_accent);
|
|
|
|
// Apply layout mode class to body
|
|
document.body.classList.remove('theme-dark', 'theme-light');
|
|
document.body.classList.add(`theme-${themeData.theme_layout_mode}`);
|
|
document.documentElement.classList.remove('theme-dark', 'theme-light');
|
|
document.documentElement.classList.add(`theme-${themeData.theme_layout_mode}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading theme settings:', error);
|
|
// Apply defaults
|
|
document.body.classList.remove('theme-dark', 'theme-light');
|
|
document.body.classList.add('theme-dark');
|
|
document.documentElement.classList.remove('theme-dark', 'theme-light');
|
|
document.documentElement.classList.add('theme-dark');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadTheme();
|
|
|
|
// Listen for theme refresh events
|
|
const handleRefresh = () => {
|
|
loadTheme();
|
|
};
|
|
|
|
if (typeof window !== 'undefined') {
|
|
window.addEventListener('refreshTheme', handleRefresh);
|
|
return () => {
|
|
window.removeEventListener('refreshTheme', handleRefresh);
|
|
};
|
|
}
|
|
}, []);
|
|
|
|
const refreshTheme = async () => {
|
|
await loadTheme();
|
|
};
|
|
|
|
return (
|
|
<ThemeContext.Provider
|
|
value={{
|
|
theme,
|
|
isLoading,
|
|
refreshTheme,
|
|
}}
|
|
>
|
|
{children}
|
|
</ThemeContext.Provider>
|
|
);
|
|
};
|