@realtimexsco/live-chat 1.4.8 → 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 +338 -75
- package/dist/index.cjs +951 -666
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +27 -19
- package/dist/index.d.ts +27 -19
- package/dist/index.mjs +941 -662
- 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;
|
|
@@ -4659,46 +4659,114 @@ init_store_helpers();
|
|
|
4659
4659
|
init_store_helpers();
|
|
4660
4660
|
var OPEN_CONVERSATION_EVENT = "realtimex:open-conversation";
|
|
4661
4661
|
var NOTIFICATION_CLICK_SW_TYPE = "realtimex:notification-click";
|
|
4662
|
+
var PUSH_BROADCAST_CHANNEL = "realtimex-push";
|
|
4663
|
+
var PUSH_DATA_CACHE_NAME = "realtimex-push-data-v1";
|
|
4662
4664
|
var PENDING_STORAGE_KEY = "realtimex:pending-open-conversation";
|
|
4665
|
+
var PENDING_OPEN_CACHE_PATH = "pending-open";
|
|
4663
4666
|
var resolveConversationIdFromPushData = (data) => {
|
|
4664
4667
|
if (!data || typeof data !== "object") return "";
|
|
4665
|
-
|
|
4668
|
+
let fcmMsg = data.FCM_MSG;
|
|
4669
|
+
if (typeof fcmMsg === "string") {
|
|
4670
|
+
try {
|
|
4671
|
+
fcmMsg = JSON.parse(fcmMsg);
|
|
4672
|
+
} catch {
|
|
4673
|
+
fcmMsg = void 0;
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
const nested = fcmMsg && typeof fcmMsg === "object" ? fcmMsg.data : void 0;
|
|
4666
4677
|
const source = { ...nested || {}, ...data };
|
|
4667
4678
|
return String(
|
|
4668
4679
|
source.conversationId || source.conversation_id || source.conversationID || ""
|
|
4669
|
-
);
|
|
4680
|
+
).trim();
|
|
4681
|
+
};
|
|
4682
|
+
var normalizePushMeta = (meta) => {
|
|
4683
|
+
if (!meta || typeof meta !== "object") return {};
|
|
4684
|
+
return {
|
|
4685
|
+
senderId: String(
|
|
4686
|
+
meta.senderId || meta.sender_id || ""
|
|
4687
|
+
).trim() || void 0,
|
|
4688
|
+
kind: String(meta.kind || "").trim() || void 0,
|
|
4689
|
+
messageId: String(
|
|
4690
|
+
meta.messageId || meta.message_id || ""
|
|
4691
|
+
).trim() || void 0,
|
|
4692
|
+
title: String(meta.title || "").trim() || void 0
|
|
4693
|
+
};
|
|
4694
|
+
};
|
|
4695
|
+
var parsePendingRaw = (raw) => {
|
|
4696
|
+
if (!raw) return null;
|
|
4697
|
+
try {
|
|
4698
|
+
const parsed = JSON.parse(raw);
|
|
4699
|
+
if (parsed?.conversationId) {
|
|
4700
|
+
return {
|
|
4701
|
+
conversationId: String(parsed.conversationId).trim(),
|
|
4702
|
+
...normalizePushMeta(parsed)
|
|
4703
|
+
};
|
|
4704
|
+
}
|
|
4705
|
+
} catch {
|
|
4706
|
+
}
|
|
4707
|
+
const id = String(raw).trim();
|
|
4708
|
+
return id ? { conversationId: id } : null;
|
|
4670
4709
|
};
|
|
4671
|
-
var peekPendingOpenConversation = () =>
|
|
4710
|
+
var peekPendingOpenConversation = () => peekPendingOpenRequest()?.conversationId ?? null;
|
|
4711
|
+
var peekPendingOpenRequest = () => {
|
|
4672
4712
|
try {
|
|
4673
|
-
return sessionStorage.getItem(PENDING_STORAGE_KEY);
|
|
4713
|
+
return parsePendingRaw(sessionStorage.getItem(PENDING_STORAGE_KEY));
|
|
4674
4714
|
} catch {
|
|
4675
4715
|
return null;
|
|
4676
4716
|
}
|
|
4677
4717
|
};
|
|
4678
|
-
var consumePendingOpenConversation = () =>
|
|
4679
|
-
|
|
4718
|
+
var consumePendingOpenConversation = () => consumePendingOpenRequest()?.conversationId ?? null;
|
|
4719
|
+
var consumePendingOpenRequest = () => {
|
|
4720
|
+
const request = peekPendingOpenRequest();
|
|
4680
4721
|
try {
|
|
4681
4722
|
sessionStorage.removeItem(PENDING_STORAGE_KEY);
|
|
4682
4723
|
} catch {
|
|
4683
4724
|
}
|
|
4684
|
-
return
|
|
4725
|
+
return request;
|
|
4685
4726
|
};
|
|
4686
|
-
var requestOpenConversation = (conversationId) => {
|
|
4727
|
+
var requestOpenConversation = (conversationId, meta) => {
|
|
4687
4728
|
const id = String(conversationId || "").trim();
|
|
4688
4729
|
if (!id) return;
|
|
4730
|
+
const request = {
|
|
4731
|
+
conversationId: id,
|
|
4732
|
+
...normalizePushMeta(meta)
|
|
4733
|
+
};
|
|
4734
|
+
console.log("[realtimex-push] requestOpenConversation:", request);
|
|
4689
4735
|
try {
|
|
4690
|
-
sessionStorage.setItem(PENDING_STORAGE_KEY,
|
|
4736
|
+
sessionStorage.setItem(PENDING_STORAGE_KEY, JSON.stringify(request));
|
|
4691
4737
|
} catch {
|
|
4692
4738
|
}
|
|
4693
4739
|
try {
|
|
4694
4740
|
window.dispatchEvent(
|
|
4695
|
-
new CustomEvent(OPEN_CONVERSATION_EVENT, {
|
|
4696
|
-
detail: { conversationId: id }
|
|
4697
|
-
})
|
|
4741
|
+
new CustomEvent(OPEN_CONVERSATION_EVENT, { detail: request })
|
|
4698
4742
|
);
|
|
4699
4743
|
} catch {
|
|
4700
4744
|
}
|
|
4701
4745
|
};
|
|
4746
|
+
var buildChannelFromPushRequest = (request, loggedUserId, allUsers) => {
|
|
4747
|
+
const conversationId = request.conversationId;
|
|
4748
|
+
const isGroup = request.kind === "group";
|
|
4749
|
+
const senderId = String(request.senderId || "").trim();
|
|
4750
|
+
if (isGroup) {
|
|
4751
|
+
const rawName2 = request.title || "Group Chat";
|
|
4752
|
+
return {
|
|
4753
|
+
id: conversationId,
|
|
4754
|
+
conversationId,
|
|
4755
|
+
name: rawName2.charAt(0).toUpperCase() + rawName2.slice(1),
|
|
4756
|
+
isGroup: true
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
const senderUser = senderId ? (allUsers || []).find((user) => String(user._id) === senderId) : null;
|
|
4760
|
+
const rawName = senderUser?.name || request.title || "New message";
|
|
4761
|
+
return {
|
|
4762
|
+
id: senderId || conversationId,
|
|
4763
|
+
conversationId,
|
|
4764
|
+
name: rawName.charAt(0).toUpperCase() + rawName.slice(1),
|
|
4765
|
+
image: senderUser?.image || void 0,
|
|
4766
|
+
email: senderUser?.email,
|
|
4767
|
+
isGroup: false
|
|
4768
|
+
};
|
|
4769
|
+
};
|
|
4702
4770
|
var mapConversationToChannel = (conversation, loggedUserId, allUsers) => {
|
|
4703
4771
|
const conversationId = String(conversation?._id || conversation?.id || "");
|
|
4704
4772
|
const isGroup = isGroupConversation(conversation);
|
|
@@ -4735,6 +4803,37 @@ var mapConversationToChannel = (conversation, loggedUserId, allUsers) => {
|
|
|
4735
4803
|
starredCount: conversation.starredCount
|
|
4736
4804
|
};
|
|
4737
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
|
+
};
|
|
4738
4837
|
var readConversationIdFromLocation = () => {
|
|
4739
4838
|
try {
|
|
4740
4839
|
return new URLSearchParams(window.location.search).get("conversationId") || "";
|
|
@@ -4743,34 +4842,73 @@ var readConversationIdFromLocation = () => {
|
|
|
4743
4842
|
}
|
|
4744
4843
|
};
|
|
4745
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
|
+
};
|
|
4858
|
+
var handleNotificationOpen = (conversationId, pushData, options) => {
|
|
4859
|
+
const id = String(conversationId || "").trim();
|
|
4860
|
+
if (!id) {
|
|
4861
|
+
console.warn("[realtimex-push] notification open ignored \u2014 no conversationId", pushData);
|
|
4862
|
+
return;
|
|
4863
|
+
}
|
|
4864
|
+
if (!shouldHandleOpen(id)) {
|
|
4865
|
+
stripConversationIdFromUrl();
|
|
4866
|
+
return;
|
|
4867
|
+
}
|
|
4868
|
+
requestOpenConversation(id, pushData);
|
|
4869
|
+
const chatPath = options.chatPath || "/chat";
|
|
4870
|
+
stripConversationIdFromUrl();
|
|
4871
|
+
options.onNavigate?.(id, chatPath);
|
|
4872
|
+
};
|
|
4746
4873
|
var installNotificationClickBridge = (options = {}) => {
|
|
4747
4874
|
if (typeof window === "undefined") return () => void 0;
|
|
4748
|
-
const chatPath = options.chatPath || "/chat";
|
|
4749
|
-
const handleOpen = (conversationId) => {
|
|
4750
|
-
const id = String(conversationId || "").trim();
|
|
4751
|
-
if (!id) return;
|
|
4752
|
-
requestOpenConversation(id);
|
|
4753
|
-
const pathWithQuery = `${chatPath}?conversationId=${encodeURIComponent(id)}`;
|
|
4754
|
-
options.onNavigate?.(id, pathWithQuery);
|
|
4755
|
-
};
|
|
4756
4875
|
const onSwMessage = (event) => {
|
|
4757
4876
|
const data = event.data;
|
|
4758
4877
|
console.log("[realtimex-push] SW \u2192 page message:", data);
|
|
4759
4878
|
if (!data || data.type !== NOTIFICATION_CLICK_SW_TYPE) return;
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4879
|
+
const pushData = data.data && typeof data.data === "object" ? data.data : void 0;
|
|
4880
|
+
const conversationId = String(data.conversationId || "") || resolveConversationIdFromPushData(pushData);
|
|
4881
|
+
console.log("[realtimex-push] notification click \u2192 open:", {
|
|
4882
|
+
conversationId,
|
|
4883
|
+
pushData
|
|
4884
|
+
});
|
|
4885
|
+
handleNotificationOpen(conversationId, pushData, options);
|
|
4765
4886
|
};
|
|
4766
4887
|
navigator.serviceWorker?.addEventListener("message", onSwMessage);
|
|
4888
|
+
let broadcast = null;
|
|
4889
|
+
try {
|
|
4890
|
+
broadcast = new BroadcastChannel(PUSH_BROADCAST_CHANNEL);
|
|
4891
|
+
broadcast.onmessage = onSwMessage;
|
|
4892
|
+
} catch {
|
|
4893
|
+
}
|
|
4767
4894
|
const fromUrl = readConversationIdFromLocation();
|
|
4768
4895
|
if (fromUrl && !consumedUrlConversationIds.has(fromUrl)) {
|
|
4769
4896
|
consumedUrlConversationIds.add(fromUrl);
|
|
4770
|
-
|
|
4897
|
+
handleNotificationOpen(fromUrl, void 0, options);
|
|
4898
|
+
} else {
|
|
4899
|
+
stripConversationIdFromUrl();
|
|
4771
4900
|
}
|
|
4901
|
+
void consumePendingOpenFromPushCache().then((request) => {
|
|
4902
|
+
if (!request?.conversationId) return;
|
|
4903
|
+
handleNotificationOpen(
|
|
4904
|
+
request.conversationId,
|
|
4905
|
+
request,
|
|
4906
|
+
options
|
|
4907
|
+
);
|
|
4908
|
+
});
|
|
4772
4909
|
return () => {
|
|
4773
4910
|
navigator.serviceWorker?.removeEventListener("message", onSwMessage);
|
|
4911
|
+
broadcast?.close();
|
|
4774
4912
|
};
|
|
4775
4913
|
};
|
|
4776
4914
|
|
|
@@ -4850,7 +4988,7 @@ var useChatController = () => {
|
|
|
4850
4988
|
const allUsers = exports.useChatStore((s) => s.allUsers);
|
|
4851
4989
|
const isFetchingConversations = exports.useChatStore((s) => s.isFetchingConversations);
|
|
4852
4990
|
const conversations = exports.useChatStore((s) => s.conversations);
|
|
4853
|
-
const [
|
|
4991
|
+
const [pendingOpenRequest, setPendingOpenRequest] = React2.useState(() => peekPendingOpenRequest());
|
|
4854
4992
|
const conversationsLength = exports.useChatStore(
|
|
4855
4993
|
(s) => state.activeChannel?.conversationId ? 0 : s.conversations.length
|
|
4856
4994
|
);
|
|
@@ -4881,32 +5019,42 @@ var useChatController = () => {
|
|
|
4881
5019
|
});
|
|
4882
5020
|
React2.useEffect(() => {
|
|
4883
5021
|
const onOpen = (event) => {
|
|
4884
|
-
const
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
5022
|
+
const detail = event.detail;
|
|
5023
|
+
if (detail?.conversationId) {
|
|
5024
|
+
console.log("[realtimex-push] OPEN_CONVERSATION_EVENT:", detail);
|
|
5025
|
+
setPendingOpenRequest({
|
|
5026
|
+
conversationId: String(detail.conversationId),
|
|
5027
|
+
senderId: detail.senderId,
|
|
5028
|
+
kind: detail.kind,
|
|
5029
|
+
messageId: detail.messageId,
|
|
5030
|
+
title: detail.title
|
|
5031
|
+
});
|
|
5032
|
+
}
|
|
4888
5033
|
};
|
|
4889
5034
|
window.addEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
4890
5035
|
return () => window.removeEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
4891
5036
|
}, []);
|
|
4892
5037
|
React2.useEffect(() => {
|
|
4893
|
-
if (!
|
|
5038
|
+
if (!pendingOpenRequest?.conversationId || !loggedUserDetails) return;
|
|
4894
5039
|
let cancelled = false;
|
|
4895
5040
|
const openPending = async () => {
|
|
4896
|
-
const targetId = String(
|
|
5041
|
+
const targetId = String(pendingOpenRequest.conversationId);
|
|
5042
|
+
console.log("[realtimex-push] opening conversation:", pendingOpenRequest);
|
|
4897
5043
|
let conversation = conversations.find(
|
|
4898
5044
|
(c) => String(c._id || c.id) === targetId
|
|
4899
5045
|
) || null;
|
|
4900
5046
|
if (!conversation) {
|
|
4901
|
-
|
|
4902
|
-
if (fromInfo) conversation = fromInfo;
|
|
5047
|
+
conversation = conversationInfos[targetId] || null;
|
|
4903
5048
|
}
|
|
4904
5049
|
if (!conversation) {
|
|
4905
|
-
if (isFetchingConversations)
|
|
5050
|
+
if (isFetchingConversations) {
|
|
5051
|
+
console.log("[realtimex-push] waiting for conversations list\u2026");
|
|
5052
|
+
return;
|
|
5053
|
+
}
|
|
4906
5054
|
try {
|
|
4907
5055
|
await fetchConversationInfo2(targetId);
|
|
4908
|
-
} catch {
|
|
4909
|
-
|
|
5056
|
+
} catch (error) {
|
|
5057
|
+
console.warn("[realtimex-push] fetchConversationInfo failed:", error);
|
|
4910
5058
|
}
|
|
4911
5059
|
if (cancelled) return;
|
|
4912
5060
|
const stateNow = exports.useChatStore.getState();
|
|
@@ -4914,12 +5062,17 @@ var useChatController = () => {
|
|
|
4914
5062
|
(c) => String(c._id || c.id) === targetId
|
|
4915
5063
|
) || stateNow.conversationInfos[targetId] || null;
|
|
4916
5064
|
}
|
|
4917
|
-
|
|
4918
|
-
const channel = mapConversationToChannel(
|
|
5065
|
+
const channel = conversation ? mapConversationToChannel(
|
|
4919
5066
|
conversation,
|
|
4920
5067
|
loggedUserDetails._id,
|
|
4921
5068
|
allUsers
|
|
5069
|
+
) : buildChannelFromPushRequest(
|
|
5070
|
+
pendingOpenRequest,
|
|
5071
|
+
loggedUserDetails._id,
|
|
5072
|
+
allUsers
|
|
4922
5073
|
);
|
|
5074
|
+
console.log("[realtimex-push] selected channel:", channel);
|
|
5075
|
+
if (cancelled) return;
|
|
4923
5076
|
setState((prev) => {
|
|
4924
5077
|
if (prev.activeChannel?.conversationId && String(prev.activeChannel.conversationId) === targetId) {
|
|
4925
5078
|
return prev;
|
|
@@ -4930,15 +5083,16 @@ var useChatController = () => {
|
|
|
4930
5083
|
activeConversationId: targetId
|
|
4931
5084
|
};
|
|
4932
5085
|
});
|
|
4933
|
-
|
|
4934
|
-
|
|
5086
|
+
exports.useChatStore.getState().setActiveConversationId(targetId);
|
|
5087
|
+
consumePendingOpenRequest();
|
|
5088
|
+
setPendingOpenRequest(null);
|
|
4935
5089
|
};
|
|
4936
5090
|
void openPending();
|
|
4937
5091
|
return () => {
|
|
4938
5092
|
cancelled = true;
|
|
4939
5093
|
};
|
|
4940
5094
|
}, [
|
|
4941
|
-
|
|
5095
|
+
pendingOpenRequest,
|
|
4942
5096
|
loggedUserDetails,
|
|
4943
5097
|
conversations,
|
|
4944
5098
|
conversationInfos,
|
|
@@ -6389,184 +6543,562 @@ var CreateChatDialog = (props) => {
|
|
|
6389
6543
|
);
|
|
6390
6544
|
};
|
|
6391
6545
|
var CreateChatDialog_default = CreateChatDialog;
|
|
6392
|
-
|
|
6393
|
-
loggedUserDetails,
|
|
6394
|
-
onUserSelect,
|
|
6395
|
-
isCreateModalOpen = false,
|
|
6396
|
-
setIsCreateModalOpen,
|
|
6397
|
-
searchQuery = "",
|
|
6398
|
-
setSearchQuery
|
|
6399
|
-
}) => {
|
|
6400
|
-
const { showColorModeToggle } = useChatTheme();
|
|
6401
|
-
const user = {
|
|
6402
|
-
_id: loggedUserDetails?._id || "1",
|
|
6403
|
-
name: formatLoggedUserName(loggedUserDetails?.name),
|
|
6404
|
-
email: loggedUserDetails?.email || "user@example.com",
|
|
6405
|
-
role: loggedUserDetails?.role || "user",
|
|
6406
|
-
isActive: loggedUserDetails?.isActive ?? true,
|
|
6407
|
-
createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
|
|
6408
|
-
updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
|
|
6409
|
-
image: loggedUserDetails?.image || void 0
|
|
6410
|
-
};
|
|
6411
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b border-(--chat-border) bg-(--chat-surface) px-3 pb-3 pt-3", children: [
|
|
6412
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
6413
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative shrink-0", children: [
|
|
6414
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-8 ring-1 ring-(--chat-surface)", children: [
|
|
6415
|
-
user.image ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
|
|
6416
|
-
/* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-[10px] font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
|
|
6417
|
-
] }),
|
|
6418
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -bottom-0.5 -right-0.5 size-2 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
|
|
6419
|
-
] }),
|
|
6420
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
6421
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "truncate text-xs font-medium leading-tight text-(--chat-text)", children: user.name }),
|
|
6422
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[10px] text-(--chat-muted)", children: user.email })
|
|
6423
|
-
] }),
|
|
6424
|
-
showColorModeToggle ? /* @__PURE__ */ jsxRuntime.jsx(ChatThemeToggle_default, {}) : null
|
|
6425
|
-
] }),
|
|
6426
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center gap-1.5", children: [
|
|
6427
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: chatSidebarSearchShellClass, children: [
|
|
6428
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "pointer-events-none size-3.5 shrink-0 text-(--chat-muted)" }),
|
|
6429
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6430
|
-
"input",
|
|
6431
|
-
{
|
|
6432
|
-
type: "text",
|
|
6433
|
-
inputMode: "search",
|
|
6434
|
-
enterKeyHint: "search",
|
|
6435
|
-
placeholder: "Search conversations...",
|
|
6436
|
-
value: searchQuery,
|
|
6437
|
-
onChange: (e) => setSearchQuery?.(e.target.value),
|
|
6438
|
-
className: chatSidebarSearchInputClass
|
|
6439
|
-
}
|
|
6440
|
-
),
|
|
6441
|
-
searchQuery ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6442
|
-
"button",
|
|
6443
|
-
{
|
|
6444
|
-
type: "button",
|
|
6445
|
-
onClick: () => setSearchQuery?.(""),
|
|
6446
|
-
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)",
|
|
6447
|
-
"aria-label": "Clear search",
|
|
6448
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 12 })
|
|
6449
|
-
}
|
|
6450
|
-
) : null
|
|
6451
|
-
] }),
|
|
6452
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6453
|
-
CreateChatDialog_default,
|
|
6454
|
-
{
|
|
6455
|
-
loggedUserDetails,
|
|
6456
|
-
onUserSelect,
|
|
6457
|
-
isCreateModalOpen,
|
|
6458
|
-
setIsCreateModalOpen
|
|
6459
|
-
}
|
|
6460
|
-
)
|
|
6461
|
-
] })
|
|
6462
|
-
] });
|
|
6463
|
-
};
|
|
6464
|
-
var LoggedUserDetails_default = LoggedUserDetails;
|
|
6465
|
-
function ScrollArea({
|
|
6466
|
-
className,
|
|
6467
|
-
children,
|
|
6468
|
-
...props
|
|
6469
|
-
}) {
|
|
6470
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6471
|
-
radixUi.ScrollArea.Root,
|
|
6472
|
-
{
|
|
6473
|
-
"data-slot": "scroll-area",
|
|
6474
|
-
className: cn("relative", className),
|
|
6475
|
-
...props,
|
|
6476
|
-
children: [
|
|
6477
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6478
|
-
radixUi.ScrollArea.Viewport,
|
|
6479
|
-
{
|
|
6480
|
-
"data-slot": "scroll-area-viewport",
|
|
6481
|
-
className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
|
|
6482
|
-
children
|
|
6483
|
-
}
|
|
6484
|
-
),
|
|
6485
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
|
|
6486
|
-
/* @__PURE__ */ jsxRuntime.jsx(radixUi.ScrollArea.Corner, {})
|
|
6487
|
-
]
|
|
6488
|
-
}
|
|
6489
|
-
);
|
|
6490
|
-
}
|
|
6491
|
-
function ScrollBar({
|
|
6546
|
+
function Switch({
|
|
6492
6547
|
className,
|
|
6493
|
-
|
|
6548
|
+
size = "default",
|
|
6494
6549
|
...props
|
|
6495
6550
|
}) {
|
|
6496
6551
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6497
|
-
radixUi.
|
|
6552
|
+
radixUi.Switch.Root,
|
|
6498
6553
|
{
|
|
6499
|
-
"data-slot": "
|
|
6500
|
-
|
|
6554
|
+
"data-slot": "switch",
|
|
6555
|
+
"data-size": size,
|
|
6501
6556
|
className: cn(
|
|
6502
|
-
"flex
|
|
6503
|
-
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
6504
|
-
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",
|
|
6505
6558
|
className
|
|
6506
6559
|
),
|
|
6507
6560
|
...props,
|
|
6508
6561
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6509
|
-
radixUi.
|
|
6562
|
+
radixUi.Switch.Thumb,
|
|
6510
6563
|
{
|
|
6511
|
-
"data-slot": "
|
|
6512
|
-
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
|
+
)
|
|
6513
6568
|
}
|
|
6514
6569
|
)
|
|
6515
6570
|
}
|
|
6516
6571
|
);
|
|
6517
6572
|
}
|
|
6518
6573
|
|
|
6519
|
-
// src/
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
var
|
|
6523
|
-
var
|
|
6524
|
-
var
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
})
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
function notifyDraftChange() {
|
|
6531
|
-
draftRevision += 1;
|
|
6532
|
-
draftListeners.forEach((listener) => listener());
|
|
6533
|
-
}
|
|
6534
|
-
function subscribeToDrafts(listener) {
|
|
6535
|
-
draftListeners.add(listener);
|
|
6536
|
-
return () => {
|
|
6537
|
-
draftListeners.delete(listener);
|
|
6538
|
-
};
|
|
6539
|
-
}
|
|
6540
|
-
function getDraftRevision() {
|
|
6541
|
-
return draftRevision;
|
|
6542
|
-
}
|
|
6543
|
-
function useDraftRevision() {
|
|
6544
|
-
return React2.useSyncExternalStore(subscribeToDrafts, getDraftRevision, getDraftRevision);
|
|
6545
|
-
}
|
|
6546
|
-
function getConversationDraft(conversationId) {
|
|
6547
|
-
if (!conversationId) return emptyDraft();
|
|
6548
|
-
return conversationDrafts.get(conversationId) ?? emptyDraft();
|
|
6549
|
-
}
|
|
6550
|
-
function updateConversationDraft(conversationId, draft) {
|
|
6551
|
-
if (!conversationId) return;
|
|
6552
|
-
if (draft.messageInput.trim() || draft.attachments.length > 0) {
|
|
6553
|
-
conversationDrafts.set(conversationId, {
|
|
6554
|
-
messageInput: draft.messageInput,
|
|
6555
|
-
attachments: draft.attachments
|
|
6556
|
-
});
|
|
6557
|
-
} else {
|
|
6558
|
-
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 {
|
|
6559
6585
|
}
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
}
|
|
6568
|
-
|
|
6569
|
-
|
|
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;
|
|
6624
|
+
}
|
|
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 {
|
|
6631
|
+
}
|
|
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;
|
|
6570
7102
|
const draft = conversationDrafts.get(conversationId);
|
|
6571
7103
|
if (!draft) return null;
|
|
6572
7104
|
const text = draft.messageInput.trim();
|
|
@@ -12131,52 +12663,23 @@ var ChannelDetailsDrawer = (props) => {
|
|
|
12131
12663
|
participantCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5 pb-1", children: participants.map((p, index) => {
|
|
12132
12664
|
const pId = typeof p === "string" ? p : p._id;
|
|
12133
12665
|
const pName = typeof p === "string" ? "Unknown" : p.name;
|
|
12134
|
-
if (!pId) return null;
|
|
12135
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12136
|
-
"span",
|
|
12137
|
-
{
|
|
12138
|
-
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)",
|
|
12139
|
-
children: pName
|
|
12140
|
-
},
|
|
12141
|
-
`${pId}-${index}`
|
|
12142
|
-
);
|
|
12143
|
-
}) })
|
|
12144
|
-
] })
|
|
12145
|
-
] })
|
|
12146
|
-
] })
|
|
12147
|
-
] })
|
|
12148
|
-
] }) });
|
|
12149
|
-
};
|
|
12150
|
-
var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
|
|
12151
|
-
function Switch({
|
|
12152
|
-
className,
|
|
12153
|
-
size = "default",
|
|
12154
|
-
...props
|
|
12155
|
-
}) {
|
|
12156
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12157
|
-
radixUi.Switch.Root,
|
|
12158
|
-
{
|
|
12159
|
-
"data-slot": "switch",
|
|
12160
|
-
"data-size": size,
|
|
12161
|
-
className: cn(
|
|
12162
|
-
"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",
|
|
12163
|
-
className
|
|
12164
|
-
),
|
|
12165
|
-
...props,
|
|
12166
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12167
|
-
radixUi.Switch.Thumb,
|
|
12168
|
-
{
|
|
12169
|
-
"data-slot": "switch-thumb",
|
|
12170
|
-
className: cn(
|
|
12171
|
-
"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"
|
|
12172
|
-
)
|
|
12173
|
-
}
|
|
12174
|
-
)
|
|
12175
|
-
}
|
|
12176
|
-
);
|
|
12177
|
-
}
|
|
12178
|
-
|
|
12179
|
-
// 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;
|
|
12180
12683
|
init_useStore();
|
|
12181
12684
|
var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo }) => {
|
|
12182
12685
|
const updateGroupPermissions = exports.useChatStore((s) => s.updateGroupPermissions);
|
|
@@ -17568,251 +18071,15 @@ function ChatViewport({
|
|
|
17568
18071
|
"chat-package-viewport flex min-h-0 w-full flex-col overflow-hidden",
|
|
17569
18072
|
resolved.className,
|
|
17570
18073
|
className
|
|
17571
|
-
),
|
|
17572
|
-
style: { ...resolved.style, ...style },
|
|
17573
|
-
children
|
|
17574
|
-
}
|
|
17575
|
-
);
|
|
17576
|
-
}
|
|
17577
|
-
var ChatViewport_default = ChatViewport;
|
|
17578
|
-
|
|
17579
|
-
|
|
17580
|
-
icon,
|
|
17581
|
-
duration
|
|
17582
|
-
};
|
|
17583
|
-
switch (type) {
|
|
17584
|
-
case "success":
|
|
17585
|
-
toast2.toast.success(message, options);
|
|
17586
|
-
break;
|
|
17587
|
-
case "error":
|
|
17588
|
-
toast2.toast.error(message, options);
|
|
17589
|
-
break;
|
|
17590
|
-
case "info":
|
|
17591
|
-
toast2.toast(message, options);
|
|
17592
|
-
break;
|
|
17593
|
-
case "warning":
|
|
17594
|
-
toast2.toast(message, { ...options, icon: "\u26A0\uFE0F" });
|
|
17595
|
-
break;
|
|
17596
|
-
default:
|
|
17597
|
-
toast2.toast(message, options);
|
|
17598
|
-
}
|
|
17599
|
-
};
|
|
17600
|
-
var downloadFile = async (src, name) => {
|
|
17601
|
-
try {
|
|
17602
|
-
const link = document.createElement("a");
|
|
17603
|
-
link.href = src;
|
|
17604
|
-
link.setAttribute("download", name);
|
|
17605
|
-
link.setAttribute("rel", "noopener noreferrer");
|
|
17606
|
-
link.click();
|
|
17607
|
-
showNotification("File Downloaded Successfully", "success");
|
|
17608
|
-
} catch (err) {
|
|
17609
|
-
console.error("File download failed:", err);
|
|
17610
|
-
showNotification("Failed to download file", "error");
|
|
17611
|
-
}
|
|
17612
|
-
};
|
|
17613
|
-
var getResponsiveWidth = (width) => {
|
|
17614
|
-
const screenWidth = window.innerWidth;
|
|
17615
|
-
if (width) {
|
|
17616
|
-
return width;
|
|
17617
|
-
} else if (screenWidth < 640) {
|
|
17618
|
-
return 350;
|
|
17619
|
-
} else if (screenWidth >= 640 && screenWidth < 1024) {
|
|
17620
|
-
return 600;
|
|
17621
|
-
} else if (screenWidth >= 1024 && screenWidth < 1280) {
|
|
17622
|
-
return 800;
|
|
17623
|
-
} else {
|
|
17624
|
-
return 1e3;
|
|
17625
|
-
}
|
|
17626
|
-
};
|
|
17627
|
-
var isEmpty = (value) => {
|
|
17628
|
-
if (value === null || value === void 0) return true;
|
|
17629
|
-
if (typeof value === "string") return value.trim().length === 0;
|
|
17630
|
-
if (Array.isArray(value)) {
|
|
17631
|
-
return value.length === 0 || value.every((item) => isEmpty(item));
|
|
17632
|
-
}
|
|
17633
|
-
if (typeof value === "object") {
|
|
17634
|
-
return Object.keys(value).length === 0;
|
|
17635
|
-
}
|
|
17636
|
-
return false;
|
|
17637
|
-
};
|
|
17638
|
-
function uniqueList(list, key) {
|
|
17639
|
-
const seen = /* @__PURE__ */ new Set();
|
|
17640
|
-
return list.filter((item) => {
|
|
17641
|
-
const value = item[key];
|
|
17642
|
-
if (seen.has(value)) return false;
|
|
17643
|
-
seen.add(value);
|
|
17644
|
-
return true;
|
|
17645
|
-
});
|
|
17646
|
-
}
|
|
17647
|
-
var capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
17648
|
-
var getFirstAndLastNameOneCharacter = (name) => {
|
|
17649
|
-
const names = name.split(" ");
|
|
17650
|
-
return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
|
|
17651
|
-
};
|
|
17652
|
-
|
|
17653
|
-
// src/notifications/ForegroundPushBridge.tsx
|
|
17654
|
-
init_normalize_helpers();
|
|
17655
|
-
init_useStore();
|
|
17656
|
-
|
|
17657
|
-
// src/notifications/push.service.ts
|
|
17658
|
-
init_client();
|
|
17659
|
-
var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
|
|
17660
|
-
var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
|
|
17661
|
-
var PUSH_CHANGED_EVENT = "realtimex:push-changed";
|
|
17662
|
-
var emitPushChanged = (enabled) => {
|
|
17663
|
-
try {
|
|
17664
|
-
window.dispatchEvent(
|
|
17665
|
-
new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
|
|
17666
|
-
);
|
|
17667
|
-
} catch {
|
|
17668
|
-
}
|
|
17669
|
-
};
|
|
17670
|
-
var v2Url = "https://realtimex.softwareco.com/api/v2";
|
|
17671
|
-
var apiGetPushConfig = async () => {
|
|
17672
|
-
const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
|
|
17673
|
-
return data?.data;
|
|
17674
|
-
};
|
|
17675
|
-
var apiRegisterPushToken = async (token, deviceLabel) => {
|
|
17676
|
-
const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
|
|
17677
|
-
token,
|
|
17678
|
-
deviceLabel
|
|
17679
|
-
});
|
|
17680
|
-
return data?.data;
|
|
17681
|
-
};
|
|
17682
|
-
var apiRemovePushToken = async (token) => {
|
|
17683
|
-
const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
|
|
17684
|
-
data: { token }
|
|
17685
|
-
});
|
|
17686
|
-
return data;
|
|
17687
|
-
};
|
|
17688
|
-
var apiGetPushPreference = async () => {
|
|
17689
|
-
const { data } = await apiClient.get(
|
|
17690
|
-
`${v2Url}/notifications/push/preference`
|
|
17691
|
-
);
|
|
17692
|
-
return data?.data;
|
|
17693
|
-
};
|
|
17694
|
-
var apiUpdatePushPreference = async (enabled) => {
|
|
17695
|
-
const { data } = await apiClient.patch(
|
|
17696
|
-
`${v2Url}/notifications/push/preference`,
|
|
17697
|
-
{ enabled }
|
|
17698
|
-
);
|
|
17699
|
-
return data?.data;
|
|
17700
|
-
};
|
|
17701
|
-
var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
|
|
17702
|
-
var getStoredPushToken = () => {
|
|
17703
|
-
try {
|
|
17704
|
-
return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
|
|
17705
|
-
} catch {
|
|
17706
|
-
return null;
|
|
17707
|
-
}
|
|
17708
|
-
};
|
|
17709
|
-
var storePushToken = (token) => {
|
|
17710
|
-
try {
|
|
17711
|
-
if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
|
|
17712
|
-
else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
|
|
17713
|
-
} catch {
|
|
17714
|
-
}
|
|
17715
|
-
};
|
|
17716
|
-
var defaultDeviceLabel = () => {
|
|
17717
|
-
const ua = navigator.userAgent;
|
|
17718
|
-
const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
|
|
17719
|
-
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";
|
|
17720
|
-
return `${browser} on ${os}`;
|
|
17721
|
-
};
|
|
17722
|
-
var loadFirebaseMessaging = async () => {
|
|
17723
|
-
try {
|
|
17724
|
-
const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
|
|
17725
|
-
import('firebase/app'),
|
|
17726
|
-
import('firebase/messaging')
|
|
17727
|
-
]);
|
|
17728
|
-
return { initializeApp, getApps, ...messagingModule };
|
|
17729
|
-
} catch {
|
|
17730
|
-
throw new Error(
|
|
17731
|
-
'Push notifications need the "firebase" package \u2014 run: npm install firebase'
|
|
17732
|
-
);
|
|
17733
|
-
}
|
|
17734
|
-
};
|
|
17735
|
-
var getFirebaseMessaging = async (firebaseConfig) => {
|
|
17736
|
-
const fb = await loadFirebaseMessaging();
|
|
17737
|
-
const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
|
|
17738
|
-
return { fb, messaging: fb.getMessaging(app) };
|
|
17739
|
-
};
|
|
17740
|
-
var enablePushOnThisDevice = async () => {
|
|
17741
|
-
if (!isPushSupported()) {
|
|
17742
|
-
throw new Error("Push notifications are not supported in this browser");
|
|
17743
|
-
}
|
|
17744
|
-
const config = await apiGetPushConfig();
|
|
17745
|
-
if (!config?.enabled) {
|
|
17746
|
-
throw new Error("Push notifications are disabled for this workspace");
|
|
17747
|
-
}
|
|
17748
|
-
if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
|
|
17749
|
-
throw new Error(
|
|
17750
|
-
"Push notifications are not configured on the server yet"
|
|
17751
|
-
);
|
|
17752
|
-
}
|
|
17753
|
-
const permission = await Notification.requestPermission();
|
|
17754
|
-
if (permission !== "granted") {
|
|
17755
|
-
throw new Error("Notification permission was not granted");
|
|
17756
|
-
}
|
|
17757
|
-
let registration;
|
|
17758
|
-
try {
|
|
17759
|
-
registration = await navigator.serviceWorker.register(
|
|
17760
|
-
`${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
|
|
17761
|
-
JSON.stringify(config.firebaseConfig)
|
|
17762
|
-
)}`
|
|
17763
|
-
);
|
|
17764
|
-
} catch {
|
|
17765
|
-
throw new Error(
|
|
17766
|
-
`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`
|
|
17767
|
-
);
|
|
17768
|
-
}
|
|
17769
|
-
const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
|
|
17770
|
-
const token = await fb.getToken(messaging, {
|
|
17771
|
-
vapidKey: config.vapidKey,
|
|
17772
|
-
serviceWorkerRegistration: registration
|
|
17773
|
-
});
|
|
17774
|
-
if (!token) {
|
|
17775
|
-
throw new Error("Could not obtain a push token from Firebase");
|
|
17776
|
-
}
|
|
17777
|
-
await apiRegisterPushToken(token, defaultDeviceLabel());
|
|
17778
|
-
storePushToken(token);
|
|
17779
|
-
emitPushChanged(true);
|
|
17780
|
-
return token;
|
|
17781
|
-
};
|
|
17782
|
-
var disablePushOnThisDevice = async () => {
|
|
17783
|
-
const token = getStoredPushToken();
|
|
17784
|
-
if (!token) return;
|
|
17785
|
-
try {
|
|
17786
|
-
const config = await apiGetPushConfig();
|
|
17787
|
-
if (config?.firebaseConfig) {
|
|
17788
|
-
const { fb, messaging } = await getFirebaseMessaging(
|
|
17789
|
-
config.firebaseConfig
|
|
17790
|
-
);
|
|
17791
|
-
await fb.deleteToken(messaging).catch(() => void 0);
|
|
17792
|
-
}
|
|
17793
|
-
} catch {
|
|
17794
|
-
}
|
|
17795
|
-
await apiRemovePushToken(token).catch(() => void 0);
|
|
17796
|
-
storePushToken(null);
|
|
17797
|
-
emitPushChanged(false);
|
|
17798
|
-
};
|
|
17799
|
-
var onForegroundPush = async (callback) => {
|
|
17800
|
-
const config = await apiGetPushConfig();
|
|
17801
|
-
if (!config?.configured || !config.firebaseConfig) {
|
|
17802
|
-
throw new Error("Push config unavailable (not configured or API not ready)");
|
|
17803
|
-
}
|
|
17804
|
-
const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
|
|
17805
|
-
return fb.onMessage(messaging, (payload) => {
|
|
17806
|
-
console.log("[realtimex-push] FCM foreground payload (raw):", payload);
|
|
17807
|
-
console.log("[realtimex-push] FCM foreground data:", payload?.data);
|
|
17808
|
-
console.log("[realtimex-push] FCM foreground notification:", payload?.notification);
|
|
17809
|
-
callback({
|
|
17810
|
-
title: payload?.notification?.title,
|
|
17811
|
-
body: payload?.notification?.body,
|
|
17812
|
-
data: payload?.data
|
|
17813
|
-
});
|
|
17814
|
-
});
|
|
17815
|
-
};
|
|
18074
|
+
),
|
|
18075
|
+
style: { ...resolved.style, ...style },
|
|
18076
|
+
children
|
|
18077
|
+
}
|
|
18078
|
+
);
|
|
18079
|
+
}
|
|
18080
|
+
var ChatViewport_default = ChatViewport;
|
|
18081
|
+
init_normalize_helpers();
|
|
18082
|
+
init_useStore();
|
|
17816
18083
|
var RETRY_DELAYS_MS = [1e3, 3e3, 8e3, 2e4];
|
|
17817
18084
|
var recentToastIds = /* @__PURE__ */ new Set();
|
|
17818
18085
|
var rememberToastId = (id) => {
|
|
@@ -17826,48 +18093,95 @@ var rememberToastId = (id) => {
|
|
|
17826
18093
|
}
|
|
17827
18094
|
return true;
|
|
17828
18095
|
};
|
|
17829
|
-
var
|
|
17830
|
-
|
|
17831
|
-
|
|
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
|
+
);
|
|
17832
18157
|
};
|
|
17833
18158
|
var emitToast = (payload, onPush) => {
|
|
17834
18159
|
if (onPush && onPush(payload) !== false) return;
|
|
17835
|
-
const title = payload.title || payload.data?.title;
|
|
17836
|
-
const body = payload.body || payload.data?.body || payload.data?.message;
|
|
17837
|
-
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 || "";
|
|
17838
18162
|
const conversationId = resolveConversationIdFromPushData(payload.data);
|
|
17839
|
-
|
|
17840
|
-
|
|
17841
|
-
|
|
17842
|
-
|
|
17843
|
-
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17852
|
-
|
|
17853
|
-
|
|
17854
|
-
|
|
17855
|
-
|
|
17856
|
-
|
|
17857
|
-
|
|
17858
|
-
|
|
17859
|
-
|
|
17860
|
-
|
|
17861
|
-
font: "inherit"
|
|
17862
|
-
},
|
|
17863
|
-
children: text
|
|
17864
|
-
}
|
|
17865
|
-
),
|
|
17866
|
-
{ duration: 5e3 }
|
|
17867
|
-
);
|
|
17868
|
-
return;
|
|
17869
|
-
}
|
|
17870
|
-
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
|
+
);
|
|
17871
18185
|
};
|
|
17872
18186
|
var ForegroundPushBridge = ({ onPush }) => {
|
|
17873
18187
|
const lastDM = exports.useChatStore((s) => s.lastDM);
|
|
@@ -18002,11 +18316,31 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
18002
18316
|
return () => window.removeEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
18003
18317
|
}, []);
|
|
18004
18318
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18005
|
-
|
|
18319
|
+
toast.Toaster,
|
|
18006
18320
|
{
|
|
18007
18321
|
position: "top-right",
|
|
18008
|
-
|
|
18009
|
-
|
|
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
|
+
}
|
|
18010
18344
|
}
|
|
18011
18345
|
);
|
|
18012
18346
|
};
|
|
@@ -18163,6 +18497,80 @@ var getSocketConfig = (accessToken, tenantId, options) => {
|
|
|
18163
18497
|
}
|
|
18164
18498
|
};
|
|
18165
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
|
+
};
|
|
18166
18574
|
var SIZE_MAP = {
|
|
18167
18575
|
xs: "size-6",
|
|
18168
18576
|
sm: "size-8",
|
|
@@ -18336,135 +18744,6 @@ var packageDefaultComponents = {
|
|
|
18336
18744
|
ChatDateTimeSettings: ChatDateTimeSettings_default,
|
|
18337
18745
|
ChatSocketStatus: ChatSocketStatus_default
|
|
18338
18746
|
};
|
|
18339
|
-
var usePushNotifications = () => {
|
|
18340
|
-
const [state, setState] = React2.useState({
|
|
18341
|
-
supported: false,
|
|
18342
|
-
allowedByWorkspace: false,
|
|
18343
|
-
configured: false,
|
|
18344
|
-
permission: "unsupported",
|
|
18345
|
-
userEnabled: true,
|
|
18346
|
-
deviceEnabled: false,
|
|
18347
|
-
loading: true,
|
|
18348
|
-
error: null
|
|
18349
|
-
});
|
|
18350
|
-
const refresh = React2.useCallback(async () => {
|
|
18351
|
-
if (!isPushSupported()) {
|
|
18352
|
-
setState((prev) => ({
|
|
18353
|
-
...prev,
|
|
18354
|
-
supported: false,
|
|
18355
|
-
loading: false
|
|
18356
|
-
}));
|
|
18357
|
-
return;
|
|
18358
|
-
}
|
|
18359
|
-
try {
|
|
18360
|
-
const [config, preference] = await Promise.all([
|
|
18361
|
-
apiGetPushConfig(),
|
|
18362
|
-
apiGetPushPreference().catch(() => null)
|
|
18363
|
-
]);
|
|
18364
|
-
setState({
|
|
18365
|
-
supported: true,
|
|
18366
|
-
allowedByWorkspace: Boolean(config?.enabled),
|
|
18367
|
-
configured: Boolean(config?.configured),
|
|
18368
|
-
permission: Notification.permission,
|
|
18369
|
-
userEnabled: preference?.enabled ?? true,
|
|
18370
|
-
deviceEnabled: Notification.permission === "granted" && Boolean(getStoredPushToken()),
|
|
18371
|
-
loading: false,
|
|
18372
|
-
error: null
|
|
18373
|
-
});
|
|
18374
|
-
} catch (error) {
|
|
18375
|
-
setState((prev) => ({
|
|
18376
|
-
...prev,
|
|
18377
|
-
supported: true,
|
|
18378
|
-
loading: false,
|
|
18379
|
-
error: error instanceof Error ? error.message : "Could not load push settings"
|
|
18380
|
-
}));
|
|
18381
|
-
}
|
|
18382
|
-
}, []);
|
|
18383
|
-
React2.useEffect(() => {
|
|
18384
|
-
void refresh();
|
|
18385
|
-
}, [refresh]);
|
|
18386
|
-
const enable = React2.useCallback(async () => {
|
|
18387
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
18388
|
-
try {
|
|
18389
|
-
await enablePushOnThisDevice();
|
|
18390
|
-
await refresh();
|
|
18391
|
-
return true;
|
|
18392
|
-
} catch (error) {
|
|
18393
|
-
setState((prev) => ({
|
|
18394
|
-
...prev,
|
|
18395
|
-
loading: false,
|
|
18396
|
-
permission: isPushSupported() ? Notification.permission : "unsupported",
|
|
18397
|
-
error: error instanceof Error ? error.message : "Could not enable push notifications"
|
|
18398
|
-
}));
|
|
18399
|
-
return false;
|
|
18400
|
-
}
|
|
18401
|
-
}, [refresh]);
|
|
18402
|
-
const disable = React2.useCallback(async () => {
|
|
18403
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
18404
|
-
try {
|
|
18405
|
-
await disablePushOnThisDevice();
|
|
18406
|
-
} finally {
|
|
18407
|
-
await refresh();
|
|
18408
|
-
}
|
|
18409
|
-
}, [refresh]);
|
|
18410
|
-
const setUserEnabled = React2.useCallback(
|
|
18411
|
-
async (enabled) => {
|
|
18412
|
-
setState((prev) => ({ ...prev, userEnabled: enabled }));
|
|
18413
|
-
try {
|
|
18414
|
-
await apiUpdatePushPreference(enabled);
|
|
18415
|
-
} catch (error) {
|
|
18416
|
-
setState((prev) => ({
|
|
18417
|
-
...prev,
|
|
18418
|
-
userEnabled: !enabled,
|
|
18419
|
-
error: error instanceof Error ? error.message : "Could not update push preference"
|
|
18420
|
-
}));
|
|
18421
|
-
}
|
|
18422
|
-
},
|
|
18423
|
-
[]
|
|
18424
|
-
);
|
|
18425
|
-
return { ...state, enable, disable, setUserEnabled, refresh };
|
|
18426
|
-
};
|
|
18427
|
-
var PushNotificationToggle = ({
|
|
18428
|
-
className,
|
|
18429
|
-
label = "Push notifications",
|
|
18430
|
-
description = "Get notified about new messages on this device"
|
|
18431
|
-
}) => {
|
|
18432
|
-
const push = usePushNotifications();
|
|
18433
|
-
if (!push.supported || !push.allowedByWorkspace || !push.configured) {
|
|
18434
|
-
return null;
|
|
18435
|
-
}
|
|
18436
|
-
const isOn = push.deviceEnabled && push.userEnabled;
|
|
18437
|
-
const permissionBlocked = push.permission === "denied";
|
|
18438
|
-
const handleChange = async (checked) => {
|
|
18439
|
-
if (checked) {
|
|
18440
|
-
if (!push.userEnabled) await push.setUserEnabled(true);
|
|
18441
|
-
if (!push.deviceEnabled) await push.enable();
|
|
18442
|
-
} else {
|
|
18443
|
-
await push.disable();
|
|
18444
|
-
}
|
|
18445
|
-
};
|
|
18446
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18447
|
-
"div",
|
|
18448
|
-
{
|
|
18449
|
-
className: className ?? "flex items-center justify-between gap-4 rounded-xl border border-border bg-background px-4 py-3",
|
|
18450
|
-
children: [
|
|
18451
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
|
|
18452
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: label }),
|
|
18453
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description })
|
|
18454
|
-
] }),
|
|
18455
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18456
|
-
Switch,
|
|
18457
|
-
{
|
|
18458
|
-
checked: isOn,
|
|
18459
|
-
disabled: push.loading || permissionBlocked,
|
|
18460
|
-
onCheckedChange: (checked) => void handleChange(checked),
|
|
18461
|
-
"aria-label": `Toggle ${label}`
|
|
18462
|
-
}
|
|
18463
|
-
)
|
|
18464
|
-
]
|
|
18465
|
-
}
|
|
18466
|
-
);
|
|
18467
|
-
};
|
|
18468
18747
|
|
|
18469
18748
|
// src/index.ts
|
|
18470
18749
|
var index_default = ChatMain_default;
|
|
@@ -18497,16 +18776,21 @@ exports.MessageItem = MessageItemView;
|
|
|
18497
18776
|
exports.MessageList = ActiveChannelMessagesView_default;
|
|
18498
18777
|
exports.NOTIFICATION_CLICK_SW_TYPE = NOTIFICATION_CLICK_SW_TYPE;
|
|
18499
18778
|
exports.OPEN_CONVERSATION_EVENT = OPEN_CONVERSATION_EVENT;
|
|
18779
|
+
exports.PUSH_BROADCAST_CHANNEL = PUSH_BROADCAST_CHANNEL;
|
|
18500
18780
|
exports.PUSH_CHANGED_EVENT = PUSH_CHANGED_EVENT;
|
|
18781
|
+
exports.PUSH_DATA_CACHE_NAME = PUSH_DATA_CACHE_NAME;
|
|
18501
18782
|
exports.PushNotificationToggle = PushNotificationToggle;
|
|
18502
18783
|
exports.apiGetPushConfig = apiGetPushConfig;
|
|
18503
18784
|
exports.apiGetPushPreference = apiGetPushPreference;
|
|
18504
18785
|
exports.apiRegisterPushToken = apiRegisterPushToken;
|
|
18505
18786
|
exports.apiRemovePushToken = apiRemovePushToken;
|
|
18506
18787
|
exports.apiUpdatePushPreference = apiUpdatePushPreference;
|
|
18788
|
+
exports.buildChannelFromPushRequest = buildChannelFromPushRequest;
|
|
18507
18789
|
exports.capitalizeFirst = capitalizeFirst;
|
|
18508
18790
|
exports.clampJumpDate = clampJumpDate;
|
|
18509
18791
|
exports.consumePendingOpenConversation = consumePendingOpenConversation;
|
|
18792
|
+
exports.consumePendingOpenFromPushCache = consumePendingOpenFromPushCache;
|
|
18793
|
+
exports.consumePendingOpenRequest = consumePendingOpenRequest;
|
|
18510
18794
|
exports.default = index_default;
|
|
18511
18795
|
exports.defaultChatClassNames = defaultChatClassNames;
|
|
18512
18796
|
exports.defaultChatComponents = defaultChatComponents;
|
|
@@ -18527,6 +18811,7 @@ exports.mergeChatLayoutConfig = mergeChatLayoutConfig;
|
|
|
18527
18811
|
exports.onForegroundPush = onForegroundPush;
|
|
18528
18812
|
exports.packageDefaultComponents = packageDefaultComponents;
|
|
18529
18813
|
exports.peekPendingOpenConversation = peekPendingOpenConversation;
|
|
18814
|
+
exports.peekPendingOpenRequest = peekPendingOpenRequest;
|
|
18530
18815
|
exports.requestOpenConversation = requestOpenConversation;
|
|
18531
18816
|
exports.resolveApiUrl = resolveApiUrl;
|
|
18532
18817
|
exports.resolveChatApiKey = resolveChatApiKey;
|