fix(web): currentPersona 稳定加载——不再因 mount 时无 token/一次失败就退回默认头像
- useAppStore.partialize 持久化 currentPersona:刷新后保持本角色头像/背景 - App.tsx:token 出现即重拉 + 失败 3s 重试,替代一次性 mount 拉取 - 红线:仍只显示当前角色自己的头像/背景,绝不 fallback 其它角色
This commit is contained in:
1 parent
ba8ff835cd
commit
c42aae7797
2 files changed
+31
-13
No files matched your search
+27
-13
@@ -26,24 +26,38 @@ export default function App(): React.ReactNode {
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Load personas once on mount and pick the default one as the web main-session
|
||||
// persona. On failure currentPersona stays null and components fall back to the
|
||||
// neutral default placeholder (never another role's avatar).
|
||||
// Load personas and pick the default one as the web main-session persona. This
|
||||
// must not hinge on a single mount-time fetch: a token may appear (login) after
|
||||
// mount, or the fetch may transiently fail — in which case currentPersona would
|
||||
// stay null and the UI would show a neutral placeholder (or worse, silently
|
||||
// persist a null). We re-run whenever the token appears, and retry on failure.
|
||||
// The resolved persona is also persisted by useAppStore so a refresh keeps the
|
||||
// correct avatar/background.
|
||||
const token = getAuthToken();
|
||||
useEffect(() => {
|
||||
if (!getAuthToken()) return;
|
||||
if (!token) return;
|
||||
let cancelled = false;
|
||||
fetchPersonas()
|
||||
.then((list) => {
|
||||
if (cancelled) return;
|
||||
setCurrentPersona(list.find((p) => p.isDefault) ?? list[0] ?? null);
|
||||
})
|
||||
.catch(() => {
|
||||
// Keep currentPersona null → neutral default placeholder.
|
||||
});
|
||||
let retry: number | null = null;
|
||||
|
||||
const load = () => {
|
||||
if (cancelled) return;
|
||||
fetchPersonas()
|
||||
.then((list) => {
|
||||
if (cancelled) return;
|
||||
setCurrentPersona(list.find((p) => p.isDefault) ?? list[0] ?? null);
|
||||
})
|
||||
.catch(() => {
|
||||
// Transient failure — retry rather than leaving the placeholder forever.
|
||||
if (!cancelled) retry = window.setTimeout(load, 3000);
|
||||
});
|
||||
};
|
||||
load();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
if (retry !== null) window.clearTimeout(retry);
|
||||
};
|
||||
}, [setCurrentPersona]);
|
||||
}, [token, setCurrentPersona]);
|
||||
|
||||
// The M9 modal UI and the admin subsystem (design/10) are two separate shells.
|
||||
// `/admin` is reached via `#/admin`; every admin module is a hash segment.
|
||||
|
||||
@@ -256,6 +256,10 @@ export const useAppStore = create<AppStore>()(
|
||||
mood: s.mood,
|
||||
context: s.context,
|
||||
backthink: s.backthink,
|
||||
// Persist the resolved persona so a refresh keeps showing THIS persona's
|
||||
// own avatar/background — never falling back to a neutral placeholder or
|
||||
// (worse) another role's image because the mount-time fetch missed.
|
||||
currentPersona: s.currentPersona,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user