diff --git a/src/views/contact-management-view.jsx b/src/views/contact-management-view.jsx index 3578c44e..6285f29b 100644 --- a/src/views/contact-management-view.jsx +++ b/src/views/contact-management-view.jsx @@ -356,6 +356,20 @@ function Verification({uid, onToast}) { React.useEffect(() => { if (!uid) return; getUserProfile(uid).then(data => { writeCachedData('profile-seed:' + uid, data); setProfile(data); }).catch(() => {}); + // getUserProfile 403s for anyone who isn't currently a friend (server privacy default) -- same + // gap Profile already works around below. Without this, a `profile-seed` left over from *earlier + // in the same session* (e.g. this pair really were friends before one side unfriended them, or a + // request was sent and then rejected) stayed on screen forever: alreadyFriend/alreadyPending read + // straight off `profile.relationship`, and the 403 catch above has nothing to correct it with. + // Confirmed live: unfriend someone, then re-open this exact page for them (still reachable via + // their still-cached, now-stale seed) -- it kept claiming "你们已经是好友了" and hid the compose + // box entirely, with no way to send a new request short of a full page reload to drop the cache. + // getConversationContext isn't gated on friendship and reports the true current relationship. + getConversationContext(uid).then(ctx => { + if (ctx && ctx.relationship) { + setProfile(current => current ? {...current, relationship: ctx.relationship} : current); + } + }).catch(() => {}); }, [uid]); const alreadyPending = profile && (profile.relationship === 'pending_outbound' || profile.relationship === 'pending_inbound'); const alreadyFriend = profile && profile.relationship === 'friend'; @@ -420,9 +434,19 @@ function Profile({uid, friend, onTopicSelected, onToast}) { // handles below. getConversationContext resolves for a P2P conversation regardless of block // status and correctly reports the real relationship, so it's used here purely to refresh that // one field on top of whatever getUserProfile/the seed cache already provided for the rest. + // + // 同时必须把 ctx.capabilities 一起合并进去,不能只更新 relationship:canAdd 这个渲染判断读的是 + // profile.capabilities.can_add_friend,不是 relationship 本身。实测复现:从陌生人搜索结果进来的 + // seed 一直带着 capabilities.can_add_friend=true(搜索时 can_add 确实是 true),发送好友申请后 + // relationship 变成 pending_outbound,可这里原来只覆盖 relationship 字段,capabilities 原样保留 + // 着申请前的 can_add_friend:true——canAdd 分支判断不看 relationship,于是"添加好友"按钮在申请 + // 已发出后继续显示、可以重复点击再次发起申请(配合后端不去重的缺口——新增44——实际造成重复申请)。 + // ctx.capabilities 本身就是服务端针对当前 relationship 算出来的权威值(此时 can_add_friend 已经 + // 是 false),直接一起合并即可,不需要在前端另外推导一套"这些 relationship 不能加好友"的规则。 getConversationContext(uid).then(ctx => { if (ctx && ctx.relationship) { - setProfile(current => current ? {...current, relationship: ctx.relationship} : current); + setProfile(current => current ? {...current, relationship: ctx.relationship, + capabilities: ctx.capabilities || current.capabilities} : current); } }).catch(() => {}); }, [uid]);