fix: null display name, settings scrollbar, redundant passkey offer
All checks were successful
CI / build (push) Successful in 2m20s
CI / docker (push) Successful in 1m36s

- Profile API returns empty string instead of "null" when Logto user
  has no display name set (String.valueOf(null) → "null" bug).
- SettingsPage: add overflowY auto + flex 1 so content scrolls within
  the AppShell layout (which uses overflow: hidden).
- Remove redundant passkey offer from onboarding page — passkey
  enrollment now happens during sign-in via the Experience API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-27 18:53:13 +02:00
parent 3384510f3c
commit 67ec409383
3 changed files with 5 additions and 43 deletions

View File

@@ -46,10 +46,12 @@ public class AccountService {
if (user == null) { if (user == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");
} }
Object nameVal = user.get("name");
Object emailVal = user.get("primaryEmail");
return new ProfileData( return new ProfileData(
userId, userId,
String.valueOf(user.getOrDefault("name", "")), nameVal != null ? String.valueOf(nameVal) : "",
String.valueOf(user.getOrDefault("primaryEmail", "")) emailVal != null ? String.valueOf(emailVal) : ""
); );
} }

View File

@@ -20,7 +20,6 @@ export function OnboardingPage() {
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [slugAvailable, setSlugAvailable] = useState<boolean | null>(null); const [slugAvailable, setSlugAvailable] = useState<boolean | null>(null);
const [checkingSlug, setCheckingSlug] = useState(false); const [checkingSlug, setCheckingSlug] = useState(false);
const [showPasskeyOffer, setShowPasskeyOffer] = useState(false);
const debounceRef = useRef<ReturnType<typeof setTimeout>>(undefined); const debounceRef = useRef<ReturnType<typeof setTimeout>>(undefined);
const slug = toSlug(name); const slug = toSlug(name);
@@ -51,17 +50,6 @@ export function OnboardingPage() {
setLoading(true); setLoading(true);
try { try {
await api.post<TenantResponse>('/onboarding/tenant', { name, slug }); await api.post<TenantResponse>('/onboarding/tenant', { name, slug });
// Check if passkeys are enabled in vendor policy
try {
const config = await fetch('/platform/api/config').then(r => r.json());
if (config.vendorAuthPolicy?.passkeyEnabled) {
setShowPasskeyOffer(true);
setLoading(false);
return; // Don't redirect yet
}
} catch {
// Ignore — proceed without passkey offer
}
// Tenant created — force a fresh OIDC sign-in so the Logto SDK gets // Tenant created — force a fresh OIDC sign-in so the Logto SDK gets
// new tokens that include the org membership just created. The existing // new tokens that include the org membership just created. The existing
// Logto session cookie means the user won't see a login form — Logto // Logto session cookie means the user won't see a login form — Logto
@@ -78,34 +66,6 @@ export function OnboardingPage() {
} }
} }
async function handleSkipPasskey() {
await signIn(`${window.location.origin}/platform/callback`);
}
if (showPasskeyOffer) {
return (
<div className={styles.page}>
<div className={styles.wrapper}>
<Card className={styles.card}>
<div className={styles.inner}>
<div style={{ textAlign: 'center' }}>
<h2 style={{ margin: '16px 0 8px' }}>Secure your account</h2>
<p style={{ color: 'var(--text-muted)', marginBottom: 24 }}>
Add a passkey to sign in faster with your fingerprint, face, or security key.
</p>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
<Button variant="secondary" onClick={handleSkipPasskey}>
Set up later
</Button>
</div>
</div>
</Card>
</div>
</div>
);
}
return ( return (
<div className={styles.page}> <div className={styles.page}>
<div className={styles.wrapper}> <div className={styles.wrapper}>

View File

@@ -212,7 +212,7 @@ export function SettingsPage() {
} }
return ( return (
<div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 20 }}> <div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 20, overflowY: 'auto', flex: 1 }}>
<h1 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 600 }}>Settings</h1> <h1 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 600 }}>Settings</h1>
<PasskeyNudgeBanner /> <PasskeyNudgeBanner />