@realtimexsco/live-chat 1.4.9 → 1.4.10

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
@@ -16,7 +16,7 @@ var lucideReact = require('lucide-react');
16
16
  var classVarianceAuthority = require('class-variance-authority');
17
17
  var EmojiPicker = require('emoji-picker-react');
18
18
  var reactDayPicker = require('react-day-picker');
19
- var toast2 = require('react-hot-toast');
19
+ var toast = require('react-hot-toast');
20
20
 
21
21
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
22
22
 
@@ -41,7 +41,7 @@ function _interopNamespace(e) {
41
41
  var axios__default = /*#__PURE__*/_interopDefault(axios);
42
42
  var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
43
43
  var EmojiPicker__default = /*#__PURE__*/_interopDefault(EmojiPicker);
44
- var toast2__default = /*#__PURE__*/_interopDefault(toast2);
44
+ var toast__default = /*#__PURE__*/_interopDefault(toast);
45
45
 
46
46
  var __defProp = Object.defineProperty;
47
47
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -4660,7 +4660,9 @@ init_store_helpers();
4660
4660
  var OPEN_CONVERSATION_EVENT = "realtimex:open-conversation";
4661
4661
  var NOTIFICATION_CLICK_SW_TYPE = "realtimex:notification-click";
4662
4662
  var PUSH_BROADCAST_CHANNEL = "realtimex-push";
4663
+ var PUSH_DATA_CACHE_NAME = "realtimex-push-data-v1";
4663
4664
  var PENDING_STORAGE_KEY = "realtimex:pending-open-conversation";
4665
+ var PENDING_OPEN_CACHE_PATH = "pending-open";
4664
4666
  var resolveConversationIdFromPushData = (data) => {
4665
4667
  if (!data || typeof data !== "object") return "";
4666
4668
  let fcmMsg = data.FCM_MSG;
@@ -4801,6 +4803,37 @@ var mapConversationToChannel = (conversation, loggedUserId, allUsers) => {
4801
4803
  starredCount: conversation.starredCount
4802
4804
  };
4803
4805
  };
4806
+ var stripConversationIdFromUrl = () => {
4807
+ if (typeof window === "undefined") return;
4808
+ try {
4809
+ const url = new URL(window.location.href);
4810
+ if (!url.searchParams.has("conversationId")) return;
4811
+ url.searchParams.delete("conversationId");
4812
+ const next = `${url.pathname}${url.search}${url.hash}`;
4813
+ window.history.replaceState(window.history.state, "", next);
4814
+ } catch {
4815
+ }
4816
+ };
4817
+ var cacheRequestForPath = (path) => new Request(new URL(path, window.location.origin).toString());
4818
+ var consumePendingOpenFromPushCache = async () => {
4819
+ if (typeof caches === "undefined") return null;
4820
+ try {
4821
+ const cache = await caches.open(PUSH_DATA_CACHE_NAME);
4822
+ const req = cacheRequestForPath(PENDING_OPEN_CACHE_PATH);
4823
+ const res = await cache.match(req);
4824
+ if (!res) return null;
4825
+ await cache.delete(req);
4826
+ const data = await res.json();
4827
+ const conversationId = resolveConversationIdFromPushData(data);
4828
+ if (!conversationId) return null;
4829
+ return {
4830
+ conversationId,
4831
+ ...normalizePushMeta(data)
4832
+ };
4833
+ } catch {
4834
+ return null;
4835
+ }
4836
+ };
4804
4837
  var readConversationIdFromLocation = () => {
4805
4838
  try {
4806
4839
  return new URLSearchParams(window.location.search).get("conversationId") || "";
@@ -4809,16 +4842,33 @@ var readConversationIdFromLocation = () => {
4809
4842
  }
4810
4843
  };
4811
4844
  var consumedUrlConversationIds = /* @__PURE__ */ new Set();
4845
+ var lastHandledOpenId = "";
4846
+ var lastHandledOpenAt = 0;
4847
+ var shouldHandleOpen = (conversationId) => {
4848
+ const id = String(conversationId || "").trim();
4849
+ if (!id) return false;
4850
+ const now = Date.now();
4851
+ if (lastHandledOpenId === id && now - lastHandledOpenAt < 2500) {
4852
+ return false;
4853
+ }
4854
+ lastHandledOpenId = id;
4855
+ lastHandledOpenAt = now;
4856
+ return true;
4857
+ };
4812
4858
  var handleNotificationOpen = (conversationId, pushData, options) => {
4813
4859
  const id = String(conversationId || "").trim();
4814
4860
  if (!id) {
4815
4861
  console.warn("[realtimex-push] notification open ignored \u2014 no conversationId", pushData);
4816
4862
  return;
4817
4863
  }
4864
+ if (!shouldHandleOpen(id)) {
4865
+ stripConversationIdFromUrl();
4866
+ return;
4867
+ }
4818
4868
  requestOpenConversation(id, pushData);
4819
4869
  const chatPath = options.chatPath || "/chat";
4820
- const pathWithQuery = `${chatPath}?conversationId=${encodeURIComponent(id)}`;
4821
- options.onNavigate?.(id, pathWithQuery);
4870
+ stripConversationIdFromUrl();
4871
+ options.onNavigate?.(id, chatPath);
4822
4872
  };
4823
4873
  var installNotificationClickBridge = (options = {}) => {
4824
4874
  if (typeof window === "undefined") return () => void 0;
@@ -4845,7 +4895,17 @@ var installNotificationClickBridge = (options = {}) => {
4845
4895
  if (fromUrl && !consumedUrlConversationIds.has(fromUrl)) {
4846
4896
  consumedUrlConversationIds.add(fromUrl);
4847
4897
  handleNotificationOpen(fromUrl, void 0, options);
4898
+ } else {
4899
+ stripConversationIdFromUrl();
4848
4900
  }
4901
+ void consumePendingOpenFromPushCache().then((request) => {
4902
+ if (!request?.conversationId) return;
4903
+ handleNotificationOpen(
4904
+ request.conversationId,
4905
+ request,
4906
+ options
4907
+ );
4908
+ });
4849
4909
  return () => {
4850
4910
  navigator.serviceWorker?.removeEventListener("message", onSwMessage);
4851
4911
  broadcast?.close();
@@ -6483,194 +6543,572 @@ var CreateChatDialog = (props) => {
6483
6543
  );
6484
6544
  };
6485
6545
  var CreateChatDialog_default = CreateChatDialog;
6486
- var LoggedUserDetails = ({
6487
- loggedUserDetails,
6488
- onUserSelect,
6489
- isCreateModalOpen = false,
6490
- setIsCreateModalOpen,
6491
- searchQuery = "",
6492
- setSearchQuery
6493
- }) => {
6494
- const { showColorModeToggle } = useChatTheme();
6495
- const user = {
6496
- _id: loggedUserDetails?._id || "1",
6497
- name: formatLoggedUserName(loggedUserDetails?.name),
6498
- email: loggedUserDetails?.email || "user@example.com",
6499
- role: loggedUserDetails?.role || "user",
6500
- isActive: loggedUserDetails?.isActive ?? true,
6501
- createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
6502
- updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
6503
- image: loggedUserDetails?.image || void 0
6504
- };
6505
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b border-(--chat-border) bg-(--chat-surface) px-3 pb-3 pt-3", children: [
6506
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
6507
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative shrink-0", children: [
6508
- /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-8 ring-1 ring-(--chat-surface)", children: [
6509
- user.image ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
6510
- /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-[10px] font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
6511
- ] }),
6512
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -bottom-0.5 -right-0.5 size-2 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
6513
- ] }),
6514
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
6515
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "truncate text-xs font-medium leading-tight text-(--chat-text)", children: user.name }),
6516
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[10px] text-(--chat-muted)", children: user.email })
6517
- ] }),
6518
- showColorModeToggle ? /* @__PURE__ */ jsxRuntime.jsx(ChatThemeToggle_default, {}) : null
6519
- ] }),
6520
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center gap-1.5", children: [
6521
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chatSidebarSearchShellClass, children: [
6522
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "pointer-events-none size-3.5 shrink-0 text-(--chat-muted)" }),
6523
- /* @__PURE__ */ jsxRuntime.jsx(
6524
- "input",
6525
- {
6526
- type: "text",
6527
- inputMode: "search",
6528
- enterKeyHint: "search",
6529
- placeholder: "Search conversations...",
6530
- value: searchQuery,
6531
- onChange: (e) => setSearchQuery?.(e.target.value),
6532
- className: chatSidebarSearchInputClass
6533
- }
6534
- ),
6535
- searchQuery ? /* @__PURE__ */ jsxRuntime.jsx(
6536
- "button",
6537
- {
6538
- type: "button",
6539
- onClick: () => setSearchQuery?.(""),
6540
- className: "flex size-6 shrink-0 items-center justify-center rounded-md text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text)",
6541
- "aria-label": "Clear search",
6542
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 12 })
6543
- }
6544
- ) : null
6545
- ] }),
6546
- /* @__PURE__ */ jsxRuntime.jsx(
6547
- CreateChatDialog_default,
6548
- {
6549
- loggedUserDetails,
6550
- onUserSelect,
6551
- isCreateModalOpen,
6552
- setIsCreateModalOpen
6553
- }
6554
- )
6555
- ] })
6556
- ] });
6557
- };
6558
- var LoggedUserDetails_default = LoggedUserDetails;
6559
- function ScrollArea({
6560
- className,
6561
- children,
6562
- ...props
6563
- }) {
6564
- return /* @__PURE__ */ jsxRuntime.jsxs(
6565
- radixUi.ScrollArea.Root,
6566
- {
6567
- "data-slot": "scroll-area",
6568
- className: cn("relative", className),
6569
- ...props,
6570
- children: [
6571
- /* @__PURE__ */ jsxRuntime.jsx(
6572
- radixUi.ScrollArea.Viewport,
6573
- {
6574
- "data-slot": "scroll-area-viewport",
6575
- className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
6576
- children
6577
- }
6578
- ),
6579
- /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
6580
- /* @__PURE__ */ jsxRuntime.jsx(radixUi.ScrollArea.Corner, {})
6581
- ]
6582
- }
6583
- );
6584
- }
6585
- function ScrollBar({
6546
+ function Switch({
6586
6547
  className,
6587
- orientation = "vertical",
6548
+ size = "default",
6588
6549
  ...props
6589
6550
  }) {
6590
6551
  return /* @__PURE__ */ jsxRuntime.jsx(
6591
- radixUi.ScrollArea.ScrollAreaScrollbar,
6552
+ radixUi.Switch.Root,
6592
6553
  {
6593
- "data-slot": "scroll-area-scrollbar",
6594
- orientation,
6554
+ "data-slot": "switch",
6555
+ "data-size": size,
6595
6556
  className: cn(
6596
- "flex touch-none p-px transition-colors select-none",
6597
- orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
6598
- orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
6557
+ "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
6599
6558
  className
6600
6559
  ),
6601
6560
  ...props,
6602
6561
  children: /* @__PURE__ */ jsxRuntime.jsx(
6603
- radixUi.ScrollArea.ScrollAreaThumb,
6562
+ radixUi.Switch.Thumb,
6604
6563
  {
6605
- "data-slot": "scroll-area-thumb",
6606
- className: "bg-border relative flex-1 rounded-full"
6564
+ "data-slot": "switch-thumb",
6565
+ className: cn(
6566
+ "pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground"
6567
+ )
6607
6568
  }
6608
6569
  )
6609
6570
  }
6610
6571
  );
6611
6572
  }
6612
6573
 
6613
- // src/chat/channel-list/useChannelList.ts
6614
- init_useStore();
6615
- init_store_helpers();
6616
- var conversationDrafts = /* @__PURE__ */ new Map();
6617
- var DRAFT_PREVIEW_MAX_LENGTH = 50;
6618
- var emptyDraft = () => ({
6619
- messageInput: "",
6620
- attachments: []
6621
- });
6622
- var draftRevision = 0;
6623
- var draftListeners = /* @__PURE__ */ new Set();
6624
- function notifyDraftChange() {
6625
- draftRevision += 1;
6626
- draftListeners.forEach((listener) => listener());
6627
- }
6628
- function subscribeToDrafts(listener) {
6629
- draftListeners.add(listener);
6630
- return () => {
6631
- draftListeners.delete(listener);
6632
- };
6633
- }
6634
- function getDraftRevision() {
6635
- return draftRevision;
6636
- }
6637
- function useDraftRevision() {
6638
- return React2.useSyncExternalStore(subscribeToDrafts, getDraftRevision, getDraftRevision);
6639
- }
6640
- function getConversationDraft(conversationId) {
6641
- if (!conversationId) return emptyDraft();
6642
- return conversationDrafts.get(conversationId) ?? emptyDraft();
6643
- }
6644
- function updateConversationDraft(conversationId, draft) {
6645
- if (!conversationId) return;
6646
- if (draft.messageInput.trim() || draft.attachments.length > 0) {
6647
- conversationDrafts.set(conversationId, {
6648
- messageInput: draft.messageInput,
6649
- attachments: draft.attachments
6650
- });
6651
- } else {
6652
- conversationDrafts.delete(conversationId);
6574
+ // src/notifications/push.service.ts
6575
+ init_client();
6576
+ var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
6577
+ var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
6578
+ var PUSH_CHANGED_EVENT = "realtimex:push-changed";
6579
+ var emitPushChanged = (enabled) => {
6580
+ try {
6581
+ window.dispatchEvent(
6582
+ new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
6583
+ );
6584
+ } catch {
6653
6585
  }
6654
- notifyDraftChange();
6655
- }
6656
- function clearConversationDraft(conversationId) {
6657
- if (!conversationId) return;
6658
- if (!conversationDrafts.has(conversationId)) return;
6659
- conversationDrafts.delete(conversationId);
6660
- notifyDraftChange();
6661
- }
6662
- function getConversationDraftPreview(conversationId) {
6663
- if (!conversationId) return null;
6664
- const draft = conversationDrafts.get(conversationId);
6665
- if (!draft) return null;
6666
- const text = draft.messageInput.trim();
6667
- if (text) {
6668
- return text.length > DRAFT_PREVIEW_MAX_LENGTH ? `${text.slice(0, DRAFT_PREVIEW_MAX_LENGTH)}\u2026` : text;
6586
+ };
6587
+ var v2Url = "https://realtimex.softwareco.com/api/v2";
6588
+ var apiGetPushConfig = async () => {
6589
+ const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
6590
+ return data?.data;
6591
+ };
6592
+ var apiRegisterPushToken = async (token, deviceLabel) => {
6593
+ const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
6594
+ token,
6595
+ deviceLabel
6596
+ });
6597
+ return data?.data;
6598
+ };
6599
+ var apiRemovePushToken = async (token) => {
6600
+ const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
6601
+ data: { token }
6602
+ });
6603
+ return data;
6604
+ };
6605
+ var apiGetPushPreference = async () => {
6606
+ const { data } = await apiClient.get(
6607
+ `${v2Url}/notifications/push/preference`
6608
+ );
6609
+ return data?.data;
6610
+ };
6611
+ var apiUpdatePushPreference = async (enabled) => {
6612
+ const { data } = await apiClient.patch(
6613
+ `${v2Url}/notifications/push/preference`,
6614
+ { enabled }
6615
+ );
6616
+ return data?.data;
6617
+ };
6618
+ var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
6619
+ var getStoredPushToken = () => {
6620
+ try {
6621
+ return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
6622
+ } catch {
6623
+ return null;
6669
6624
  }
6670
- if (draft.attachments.length > 0) {
6671
- return draft.attachments.length === 1 ? "Attachment" : `${draft.attachments.length} attachments`;
6625
+ };
6626
+ var storePushToken = (token) => {
6627
+ try {
6628
+ if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
6629
+ else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
6630
+ } catch {
6672
6631
  }
6673
- return null;
6632
+ };
6633
+ var defaultDeviceLabel = () => {
6634
+ const ua = navigator.userAgent;
6635
+ const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
6636
+ 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";
6637
+ return `${browser} on ${os}`;
6638
+ };
6639
+ var loadFirebaseMessaging = async () => {
6640
+ try {
6641
+ const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
6642
+ import('firebase/app'),
6643
+ import('firebase/messaging')
6644
+ ]);
6645
+ return { initializeApp, getApps, ...messagingModule };
6646
+ } catch {
6647
+ throw new Error(
6648
+ 'Push notifications need the "firebase" package \u2014 run: npm install firebase'
6649
+ );
6650
+ }
6651
+ };
6652
+ var getFirebaseMessaging = async (firebaseConfig) => {
6653
+ const fb = await loadFirebaseMessaging();
6654
+ const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
6655
+ return { fb, messaging: fb.getMessaging(app) };
6656
+ };
6657
+ var enablePushOnThisDevice = async () => {
6658
+ if (!isPushSupported()) {
6659
+ throw new Error("Push notifications are not supported in this browser");
6660
+ }
6661
+ const config = await apiGetPushConfig();
6662
+ if (!config?.enabled) {
6663
+ throw new Error("Push notifications are disabled for this workspace");
6664
+ }
6665
+ if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
6666
+ throw new Error(
6667
+ "Push notifications are not configured on the server yet"
6668
+ );
6669
+ }
6670
+ const permission = await Notification.requestPermission();
6671
+ if (permission !== "granted") {
6672
+ throw new Error("Notification permission was not granted");
6673
+ }
6674
+ let registration;
6675
+ try {
6676
+ registration = await navigator.serviceWorker.register(
6677
+ `${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
6678
+ JSON.stringify(config.firebaseConfig)
6679
+ )}`
6680
+ );
6681
+ } catch {
6682
+ throw new Error(
6683
+ `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`
6684
+ );
6685
+ }
6686
+ const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
6687
+ const token = await fb.getToken(messaging, {
6688
+ vapidKey: config.vapidKey,
6689
+ serviceWorkerRegistration: registration
6690
+ });
6691
+ if (!token) {
6692
+ throw new Error("Could not obtain a push token from Firebase");
6693
+ }
6694
+ await apiRegisterPushToken(token, defaultDeviceLabel());
6695
+ storePushToken(token);
6696
+ emitPushChanged(true);
6697
+ return token;
6698
+ };
6699
+ var disablePushOnThisDevice = async () => {
6700
+ const token = getStoredPushToken();
6701
+ if (!token) return;
6702
+ try {
6703
+ const config = await apiGetPushConfig();
6704
+ if (config?.firebaseConfig) {
6705
+ const { fb, messaging } = await getFirebaseMessaging(
6706
+ config.firebaseConfig
6707
+ );
6708
+ await fb.deleteToken(messaging).catch(() => void 0);
6709
+ }
6710
+ } catch {
6711
+ }
6712
+ await apiRemovePushToken(token).catch(() => void 0);
6713
+ storePushToken(null);
6714
+ emitPushChanged(false);
6715
+ };
6716
+ var onForegroundPush = async (callback) => {
6717
+ const config = await apiGetPushConfig();
6718
+ if (!config?.configured || !config.firebaseConfig) {
6719
+ throw new Error("Push config unavailable (not configured or API not ready)");
6720
+ }
6721
+ const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
6722
+ return fb.onMessage(messaging, (payload) => {
6723
+ console.log("[realtimex-push] FCM foreground payload (raw):", payload);
6724
+ console.log("[realtimex-push] FCM foreground data:", payload?.data);
6725
+ console.log("[realtimex-push] FCM foreground notification:", payload?.notification);
6726
+ callback({
6727
+ title: payload?.notification?.title,
6728
+ body: payload?.notification?.body,
6729
+ data: payload?.data
6730
+ });
6731
+ });
6732
+ };
6733
+
6734
+ // src/notifications/usePushNotifications.ts
6735
+ var usePushNotifications = () => {
6736
+ const [state, setState] = React2.useState({
6737
+ supported: false,
6738
+ allowedByWorkspace: false,
6739
+ configured: false,
6740
+ permission: "unsupported",
6741
+ userEnabled: true,
6742
+ deviceEnabled: false,
6743
+ loading: true,
6744
+ error: null
6745
+ });
6746
+ const refresh = React2.useCallback(async () => {
6747
+ if (!isPushSupported()) {
6748
+ setState((prev) => ({
6749
+ ...prev,
6750
+ supported: false,
6751
+ loading: false
6752
+ }));
6753
+ return;
6754
+ }
6755
+ try {
6756
+ const [config, preference] = await Promise.all([
6757
+ apiGetPushConfig(),
6758
+ apiGetPushPreference().catch(() => null)
6759
+ ]);
6760
+ setState({
6761
+ supported: true,
6762
+ allowedByWorkspace: Boolean(config?.enabled),
6763
+ configured: Boolean(config?.configured),
6764
+ permission: Notification.permission,
6765
+ userEnabled: preference?.enabled ?? true,
6766
+ deviceEnabled: Notification.permission === "granted" && Boolean(getStoredPushToken()),
6767
+ loading: false,
6768
+ error: null
6769
+ });
6770
+ } catch (error) {
6771
+ setState((prev) => ({
6772
+ ...prev,
6773
+ supported: true,
6774
+ loading: false,
6775
+ error: error instanceof Error ? error.message : "Could not load push settings"
6776
+ }));
6777
+ }
6778
+ }, []);
6779
+ React2.useEffect(() => {
6780
+ void refresh();
6781
+ }, [refresh]);
6782
+ const enable = React2.useCallback(async () => {
6783
+ setState((prev) => ({ ...prev, loading: true, error: null }));
6784
+ try {
6785
+ await enablePushOnThisDevice();
6786
+ await refresh();
6787
+ return true;
6788
+ } catch (error) {
6789
+ setState((prev) => ({
6790
+ ...prev,
6791
+ loading: false,
6792
+ permission: isPushSupported() ? Notification.permission : "unsupported",
6793
+ error: error instanceof Error ? error.message : "Could not enable push notifications"
6794
+ }));
6795
+ return false;
6796
+ }
6797
+ }, [refresh]);
6798
+ const disable = React2.useCallback(async () => {
6799
+ setState((prev) => ({ ...prev, loading: true, error: null }));
6800
+ try {
6801
+ await disablePushOnThisDevice();
6802
+ } finally {
6803
+ await refresh();
6804
+ }
6805
+ }, [refresh]);
6806
+ const setUserEnabled = React2.useCallback(
6807
+ async (enabled) => {
6808
+ setState((prev) => ({ ...prev, userEnabled: enabled }));
6809
+ try {
6810
+ await apiUpdatePushPreference(enabled);
6811
+ } catch (error) {
6812
+ setState((prev) => ({
6813
+ ...prev,
6814
+ userEnabled: !enabled,
6815
+ error: error instanceof Error ? error.message : "Could not update push preference"
6816
+ }));
6817
+ }
6818
+ },
6819
+ []
6820
+ );
6821
+ return { ...state, enable, disable, setUserEnabled, refresh };
6822
+ };
6823
+ var PushNotificationToggle = ({
6824
+ className,
6825
+ label = "Push notifications",
6826
+ description = "Get notified about new messages on this device"
6827
+ }) => {
6828
+ const push = usePushNotifications();
6829
+ if (!push.supported || !push.allowedByWorkspace || !push.configured) {
6830
+ return null;
6831
+ }
6832
+ const isOn = push.deviceEnabled && push.userEnabled;
6833
+ const permissionBlocked = push.permission === "denied";
6834
+ const handleChange = async (checked) => {
6835
+ if (checked) {
6836
+ if (!push.userEnabled) await push.setUserEnabled(true);
6837
+ if (!push.deviceEnabled) await push.enable();
6838
+ } else {
6839
+ await push.disable();
6840
+ }
6841
+ };
6842
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6843
+ "div",
6844
+ {
6845
+ className: className ?? "flex items-center justify-between gap-4 rounded-xl border border-(--chat-border) bg-(--chat-surface) px-4 py-3",
6846
+ children: [
6847
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
6848
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-(--chat-text)", children: label }),
6849
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-(--chat-muted)", children: permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description })
6850
+ ] }),
6851
+ /* @__PURE__ */ jsxRuntime.jsx(
6852
+ Switch,
6853
+ {
6854
+ checked: isOn,
6855
+ disabled: push.loading || permissionBlocked,
6856
+ onCheckedChange: (checked) => void handleChange(checked),
6857
+ "aria-label": `Toggle ${label}`
6858
+ }
6859
+ )
6860
+ ]
6861
+ }
6862
+ );
6863
+ };
6864
+ var LoggedUserSettingsDialog = ({
6865
+ loggedUserDetails
6866
+ }) => {
6867
+ const [open, setOpen] = React2.useState(false);
6868
+ const user = {
6869
+ _id: loggedUserDetails?._id || "1",
6870
+ name: formatLoggedUserName(loggedUserDetails?.name),
6871
+ email: loggedUserDetails?.email || "user@example.com",
6872
+ role: loggedUserDetails?.role || "user",
6873
+ isActive: loggedUserDetails?.isActive ?? true,
6874
+ createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
6875
+ updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
6876
+ image: loggedUserDetails?.image || void 0
6877
+ };
6878
+ return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { open, onOpenChange: setOpen, children: [
6879
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6880
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6881
+ Button,
6882
+ {
6883
+ type: "button",
6884
+ variant: "ghost",
6885
+ size: "icon",
6886
+ className: sidebarActionBtnClass,
6887
+ "aria-label": "Account settings",
6888
+ onClick: () => setOpen(true),
6889
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { className: "size-3.5", strokeWidth: 2 })
6890
+ }
6891
+ ) }),
6892
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "bottom", children: "Settings" })
6893
+ ] }),
6894
+ /* @__PURE__ */ jsxRuntime.jsxs(ChatDialogContent, { className: "gap-0 overflow-hidden p-0 sm:max-w-[380px]", children: [
6895
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-(--chat-border) px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-left text-base font-semibold text-(--chat-text)", children: "Account settings" }) }),
6896
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5 px-5 py-5", children: [
6897
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center text-center", children: [
6898
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
6899
+ /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-16 ring-2 ring-(--chat-theme-20)", children: [
6900
+ user.image ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
6901
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-lg font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
6902
+ ] }),
6903
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute bottom-0.5 right-0.5 size-3 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
6904
+ ] }),
6905
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mt-3 text-base font-semibold text-(--chat-text)", children: user.name }),
6906
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-sm text-(--chat-muted)", children: user.email }),
6907
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2 inline-flex items-center gap-1.5 rounded-full bg-(--chat-theme-10) px-2.5 py-0.5 text-xs font-medium text-(--chat-theme)", children: [
6908
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 rounded-full bg-(--chat-online)" }),
6909
+ "Online"
6910
+ ] })
6911
+ ] }),
6912
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-(--chat-border) pt-4", children: /* @__PURE__ */ jsxRuntime.jsx(PushNotificationToggle, { className: "flex items-center justify-between gap-4 rounded-xl border border-(--chat-border) bg-(--chat-theme-10) px-4 py-3" }) })
6913
+ ] })
6914
+ ] })
6915
+ ] });
6916
+ };
6917
+ var LoggedUserSettingsDialog_default = LoggedUserSettingsDialog;
6918
+ var LoggedUserDetails = ({
6919
+ loggedUserDetails,
6920
+ onUserSelect,
6921
+ isCreateModalOpen = false,
6922
+ setIsCreateModalOpen,
6923
+ searchQuery = "",
6924
+ setSearchQuery
6925
+ }) => {
6926
+ const { showColorModeToggle } = useChatTheme();
6927
+ const user = {
6928
+ _id: loggedUserDetails?._id || "1",
6929
+ name: formatLoggedUserName(loggedUserDetails?.name),
6930
+ email: loggedUserDetails?.email || "user@example.com",
6931
+ role: loggedUserDetails?.role || "user",
6932
+ isActive: loggedUserDetails?.isActive ?? true,
6933
+ createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
6934
+ updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
6935
+ image: loggedUserDetails?.image || void 0
6936
+ };
6937
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b border-(--chat-border) bg-(--chat-surface) px-3 pb-3 pt-3", children: [
6938
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
6939
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative shrink-0", children: [
6940
+ /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-8 ring-1 ring-(--chat-surface)", children: [
6941
+ user.image ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
6942
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-[10px] font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
6943
+ ] }),
6944
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -bottom-0.5 -right-0.5 size-2 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
6945
+ ] }),
6946
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
6947
+ /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "truncate text-xs font-medium leading-tight text-(--chat-text)", children: [
6948
+ user.name,
6949
+ "123"
6950
+ ] }),
6951
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[10px] text-(--chat-muted)", children: user.email })
6952
+ ] }),
6953
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [
6954
+ /* @__PURE__ */ jsxRuntime.jsx(LoggedUserSettingsDialog_default, { loggedUserDetails }),
6955
+ showColorModeToggle ? /* @__PURE__ */ jsxRuntime.jsx(ChatThemeToggle_default, {}) : null
6956
+ ] })
6957
+ ] }),
6958
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center gap-1.5", children: [
6959
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chatSidebarSearchShellClass, children: [
6960
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "pointer-events-none size-3.5 shrink-0 text-(--chat-muted)" }),
6961
+ /* @__PURE__ */ jsxRuntime.jsx(
6962
+ "input",
6963
+ {
6964
+ type: "text",
6965
+ inputMode: "search",
6966
+ enterKeyHint: "search",
6967
+ placeholder: "Search conversations...",
6968
+ value: searchQuery,
6969
+ onChange: (e) => setSearchQuery?.(e.target.value),
6970
+ className: chatSidebarSearchInputClass
6971
+ }
6972
+ ),
6973
+ searchQuery ? /* @__PURE__ */ jsxRuntime.jsx(
6974
+ "button",
6975
+ {
6976
+ type: "button",
6977
+ onClick: () => setSearchQuery?.(""),
6978
+ className: "flex size-6 shrink-0 items-center justify-center rounded-md text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text)",
6979
+ "aria-label": "Clear search",
6980
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 12 })
6981
+ }
6982
+ ) : null
6983
+ ] }),
6984
+ /* @__PURE__ */ jsxRuntime.jsx(
6985
+ CreateChatDialog_default,
6986
+ {
6987
+ loggedUserDetails,
6988
+ onUserSelect,
6989
+ isCreateModalOpen,
6990
+ setIsCreateModalOpen
6991
+ }
6992
+ )
6993
+ ] })
6994
+ ] });
6995
+ };
6996
+ var LoggedUserDetails_default = LoggedUserDetails;
6997
+ function ScrollArea({
6998
+ className,
6999
+ children,
7000
+ ...props
7001
+ }) {
7002
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7003
+ radixUi.ScrollArea.Root,
7004
+ {
7005
+ "data-slot": "scroll-area",
7006
+ className: cn("relative", className),
7007
+ ...props,
7008
+ children: [
7009
+ /* @__PURE__ */ jsxRuntime.jsx(
7010
+ radixUi.ScrollArea.Viewport,
7011
+ {
7012
+ "data-slot": "scroll-area-viewport",
7013
+ className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
7014
+ children
7015
+ }
7016
+ ),
7017
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
7018
+ /* @__PURE__ */ jsxRuntime.jsx(radixUi.ScrollArea.Corner, {})
7019
+ ]
7020
+ }
7021
+ );
7022
+ }
7023
+ function ScrollBar({
7024
+ className,
7025
+ orientation = "vertical",
7026
+ ...props
7027
+ }) {
7028
+ return /* @__PURE__ */ jsxRuntime.jsx(
7029
+ radixUi.ScrollArea.ScrollAreaScrollbar,
7030
+ {
7031
+ "data-slot": "scroll-area-scrollbar",
7032
+ orientation,
7033
+ className: cn(
7034
+ "flex touch-none p-px transition-colors select-none",
7035
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
7036
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
7037
+ className
7038
+ ),
7039
+ ...props,
7040
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7041
+ radixUi.ScrollArea.ScrollAreaThumb,
7042
+ {
7043
+ "data-slot": "scroll-area-thumb",
7044
+ className: "bg-border relative flex-1 rounded-full"
7045
+ }
7046
+ )
7047
+ }
7048
+ );
7049
+ }
7050
+
7051
+ // src/chat/channel-list/useChannelList.ts
7052
+ init_useStore();
7053
+ init_store_helpers();
7054
+ var conversationDrafts = /* @__PURE__ */ new Map();
7055
+ var DRAFT_PREVIEW_MAX_LENGTH = 50;
7056
+ var emptyDraft = () => ({
7057
+ messageInput: "",
7058
+ attachments: []
7059
+ });
7060
+ var draftRevision = 0;
7061
+ var draftListeners = /* @__PURE__ */ new Set();
7062
+ function notifyDraftChange() {
7063
+ draftRevision += 1;
7064
+ draftListeners.forEach((listener) => listener());
7065
+ }
7066
+ function subscribeToDrafts(listener) {
7067
+ draftListeners.add(listener);
7068
+ return () => {
7069
+ draftListeners.delete(listener);
7070
+ };
7071
+ }
7072
+ function getDraftRevision() {
7073
+ return draftRevision;
7074
+ }
7075
+ function useDraftRevision() {
7076
+ return React2.useSyncExternalStore(subscribeToDrafts, getDraftRevision, getDraftRevision);
7077
+ }
7078
+ function getConversationDraft(conversationId) {
7079
+ if (!conversationId) return emptyDraft();
7080
+ return conversationDrafts.get(conversationId) ?? emptyDraft();
7081
+ }
7082
+ function updateConversationDraft(conversationId, draft) {
7083
+ if (!conversationId) return;
7084
+ if (draft.messageInput.trim() || draft.attachments.length > 0) {
7085
+ conversationDrafts.set(conversationId, {
7086
+ messageInput: draft.messageInput,
7087
+ attachments: draft.attachments
7088
+ });
7089
+ } else {
7090
+ conversationDrafts.delete(conversationId);
7091
+ }
7092
+ notifyDraftChange();
7093
+ }
7094
+ function clearConversationDraft(conversationId) {
7095
+ if (!conversationId) return;
7096
+ if (!conversationDrafts.has(conversationId)) return;
7097
+ conversationDrafts.delete(conversationId);
7098
+ notifyDraftChange();
7099
+ }
7100
+ function getConversationDraftPreview(conversationId) {
7101
+ if (!conversationId) return null;
7102
+ const draft = conversationDrafts.get(conversationId);
7103
+ if (!draft) return null;
7104
+ const text = draft.messageInput.trim();
7105
+ if (text) {
7106
+ return text.length > DRAFT_PREVIEW_MAX_LENGTH ? `${text.slice(0, DRAFT_PREVIEW_MAX_LENGTH)}\u2026` : text;
7107
+ }
7108
+ if (draft.attachments.length > 0) {
7109
+ return draft.attachments.length === 1 ? "Attachment" : `${draft.attachments.length} attachments`;
7110
+ }
7111
+ return null;
6674
7112
  }
6675
7113
  function useConversationDraft(conversationId) {
6676
7114
  const composerRef = React2.useRef(emptyDraft());
@@ -12225,52 +12663,23 @@ var ChannelDetailsDrawer = (props) => {
12225
12663
  participantCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5 pb-1", children: participants.map((p, index) => {
12226
12664
  const pId = typeof p === "string" ? p : p._id;
12227
12665
  const pName = typeof p === "string" ? "Unknown" : p.name;
12228
- if (!pId) return null;
12229
- return /* @__PURE__ */ jsxRuntime.jsx(
12230
- "span",
12231
- {
12232
- className: "rounded-md border border-(--chat-border) bg-(--chat-input-bg)/50 px-2 py-0.5 text-[10px] font-medium text-(--chat-text-secondary)",
12233
- children: pName
12234
- },
12235
- `${pId}-${index}`
12236
- );
12237
- }) })
12238
- ] })
12239
- ] })
12240
- ] })
12241
- ] })
12242
- ] }) });
12243
- };
12244
- var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
12245
- function Switch({
12246
- className,
12247
- size = "default",
12248
- ...props
12249
- }) {
12250
- return /* @__PURE__ */ jsxRuntime.jsx(
12251
- radixUi.Switch.Root,
12252
- {
12253
- "data-slot": "switch",
12254
- "data-size": size,
12255
- className: cn(
12256
- "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
12257
- className
12258
- ),
12259
- ...props,
12260
- children: /* @__PURE__ */ jsxRuntime.jsx(
12261
- radixUi.Switch.Thumb,
12262
- {
12263
- "data-slot": "switch-thumb",
12264
- className: cn(
12265
- "pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground"
12266
- )
12267
- }
12268
- )
12269
- }
12270
- );
12271
- }
12272
-
12273
- // src/chat/header/PermissionDrawer.tsx
12666
+ if (!pId) return null;
12667
+ return /* @__PURE__ */ jsxRuntime.jsx(
12668
+ "span",
12669
+ {
12670
+ className: "rounded-md border border-(--chat-border) bg-(--chat-input-bg)/50 px-2 py-0.5 text-[10px] font-medium text-(--chat-text-secondary)",
12671
+ children: pName
12672
+ },
12673
+ `${pId}-${index}`
12674
+ );
12675
+ }) })
12676
+ ] })
12677
+ ] })
12678
+ ] })
12679
+ ] })
12680
+ ] }) });
12681
+ };
12682
+ var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
12274
12683
  init_useStore();
12275
12684
  var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo }) => {
12276
12685
  const updateGroupPermissions = exports.useChatStore((s) => s.updateGroupPermissions);
@@ -17662,251 +18071,15 @@ function ChatViewport({
17662
18071
  "chat-package-viewport flex min-h-0 w-full flex-col overflow-hidden",
17663
18072
  resolved.className,
17664
18073
  className
17665
- ),
17666
- style: { ...resolved.style, ...style },
17667
- children
17668
- }
17669
- );
17670
- }
17671
- var ChatViewport_default = ChatViewport;
17672
- var showNotification = (message, type = "info", icon, duration) => {
17673
- const options = {
17674
- icon,
17675
- duration
17676
- };
17677
- switch (type) {
17678
- case "success":
17679
- toast2.toast.success(message, options);
17680
- break;
17681
- case "error":
17682
- toast2.toast.error(message, options);
17683
- break;
17684
- case "info":
17685
- toast2.toast(message, options);
17686
- break;
17687
- case "warning":
17688
- toast2.toast(message, { ...options, icon: "\u26A0\uFE0F" });
17689
- break;
17690
- default:
17691
- toast2.toast(message, options);
17692
- }
17693
- };
17694
- var downloadFile = async (src, name) => {
17695
- try {
17696
- const link = document.createElement("a");
17697
- link.href = src;
17698
- link.setAttribute("download", name);
17699
- link.setAttribute("rel", "noopener noreferrer");
17700
- link.click();
17701
- showNotification("File Downloaded Successfully", "success");
17702
- } catch (err) {
17703
- console.error("File download failed:", err);
17704
- showNotification("Failed to download file", "error");
17705
- }
17706
- };
17707
- var getResponsiveWidth = (width) => {
17708
- const screenWidth = window.innerWidth;
17709
- if (width) {
17710
- return width;
17711
- } else if (screenWidth < 640) {
17712
- return 350;
17713
- } else if (screenWidth >= 640 && screenWidth < 1024) {
17714
- return 600;
17715
- } else if (screenWidth >= 1024 && screenWidth < 1280) {
17716
- return 800;
17717
- } else {
17718
- return 1e3;
17719
- }
17720
- };
17721
- var isEmpty = (value) => {
17722
- if (value === null || value === void 0) return true;
17723
- if (typeof value === "string") return value.trim().length === 0;
17724
- if (Array.isArray(value)) {
17725
- return value.length === 0 || value.every((item) => isEmpty(item));
17726
- }
17727
- if (typeof value === "object") {
17728
- return Object.keys(value).length === 0;
17729
- }
17730
- return false;
17731
- };
17732
- function uniqueList(list, key) {
17733
- const seen = /* @__PURE__ */ new Set();
17734
- return list.filter((item) => {
17735
- const value = item[key];
17736
- if (seen.has(value)) return false;
17737
- seen.add(value);
17738
- return true;
17739
- });
17740
- }
17741
- var capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
17742
- var getFirstAndLastNameOneCharacter = (name) => {
17743
- const names = name.split(" ");
17744
- return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
17745
- };
17746
-
17747
- // src/notifications/ForegroundPushBridge.tsx
17748
- init_normalize_helpers();
17749
- init_useStore();
17750
-
17751
- // src/notifications/push.service.ts
17752
- init_client();
17753
- var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
17754
- var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
17755
- var PUSH_CHANGED_EVENT = "realtimex:push-changed";
17756
- var emitPushChanged = (enabled) => {
17757
- try {
17758
- window.dispatchEvent(
17759
- new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
17760
- );
17761
- } catch {
17762
- }
17763
- };
17764
- var v2Url = "https://realtimex.softwareco.com/api/v2";
17765
- var apiGetPushConfig = async () => {
17766
- const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
17767
- return data?.data;
17768
- };
17769
- var apiRegisterPushToken = async (token, deviceLabel) => {
17770
- const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
17771
- token,
17772
- deviceLabel
17773
- });
17774
- return data?.data;
17775
- };
17776
- var apiRemovePushToken = async (token) => {
17777
- const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
17778
- data: { token }
17779
- });
17780
- return data;
17781
- };
17782
- var apiGetPushPreference = async () => {
17783
- const { data } = await apiClient.get(
17784
- `${v2Url}/notifications/push/preference`
17785
- );
17786
- return data?.data;
17787
- };
17788
- var apiUpdatePushPreference = async (enabled) => {
17789
- const { data } = await apiClient.patch(
17790
- `${v2Url}/notifications/push/preference`,
17791
- { enabled }
17792
- );
17793
- return data?.data;
17794
- };
17795
- var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
17796
- var getStoredPushToken = () => {
17797
- try {
17798
- return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
17799
- } catch {
17800
- return null;
17801
- }
17802
- };
17803
- var storePushToken = (token) => {
17804
- try {
17805
- if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
17806
- else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
17807
- } catch {
17808
- }
17809
- };
17810
- var defaultDeviceLabel = () => {
17811
- const ua = navigator.userAgent;
17812
- const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
17813
- 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";
17814
- return `${browser} on ${os}`;
17815
- };
17816
- var loadFirebaseMessaging = async () => {
17817
- try {
17818
- const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
17819
- import('firebase/app'),
17820
- import('firebase/messaging')
17821
- ]);
17822
- return { initializeApp, getApps, ...messagingModule };
17823
- } catch {
17824
- throw new Error(
17825
- 'Push notifications need the "firebase" package \u2014 run: npm install firebase'
17826
- );
17827
- }
17828
- };
17829
- var getFirebaseMessaging = async (firebaseConfig) => {
17830
- const fb = await loadFirebaseMessaging();
17831
- const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
17832
- return { fb, messaging: fb.getMessaging(app) };
17833
- };
17834
- var enablePushOnThisDevice = async () => {
17835
- if (!isPushSupported()) {
17836
- throw new Error("Push notifications are not supported in this browser");
17837
- }
17838
- const config = await apiGetPushConfig();
17839
- if (!config?.enabled) {
17840
- throw new Error("Push notifications are disabled for this workspace");
17841
- }
17842
- if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
17843
- throw new Error(
17844
- "Push notifications are not configured on the server yet"
17845
- );
17846
- }
17847
- const permission = await Notification.requestPermission();
17848
- if (permission !== "granted") {
17849
- throw new Error("Notification permission was not granted");
17850
- }
17851
- let registration;
17852
- try {
17853
- registration = await navigator.serviceWorker.register(
17854
- `${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
17855
- JSON.stringify(config.firebaseConfig)
17856
- )}`
17857
- );
17858
- } catch {
17859
- throw new Error(
17860
- `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`
17861
- );
17862
- }
17863
- const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17864
- const token = await fb.getToken(messaging, {
17865
- vapidKey: config.vapidKey,
17866
- serviceWorkerRegistration: registration
17867
- });
17868
- if (!token) {
17869
- throw new Error("Could not obtain a push token from Firebase");
17870
- }
17871
- await apiRegisterPushToken(token, defaultDeviceLabel());
17872
- storePushToken(token);
17873
- emitPushChanged(true);
17874
- return token;
17875
- };
17876
- var disablePushOnThisDevice = async () => {
17877
- const token = getStoredPushToken();
17878
- if (!token) return;
17879
- try {
17880
- const config = await apiGetPushConfig();
17881
- if (config?.firebaseConfig) {
17882
- const { fb, messaging } = await getFirebaseMessaging(
17883
- config.firebaseConfig
17884
- );
17885
- await fb.deleteToken(messaging).catch(() => void 0);
17886
- }
17887
- } catch {
17888
- }
17889
- await apiRemovePushToken(token).catch(() => void 0);
17890
- storePushToken(null);
17891
- emitPushChanged(false);
17892
- };
17893
- var onForegroundPush = async (callback) => {
17894
- const config = await apiGetPushConfig();
17895
- if (!config?.configured || !config.firebaseConfig) {
17896
- throw new Error("Push config unavailable (not configured or API not ready)");
17897
- }
17898
- const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
17899
- return fb.onMessage(messaging, (payload) => {
17900
- console.log("[realtimex-push] FCM foreground payload (raw):", payload);
17901
- console.log("[realtimex-push] FCM foreground data:", payload?.data);
17902
- console.log("[realtimex-push] FCM foreground notification:", payload?.notification);
17903
- callback({
17904
- title: payload?.notification?.title,
17905
- body: payload?.notification?.body,
17906
- data: payload?.data
17907
- });
17908
- });
17909
- };
18074
+ ),
18075
+ style: { ...resolved.style, ...style },
18076
+ children
18077
+ }
18078
+ );
18079
+ }
18080
+ var ChatViewport_default = ChatViewport;
18081
+ init_normalize_helpers();
18082
+ init_useStore();
17910
18083
  var RETRY_DELAYS_MS = [1e3, 3e3, 8e3, 2e4];
