User settings don't persist: profile changes stale after save, client preferences not stored #36

Closed
opened 2026-04-26 16:45:55 +00:00 by icub3d · 0 comments
Owner

Migrated from GitHub issue icub3d/decentcom#41
Original Author: @icub3d
Original Date: 2026-04-15T20:54:57Z


Summary

User settings don't persist correctly in two areas: profile changes (display name, avatar) and client-side preferences (e.g., theme).


Bug 1: Profile changes appear stale after saving

Root cause

ProfileEditor calls the server API (updateProfile, uploadAvatar, deleteAvatar) and the server returns the updated Member object, but the result is never applied back to useMembersStore. The local store stays stale until the next connect() reloads members from the server.

This means:

  • Closing and reopening the settings panel shows the old display name pre-filled.
  • The avatar doesn't update in the UI immediately after uploading or deleting.
  • Any component reading useMembersStore (e.g. Avatar, ProfilePopover) shows the stale value until reconnect.

The useMembersStore does handle MEMBER_UPDATE gateway events, so the store will eventually update if the server broadcasts the event — but this is not guaranteed to happen synchronously, and the ProfileEditor shouldn't rely on it.

Fix

Add an updateMemberProfile(userId, patch) action to useMembersStore that optimistically updates display_name and/or avatar_hash for a given user. Call it in ProfileEditor after each successful save, using the Member returned by the API.

Files to change:

  • client/src/stores/members.ts — add updateMemberProfile action
  • client/src/components/profile/ProfileEditor.tsx — call updateMemberProfile after updateProfile, uploadAvatar, and set avatar_hash: null after deleteAvatar

Bug 2: Client-side preferences not stored as part of identity

Context

The theme is currently stored in two separate localStorage keys:

  1. decentcom-theme (written by saveTheme in apply.ts)
  2. decentcom-app-storage (written by zustand persist middleware in appStore.ts)

This dual-write is redundant and can lead to subtle divergence.

More importantly, client-side preferences (theme, UI density, notification settings, etc.) are not stored alongside identity. If a user's Tauri data directory is reset or they move to a different device, all preferences are lost.

Recommendation

  • Consolidate theme storage to a single source of truth (remove the manual saveTheme/loadTheme layer and rely solely on zustand persist, or vice versa).
  • Define a UserPreferences type in shared/ or client/ that captures all client-side settings.
  • Consider persisting preferences via Tauri's store plugin (or a Tauri IPC command backed by a file) so they survive WebView cache clears and are co-located with identity data.

Files to consider:

  • client/src/theme/apply.ts
  • client/src/stores/appStore.ts
  • client/src-tauri/ (Tauri core — for a Tauri-backed persistence option)
  • docs/design/identity.md — document the decision on where client prefs live

Steps to reproduce Bug 1

  1. Connect to a server.
  2. Open user settings → set a display name → click Save.
  3. Close the settings panel and reopen it.
  4. Observed: the display name input shows the old (pre-save) value.
  5. Expected: the display name input shows the value that was just saved.
**Migrated from GitHub issue icub3d/decentcom#41** **Original Author:** @icub3d **Original Date:** 2026-04-15T20:54:57Z --- ## Summary User settings don't persist correctly in two areas: **profile changes** (display name, avatar) and **client-side preferences** (e.g., theme). --- ## Bug 1: Profile changes appear stale after saving ### Root cause `ProfileEditor` calls the server API (`updateProfile`, `uploadAvatar`, `deleteAvatar`) and the server returns the updated `Member` object, but the result is **never applied back to `useMembersStore`**. The local store stays stale until the next `connect()` reloads members from the server. This means: - Closing and reopening the settings panel shows the **old** display name pre-filled. - The avatar doesn't update in the UI immediately after uploading or deleting. - Any component reading `useMembersStore` (e.g. `Avatar`, `ProfilePopover`) shows the stale value until reconnect. The `useMembersStore` does handle `MEMBER_UPDATE` gateway events, so the store _will_ eventually update if the server broadcasts the event — but this is not guaranteed to happen synchronously, and the `ProfileEditor` shouldn't rely on it. ### Fix Add an `updateMemberProfile(userId, patch)` action to `useMembersStore` that optimistically updates `display_name` and/or `avatar_hash` for a given user. Call it in `ProfileEditor` after each successful save, using the `Member` returned by the API. Files to change: - `client/src/stores/members.ts` — add `updateMemberProfile` action - `client/src/components/profile/ProfileEditor.tsx` — call `updateMemberProfile` after `updateProfile`, `uploadAvatar`, and set `avatar_hash: null` after `deleteAvatar` --- ## Bug 2: Client-side preferences not stored as part of identity ### Context The theme is currently stored in **two** separate `localStorage` keys: 1. `decentcom-theme` (written by `saveTheme` in `apply.ts`) 2. `decentcom-app-storage` (written by zustand `persist` middleware in `appStore.ts`) This dual-write is redundant and can lead to subtle divergence. More importantly, **client-side preferences** (theme, UI density, notification settings, etc.) are not stored alongside identity. If a user's Tauri data directory is reset or they move to a different device, all preferences are lost. ### Recommendation - Consolidate theme storage to a single source of truth (remove the manual `saveTheme`/`loadTheme` layer and rely solely on zustand `persist`, or vice versa). - Define a `UserPreferences` type in `shared/` or `client/` that captures all client-side settings. - Consider persisting preferences via Tauri's `store` plugin (or a Tauri IPC command backed by a file) so they survive WebView cache clears and are co-located with identity data. Files to consider: - `client/src/theme/apply.ts` - `client/src/stores/appStore.ts` - `client/src-tauri/` (Tauri core — for a Tauri-backed persistence option) - `docs/design/identity.md` — document the decision on where client prefs live --- ## Steps to reproduce Bug 1 1. Connect to a server. 2. Open user settings → set a display name → click Save. 3. Close the settings panel and reopen it. 4. **Observed:** the display name input shows the old (pre-save) value. 5. **Expected:** the display name input shows the value that was just saved.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
icub3d/decentcom#36
No description provided.