Files
Hotel-Booking/Frontend/src/shared/contexts/ThemeContext.tsx
Iliyan Angelov e43a95eafb updates
2025-12-09 00:14:21 +02:00

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>
);
};