diff --git a/src/services/theme.service.ts b/src/services/theme.service.ts index c363f2e..1a3c2ad 100644 --- a/src/services/theme.service.ts +++ b/src/services/theme.service.ts @@ -4,80 +4,89 @@ * Single Responsibility: Orchestrate theme business logic. * * This service is the ONLY layer that knows about both storage and DOM. - * It delegates: - * - Persistence → theme.storage.ts - * - DOM mutation → applyTheme.ts (utils) - * - * FUTURE API INTEGRATION: - * When a backend API is introduced, only this file changes. - * The storage layer, DOM utility, context, and hook remain untouched. - * Pattern: replace loadTheme() / saveTheme() calls with API calls, - * keeping the same method signatures. - * - * RULES: - * - No React imports. - * - No JSX. - * - No component access. + * It delegates persistence to the backend database via REST API. */ import type { Theme } from "../types/theme.types"; -import { - loadTheme as storageLoad, - saveTheme as storageSave, - clearTheme as storageClear, -} from "../storage/theme.storage"; +import apiClient from "../api/axiosInstance"; import { applyTheme as applyThemeToDom } from "../utils/applyTheme"; import { DEFAULT_THEME, AVAILABLE_THEMES } from "../constants/themes"; export { DEFAULT_THEME, AVAILABLE_THEMES }; +let currentTheme: Theme = DEFAULT_THEME; + +// Load user theme preference asynchronously during application initialization (module import) +try { + const token = localStorage.getItem("accessToken"); + if (token) { + const response = await apiClient.get<{ success: boolean; data: { themeCode: string } }>("/api/v1/settings/theme"); + if (response && response.success && response.data?.themeCode) { + const themeCode = response.data.themeCode; + const found = AVAILABLE_THEMES.find((t) => t.id === themeCode); + if (found) { + currentTheme = found; + } + } + } +} catch (error) { + console.error("Failed to load user theme preference asynchronously at startup:", error); +} + +// Apply the resolved theme to the DOM immediately prior to React tree mount +applyThemeToDom(currentTheme.palette); +if (typeof document !== "undefined") { + if (currentTheme.mode === "dark") { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } +} + // ───────────────────────────────────────────────────────────────────────────── // PUBLIC SERVICE METHODS // ───────────────────────────────────────────────────────────────────────────── /** - * Returns the currently persisted theme from storage. - * Falls back to DEFAULT_THEME if nothing is saved or storage fails. + * Returns the loaded theme. */ export function getCurrentTheme(): Theme { - const saved = storageLoad(); - if (!saved) return DEFAULT_THEME; - // If the saved theme id still exists in the registry, use it. - // Otherwise (e.g. default changed), fall back to DEFAULT_THEME. - const exists = AVAILABLE_THEMES.some((t) => t.id === saved.id); - return exists ? saved : DEFAULT_THEME; + return currentTheme; } /** * Returns all themes available for selection. - * Future: merge with API-fetched tenant themes. */ export function getAvailableThemes(): Theme[] { return AVAILABLE_THEMES; } /** - * Persists a theme to storage. - * Does NOT apply it to the DOM — call applyTheme() separately if needed. + * Persists a theme to the backend database. * * @param theme - The theme to persist. */ export function saveTheme(theme: Theme): void { - storageSave(theme); + currentTheme = theme; + const themeCode = (theme as any).code || theme.id; + apiClient.put("/api/v1/settings/theme", { themeCode }) + .catch((err) => { + console.error("Failed to save theme preference to DB:", err); + }); } /** - * Resets to the default theme: - * 1. Clears persisted theme from storage. - * 2. Removes all runtime CSS variable overrides from the DOM. - * The static @theme values in index.css take effect again. + * Resets to the default theme. * * @returns The default theme, so the caller can update its state. */ export function resetTheme(): Theme { - storageClear(); - // Apply explicitly so the DOM reflects DEFAULT_THEME (Royal Purple), - // matching the static @theme values in index.css. + currentTheme = DEFAULT_THEME; + apiClient.put("/api/v1/settings/theme", { themeCode: DEFAULT_THEME.id }) + .catch((err) => { + console.error("Failed to reset theme preference on DB:", err); + }); + applyThemeToDom(DEFAULT_THEME.palette); if (typeof document !== "undefined") { document.documentElement.classList.remove("dark");