@algenium/blocks 1.16.1 → 1.18.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.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, MessageSquare, Wifi, WifiOff, FileIcon, Download, Paperclip, Send, ArrowLeft, Search, 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';
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
+ }
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
+ }
6825
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
- } = useChatRoom(roomId, config);
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
- return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full flex-col", className), children: [
7173
- /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center justify-between border-b px-4 py-3", children: [
7174
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7175
- /* @__PURE__ */ jsx(MessageSquare, { className: "h-4 w-4 text-primary", "aria-hidden": "true" }),
7176
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: roomLabel ?? "Chat" })
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-green-500" }) : /* @__PURE__ */ jsx(WifiOff, { className: "h-3.5 w-3.5 text-destructive" }) }) }),
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__ */ jsxs(
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 && !isLoadingHistory ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center py-8 text-center", children: [
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(([date, dateMessages]) => /* @__PURE__ */ jsxs("div", { children: [
7202
- /* @__PURE__ */ jsxs("div", { className: "my-3 flex items-center gap-3", children: [
7203
- /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" }),
7204
- /* @__PURE__ */ jsx("span", { className: "px-2 text-xs text-muted-foreground", children: date }),
7205
- /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
7206
- ] }),
7207
- /* @__PURE__ */ jsx("div", { className: "space-y-3", children: dateMessages.map((message) => {
7208
- const isCurrentUser = message.senderId === currentUserId;
7209
- return /* @__PURE__ */ jsxs(
7210
- "div",
7211
- {
7212
- className: cn(
7213
- "flex gap-2",
7214
- isCurrentUser ? "flex-row-reverse" : "flex-row"
7215
- ),
7216
- children: [
7217
- /* @__PURE__ */ jsx(
7218
- "div",
7219
- {
7220
- className: cn(
7221
- "flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full text-xs font-medium",
7222
- roleColors[message.senderRole] ?? roleColors.client
7223
- ),
7224
- children: (message.senderName ?? message.senderId).split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase()
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
- /* @__PURE__ */ jsxs(
7228
- "div",
7229
- {
7230
- className: cn(
7231
- "flex max-w-[80%] flex-col",
7232
- isCurrentUser ? "items-end" : "items-start"
7233
- ),
7234
- children: [
7235
- /* @__PURE__ */ jsxs("div", { className: "mb-0.5 flex items-center gap-1.5", children: [
7236
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: message.senderName ?? message.senderId.slice(0, 8) }),
7237
- /* @__PURE__ */ jsx(
7238
- "span",
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-1 py-0.5 text-[10px] font-medium",
7242
- roleColors[message.senderRole] ?? ""
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: getRoleLabel(message.senderRole)
7471
+ children: message.content
7245
7472
  }
7246
7473
  ),
7247
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatTime2(message.createdAt) })
7248
- ] }),
7249
- message.content && /* @__PURE__ */ jsx(
7250
- "div",
7251
- {
7252
- className: cn(
7253
- "rounded-xl px-3 py-2 text-sm",
7254
- isCurrentUser ? "rounded-br-sm bg-primary text-primary-foreground" : "rounded-bl-sm bg-muted text-foreground"
7255
- ),
7256
- children: message.content
7257
- }
7258
- ),
7259
- message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-col gap-1", children: message.attachments.map(
7260
- (att) => att.mimeType.startsWith("image/") ? /* @__PURE__ */ jsx(
7261
- "a",
7262
- {
7263
- href: getAttachmentUrl(att.id),
7264
- target: "_blank",
7265
- rel: "noopener noreferrer",
7266
- className: "block max-w-[200px] overflow-hidden rounded-lg border",
7267
- children: /* @__PURE__ */ jsx(
7268
- "img",
7269
- {
7270
- src: getAttachmentUrl(att.id),
7271
- alt: att.fileName,
7272
- className: "h-auto w-full object-cover",
7273
- loading: "lazy"
7274
- }
7275
- )
7276
- },
7277
- att.id
7278
- ) : /* @__PURE__ */ jsxs(
7279
- "a",
7280
- {
7281
- href: getAttachmentUrl(att.id),
7282
- target: "_blank",
7283
- rel: "noopener noreferrer",
7284
- className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-2 py-1.5 text-xs transition-colors hover:bg-muted",
7285
- children: [
7286
- /* @__PURE__ */ jsx(FileIcon, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" }),
7287
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
7288
- /* @__PURE__ */ jsx("p", { className: "truncate font-medium", children: att.fileName }),
7289
- /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: formatFileSize(att.fileSize) })
7290
- ] }),
7291
- /* @__PURE__ */ jsx(Download, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" })
7292
- ]
7293
- },
7294
- att.id
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,45 @@ 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
+ };
7648
+ var roomTypeIconClasses = {
7649
+ client_agent: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
7650
+ dealer_agent: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
7651
+ };
7405
7652
  function ChatSidebar({
7406
7653
  currentUserId,
7407
7654
  config,
7408
7655
  labels = {},
7409
7656
  roleLabel,
7410
7657
  roomTypeLabel,
7658
+ statusLabel,
7659
+ statusTone,
7411
7660
  mobileTopOffset,
7412
7661
  className
7413
7662
  }) {
@@ -7418,9 +7667,12 @@ function ChatSidebar({
7418
7667
  isLoading,
7419
7668
  activeCaseId,
7420
7669
  activeRoomId,
7670
+ searchQuery,
7671
+ setSearchQuery,
7421
7672
  close,
7422
7673
  selectRoom,
7423
- back
7674
+ back,
7675
+ clearRoomUnread
7424
7676
  } = useChatSidebar();
7425
7677
  useEffect(() => {
7426
7678
  if (!isOpen || typeof window === "undefined") return;
@@ -7436,12 +7688,24 @@ function ChatSidebar({
7436
7688
  document.body.style.overflow = "";
7437
7689
  };
7438
7690
  }, [isOpen]);
7691
+ const filteredConversations = useMemo(() => {
7692
+ const q = searchQuery.trim().toLowerCase();
7693
+ if (!q) return conversations;
7694
+ return conversations.filter(
7695
+ (c) => c.caseNumber.toLowerCase().includes(q) || (c.clientName?.toLowerCase().includes(q) ?? false)
7696
+ );
7697
+ }, [conversations, searchQuery]);
7439
7698
  if (!isOpen) return null;
7440
7699
  const getRoomTypeLabel = (type) => {
7441
7700
  if (roomTypeLabel) return roomTypeLabel(type);
7442
7701
  return roomTypeLabels[type] ?? type;
7443
7702
  };
7703
+ const getStatusLabel = (status) => statusLabel ? statusLabel(status) : status;
7704
+ const getStatusTone = (status) => statusTone?.(status) ?? "neutral";
7444
7705
  const activeConversation = activeCaseId ? conversations.find((c) => c.caseId === activeCaseId) : null;
7706
+ const activeRoom = activeConversation?.rooms.find(
7707
+ (r2) => r2.id === activeRoomId
7708
+ );
7445
7709
  const cssVars = {
7446
7710
  "--sidebar-top": mobileTopOffset ?? "0px"
7447
7711
  };
@@ -7472,40 +7736,99 @@ function ChatSidebar({
7472
7736
  }
7473
7737
  )
7474
7738
  ] }),
7739
+ /* @__PURE__ */ jsx("div", { className: "border-b px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
7740
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
7741
+ /* @__PURE__ */ jsx(
7742
+ Input,
7743
+ {
7744
+ value: searchQuery,
7745
+ onChange: (e) => setSearchQuery(e.target.value),
7746
+ placeholder: labels.searchPlaceholder ?? "Search by case or client...",
7747
+ className: "h-8 pl-8 text-sm"
7748
+ }
7749
+ )
7750
+ ] }) }),
7475
7751
  /* @__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
7752
  /* @__PURE__ */ jsx(MessageSquare, { className: "mb-3 h-8 w-8 text-muted-foreground/50" }),
7477
7753
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.noConversations ?? "No conversations yet" })
7478
- ] }) : /* @__PURE__ */ jsx("div", { className: "py-1", children: conversations.map((conv) => /* @__PURE__ */ jsxs("div", { className: "px-2", children: [
7479
- /* @__PURE__ */ jsxs("div", { className: "px-2 pt-3 pb-1", children: [
7480
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
7481
- /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-foreground", children: conv.caseNumber }),
7482
- /* @__PURE__ */ jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground", children: conv.caseStatus })
7483
- ] }),
7484
- conv.clientName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: conv.clientName })
7485
- ] }),
7486
- conv.rooms.map((room) => /* @__PURE__ */ jsxs(
7487
- "button",
7754
+ ] }) : filteredConversations.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center px-4", children: [
7755
+ /* @__PURE__ */ jsx(Search, { className: "mb-3 h-8 w-8 text-muted-foreground/50" }),
7756
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.noResults ?? "No matching conversations" })
7757
+ ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-2 p-3", children: filteredConversations.map((conv) => {
7758
+ const caseUnread = conv.rooms.reduce(
7759
+ (sum, r2) => sum + (r2.unreadCount ?? 0),
7760
+ 0
7761
+ );
7762
+ return /* @__PURE__ */ jsxs(
7763
+ "div",
7488
7764
  {
7489
- type: "button",
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
- ),
7765
+ className: "rounded-lg border bg-card shadow-sm",
7495
7766
  children: [
7496
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
7497
- /* @__PURE__ */ jsx(MessageSquare, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" }),
7498
- /* @__PURE__ */ jsx("span", { className: "text-sm truncate", children: getRoomTypeLabel(room.type) })
7767
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2 border-b bg-muted/40 px-3 py-2.5", children: [
7768
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
7769
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7770
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-foreground truncate", children: conv.caseNumber }),
7771
+ caseUnread > 0 && /* @__PURE__ */ jsx(
7772
+ "span",
7773
+ {
7774
+ className: "h-2 w-2 flex-shrink-0 rounded-full bg-primary",
7775
+ "aria-label": `${caseUnread} unread`
7776
+ }
7777
+ )
7778
+ ] }),
7779
+ conv.clientName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: conv.clientName })
7780
+ ] }),
7781
+ /* @__PURE__ */ jsx(
7782
+ "span",
7783
+ {
7784
+ className: cn(
7785
+ "flex-shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium",
7786
+ statusToneClasses[getStatusTone(conv.caseStatus)]
7787
+ ),
7788
+ children: getStatusLabel(conv.caseStatus)
7789
+ }
7790
+ )
7499
7791
  ] }),
