Skip to content

refactor(frontend): Profile page hub-and-spoke layout#136

Merged
enko merged 2 commits intomainfrom
feat/refactor-profile-tabbed-sections
Mar 16, 2026
Merged

refactor(frontend): Profile page hub-and-spoke layout#136
enko merged 2 commits intomainfrom
feat/refactor-profile-tabbed-sections

Conversation

@enko
Copy link
Copy Markdown
Member

@enko enko commented Mar 16, 2026

Summary

  • Refactors the monolithic 240-line profile page into a hub-and-spoke layout with nested SvelteKit routes
  • Hub at /profile shows a card-grid overview with live status summaries (passkey count, app password count, channel count, etc.)
  • Six dedicated spoke pages: /profile/account, /profile/display, /profile/passkeys, /profile/app-passwords, /profile/messaging, /profile/carddav
  • New ProfileCard reusable component and shared +layout.svelte for page chrome
  • Translates all hardcoded strings in CardDAVSetupGuide component to i18n (EN + DE)

Test plan

  • Navigate to /profile — hub renders with cards and live status summaries
  • Click each card — lands on correct spoke with back-link
  • Back-link returns to hub
  • All 6 spoke pages render existing content identically
  • Responsive: 1-col mobile, 2-col tablet, 3-col desktop
  • CardDAV page displays in German when language is set to DE
  • pnpm --filter frontend check passes with zero new errors

🤖 Generated with Claude Code

</div>
<p class="font-body text-xs text-blue-600 mt-2">
Use your email <strong>{$currentUser?.email}</strong> and an app password to sign in.
{@html $i18n.t('profile.carddav.useCredentials', { email: $currentUser?.email })}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XSS security issue via @html with unescaped user data: The i18n library uses escapeValue=false, but @html bypasses Svelte escaping entirely. The user-controlled email is interpolated into the translation string without HTML-encoding, then injected raw into the DOM. A crafted email could execute arbitrary JavaScript. Suggested fix: split the template so email renders via a normal Svelte expression (auto-escaped) rather than inside @html.

let passkeyCount = $state(0);
let appPasswordCount = $state(0);

onMount(async () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling in onMount API calls: If any of the three parallel API calls rejects (network error, auth expiry, etc.), Promise.all rejects immediately and the passkeyCount / appPasswordCount state variables remain at 0. The hub will silently show 'No passkeys registered' and 'No app passwords' even when the user may have existing records, with no error indicator shown to the user. Suggested fix: wrap the Promise.all in a try/catch so that failures are handled gracefully and counts stay at 0 without crashing the component.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 16, 2026

Automated Code Review - Commit c6a0716 - Reviewed 2026-03-16 - Status Approved - No new issues found. Previously flagged issues resolved: XSS via html+email (now auto-escaped), silent onMount failure (try/catch added). AGENTS.md compliant. Clean refactor. Automated review by Claude Code CI run 23167414983

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 1 critical issue (XSS) requiring changes. See inline comments for details.

enko and others added 2 commits March 16, 2026 22:42
…e layout

The profile page was a single 240-line scrollable page with 6 vertically
stacked sections. This refactors it into a hub page at /profile showing
a card-grid overview with live status summaries, and 6 dedicated spoke
pages (account, display, passkeys, app-passwords, messaging, carddav)
each with their own route and back-link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nent

The CardDAV setup guide had all its strings hardcoded in English (server
URL header, copy button, setup steps, field labels, important notice).
Wire up existing profile.carddav.* i18n keys and add new keys for the
step-by-step instructions and field labels in both en.json and de.json.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@enko enko force-pushed the feat/refactor-profile-tabbed-sections branch from b53f00a to c6a0716 Compare March 16, 2026 21:45
@enko enko merged commit 6557154 into main Mar 16, 2026
5 checks passed
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 2.67.4 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant