ae9afab5a5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
1.5 KiB
TypeScript
56 lines
1.5 KiB
TypeScript
import { createContext, useContext, useEffect, useState, useCallback } from "react";
|
|
|
|
export interface Branding {
|
|
businessName: string;
|
|
primaryColor: string;
|
|
accentColor: string;
|
|
logoBase64: string | null;
|
|
logoMimeType: string | null;
|
|
}
|
|
|
|
const DEFAULT_BRANDING: Branding = {
|
|
businessName: "GroomBook",
|
|
primaryColor: "#4f8a6f",
|
|
accentColor: "#8b7355",
|
|
logoBase64: null,
|
|
logoMimeType: null,
|
|
};
|
|
|
|
const BrandingContext = createContext<{
|
|
branding: Branding;
|
|
refresh: () => void;
|
|
}>({ branding: DEFAULT_BRANDING, refresh: () => {} });
|
|
|
|
export function useBranding() {
|
|
return useContext(BrandingContext);
|
|
}
|
|
|
|
export function BrandingProvider({ children }: { children: React.ReactNode }) {
|
|
const [branding, setBranding] = useState<Branding>(DEFAULT_BRANDING);
|
|
|
|
const fetchBranding = useCallback(() => {
|
|
fetch("/api/branding")
|
|
.then((r) => (r.ok ? r.json() : null))
|
|
.then((data) => {
|
|
if (data && typeof data.businessName === "string") setBranding(data);
|
|
})
|
|
.catch(() => {});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
fetchBranding();
|
|
}, [fetchBranding]);
|
|
|
|
// Apply CSS custom properties whenever branding changes
|
|
useEffect(() => {
|
|
document.documentElement.style.setProperty("--color-primary", branding.primaryColor);
|
|
document.documentElement.style.setProperty("--color-accent", branding.accentColor);
|
|
}, [branding.primaryColor, branding.accentColor]);
|
|
|
|
return (
|
|
<BrandingContext.Provider value={{ branding, refresh: fetchBranding }}>
|
|
{children}
|
|
</BrandingContext.Provider>
|
|
);
|
|
}
|