fix: persist status message and timezone across reconnects
CI / Build & Quality Checks (push) Successful in 10m36s
Trigger Desktop Build / trigger (push) Successful in 12s

Status message: Synapse clears status_msg when a user goes offline/reconnects.
Fix by caching to localStorage and re-sending on setOnline(). The sync
effect no longer overwrites the local value with an empty server event.

Timezone: PUT /profile/{userId}/m.tz is MSC1769 (unstable) and not
supported by standard Synapse — save/load silently fails. Fix by using
Matrix account data (im.lotus.timezone) instead, which is fully
supported. Own profile falls back to account data; other users still
try the m.tz profile endpoint (for federated servers that support it).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 21:31:58 -04:00
parent 6a83e67f95
commit b41bfd35c0
3 changed files with 76 additions and 24 deletions
+16 -3
View File
@@ -16,10 +16,23 @@ export function usePresenceUpdater() {
const lastActivityRef = useRef(0);
useEffect(() => {
const userId = mx.getUserId();
const storedStatus = userId ? localStorage.getItem(`lotus-status-msg-${userId}`) ?? '' : '';
const setOnline = () =>
mx.setPresence({ presence: 'online' }).catch(() => undefined);
mx.setPresence({
presence: 'online',
...(storedStatus ? { status_msg: storedStatus } : {}),
}).catch(() => undefined);
const setUnavailable = (statusMsg?: string) =>
mx.setPresence({ presence: 'unavailable', ...(statusMsg ? { status_msg: statusMsg } : {}) }).catch(() => undefined);
mx.setPresence({
presence: 'unavailable',
...(statusMsg
? { status_msg: statusMsg }
: storedStatus
? { status_msg: storedStatus }
: {}),
}).catch(() => undefined);
const setOffline = () =>
mx.setPresence({ presence: 'offline', status_msg: '' }).catch(() => undefined);
@@ -44,7 +57,7 @@ export function usePresenceUpdater() {
// presenceStatus === 'auto' — original activity-tracking behavior.
const startIdleTimer = () => {
clearTimeout(idleTimerRef.current);
idleTimerRef.current = window.setTimeout(() => {
idleTimerRef.current = setTimeout(() => {
isIdleRef.current = true;
setUnavailable();
}, IDLE_TIMEOUT_MS);