Merge pull request #43 from BEDOLAGA-DEV/dev

Dev
This commit is contained in:
Egor
2026-01-19 10:33:17 +03:00
committed by GitHub
3 changed files with 41 additions and 8 deletions

View File

@@ -11,6 +11,30 @@ export interface AnimationEnabled {
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 = {
// Get current branding (public, no auth required)
getBranding: async (): Promise<BrandingInfo> => {

View File

@@ -9,7 +9,7 @@ import TicketNotificationBell from '../TicketNotificationBell'
import AnimatedBackground from '../AnimatedBackground'
import { contestsApi } from '../../api/contests'
import { pollsApi } from '../../api/polls'
import { brandingApi } from '../../api/branding'
import { brandingApi, getCachedBranding, setCachedBranding } from '../../api/branding'
import { wheelApi } from '../../api/wheel'
import { themeColorsApi } from '../../api/themeColors'
import { promoApi } from '../../api/promo'
@@ -167,15 +167,21 @@ export default function Layout({ children }: LayoutProps) {
}
}, [mobileMenuOpen])
// Fetch branding settings
// Fetch branding settings with localStorage cache for instant load
const { data: branding } = useQuery({
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
refetchOnWindowFocus: true,
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 logoLetter = branding?.logo_letter || FALLBACK_LOGO
const hasCustomLogo = branding?.has_custom_logo || false

View File

@@ -3,7 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { adminSettingsApi, SettingDefinition, SettingCategorySummary } from '../api/adminSettings'
import { brandingApi } from '../api/branding'
import { brandingApi, setCachedBranding } from '../api/branding'
import { setCachedAnimationEnabled } from '../components/AnimatedBackground'
import { themeColorsApi } from '../api/themeColors'
import { DEFAULT_THEME_COLORS, DEFAULT_ENABLED_THEMES } from '../types/theme'
@@ -882,7 +882,8 @@ export default function AdminSettings() {
const updateNameMutation = useMutation({
mutationFn: (name: string) => brandingApi.updateName(name),
onSuccess: () => {
onSuccess: (data) => {
setCachedBranding(data) // Update cache immediately
queryClient.invalidateQueries({ queryKey: ['branding'] })
setEditingName(false)
},
@@ -890,14 +891,16 @@ export default function AdminSettings() {
const uploadLogoMutation = useMutation({
mutationFn: (file: File) => brandingApi.uploadLogo(file),
onSuccess: () => {
onSuccess: (data) => {
setCachedBranding(data) // Update cache immediately
queryClient.invalidateQueries({ queryKey: ['branding'] })
},
})
const deleteLogoMutation = useMutation({
mutationFn: () => brandingApi.deleteLogo(),
onSuccess: () => {
onSuccess: (data) => {
setCachedBranding(data) // Update cache immediately
queryClient.invalidateQueries({ queryKey: ['branding'] })
},
})