This commit is contained in:
lendry
2026-06-26 17:49:22 +03:00
parent c23f35e732
commit 4e853f8041
17 changed files with 1547 additions and 167 deletions

View File

@@ -135,6 +135,16 @@ export function FamilyBotChat({
return;
}
const eventScope = payload.scope === 'broadcast' ? 'broadcast' : 'private';
const eventRoomId = typeof payload.roomId === 'string' ? payload.roomId : null;
if (eventScope === 'broadcast') {
if (roomId && eventRoomId && eventRoomId !== roomId) {
return;
}
} else if (roomId) {
// Личные сообщения бота не транслируются другим участникам комнаты.
}
if (event.type === 'bot_message') {
const messageId = Number(payload.messageId);
if (!Number.isFinite(messageId)) {
@@ -144,8 +154,9 @@ export function FamilyBotChat({
const replyMarkupJson = markupJsonFromPayload(payload);
const outbound: BotChatMessage = {
id: `out-ws-${messageId}`,
id: `${eventScope === 'broadcast' ? 'broadcast' : 'out'}-ws-${messageId}`,
direction: 'out',
scope: eventScope,
text: typeof payload.text === 'string' ? payload.text : '',
messageType: typeof payload.messageType === 'string' ? payload.messageType : 'text',
messageId,
@@ -156,7 +167,9 @@ export function FamilyBotChat({
};
setMessages((current) => {
const withoutDuplicate = current.filter((item) => item.messageId !== messageId || item.direction !== 'out');
const withoutDuplicate = current.filter(
(item) => item.messageId !== messageId || item.direction !== 'out' || item.scope !== eventScope
);
return [...withoutDuplicate, outbound].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
});
return;
@@ -191,7 +204,7 @@ export function FamilyBotChat({
const replyMarkupJson = markupJsonFromPayload(payload);
setMessages((current) =>
current.map((item) =>
item.messageId === messageId && item.direction === 'out'
item.messageId === messageId && item.direction === 'out' && (item.scope ?? 'private') === eventScope
? {
...item,
text: typeof payload.text === 'string' ? payload.text : item.text,
@@ -212,7 +225,7 @@ export function FamilyBotChat({
setMessages((current) =>
current.map((item) =>
item.messageId === messageId && item.direction === 'out'
item.messageId === messageId && item.direction === 'out' && (item.scope ?? 'private') === eventScope
? {
...item,
isPinned: Boolean(payload.isPinned),
@@ -223,7 +236,7 @@ export function FamilyBotChat({
);
}
});
}, [botRef, loadMessages, subscribe]);
}, [botRef, loadMessages, roomId, subscribe]);
async function handleSend() {
if (!token || !draft.trim() || sending) return;
@@ -271,12 +284,18 @@ export function FamilyBotChat({
) : messages.length ? (
messages.map((message) => {
const mine = message.direction === 'in';
const isBroadcast = message.scope === 'broadcast';
const hasKeyboard = Boolean(message.replyMarkupJson?.trim());
return (
<div key={message.id} id={`bot-msg-${message.id}`} className={cn('flex', mine ? 'justify-end' : 'justify-start')}>
<BotChatMessageContextMenu text={message.text} onCopy={() => showToast('Текст скопирован')}>
<div className={cn('max-w-[78%] rounded-[18px] px-3 py-2 shadow-sm', mine ? 'rounded-br-md bg-[#effdde]' : 'rounded-bl-md bg-white')}>
{!mine ? <p className="mb-0.5 text-[11px] font-semibold text-[#3390ec]">{botName}</p> : null}
{!mine ? (
<p className="mb-0.5 text-[11px] font-semibold text-[#3390ec]">
{botName}
{isBroadcast ? ' · уведомление' : ''}
</p>
) : null}
<p className="whitespace-pre-wrap text-sm">{message.text || '…'}</p>
{!mine && hasKeyboard && message.messageId > 0 ? (
<BotMessageKeyboard