@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/firebase-messaging-sw.js +312 -71
- package/dist/index.cjs +820 -633
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.mjs +814 -629
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +11 -0
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
|
|
4821
|
-
options.onNavigate?.(id,
|
|
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
|
-
|
|
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
|
-
|
|
6548
|
+
size = "default",
|
|
6588
6549
|
...props
|
|
6589
6550
|
}) {
|
|
6590
6551
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6591
|
-
radixUi.
|
|
6552
|
+
radixUi.Switch.Root,
|
|
6592
6553
|
{
|
|
6593
|
-
"data-slot": "
|
|
6594
|
-
|
|
6554
|
+
"data-slot": "switch",
|
|
6555
|
+
"data-size": size,
|
|
6595
6556
|
className: cn(
|
|
6596
|
-
"flex
|
|
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.
|
|
6562
|
+
radixUi.Switch.Thumb,
|
|
6604
6563
|
{
|
|
6605
|
-
"data-slot": "
|
|
6606
|
-
className:
|
|
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/
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
var
|
|
6617
|
-
var
|
|
6618
|
-
var
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
})
|
|
6622
|
-
|
|
6623
|
-
|
|
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
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
}
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
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
|
-
|
|
6671
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17673
|
-
|
|
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
|
|
17924
|
-
|
|
17925
|
-
|
|
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
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
17936
|
-
|
|
17937
|
-
|
|
17938
|
-
|
|
17939
|
-
|
|
17940
|
-
|
|
17941
|
-
|
|
17942
|
-
|
|
17943
|
-
|
|
17944
|
-
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
|
|
17948
|
-
|
|
17949
|
-
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
17953
|
-
|
|
17954
|
-
|
|
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
|
-
|
|
18319
|
+
toast.Toaster,
|
|
18100
18320
|
{
|
|
18101
18321
|
position: "top-right",
|
|
18102
|
-
|
|
18103
|
-
|
|
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;
|