mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
@@ -11,6 +11,30 @@ export interface AnimationEnabled {
|
|||||||
enabled: boolean
|
enabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BRANDING_CACHE_KEY = 'cabinet_branding'
|
||||||
|
|
||||||
|
// Get cached branding from localStorage
|
||||||
|
export const getCachedBranding = (): BrandingInfo | null => {
|
||||||
|
try {
|
||||||
|
const cached = localStorage.getItem(BRANDING_CACHE_KEY)
|
||||||
|
if (cached) {
|
||||||
|
return JSON.parse(cached)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// localStorage not available or invalid JSON
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update branding cache in localStorage
|
||||||
|
export const setCachedBranding = (branding: BrandingInfo) => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(BRANDING_CACHE_KEY, JSON.stringify(branding))
|
||||||
|
} catch {
|
||||||
|
// localStorage not available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const brandingApi = {
|
export const brandingApi = {
|
||||||
// Get current branding (public, no auth required)
|
// Get current branding (public, no auth required)
|
||||||
getBranding: async (): Promise<BrandingInfo> => {
|
getBranding: async (): Promise<BrandingInfo> => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import TicketNotificationBell from '../TicketNotificationBell'
|
|||||||
import AnimatedBackground from '../AnimatedBackground'
|
import AnimatedBackground from '../AnimatedBackground'
|
||||||
import { contestsApi } from '../../api/contests'
|
import { contestsApi } from '../../api/contests'
|
||||||
import { pollsApi } from '../../api/polls'
|
import { pollsApi } from '../../api/polls'
|
||||||
import { brandingApi } from '../../api/branding'
|
import { brandingApi, getCachedBranding, setCachedBranding } from '../../api/branding'
|
||||||
import { wheelApi } from '../../api/wheel'
|
import { wheelApi } from '../../api/wheel'
|
||||||
import { themeColorsApi } from '../../api/themeColors'
|
import { themeColorsApi } from '../../api/themeColors'
|
||||||
import { promoApi } from '../../api/promo'
|
import { promoApi } from '../../api/promo'
|
||||||
@@ -167,15 +167,21 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
}
|
}
|
||||||
}, [mobileMenuOpen])
|
}, [mobileMenuOpen])
|
||||||
|
|
||||||
// Fetch branding settings
|
// Fetch branding settings with localStorage cache for instant load
|
||||||
const { data: branding } = useQuery({
|
const { data: branding } = useQuery({
|
||||||
queryKey: ['branding'],
|
queryKey: ['branding'],
|
||||||
queryFn: brandingApi.getBranding,
|
queryFn: async () => {
|
||||||
|
const data = await brandingApi.getBranding()
|
||||||
|
setCachedBranding(data) // Update cache
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
initialData: getCachedBranding() ?? undefined, // Use cached data immediately
|
||||||
staleTime: 60000, // 1 minute
|
staleTime: 60000, // 1 minute
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
retry: 1,
|
retry: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Computed branding values - use fallback only if branding not loaded yet
|
// Computed branding values - use fallback only if no branding and no cache
|
||||||
const appName = branding ? branding.name : FALLBACK_NAME // Empty string is valid (logo-only mode)
|
const appName = branding ? branding.name : FALLBACK_NAME // Empty string is valid (logo-only mode)
|
||||||
const logoLetter = branding?.logo_letter || FALLBACK_LOGO
|
const logoLetter = branding?.logo_letter || FALLBACK_LOGO
|
||||||
const hasCustomLogo = branding?.has_custom_logo || false
|
const hasCustomLogo = branding?.has_custom_logo || false
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { adminSettingsApi, SettingDefinition, SettingCategorySummary } from '../api/adminSettings'
|
import { adminSettingsApi, SettingDefinition, SettingCategorySummary } from '../api/adminSettings'
|
||||||
import { brandingApi } from '../api/branding'
|
import { brandingApi, setCachedBranding } from '../api/branding'
|
||||||
import { setCachedAnimationEnabled } from '../components/AnimatedBackground'
|
import { setCachedAnimationEnabled } from '../components/AnimatedBackground'
|
||||||
import { themeColorsApi } from '../api/themeColors'
|
import { themeColorsApi } from '../api/themeColors'
|
||||||
import { DEFAULT_THEME_COLORS, DEFAULT_ENABLED_THEMES } from '../types/theme'
|
import { DEFAULT_THEME_COLORS, DEFAULT_ENABLED_THEMES } from '../types/theme'
|
||||||
@@ -882,7 +882,8 @@ export default function AdminSettings() {
|
|||||||
|
|
||||||
const updateNameMutation = useMutation({
|
const updateNameMutation = useMutation({
|
||||||
mutationFn: (name: string) => brandingApi.updateName(name),
|
mutationFn: (name: string) => brandingApi.updateName(name),
|
||||||
onSuccess: () => {
|
onSuccess: (data) => {
|
||||||
|
setCachedBranding(data) // Update cache immediately
|
||||||
queryClient.invalidateQueries({ queryKey: ['branding'] })
|
queryClient.invalidateQueries({ queryKey: ['branding'] })
|
||||||
setEditingName(false)
|
setEditingName(false)
|
||||||
},
|
},
|
||||||
@@ -890,14 +891,16 @@ export default function AdminSettings() {
|
|||||||
|
|
||||||
const uploadLogoMutation = useMutation({
|
const uploadLogoMutation = useMutation({
|
||||||
mutationFn: (file: File) => brandingApi.uploadLogo(file),
|
mutationFn: (file: File) => brandingApi.uploadLogo(file),
|
||||||
onSuccess: () => {
|
onSuccess: (data) => {
|
||||||
|
setCachedBranding(data) // Update cache immediately
|
||||||
queryClient.invalidateQueries({ queryKey: ['branding'] })
|
queryClient.invalidateQueries({ queryKey: ['branding'] })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const deleteLogoMutation = useMutation({
|
const deleteLogoMutation = useMutation({
|
||||||
mutationFn: () => brandingApi.deleteLogo(),
|
mutationFn: () => brandingApi.deleteLogo(),
|
||||||
onSuccess: () => {
|
onSuccess: (data) => {
|
||||||
|
setCachedBranding(data) // Update cache immediately
|
||||||
queryClient.invalidateQueries({ queryKey: ['branding'] })
|
queryClient.invalidateQueries({ queryKey: ['branding'] })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user