Skip to content

Bug: Theme "System" never persists — nil optional is omitted, so the route never clears the stored theme #79

Description

@Adron

Same class as #46 (a PATCH /api/user/update body that silently does nothing), found while
reviewing light/dark/system theme support.

Symptom

Settings → Appearance → Theme → System does not stick. Pick Dark, then pick System: the app
stays dark, and the picker snaps back to Dark the next time the sheet syncs from the user.

Root cause

SettingsView.swift:87 maps "system" to nil:

Task { await save(theme: newValue == "system" ? nil : newValue) }

updateUserSettings puts that in a synthesized Encodable struct, and Swift encodes optionals with
encodeIfPresent — so a nil field is omitted, not sent as null. Verified:

system-pick body: {}

The route applies ...(theme !== undefined && { theme }) (app/api/user/update/route.ts:102,157),
so an absent key is a no-op. The response then returns the unchanged user (theme: "dark"),
authState.updateUser stores it, and syncFromUser resets the picker to Dark.

The comment justifying it is wrong

SettingsView.swift:85-86 says:

"system" means no explicit preference — send nil so the server clears it.
Sending the string "system" is rejected or treated as default (light) by the server.

The route performs no validation on theme — it stores whatever string arrives. And the web
stores the literal "system": ThemeProvider defaults to theme = 'system' and writes
localStorage.setItem('theme', themeValue) unconditionally
(components/layout/ThemeProvider.tsx:11,17). "system" is the web's own persisted value.

Fix

  • Send "system" verbatim; delete the nil mapping and the incorrect comment.
  • Unit test asserting the body is {"theme":"system"} — it fails today, where the body is {}.
  • While here: RootView.preferredScheme already treats any non-light/dark value (including
    "system") as "follow the OS", so no change is needed there.

Acceptance criteria

  • Dark → System persists across a GET /api/user refresh and app relaunch.
  • The value round-trips with the web's Settings page.

Files: Views/SettingsView.swift:81-88, InterlinedListTests/APIClientTests/APIClientProfileTests.swift.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingws:moderation-privacyW2 — moderation, privacy, account settings

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions