feat(admin-web/auth): support phone-or-email login and dim shell on expiry

Login form takes a phone-or-email identifier; user info now exposes phone
so the shell can fall back through name → phone → email. When membership
expires, the app stays on the current route but renders a minimal blocked
state in the shell instead of redirecting to a dedicated page; an Axios
interceptor flips the local session into the blocked state when the API
returns trial/subscription errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-29 00:01:47 +08:00
parent ee21f512a9
commit 62b824520c
10 changed files with 170 additions and 33 deletions
@@ -94,6 +94,7 @@ const enUS = {
tenantAdminLogin: "Tenant Admin Login",
loginAndEnter: "Sign in to workspace",
email: "Email",
loginIdentifier: "Phone / Email",
password: "Password",
defaultTestAccount: "Default account",
defaultTestPassword: "Default password",
@@ -101,6 +102,7 @@ const enUS = {
membershipBlocked: {
eyebrow: "Access Paused",
title: "This tenant plan is unavailable",
expiredMessage: "Membership expired. Please renew or contact support.",
reasonTrialExpired: "The free trial's 3-day page access window has ended. All business pages are now locked. Please contact an administrator to reactivate trial access.",
reasonRequired: "This tenant does not have an active plan. All business pages are now locked. Please contact an administrator.",
reasonInactive: "This tenant plan has expired or been disabled. All business pages are now locked. Please contact an administrator to restore access.",
@@ -118,6 +120,7 @@ const enUS = {
localeLabel: "Language",
quotaTitle: "Plan & Quota",
quotaStatus: "Healthy",
membershipExpiresAt: "Expires",
remainingQuota: "Article quota",
aiPoints: "AI points",
resetAt: "Reset at",