17911
18084
  var recentToastIds = /* @__PURE__ */ new Set();
17912
18085
  var rememberToastId = (id) => {
@@ -17920,48 +18093,95 @@ var rememberToastId = (id) => {
17920
18093
  }
17921
18094
  return true;
17922
18095
  };
17923
- var resolveToastText = (title, body) => {
17924
- if (title && body) return `${title}: ${body}`;
17925
- return title || body || "";
18096
+ var truncate = (value, max) => value.length > max ? `${value.slice(0, max - 1)}\u2026` : value;
18097
+ var PushMessageToast = ({
18098
+ t,
18099
+ title,
18100
+ body,
18101
+ onOpen
18102
+ }) => {
18103
+ const dismiss = () => toast__default.default.dismiss(t.id);
18104
+ const handleDismiss = (event) => {
18105
+ event.stopPropagation();
18106
+ dismiss();
18107
+ };
18108
+ const handleOpen = () => {
18109
+ dismiss();
18110
+ onOpen?.();
18111
+ };
18112
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18113
+ "div",
18114
+ {
18115
+ role: "alert",
18116
+ "aria-live": "polite",
18117
+ onClick: onOpen ? handleOpen : void 0,
18118
+ onKeyDown: onOpen ? (event) => {
18119
+ if (event.key === "Enter" || event.key === " ") {
18120
+ event.preventDefault();
18121
+ handleOpen();
18122
+ }
18123
+ } : void 0,
18124
+ tabIndex: onOpen ? 0 : void 0,
18125
+ className: cn(
18126
+ "pointer-events-auto flex w-[min(320px,calc(100vw-24px))] items-start gap-3 rounded-xl border border-(--chat-border) bg-(--chat-surface) p-3 shadow-[0_8px_24px_rgba(15,23,42,0.12)] transition-[opacity,transform] duration-200 ease-out",
18127
+ onOpen && "cursor-pointer hover:border-(--chat-theme-20) hover:shadow-[0_10px_28px_rgba(15,23,42,0.16)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--chat-theme-30)",
18128
+ t.visible ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"
18129
+ ),
18130
+ children: [
18131
+ /* @__PURE__ */ jsxRuntime.jsx(
18132
+ "div",
18133
+ {
18134
+ "aria-hidden": true,
18135
+ className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-(--chat-theme-10) text-(--chat-theme)",
18136
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-4", strokeWidth: 2.25 })
18137
+ }
18138
+ ),
18139
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [
18140
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold uppercase tracking-wide text-(--chat-muted)", children: "New message" }),
18141
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 truncate text-sm font-semibold leading-snug text-(--chat-text)", children: truncate(title, 40) }),
18142
+ body ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-relaxed text-(--chat-muted)", children: truncate(body, 72) }) : null
18143
+ ] }),
18144
+ /* @__PURE__ */ jsxRuntime.jsx(
18145
+ "button",
18146
+ {
18147
+ type: "button",
18148
+ "aria-label": "Dismiss notification",
18149
+ onClick: handleDismiss,
18150
+ className: "shrink-0 rounded-md p-1 text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--chat-theme-30)",
18151
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4", strokeWidth: 2 })
18152
+ }
18153
+ )
18154
+ ]
18155
+ }
18156
+ );
17926
18157
  };