7500
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
7501
- room.lastMessageAt && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatRelativeTime(room.lastMessageAt) }),
7502
- /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 text-muted-foreground" })
7503
- ] })
7792
+ /* @__PURE__ */ jsx("div", { className: "ml-1 divide-y", children: conv.rooms.map((room) => {
7793
+ const RoomIcon = room.type === "dealer_agent" ? Store : User;
7794
+ const unread = room.unreadCount ?? 0;
7795
+ const iconClasses = roomTypeIconClasses[room.type] ?? "bg-muted text-muted-foreground";
7796
+ return /* @__PURE__ */ jsxs(
7797
+ "button",
7798
+ {
7799
+ type: "button",
7800
+ onClick: () => selectRoom(room.id, conv.caseId),
7801
+ className: cn(
7802
+ "flex w-full items-center gap-2.5 py-2.5 pl-4 pr-3 text-left transition-colors hover:bg-accent/60",
7803
+ activeRoomId === room.id && "bg-accent"
7804
+ ),
7805
+ children: [
7806
+ /* @__PURE__ */ jsx(
7807
+ "div",
7808
+ {
7809
+ className: cn(
7810
+ "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full",
7811
+ iconClasses
7812
+ ),
7813
+ children: /* @__PURE__ */ jsx(RoomIcon, { className: "h-3.5 w-3.5" })
7814
+ }
7815
+ ),
7816
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
7817
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: getRoomTypeLabel(room.type) }),
7818
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: room.lastMessageAt ? formatRelativeTime(room.lastMessageAt) : labels.noMessagesShort ?? "No messages" })
7819
+ ] }),
7820
+ 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 }),
7821
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground" })
7822
+ ]
7823
+ },
7824
+ room.id
7825
+ );
7826
+ }) })
7504
7827
  ]
