@realtimexsco/live-chat 1.4.2 → 1.4.4

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.mjs CHANGED
@@ -9,7 +9,7 @@ import { clsx } from 'clsx';
9
9
  import { twMerge } from 'tailwind-merge';
10
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
11
  import { flushSync } from 'react-dom';
12
- import { Sun, Moon, Search, X, Loader2, UserPlus, ChevronDown, ArrowLeft, Users, WifiOff, Wifi, Sparkles, MessageSquareText, ChevronRight, Pin, Star, Phone, Video, MoreVertical, Info, UserKey, ShieldUser, Paperclip, Clock, MessageSquareX, Trash2, LogOut, Ban, CheckCheck, Check, Camera, Save, Pencil, Mail, CornerUpLeft, CheckSquare, Smile, ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, MessageCircleMore, History, Shield, Send, AlertCircle, ShieldCheck, UserMinus, MessageCircle, ExternalLink, Download, ChevronLeft, ZoomOut, ZoomIn, RotateCcw, Music, ArrowRight, MoreHorizontal, PinOff, StarOff, XIcon, ImageIcon, Film, Play, Pause, FileText, FileSpreadsheet, FileIcon, Eye, Captions } from 'lucide-react';
12
+ import { Sun, Moon, Search, X, Loader2, UserPlus, ChevronDown, ArrowLeft, Users, WifiOff, Wifi, Sparkles, MessageSquareText, ChevronRight, Pin, Star, MoreVertical, Info, UserKey, ShieldUser, Paperclip, Clock, MessageSquareX, Trash2, LogOut, Ban, CheckCheck, Check, Camera, Save, Pencil, Mail, CornerUpLeft, CheckSquare, Smile, ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, MessageCircleMore, History, Shield, Send, AlertCircle, ShieldCheck, UserMinus, MessageCircle, Phone, Video, ExternalLink, Download, ChevronLeft, ZoomOut, ZoomIn, RotateCcw, Music, ArrowRight, MoreHorizontal, PinOff, StarOff, XIcon, ImageIcon, Film, Play, Pause, FileText, FileSpreadsheet, FileIcon, Eye, Captions } from 'lucide-react';
13
13
  import { cva } from 'class-variance-authority';
14
14
  import EmojiPicker, { Theme } from 'emoji-picker-react';
15
15
  import { getDefaultClassNames, DayPicker } from 'react-day-picker';
@@ -7620,6 +7620,76 @@ var HeaderSearchPopover = ({
7620
7620
  ] });
7621
7621
  };
7622
7622
  var HeaderSearchPopover_default = HeaderSearchPopover;