17927
18158
  var emitToast = (payload, onPush) => {
17928
18159
  if (onPush && onPush(payload) !== false) return;
17929
- const title = payload.title || payload.data?.title;
17930
- const body = payload.body || payload.data?.body || payload.data?.message;
17931
- const text = resolveToastText(title, body);
18160
+ const title = payload.title || payload.data?.title || "New message";
18161
+ const body = payload.body || payload.data?.body || payload.data?.message || "";
17932
18162
  const conversationId = resolveConversationIdFromPushData(payload.data);
17933
- if (!text) return;
17934
- if (conversationId) {
17935
- toast2__default.default.custom(
17936
- (t) => /* @__PURE__ */ jsxRuntime.jsx(
17937
- "button",
17938
- {
17939
- type: "button",
17940
- onClick: () => {
17941
- toast2__default.default.dismiss(t.id);
17942
- requestOpenConversation(conversationId, payload.data);
17943
- },
17944
- style: {
17945
- display: "block",
17946
- width: "100%",
17947
- textAlign: "left",
17948
- cursor: "pointer",
17949
- background: "var(--background, #fff)",
17950
- color: "var(--foreground, #111)",
17951
- border: "1px solid rgba(0,0,0,0.08)",
17952
- borderRadius: 8,
17953
- padding: "10px 14px",
17954
- boxShadow: "0 4px 12px rgba(0,0,0,0.12)",
17955
- font: "inherit"
17956
- },
17957
- children: text
17958
- }
17959
- ),
17960
- { duration: 5e3 }
17961
- );
17962
- return;
17963
- }
17964
- showNotification(text, "info");
18163
+ const messageId2 = String(
18164
+ payload.data?.messageId || payload.data?.message_id || payload.data?.messageID || ""
18165
+ );
18166
+ if (!title && !body) return;
18167
+ toast__default.default.custom(
18168
+ (t) => /* @__PURE__ */ jsxRuntime.jsx(
18169
+ PushMessageToast,
18170
+ {
18171
+ t,
18172
+ title,
18173
+ body: body || void 0,
18174
+ onOpen: conversationId ? () => requestOpenConversation(
18175
+ conversationId,
18176
+ payload.data
18177
+ ) : void 0
18178
+ }
18179
+ ),
18180
+ {
18181
+ duration: 5e3,
18182
+ id: messageId2 || void 0
18183
+ }
18184
+ );
17965
18185
  };