7505
7828
  },
7506
- room.id
7507
- ))
7508
- ] }, conv.caseId)) }) })
7829
+ conv.caseId
7830
+ );
7831
+ }) }) })
7509
7832
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7510
7833
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [
7511
7834
  /* @__PURE__ */ jsx(
@@ -7519,8 +7842,11 @@ function ChatSidebar({
7519
7842
  }
7520
7843
  ),
7521
7844
  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
- activeConversation.clientName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: activeConversation.clientName })
7845
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: activeRoom ? getRoomTypeLabel(activeRoom.type) : activeConversation.caseNumber }),
7846
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate", children: [
7847
+ activeConversation.caseNumber,
7848
+ activeConversation.clientName ? ` \xB7 ${activeConversation.clientName}` : ""
7849
+ ] })
7524
7850
  ] }),
7525
7851
  /* @__PURE__ */ jsx(
7526
7852
  Button,
@@ -7539,8 +7865,11 @@ function ChatSidebar({
7539
7865
  roomId: activeRoomId,
7540
7866
  currentUserId,
7541
7867
  config,
7868
+ roomLabel: activeRoom ? getRoomTypeLabel(activeRoom.type) : void 0,
7869
+ caseNumber: activeConversation?.caseNumber,
7542
7870
  labels,
7543
7871
  roleLabel,
7872
+ onMarkedRead: clearRoomUnread,
7544
7873
  className: "flex-1"
7545
7874
  }
7546
7875
  )
@@ -10260,22 +10589,6 @@ function USAddressInput({
10260
10589
  ] })
10261
10590
  ] });
10262
10591
  }
10263
- function Input({ className, type, ...props }) {
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
- }
10279
10592
  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";
10280
10593
  var PhoneInput = React7.forwardRef(
10281
10594
  ({ className, onChange, value, defaultCountry = "MX", ...props }, ref) => {