7623
+ var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text)";
7624
+ var DefaultHeaderCallActions = ({
7625
+ activeChannel,
7626
+ conversationId,
7627
+ showPhoneCall = true,
7628
+ showVideoCall = true,
7629
+ onPhoneCall,
7630
+ onVideoCall,
7631
+ className
7632
+ }) => {
7633
+ const { components, slotClassName, features } = useChatCustomizationOptional();
7634
+ const PhoneSlot = components.PhoneCallButton;
7635
+ const VideoSlot = components.VideoCallButton;
7636
+ const hideInGroups = features.hideCallActionsInGroupChats ?? false;
7637
+ if (hideInGroups && activeChannel.isGroup) return null;
7638
+ if (!showPhoneCall && !showVideoCall) return null;
7639
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
7640
+ showPhoneCall && (PhoneSlot ? /* @__PURE__ */ jsx(
7641
+ PhoneSlot,
7642
+ {
7643
+ activeChannel,
7644
+ conversationId,
7645
+ onPhoneCall,
7646
+ className: cn(className, slotClassName("phoneCallButton"))
7647
+ }
7648
+ ) : /* @__PURE__ */ jsx(
7649
+ Button,
7650
+ {
7651
+ variant: "ghost",
7652
+ size: "icon",
7653
+ className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
7654
+ "aria-label": "Voice call",
7655
+ onClick: onPhoneCall,
7656
+ children: /* @__PURE__ */ jsx(Phone, { size: 15 })
7657
+ }
7658
+ )),
7659
+ showVideoCall && (VideoSlot ? /* @__PURE__ */ jsx(
7660
+ VideoSlot,
7661
+ {
7662
+ activeChannel,
7663
+ conversationId,
7664
+ onVideoCall,
7665
+ className: cn(className, slotClassName("videoCallButton"))
7666
+ }
7667
+ ) : /* @__PURE__ */ jsx(
7668
+ Button,
7669
+ {
7670
+ variant: "ghost",
7671
+ size: "icon",
7672
+ className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
7673
+ "aria-label": "Video call",
7674
+ onClick: onVideoCall,
7675
+ children: /* @__PURE__ */ jsx(Video, { size: 15 })
7676
+ }
7677
+ ))
7678
+ ] });
7679
+ };
7680
+ var HeaderCallActions = (props) => {
7681
+ const { components, slotClassName, features } = useChatCustomizationOptional();
7682
+ const Custom = components.HeaderCallActions;
7683
+ if (!Custom) {
7684
+ const hideInGroups = features.hideCallActionsInGroupChats ?? false;
7685
+ const showPhoneCall = props.showPhoneCall ?? true;
7686
+ const showVideoCall = props.showVideoCall ?? true;
7687
+ if (hideInGroups && props.activeChannel.isGroup) return null;
7688
+ if (!showPhoneCall && !showVideoCall) return null;
7689
+ }
7690
+ return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-0.5", slotClassName("headerCallActions")), children: Custom ? /* @__PURE__ */ jsx(Custom, { ...props }) : /* @__PURE__ */ jsx(DefaultHeaderCallActions, { ...props }) });
7691
+ };
7692
+ var HeaderCallActions_default = HeaderCallActions;
7623
7693
  function OptionsMenuItem({
7624
7694
  icon: Icon,
7625
7695
  label,
@@ -7640,6 +7710,7 @@ function OptionsMenuItem({
7640
7710
  }
7641
7711
  var HeaderRightSide = ({
7642
7712
  activeChannel,
7713
+ conversationId,
7643
7714
  isAdmin,
7644
7715
  canViewMembers,
7645
7716
  pinnedCount,
@@ -7669,6 +7740,15 @@ var HeaderRightSide = ({
7669
7740
  }) => {
7670
7741
  const { scopeClassName, themeStyles, showColorModeToggle } = useChatTheme();
7671
7742
  const { showDateTimeSettings } = useChatLocale();
7743
+ const features = useChatFeaturesOptional();
7744
+ const showPhoneCall = features.showPhoneCall ?? defaultChatFeatures.showPhoneCall;
7745
+ const showVideoCall = features.showVideoCall ?? defaultChatFeatures.showVideoCall;
7746
+ const handlePhoneCall = () => {
7747
+ features.onPhoneCall?.({ activeChannel, conversationId });
7748
+ };
7749
+ const handleVideoCall = () => {
7750
+ features.onVideoCall?.({ activeChannel, conversationId });
7751
+ };
7672
7752
  const headerItemGapClass = "gap-0.5";
7673
7753
  const headerIconBtnClass = "inline-flex size-6 shrink-0 items-center justify-center rounded-lg p-0 text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text) has-[>svg]:p-0";
7674
7754
  const headerCountBtnClass = "inline-flex h-7 shrink-0 items-center justify-center gap-0.5 rounded-lg px-1.5 text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text)";
@@ -7726,26 +7806,18 @@ var HeaderRightSide = ({
7726
7806
  triggerClassName: headerIconBtnClass
7727
7807
  }
7728
7808
  ),
7729
- /* @__PURE__ */ jsx(
7730
- Button,
7731
- {
7732
- variant: "ghost",
7733
- size: "icon-xs",
7734
- className: cn(headerIconBtnClass, "hidden sm:inline-flex"),
7735
- "aria-label": "Voice call",
7736
- children: /* @__PURE__ */ jsx(Phone, { size: 15 })
7737
- }
7738
- ),
7739
- /* @__PURE__ */ jsx(
7740
- Button,
7809
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx(
7810
+ HeaderCallActions_default,
7741
7811
  {
7742
- variant: "ghost",
7743
- size: "icon-xs",
7744
- className: cn(headerIconBtnClass, "hidden sm:inline-flex"),
7745
- "aria-label": "Video call",
7746
- children: /* @__PURE__ */ jsx(Video, { size: 15 })
7812
+ activeChannel,
7813
+ conversationId,
7814
+ showPhoneCall,
7815
+ showVideoCall,
7816
+ onPhoneCall: handlePhoneCall,
7817
+ onVideoCall: handleVideoCall,
7818
+ className: headerIconBtnClass
7747
7819
  }
7748
- ),
7820
+ ) }),
7749
7821
  /* @__PURE__ */ jsx("span", { className: headerDividerClass, "aria-hidden": true }),
7750
7822
  /* @__PURE__ */ jsxs(DropdownMenu, { children: [
7751
7823
  /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-xs", className: headerIconBtnClass, "aria-label": "More options", children: /* @__PURE__ */ jsx(MoreVertical, { size: 15 }) }) }),
@@ -12883,6 +12955,7 @@ var ChannelHeaderView = (props) => {
12883
12955
  HeaderRightSideSlot,
12884
12956
  {
12885
12957
  activeChannel,
12958
+ conversationId,
12886
12959
  isAdmin,
12887
12960
  canViewMembers,
12888
12961
  pinnedCount,
@@ -17282,156 +17355,6 @@ function ChatViewport({
17282
17355
  );
17283
17356
  }
17284
17357
  var ChatViewport_default = ChatViewport;
17285
- var ChatMain = ({
17286
- clientId,
17287
- loggedUserDetails,
17288
- accessToken,
17289
- apiUrl,
17290
- socketUrl,
17291
- queryParams,
17292
- queryParamApis,
17293
- queryParamsByApi,
17294
- themeColor = "#7494ec",
17295
- theme,
17296
- uiConfig,
17297
- components,
17298
- classNames,
17299
- features,
17300
- layout,
17301
- colorMode,
17302
- defaultColorMode = "light",
17303
- onColorModeChange,
17304
- showColorModeToggle = true,
17305
- locale,
17306
- timeZone,
17307
- hour12,
17308
- defaultLocale,
17309
- defaultTimeZone,
17310
- defaultHour12,
17311
- onDateTimePreferencesChange,
17312
- showDateTimeSettings = true,
17313
- error,
17314
- info,
17315
- onErrorDismiss,
17316
- onInfoDismiss,
17317
- viewportHeight = "full",
17318
- viewportClassName
17319
- }) => {
17320
- const clientObj = React2__default.useMemo(() => ({ id: clientId }), [clientId]);
17321
- const uiConfigObj = React2__default.useMemo(
17322
- () => ({
17323
- ...uiConfig || {},
17324
- components: { ...uiConfig?.components, ...components },
17325
- classNames: { ...uiConfig?.classNames, ...classNames },
17326
- features: { ...uiConfig?.features, ...features }
17327
- }),
17328
- [uiConfig, components, classNames, features]
17329
- );
17330
- return /* @__PURE__ */ jsx(ChatViewport_default, { height: viewportHeight, className: viewportClassName, children: /* @__PURE__ */ jsx(
17331
- ChatThemeProvider,
17332
- {
17333
- themeColor,
17334
- colorMode,
17335
- defaultColorMode,
17336
- onColorModeChange,
17337
- showColorModeToggle,
17338
- children: /* @__PURE__ */ jsx(
17339
- ChatLocaleProvider,
17340
- {
17341
- locale,
17342
- timeZone,
17343
- hour12,
17344
- defaultLocale,
17345
- defaultTimeZone,
17346
- defaultHour12,
17347
- onDateTimePreferencesChange,
17348
- showDateTimeSettings,
17349
- children: /* @__PURE__ */ jsx(
17350
- Chat,
17351
- {
17352
- client: clientObj,
17353
- accessToken,
17354
- loggedUserDetails,
17355
- themeColor,
17356
- theme,
17357
- uiConfig: uiConfigObj,
17358
- apiUrl,
17359
- socketUrl,
17360
- queryParams,
17361
- queryParamApis,
17362
- queryParamsByApi,
17363
- children: /* @__PURE__ */ jsx(
17364
- ChatAlertsProvider,
17365
- {
17366
- value: {
17367
- error,
17368
- info,
17369
- onDismissError: onErrorDismiss,
17370
- onDismissInfo: onInfoDismiss
17371
- },
17372
- children: /* @__PURE__ */ jsx(
17373
- ChatLayout_default,
17374
- {
17375
- layout,
17376
- loggedUserDetails,
17377
- themeColor
17378
- }
17379
- )
17380
- }
17381
- )
17382
- }
17383
- )
17384
- }
17385
- )
17386
- }
17387
- ) });
17388
- };
17389
- var ChatMain_default = ChatMain;
17390
-
17391
- // src/index.ts
17392
- init_useStore();
17393
- init_socket_service2();
17394
- var Channel = ({ children }) => {
17395
- return /* @__PURE__ */ jsx("div", { className: "relative flex h-full min-w-0 w-full flex-1 flex-col overflow-hidden bg-(--chat-main-bg)", children });
17396
- };
17397
-
17398
- // src/index.ts
17399
- init_api_service();
17400
-
17401
- // src/config/socket.config.ts
17402
- init_client();
17403
- var getSocketConfig = (accessToken, tenantId, options) => {
17404
- const baseURL = resolveSocketUrl(
17405
- options?.socketUrl ?? getChatSocketUrl(),
17406
- options?.apiUrl ?? getChatBaseUrl()
17407
- );
17408
- return {
17409
- url: baseURL,
17410
- options: {
17411
- path: "/connection",
17412
- auth: {
17413
- accessToken
17414
- },
17415
- query: {
17416
- platform: "web",
17417
- tenantId: tenantId || "",
17418
- isTenant: "true"
17419
- },
17420
- extraHeaders: {
17421
- Authorization: `Bearer ${accessToken}`,
17422
- platform: "web",
17423
- tenantId: tenantId || "",
17424
- isTenant: "true"
17425
- },
17426
- transports: ["websocket", "polling"],
17427
- reconnection: true,
17428
- reconnectionAttempts: Infinity,
17429
- reconnectionDelay: 2e3,
17430
- reconnectionDelayMax: 5e3,
17431
- timeout: 2e4
17432
- }
17433
- };
17434
- };
17435
17358
  var showNotification = (message, type = "info", icon, duration) => {
17436
17359
  const options = {
17437
17360
  icon,
@@ -17506,21 +17429,373 @@ var getFirstAndLastNameOneCharacter = (name) => {
17506
17429
  const names = name.split(" ");
17507
17430
  return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
17508
17431
  };
17509
- var SIZE_MAP = {
17510
- xs: "size-6",
17511
- sm: "size-8",
17512
- md: "size-9",
17513
- lg: "size-10",
17514
- xl: "size-12"
17432
+
17433
+ // src/notifications/ForegroundPushBridge.tsx
17434
+ init_useStore();
17435
+
17436
+ // src/notifications/push.service.ts
17437
+ init_client();
17438
+ var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
17439
+ var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
17440
+ var PUSH_CHANGED_EVENT = "realtimex:push-changed";
17441
+ var emitPushChanged = (enabled) => {
17442
+ try {
17443
+ window.dispatchEvent(
17444
+ new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
17445
+ );
17446
+ } catch {
17447
+ }
17515
17448
  };
17516
- var DefaultChatAvatar = ({
17517
- src,
17518
- alt,
17519
- name,
17520
- fallback,
17521
- size = "md",
17522
- showOnline = false,
17523
- isOnline = false,
17449
+ var v2Url = "https://realtimex.softwareco.com/api/v2";
17450
+ var apiGetPushConfig = async () => {
17451
+ const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
17452
+ return data?.data;
17453
+ };
17454
+ var apiRegisterPushToken = async (token, deviceLabel) => {
17455
+ const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
17456
+ token,
17457
+ deviceLabel
17458
+ });
17459
+ return data?.data;
17460
+ };
17461
+ var apiRemovePushToken = async (token) => {
17462
+ const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
17463
+ data: { token }
17464
+ });
17465
+ return data;
17466
+ };
17467
+ var apiGetPushPreference = async () => {
17468
+ const { data } = await apiClient.get(
17469
+ `${v2Url}/notifications/push/preference`
17470
+ );
17471
+ return data?.data;
17472
+ };
17473
+ var apiUpdatePushPreference = async (enabled) => {
17474
+ const { data } = await apiClient.patch(
17475
+ `${v2Url}/notifications/push/preference`,
17476
+ { enabled }
17477
+ );
17478
+ return data?.data;
17479
+ };
17480
+ var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
17481
+ var getStoredPushToken = () => {
17482
+ try {
17483
+ return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
17484
+ } catch {
17485
+ return null;
17486
+ }
17487
+ };
17488
+ var storePushToken = (token) => {
17489
+ try {
17490
+ if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
17491
+ else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
17492
+ } catch {
17493
+ }
17494
+ };
17495
+ var defaultDeviceLabel = () => {
17496
+ const ua = navigator.userAgent;
17497
+ const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
17498
+ const os = /mac/i.test(ua) ? "macOS" : /windows/i.test(ua) ? "Windows" : /android/i.test(ua) ? "Android" : /iphone|ipad/i.test(ua) ? "iOS" : /linux/i.test(ua) ? "Linux" : "Unknown OS";
17499
+ return `${browser} on ${os}`;
17500
+ };
17501
+ var loadFirebaseMessaging = async () => {
17502
+ try {
17503
+ const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
17504
+ import('firebase/app'),
17505
+ import('firebase/messaging')
17506
+ ]);
17507
+ return { initializeApp, getApps, ...messagingModule };
17508
+ } catch {
17509
+ throw new Error(
17510
+ 'Push notifications need the "firebase" package \u2014 run: npm install firebase'
17511
+ );
17512
+ }
17513
+ };
17514
+ var getFirebaseMessaging = async (firebaseConfig) => {
17515
+ const fb = await loadFirebaseMessaging();
17516
+ const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
17517
+ return { fb, messaging: fb.getMessaging(app) };
17518
+ };
17519
+ var enablePushOnThisDevice = async () => {
17520
+ if (!isPushSupported()) {
17521
+ throw new Error("Push notifications are not supported in this browser");
17522
+ }
17523
+ const config = await apiGetPushConfig();
17524
+ if (!config?.enabled) {
17525
+ throw new Error("Push notifications are disabled for this workspace");
17526
+ }
17527
+ if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
17528
+ throw new Error(
17529
+ "Push notifications are not configured on the server yet"
17530
+ );
17531
+ }
17532
+ const permission = await Notification.requestPermission();
17533
+ if (permission !== "granted") {
17534
+ throw new Error("Notification permission was not granted");
17535
+ }
17536
+ let registration;
17537
+ try {
17538
+ registration = await navigator.serviceWorker.register(
17539
+ `${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
17540
+ JSON.stringify(config.firebaseConfig)
17541
+ )}`
17542
+ );
17543
+ } catch {
17544
+ throw new Error(
17545
+ `Could not register ${SERVICE_WORKER_PATH} \u2014 copy it from node_modules/@realtimexsco/live-chat/dist/firebase-messaging-sw.js into your app's public folder`
17546
+ );
17547
+ }
17548
+ const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17549
+ const token = await fb.getToken(messaging, {
17550
+ vapidKey: config.vapidKey,
17551
+ serviceWorkerRegistration: registration
17552
+ });
17553
+ if (!token) {
17554
+ throw new Error("Could not obtain a push token from Firebase");
17555
+ }
17556
+ await apiRegisterPushToken(token, defaultDeviceLabel());
17557
+ storePushToken(token);
17558
+ emitPushChanged(true);
17559
+ return token;
17560
+ };
17561
+ var disablePushOnThisDevice = async () => {
17562
+ const token = getStoredPushToken();
17563
+ if (!token) return;
17564
+ try {
17565
+ const config = await apiGetPushConfig();
17566
+ if (config?.firebaseConfig) {
17567
+ const { fb, messaging } = await getFirebaseMessaging(
17568
+ config.firebaseConfig
17569
+ );
17570
+ await fb.deleteToken(messaging).catch(() => void 0);
17571
+ }
17572
+ } catch {
17573
+ }
17574
+ await apiRemovePushToken(token).catch(() => void 0);
17575
+ storePushToken(null);
17576
+ emitPushChanged(false);
17577
+ };
17578
+ var onForegroundPush = async (callback) => {
17579
+ const config = await apiGetPushConfig();
17580
+ if (!config?.configured || !config.firebaseConfig) return () => void 0;
17581
+ const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17582
+ return fb.onMessage(messaging, (payload) => {
17583
+ callback({
17584
+ title: payload?.notification?.title,
17585
+ body: payload?.notification?.body,
17586
+ data: payload?.data
17587
+ });
17588
+ });
17589
+ };
17590
+
17591
+ // src/notifications/ForegroundPushBridge.tsx
17592
+ var ForegroundPushBridge = ({ onPush }) => {
17593
+ useEffect(() => {
17594
+ let unsubscribe = null;
17595
+ let cancelled = false;
17596
+ const handlePayload = (payload) => {
17597
+ const incoming = payload.data?.conversationId;
17598
+ const activeId = useStore.getState().activeConversationId;
17599
+ if (incoming && activeId && incoming === activeId) return;
17600
+ if (onPush && onPush(payload) !== false) return;
17601
+ const text = payload.title ? payload.body ? `${payload.title}: ${payload.body}` : payload.title : payload.body;
17602
+ if (text) showNotification(text, "info");
17603
+ };
17604
+ const start = async () => {
17605
+ if (cancelled || unsubscribe || !getStoredPushToken()) return;
17606
+ try {
17607
+ const stop = await onForegroundPush(handlePayload);
17608
+ if (cancelled) stop();
17609
+ else unsubscribe = stop;
17610
+ } catch {
17611
+ }
17612
+ };
17613
+ void start();
17614
+ const onPushChanged = (event) => {
17615
+ const enabled = event.detail?.enabled;
17616
+ if (enabled) void start();
17617
+ else {
17618
+ unsubscribe?.();
17619
+ unsubscribe = null;
17620
+ }
17621
+ };
17622
+ window.addEventListener(PUSH_CHANGED_EVENT, onPushChanged);
17623
+ return () => {
17624
+ cancelled = true;
17625
+ unsubscribe?.();
17626
+ window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
17627
+ };
17628
+ }, [onPush]);
17629
+ return null;
17630
+ };
17631
+ var ChatMain = ({
17632
+ clientId,
17633
+ loggedUserDetails,
17634
+ accessToken,
17635
+ apiUrl,
17636
+ socketUrl,
17637
+ queryParams,
17638
+ queryParamApis,
17639
+ queryParamsByApi,
17640
+ themeColor = "#7494ec",
17641
+ theme,
17642
+ uiConfig,
17643
+ components,
17644
+ classNames,
17645
+ features,
17646
+ layout,
17647
+ colorMode,
17648
+ defaultColorMode = "light",
17649
+ onColorModeChange,
17650
+ showColorModeToggle = true,
17651
+ locale,
17652
+ timeZone,
17653
+ hour12,
17654
+ defaultLocale,
17655
+ defaultTimeZone,
17656
+ defaultHour12,
17657
+ onDateTimePreferencesChange,
17658
+ showDateTimeSettings = true,
17659
+ error,
17660
+ info,
17661
+ onErrorDismiss,
17662
+ onInfoDismiss,
17663
+ viewportHeight = "full",
17664
+ viewportClassName
17665
+ }) => {
17666
+ const clientObj = React2__default.useMemo(() => ({ id: clientId }), [clientId]);
17667
+ const uiConfigObj = React2__default.useMemo(
17668
+ () => ({
17669
+ ...uiConfig || {},
17670
+ components: { ...uiConfig?.components, ...components },
17671
+ classNames: { ...uiConfig?.classNames, ...classNames },
17672
+ features: { ...uiConfig?.features, ...features }
17673
+ }),
17674
+ [uiConfig, components, classNames, features]
17675
+ );
17676
+ return /* @__PURE__ */ jsx(ChatViewport_default, { height: viewportHeight, className: viewportClassName, children: /* @__PURE__ */ jsx(
17677
+ ChatThemeProvider,
17678
+ {
17679
+ themeColor,
17680
+ colorMode,
17681
+ defaultColorMode,
17682
+ onColorModeChange,
17683
+ showColorModeToggle,
17684
+ children: /* @__PURE__ */ jsx(
17685
+ ChatLocaleProvider,
17686
+ {
17687
+ locale,
17688
+ timeZone,
17689
+ hour12,
17690
+ defaultLocale,
17691
+ defaultTimeZone,
17692
+ defaultHour12,
17693
+ onDateTimePreferencesChange,
17694
+ showDateTimeSettings,
17695
+ children: /* @__PURE__ */ jsxs(
17696
+ Chat,
17697
+ {
17698
+ client: clientObj,
17699
+ accessToken,
17700
+ loggedUserDetails,
17701
+ themeColor,
17702
+ theme,
17703
+ uiConfig: uiConfigObj,
17704
+ apiUrl,
17705
+ socketUrl,
17706
+ queryParams,
17707
+ queryParamApis,
17708
+ queryParamsByApi,
17709
+ children: [
17710
+ /* @__PURE__ */ jsx(ForegroundPushBridge, {}),
17711
+ /* @__PURE__ */ jsx(
17712
+ ChatAlertsProvider,
17713
+ {
17714
+ value: {
17715
+ error,
17716
+ info,
17717
+ onDismissError: onErrorDismiss,
17718
+ onDismissInfo: onInfoDismiss
17719
+ },
17720
+ children: /* @__PURE__ */ jsx(
17721
+ ChatLayout_default,
17722
+ {
17723
+ layout,
17724
+ loggedUserDetails,
17725
+ themeColor
17726
+ }
17727
+ )
17728
+ }
17729
+ )
17730
+ ]
17731
+ }
17732
+ )
17733
+ }
17734
+ )
17735
+ }
17736
+ ) });
17737
+ };
17738
+ var ChatMain_default = ChatMain;
17739
+
17740
+ // src/index.ts
17741
+ init_useStore();
17742
+ init_socket_service2();
17743
+ var Channel = ({ children }) => {
17744
+ return /* @__PURE__ */ jsx("div", { className: "relative flex h-full min-w-0 w-full flex-1 flex-col overflow-hidden bg-(--chat-main-bg)", children });
17745
+ };
17746
+
17747
+ // src/index.ts
17748
+ init_api_service();
17749
+
17750
+ // src/config/socket.config.ts
17751
+ init_client();
17752
+ var getSocketConfig = (accessToken, tenantId, options) => {
17753
+ const baseURL = resolveSocketUrl(
17754
+ options?.socketUrl ?? getChatSocketUrl(),
17755
+ options?.apiUrl ?? getChatBaseUrl()
17756
+ );
17757
+ return {
17758
+ url: baseURL,
17759
+ options: {
17760
+ path: "/connection",
17761
+ auth: {
17762
+ accessToken
17763
+ },
17764
+ query: {
17765
+ platform: "web",
17766
+ tenantId: tenantId || "",
17767
+ isTenant: "true"
17768
+ },
17769
+ extraHeaders: {
17770
+ Authorization: `Bearer ${accessToken}`,
17771
+ platform: "web",
17772
+ tenantId: tenantId || "",
17773
+ isTenant: "true"
17774
+ },
17775
+ transports: ["websocket", "polling"],
17776
+ reconnection: true,
17777
+ reconnectionAttempts: Infinity,
17778
+ reconnectionDelay: 2e3,
17779
+ reconnectionDelayMax: 5e3,
17780
+ timeout: 2e4
17781
+ }
17782
+ };
17783
+ };
17784
+ var SIZE_MAP = {
17785
+ xs: "size-6",
17786
+ sm: "size-8",
17787
+ md: "size-9",
17788
+ lg: "size-10",
17789
+ xl: "size-12"
17790
+ };
17791
+ var DefaultChatAvatar = ({
17792
+ src,
17793
+ alt,
17794
+ name,
17795
+ fallback,
17796
+ size = "md",
17797
+ showOnline = false,
17798
+ isOnline = false,
17524
17799
  className,
17525
17800
  fallbackClassName
17526
17801
  }) => {
@@ -17644,76 +17919,6 @@ var ChannelListItem2 = (props) => {
17644
17919
  return /* @__PURE__ */ jsx(ItemSlot, { ...props });
17645
17920
  };
17646
17921
  var ChannelListItem_default = ChannelListItem2;
17647
- var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text)";
17648
- var DefaultHeaderCallActions = ({
17649
- activeChannel,
17650
- conversationId,
17651
- showPhoneCall = true,
17652
- showVideoCall = true,
17653
- onPhoneCall,
17654
- onVideoCall,
17655
- className
17656
- }) => {
17657
- const { components, slotClassName, features } = useChatCustomizationOptional();
17658
- const PhoneSlot = components.PhoneCallButton;
17659
- const VideoSlot = components.VideoCallButton;
17660
- const hideInGroups = features.hideCallActionsInGroupChats ?? false;
17661
- if (hideInGroups && activeChannel.isGroup) return null;
17662
- if (!showPhoneCall && !showVideoCall) return null;
17663
- return /* @__PURE__ */ jsxs(Fragment, { children: [
17664
- showPhoneCall && (PhoneSlot ? /* @__PURE__ */ jsx(
17665
- PhoneSlot,
17666
- {
17667
- activeChannel,
17668
- conversationId,
17669
- onPhoneCall,
17670
- className: cn(className, slotClassName("phoneCallButton"))
17671
- }
17672
- ) : /* @__PURE__ */ jsx(
17673
- Button,
17674
- {
17675
- variant: "ghost",
17676
- size: "icon",
17677
- className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
17678
- "aria-label": "Voice call",
17679
- onClick: onPhoneCall,
17680
- children: /* @__PURE__ */ jsx(Phone, { size: 15 })
17681
- }
17682
- )),
17683
- showVideoCall && (VideoSlot ? /* @__PURE__ */ jsx(
17684
- VideoSlot,
17685
- {
17686
- activeChannel,
17687
- conversationId,
17688
- onVideoCall,
17689
- className: cn(className, slotClassName("videoCallButton"))
17690
- }
17691
- ) : /* @__PURE__ */ jsx(
17692
- Button,
17693
- {
17694
- variant: "ghost",
17695
- size: "icon",
17696
- className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
17697
- "aria-label": "Video call",
17698
- onClick: onVideoCall,
17699
- children: /* @__PURE__ */ jsx(Video, { size: 15 })
17700
- }
17701
- ))
17702
- ] });
17703
- };
17704
- var HeaderCallActions = (props) => {
17705
- const { components, slotClassName, features } = useChatCustomizationOptional();
17706
- const Custom = components.HeaderCallActions;
17707
- if (!Custom) {
17708
- const hideInGroups = features.hideCallActionsInGroupChats ?? false;
17709
- const showPhoneCall = props.showPhoneCall ?? true;
17710
- const showVideoCall = props.showVideoCall ?? true;
17711
- if (hideInGroups && props.activeChannel.isGroup) return null;
17712
- if (!showPhoneCall && !showVideoCall) return null;
17713
- }
17714
- return /* @__PURE__ */ jsx("div", { className: slotClassName("headerCallActions"), children: Custom ? /* @__PURE__ */ jsx(Custom, { ...props }) : /* @__PURE__ */ jsx(DefaultHeaderCallActions, { ...props }) });
17715
- };
17716
- var HeaderCallActions_default = HeaderCallActions;
17717
17922
 
17718
17923
  // src/chat/packageDefaultComponents.ts
17719
17924
  var packageDefaultComponents = {
@@ -17749,150 +17954,6 @@ var packageDefaultComponents = {
17749
17954
  ChatDateTimeSettings: ChatDateTimeSettings_default,
17750
17955
  ChatSocketStatus: ChatSocketStatus_default
17751
17956
  };
17752
-
17753
- // src/notifications/push.service.ts
17754
- init_client();
17755
- var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
17756
- var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
17757
- var v2Url = "https://realtimex.softwareco.com/api/v2";
17758
- var apiGetPushConfig = async () => {
17759
- const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
17760
- return data?.data;
17761
- };
17762
- var apiRegisterPushToken = async (token, deviceLabel) => {
17763
- const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
17764
- token,
17765
- deviceLabel
17766
- });
17767
- return data?.data;
17768
- };
17769
- var apiRemovePushToken = async (token) => {
17770
- const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
17771
- data: { token }
17772
- });
17773
- return data;
17774
- };
17775
- var apiGetPushPreference = async () => {
17776
- const { data } = await apiClient.get(
17777
- `${v2Url}/notifications/push/preference`
17778
- );
17779
- return data?.data;
17780
- };
17781
- var apiUpdatePushPreference = async (enabled) => {
17782
- const { data } = await apiClient.patch(
17783
- `${v2Url}/notifications/push/preference`,
17784
- { enabled }
17785
- );
17786
- return data?.data;
17787
- };
17788
- var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
17789
- var getStoredPushToken = () => {
17790
- try {
17791
- return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
17792
- } catch {
17793
- return null;
17794
- }
17795
- };
17796
- var storePushToken = (token) => {
17797
- try {
17798
- if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
17799
- else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
17800
- } catch {
17801
- }
17802
- };
17803
- var defaultDeviceLabel = () => {
17804
- const ua = navigator.userAgent;
17805
- const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
17806
- const os = /mac/i.test(ua) ? "macOS" : /windows/i.test(ua) ? "Windows" : /android/i.test(ua) ? "Android" : /iphone|ipad/i.test(ua) ? "iOS" : /linux/i.test(ua) ? "Linux" : "Unknown OS";
17807
- return `${browser} on ${os}`;
17808
- };
17809
- var loadFirebaseMessaging = async () => {
17810
- try {
17811
- const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
17812
- import('firebase/app'),
17813
- import('firebase/messaging')
17814
- ]);
17815
- return { initializeApp, getApps, ...messagingModule };
17816
- } catch {
17817
- throw new Error(
17818
- 'Push notifications need the "firebase" package \u2014 run: npm install firebase'
17819
- );
17820
- }
17821
- };
17822
- var getFirebaseMessaging = async (firebaseConfig) => {
17823
- const fb = await loadFirebaseMessaging();
17824
- const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
17825
- return { fb, messaging: fb.getMessaging(app) };
17826
- };
17827
- var enablePushOnThisDevice = async () => {
17828
- if (!isPushSupported()) {
17829
- throw new Error("Push notifications are not supported in this browser");
17830
- }
17831
- const config = await apiGetPushConfig();
17832
- if (!config?.enabled) {
17833
- throw new Error("Push notifications are disabled for this workspace");
17834
- }
17835
- if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
17836
- throw new Error(
17837
- "Push notifications are not configured on the server yet"
17838
- );
17839
- }
17840
- const permission = await Notification.requestPermission();
17841
- if (permission !== "granted") {
17842
- throw new Error("Notification permission was not granted");
17843
- }
17844
- let registration;
17845
- try {
17846
- registration = await navigator.serviceWorker.register(
17847
- `${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
17848
- JSON.stringify(config.firebaseConfig)
17849
- )}`
17850
- );
17851
- } catch {
17852
- throw new Error(
17853
- `Could not register ${SERVICE_WORKER_PATH} \u2014 copy it from node_modules/@realtimexsco/live-chat/dist/firebase-messaging-sw.js into your app's public folder`
17854
- );
17855
- }
17856
- const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17857
- const token = await fb.getToken(messaging, {
17858
- vapidKey: config.vapidKey,
17859
- serviceWorkerRegistration: registration
17860
- });
17861
- if (!token) {
17862
- throw new Error("Could not obtain a push token from Firebase");
17863
- }
17864
- await apiRegisterPushToken(token, defaultDeviceLabel());
17865
- storePushToken(token);
17866
- return token;
17867
- };
17868
- var disablePushOnThisDevice = async () => {
17869
- const token = getStoredPushToken();
17870
- if (!token) return;
17871
- try {
17872
- const config = await apiGetPushConfig();
17873
- if (config?.firebaseConfig) {
17874
- const { fb, messaging } = await getFirebaseMessaging(
17875
- config.firebaseConfig
17876
- );
17877
- await fb.deleteToken(messaging).catch(() => void 0);
17878
- }
17879
- } catch {
17880
- }
17881
- await apiRemovePushToken(token).catch(() => void 0);
17882
- storePushToken(null);
17883
- };
17884
- var onForegroundPush = async (callback) => {
17885
- const config = await apiGetPushConfig();
17886
- if (!config?.configured || !config.firebaseConfig) return () => void 0;
17887
- const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17888
- return fb.onMessage(messaging, (payload) => {
17889
- callback({
17890
- title: payload?.notification?.title,
17891
- body: payload?.notification?.body,
17892
- data: payload?.data
17893
- });
17894
- });
17895
- };
17896
17957
  var usePushNotifications = () => {
17897
17958
  const [state, setState] = useState({
17898
17959
  supported: false,
@@ -18026,6 +18087,6 @@ var PushNotificationToggle = ({
18026
18087
  // src/index.ts
18027
18088
  var index_default = ChatMain_default;
18028
18089
 
18029
- export { CHAT_API_KEYS, CHAT_GET_API_KEYS, Calendar, CalendarDayButton, Channel, ChannelHeaderView_default as ChannelHeader, ChannelListView_default as ChannelList, ChannelListItem_default as ChannelListItem, Chat, ChatAlertsProvider, ChatAvatar_default as ChatAvatar, ChatCustomizationProvider, ChatDateJumpMenu, ChatLayout_default as ChatLayout, ChatLocaleProvider, ChatMain_default as ChatMain, ChatThemeProvider, ChatViewport, DefaultChannelListItem, DefaultChatAvatar, DefaultChatLayout_default as DefaultChatLayout, ForwardModalView as ForwardModal, HeaderCallActions_default as HeaderCallActions, LoggedUserDetails_default as LoggedUserDetails, ChannelMessageBoxView_default as MessageInput, MessageItemView as MessageItem, ActiveChannelMessagesView_default as MessageList, PushNotificationToggle, apiGetPushConfig, apiGetPushPreference, apiRegisterPushToken, apiRemovePushToken, apiUpdatePushPreference, capitalizeFirst, clampJumpDate, index_default as default, defaultChatClassNames, defaultChatComponents, defaultChatFeatures, defaultChatLayoutConfig, disablePushOnThisDevice, downloadFile, enablePushOnThisDevice, getChatBaseUrl, getChatQueryParamApis, getChatQueryParams, getChatQueryParamsByApi, getChatSocketUrl, getFirstAndLastNameOneCharacter, getResponsiveWidth, getSocketConfig, getStoredPushToken, isEmpty, isPushSupported, mergeChatCustomization, mergeChatLayoutConfig, onForegroundPush, packageDefaultComponents, resolveApiUrl, resolveChatApiKey, resolveJumpDateBounds, resolveJumpPreset, resolveJumpStep, resolveSocketUrl, setChatAccessToken, setChatBaseURL, setChatClientId, setChatQueryParamApis, setChatQueryParams, setChatQueryParamsByApi, setChatSocketUrl, showNotification, smoothScrollToMessage, socket_service_default as socketService, startOfLocalDay, toDateInputValue, uniqueList, useChatAlerts, useChatContext, useChatController, useChatCustomization, useChatCustomizationOptional, useChatFeatures, useChatFeaturesOptional, useChatLocale, useStore as useChatStore, useChatTheme, usePushNotifications };
18090
+ export { CHAT_API_KEYS, CHAT_GET_API_KEYS, Calendar, CalendarDayButton, Channel, ChannelHeaderView_default as ChannelHeader, ChannelListView_default as ChannelList, ChannelListItem_default as ChannelListItem, Chat, ChatAlertsProvider, ChatAvatar_default as ChatAvatar, ChatCustomizationProvider, ChatDateJumpMenu, ChatLayout_default as ChatLayout, ChatLocaleProvider, ChatMain_default as ChatMain, ChatThemeProvider, ChatViewport, DefaultChannelListItem, DefaultChatAvatar, DefaultChatLayout_default as DefaultChatLayout, ForegroundPushBridge, ForwardModalView as ForwardModal, HeaderCallActions_default as HeaderCallActions, LoggedUserDetails_default as LoggedUserDetails, ChannelMessageBoxView_default as MessageInput, MessageItemView as MessageItem, ActiveChannelMessagesView_default as MessageList, PUSH_CHANGED_EVENT, PushNotificationToggle, apiGetPushConfig, apiGetPushPreference, apiRegisterPushToken, apiRemovePushToken, apiUpdatePushPreference, capitalizeFirst, clampJumpDate, index_default as default, defaultChatClassNames, defaultChatComponents, defaultChatFeatures, defaultChatLayoutConfig, disablePushOnThisDevice, downloadFile, enablePushOnThisDevice, getChatBaseUrl, getChatQueryParamApis, getChatQueryParams, getChatQueryParamsByApi, getChatSocketUrl, getFirstAndLastNameOneCharacter, getResponsiveWidth, getSocketConfig, getStoredPushToken, isEmpty, isPushSupported, mergeChatCustomization, mergeChatLayoutConfig, onForegroundPush, packageDefaultComponents, resolveApiUrl, resolveChatApiKey, resolveJumpDateBounds, resolveJumpPreset, resolveJumpStep, resolveSocketUrl, setChatAccessToken, setChatBaseURL, setChatClientId, setChatQueryParamApis, setChatQueryParams, setChatQueryParamsByApi, setChatSocketUrl, showNotification, smoothScrollToMessage, socket_service_default as socketService, startOfLocalDay, toDateInputValue, uniqueList, useChatAlerts, useChatContext, useChatController, useChatCustomization, useChatCustomizationOptional, useChatFeatures, useChatFeaturesOptional, useChatLocale, useStore as useChatStore, useChatTheme, usePushNotifications };
18030
18091
  //# sourceMappingURL=index.mjs.map
18031
18092
  //# sourceMappingURL=index.mjs.map