@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.cjs CHANGED
@@ -7647,6 +7647,76 @@ var HeaderSearchPopover = ({
7647
7647
  ] });
7648
7648
  };
7649
7649
  var HeaderSearchPopover_default = HeaderSearchPopover;
7650
+ var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text)";
7651
+ var DefaultHeaderCallActions = ({
7652
+ activeChannel,
7653
+ conversationId,
7654
+ showPhoneCall = true,
7655
+ showVideoCall = true,
7656
+ onPhoneCall,
7657
+ onVideoCall,
7658
+ className
7659
+ }) => {
7660
+ const { components, slotClassName, features } = useChatCustomizationOptional();
7661
+ const PhoneSlot = components.PhoneCallButton;
7662
+ const VideoSlot = components.VideoCallButton;
7663
+ const hideInGroups = features.hideCallActionsInGroupChats ?? false;
7664
+ if (hideInGroups && activeChannel.isGroup) return null;
7665
+ if (!showPhoneCall && !showVideoCall) return null;
7666
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7667
+ showPhoneCall && (PhoneSlot ? /* @__PURE__ */ jsxRuntime.jsx(
7668
+ PhoneSlot,
7669
+ {
7670
+ activeChannel,
7671
+ conversationId,
7672
+ onPhoneCall,
7673
+ className: cn(className, slotClassName("phoneCallButton"))
7674
+ }
7675
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
7676
+ Button,
7677
+ {
7678
+ variant: "ghost",
7679
+ size: "icon",
7680
+ className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
7681
+ "aria-label": "Voice call",
7682
+ onClick: onPhoneCall,
7683
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 15 })
7684
+ }
7685
+ )),
7686
+ showVideoCall && (VideoSlot ? /* @__PURE__ */ jsxRuntime.jsx(
7687
+ VideoSlot,
7688
+ {
7689
+ activeChannel,
7690
+ conversationId,
7691
+ onVideoCall,
7692
+ className: cn(className, slotClassName("videoCallButton"))
7693
+ }
7694
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
7695
+ Button,
7696
+ {
7697
+ variant: "ghost",
7698
+ size: "icon",
7699
+ className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
7700
+ "aria-label": "Video call",
7701
+ onClick: onVideoCall,
7702
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 15 })
7703
+ }
7704
+ ))
7705
+ ] });
7706
+ };
7707
+ var HeaderCallActions = (props) => {
7708
+ const { components, slotClassName, features } = useChatCustomizationOptional();
7709
+ const Custom = components.HeaderCallActions;
7710
+ if (!Custom) {
7711
+ const hideInGroups = features.hideCallActionsInGroupChats ?? false;
7712
+ const showPhoneCall = props.showPhoneCall ?? true;
7713
+ const showVideoCall = props.showVideoCall ?? true;
7714
+ if (hideInGroups && props.activeChannel.isGroup) return null;
7715
+ if (!showPhoneCall && !showVideoCall) return null;
7716
+ }
7717
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center gap-0.5", slotClassName("headerCallActions")), children: Custom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeaderCallActions, { ...props }) });
7718
+ };
7719
+ var HeaderCallActions_default = HeaderCallActions;
7650
7720
  function OptionsMenuItem({
7651
7721
  icon: Icon,
7652
7722
  label,
@@ -7667,6 +7737,7 @@ function OptionsMenuItem({
7667
7737
  }
7668
7738
  var HeaderRightSide = ({
7669
7739
  activeChannel,
7740
+ conversationId,
7670
7741
  isAdmin,
7671
7742
  canViewMembers,
7672
7743
  pinnedCount,
@@ -7696,6 +7767,15 @@ var HeaderRightSide = ({
7696
7767
  }) => {
7697
7768
  const { scopeClassName, themeStyles, showColorModeToggle } = useChatTheme();
7698
7769
  const { showDateTimeSettings } = useChatLocale();
7770
+ const features = useChatFeaturesOptional();
7771
+ const showPhoneCall = features.showPhoneCall ?? defaultChatFeatures.showPhoneCall;
7772
+ const showVideoCall = features.showVideoCall ?? defaultChatFeatures.showVideoCall;
7773
+ const handlePhoneCall = () => {
7774
+ features.onPhoneCall?.({ activeChannel, conversationId });
7775
+ };
7776
+ const handleVideoCall = () => {
7777
+ features.onVideoCall?.({ activeChannel, conversationId });
7778
+ };
7699
7779
  const headerItemGapClass = "gap-0.5";
7700
7780
  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";
7701
7781
  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)";
@@ -7753,26 +7833,18 @@ var HeaderRightSide = ({
7753
7833
  triggerClassName: headerIconBtnClass
7754
7834
  }
7755
7835
  ),
7756
- /* @__PURE__ */ jsxRuntime.jsx(
7757
- Button,
7758
- {
7759
- variant: "ghost",
7760
- size: "icon-xs",
7761
- className: cn(headerIconBtnClass, "hidden sm:inline-flex"),
7762
- "aria-label": "Voice call",
7763
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 15 })
7764
- }
7765
- ),
7766
- /* @__PURE__ */ jsxRuntime.jsx(
7767
- Button,
7836
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:contents", children: /* @__PURE__ */ jsxRuntime.jsx(
7837
+ HeaderCallActions_default,
7768
7838
  {
7769
- variant: "ghost",
7770
- size: "icon-xs",
7771
- className: cn(headerIconBtnClass, "hidden sm:inline-flex"),
7772
- "aria-label": "Video call",
7773
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 15 })
7839
+ activeChannel,
7840
+ conversationId,
7841
+ showPhoneCall,
7842
+ showVideoCall,
7843
+ onPhoneCall: handlePhoneCall,
7844
+ onVideoCall: handleVideoCall,
7845
+ className: headerIconBtnClass
7774
7846
  }
7775
- ),
7847
+ ) }),
7776
7848
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: headerDividerClass, "aria-hidden": true }),
7777
7849
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
7778
7850
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon-xs", className: headerIconBtnClass, "aria-label": "More options", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { size: 15 }) }) }),
@@ -12910,6 +12982,7 @@ var ChannelHeaderView = (props) => {
12910
12982
  HeaderRightSideSlot,
12911
12983
  {
12912
12984
  activeChannel,
12985
+ conversationId,
12913
12986
  isAdmin,
12914
12987
  canViewMembers,
12915
12988
  pinnedCount,
@@ -17309,156 +17382,6 @@ function ChatViewport({
17309
17382
  );
17310
17383
  }
17311
17384
  var ChatViewport_default = ChatViewport;
17312
- var ChatMain = ({
17313
- clientId,
17314
- loggedUserDetails,
17315
- accessToken,
17316
- apiUrl,
17317
- socketUrl,
17318
- queryParams,
17319
- queryParamApis,
17320
- queryParamsByApi,
17321
- themeColor = "#7494ec",
17322
- theme,
17323
- uiConfig,
17324
- components,
17325
- classNames,
17326
- features,
17327
- layout,
17328
- colorMode,
17329
- defaultColorMode = "light",
17330
- onColorModeChange,
17331
- showColorModeToggle = true,
17332
- locale,
17333
- timeZone,
17334
- hour12,
17335
- defaultLocale,
17336
- defaultTimeZone,
17337
- defaultHour12,
17338
- onDateTimePreferencesChange,
17339
- showDateTimeSettings = true,
17340
- error,
17341
- info,
17342
- onErrorDismiss,
17343
- onInfoDismiss,
17344
- viewportHeight = "full",
17345
- viewportClassName
17346
- }) => {
17347
- const clientObj = React2__namespace.default.useMemo(() => ({ id: clientId }), [clientId]);
17348
- const uiConfigObj = React2__namespace.default.useMemo(
17349
- () => ({
17350
- ...uiConfig || {},
17351
- components: { ...uiConfig?.components, ...components },
17352
- classNames: { ...uiConfig?.classNames, ...classNames },
17353
- features: { ...uiConfig?.features, ...features }
17354
- }),
17355
- [uiConfig, components, classNames, features]
17356
- );
17357
- return /* @__PURE__ */ jsxRuntime.jsx(ChatViewport_default, { height: viewportHeight, className: viewportClassName, children: /* @__PURE__ */ jsxRuntime.jsx(
17358
- ChatThemeProvider,
17359
- {
17360
- themeColor,
17361
- colorMode,
17362
- defaultColorMode,
17363
- onColorModeChange,
17364
- showColorModeToggle,
17365
- children: /* @__PURE__ */ jsxRuntime.jsx(
17366
- ChatLocaleProvider,
17367
- {
17368
- locale,
17369
- timeZone,
17370
- hour12,
17371
- defaultLocale,
17372
- defaultTimeZone,
17373
- defaultHour12,
17374
- onDateTimePreferencesChange,
17375
- showDateTimeSettings,
17376
- children: /* @__PURE__ */ jsxRuntime.jsx(
17377
- Chat,
17378
- {
17379
- client: clientObj,
17380
- accessToken,
17381
- loggedUserDetails,
17382
- themeColor,
17383
- theme,
17384
- uiConfig: uiConfigObj,
17385
- apiUrl,
17386
- socketUrl,
17387
- queryParams,
17388
- queryParamApis,
17389
- queryParamsByApi,
17390
- children: /* @__PURE__ */ jsxRuntime.jsx(
17391
- ChatAlertsProvider,
17392
- {
17393
- value: {
17394
- error,
17395
- info,
17396
- onDismissError: onErrorDismiss,
17397
- onDismissInfo: onInfoDismiss
17398
- },
17399
- children: /* @__PURE__ */ jsxRuntime.jsx(
17400
- ChatLayout_default,
17401
- {
17402
- layout,
17403
- loggedUserDetails,
17404
- themeColor
17405
- }
17406
- )
17407
- }
17408
- )
17409
- }
17410
- )
17411
- }
17412
- )
17413
- }
17414
- ) });
17415
- };
17416
- var ChatMain_default = ChatMain;
17417
-
17418
- // src/index.ts
17419
- init_useStore();
17420
- init_socket_service2();
17421
- var Channel = ({ children }) => {
17422
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex h-full min-w-0 w-full flex-1 flex-col overflow-hidden bg-(--chat-main-bg)", children });
17423
- };
17424
-
17425
- // src/index.ts
17426
- init_api_service();
17427
-
17428
- // src/config/socket.config.ts
17429
- init_client();
17430
- var getSocketConfig = (accessToken, tenantId, options) => {
17431
- const baseURL = resolveSocketUrl(
17432
- options?.socketUrl ?? exports.getChatSocketUrl(),
17433
- options?.apiUrl ?? exports.getChatBaseUrl()
17434
- );
17435
- return {
17436
- url: baseURL,
17437
- options: {
17438
- path: "/connection",
17439
- auth: {
17440
- accessToken
17441
- },
17442
- query: {
17443
- platform: "web",
17444
- tenantId: tenantId || "",
17445
- isTenant: "true"
17446
- },
17447
- extraHeaders: {
17448
- Authorization: `Bearer ${accessToken}`,
17449
- platform: "web",
17450
- tenantId: tenantId || "",
17451
- isTenant: "true"
17452
- },
17453
- transports: ["websocket", "polling"],
17454
- reconnection: true,
17455
- reconnectionAttempts: Infinity,
17456
- reconnectionDelay: 2e3,
17457
- reconnectionDelayMax: 5e3,
17458
- timeout: 2e4
17459
- }
17460
- };
17461
- };
17462
17385
  var showNotification = (message, type = "info", icon, duration) => {
17463
17386
  const options = {
17464
17387
  icon,
@@ -17533,21 +17456,373 @@ var getFirstAndLastNameOneCharacter = (name) => {
17533
17456
  const names = name.split(" ");
17534
17457
  return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
17535
17458
  };
17536
- var SIZE_MAP = {
17537
- xs: "size-6",
17538
- sm: "size-8",
17539
- md: "size-9",
17540
- lg: "size-10",
17541
- xl: "size-12"
17459
+
17460
+ // src/notifications/ForegroundPushBridge.tsx
17461
+ init_useStore();
17462
+
17463
+ // src/notifications/push.service.ts
17464
+ init_client();
17465
+ var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
17466
+ var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
17467
+ var PUSH_CHANGED_EVENT = "realtimex:push-changed";
17468
+ var emitPushChanged = (enabled) => {
17469
+ try {
17470
+ window.dispatchEvent(
17471
+ new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
17472
+ );
17473
+ } catch {
17474
+ }
17542
17475
  };
17543
- var DefaultChatAvatar = ({
17544
- src,
17545
- alt,
17546
- name,
17547
- fallback,
17548
- size = "md",
17549
- showOnline = false,
17550
- isOnline = false,
17476
+ var v2Url = "https://realtimex.softwareco.com/api/v2";
17477
+ var apiGetPushConfig = async () => {
17478
+ const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
17479
+ return data?.data;
17480
+ };
17481
+ var apiRegisterPushToken = async (token, deviceLabel) => {
17482
+ const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
17483
+ token,
17484
+ deviceLabel
17485
+ });
17486
+ return data?.data;
17487
+ };
17488
+ var apiRemovePushToken = async (token) => {
17489
+ const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
17490
+ data: { token }
17491
+ });
17492
+ return data;
17493
+ };
17494
+ var apiGetPushPreference = async () => {
17495
+ const { data } = await apiClient.get(
17496
+ `${v2Url}/notifications/push/preference`
17497
+ );
17498
+ return data?.data;
17499
+ };
17500
+ var apiUpdatePushPreference = async (enabled) => {
17501
+ const { data } = await apiClient.patch(
17502
+ `${v2Url}/notifications/push/preference`,
17503
+ { enabled }
17504
+ );
17505
+ return data?.data;
17506
+ };
17507
+ var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
17508
+ var getStoredPushToken = () => {
17509
+ try {
17510
+ return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
17511
+ } catch {
17512
+ return null;
17513
+ }
17514
+ };
17515
+ var storePushToken = (token) => {
17516
+ try {
17517
+ if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
17518
+ else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
17519
+ } catch {
17520
+ }
17521
+ };
17522
+ var defaultDeviceLabel = () => {
17523
+ const ua = navigator.userAgent;
17524
+ const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
17525
+ 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";
17526
+ return `${browser} on ${os}`;
17527
+ };
17528
+ var loadFirebaseMessaging = async () => {
17529
+ try {
17530
+ const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
17531
+ import('firebase/app'),
17532
+ import('firebase/messaging')
17533
+ ]);
17534
+ return { initializeApp, getApps, ...messagingModule };
17535
+ } catch {
17536
+ throw new Error(
17537
+ 'Push notifications need the "firebase" package \u2014 run: npm install firebase'
17538
+ );
17539
+ }
17540
+ };
17541
+ var getFirebaseMessaging = async (firebaseConfig) => {
17542
+ const fb = await loadFirebaseMessaging();
17543
+ const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
17544
+ return { fb, messaging: fb.getMessaging(app) };
17545
+ };
17546
+ var enablePushOnThisDevice = async () => {
17547
+ if (!isPushSupported()) {
17548
+ throw new Error("Push notifications are not supported in this browser");
17549
+ }
17550
+ const config = await apiGetPushConfig();
17551
+ if (!config?.enabled) {
17552
+ throw new Error("Push notifications are disabled for this workspace");
17553
+ }
17554
+ if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
17555
+ throw new Error(
17556
+ "Push notifications are not configured on the server yet"
17557
+ );
17558
+ }
17559
+ const permission = await Notification.requestPermission();
17560
+ if (permission !== "granted") {
17561
+ throw new Error("Notification permission was not granted");
17562
+ }
17563
+ let registration;
17564
+ try {
17565
+ registration = await navigator.serviceWorker.register(
17566
+ `${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
17567
+ JSON.stringify(config.firebaseConfig)
17568
+ )}`
17569
+ );
17570
+ } catch {
17571
+ throw new Error(
17572
+ `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`
17573
+ );
17574
+ }
17575
+ const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17576
+ const token = await fb.getToken(messaging, {
17577
+ vapidKey: config.vapidKey,
17578
+ serviceWorkerRegistration: registration
17579
+ });
17580
+ if (!token) {
17581
+ throw new Error("Could not obtain a push token from Firebase");
17582
+ }
17583
+ await apiRegisterPushToken(token, defaultDeviceLabel());
17584
+ storePushToken(token);
17585
+ emitPushChanged(true);
17586
+ return token;
17587
+ };
17588
+ var disablePushOnThisDevice = async () => {
17589
+ const token = getStoredPushToken();
17590
+ if (!token) return;
17591
+ try {
17592
+ const config = await apiGetPushConfig();
17593
+ if (config?.firebaseConfig) {
17594
+ const { fb, messaging } = await getFirebaseMessaging(
17595
+ config.firebaseConfig
17596
+ );
17597
+ await fb.deleteToken(messaging).catch(() => void 0);
17598
+ }
17599
+ } catch {
17600
+ }
17601
+ await apiRemovePushToken(token).catch(() => void 0);
17602
+ storePushToken(null);
17603
+ emitPushChanged(false);
17604
+ };
17605
+ var onForegroundPush = async (callback) => {
17606
+ const config = await apiGetPushConfig();
17607
+ if (!config?.configured || !config.firebaseConfig) return () => void 0;
17608
+ const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17609
+ return fb.onMessage(messaging, (payload) => {
17610
+ callback({
17611
+ title: payload?.notification?.title,
17612
+ body: payload?.notification?.body,
17613
+ data: payload?.data
17614
+ });
17615
+ });
17616
+ };
17617
+
17618
+ // src/notifications/ForegroundPushBridge.tsx
17619
+ var ForegroundPushBridge = ({ onPush }) => {
17620
+ React2.useEffect(() => {
17621
+ let unsubscribe = null;
17622
+ let cancelled = false;
17623
+ const handlePayload = (payload) => {
17624
+ const incoming = payload.data?.conversationId;
17625
+ const activeId = exports.useChatStore.getState().activeConversationId;
17626
+ if (incoming && activeId && incoming === activeId) return;
17627
+ if (onPush && onPush(payload) !== false) return;
17628
+ const text = payload.title ? payload.body ? `${payload.title}: ${payload.body}` : payload.title : payload.body;
17629
+ if (text) showNotification(text, "info");
17630
+ };
17631
+ const start = async () => {
17632
+ if (cancelled || unsubscribe || !getStoredPushToken()) return;
17633
+ try {
17634
+ const stop = await onForegroundPush(handlePayload);
17635
+ if (cancelled) stop();
17636
+ else unsubscribe = stop;
17637
+ } catch {
17638
+ }
17639
+ };
17640
+ void start();
17641
+ const onPushChanged = (event) => {
17642
+ const enabled = event.detail?.enabled;
17643
+ if (enabled) void start();
17644
+ else {
17645
+ unsubscribe?.();
17646
+ unsubscribe = null;
17647
+ }
17648
+ };
17649
+ window.addEventListener(PUSH_CHANGED_EVENT, onPushChanged);
17650
+ return () => {
17651
+ cancelled = true;
17652
+ unsubscribe?.();
17653
+ window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
17654
+ };
17655
+ }, [onPush]);
17656
+ return null;
17657
+ };
17658
+ var ChatMain = ({
17659
+ clientId,
17660
+ loggedUserDetails,
17661
+ accessToken,
17662
+ apiUrl,
17663
+ socketUrl,
17664
+ queryParams,
17665
+ queryParamApis,
17666
+ queryParamsByApi,
17667
+ themeColor = "#7494ec",
17668
+ theme,
17669
+ uiConfig,
17670
+ components,
17671
+ classNames,
17672
+ features,
17673
+ layout,
17674
+ colorMode,
17675
+ defaultColorMode = "light",
17676
+ onColorModeChange,
17677
+ showColorModeToggle = true,
17678
+ locale,
17679
+ timeZone,
17680
+ hour12,
17681
+ defaultLocale,
17682
+ defaultTimeZone,
17683
+ defaultHour12,
17684
+ onDateTimePreferencesChange,
17685
+ showDateTimeSettings = true,
17686
+ error,
17687
+ info,
17688
+ onErrorDismiss,
17689
+ onInfoDismiss,
17690
+ viewportHeight = "full",
17691
+ viewportClassName
17692
+ }) => {
17693
+ const clientObj = React2__namespace.default.useMemo(() => ({ id: clientId }), [clientId]);
17694
+ const uiConfigObj = React2__namespace.default.useMemo(
17695
+ () => ({
17696
+ ...uiConfig || {},
17697
+ components: { ...uiConfig?.components, ...components },
17698
+ classNames: { ...uiConfig?.classNames, ...classNames },
17699
+ features: { ...uiConfig?.features, ...features }
17700
+ }),
17701
+ [uiConfig, components, classNames, features]
17702
+ );
17703
+ return /* @__PURE__ */ jsxRuntime.jsx(ChatViewport_default, { height: viewportHeight, className: viewportClassName, children: /* @__PURE__ */ jsxRuntime.jsx(
17704
+ ChatThemeProvider,
17705
+ {
17706
+ themeColor,
17707
+ colorMode,
17708
+ defaultColorMode,
17709
+ onColorModeChange,
17710
+ showColorModeToggle,
17711
+ children: /* @__PURE__ */ jsxRuntime.jsx(
17712
+ ChatLocaleProvider,
17713
+ {
17714
+ locale,
17715
+ timeZone,
17716
+ hour12,
17717
+ defaultLocale,
17718
+ defaultTimeZone,
17719
+ defaultHour12,
17720
+ onDateTimePreferencesChange,
17721
+ showDateTimeSettings,
17722
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
17723
+ Chat,
17724
+ {
17725
+ client: clientObj,
17726
+ accessToken,
17727
+ loggedUserDetails,
17728
+ themeColor,
17729
+ theme,
17730
+ uiConfig: uiConfigObj,
17731
+ apiUrl,
17732
+ socketUrl,
17733
+ queryParams,
17734
+ queryParamApis,
17735
+ queryParamsByApi,
17736
+ children: [
17737
+ /* @__PURE__ */ jsxRuntime.jsx(ForegroundPushBridge, {}),
17738
+ /* @__PURE__ */ jsxRuntime.jsx(
17739
+ ChatAlertsProvider,
17740
+ {
17741
+ value: {
17742
+ error,
17743
+ info,
17744
+ onDismissError: onErrorDismiss,
17745
+ onDismissInfo: onInfoDismiss
17746
+ },
17747
+ children: /* @__PURE__ */ jsxRuntime.jsx(
17748
+ ChatLayout_default,
17749
+ {
17750
+ layout,
17751
+ loggedUserDetails,
17752
+ themeColor
17753
+ }
17754
+ )
17755
+ }
17756
+ )
17757
+ ]
17758
+ }
17759
+ )
17760
+ }
17761
+ )
17762
+ }
17763
+ ) });
17764
+ };
17765
+ var ChatMain_default = ChatMain;
17766
+
17767
+ // src/index.ts
17768
+ init_useStore();
17769
+ init_socket_service2();
17770
+ var Channel = ({ children }) => {
17771
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex h-full min-w-0 w-full flex-1 flex-col overflow-hidden bg-(--chat-main-bg)", children });
17772
+ };
17773
+
17774
+ // src/index.ts
17775
+ init_api_service();
17776
+
17777
+ // src/config/socket.config.ts
17778
+ init_client();
17779
+ var getSocketConfig = (accessToken, tenantId, options) => {
17780
+ const baseURL = resolveSocketUrl(
17781
+ options?.socketUrl ?? exports.getChatSocketUrl(),
17782
+ options?.apiUrl ?? exports.getChatBaseUrl()
17783
+ );
17784
+ return {
17785
+ url: baseURL,
17786
+ options: {
17787
+ path: "/connection",
17788
+ auth: {
17789
+ accessToken
17790
+ },
17791
+ query: {
17792
+ platform: "web",
17793
+ tenantId: tenantId || "",
17794
+ isTenant: "true"
17795
+ },
17796
+ extraHeaders: {
17797
+ Authorization: `Bearer ${accessToken}`,
17798
+ platform: "web",
17799
+ tenantId: tenantId || "",
17800
+ isTenant: "true"
17801
+ },
17802
+ transports: ["websocket", "polling"],
17803
+ reconnection: true,
17804
+ reconnectionAttempts: Infinity,
17805
+ reconnectionDelay: 2e3,
17806
+ reconnectionDelayMax: 5e3,
17807
+ timeout: 2e4
17808
+ }
17809
+ };
17810
+ };
17811
+ var SIZE_MAP = {
17812
+ xs: "size-6",
17813
+ sm: "size-8",
17814
+ md: "size-9",
17815
+ lg: "size-10",
17816
+ xl: "size-12"
17817
+ };
17818
+ var DefaultChatAvatar = ({
17819
+ src,
17820
+ alt,
17821
+ name,
17822
+ fallback,
17823
+ size = "md",
17824
+ showOnline = false,
17825
+ isOnline = false,
17551
17826
  className,
17552
17827
  fallbackClassName
17553
17828
  }) => {
@@ -17671,76 +17946,6 @@ var ChannelListItem2 = (props) => {
17671
17946
  return /* @__PURE__ */ jsxRuntime.jsx(ItemSlot, { ...props });
17672
17947
  };
17673
17948
  var ChannelListItem_default = ChannelListItem2;
17674
- var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text)";
17675
- var DefaultHeaderCallActions = ({
17676
- activeChannel,
17677
- conversationId,
17678
- showPhoneCall = true,
17679
- showVideoCall = true,
17680
- onPhoneCall,
17681
- onVideoCall,
17682
- className
17683
- }) => {
17684
- const { components, slotClassName, features } = useChatCustomizationOptional();
17685
- const PhoneSlot = components.PhoneCallButton;
17686
- const VideoSlot = components.VideoCallButton;
17687
- const hideInGroups = features.hideCallActionsInGroupChats ?? false;
17688
- if (hideInGroups && activeChannel.isGroup) return null;
17689
- if (!showPhoneCall && !showVideoCall) return null;
17690
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17691
- showPhoneCall && (PhoneSlot ? /* @__PURE__ */ jsxRuntime.jsx(
17692
- PhoneSlot,
17693
- {
17694
- activeChannel,
17695
- conversationId,
17696
- onPhoneCall,
17697
- className: cn(className, slotClassName("phoneCallButton"))
17698
- }
17699
- ) : /* @__PURE__ */ jsxRuntime.jsx(
17700
- Button,
17701
- {
17702
- variant: "ghost",
17703
- size: "icon",
17704
- className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
17705
- "aria-label": "Voice call",
17706
- onClick: onPhoneCall,
17707
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 15 })
17708
- }
17709
- )),
17710
- showVideoCall && (VideoSlot ? /* @__PURE__ */ jsxRuntime.jsx(
17711
- VideoSlot,
17712
- {
17713
- activeChannel,
17714
- conversationId,
17715
- onVideoCall,
17716
- className: cn(className, slotClassName("videoCallButton"))
17717
- }
17718
- ) : /* @__PURE__ */ jsxRuntime.jsx(
17719
- Button,
17720
- {
17721
- variant: "ghost",
17722
- size: "icon",
17723
- className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
17724
- "aria-label": "Video call",
17725
- onClick: onVideoCall,
17726
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 15 })
17727
- }
17728
- ))
17729
- ] });
17730
- };
17731
- var HeaderCallActions = (props) => {
17732
- const { components, slotClassName, features } = useChatCustomizationOptional();
17733
- const Custom = components.HeaderCallActions;
17734
- if (!Custom) {
17735
- const hideInGroups = features.hideCallActionsInGroupChats ?? false;
17736
- const showPhoneCall = props.showPhoneCall ?? true;
17737
- const showVideoCall = props.showVideoCall ?? true;
17738
- if (hideInGroups && props.activeChannel.isGroup) return null;
17739
- if (!showPhoneCall && !showVideoCall) return null;
17740
- }
17741
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: slotClassName("headerCallActions"), children: Custom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeaderCallActions, { ...props }) });
17742
- };
17743
- var HeaderCallActions_default = HeaderCallActions;
17744
17949
 