17966
18186
  var ForegroundPushBridge = ({ onPush }) => {
17967
18187
  const lastDM = exports.useChatStore((s) => s.lastDM);
@@ -18096,11 +18316,31 @@ var ForegroundPushBridge = ({ onPush }) => {
18096
18316
  return () => window.removeEventListener(OPEN_CONVERSATION_EVENT, onOpen);
18097
18317
  }, []);
18098
18318
  return /* @__PURE__ */ jsxRuntime.jsx(
18099
- toast2.Toaster,
18319
+ toast.Toaster,
18100
18320
  {
18101
18321
  position: "top-right",
18102
- toastOptions: { duration: 4e3 },
18103
- containerStyle: { zIndex: 99999 }
18322
+ gutter: 12,
18323
+ containerClassName: "realtimex-push-toaster",
18324
+ containerStyle: {
18325
+ zIndex: 99999,
18326
+ top: 16,
18327
+ right: 16,
18328
+ width: "auto",
18329
+ maxWidth: "none"
18330
+ },
18331
+ toastOptions: {
18332
+ duration: 5e3,
18333
+ className: "!w-auto !max-w-none",
18334
+ style: {
18335
+ padding: 0,
18336
+ margin: 0,
18337
+ background: "transparent",
18338
+ boxShadow: "none",
18339
+ border: "none",
18340
+ width: "auto",
18341
+ maxWidth: "none"
18342
+ }
18343
+ }
18104
18344
  }
18105
18345
  );
