@algenium/blocks 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +466 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +467 -165
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React7 from 'react';
|
|
3
3
|
import { createContext, useContext, useState, useCallback, useEffect, useRef, useMemo, useId } from 'react';
|
|
4
|
-
import { ChevronsUpDown, CheckIcon, SearchIcon, Loader2, AlertTriangle, Inbox, CircleIcon, ChevronRightIcon, Monitor, Sun, Moon, Building2, Check, Plus, Languages, FlaskConical, X, Upload, Move, ZoomOut, ZoomIn, RotateCcw, RotateCw, Grid3X3, RefreshCw, XIcon, User, Pencil, Bell, CheckCheck, XCircle, CheckCircle, Info, Trash2, Clock, MapPin, Link, CalendarDays, ExternalLink, ChevronLeft, ChevronRight, HelpCircle,
|
|
4
|
+
import { ChevronsUpDown, CheckIcon, SearchIcon, Loader2, AlertTriangle, Inbox, CircleIcon, ChevronRightIcon, Monitor, Sun, Moon, Building2, Check, Plus, Languages, FlaskConical, X, Upload, Move, ZoomOut, ZoomIn, RotateCcw, RotateCw, Grid3X3, RefreshCw, XIcon, User, Pencil, Bell, CheckCheck, XCircle, CheckCircle, Info, Trash2, Clock, MapPin, Link, CalendarDays, ExternalLink, ChevronLeft, ChevronRight, HelpCircle, Circle, Wifi, WifiOff, MessageSquare, FileIcon, Download, Paperclip, Send, Search, Store, ArrowLeft, Flag, Hash, Lightbulb, Trophy, Plane, Apple, Leaf, Hand, Smile, Play, AlertCircle, VolumeX, Pause, Volume1, Volume2, Settings, PictureInPicture2, Minimize, Maximize, CreditCard, CheckCircle2, BadgeCheck } from 'lucide-react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { useTheme } from 'next-themes';
|
|
7
7
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
@@ -6704,7 +6704,9 @@ function ChatSidebarProvider({
|
|
|
6704
6704
|
const [isLoading, setIsLoading] = useState(false);
|
|
6705
6705
|
const [activeCaseId, setActiveCaseId] = useState(null);
|
|
6706
6706
|
const [activeRoomId, setActiveRoomId] = useState(null);
|
|
6707
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
6707
6708
|
const fetchRef = useRef(fetchConversations);
|
|
6709
|
+
const prevOpenRef = useRef(isOpen);
|
|
6708
6710
|
fetchRef.current = fetchConversations;
|
|
6709
6711
|
const persistOpen = useCallback((open2) => {
|
|
6710
6712
|
setIsOpen(open2);
|
|
@@ -6726,6 +6728,32 @@ function ChatSidebarProvider({
|
|
|
6726
6728
|
useEffect(() => {
|
|
6727
6729
|
void loadConversations();
|
|
6728
6730
|
}, [loadConversations]);
|
|
6731
|
+
useEffect(() => {
|
|
6732
|
+
if (isOpen && !prevOpenRef.current) {
|
|
6733
|
+
void loadConversations();
|
|
6734
|
+
}
|
|
6735
|
+
prevOpenRef.current = isOpen;
|
|
6736
|
+
}, [isOpen, loadConversations]);
|
|
6737
|
+
const clearRoomUnread = useCallback((roomId) => {
|
|
6738
|
+
setConversations(
|
|
6739
|
+
(prev) => prev.map((conv) => ({
|
|
6740
|
+
...conv,
|
|
6741
|
+
rooms: conv.rooms.map(
|
|
6742
|
+
(room) => room.id === roomId ? { ...room, unreadCount: 0 } : room
|
|
6743
|
+
)
|
|
6744
|
+
}))
|
|
6745
|
+
);
|
|
6746
|
+
}, []);
|
|
6747
|
+
const totalUnreadCount = useMemo(
|
|
6748
|
+
() => conversations.reduce(
|
|
6749
|
+
(sum, conv) => sum + conv.rooms.reduce(
|
|
6750
|
+
(roomSum, room) => roomSum + (room.unreadCount ?? 0),
|
|
6751
|
+
0
|
|
6752
|
+
),
|
|
6753
|
+
0
|
|
6754
|
+
),
|
|
6755
|
+
[conversations]
|
|
6756
|
+
);
|
|
6729
6757
|
const toggle = useCallback(() => persistOpen(!isOpen), [isOpen, persistOpen]);
|
|
6730
6758
|
const open = useCallback(() => persistOpen(true), [persistOpen]);
|
|
6731
6759
|
const close = useCallback(() => {
|
|
@@ -6733,6 +6761,7 @@ function ChatSidebarProvider({
|
|
|
6733
6761
|
setView("list");
|
|
6734
6762
|
setActiveCaseId(null);
|
|
6735
6763
|
setActiveRoomId(null);
|
|
6764
|
+
setSearchQuery("");
|
|
6736
6765
|
}, [persistOpen]);
|
|
6737
6766
|
const openChat = useCallback(
|
|
6738
6767
|
(caseId, roomId) => {
|
|
@@ -6774,31 +6803,40 @@ function ChatSidebarProvider({
|
|
|
6774
6803
|
isLoading,
|
|
6775
6804
|
activeCaseId,
|
|
6776
6805
|
activeRoomId,
|
|
6806
|
+
searchQuery,
|
|
6807
|
+
setSearchQuery,
|
|
6808
|
+
totalUnreadCount,
|
|
6777
6809
|
toggle,
|
|
6778
6810
|
open,
|
|
6779
6811
|
close,
|
|
6780
6812
|
openChat,
|
|
6781
6813
|
selectRoom,
|
|
6782
6814
|
back,
|
|
6783
|
-
refetch: loadConversations
|
|
6815
|
+
refetch: loadConversations,
|
|
6816
|
+
clearRoomUnread
|
|
6784
6817
|
};
|
|
6785
6818
|
return /* @__PURE__ */ jsx(ChatSidebarContext.Provider, { value, children });
|
|
6786
6819
|
}
|
|
6787
6820
|
var PING_INTERVAL = 3e4;
|
|
6788
6821
|
var MIN_RECONNECT_DELAY = 1e3;
|
|
6789
6822
|
var MAX_RECONNECT_DELAY = 3e4;
|
|
6823
|
+
var MARK_READ_DEBOUNCE_MS = 1e3;
|
|
6790
6824
|
function useChatRoom(roomId, config, options = {}) {
|
|
6791
6825
|
const {
|
|
6792
6826
|
minReconnectDelay = MIN_RECONNECT_DELAY,
|
|
6793
6827
|
maxReconnectDelay = MAX_RECONNECT_DELAY,
|
|
6794
|
-
pingInterval = PING_INTERVAL
|
|
6828
|
+
pingInterval = PING_INTERVAL,
|
|
6829
|
+
onMarkedRead
|
|
6795
6830
|
} = options;
|
|
6796
6831
|
const [messages, setMessages] = useState([]);
|
|
6797
6832
|
const [isConnected, setIsConnected] = useState(false);
|
|
6798
6833
|
const [error, setError] = useState(null);
|
|
6799
6834
|
const [typingUsers, setTypingUsers] = useState([]);
|
|
6835
|
+
const [onlineUserIds, setOnlineUserIds] = useState([]);
|
|
6836
|
+
const [readReceipts, setReadReceipts] = useState({});
|
|
6800
6837
|
const [hasMoreHistory, setHasMoreHistory] = useState(true);
|
|
6801
6838
|
const [isLoadingHistory, setIsLoadingHistory] = useState(false);
|
|
6839
|
+
const [isInitialLoading, setIsInitialLoading] = useState(false);
|
|
6802
6840
|
const wsRef = useRef(null);
|
|
6803
6841
|
const mountedRef = useRef(true);
|
|
6804
6842
|
const reconnectDelayRef = useRef(minReconnectDelay);
|
|
@@ -6811,8 +6849,13 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6811
6849
|
() => Promise.resolve()
|
|
6812
6850
|
);
|
|
6813
6851
|
const configRef = useRef(config);
|
|
6852
|
+
const onMarkedReadRef = useRef(onMarkedRead);
|
|
6853
|
+
const lastSentWatermarkRef = useRef(null);
|
|
6854
|
+
const pendingMarkRef = useRef(null);
|
|
6855
|
+
const markReadTimerRef = useRef(null);
|
|
6814
6856
|
roomIdRef.current = roomId;
|
|
6815
6857
|
configRef.current = config;
|
|
6858
|
+
onMarkedReadRef.current = onMarkedRead;
|
|
6816
6859
|
const clearTimers = useCallback(() => {
|
|
6817
6860
|
if (reconnectTimerRef.current) {
|
|
6818
6861
|
clearTimeout(reconnectTimerRef.current);
|
|
@@ -6822,7 +6865,74 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6822
6865
|
clearInterval(pingTimerRef.current);
|
|
6823
6866
|
pingTimerRef.current = null;
|
|
6824
6867
|
}
|
|
6868
|
+
if (markReadTimerRef.current) {
|
|
6869
|
+
clearTimeout(markReadTimerRef.current);
|
|
6870
|
+
markReadTimerRef.current = null;
|
|
6871
|
+
}
|
|
6825
6872
|
}, []);
|
|
6873
|
+
const flushMarkRead = useCallback(async () => {
|
|
6874
|
+
const pending = pendingMarkRef.current;
|
|
6875
|
+
const currentRoomId = roomIdRef.current;
|
|
6876
|
+
if (!pending || !currentRoomId) return;
|
|
6877
|
+
const { lastMessageId, lastReadAt } = pending;
|
|
6878
|
+
pendingMarkRef.current = null;
|
|
6879
|
+
if (lastSentWatermarkRef.current && lastSentWatermarkRef.current >= lastReadAt) {
|
|
6880
|
+
return;
|
|
6881
|
+
}
|
|
6882
|
+
const ws = wsRef.current;
|
|
6883
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
6884
|
+
ws.send(
|
|
6885
|
+
JSON.stringify({
|
|
6886
|
+
type: "mark_read",
|
|
6887
|
+
lastMessageId,
|
|
6888
|
+
lastReadAt
|
|
6889
|
+
})
|
|
6890
|
+
);
|
|
6891
|
+
lastSentWatermarkRef.current = lastReadAt;
|
|
6892
|
+
onMarkedReadRef.current?.(currentRoomId);
|
|
6893
|
+
return;
|
|
6894
|
+
}
|
|
6895
|
+
try {
|
|
6896
|
+
const jwt = await configRef.current.getToken();
|
|
6897
|
+
if (!jwt) return;
|
|
6898
|
+
const res = await fetch(
|
|
6899
|
+
`${configRef.current.baseUrl}/rooms/${currentRoomId}/read`,
|
|
6900
|
+
{
|
|
6901
|
+
method: "POST",
|
|
6902
|
+
headers: {
|
|
6903
|
+
Authorization: `Bearer ${jwt}`,
|
|
6904
|
+
"Content-Type": "application/json"
|
|
6905
|
+
},
|
|
6906
|
+
body: JSON.stringify({ lastMessageId, lastReadAt })
|
|
6907
|
+
}
|
|
6908
|
+
);
|
|
6909
|
+
if (res.ok) {
|
|
6910
|
+
lastSentWatermarkRef.current = lastReadAt;
|
|
6911
|
+
onMarkedReadRef.current?.(currentRoomId);
|
|
6912
|
+
}
|
|
6913
|
+
} catch {
|
|
6914
|
+
}
|
|
6915
|
+
}, []);
|
|
6916
|
+
const markRead = useCallback(
|
|
6917
|
+
(lastMessageId, lastReadAt) => {
|
|
6918
|
+
if (lastSentWatermarkRef.current && lastSentWatermarkRef.current >= lastReadAt) {
|
|
6919
|
+
return;
|
|
6920
|
+
}
|
|
6921
|
+
const pending = pendingMarkRef.current;
|
|
6922
|
+
if (pending && pending.lastReadAt >= lastReadAt) {
|
|
6923
|
+
return;
|
|
6924
|
+
}
|
|
6925
|
+
pendingMarkRef.current = { lastMessageId, lastReadAt };
|
|
6926
|
+
if (markReadTimerRef.current) {
|
|
6927
|
+
clearTimeout(markReadTimerRef.current);
|
|
6928
|
+
}
|
|
6929
|
+
markReadTimerRef.current = setTimeout(() => {
|
|
6930
|
+
markReadTimerRef.current = null;
|
|
6931
|
+
void flushMarkRead();
|
|
6932
|
+
}, MARK_READ_DEBOUNCE_MS);
|
|
6933
|
+
},
|
|
6934
|
+
[flushMarkRead]
|
|
6935
|
+
);
|
|
6826
6936
|
const loadMoreHistory = useCallback(async () => {
|
|
6827
6937
|
if (!roomIdRef.current || isLoadingHistory || !hasMoreHistory) return;
|
|
6828
6938
|
setIsLoadingHistory(true);
|
|
@@ -6855,6 +6965,7 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6855
6965
|
} catch {
|
|
6856
6966
|
} finally {
|
|
6857
6967
|
setIsLoadingHistory(false);
|
|
6968
|
+
setIsInitialLoading(false);
|
|
6858
6969
|
}
|
|
6859
6970
|
}, [isLoadingHistory, hasMoreHistory]);
|
|
6860
6971
|
const sendMessage = useCallback(
|
|
@@ -6888,6 +6999,7 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6888
6999
|
} catch {
|
|
6889
7000
|
if (mountedRef.current) {
|
|
6890
7001
|
setError("Failed to get authentication token");
|
|
7002
|
+
setIsInitialLoading(false);
|
|
6891
7003
|
}
|
|
6892
7004
|
return;
|
|
6893
7005
|
}
|
|
@@ -6903,6 +7015,7 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6903
7015
|
setError(
|
|
6904
7016
|
err instanceof Error ? err.message : "WebSocket creation failed"
|
|
6905
7017
|
);
|
|
7018
|
+
setIsInitialLoading(false);
|
|
6906
7019
|
}
|
|
6907
7020
|
return;
|
|
6908
7021
|
}
|
|
@@ -6927,9 +7040,23 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6927
7040
|
try {
|
|
6928
7041
|
const msg = JSON.parse(event.data);
|
|
6929
7042
|
switch (msg.type) {
|
|
6930
|
-
case "server_hello":
|
|
7043
|
+
case "server_hello": {
|
|
7044
|
+
const readState = msg.readState;
|
|
7045
|
+
if (readState) {
|
|
7046
|
+
setReadReceipts((prev) => {
|
|
7047
|
+
const next = { ...prev };
|
|
7048
|
+
for (const entry of readState) {
|
|
7049
|
+
const existing = next[entry.userId];
|
|
7050
|
+
if (!existing || existing < entry.lastReadAt) {
|
|
7051
|
+
next[entry.userId] = entry.lastReadAt;
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
return next;
|
|
7055
|
+
});
|
|
7056
|
+
}
|
|
6931
7057
|
void loadMoreHistoryRef.current();
|
|
6932
7058
|
break;
|
|
7059
|
+
}
|
|
6933
7060
|
case "new_message": {
|
|
6934
7061
|
const message = msg.message;
|
|
6935
7062
|
if (!messageIdsRef.current.has(message.id)) {
|
|
@@ -6954,6 +7081,25 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6954
7081
|
});
|
|
6955
7082
|
break;
|
|
6956
7083
|
}
|
|
7084
|
+
case "presence_update": {
|
|
7085
|
+
const ids = msg.onlineUserIds;
|
|
7086
|
+
if (Array.isArray(ids)) {
|
|
7087
|
+
setOnlineUserIds(ids);
|
|
7088
|
+
}
|
|
7089
|
+
break;
|
|
7090
|
+
}
|
|
7091
|
+
case "read_receipt": {
|
|
7092
|
+
const userId = msg.userId;
|
|
7093
|
+
const lastReadAt = msg.lastReadAt;
|
|
7094
|
+
if (userId && lastReadAt) {
|
|
7095
|
+
setReadReceipts((prev) => {
|
|
7096
|
+
const existing = prev[userId];
|
|
7097
|
+
if (existing && existing >= lastReadAt) return prev;
|
|
7098
|
+
return { ...prev, [userId]: lastReadAt };
|
|
7099
|
+
});
|
|
7100
|
+
}
|
|
7101
|
+
break;
|
|
7102
|
+
}
|
|
6957
7103
|
case "pong":
|
|
6958
7104
|
break;
|
|
6959
7105
|
case "error":
|
|
@@ -6990,16 +7136,27 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
6990
7136
|
setIsConnected(false);
|
|
6991
7137
|
setError(null);
|
|
6992
7138
|
setTypingUsers([]);
|
|
7139
|
+
setOnlineUserIds([]);
|
|
7140
|
+
setReadReceipts({});
|
|
6993
7141
|
setHasMoreHistory(true);
|
|
7142
|
+
setIsLoadingHistory(false);
|
|
7143
|
+
setIsInitialLoading(false);
|
|
6994
7144
|
cursorRef.current = null;
|
|
6995
7145
|
messageIdsRef.current = /* @__PURE__ */ new Set();
|
|
7146
|
+
lastSentWatermarkRef.current = null;
|
|
7147
|
+
pendingMarkRef.current = null;
|
|
6996
7148
|
return;
|
|
6997
7149
|
}
|
|
6998
7150
|
setMessages([]);
|
|
6999
7151
|
setTypingUsers([]);
|
|
7152
|
+
setOnlineUserIds([]);
|
|
7153
|
+
setReadReceipts({});
|
|
7000
7154
|
setHasMoreHistory(true);
|
|
7155
|
+
setIsInitialLoading(true);
|
|
7001
7156
|
cursorRef.current = null;
|
|
7002
7157
|
messageIdsRef.current = /* @__PURE__ */ new Set();
|
|
7158
|
+
lastSentWatermarkRef.current = null;
|
|
7159
|
+
pendingMarkRef.current = null;
|
|
7003
7160
|
reconnectDelayRef.current = minReconnectDelay;
|
|
7004
7161
|
void connect();
|
|
7005
7162
|
return () => {
|
|
@@ -7015,12 +7172,16 @@ function useChatRoom(roomId, config, options = {}) {
|
|
|
7015
7172
|
messages,
|
|
7016
7173
|
sendMessage,
|
|
7017
7174
|
sendTyping,
|
|
7175
|
+
markRead,
|
|
7018
7176
|
isConnected,
|
|
7019
7177
|
error,
|
|
7020
7178
|
typingUsers,
|
|
7179
|
+
onlineUserIds,
|
|
7180
|
+
readReceipts,
|
|
7021
7181
|
loadMoreHistory,
|
|
7022
7182
|
hasMoreHistory,
|
|
7023
|
-
isLoadingHistory
|
|
7183
|
+
isLoadingHistory,
|
|
7184
|
+
isInitialLoading
|
|
7024
7185
|
};
|
|
7025
7186
|
}
|
|
7026
7187
|
var roleColors = {
|
|
@@ -7035,21 +7196,27 @@ function ChatRoomView({
|
|
|
7035
7196
|
currentUserId,
|
|
7036
7197
|
config,
|
|
7037
7198
|
roomLabel,
|
|
7199
|
+
caseNumber,
|
|
7038
7200
|
labels = {},
|
|
7039
7201
|
roleLabel,
|
|
7202
|
+
onMarkedRead,
|
|
7040
7203
|
className
|
|
7041
7204
|
}) {
|
|
7042
7205
|
const {
|
|
7043
7206
|
messages,
|
|
7044
7207
|
sendMessage,
|
|
7045
7208
|
sendTyping,
|
|
7209
|
+
markRead,
|
|
7046
7210
|
isConnected,
|
|
7047
7211
|
error,
|
|
7048
7212
|
typingUsers,
|
|
7213
|
+
onlineUserIds,
|
|
7214
|
+
readReceipts,
|
|
7049
7215
|
loadMoreHistory,
|
|
7050
7216
|
hasMoreHistory,
|
|
7051
|
-
isLoadingHistory
|
|
7052
|
-
|
|
7217
|
+
isLoadingHistory,
|
|
7218
|
+
isInitialLoading
|
|
7219
|
+
} = useChatRoom(roomId, config, { onMarkedRead });
|
|
7053
7220
|
const [newMessage, setNewMessage] = useState("");
|
|
7054
7221
|
const [pendingAttachments, setPendingAttachments] = useState([]);
|
|
7055
7222
|
const scrollRef = useRef(null);
|
|
@@ -7057,6 +7224,16 @@ function ChatRoomView({
|
|
|
7057
7224
|
const fileInputRef = useRef(null);
|
|
7058
7225
|
const typingTimeoutRef = useRef(null);
|
|
7059
7226
|
const prevMessageCountRef = useRef(0);
|
|
7227
|
+
const counterpartOnline = useMemo(
|
|
7228
|
+
() => onlineUserIds.some((id) => id !== currentUserId),
|
|
7229
|
+
[onlineUserIds, currentUserId]
|
|
7230
|
+
);
|
|
7231
|
+
useEffect(() => {
|
|
7232
|
+
if (isInitialLoading || messages.length === 0) return;
|
|
7233
|
+
const latest = messages[messages.length - 1];
|
|
7234
|
+
if (!latest) return;
|
|
7235
|
+
markRead(latest.id, latest.createdAt);
|
|
7236
|
+
}, [messages, isInitialLoading, markRead]);
|
|
7060
7237
|
useEffect(() => {
|
|
7061
7238
|
const el = scrollRef.current;
|
|
7062
7239
|
if (!el) return;
|
|
@@ -7169,27 +7346,50 @@ function ChatRoomView({
|
|
|
7169
7346
|
};
|
|
7170
7347
|
const getAttachmentUrl = (attachmentId) => `${config.baseUrl}/rooms/${roomId}/attachments/${attachmentId}`;
|
|
7171
7348
|
const getRoleLabel = (role) => roleLabel ? roleLabel(role) : role;
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7349
|
+
const isMessageSeen = (message) => {
|
|
7350
|
+
if (message.senderId !== currentUserId) return false;
|
|
7351
|
+
return Object.entries(readReceipts).some(
|
|
7352
|
+
([userId, lastReadAt]) => userId !== currentUserId && lastReadAt >= message.createdAt
|
|
7353
|
+
);
|
|
7354
|
+
};
|
|
7355
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col", className), children: [
|
|
7356
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center justify-between border-b px-4 py-2.5", children: [
|
|
7357
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7358
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
7359
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: roomLabel ?? "Chat" }),
|
|
7360
|
+
caseNumber && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground truncate", children: caseNumber })
|
|
7361
|
+
] }),
|
|
7362
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-center gap-1.5", children: [
|
|
7363
|
+
/* @__PURE__ */ jsx(
|
|
7364
|
+
Circle,
|
|
7365
|
+
{
|
|
7366
|
+
className: cn(
|
|
7367
|
+
"h-2 w-2 fill-current",
|
|
7368
|
+
counterpartOnline ? "text-emerald-500" : "text-muted-foreground/40"
|
|
7369
|
+
)
|
|
7370
|
+
}
|
|
7371
|
+
),
|
|
7372
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: counterpartOnline ? labels.online ?? "Online" : labels.offline ?? "Offline" })
|
|
7373
|
+
] })
|
|
7177
7374
|
] }),
|
|
7178
7375
|
/* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
7179
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: isConnected ? /* @__PURE__ */ jsx(Wifi, { className: "h-3.5 w-3.5 text-
|
|
7376
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: isConnected ? /* @__PURE__ */ jsx(Wifi, { className: "h-3.5 w-3.5 text-emerald-500" }) : /* @__PURE__ */ jsx(WifiOff, { className: "h-3.5 w-3.5 text-destructive" }) }) }),
|
|
7180
7377
|
/* @__PURE__ */ jsx(TooltipContent, { children: isConnected ? "Connected" : error ?? "Reconnecting..." })
|
|
7181
7378
|
] }) })
|
|
7182
7379
|
] }),
|
|
7183
7380
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
7184
|
-
/* @__PURE__ */
|
|
7381
|
+
/* @__PURE__ */ jsx(
|
|
7185
7382
|
"div",
|
|
7186
7383
|
{
|
|
7187
7384
|
ref: scrollRef,
|
|
7188
7385
|
onScroll: handleScroll,
|
|
7189
7386
|
className: "flex-1 overflow-y-auto p-3",
|
|
7190
|
-
children: [
|
|
7387
|
+
children: isInitialLoading ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center py-8", children: [
|
|
7388
|
+
/* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground" }),
|
|
7389
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: labels.loading ?? "Loading messages..." })
|
|
7390
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7191
7391
|
isLoadingHistory && /* @__PURE__ */ jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
|
|
7192
|
-
messages.length === 0
|
|
7392
|
+
messages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center py-8 text-center", children: [
|
|
7193
7393
|
/* @__PURE__ */ jsx(
|
|
7194
7394
|
MessageSquare,
|
|
7195
7395
|
{
|
|
@@ -7198,112 +7398,132 @@ function ChatRoomView({
|
|
|
7198
7398
|
}
|
|
7199
7399
|
),
|
|
7200
7400
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.noMessages ?? "No messages yet" })
|
|
7201
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "space-y-4", children: Object.entries(groupedMessages).map(
|
|
7202
|
-
/* @__PURE__ */ jsxs("div", {
|
|
7203
|
-
/* @__PURE__ */
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7401
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "space-y-4", children: Object.entries(groupedMessages).map(
|
|
7402
|
+
([date, dateMessages]) => /* @__PURE__ */ jsxs("div", { children: [
|
|
7403
|
+
/* @__PURE__ */ jsxs("div", { className: "my-3 flex items-center gap-3", children: [
|
|
7404
|
+
/* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" }),
|
|
7405
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 text-xs text-muted-foreground", children: date }),
|
|
7406
|
+
/* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
|
|
7407
|
+
] }),
|
|
7408
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: dateMessages.map((message) => {
|
|
7409
|
+
if (message.senderRole === "system") {
|
|
7410
|
+
return /* @__PURE__ */ jsx(
|
|
7411
|
+
"div",
|
|
7412
|
+
{
|
|
7413
|
+
className: "flex justify-center py-1",
|
|
7414
|
+
children: /* @__PURE__ */ jsxs("div", { className: "inline-flex max-w-[90%] items-center gap-1.5 rounded-full border bg-muted/60 px-3 py-1 text-[11px] text-muted-foreground", children: [
|
|
7415
|
+
/* @__PURE__ */ jsx(Info, { className: "h-3 w-3 flex-shrink-0" }),
|
|
7416
|
+
/* @__PURE__ */ jsx("span", { className: "text-center", children: message.content })
|
|
7417
|
+
] })
|
|
7418
|
+
},
|
|
7419
|
+
message.id
|
|
7420
|
+
);
|
|
7421
|
+
}
|
|
7422
|
+
const isCurrentUser = message.senderId === currentUserId;
|
|
7423
|
+
const seen = isMessageSeen(message);
|
|
7424
|
+
return /* @__PURE__ */ jsxs(
|
|
7425
|
+
"div",
|
|
7426
|
+
{
|
|
7427
|
+
className: cn(
|
|
7428
|
+
"flex gap-2",
|
|
7429
|
+
isCurrentUser ? "flex-row-reverse" : "flex-row"
|
|
7226
7430
|
),
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7431
|
+
children: [
|
|
7432
|
+
/* @__PURE__ */ jsx(
|
|
7433
|
+
"div",
|
|
7434
|
+
{
|
|
7435
|
+
className: cn(
|
|
7436
|
+
"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full text-xs font-medium",
|
|
7437
|
+
roleColors[message.senderRole] ?? roleColors.client
|
|
7438
|
+
),
|
|
7439
|
+
children: (message.senderName ?? message.senderId).split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase()
|
|
7440
|
+
}
|
|
7441
|
+
),
|
|
7442
|
+
/* @__PURE__ */ jsxs(
|
|
7443
|
+
"div",
|
|
7444
|
+
{
|
|
7445
|
+
className: cn(
|
|
7446
|
+
"flex max-w-[80%] flex-col",
|
|
7447
|
+
isCurrentUser ? "items-end" : "items-start"
|
|
7448
|
+
),
|
|
7449
|
+
children: [
|
|
7450
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-0.5 flex items-center gap-1.5", children: [
|
|
7451
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: message.senderName ?? message.senderId.slice(0, 8) }),
|
|
7452
|
+
/* @__PURE__ */ jsx(
|
|
7453
|
+
"span",
|
|
7454
|
+
{
|
|
7455
|
+
className: cn(
|
|
7456
|
+
"rounded px-1 py-0.5 text-[10px] font-medium",
|
|
7457
|
+
roleColors[message.senderRole] ?? ""
|
|
7458
|
+
),
|
|
7459
|
+
children: getRoleLabel(message.senderRole)
|
|
7460
|
+
}
|
|
7461
|
+
),
|
|
7462
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatTime2(message.createdAt) })
|
|
7463
|
+
] }),
|
|
7464
|
+
message.content && /* @__PURE__ */ jsx(
|
|
7465
|
+
"div",
|
|
7239
7466
|
{
|
|
7240
7467
|
className: cn(
|
|
7241
|
-
"rounded px-
|
|
7242
|
-
|
|
7468
|
+
"rounded-2xl px-3 py-2 text-sm shadow-sm",
|
|
7469
|
+
isCurrentUser ? "rounded-br-md bg-primary text-primary-foreground" : "rounded-bl-md bg-muted text-foreground"
|
|
7243
7470
|
),
|
|
7244
|
-
children:
|
|
7471
|
+
children: message.content
|
|
7245
7472
|
}
|
|
7246
7473
|
),
|
|
7247
|
-
/* @__PURE__ */ jsx("
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
]
|
|
7301
|
-
},
|
|
7302
|
-
message.id
|
|
7303
|
-
);
|
|
7304
|
-
}) })
|
|
7305
|
-
] }, date)) })
|
|
7306
|
-
]
|
|
7474
|
+
message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-col gap-1", children: message.attachments.map(
|
|
7475
|
+
(att) => att.mimeType.startsWith("image/") ? /* @__PURE__ */ jsx(
|
|
7476
|
+
"a",
|
|
7477
|
+
{
|
|
7478
|
+
href: getAttachmentUrl(att.id),
|
|
7479
|
+
target: "_blank",
|
|
7480
|
+
rel: "noopener noreferrer",
|
|
7481
|
+
className: "block max-w-[200px] overflow-hidden rounded-lg border",
|
|
7482
|
+
children: /* @__PURE__ */ jsx(
|
|
7483
|
+
"img",
|
|
7484
|
+
{
|
|
7485
|
+
src: getAttachmentUrl(att.id),
|
|
7486
|
+
alt: att.fileName,
|
|
7487
|
+
className: "h-auto w-full object-cover",
|
|
7488
|
+
loading: "lazy"
|
|
7489
|
+
}
|
|
7490
|
+
)
|
|
7491
|
+
},
|
|
7492
|
+
att.id
|
|
7493
|
+
) : /* @__PURE__ */ jsxs(
|
|
7494
|
+
"a",
|
|
7495
|
+
{
|
|
7496
|
+
href: getAttachmentUrl(att.id),
|
|
7497
|
+
target: "_blank",
|
|
7498
|
+
rel: "noopener noreferrer",
|
|
7499
|
+
className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-2 py-1.5 text-xs transition-colors hover:bg-muted",
|
|
7500
|
+
children: [
|
|
7501
|
+
/* @__PURE__ */ jsx(FileIcon, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" }),
|
|
7502
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7503
|
+
/* @__PURE__ */ jsx("p", { className: "truncate font-medium", children: att.fileName }),
|
|
7504
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: formatFileSize(att.fileSize) })
|
|
7505
|
+
] }),
|
|
7506
|
+
/* @__PURE__ */ jsx(Download, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" })
|
|
7507
|
+
]
|
|
7508
|
+
},
|
|
7509
|
+
att.id
|
|
7510
|
+
)
|
|
7511
|
+
) }),
|
|
7512
|
+
isCurrentUser && /* @__PURE__ */ jsx("div", { className: "mt-0.5 flex items-center gap-0.5 text-[10px] text-muted-foreground", children: seen ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7513
|
+
/* @__PURE__ */ jsx(CheckCheck, { className: "h-3 w-3 text-primary" }),
|
|
7514
|
+
/* @__PURE__ */ jsx("span", { children: labels.seen ?? "Seen" })
|
|
7515
|
+
] }) : /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) })
|
|
7516
|
+
]
|
|
7517
|
+
}
|
|
7518
|
+
)
|
|
7519
|
+
]
|
|
7520
|
+
},
|
|
7521
|
+
message.id
|
|
7522
|
+
);
|
|
7523
|
+
}) })
|
|
7524
|
+
] }, date)
|
|
7525
|
+
) })
|
|
7526
|
+
] })
|
|
7307
7527
|
}
|
|
7308
7528
|
),
|
|
7309
7529
|
typingUsers.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 px-3 py-1", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground italic", children: [
|
|
@@ -7398,16 +7618,41 @@ function ChatRoomView({
|
|
|
7398
7618
|
] })
|
|
7399
7619
|
] });
|
|
7400
7620
|
}
|
|
7621
|
+
function Input({ className, type, ...props }) {
|
|
7622
|
+
return /* @__PURE__ */ jsx(
|
|
7623
|
+
"input",
|
|
7624
|
+
{
|
|
7625
|
+
type,
|
|
7626
|
+
"data-slot": "input",
|
|
7627
|
+
className: cn(
|
|
7628
|
+
"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
|
|
7629
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
7630
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
7631
|
+
className
|
|
7632
|
+
),
|
|
7633
|
+
...props
|
|
7634
|
+
}
|
|
7635
|
+
);
|
|
7636
|
+
}
|
|
7401
7637
|
var roomTypeLabels = {
|
|
7402
7638
|
client_agent: "Client \u2194 Agent",
|
|
7403
7639
|
dealer_agent: "Dealer \u2194 Agent"
|
|
7404
7640
|
};
|
|
7641
|
+
var statusToneClasses = {
|
|
7642
|
+
success: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 border-emerald-500/20",
|
|
7643
|
+
warning: "bg-amber-500/10 text-amber-700 dark:text-amber-400 border-amber-500/20",
|
|
7644
|
+
destructive: "bg-destructive/10 text-destructive border-destructive/20",
|
|
7645
|
+
info: "bg-primary/10 text-primary border-primary/20",
|
|
7646
|
+
neutral: "bg-muted text-muted-foreground border-border"
|
|
7647
|
+
};
|
|
7405
7648
|
function ChatSidebar({
|
|
7406
7649
|
currentUserId,
|
|
7407
7650
|
config,
|
|
7408
7651
|
labels = {},
|
|
7409
7652
|
roleLabel,
|
|
7410
7653
|
roomTypeLabel,
|
|
7654
|
+
statusLabel,
|
|
7655
|
+
statusTone,
|
|
7411
7656
|
mobileTopOffset,
|
|
7412
7657
|
className
|
|
7413
7658
|
}) {
|
|
@@ -7418,9 +7663,12 @@ function ChatSidebar({
|
|
|
7418
7663
|
isLoading,
|
|
7419
7664
|
activeCaseId,
|
|
7420
7665
|
activeRoomId,
|
|
7666
|
+
searchQuery,
|
|
7667
|
+
setSearchQuery,
|
|
7421
7668
|
close,
|
|
7422
7669
|
selectRoom,
|
|
7423
|
-
back
|
|
7670
|
+
back,
|
|
7671
|
+
clearRoomUnread
|
|
7424
7672
|
} = useChatSidebar();
|
|
7425
7673
|
useEffect(() => {
|
|
7426
7674
|
if (!isOpen || typeof window === "undefined") return;
|
|
@@ -7436,12 +7684,24 @@ function ChatSidebar({
|
|
|
7436
7684
|
document.body.style.overflow = "";
|
|
7437
7685
|
};
|
|
7438
7686
|
}, [isOpen]);
|
|
7687
|
+
const filteredConversations = useMemo(() => {
|
|
7688
|
+
const q = searchQuery.trim().toLowerCase();
|
|
7689
|
+
if (!q) return conversations;
|
|
7690
|
+
return conversations.filter(
|
|
7691
|
+
(c) => c.caseNumber.toLowerCase().includes(q) || (c.clientName?.toLowerCase().includes(q) ?? false)
|
|
7692
|
+
);
|
|
7693
|
+
}, [conversations, searchQuery]);
|
|
7439
7694
|
if (!isOpen) return null;
|
|
7440
7695
|
const getRoomTypeLabel = (type) => {
|
|
7441
7696
|
if (roomTypeLabel) return roomTypeLabel(type);
|
|
7442
7697
|
return roomTypeLabels[type] ?? type;
|
|
7443
7698
|
};
|
|
7699
|
+
const getStatusLabel = (status) => statusLabel ? statusLabel(status) : status;
|
|
7700
|
+
const getStatusTone = (status) => statusTone?.(status) ?? "neutral";
|
|
7444
7701
|
const activeConversation = activeCaseId ? conversations.find((c) => c.caseId === activeCaseId) : null;
|
|
7702
|
+
const activeRoom = activeConversation?.rooms.find(
|
|
7703
|
+
(r2) => r2.id === activeRoomId
|
|
7704
|
+
);
|
|
7445
7705
|
const cssVars = {
|
|
7446
7706
|
"--sidebar-top": mobileTopOffset ?? "0px"
|
|
7447
7707
|
};
|
|
@@ -7472,40 +7732,88 @@ function ChatSidebar({
|
|
|
7472
7732
|
}
|
|
7473
7733
|
)
|
|
7474
7734
|
] }),
|
|
7735
|
+
/* @__PURE__ */ jsx("div", { className: "border-b px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
7736
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
|
|
7737
|
+
/* @__PURE__ */ jsx(
|
|
7738
|
+
Input,
|
|
7739
|
+
{
|
|
7740
|
+
value: searchQuery,
|
|
7741
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
7742
|
+
placeholder: labels.searchPlaceholder ?? "Search by case or client...",
|
|
7743
|
+
className: "h-8 pl-8 text-sm"
|
|
7744
|
+
}
|
|
7745
|
+
)
|
|
7746
|
+
] }) }),
|
|
7475
7747
|
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(Loader2, { className: "h-5 w-5 animate-spin text-muted-foreground" }) }) : conversations.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center px-4", children: [
|
|
7476
7748
|
/* @__PURE__ */ jsx(MessageSquare, { className: "mb-3 h-8 w-8 text-muted-foreground/50" }),
|
|
7477
7749
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.noConversations ?? "No conversations yet" })
|
|
7478
|
-
] }) : /* @__PURE__ */
|
|
7479
|
-
/* @__PURE__ */
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
"
|
|
7750
|
+
] }) : filteredConversations.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center px-4", children: [
|
|
7751
|
+
/* @__PURE__ */ jsx(Search, { className: "mb-3 h-8 w-8 text-muted-foreground/50" }),
|
|
7752
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.noResults ?? "No matching conversations" })
|
|
7753
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "space-y-2 p-3", children: filteredConversations.map((conv) => {
|
|
7754
|
+
const caseUnread = conv.rooms.reduce(
|
|
7755
|
+
(sum, r2) => sum + (r2.unreadCount ?? 0),
|
|
7756
|
+
0
|
|
7757
|
+
);
|
|
7758
|
+
return /* @__PURE__ */ jsxs(
|
|
7759
|
+
"div",
|
|
7488
7760
|
{
|
|
7489
|
-
|
|
7490
|
-
onClick: () => selectRoom(room.id, conv.caseId),
|
|
7491
|
-
className: cn(
|
|
7492
|
-
"flex w-full items-center justify-between rounded-md px-2 py-2 text-left transition-colors hover:bg-accent",
|
|
7493
|
-
activeRoomId === room.id && "bg-accent"
|
|
7494
|
-
),
|
|
7761
|
+
className: "rounded-lg border bg-card shadow-sm",
|
|
7495
7762
|
children: [
|
|
7496
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-
|
|
7497
|
-
/* @__PURE__ */
|
|
7498
|
-
|
|
7763
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2 border-b px-3 py-2.5", children: [
|
|
7764
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7765
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
7766
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-foreground truncate", children: conv.caseNumber }),
|
|
7767
|
+
caseUnread > 0 && /* @__PURE__ */ jsx(
|
|
7768
|
+
"span",
|
|
7769
|
+
{
|
|
7770
|
+
className: "h-2 w-2 flex-shrink-0 rounded-full bg-primary",
|
|
7771
|
+
"aria-label": `${caseUnread} unread`
|
|
7772
|
+
}
|
|
7773
|
+
)
|
|
7774
|
+
] }),
|
|
7775
|
+
conv.clientName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: conv.clientName })
|
|
7776
|
+
] }),
|
|
7777
|
+
/* @__PURE__ */ jsx(
|
|
7778
|
+
"span",
|
|
7779
|
+
{
|
|
7780
|
+
className: cn(
|
|
7781
|
+
"flex-shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium",
|
|
7782
|
+
statusToneClasses[getStatusTone(conv.caseStatus)]
|
|
7783
|
+
),
|
|
7784
|
+
children: getStatusLabel(conv.caseStatus)
|
|
7785
|
+
}
|
|
7786
|
+
)
|
|
7499
7787
|
] }),
|
|
7500
|
-
/* @__PURE__ */
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7788
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y", children: conv.rooms.map((room) => {
|
|
7789
|
+
const RoomIcon = room.type === "dealer_agent" ? Store : User;
|
|
7790
|
+
const unread = room.unreadCount ?? 0;
|
|
7791
|
+
return /* @__PURE__ */ jsxs(
|
|
7792
|
+
"button",
|
|
7793
|
+
{
|
|
7794
|
+
type: "button",
|
|
7795
|
+
onClick: () => selectRoom(room.id, conv.caseId),
|
|
7796
|
+
className: cn(
|
|
7797
|
+
"flex w-full items-center gap-2.5 px-3 py-2.5 text-left transition-colors hover:bg-accent/60",
|
|
7798
|
+
activeRoomId === room.id && "bg-accent"
|
|
7799
|
+
),
|
|
7800
|
+
children: [
|
|
7801
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-muted", children: /* @__PURE__ */ jsx(RoomIcon, { className: "h-3.5 w-3.5 text-muted-foreground" }) }),
|
|
7802
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7803
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: getRoomTypeLabel(room.type) }),
|
|
7804
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: room.lastMessageAt ? formatRelativeTime(room.lastMessageAt) : labels.noMessagesShort ?? "No messages" })
|
|
7805
|
+
] }),
|
|
7806
|
+
unread > 0 && /* @__PURE__ */ jsx("span", { className: "flex h-5 min-w-5 flex-shrink-0 items-center justify-center rounded-full bg-primary px-1.5 text-[10px] font-semibold text-primary-foreground", children: unread > 99 ? "99+" : unread })
|
|
7807
|
+
]
|
|
7808
|
+
},
|
|
7809
|
+
room.id
|
|
7810
|
+
);
|
|
7811
|
+
}) })
|
|
7504
7812
|
]
|
|
7505
7813
|
},
|
|
7506
|
-
|
|
7507
|
-
)
|
|
7508
|
-
|
|
7814
|
+
conv.caseId
|
|
7815
|
+
);
|
|
7816
|
+
}) }) })
|
|
7509
7817
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7510
7818
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [
|
|
7511
7819
|
/* @__PURE__ */ jsx(
|
|
@@ -7519,8 +7827,11 @@ function ChatSidebar({
|
|
|
7519
7827
|
}
|
|
7520
7828
|
),
|
|
7521
7829
|
activeConversation && /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7522
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: activeConversation.caseNumber }),
|
|
7523
|
-
|
|
7830
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: activeRoom ? getRoomTypeLabel(activeRoom.type) : activeConversation.caseNumber }),
|
|
7831
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate", children: [
|
|
7832
|
+
activeConversation.caseNumber,
|
|
7833
|
+
activeConversation.clientName ? ` \xB7 ${activeConversation.clientName}` : ""
|
|
7834
|
+
] })
|
|
7524
7835
|
] }),
|
|
7525
7836
|
/* @__PURE__ */ jsx(
|
|
7526
7837
|
Button,
|
|
@@ -7539,8 +7850,11 @@ function ChatSidebar({
|
|
|
7539
7850
|
roomId: activeRoomId,
|
|
7540
7851
|
currentUserId,
|
|
7541
7852
|
config,
|
|
7853
|
+
roomLabel: activeRoom ? getRoomTypeLabel(activeRoom.type) : void 0,
|
|
7854
|
+
caseNumber: activeConversation?.caseNumber,
|
|
7542
7855
|
labels,
|
|
7543
7856
|
roleLabel,
|
|
7857
|
+
onMarkedRead: clearRoomUnread,
|
|
7544
7858
|
className: "flex-1"
|
|
7545
7859
|
}
|
|
7546
7860
|
)
|
|
@@ -10260,29 +10574,14 @@ function USAddressInput({
|
|
|
10260
10574
|
] })
|
|
10261
10575
|
] });
|
|
10262
10576
|
}
|
|
10263
|
-
|
|
10264
|
-
return /* @__PURE__ */ jsx(
|
|
10265
|
-
"input",
|
|
10266
|
-
{
|
|
10267
|
-
type,
|
|
10268
|
-
"data-slot": "input",
|
|
10269
|
-
className: cn(
|
|
10270
|
-
"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
|
|
10271
|
-
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
10272
|
-
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
10273
|
-
className
|
|
10274
|
-
),
|
|
10275
|
-
...props
|
|
10276
|
-
}
|
|
10277
|
-
);
|
|
10278
|
-
}
|
|
10577
|
+
var phoneInputGroupClass = "flex h-9 w-full gap-0 overflow-hidden rounded-md border border-input bg-transparent shadow-xs transition-[color,box-shadow] [--PhoneInputCountrySelect-marginRight:0] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 dark:bg-input/30 [&_.PhoneInputCountry]:mr-0";
|
|
10279
10578
|
var PhoneInput = React7.forwardRef(
|
|
10280
10579
|
({ className, onChange, value, defaultCountry = "MX", ...props }, ref) => {
|
|
10281
10580
|
return /* @__PURE__ */ jsx(
|
|
10282
10581
|
RPNInput.default,
|
|
10283
10582
|
{
|
|
10284
10583
|
ref,
|
|
10285
|
-
className: cn(
|
|
10584
|
+
className: cn(phoneInputGroupClass, className),
|
|
10286
10585
|
flagComponent: FlagComponent,
|
|
10287
10586
|
countrySelectComponent: CountrySelect,
|
|
10288
10587
|
inputComponent: InputComponent,
|
|
@@ -10299,7 +10598,10 @@ PhoneInput.displayName = "PhoneInput";
|
|
|
10299
10598
|
var InputComponent = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
10300
10599
|
Input,
|
|
10301
10600
|
{
|
|
10302
|
-
className: cn(
|
|
10601
|
+
className: cn(
|
|
10602
|
+
"h-9 min-h-0 rounded-none border-0 bg-transparent shadow-none focus-visible:border-transparent focus-visible:ring-0 dark:bg-transparent",
|
|
10603
|
+
className
|
|
10604
|
+
),
|
|
10303
10605
|
...props,
|
|
10304
10606
|
ref
|
|
10305
10607
|
}
|
|
@@ -10328,8 +10630,8 @@ var CountrySelect = ({
|
|
|
10328
10630
|
Button,
|
|
10329
10631
|
{
|
|
10330
10632
|
type: "button",
|
|
10331
|
-
variant: "
|
|
10332
|
-
className: "
|
|
10633
|
+
variant: "ghost",
|
|
10634
|
+
className: "h-9 shrink-0 gap-1 rounded-none border-0 border-r border-input px-2.5 shadow-none hover:bg-muted/50 focus:z-10",
|
|
10333
10635
|
disabled,
|
|
10334
10636
|
children: [
|
|
10335
10637
|
/* @__PURE__ */ jsx(
|