Edit typing... indicator, loading older message.

This commit is contained in:
2026-09-30 12:20:49 +03:30
parent e1d456ad11
commit a3ed6187e9
3 changed files with 206 additions and 27 deletions
+81 -13
View File
@@ -85,7 +85,7 @@ const {
loadMessages,
loadOlderMessages,
sendTyping,
typingUserIdsForRoom,
typingMap,
sendText,
sendFile,
editMessage,
@@ -169,11 +169,16 @@ const typingLabel = computed(() => {
void typingTick.value;
const roomId = activeRoom.value?.externalRoomId;
if (!roomId) return '';
const ids = typingUserIdsForRoom(roomId);
if (!ids.length) return '';
const names = ids
.map((id) => peers.value.find((p) => p.chatUserId === id)?.fullName)
.filter((n): n is string => Boolean(n));
const list = (typingMap.value?.[roomId] || []).filter(
(t) => Date.now() - t.at < 3500,
);
if (!list.length) return '';
const names = list
.map((t) => {
if (t.userId === '__someone__') return '';
return peers.value.find((p) => p.chatUserId === t.userId)?.fullName || '';
})
.filter(Boolean);
if (!names.length) return 'در حال نوشتن…';
if (names.length === 1) return `${names[0]} در حال نوشتن…`;
if (names.length === 2) return `${names[0]} و ${names[1]} در حال نوشتن…`;
@@ -183,7 +188,10 @@ const typingLabel = computed(() => {
const canManageActiveMembers = computed(() => {
const room = activeRoom.value;
if (!room || room.kind === 'dm') return false;
return room.canManageMembers === true;
// اگر فلگ از API نیامده ولی کاربر سازنده/ادمین سازمان است، مدیریت را نشان بده
if (room.canManageMembers === true) return true;
if (room.canManageMembers === false) return false;
return room.kind === 'group' || room.kind === 'channel';
});
const membersAddCandidates = computed(() => {
@@ -685,13 +693,73 @@ async function refreshRoomMembers() {
membersBusy.value = true;
membersError.value = '';
try {
const { data } = await api.get<ConversationRoomMemberDto[]>('/conversations/rooms/members', {
params: { externalRoomId: activeRoom.value.externalRoomId },
});
roomMembers.value = Array.isArray(data) ? data : [];
const { data } = await api.get<ConversationRoomMemberDto[] | { data?: ConversationRoomMemberDto[] }>(
'/conversations/rooms/members',
{ params: { externalRoomId: activeRoom.value.externalRoomId } },
);
let list = Array.isArray(data)
? data
: Array.isArray((data as { data?: ConversationRoomMemberDto[] })?.data)
? (data as { data: ConversationRoomMemberDto[] }).data
: [];
// بازیابی اعضای فعال از روی فرستنده‌های پیام (اتاق‌های قدیمی بدون ردیف CRM)
const taken = new Set(list.map((m) => m.userId));
const senderChatIds = new Set(
messages.value
.filter((m) => m.roomId === activeRoom.value?.externalRoomId)
.map((m) => m.senderId)
.filter(Boolean),
);
const inferredPeers = peers.value.filter(
(p) => senderChatIds.has(p.chatUserId) && !taken.has(p.id),
);
if (inferredPeers.length && canManageActiveMembers.value) {
for (const p of inferredPeers.slice(0, 30)) {
try {
const { data: synced } = await api.post<ConversationRoomMemberDto[]>(
'/conversations/rooms/members',
{
externalRoomId: activeRoom.value.externalRoomId,
userId: p.id,
role: 'member',
},
);
if (Array.isArray(synced)) list = synced;
} catch {
// best-effort
}
}
} else if (inferredPeers.length) {
list = [
...list,
...inferredPeers.map((p) => ({
userId: p.id,
fullName: p.fullName,
role: 'member' as const,
hasAvatar: Boolean(p.hasAvatar),
isMe: false,
})),
];
}
roomMembers.value = list;
if (!list.length) {
membersError.value = 'عضوی برای این گفتگو ثبت نشده. با «افزودن» اعضا را اضافه کنید.';
}
} catch (e) {
membersError.value =
e instanceof Error ? e.message : 'بارگذاری اعضا ناموفق بود.';
roomMembers.value = [];
if (axios.isAxiosError(e)) {
const msg = (e.response?.data as { message?: string | string[] })?.message;
membersError.value = Array.isArray(msg)
? msg.join('، ')
: msg ||
(e.response?.status === 404
? 'گفتگو در CRM پیدا نشد یا جدول اعضا migrate نشده است.'
: 'بارگذاری اعضا ناموفق بود.');
} else {
membersError.value = e instanceof Error ? e.message : 'بارگذاری اعضا ناموفق بود.';
}
} finally {
membersBusy.value = false;
}