17745
17950
  // src/chat/packageDefaultComponents.ts
17746
17951
  var packageDefaultComponents = {
@@ -17776,150 +17981,6 @@ var packageDefaultComponents = {
17776
17981
  ChatDateTimeSettings: ChatDateTimeSettings_default,
17777
17982
  ChatSocketStatus: ChatSocketStatus_default
17778
17983
  };
17779
-
17780
- // src/notifications/push.service.ts
17781
- init_client();
17782
- var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
17783
- var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
17784
- var v2Url = "https://realtimex.softwareco.com/api/v2";
17785
- var apiGetPushConfig = async () => {
17786
- const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
17787
- return data?.data;
17788
- };
17789
- var apiRegisterPushToken = async (token, deviceLabel) => {
17790
- const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
17791
- token,
17792
- deviceLabel
17793
- });
17794
- return data?.data;
17795
- };
17796
- var apiRemovePushToken = async (token) => {
17797
- const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
17798
- data: { token }
17799
- });
17800
- return data;
17801
- };
17802
- var apiGetPushPreference = async () => {
17803
- const { data } = await apiClient.get(
17804
- `${v2Url}/notifications/push/preference`
17805
- );
17806
- return data?.data;
17807
- };
17808
- var apiUpdatePushPreference = async (enabled) => {
17809
- const { data } = await apiClient.patch(
17810
- `${v2Url}/notifications/push/preference`,
17811
- { enabled }
17812
- );
17813
- return data?.data;
17814
- };
17815
- var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
17816
- var getStoredPushToken = () => {
17817
- try {
17818
- return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
17819
- } catch {
17820
- return null;
17821
- }
17822
- };
17823
- var storePushToken = (token) => {
17824
- try {
17825
- if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
17826
- else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
17827
- } catch {
17828
- }
17829
- };
17830
- var defaultDeviceLabel = () => {
17831
- const ua = navigator.userAgent;
17832
- const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
17833
- 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";
17834
- return `${browser} on ${os}`;
17835
- };
17836
- var loadFirebaseMessaging = async () => {
17837
- try {
17838
- const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
17839
- import('firebase/app'),
17840
- import('firebase/messaging')
17841
- ]);
17842
- return { initializeApp, getApps, ...messagingModule };
17843
- } catch {
17844
- throw new Error(
17845
- 'Push notifications need the "firebase" package \u2014 run: npm install firebase'
17846
- );
17847
- }
17848
- };
17849
- var getFirebaseMessaging = async (firebaseConfig) => {
17850
- const fb = await loadFirebaseMessaging();
17851
- const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
17852
- return { fb, messaging: fb.getMessaging(app) };
17853
- };
17854
- var enablePushOnThisDevice = async () => {
17855
- if (!isPushSupported()) {
17856
- throw new Error("Push notifications are not supported in this browser");
17857
- }
17858
- const config = await apiGetPushConfig();
17859
- if (!config?.enabled) {
17860
- throw new Error("Push notifications are disabled for this workspace");
17861
- }
17862
- if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
17863
- throw new Error(
17864
- "Push notifications are not configured on the server yet"
17865
- );
17866
- }
17867
- const permission = await Notification.requestPermission();
17868
- if (permission !== "granted") {
17869
- throw new Error("Notification permission was not granted");
17870
- }
17871
- let registration;
17872
- try {
17873
- registration = await navigator.serviceWorker.register(
17874
- `${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
17875
- JSON.stringify(config.firebaseConfig)
17876
- )}`
17877
- );
17878
- } catch {
17879
- throw new Error(
17880
- `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`
17881
- );
17882
- }
17883
- const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17884
- const token = await fb.getToken(messaging, {
17885
- vapidKey: config.vapidKey,
17886
- serviceWorkerRegistration: registration
17887
- });
17888
- if (!token) {
17889
- throw new Error("Could not obtain a push token from Firebase");
17890
- }
17891
- await apiRegisterPushToken(token, defaultDeviceLabel());
17892
- storePushToken(token);
17893
- return token;
17894
- };
17895
- var disablePushOnThisDevice = async () => {
17896
- const token = getStoredPushToken();
17897
- if (!token) return;
17898
- try {
17899
- const config = await apiGetPushConfig();
17900
- if (config?.firebaseConfig) {
17901
- const { fb, messaging } = await getFirebaseMessaging(
17902
- config.firebaseConfig
17903
- );
17904
- await fb.deleteToken(messaging).catch(() => void 0);
17905
- }
17906
- } catch {
17907
- }
17908
- await apiRemovePushToken(token).catch(() => void 0);
17909
- storePushToken(null);
17910
- };
17911
- var onForegroundPush = async (callback) => {
17912
- const config = await apiGetPushConfig();
17913
- if (!config?.configured || !config.firebaseConfig) return () => void 0;
17914
- const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17915
- return fb.onMessage(messaging, (payload) => {
17916
- callback({
17917
- title: payload?.notification?.title,
17918
- body: payload?.notification?.body,
17919
- data: payload?.data
17920
- });
17921
- });
17922
- };
17923
17984
  var usePushNotifications = () => {
17924
17985
  const [state, setState] = React2.useState({
17925
17986
  supported: false,
@@ -18072,12 +18133,14 @@ exports.ChatViewport = ChatViewport;
18072
18133
  exports.DefaultChannelListItem = DefaultChannelListItem;
18073
18134
  exports.DefaultChatAvatar = DefaultChatAvatar;
18074
18135
  exports.DefaultChatLayout = DefaultChatLayout_default;
18136
+ exports.ForegroundPushBridge = ForegroundPushBridge;
18075
18137
  exports.ForwardModal = ForwardModalView;
18076
18138
  exports.HeaderCallActions = HeaderCallActions_default;
18077
18139
  exports.LoggedUserDetails = LoggedUserDetails_default;
18078
18140
  exports.MessageInput = ChannelMessageBoxView_default;
18079
18141
  exports.MessageItem = MessageItemView;
18080
18142
  exports.MessageList = ActiveChannelMessagesView_default;
18143
+ exports.PUSH_CHANGED_EVENT = PUSH_CHANGED_EVENT;
18081
18144
  exports.PushNotificationToggle = PushNotificationToggle;
18082
18145
  exports.apiGetPushConfig = apiGetPushConfig;
18083
18146
  exports.apiGetPushPreference = apiGetPushPreference;