feat: add customizable business branding (name, logo, colors)
Add admin settings for business branding with name, logo upload, and color scheme via CSS custom properties. Includes database migration, API endpoints, admin settings page, and dynamic branding in both admin nav and customer portal. Closes #61 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
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) 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user