diff --git a/src/pages/support/components/AdminSupportMessages.vue b/src/pages/support/components/AdminSupportMessages.vue index 7f3550f..d79d826 100644 --- a/src/pages/support/components/AdminSupportMessages.vue +++ b/src/pages/support/components/AdminSupportMessages.vue @@ -63,7 +63,7 @@ " :style="{ opacity: getSwipeOpacity(message.id) }" > - ↩ +
-
↩
+
@@ -904,6 +908,8 @@ AdminSupport .admin-bubble__image-wrap { .admin-day-group { display: block; + position: relative; + isolation: isolate; } .admin-day-sticky { @@ -923,12 +929,13 @@ AdminSupport .admin-bubble__image-wrap { justify-content: center; padding: 7px 14px; border-radius: 999px; - background: color-mix(in srgb, var(--admin-bg-elevated, #fff) 88%, transparent); + background: var(--admin-bg-elevated, #fff); border: 1px solid var(--admin-border, #e4e4e7); color: var(--admin-text-muted, #3f3f46); - backdrop-filter: blur(8px); font-size: 12px; font-weight: 700; + line-height: 1.4; + white-space: nowrap; box-shadow: 0 6px 20px var(--admin-shadow, rgba(15, 23, 42, 0.06)); } @@ -1210,11 +1217,14 @@ AdminSupport .admin-bubble__image-wrap { display: inline-flex; align-items: center; justify-content: center; - font-size: 18px; line-height: 1; box-shadow: 0 6px 14px rgba(15, 23, 42, 0.045); } +.admin-reply-button :deep(svg) { + display: block; +} + .admin-typing { display: flex; align-items: center; @@ -1660,7 +1670,6 @@ AdminSupport .admin-bubble__image-wrap { width: 32px; height: 32px; flex: 0 0 32px; - font-size: 17px; } .admin-message-row--out .admin-reply-button { @@ -1858,7 +1867,7 @@ html.is-dark .admin-jump-bottom, html.is-dark .admin-day-chip { color: var(--admin-text-muted); border-color: var(--admin-border); - background: color-mix(in srgb, var(--admin-bg-elevated) 92%, transparent); + background: var(--admin-bg-elevated); } html.is-dark .admin-bubble--in { @@ -1927,8 +1936,24 @@ html.is-dark .admin-reply-swipe-cue { color: var(--admin-gold-light, var(--colorPrimary, #2563eb)); } +html.is-dark .admin-bubble--in .admin-message__reply, +html.is-dark .admin-bubble--out .admin-message__reply { + background: var(--admin-bg-muted) !important; +} + +html.is-dark .admin-bubble--in .admin-message__reply-title { + color: var(--admin-gold-light, var(--colorPrimary, #2563eb)) !important; +} + html.is-dark .admin-bubble--in .admin-message__reply-text { - color: var(--admin-text-secondary); + color: var(--admin-text) !important; + opacity: 0.92; +} + +html.is-dark .admin-bubble--out .admin-message__reply-title, +html.is-dark .admin-bubble--out .admin-message__reply-text { + color: var(--admin-text) !important; + opacity: 0.92; } html.is-dark .typing-dot { diff --git a/src/utils/adminChat.ts b/src/utils/adminChat.ts index 6a1d506..9a6daf7 100644 --- a/src/utils/adminChat.ts +++ b/src/utils/adminChat.ts @@ -40,6 +40,7 @@ type PendingOutgoingAdminMessage = { type: AdminOutgoingMessageType room_id: string content: string + reply?: string } optimisticKey: string | null attempts: number @@ -908,7 +909,8 @@ const appendOptimisticAdminMessage = ( roomId: string, content: string, messageId: string, - typeContent: AdminOutgoingMessageType = 'text' + typeContent: AdminOutgoingMessageType = 'text', + replyId: string | null = null ) => { const optimistic = normalizeMessage( { @@ -918,6 +920,7 @@ const appendOptimisticAdminMessage = ( content, type_content: typeContent, type: typeContent, + reply: replyId || undefined, created_at: new Date().toISOString() }, 'optimistic' @@ -1348,7 +1351,7 @@ export const fetchAdminRooms = async () => { const existing = existingMap.get(roomId) const serverUnread = Number(room?.unread_count ?? room?.unreadCount ?? 0) const localUnread = Number(existing?.unread_count ?? existing?.unreadCount ?? 0) - const unread = isViewingRoomNow(roomId) + const unread = canTreatAdminRoomAsRead(roomId) ? 0 : Math.max(serverUnread, localUnread) @@ -1513,7 +1516,7 @@ export const setAdminActiveRoom = async ( refreshFocusHeartbeat() - if (isViewingRoomNow(roomId)) { + if (isViewingRoomNow(roomId) && isAdminActiveRoomAtBottom.value) { clearRoomUnread(roomId) } @@ -1550,9 +1553,11 @@ export const setAdminActiveRoom = async ( export const sendAdminMessage = async ( roomId: string, content: string, - type: AdminOutgoingMessageType = 'text' + type: AdminOutgoingMessageType = 'text', + replyId: string | null = null ) => { const value = content.trim() + const reply = replyId ? String(replyId).trim() : '' if (!roomId) throw new Error('room_id is required') if (!value) return @@ -1570,15 +1575,25 @@ export const sendAdminMessage = async ( } const messageId = createUuid() - const optimisticKey = appendOptimisticAdminMessage(roomId, value, messageId, type) + const optimisticKey = appendOptimisticAdminMessage( + roomId, + value, + messageId, + type, + reply || null + ) - const payload = { + const payload: PendingOutgoingAdminMessage['payload'] = { id: messageId, type, room_id: roomId, content: value } + if (reply) { + payload.reply = reply + } + pendingOutgoingById.set(messageId, { payload, optimisticKey, @@ -1596,8 +1611,12 @@ export const sendAdminMessage = async ( } } -export const sendAdminTextMessage = async (roomId: string, content: string) => { - return await sendAdminMessage(roomId, content, 'text') +export const sendAdminTextMessage = async ( + roomId: string, + content: string, + replyId: string | null = null +) => { + return await sendAdminMessage(roomId, content, 'text', replyId) } export const sendAdminMediaMessage = async (