18106
18346
  };
@@ -18257,6 +18497,80 @@ var getSocketConfig = (accessToken, tenantId, options) => {
18257
18497
  }
18258
18498
  };
18259
18499
  };
18500
+ var showNotification = (message, type = "info", icon, duration) => {
18501
+ const options = {
18502
+ icon,
18503
+ duration
18504
+ };
18505
+ switch (type) {
18506
+ case "success":
18507
+ toast.toast.success(message, options);
18508
+ break;
18509
+ case "error":
18510
+ toast.toast.error(message, options);
18511
+ break;
18512
+ case "info":
18513
+ toast.toast(message, options);
18514
+ break;
18515
+ case "warning":
18516
+ toast.toast(message, { ...options, icon: "\u26A0\uFE0F" });
18517
+ break;
18518
+ default:
18519
+ toast.toast(message, options);
18520
+ }
18521
+ };
18522
+ var downloadFile = async (src, name) => {
18523
+ try {
18524
+ const link = document.createElement("a");
18525
+ link.href = src;
18526
+ link.setAttribute("download", name);
18527
+ link.setAttribute("rel", "noopener noreferrer");
18528
+ link.click();
18529
+ showNotification("File Downloaded Successfully", "success");
18530
+ } catch (err) {
18531
+ console.error("File download failed:", err);
18532
+ showNotification("Failed to download file", "error");
18533
+ }
18534
+ };
18535
+ var getResponsiveWidth = (width) => {
18536
+ const screenWidth = window.innerWidth;
18537
+ if (width) {
18538
+ return width;
18539
+ } else if (screenWidth < 640) {
18540
+ return 350;
18541
+ } else if (screenWidth >= 640 && screenWidth < 1024) {
18542
+ return 600;
18543
+ } else if (screenWidth >= 1024 && screenWidth < 1280) {
18544
+ return 800;
18545
+ } else {
18546
+ return 1e3;
18547
+ }
18548
+ };
18549
+ var isEmpty = (value) => {
18550
+ if (value === null || value === void 0) return true;
18551
+ if (typeof value === "string") return value.trim().length === 0;
18552
+ if (Array.isArray(value)) {
18553
+ return value.length === 0 || value.every((item) => isEmpty(item));
18554
+ }
18555
+ if (typeof value === "object") {
18556
+ return Object.keys(value).length === 0;
18557
+ }
18558
+ return false;
18559
+ };
18560
+ function uniqueList(list, key) {
18561
+ const seen = /* @__PURE__ */ new Set();
18562
+ return list.filter((item) => {
18563
+ const value = item[key];
18564
+ if (seen.has(value)) return false;
18565
+ seen.add(value);
18566
+ return true;
18567
+ });
18568
+ }
18569
+ var capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
18570
+ var getFirstAndLastNameOneCharacter = (name) => {
18571
+ const names = name.split(" ");
18572
+ return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
18573
+ };
18260
18574
  var SIZE_MAP = {
18261
18575
  xs: "size-6",
18262
18576
  sm: "size-8",
@@ -18430,135 +18744,6 @@ var packageDefaultComponents = {
18430
18744
  ChatDateTimeSettings: ChatDateTimeSettings_default,
18431
18745
  ChatSocketStatus: ChatSocketStatus_default
18432
18746
  };
18433
- var usePushNotifications = () => {
18434
- const [state, setState] = React2.useState({
18435
- supported: false,
18436
- allowedByWorkspace: false,
18437
- configured: false,
18438
- permission: "unsupported",
18439
- userEnabled: true,
18440
- deviceEnabled: false,
18441
- loading: true,
18442
- error: null
18443
- });
18444
- const refresh = React2.useCallback(async () => {
18445
- if (!isPushSupported()) {
18446
- setState((prev) => ({
18447
- ...prev,
18448
- supported: false,
18449
- loading: false
18450
- }));
18451
- return;
18452
- }
18453
- try {
18454
- const [config, preference] = await Promise.all([
18455
- apiGetPushConfig(),
18456
- apiGetPushPreference().catch(() => null)
18457
- ]);
18458
- setState({
18459
- supported: true,
18460
- allowedByWorkspace: Boolean(config?.enabled),
18461
- configured: Boolean(config?.configured),
18462
- permission: Notification.permission,
18463
- userEnabled: preference?.enabled ?? true,
18464
- deviceEnabled: Notification.permission === "granted" && Boolean(getStoredPushToken()),
18465
- loading: false,
18466
- error: null
18467
- });
18468
- } catch (error) {
18469
- setState((prev) => ({
18470
- ...prev,
18471
- supported: true,
18472
- loading: false,
18473
- error: error instanceof Error ? error.message : "Could not load push settings"
18474
- }));
18475
- }
18476
- }, []);
18477
- React2.useEffect(() => {
18478
- void refresh();
18479
- }, [refresh]);
18480
- const enable = React2.useCallback(async () => {
18481
- setState((prev) => ({ ...prev, loading: true, error: null }));
18482
- try {
18483
- await enablePushOnThisDevice();
18484
- await refresh();
18485
- return true;
18486
- } catch (error) {
18487
- setState((prev) => ({
18488
- ...prev,
18489
- loading: false,
18490
- permission: isPushSupported() ? Notification.permission : "unsupported",
18491
- error: error instanceof Error ? error.message : "Could not enable push notifications"
18492
- }));
18493
- return false;
18494
- }
18495
- }, [refresh]);
18496
- const disable = React2.useCallback(async () => {
18497
- setState((prev) => ({ ...prev, loading: true, error: null }));
18498
- try {
18499
- await disablePushOnThisDevice();
18500
- } finally {
18501
- await refresh();
18502
- }
18503
- }, [refresh]);
18504
- const setUserEnabled = React2.useCallback(
18505
- async (enabled) => {
18506
- setState((prev) => ({ ...prev, userEnabled: enabled }));
18507
- try {
18508
- await apiUpdatePushPreference(enabled);
18509
- } catch (error) {
18510
- setState((prev) => ({
18511
- ...prev,
18512
- userEnabled: !enabled,
18513
- error: error instanceof Error ? error.message : "Could not update push preference"
18514
- }));
18515
- }
18516
- },
18517
- []
18518
- );
18519
- return { ...state, enable, disable, setUserEnabled, refresh };
18520
- };
18521
- var PushNotificationToggle = ({
18522
- className,
18523
- label = "Push notifications",
18524
- description = "Get notified about new messages on this device"
18525
- }) => {
18526
- const push = usePushNotifications();
18527
- if (!push.supported || !push.allowedByWorkspace || !push.configured) {
18528
- return null;
18529
- }
18530
- const isOn = push.deviceEnabled && push.userEnabled;
18531
- const permissionBlocked = push.permission === "denied";
18532
- const handleChange = async (checked) => {
18533
- if (checked) {
18534
- if (!push.userEnabled) await push.setUserEnabled(true);
18535
- if (!push.deviceEnabled) await push.enable();
18536
- } else {
18537
- await push.disable();
18538
- }
18539
- };
18540
- return /* @__PURE__ */ jsxRuntime.jsxs(
18541
- "div",
18542
- {
18543
- className: className ?? "flex items-center justify-between gap-4 rounded-xl border border-border bg-background px-4 py-3",
18544
- children: [
18545
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
18546
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: label }),
18547
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description })
18548
- ] }),
18549
- /* @__PURE__ */ jsxRuntime.jsx(
18550
- Switch,
18551
- {
18552
- checked: isOn,
18553
- disabled: push.loading || permissionBlocked,
18554
- onCheckedChange: (checked) => void handleChange(checked),
18555
- "aria-label": `Toggle ${label}`
18556
- }
18557
- )
18558
- ]
18559
- }
18560
- );
18561
- };
18562
18747
 
