Add business dashboard dark mode from Super Admin theme setting.
Login and in-app surfaces follow tenant themeMode, matching customer dark tokens, with themed switches and tighter card/table chrome. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
65012717d0
commit
e9400c2281
@@ -2,12 +2,13 @@ import { useEffect, type ReactNode } from 'react'
|
||||
import { isAbortError } from '../lib/api'
|
||||
import { getBusinessDomain } from '../lib/config'
|
||||
import { resolveTenantByDomain } from '../services/tenantService'
|
||||
import { applyBusinessPrimaryColor } from '../utils/applyBusinessTheme'
|
||||
import { applyBusinessPrimaryColor, applyThemeMode } from '../utils/applyBusinessTheme'
|
||||
import { normalizeBusinessPrimaryColorId } from '../utils/businessPrimaryColors'
|
||||
|
||||
/**
|
||||
* Applies the tenant primary color. Does not reset to blue on unmount —
|
||||
* Strict Mode / HMR remounts were wiping the brand color back to the default.
|
||||
* Applies the tenant primary color and dashboard theme mode.
|
||||
* Does not reset to blue on unmount — Strict Mode / HMR remounts were
|
||||
* wiping the brand color back to the default.
|
||||
*/
|
||||
export function BusinessThemeProvider({ children }: { children: ReactNode }) {
|
||||
useEffect(() => {
|
||||
@@ -21,9 +22,11 @@ export function BusinessThemeProvider({ children }: { children: ReactNode }) {
|
||||
applyBusinessPrimaryColor(
|
||||
normalizeBusinessPrimaryColorId(tenant.primaryColor),
|
||||
)
|
||||
applyThemeMode(tenant.themeMode)
|
||||
} catch (err) {
|
||||
if (isAbortError(err) || controller.signal.aborted) return
|
||||
applyBusinessPrimaryColor(undefined)
|
||||
applyThemeMode('light')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,12 @@ import { getBusinessDomain } from '../lib/config'
|
||||
import { BUSINESS_PROFILE_UPDATED_EVENT } from '../lib/businessContext'
|
||||
import { getBusinessProfile } from '../services/businessProfileService'
|
||||
import { resolveTenantByDomain } from '../services/tenantService'
|
||||
import { applyBusinessPrimaryColor } from '../utils/applyBusinessTheme'
|
||||
import {
|
||||
applyBusinessPrimaryColor,
|
||||
applyThemeMode,
|
||||
pickThemedLogoUrl,
|
||||
type DashboardThemeMode,
|
||||
} from '../utils/applyBusinessTheme'
|
||||
import { normalizeBusinessPrimaryColorId } from '../utils/businessPrimaryColors'
|
||||
import {
|
||||
DEFAULT_ENABLED_BUSINESS_MODULES,
|
||||
@@ -31,6 +36,7 @@ interface TenantBrandingContextValue {
|
||||
businessNameEn: string
|
||||
logoUrl: string | null
|
||||
faviconUrl: string | null
|
||||
themeMode: DashboardThemeMode
|
||||
enabledModules: BusinessModuleId[]
|
||||
homeCharts: [HomeChartId, HomeChartId]
|
||||
refreshBranding: () => void
|
||||
@@ -54,6 +60,7 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
const [nameFa, setNameFa] = useState('')
|
||||
const [logoUrl, setLogoUrl] = useState<string | null>(null)
|
||||
const [faviconUrl, setFaviconUrl] = useState<string | null>(null)
|
||||
const [themeMode, setThemeMode] = useState<DashboardThemeMode>('light')
|
||||
const [enabledModules, setEnabledModules] = useState<BusinessModuleId[]>(
|
||||
DEFAULT_ENABLED_BUSINESS_MODULES,
|
||||
)
|
||||
@@ -78,7 +85,13 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
let nextNameEn = pickBusinessName(tenant.name, domain)
|
||||
let nextNameFa = pickBusinessName(tenant.nameFa, tenant.name, domain)
|
||||
let nextLogo = tenant.logoUrl?.trim() || null
|
||||
const nextThemeMode: DashboardThemeMode =
|
||||
tenant.themeMode === 'dark' ? 'dark' : 'light'
|
||||
let nextLogo = pickThemedLogoUrl(
|
||||
tenant.logoUrl,
|
||||
tenant.logoDarkUrl,
|
||||
nextThemeMode,
|
||||
)
|
||||
let nextFavicon =
|
||||
tenant.faviconUrl?.trim() || tenant.logoUrl?.trim() || null
|
||||
|
||||
@@ -96,7 +109,12 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
nextNameFa,
|
||||
domain,
|
||||
)
|
||||
nextLogo = profile.profile.logoUrl?.trim() || nextLogo
|
||||
nextLogo =
|
||||
pickThemedLogoUrl(
|
||||
profile.profile.logoUrl,
|
||||
profile.profile.logoDarkUrl,
|
||||
nextThemeMode,
|
||||
) || nextLogo
|
||||
nextFavicon =
|
||||
profile.profile.faviconUrl?.trim() ||
|
||||
profile.profile.logoUrl?.trim() ||
|
||||
@@ -113,12 +131,14 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
setNameFa(nextNameFa || nextNameEn || domain)
|
||||
setLogoUrl(nextLogo)
|
||||
setFaviconUrl(nextFavicon)
|
||||
setThemeMode(nextThemeMode)
|
||||
setEnabledModules(normalizeEnabledBusinessModules(tenant.enabledModules))
|
||||
setHomeCharts(normalizeHomeCharts(tenant.homeCharts))
|
||||
applyDocumentFavicon(nextFavicon)
|
||||
applyBusinessPrimaryColor(
|
||||
normalizeBusinessPrimaryColorId(tenant.primaryColor),
|
||||
)
|
||||
applyThemeMode(nextThemeMode)
|
||||
if (!defaultLocaleAppliedRef.current) {
|
||||
defaultLocaleAppliedRef.current = true
|
||||
if (tenant.defaultLocale === 'en' || tenant.defaultLocale === 'fa') {
|
||||
@@ -135,10 +155,12 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
setNameFa(domain)
|
||||
setLogoUrl(null)
|
||||
setFaviconUrl(null)
|
||||
setThemeMode('light')
|
||||
setEnabledModules([...DEFAULT_ENABLED_BUSINESS_MODULES])
|
||||
setHomeCharts([...DEFAULT_HOME_CHARTS])
|
||||
applyDocumentFavicon(null)
|
||||
applyBusinessPrimaryColor(undefined)
|
||||
applyThemeMode('light')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +195,7 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
businessNameEn,
|
||||
logoUrl,
|
||||
faviconUrl,
|
||||
themeMode,
|
||||
enabledModules,
|
||||
homeCharts,
|
||||
refreshBranding,
|
||||
@@ -182,6 +205,7 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
|
||||
businessNameEn,
|
||||
logoUrl,
|
||||
faviconUrl,
|
||||
themeMode,
|
||||
enabledModules,
|
||||
homeCharts,
|
||||
refreshBranding,
|
||||
|
||||
Reference in New Issue
Block a user