Files
CRM_ENVR/src/providers/website-theme-provider.tsx
T

136 lines
4.0 KiB
TypeScript

"use client"
import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from "react"
const WEBSITE_THEME_KEY = "crm-website-theme"
const COLOR_THEME_KEY = "crm-color-theme"
const themeClasses: Record<string, string> = {
spidey: "theme-spidey",
}
const colorThemes = ["default","ocean","forest","sunset","midnight","rose","amber","violet","slate","ruby"]
interface WebsiteThemeContextValue {
websiteTheme: string
setWebsiteTheme: (theme: string) => Promise<void>
colorTheme: string
setColorTheme: (theme: string) => Promise<void>
loading: boolean
}
const WebsiteThemeContext = createContext<WebsiteThemeContextValue | null>(null)
function applyWebsiteTheme(theme: string) {
const prefix = "theme-"
const root = document.documentElement
const classes = root.className.split(" ").filter((c) => !c.startsWith(prefix))
const cls = themeClasses[theme]
if (cls) {
classes.push(cls)
}
root.className = classes.join(" ").trim()
}
function applyColorTheme(theme: string) {
const root = document.documentElement
const classes = root.className.split(" ").filter((c) => !colorThemes.includes(c))
if (theme !== "default") {
classes.push(theme)
}
root.className = classes.join(" ").trim()
localStorage.setItem(COLOR_THEME_KEY, theme)
}
function getStored(key: string): string | null {
if (typeof window === "undefined") return null
return localStorage.getItem(key)
}
function storeTheme(theme: string) {
if (typeof window === "undefined") return
localStorage.setItem(WEBSITE_THEME_KEY, theme)
}
export function WebsiteThemeProvider({ children }: { children: ReactNode }) {
const [websiteTheme, setWebsiteThemeState] = useState<string>("default")
const [colorTheme, setColorThemeState] = useState<string>("default")
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch("/api/settings/website-theme")
.then((res) => (res.ok ? res.json() : null))
.then((data) => {
const wt = data?.websiteTheme || "default"
setWebsiteThemeState(wt)
storeTheme(wt)
applyWebsiteTheme(wt)
if (data?.colorTheme) {
setColorThemeState(data.colorTheme)
applyColorTheme(data.colorTheme)
} else {
const stored = getStored(COLOR_THEME_KEY)
if (stored) {
setColorThemeState(stored)
applyColorTheme(stored)
}
}
})
.catch(() => {
const stored = getStored(WEBSITE_THEME_KEY)
const theme = stored || "default"
setWebsiteThemeState(theme)
applyWebsiteTheme(theme)
const storedColor = getStored(COLOR_THEME_KEY)
if (storedColor) {
setColorThemeState(storedColor)
applyColorTheme(storedColor)
}
})
.finally(() => setLoading(false))
}, [])
const setWebsiteTheme = useCallback(async (theme: string) => {
setWebsiteThemeState(theme)
storeTheme(theme)
applyWebsiteTheme(theme)
try {
await fetch("/api/settings/website-theme", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ websiteTheme: theme }),
})
} catch {
console.warn("Failed to persist website theme")
}
}, [])
const setColorTheme = useCallback(async (theme: string) => {
setColorThemeState(theme)
applyColorTheme(theme)
try {
await fetch("/api/settings/website-theme", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ colorTheme: theme }),
})
} catch {
console.warn("Failed to persist color theme")
}
}, [])
return (
<WebsiteThemeContext.Provider value={{ websiteTheme, setWebsiteTheme, colorTheme, setColorTheme, loading }}>
{children}
</WebsiteThemeContext.Provider>
)
}
export function useWebsiteTheme() {
const ctx = useContext(WebsiteThemeContext)
if (!ctx) throw new Error("useWebsiteTheme must be used within WebsiteThemeProvider")
return ctx
}