18563
18748
  // src/index.ts
18564
18749
  var index_default = ChatMain_default;
@@ -18593,6 +18778,7 @@ exports.NOTIFICATION_CLICK_SW_TYPE = NOTIFICATION_CLICK_SW_TYPE;
18593
18778
  exports.OPEN_CONVERSATION_EVENT = OPEN_CONVERSATION_EVENT;
18594
18779
  exports.PUSH_BROADCAST_CHANNEL = PUSH_BROADCAST_CHANNEL;
18595
18780
  exports.PUSH_CHANGED_EVENT = PUSH_CHANGED_EVENT;
18781
+ exports.PUSH_DATA_CACHE_NAME = PUSH_DATA_CACHE_NAME;
18596
18782
  exports.PushNotificationToggle = PushNotificationToggle;
18597
18783
  exports.apiGetPushConfig = apiGetPushConfig;
18598
18784
  exports.apiGetPushPreference = apiGetPushPreference;
@@ -18603,6 +18789,7 @@ exports.buildChannelFromPushRequest = buildChannelFromPushRequest;
18603
18789
  exports.capitalizeFirst = capitalizeFirst;
18604
18790
  exports.clampJumpDate = clampJumpDate;
18605
18791
  exports.consumePendingOpenConversation = consumePendingOpenConversation;
18792
+ exports.consumePendingOpenFromPushCache = consumePendingOpenFromPushCache;
18606
18793
  exports.consumePendingOpenRequest = consumePendingOpenRequest;
18607
18794
  exports.default = index_default;
18608
18795
  exports.defaultChatClassNames = defaultChatClassNames;