修复群邀请消息卡片丢弃"立即加入"按钮,被邀请人无法接受邀请
根因:POST /groups/{topic}/invitations 邀请成功后,后端会往邀请人与被邀请人的
单聊会话里发一条 x-im-type=system_action、template=group_invitation_created 的
消息,content.actions 里带着真实可用的 {type:"group_invitation_accept",
label:"立即加入", target_id:<invitation_id>}(对照参考图 6.3 加入群聊.png)。但
chat-message.jsx 原来对所有 system_action/system_notice 消息一律只取
content.text 渲染成纯文本,这个 action 数据被整体丢弃,消息只显示"邀请你加入群聊。"
没有任何按钮——im-api.js 里封装好的 acceptGroupInvitation() 因此从来没有调用点。
怎么修:chat-message.jsx 在原有的文本兜底之前,单独识别 content.actions 里
type=="group_invitation_accept" 的这一种模板,渲染一张带按钮的小卡片(其余
system_action/system_notice 模板的纯文本渲染保持不变,不受影响);
messages-view.jsx 新增 handleAcceptGroupInvitation,调用 acceptGroupInvitation()
并用已有的 showToast 反馈结果,逐层传给 ChatMessage 的新 onAcceptGroupInvitation
prop。按钮点击后按 busy/joined/pending_approval/error 四态展示,避免重复提交。
验证:用两个真实账号(A 建群,直接对 B 发起 POST /invitations)复现,重新构建后
B 的会话里正确出现"邀请你加入群聊。"+"立即加入"按钮;点击后正确调用
POST /group-invitations/{id}/accept 并把返回的失败原因("服务器繁忙,请稍后重试")
展示出来——这一步暴露了一个独立的后端 500 bug(accept 接口本身的实现有问题,
已记录在测试报告里,不在本次前端修复范围内),前端的请求发起、按钮状态机和错误展示
均已确认按预期工作。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a6014b84ee
commit
cdca509183
@@ -248,6 +248,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
this.handleShowAnnouncement = this.handleShowAnnouncement.bind(this);
|
||||
this.handleShowJoinRequests = this.handleShowJoinRequests.bind(this);
|
||||
this.handleSendFriendVerification = this.handleSendFriendVerification.bind(this);
|
||||
this.handleAcceptGroupInvitation = this.handleAcceptGroupInvitation.bind(this);
|
||||
this.handleBatchDelete = this.handleBatchDelete.bind(this);
|
||||
this.handleBatchFavorite = this.handleBatchFavorite.bind(this);
|
||||
this.handleAttachFile = this.handleAttachFile.bind(this);
|
||||
@@ -1218,6 +1219,21 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
e.preventDefault();
|
||||
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel('', 'friend-verification'), 'uid', this.state.topic));
|
||||
}
|
||||
handleAcceptGroupInvitation(invitationId) {
|
||||
return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.acceptGroupInvitation)(invitationId).then(result => {
|
||||
if (result && result.status == 'joined') {
|
||||
this.showToast('已加入群聊');
|
||||
} else if (result && result.status == 'pending_approval') {
|
||||
this.showToast('申请已提交,等待管理员通过');
|
||||
} else {
|
||||
this.showToast('已处理该邀请');
|
||||
}
|
||||
return result;
|
||||
}).catch(err => {
|
||||
this.showToast(err.message || '加入群聊失败,请重试');
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
showToast(text) {
|
||||
this.setState({
|
||||
toast: text
|
||||
@@ -2055,6 +2071,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
userIsAdmin: this.state.isAdmin,
|
||||
relationship: this.state.relationshipContext ? this.state.relationshipContext.relationship : null,
|
||||
onSendFriendVerification: this.handleSendFriendVerification,
|
||||
onAcceptGroupInvitation: this.handleAcceptGroupInvitation,
|
||||
selectMode: this.props.selectMode,
|
||||
selected: this.props.selectedSeqs && this.props.selectedSeqs.includes(msg.seq),
|
||||
onToggleSelect: this.props.onToggleMessageSelect,
|
||||
@@ -2595,7 +2612,10 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
super(props);
|
||||
this.state = {
|
||||
progress: 0,
|
||||
voicePlayed: isVoicePlayed(props.tinode.getCurrentUserID(), props.topic, props.seq)
|
||||
voicePlayed: isVoicePlayed(props.tinode.getCurrentUserID(), props.topic, props.seq),
|
||||
invitationBusy: false,
|
||||
invitationResult: null,
|
||||
invitationError: null
|
||||
};
|
||||
if (props.uploader) {
|
||||
props.uploader.onProgress = this.handleProgress.bind(this);
|
||||
@@ -2608,6 +2628,7 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
||||
this.handleDraftyClick = this.handleDraftyClick.bind(this);
|
||||
this.handleVoicePlayed = this.handleVoicePlayed.bind(this);
|
||||
this.handleAcceptGroupInvitation = this.handleAcceptGroupInvitation.bind(this);
|
||||
this.formatterContext = {
|
||||
formatMessage: props.intl.formatMessage.bind(props.intl),
|
||||
viewportWidth: props.viewportWidth,
|
||||
@@ -2763,6 +2784,53 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
this.props.onQuoteClick(replyToSeq);
|
||||
}
|
||||
}
|
||||
handleAcceptGroupInvitation(invitationId) {
|
||||
if (this.state.invitationBusy || this.state.invitationResult || !this.props.onAcceptGroupInvitation) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
invitationBusy: true,
|
||||
invitationError: null
|
||||
});
|
||||
this.props.onAcceptGroupInvitation(invitationId).then(result => {
|
||||
this.setState({
|
||||
invitationBusy: false,
|
||||
invitationResult: result && result.status || 'joined'
|
||||
});
|
||||
}).catch(err => {
|
||||
this.setState({
|
||||
invitationBusy: false,
|
||||
invitationError: err && err.message || '操作失败,请重试'
|
||||
});
|
||||
});
|
||||
}
|
||||
renderGroupInvitationCard(text, action) {
|
||||
const {
|
||||
invitationBusy,
|
||||
invitationResult,
|
||||
invitationError
|
||||
} = this.state;
|
||||
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
|
||||
className: "message-group-invitation",
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
|
||||
children: text
|
||||
}, void 0, false), invitationResult == 'joined' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("em", {
|
||||
children: "已加入群聊"
|
||||
}, void 0, false) : invitationResult == 'pending_approval' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("em", {
|
||||
children: "已提交申请,等待管理员通过"
|
||||
}, void 0, false) : invitationResult ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("em", {
|
||||
children: invitationResult
|
||||
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("button", {
|
||||
type: "button",
|
||||
disabled: invitationBusy,
|
||||
onClick: () => this.handleAcceptGroupInvitation(action.target_id),
|
||||
children: invitationBusy ? '处理中…' : action.label || '立即加入'
|
||||
}, void 0, false), invitationError ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("small", {
|
||||
className: "message-group-invitation-error",
|
||||
children: invitationError
|
||||
}, void 0, false) : null]
|
||||
}, void 0, true);
|
||||
}
|
||||
renderFailReason() {
|
||||
if (this.props.response || this.props.received != tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED && this.props.received != tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL) {
|
||||
return null;
|
||||
@@ -2804,7 +2872,12 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
let textSizeClass = 'message-content';
|
||||
const fullDisplay = this.props.isGroup && this.props.response && (this.props.sequence == 'single' || this.props.sequence == 'last');
|
||||
let content = this.props.content;
|
||||
if (this.props.head && (this.props.head['x-im-type'] === 'system_notice' || this.props.head['x-im-type'] === 'system_action') && content && typeof content == 'object' && typeof content.text == 'string') {
|
||||
const systemActions = content && typeof content == 'object' && Array.isArray(content.actions) ? content.actions : null;
|
||||
const inviteAction = this.props.head && this.props.head['x-im-type'] === 'system_action' && systemActions && systemActions.find(a => a && a.type === 'group_invitation_accept');
|
||||
let invitationCard = null;
|
||||
if (inviteAction && typeof content.text == 'string') {
|
||||
invitationCard = this.renderGroupInvitationCard(content.text, inviteAction);
|
||||
} else if (this.props.head && (this.props.head['x-im-type'] === 'system_notice' || this.props.head['x-im-type'] === 'system_action') && content && typeof content == 'object' && typeof content.text == 'string') {
|
||||
content = content.text;
|
||||
}
|
||||
let bundleCard = null;
|
||||
@@ -2880,7 +2953,7 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
className: "content-meta",
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
|
||||
className: textSizeClass,
|
||||
children: [bundleCard || content, attachments]
|
||||
children: [invitationCard || bundleCard || content, attachments]
|
||||
}, void 0, true), this.props.timestamp ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_received_marker_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], {
|
||||
edited: this.props.edited,
|
||||
timestamp: this.props.timestamp,
|
||||
|
||||
Reference in New Issue
Block a user