@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.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
+ }
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
- } = 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,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__ */ 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",
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
- 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
- ),
7761
+ className: "rounded-lg border bg-card shadow-sm",
7495
7762
  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) })
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__ */ 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
- ] })
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
- room.id
7507
- ))
7508
- ] }, conv.caseId)) }) })
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
- activeConversation.clientName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: activeConversation.clientName })
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
- 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
- }
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("flex", className),
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("rounded-e-lg rounded-s-none", className),
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: "outline",
10332
- className: "flex gap-1 rounded-e-none rounded-s-lg border-r-0 px-3 focus:z-10",
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(