feat: improve public user identity fallbacks
This commit is contained in:
parent
c622d0b1d2
commit
5f1b59be70
@ -59,14 +59,20 @@ export default function Header({
|
||||
const isLoading = useUserStore((state) => state.isLoading);
|
||||
const role: UserRole = user?.role ?? "guest";
|
||||
const badge = ROLE_BADGES[role];
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail({
|
||||
email: user?.email,
|
||||
role,
|
||||
});
|
||||
const accountLabel =
|
||||
user?.name ?? user?.username ?? user?.email ?? "Guest user";
|
||||
user?.name ??
|
||||
user?.username ??
|
||||
(shouldRenderPublicEmail ? user?.email : undefined) ??
|
||||
"Guest user";
|
||||
const accountInitial = resolveAccountInitial(accountLabel);
|
||||
const statusBadge = isLoading ? "Syncing" : badge.label;
|
||||
const badgeClasses = isLoading
|
||||
? "bg-[var(--color-surface-muted)] text-[var(--color-text-subtle)] opacity-70"
|
||||
: badge.className;
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail(user?.email);
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-30 overflow-hidden border-b border-[color:var(--color-surface-border)] bg-[var(--color-surface-elevated)] text-[var(--color-text)] shadow-[var(--shadow-soft)] backdrop-blur-xl transition-colors">
|
||||
|
||||
@ -58,11 +58,14 @@ export default function Navbar() {
|
||||
const user = useUserStore((state) => state.user);
|
||||
const nav = translations[language].nav;
|
||||
const accountCopy = nav.account;
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail({
|
||||
email: user?.email,
|
||||
role: user?.role,
|
||||
});
|
||||
const accountInitial =
|
||||
user?.username?.charAt(0)?.toUpperCase() ??
|
||||
user?.email?.charAt(0)?.toUpperCase() ??
|
||||
(shouldRenderPublicEmail ? user?.email?.charAt(0)?.toUpperCase() : null) ??
|
||||
"?";
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail(user?.email);
|
||||
const [accountMenuOpen, setAccountMenuOpen] = useState(false);
|
||||
const accountMenuRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
|
||||
@ -41,14 +41,17 @@ export default function UnifiedNavigation() {
|
||||
const user = useUserStore((state) => state.user);
|
||||
const { toggleOpen } = useMoltbotStore();
|
||||
const nav = translations[language].nav;
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail({
|
||||
email: user?.email,
|
||||
role: user?.role,
|
||||
});
|
||||
const accountInitial =
|
||||
user?.username?.charAt(0)?.toUpperCase() ??
|
||||
user?.email?.charAt(0)?.toUpperCase() ??
|
||||
(shouldRenderPublicEmail ? user?.email?.charAt(0)?.toUpperCase() : null) ??
|
||||
"?";
|
||||
const [accountMenuOpen, setAccountMenuOpen] = useState(false);
|
||||
const accountMenuRef = useRef<HTMLDivElement | null>(null);
|
||||
const isChinese = language === "zh";
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail(user?.email);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
@ -25,7 +25,18 @@ describe("publicUserIdentity", () => {
|
||||
});
|
||||
|
||||
it("detects whether a public email should be rendered", () => {
|
||||
expect(hasPublicUserEmail("")).toBe(false);
|
||||
expect(hasPublicUserEmail("guest@svc.plus")).toBe(true);
|
||||
expect(hasPublicUserEmail({ email: "" })).toBe(false);
|
||||
expect(
|
||||
hasPublicUserEmail({
|
||||
email: "sandbox@svc.plus",
|
||||
role: "guest",
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasPublicUserEmail({
|
||||
email: "admin@svc.plus",
|
||||
role: "admin",
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,11 +2,15 @@ function normalizeText(value?: string | null): string {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
function normalizeRole(value?: string | null): string {
|
||||
return normalizeText(value).toLowerCase();
|
||||
}
|
||||
|
||||
export function resolvePublicUserEmail(input: {
|
||||
email?: string | null;
|
||||
role?: string | null;
|
||||
}): string {
|
||||
const normalizedRole = normalizeText(input.role).toLowerCase();
|
||||
const normalizedRole = normalizeRole(input.role);
|
||||
if (normalizedRole === "guest") {
|
||||
return "";
|
||||
}
|
||||
@ -14,6 +18,13 @@ export function resolvePublicUserEmail(input: {
|
||||
return normalizeText(input.email);
|
||||
}
|
||||
|
||||
export function hasPublicUserEmail(email?: string | null): boolean {
|
||||
return normalizeText(email).length > 0;
|
||||
export function hasPublicUserEmail(input: {
|
||||
email?: string | null;
|
||||
role?: string | null;
|
||||
}): boolean {
|
||||
if (normalizeRole(input.role) === "guest") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return normalizeText(input.email).length > 0;
|
||||
}
|
||||
|
||||
@ -51,12 +51,16 @@ export default function UserOverview({ hideMfaMainPrompt = false }: UserOverview
|
||||
const logout = useUserStore((state) => state.logout)
|
||||
const [copied, setCopied] = useState(false)
|
||||
const [guestBoundNodeAddress, setGuestBoundNodeAddress] = useState<string | null>(null)
|
||||
const shouldRenderPublicEmail = hasPublicUserEmail({
|
||||
email: user?.email,
|
||||
role: user?.role,
|
||||
})
|
||||
|
||||
const displayName = useMemo(() => resolveDisplayName(user), [user])
|
||||
const uuid = user?.proxyUuid ?? user?.uuid ?? user?.id ?? '—'
|
||||
const vlessUuid = user?.proxyUuid ?? user?.uuid ?? user?.id ?? null
|
||||
const username = user?.username ?? '—'
|
||||
const email = hasPublicUserEmail(user?.email) ? user?.email : '—'
|
||||
const email = shouldRenderPublicEmail ? user?.email : '—'
|
||||
const docsUrl = mfaCopy.actions.docsUrl
|
||||
const isGuestSandboxReadOnly = Boolean(user?.isGuest && user?.isReadOnly)
|
||||
const guestUuidExpiresAtText = useMemo(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user