Apply tenant theme on business login and polish login branding.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-07 18:37:13 +03:30
co-authored by Cursor
parent 56f6b23074
commit a48a24e6f2
12 changed files with 122 additions and 52 deletions
@@ -16,6 +16,7 @@ import { resolveTenantByDomain } from '../services/tenantService'
interface TenantBrandingContextValue {
businessName: string
businessNameEn: string
logoUrl: string | null
faviconUrl: string | null
}
@@ -35,6 +36,7 @@ function pickBusinessName(
export function TenantBrandingProvider({ children }: { children: ReactNode }) {
const { setLocale } = useLocale()
const [businessName, setBusinessName] = useState('')
const [businessNameEn, setBusinessNameEn] = useState('')
const [logoUrl, setLogoUrl] = useState<string | null>(null)
const [faviconUrl, setFaviconUrl] = useState<string | null>(null)
const defaultLocaleAppliedRef = useRef(false)
@@ -59,6 +61,7 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
tenant.name,
domain,
)
const nameEn = pickBusinessName(info?.name, tenant.name, domain)
const nextLogo =
info?.logoUrl?.trim() || tenant.logoUrl?.trim() || null
@@ -69,6 +72,7 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
null
setBusinessName(name || domain)
setBusinessNameEn(nameEn || domain)
setLogoUrl(nextLogo)
setFaviconUrl(nextFavicon)
applyDocumentFavicon(nextFavicon)
@@ -84,6 +88,7 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
} catch (err) {
if (isAbortError(err) || controller.signal.aborted) return
setBusinessName(domain)
setBusinessNameEn(domain)
setLogoUrl(null)
setFaviconUrl(null)
applyDocumentFavicon(null)
@@ -98,8 +103,8 @@ export function TenantBrandingProvider({ children }: { children: ReactNode }) {
}, [domain, setLocale])
const value = useMemo(
() => ({ businessName, logoUrl, faviconUrl }),
[businessName, logoUrl, faviconUrl],
() => ({ businessName, businessNameEn, logoUrl, faviconUrl }),
[businessName, businessNameEn, logoUrl, faviconUrl],
)
return (
@@ -1,10 +1,12 @@
.page {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px;
position: relative;
gap: 20px;
}
.card {
@@ -60,6 +62,18 @@
margin-top: 2px;
}
.poweredBy {
font-size: 12px;
font-weight: 500;
color: var(--text-muted);
text-align: center;
transition: color 0.2s;
}
.poweredBy:hover {
color: var(--primary);
}
.title {
font-size: 24px;
font-weight: 700;
+10 -2
View File
@@ -35,7 +35,7 @@ export function LoginPage() {
const [searchParams] = useSearchParams()
const redirectTo = safeRedirectPath(searchParams.get('redirect'))
const { login, loginWithOtp } = useAuth()
const { businessName, logoUrl } = useTenantBranding()
const { businessName, businessNameEn, logoUrl } = useTenantBranding()
const tenantDomain = getTenantDomain()
const t = useT()
@@ -247,7 +247,7 @@ export function LoginPage() {
<img src={logoUrl || meshkeeLogo} alt="" className={styles.logo} />
<div className={styles.brandText}>
<span className={styles.domain}>{businessName || tenantDomain}</span>
<span className={styles.appName}>{t('app.poweredBy')}</span>
<span className={styles.appName}>{businessNameEn || tenantDomain}</span>
</div>
<div className={styles.langSelect}>
<LanguageSelect />
@@ -704,6 +704,14 @@ export function LoginPage() {
</>
)}
</div>
<a
className={styles.poweredBy}
href="https://meshkee.com"
target="_blank"
rel="noopener noreferrer"
>
Powered by Meshkee.app
</a>
</div>
)
}