@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.mjs
CHANGED
|
@@ -4,16 +4,16 @@ import { create } from 'zustand';
|
|
|
4
4
|
import { persist } from 'zustand/middleware';
|
|
5
5
|
import * as React2 from 'react';
|
|
6
6
|
import React2__default, { createContext, useMemo, useContext, useState, useCallback, useRef, useEffect, useLayoutEffect, useSyncExternalStore } from 'react';
|
|
7
|
-
import { Tooltip as Tooltip$1, Slot, Avatar as Avatar$1, ScrollArea as ScrollArea$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, Dialog as Dialog$1,
|
|
7
|
+
import { Tooltip as Tooltip$1, Slot, Switch as Switch$1, Avatar as Avatar$1, ScrollArea as ScrollArea$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, Dialog as Dialog$1, AlertDialog as AlertDialog$1 } from 'radix-ui';
|
|
8
8
|
import { clsx } from 'clsx';
|
|
9
9
|
import { twMerge } from 'tailwind-merge';
|
|
10
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
11
|
import { flushSync } from 'react-dom';
|
|
12
|
-
import { Sun, Moon, Search, X, Loader2, UserPlus, ChevronDown, ArrowLeft, Users, WifiOff, Wifi, Sparkles, MessageSquareText, ChevronRight, Pin, Star, MoreVertical, Info, UserKey, ShieldUser, Paperclip, Clock, MessageSquareX, Trash2, LogOut, Ban, CheckCheck, Check, Camera, Save, Pencil, Mail, CornerUpLeft, CheckSquare, Smile, ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, MessageCircleMore, History, Shield, Send, AlertCircle, ShieldCheck, UserMinus, MessageCircle, Phone, Video, ExternalLink, Download, ChevronLeft, ZoomOut, ZoomIn, RotateCcw, Music, ArrowRight, MoreHorizontal, PinOff, StarOff, XIcon, ImageIcon, Film, Play, Pause, FileText, FileSpreadsheet, FileIcon, Eye, Captions } from 'lucide-react';
|
|
12
|
+
import { Sun, Moon, Search, X, Loader2, UserPlus, ChevronDown, ArrowLeft, Users, WifiOff, Wifi, Sparkles, MessageSquareText, ChevronRight, Pin, Star, MoreVertical, Info, UserKey, ShieldUser, Paperclip, Clock, MessageSquareX, Trash2, LogOut, Ban, CheckCheck, Check, Camera, Save, Pencil, Mail, CornerUpLeft, CheckSquare, Smile, ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, MessageCircleMore, History, Shield, Send, AlertCircle, ShieldCheck, UserMinus, Settings, MessageCircle, Phone, Video, ExternalLink, Download, ChevronLeft, ZoomOut, ZoomIn, RotateCcw, Music, ArrowRight, MoreHorizontal, PinOff, StarOff, XIcon, ImageIcon, Film, Play, Pause, FileText, FileSpreadsheet, FileIcon, MessageSquare, Eye, Captions } from 'lucide-react';
|
|
13
13
|
import { cva } from 'class-variance-authority';
|
|
14
14
|
import EmojiPicker, { Theme } from 'emoji-picker-react';
|
|
15
15
|
import { getDefaultClassNames, DayPicker } from 'react-day-picker';
|
|
16
|
-
import
|
|
16
|
+
import toast$1, { Toaster, toast } from 'react-hot-toast';
|
|
17
17
|
|
|
18
18
|
var __defProp = Object.defineProperty;
|
|
19
19
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -4631,46 +4631,114 @@ init_store_helpers();
|
|
|
4631
4631
|
init_store_helpers();
|
|
4632
4632
|
var OPEN_CONVERSATION_EVENT = "realtimex:open-conversation";
|
|
4633
4633
|
var NOTIFICATION_CLICK_SW_TYPE = "realtimex:notification-click";
|
|
4634
|
+
var PUSH_BROADCAST_CHANNEL = "realtimex-push";
|
|
4635
|
+
var PUSH_DATA_CACHE_NAME = "realtimex-push-data-v1";
|
|
4634
4636
|
var PENDING_STORAGE_KEY = "realtimex:pending-open-conversation";
|
|
4637
|
+
var PENDING_OPEN_CACHE_PATH = "pending-open";
|
|
4635
4638
|
var resolveConversationIdFromPushData = (data) => {
|
|
4636
4639
|
if (!data || typeof data !== "object") return "";
|
|
4637
|
-
|
|
4640
|
+
let fcmMsg = data.FCM_MSG;
|
|
4641
|
+
if (typeof fcmMsg === "string") {
|
|
4642
|
+
try {
|
|
4643
|
+
fcmMsg = JSON.parse(fcmMsg);
|
|
4644
|
+
} catch {
|
|
4645
|
+
fcmMsg = void 0;
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
const nested = fcmMsg && typeof fcmMsg === "object" ? fcmMsg.data : void 0;
|
|
4638
4649
|
const source = { ...nested || {}, ...data };
|
|
4639
4650
|
return String(
|
|
4640
4651
|
source.conversationId || source.conversation_id || source.conversationID || ""
|
|
4641
|
-
);
|
|
4652
|
+
).trim();
|
|
4653
|
+
};
|
|
4654
|
+
var normalizePushMeta = (meta) => {
|
|
4655
|
+
if (!meta || typeof meta !== "object") return {};
|
|
4656
|
+
return {
|
|
4657
|
+
senderId: String(
|
|
4658
|
+
meta.senderId || meta.sender_id || ""
|
|
4659
|
+
).trim() || void 0,
|
|
4660
|
+
kind: String(meta.kind || "").trim() || void 0,
|
|
4661
|
+
messageId: String(
|
|
4662
|
+
meta.messageId || meta.message_id || ""
|
|
4663
|
+
).trim() || void 0,
|
|
4664
|
+
title: String(meta.title || "").trim() || void 0
|
|
4665
|
+
};
|
|
4666
|
+
};
|
|
4667
|
+
var parsePendingRaw = (raw) => {
|
|
4668
|
+
if (!raw) return null;
|
|
4669
|
+
try {
|
|
4670
|
+
const parsed = JSON.parse(raw);
|
|
4671
|
+
if (parsed?.conversationId) {
|
|
4672
|
+
return {
|
|
4673
|
+
conversationId: String(parsed.conversationId).trim(),
|
|
4674
|
+
...normalizePushMeta(parsed)
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
} catch {
|
|
4678
|
+
}
|
|
4679
|
+
const id = String(raw).trim();
|
|
4680
|
+
return id ? { conversationId: id } : null;
|
|
4642
4681
|
};
|
|
4643
|
-
var peekPendingOpenConversation = () =>
|
|
4682
|
+
var peekPendingOpenConversation = () => peekPendingOpenRequest()?.conversationId ?? null;
|
|
4683
|
+
var peekPendingOpenRequest = () => {
|
|
4644
4684
|
try {
|
|
4645
|
-
return sessionStorage.getItem(PENDING_STORAGE_KEY);
|
|
4685
|
+
return parsePendingRaw(sessionStorage.getItem(PENDING_STORAGE_KEY));
|
|
4646
4686
|
} catch {
|
|
4647
4687
|
return null;
|
|
4648
4688
|
}
|
|
4649
4689
|
};
|
|
4650
|
-
var consumePendingOpenConversation = () =>
|
|
4651
|
-
|
|
4690
|
+
var consumePendingOpenConversation = () => consumePendingOpenRequest()?.conversationId ?? null;
|
|
4691
|
+
var consumePendingOpenRequest = () => {
|
|
4692
|
+
const request = peekPendingOpenRequest();
|
|
4652
4693
|
try {
|
|
4653
4694
|
sessionStorage.removeItem(PENDING_STORAGE_KEY);
|
|
4654
4695
|
} catch {
|
|
4655
4696
|
}
|
|
4656
|
-
return
|
|
4697
|
+
return request;
|
|
4657
4698
|
};
|
|
4658
|
-
var requestOpenConversation = (conversationId) => {
|
|
4699
|
+
var requestOpenConversation = (conversationId, meta) => {
|
|
4659
4700
|
const id = String(conversationId || "").trim();
|
|
4660
4701
|
if (!id) return;
|
|
4702
|
+
const request = {
|
|
4703
|
+
conversationId: id,
|
|
4704
|
+
...normalizePushMeta(meta)
|
|
4705
|
+
};
|
|
4706
|
+
console.log("[realtimex-push] requestOpenConversation:", request);
|
|
4661
4707
|
try {
|
|
4662
|
-
sessionStorage.setItem(PENDING_STORAGE_KEY,
|
|
4708
|
+
sessionStorage.setItem(PENDING_STORAGE_KEY, JSON.stringify(request));
|
|
4663
4709
|
} catch {
|
|
4664
4710
|
}
|
|
4665
4711
|
try {
|
|
4666
4712
|
window.dispatchEvent(
|
|
4667
|
-
new CustomEvent(OPEN_CONVERSATION_EVENT, {
|
|
4668
|
-
detail: { conversationId: id }
|
|
4669
|
-
})
|
|
4713
|
+
new CustomEvent(OPEN_CONVERSATION_EVENT, { detail: request })
|
|
4670
4714
|
);
|
|
4671
4715
|
} catch {
|
|
4672
4716
|
}
|
|
4673
4717
|
};
|
|
4718
|
+
var buildChannelFromPushRequest = (request, loggedUserId, allUsers) => {
|
|
4719
|
+
const conversationId = request.conversationId;
|
|
4720
|
+
const isGroup = request.kind === "group";
|
|
4721
|
+
const senderId = String(request.senderId || "").trim();
|
|
4722
|
+
if (isGroup) {
|
|
4723
|
+
const rawName2 = request.title || "Group Chat";
|
|
4724
|
+
return {
|
|
4725
|
+
id: conversationId,
|
|
4726
|
+
conversationId,
|
|
4727
|
+
name: rawName2.charAt(0).toUpperCase() + rawName2.slice(1),
|
|
4728
|
+
isGroup: true
|
|
4729
|
+
};
|
|
4730
|
+
}
|
|
4731
|
+
const senderUser = senderId ? (allUsers || []).find((user) => String(user._id) === senderId) : null;
|
|
4732
|
+
const rawName = senderUser?.name || request.title || "New message";
|
|
4733
|
+
return {
|
|
4734
|
+
id: senderId || conversationId,
|
|
4735
|
+
conversationId,
|
|
4736
|
+
name: rawName.charAt(0).toUpperCase() + rawName.slice(1),
|
|
4737
|
+
image: senderUser?.image || void 0,
|
|
4738
|
+
email: senderUser?.email,
|
|
4739
|
+
isGroup: false
|
|
4740
|
+
};
|
|
4741
|
+
};
|
|
4674
4742
|
var mapConversationToChannel = (conversation, loggedUserId, allUsers) => {
|
|
4675
4743
|
const conversationId = String(conversation?._id || conversation?.id || "");
|
|
4676
4744
|
const isGroup = isGroupConversation(conversation);
|
|
@@ -4707,6 +4775,37 @@ var mapConversationToChannel = (conversation, loggedUserId, allUsers) => {
|
|
|
4707
4775
|
starredCount: conversation.starredCount
|
|
4708
4776
|
};
|
|
4709
4777
|
};
|
|
4778
|
+
var stripConversationIdFromUrl = () => {
|
|
4779
|
+
if (typeof window === "undefined") return;
|
|
4780
|
+
try {
|
|
4781
|
+
const url = new URL(window.location.href);
|
|
4782
|
+
if (!url.searchParams.has("conversationId")) return;
|
|
4783
|
+
url.searchParams.delete("conversationId");
|
|
4784
|
+
const next = `${url.pathname}${url.search}${url.hash}`;
|
|
4785
|
+
window.history.replaceState(window.history.state, "", next);
|
|
4786
|
+
} catch {
|
|
4787
|
+
}
|
|
4788
|
+
};
|
|
4789
|
+
var cacheRequestForPath = (path) => new Request(new URL(path, window.location.origin).toString());
|
|
4790
|
+
var consumePendingOpenFromPushCache = async () => {
|
|
4791
|
+
if (typeof caches === "undefined") return null;
|
|
4792
|
+
try {
|
|
4793
|
+
const cache = await caches.open(PUSH_DATA_CACHE_NAME);
|
|
4794
|
+
const req = cacheRequestForPath(PENDING_OPEN_CACHE_PATH);
|
|
4795
|
+
const res = await cache.match(req);
|
|
4796
|
+
if (!res) return null;
|
|
4797
|
+
await cache.delete(req);
|
|
4798
|
+
const data = await res.json();
|
|
4799
|
+
const conversationId = resolveConversationIdFromPushData(data);
|
|
4800
|
+
if (!conversationId) return null;
|
|
4801
|
+
return {
|
|
4802
|
+
conversationId,
|
|
4803
|
+
...normalizePushMeta(data)
|
|
4804
|
+
};
|
|
4805
|
+
} catch {
|
|
4806
|
+
return null;
|
|
4807
|
+
}
|
|
4808
|
+
};
|
|
4710
4809
|
var readConversationIdFromLocation = () => {
|
|
4711
4810
|
try {
|
|
4712
4811
|
return new URLSearchParams(window.location.search).get("conversationId") || "";
|
|
@@ -4715,34 +4814,73 @@ var readConversationIdFromLocation = () => {
|
|
|
4715
4814
|
}
|
|
4716
4815
|
};
|
|
4717
4816
|
var consumedUrlConversationIds = /* @__PURE__ */ new Set();
|
|
4817
|
+
var lastHandledOpenId = "";
|
|
4818
|
+
var lastHandledOpenAt = 0;
|
|
4819
|
+
var shouldHandleOpen = (conversationId) => {
|
|
4820
|
+
const id = String(conversationId || "").trim();
|
|
4821
|
+
if (!id) return false;
|
|
4822
|
+
const now = Date.now();
|
|
4823
|
+
if (lastHandledOpenId === id && now - lastHandledOpenAt < 2500) {
|
|
4824
|
+
return false;
|
|
4825
|
+
}
|
|
4826
|
+
lastHandledOpenId = id;
|
|
4827
|
+
lastHandledOpenAt = now;
|
|
4828
|
+
return true;
|
|
4829
|
+
};
|
|
4830
|
+
var handleNotificationOpen = (conversationId, pushData, options) => {
|
|
4831
|
+
const id = String(conversationId || "").trim();
|
|
4832
|
+
if (!id) {
|
|
4833
|
+
console.warn("[realtimex-push] notification open ignored \u2014 no conversationId", pushData);
|
|
4834
|
+
return;
|
|
4835
|
+
}
|
|
4836
|
+
if (!shouldHandleOpen(id)) {
|
|
4837
|
+
stripConversationIdFromUrl();
|
|
4838
|
+
return;
|
|
4839
|
+
}
|
|
4840
|
+
requestOpenConversation(id, pushData);
|
|
4841
|
+
const chatPath = options.chatPath || "/chat";
|
|
4842
|
+
stripConversationIdFromUrl();
|
|
4843
|
+
options.onNavigate?.(id, chatPath);
|
|
4844
|
+
};
|
|
4718
4845
|
var installNotificationClickBridge = (options = {}) => {
|
|
4719
4846
|
if (typeof window === "undefined") return () => void 0;
|
|
4720
|
-
const chatPath = options.chatPath || "/chat";
|
|
4721
|
-
const handleOpen = (conversationId) => {
|
|
4722
|
-
const id = String(conversationId || "").trim();
|
|
4723
|
-
if (!id) return;
|
|
4724
|
-
requestOpenConversation(id);
|
|
4725
|
-
const pathWithQuery = `${chatPath}?conversationId=${encodeURIComponent(id)}`;
|
|
4726
|
-
options.onNavigate?.(id, pathWithQuery);
|
|
4727
|
-
};
|
|
4728
4847
|
const onSwMessage = (event) => {
|
|
4729
4848
|
const data = event.data;
|
|
4730
4849
|
console.log("[realtimex-push] SW \u2192 page message:", data);
|
|
4731
4850
|
if (!data || data.type !== NOTIFICATION_CLICK_SW_TYPE) return;
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4851
|
+
const pushData = data.data && typeof data.data === "object" ? data.data : void 0;
|
|
4852
|
+
const conversationId = String(data.conversationId || "") || resolveConversationIdFromPushData(pushData);
|
|
4853
|
+
console.log("[realtimex-push] notification click \u2192 open:", {
|
|
4854
|
+
conversationId,
|
|
4855
|
+
pushData
|
|
4856
|
+
});
|
|
4857
|
+
handleNotificationOpen(conversationId, pushData, options);
|
|
4737
4858
|
};
|
|
4738
4859
|
navigator.serviceWorker?.addEventListener("message", onSwMessage);
|
|
4860
|
+
let broadcast = null;
|
|
4861
|
+
try {
|
|
4862
|
+
broadcast = new BroadcastChannel(PUSH_BROADCAST_CHANNEL);
|
|
4863
|
+
broadcast.onmessage = onSwMessage;
|
|
4864
|
+
} catch {
|
|
4865
|
+
}
|
|
4739
4866
|
const fromUrl = readConversationIdFromLocation();
|
|
4740
4867
|
if (fromUrl && !consumedUrlConversationIds.has(fromUrl)) {
|
|
4741
4868
|
consumedUrlConversationIds.add(fromUrl);
|
|
4742
|
-
|
|
4869
|
+
handleNotificationOpen(fromUrl, void 0, options);
|
|
4870
|
+
} else {
|
|
4871
|
+
stripConversationIdFromUrl();
|
|
4743
4872
|
}
|
|
4873
|
+
void consumePendingOpenFromPushCache().then((request) => {
|
|
4874
|
+
if (!request?.conversationId) return;
|
|
4875
|
+
handleNotificationOpen(
|
|
4876
|
+
request.conversationId,
|
|
4877
|
+
request,
|
|
4878
|
+
options
|
|
4879
|
+
);
|
|
4880
|
+
});
|
|
4744
4881
|
return () => {
|
|
4745
4882
|
navigator.serviceWorker?.removeEventListener("message", onSwMessage);
|
|
4883
|
+
broadcast?.close();
|
|
4746
4884
|
};
|
|
4747
4885
|
};
|
|
4748
4886
|
|
|
@@ -4822,7 +4960,7 @@ var useChatController = () => {
|
|
|
4822
4960
|
const allUsers = useStore((s) => s.allUsers);
|
|
4823
4961
|
const isFetchingConversations = useStore((s) => s.isFetchingConversations);
|
|
4824
4962
|
const conversations = useStore((s) => s.conversations);
|
|
4825
|
-
const [
|
|
4963
|
+
const [pendingOpenRequest, setPendingOpenRequest] = useState(() => peekPendingOpenRequest());
|
|
4826
4964
|
const conversationsLength = useStore(
|
|
4827
4965
|
(s) => state.activeChannel?.conversationId ? 0 : s.conversations.length
|
|
4828
4966
|
);
|
|
@@ -4853,32 +4991,42 @@ var useChatController = () => {
|
|
|
4853
4991
|
});
|
|
4854
4992
|
useEffect(() => {
|
|
4855
4993
|
const onOpen = (event) => {
|
|
4856
|
-
const
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4994
|
+
const detail = event.detail;
|
|
4995
|
+
if (detail?.conversationId) {
|
|
4996
|
+
console.log("[realtimex-push] OPEN_CONVERSATION_EVENT:", detail);
|
|
4997
|
+
setPendingOpenRequest({
|
|
4998
|
+
conversationId: String(detail.conversationId),
|
|
4999
|
+
senderId: detail.senderId,
|
|
5000
|
+
kind: detail.kind,
|
|
5001
|
+
messageId: detail.messageId,
|
|
5002
|
+
title: detail.title
|
|
5003
|
+
});
|
|
5004
|
+
}
|
|
4860
5005
|
};
|
|
4861
5006
|
window.addEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
4862
5007
|
return () => window.removeEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
4863
5008
|
}, []);
|
|
4864
5009
|
useEffect(() => {
|
|
4865
|
-
if (!
|
|
5010
|
+
if (!pendingOpenRequest?.conversationId || !loggedUserDetails) return;
|
|
4866
5011
|
let cancelled = false;
|
|
4867
5012
|
const openPending = async () => {
|
|
4868
|
-
const targetId = String(
|
|
5013
|
+
const targetId = String(pendingOpenRequest.conversationId);
|
|
5014
|
+
console.log("[realtimex-push] opening conversation:", pendingOpenRequest);
|
|
4869
5015
|
let conversation = conversations.find(
|
|
4870
5016
|
(c) => String(c._id || c.id) === targetId
|
|
4871
5017
|
) || null;
|
|
4872
5018
|
if (!conversation) {
|
|
4873
|
-
|
|
4874
|
-
if (fromInfo) conversation = fromInfo;
|
|
5019
|
+
conversation = conversationInfos[targetId] || null;
|
|
4875
5020
|
}
|
|
4876
5021
|
if (!conversation) {
|
|
4877
|
-
if (isFetchingConversations)
|
|
5022
|
+
if (isFetchingConversations) {
|
|
5023
|
+
console.log("[realtimex-push] waiting for conversations list\u2026");
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
4878
5026
|
try {
|
|
4879
5027
|
await fetchConversationInfo2(targetId);
|
|
4880
|
-
} catch {
|
|
4881
|
-
|
|
5028
|
+
} catch (error) {
|
|
5029
|
+
console.warn("[realtimex-push] fetchConversationInfo failed:", error);
|
|
4882
5030
|
}
|
|
4883
5031
|
if (cancelled) return;
|
|
4884
5032
|
const stateNow = useStore.getState();
|
|
@@ -4886,12 +5034,17 @@ var useChatController = () => {
|
|
|
4886
5034
|
(c) => String(c._id || c.id) === targetId
|
|
4887
5035
|
) || stateNow.conversationInfos[targetId] || null;
|
|
4888
5036
|
}
|
|
4889
|
-
|
|
4890
|
-
const channel = mapConversationToChannel(
|
|
5037
|
+
const channel = conversation ? mapConversationToChannel(
|
|
4891
5038
|
conversation,
|
|
4892
5039
|
loggedUserDetails._id,
|
|
4893
5040
|
allUsers
|
|
5041
|
+
) : buildChannelFromPushRequest(
|
|
5042
|
+
pendingOpenRequest,
|
|
5043
|
+
loggedUserDetails._id,
|
|
5044
|
+
allUsers
|
|
4894
5045
|
);
|
|
5046
|
+
console.log("[realtimex-push] selected channel:", channel);
|
|
5047
|
+
if (cancelled) return;
|
|
4895
5048
|
setState((prev) => {
|
|
4896
5049
|
if (prev.activeChannel?.conversationId && String(prev.activeChannel.conversationId) === targetId) {
|
|
4897
5050
|
return prev;
|
|
@@ -4902,15 +5055,16 @@ var useChatController = () => {
|
|
|
4902
5055
|
activeConversationId: targetId
|
|
4903
5056
|
};
|
|
4904
5057
|
});
|
|
4905
|
-
|
|
4906
|
-
|
|
5058
|
+
useStore.getState().setActiveConversationId(targetId);
|
|
5059
|
+
consumePendingOpenRequest();
|
|
5060
|
+
setPendingOpenRequest(null);
|
|
4907
5061
|
};
|
|
4908
5062
|
void openPending();
|
|
4909
5063
|
return () => {
|
|
4910
5064
|
cancelled = true;
|
|
4911
5065
|
};
|
|
4912
5066
|
}, [
|
|
4913
|
-
|
|
5067
|
+
pendingOpenRequest,
|
|
4914
5068
|
loggedUserDetails,
|
|
4915
5069
|
conversations,
|
|
4916
5070
|
conversationInfos,
|
|
@@ -6361,184 +6515,562 @@ var CreateChatDialog = (props) => {
|
|
|
6361
6515
|
);
|
|
6362
6516
|
};
|
|
6363
6517
|
var CreateChatDialog_default = CreateChatDialog;
|
|
6364
|
-
|
|
6365
|
-
loggedUserDetails,
|
|
6366
|
-
onUserSelect,
|
|
6367
|
-
isCreateModalOpen = false,
|
|
6368
|
-
setIsCreateModalOpen,
|
|
6369
|
-
searchQuery = "",
|
|
6370
|
-
setSearchQuery
|
|
6371
|
-
}) => {
|
|
6372
|
-
const { showColorModeToggle } = useChatTheme();
|
|
6373
|
-
const user = {
|
|
6374
|
-
_id: loggedUserDetails?._id || "1",
|
|
6375
|
-
name: formatLoggedUserName(loggedUserDetails?.name),
|
|
6376
|
-
email: loggedUserDetails?.email || "user@example.com",
|
|
6377
|
-
role: loggedUserDetails?.role || "user",
|
|
6378
|
-
isActive: loggedUserDetails?.isActive ?? true,
|
|
6379
|
-
createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
|
|
6380
|
-
updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
|
|
6381
|
-
image: loggedUserDetails?.image || void 0
|
|
6382
|
-
};
|
|
6383
|
-
return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b border-(--chat-border) bg-(--chat-surface) px-3 pb-3 pt-3", children: [
|
|
6384
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
6385
|
-
/* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
|
|
6386
|
-
/* @__PURE__ */ jsxs(Avatar, { className: "size-8 ring-1 ring-(--chat-surface)", children: [
|
|
6387
|
-
user.image ? /* @__PURE__ */ jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
|
|
6388
|
-
/* @__PURE__ */ jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-[10px] font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
|
|
6389
|
-
] }),
|
|
6390
|
-
/* @__PURE__ */ jsx("span", { className: "absolute -bottom-0.5 -right-0.5 size-2 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
|
|
6391
|
-
] }),
|
|
6392
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
6393
|
-
/* @__PURE__ */ jsx("h2", { className: "truncate text-xs font-medium leading-tight text-(--chat-text)", children: user.name }),
|
|
6394
|
-
/* @__PURE__ */ jsx("p", { className: "truncate text-[10px] text-(--chat-muted)", children: user.email })
|
|
6395
|
-
] }),
|
|
6396
|
-
showColorModeToggle ? /* @__PURE__ */ jsx(ChatThemeToggle_default, {}) : null
|
|
6397
|
-
] }),
|
|
6398
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center gap-1.5", children: [
|
|
6399
|
-
/* @__PURE__ */ jsxs("div", { className: chatSidebarSearchShellClass, children: [
|
|
6400
|
-
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none size-3.5 shrink-0 text-(--chat-muted)" }),
|
|
6401
|
-
/* @__PURE__ */ jsx(
|
|
6402
|
-
"input",
|
|
6403
|
-
{
|
|
6404
|
-
type: "text",
|
|
6405
|
-
inputMode: "search",
|
|
6406
|
-
enterKeyHint: "search",
|
|
6407
|
-
placeholder: "Search conversations...",
|
|
6408
|
-
value: searchQuery,
|
|
6409
|
-
onChange: (e) => setSearchQuery?.(e.target.value),
|
|
6410
|
-
className: chatSidebarSearchInputClass
|
|
6411
|
-
}
|
|
6412
|
-
),
|
|
6413
|
-
searchQuery ? /* @__PURE__ */ jsx(
|
|
6414
|
-
"button",
|
|
6415
|
-
{
|
|
6416
|
-
type: "button",
|
|
6417
|
-
onClick: () => setSearchQuery?.(""),
|
|
6418
|
-
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)",
|
|
6419
|
-
"aria-label": "Clear search",
|
|
6420
|
-
children: /* @__PURE__ */ jsx(X, { size: 12 })
|
|
6421
|
-
}
|
|
6422
|
-
) : null
|
|
6423
|
-
] }),
|
|
6424
|
-
/* @__PURE__ */ jsx(
|
|
6425
|
-
CreateChatDialog_default,
|
|
6426
|
-
{
|
|
6427
|
-
loggedUserDetails,
|
|
6428
|
-
onUserSelect,
|
|
6429
|
-
isCreateModalOpen,
|
|
6430
|
-
setIsCreateModalOpen
|
|
6431
|
-
}
|
|
6432
|
-
)
|
|
6433
|
-
] })
|
|
6434
|
-
] });
|
|
6435
|
-
};
|
|
6436
|
-
var LoggedUserDetails_default = LoggedUserDetails;
|
|
6437
|
-
function ScrollArea({
|
|
6438
|
-
className,
|
|
6439
|
-
children,
|
|
6440
|
-
...props
|
|
6441
|
-
}) {
|
|
6442
|
-
return /* @__PURE__ */ jsxs(
|
|
6443
|
-
ScrollArea$1.Root,
|
|
6444
|
-
{
|
|
6445
|
-
"data-slot": "scroll-area",
|
|
6446
|
-
className: cn("relative", className),
|
|
6447
|
-
...props,
|
|
6448
|
-
children: [
|
|
6449
|
-
/* @__PURE__ */ jsx(
|
|
6450
|
-
ScrollArea$1.Viewport,
|
|
6451
|
-
{
|
|
6452
|
-
"data-slot": "scroll-area-viewport",
|
|
6453
|
-
className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
|
|
6454
|
-
children
|
|
6455
|
-
}
|
|
6456
|
-
),
|
|
6457
|
-
/* @__PURE__ */ jsx(ScrollBar, {}),
|
|
6458
|
-
/* @__PURE__ */ jsx(ScrollArea$1.Corner, {})
|
|
6459
|
-
]
|
|
6460
|
-
}
|
|
6461
|
-
);
|
|
6462
|
-
}
|
|
6463
|
-
function ScrollBar({
|
|
6518
|
+
function Switch({
|
|
6464
6519
|
className,
|
|
6465
|
-
|
|
6520
|
+
size = "default",
|
|
6466
6521
|
...props
|
|
6467
6522
|
}) {
|
|
6468
6523
|
return /* @__PURE__ */ jsx(
|
|
6469
|
-
|
|
6524
|
+
Switch$1.Root,
|
|
6470
6525
|
{
|
|
6471
|
-
"data-slot": "
|
|
6472
|
-
|
|
6526
|
+
"data-slot": "switch",
|
|
6527
|
+
"data-size": size,
|
|
6473
6528
|
className: cn(
|
|
6474
|
-
"flex
|
|
6475
|
-
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
6476
|
-
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
|
|
6529
|
+
"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",
|
|
6477
6530
|
className
|
|
6478
6531
|
),
|
|
6479
6532
|
...props,
|
|
6480
6533
|
children: /* @__PURE__ */ jsx(
|
|
6481
|
-
|
|
6534
|
+
Switch$1.Thumb,
|
|
6482
6535
|
{
|
|
6483
|
-
"data-slot": "
|
|
6484
|
-
className:
|
|
6536
|
+
"data-slot": "switch-thumb",
|
|
6537
|
+
className: cn(
|
|
6538
|
+
"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"
|
|
6539
|
+
)
|
|
6485
6540
|
}
|
|
6486
6541
|
)
|
|
6487
6542
|
}
|
|
6488
6543
|
);
|
|
6489
6544
|
}
|
|
6490
6545
|
|
|
6491
|
-
// src/
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
var
|
|
6495
|
-
var
|
|
6496
|
-
var
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
})
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
function notifyDraftChange() {
|
|
6503
|
-
draftRevision += 1;
|
|
6504
|
-
draftListeners.forEach((listener) => listener());
|
|
6505
|
-
}
|
|
6506
|
-
function subscribeToDrafts(listener) {
|
|
6507
|
-
draftListeners.add(listener);
|
|
6508
|
-
return () => {
|
|
6509
|
-
draftListeners.delete(listener);
|
|
6510
|
-
};
|
|
6511
|
-
}
|
|
6512
|
-
function getDraftRevision() {
|
|
6513
|
-
return draftRevision;
|
|
6514
|
-
}
|
|
6515
|
-
function useDraftRevision() {
|
|
6516
|
-
return useSyncExternalStore(subscribeToDrafts, getDraftRevision, getDraftRevision);
|
|
6517
|
-
}
|
|
6518
|
-
function getConversationDraft(conversationId) {
|
|
6519
|
-
if (!conversationId) return emptyDraft();
|
|
6520
|
-
return conversationDrafts.get(conversationId) ?? emptyDraft();
|
|
6521
|
-
}
|
|
6522
|
-
function updateConversationDraft(conversationId, draft) {
|
|
6523
|
-
if (!conversationId) return;
|
|
6524
|
-
if (draft.messageInput.trim() || draft.attachments.length > 0) {
|
|
6525
|
-
conversationDrafts.set(conversationId, {
|
|
6526
|
-
messageInput: draft.messageInput,
|
|
6527
|
-
attachments: draft.attachments
|
|
6528
|
-
});
|
|
6529
|
-
} else {
|
|
6530
|
-
conversationDrafts.delete(conversationId);
|
|
6546
|
+
// src/notifications/push.service.ts
|
|
6547
|
+
init_client();
|
|
6548
|
+
var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
|
|
6549
|
+
var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
|
|
6550
|
+
var PUSH_CHANGED_EVENT = "realtimex:push-changed";
|
|
6551
|
+
var emitPushChanged = (enabled) => {
|
|
6552
|
+
try {
|
|
6553
|
+
window.dispatchEvent(
|
|
6554
|
+
new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
|
|
6555
|
+
);
|
|
6556
|
+
} catch {
|
|
6531
6557
|
}
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
}
|
|
6540
|
-
|
|
6541
|
-
|
|
6558
|
+
};
|
|
6559
|
+
var v2Url = "https://realtimex.softwareco.com/api/v2";
|
|
6560
|
+
var apiGetPushConfig = async () => {
|
|
6561
|
+
const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
|
|
6562
|
+
return data?.data;
|
|
6563
|
+
};
|
|
6564
|
+
var apiRegisterPushToken = async (token, deviceLabel) => {
|
|
6565
|
+
const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
|
|
6566
|
+
token,
|
|
6567
|
+
deviceLabel
|
|
6568
|
+
});
|
|
6569
|
+
return data?.data;
|
|
6570
|
+
};
|
|
6571
|
+
var apiRemovePushToken = async (token) => {
|
|
6572
|
+
const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
|
|
6573
|
+
data: { token }
|
|
6574
|
+
});
|
|
6575
|
+
return data;
|
|
6576
|
+
};
|
|
6577
|
+
var apiGetPushPreference = async () => {
|
|
6578
|
+
const { data } = await apiClient.get(
|
|
6579
|
+
`${v2Url}/notifications/push/preference`
|
|
6580
|
+
);
|
|
6581
|
+
return data?.data;
|
|
6582
|
+
};
|
|
6583
|
+
var apiUpdatePushPreference = async (enabled) => {
|
|
6584
|
+
const { data } = await apiClient.patch(
|
|
6585
|
+
`${v2Url}/notifications/push/preference`,
|
|
6586
|
+
{ enabled }
|
|
6587
|
+
);
|
|
6588
|
+
return data?.data;
|
|
6589
|
+
};
|
|
6590
|
+
var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
|
|
6591
|
+
var getStoredPushToken = () => {
|
|
6592
|
+
try {
|
|
6593
|
+
return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
|
|
6594
|
+
} catch {
|
|
6595
|
+
return null;
|
|
6596
|
+
}
|
|
6597
|
+
};
|
|
6598
|
+
var storePushToken = (token) => {
|
|
6599
|
+
try {
|
|
6600
|
+
if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
|
|
6601
|
+
else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
|
|
6602
|
+
} catch {
|
|
6603
|
+
}
|
|
6604
|
+
};
|
|
6605
|
+
var defaultDeviceLabel = () => {
|
|
6606
|
+
const ua = navigator.userAgent;
|
|
6607
|
+
const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
|
|
6608
|
+
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";
|
|
6609
|
+
return `${browser} on ${os}`;
|
|
6610
|
+
};
|
|
6611
|
+
var loadFirebaseMessaging = async () => {
|
|
6612
|
+
try {
|
|
6613
|
+
const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
|
|
6614
|
+
import('firebase/app'),
|
|
6615
|
+
import('firebase/messaging')
|
|
6616
|
+
]);
|
|
6617
|
+
return { initializeApp, getApps, ...messagingModule };
|
|
6618
|
+
} catch {
|
|
6619
|
+
throw new Error(
|
|
6620
|
+
'Push notifications need the "firebase" package \u2014 run: npm install firebase'
|
|
6621
|
+
);
|
|
6622
|
+
}
|
|
6623
|
+
};
|
|
6624
|
+
var getFirebaseMessaging = async (firebaseConfig) => {
|
|
6625
|
+
const fb = await loadFirebaseMessaging();
|
|
6626
|
+
const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
|
|
6627
|
+
return { fb, messaging: fb.getMessaging(app) };
|
|
6628
|
+
};
|
|
6629
|
+
var enablePushOnThisDevice = async () => {
|
|
6630
|
+
if (!isPushSupported()) {
|
|
6631
|
+
throw new Error("Push notifications are not supported in this browser");
|
|
6632
|
+
}
|
|
6633
|
+
const config = await apiGetPushConfig();
|
|
6634
|
+
if (!config?.enabled) {
|
|
6635
|
+
throw new Error("Push notifications are disabled for this workspace");
|
|
6636
|
+
}
|
|
6637
|
+
if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
|
|
6638
|
+
throw new Error(
|
|
6639
|
+
"Push notifications are not configured on the server yet"
|
|
6640
|
+
);
|
|
6641
|
+
}
|
|
6642
|
+
const permission = await Notification.requestPermission();
|
|
6643
|
+
if (permission !== "granted") {
|
|
6644
|
+
throw new Error("Notification permission was not granted");
|
|
6645
|
+
}
|
|
6646
|
+
let registration;
|
|
6647
|
+
try {
|
|
6648
|
+
registration = await navigator.serviceWorker.register(
|
|
6649
|
+
`${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
|
|
6650
|
+
JSON.stringify(config.firebaseConfig)
|
|
6651
|
+
)}`
|
|
6652
|
+
);
|
|
6653
|
+
} catch {
|
|
6654
|
+
throw new Error(
|
|
6655
|
+
`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`
|
|
6656
|
+
);
|
|
6657
|
+
}
|
|
6658
|
+
const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
|
|
6659
|
+
const token = await fb.getToken(messaging, {
|
|
6660
|
+
vapidKey: config.vapidKey,
|
|
6661
|
+
serviceWorkerRegistration: registration
|
|
6662
|
+
});
|
|
6663
|
+
if (!token) {
|
|
6664
|
+
throw new Error("Could not obtain a push token from Firebase");
|
|
6665
|
+
}
|
|
6666
|
+
await apiRegisterPushToken(token, defaultDeviceLabel());
|
|
6667
|
+
storePushToken(token);
|
|
6668
|
+
emitPushChanged(true);
|
|
6669
|
+
return token;
|
|
6670
|
+
};
|
|
6671
|
+
var disablePushOnThisDevice = async () => {
|
|
6672
|
+
const token = getStoredPushToken();
|
|
6673
|
+
if (!token) return;
|
|
6674
|
+
try {
|
|
6675
|
+
const config = await apiGetPushConfig();
|
|
6676
|
+
if (config?.firebaseConfig) {
|
|
6677
|
+
const { fb, messaging } = await getFirebaseMessaging(
|
|
6678
|
+
config.firebaseConfig
|
|
6679
|
+
);
|
|
6680
|
+
await fb.deleteToken(messaging).catch(() => void 0);
|
|
6681
|
+
}
|
|
6682
|
+
} catch {
|
|
6683
|
+
}
|
|
6684
|
+
await apiRemovePushToken(token).catch(() => void 0);
|
|
6685
|
+
storePushToken(null);
|
|
6686
|
+
emitPushChanged(false);
|
|
6687
|
+
};
|
|
6688
|
+
var onForegroundPush = async (callback) => {
|
|
6689
|
+
const config = await apiGetPushConfig();
|
|
6690
|
+
if (!config?.configured || !config.firebaseConfig) {
|
|
6691
|
+
throw new Error("Push config unavailable (not configured or API not ready)");
|
|
6692
|
+
}
|
|
6693
|
+
const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
|
|
6694
|
+
return fb.onMessage(messaging, (payload) => {
|
|
6695
|
+
console.log("[realtimex-push] FCM foreground payload (raw):", payload);
|
|
6696
|
+
console.log("[realtimex-push] FCM foreground data:", payload?.data);
|
|
6697
|
+
console.log("[realtimex-push] FCM foreground notification:", payload?.notification);
|
|
6698
|
+
callback({
|
|
6699
|
+
title: payload?.notification?.title,
|
|
6700
|
+
body: payload?.notification?.body,
|
|
6701
|
+
data: payload?.data
|
|
6702
|
+
});
|
|
6703
|
+
});
|
|
6704
|
+
};
|
|
6705
|
+
|
|
6706
|
+
// src/notifications/usePushNotifications.ts
|
|
6707
|
+
var usePushNotifications = () => {
|
|
6708
|
+
const [state, setState] = useState({
|
|
6709
|
+
supported: false,
|
|
6710
|
+
allowedByWorkspace: false,
|
|
6711
|
+
configured: false,
|
|
6712
|
+
permission: "unsupported",
|
|
6713
|
+
userEnabled: true,
|
|
6714
|
+
deviceEnabled: false,
|
|
6715
|
+
loading: true,
|
|
6716
|
+
error: null
|
|
6717
|
+
});
|
|
6718
|
+
const refresh = useCallback(async () => {
|
|
6719
|
+
if (!isPushSupported()) {
|
|
6720
|
+
setState((prev) => ({
|
|
6721
|
+
...prev,
|
|
6722
|
+
supported: false,
|
|
6723
|
+
loading: false
|
|
6724
|
+
}));
|
|
6725
|
+
return;
|
|
6726
|
+
}
|
|
6727
|
+
try {
|
|
6728
|
+
const [config, preference] = await Promise.all([
|
|
6729
|
+
apiGetPushConfig(),
|
|
6730
|
+
apiGetPushPreference().catch(() => null)
|
|
6731
|
+
]);
|
|
6732
|
+
setState({
|
|
6733
|
+
supported: true,
|
|
6734
|
+
allowedByWorkspace: Boolean(config?.enabled),
|
|
6735
|
+
configured: Boolean(config?.configured),
|
|
6736
|
+
permission: Notification.permission,
|
|
6737
|
+
userEnabled: preference?.enabled ?? true,
|
|
6738
|
+
deviceEnabled: Notification.permission === "granted" && Boolean(getStoredPushToken()),
|
|
6739
|
+
loading: false,
|
|
6740
|
+
error: null
|
|
6741
|
+
});
|
|
6742
|
+
} catch (error) {
|
|
6743
|
+
setState((prev) => ({
|
|
6744
|
+
...prev,
|
|
6745
|
+
supported: true,
|
|
6746
|
+
loading: false,
|
|
6747
|
+
error: error instanceof Error ? error.message : "Could not load push settings"
|
|
6748
|
+
}));
|
|
6749
|
+
}
|
|
6750
|
+
}, []);
|
|
6751
|
+
useEffect(() => {
|
|
6752
|
+
void refresh();
|
|
6753
|
+
}, [refresh]);
|
|
6754
|
+
const enable = useCallback(async () => {
|
|
6755
|
+
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
6756
|
+
try {
|
|
6757
|
+
await enablePushOnThisDevice();
|
|
6758
|
+
await refresh();
|
|
6759
|
+
return true;
|
|
6760
|
+
} catch (error) {
|
|
6761
|
+
setState((prev) => ({
|
|
6762
|
+
...prev,
|
|
6763
|
+
loading: false,
|
|
6764
|
+
permission: isPushSupported() ? Notification.permission : "unsupported",
|
|
6765
|
+
error: error instanceof Error ? error.message : "Could not enable push notifications"
|
|
6766
|
+
}));
|
|
6767
|
+
return false;
|
|
6768
|
+
}
|
|
6769
|
+
}, [refresh]);
|
|
6770
|
+
const disable = useCallback(async () => {
|
|
6771
|
+
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
6772
|
+
try {
|
|
6773
|
+
await disablePushOnThisDevice();
|
|
6774
|
+
} finally {
|
|
6775
|
+
await refresh();
|
|
6776
|
+
}
|
|
6777
|
+
}, [refresh]);
|
|
6778
|
+
const setUserEnabled = useCallback(
|
|
6779
|
+
async (enabled) => {
|
|
6780
|
+
setState((prev) => ({ ...prev, userEnabled: enabled }));
|
|
6781
|
+
try {
|
|
6782
|
+
await apiUpdatePushPreference(enabled);
|
|
6783
|
+
} catch (error) {
|
|
6784
|
+
setState((prev) => ({
|
|
6785
|
+
...prev,
|
|
6786
|
+
userEnabled: !enabled,
|
|
6787
|
+
error: error instanceof Error ? error.message : "Could not update push preference"
|
|
6788
|
+
}));
|
|
6789
|
+
}
|
|
6790
|
+
},
|
|
6791
|
+
[]
|
|
6792
|
+
);
|
|
6793
|
+
return { ...state, enable, disable, setUserEnabled, refresh };
|
|
6794
|
+
};
|
|
6795
|
+
var PushNotificationToggle = ({
|
|
6796
|
+
className,
|
|
6797
|
+
label = "Push notifications",
|
|
6798
|
+
description = "Get notified about new messages on this device"
|
|
6799
|
+
}) => {
|
|
6800
|
+
const push = usePushNotifications();
|
|
6801
|
+
if (!push.supported || !push.allowedByWorkspace || !push.configured) {
|
|
6802
|
+
return null;
|
|
6803
|
+
}
|
|
6804
|
+
const isOn = push.deviceEnabled && push.userEnabled;
|
|
6805
|
+
const permissionBlocked = push.permission === "denied";
|
|
6806
|
+
const handleChange = async (checked) => {
|
|
6807
|
+
if (checked) {
|
|
6808
|
+
if (!push.userEnabled) await push.setUserEnabled(true);
|
|
6809
|
+
if (!push.deviceEnabled) await push.enable();
|
|
6810
|
+
} else {
|
|
6811
|
+
await push.disable();
|
|
6812
|
+
}
|
|
6813
|
+
};
|
|
6814
|
+
return /* @__PURE__ */ jsxs(
|
|
6815
|
+
"div",
|
|
6816
|
+
{
|
|
6817
|
+
className: className ?? "flex items-center justify-between gap-4 rounded-xl border border-(--chat-border) bg-(--chat-surface) px-4 py-3",
|
|
6818
|
+
children: [
|
|
6819
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
6820
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-(--chat-text)", children: label }),
|
|
6821
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-(--chat-muted)", children: permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description })
|
|
6822
|
+
] }),
|
|
6823
|
+
/* @__PURE__ */ jsx(
|
|
6824
|
+
Switch,
|
|
6825
|
+
{
|
|
6826
|
+
checked: isOn,
|
|
6827
|
+
disabled: push.loading || permissionBlocked,
|
|
6828
|
+
onCheckedChange: (checked) => void handleChange(checked),
|
|
6829
|
+
"aria-label": `Toggle ${label}`
|
|
6830
|
+
}
|
|
6831
|
+
)
|
|
6832
|
+
]
|
|
6833
|
+
}
|
|
6834
|
+
);
|
|
6835
|
+
};
|
|
6836
|
+
var LoggedUserSettingsDialog = ({
|
|
6837
|
+
loggedUserDetails
|
|
6838
|
+
}) => {
|
|
6839
|
+
const [open, setOpen] = useState(false);
|
|
6840
|
+
const user = {
|
|
6841
|
+
_id: loggedUserDetails?._id || "1",
|
|
6842
|
+
name: formatLoggedUserName(loggedUserDetails?.name),
|
|
6843
|
+
email: loggedUserDetails?.email || "user@example.com",
|
|
6844
|
+
role: loggedUserDetails?.role || "user",
|
|
6845
|
+
isActive: loggedUserDetails?.isActive ?? true,
|
|
6846
|
+
createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
|
|
6847
|
+
updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
|
|
6848
|
+
image: loggedUserDetails?.image || void 0
|
|
6849
|
+
};
|
|
6850
|
+
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: setOpen, children: [
|
|
6851
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
6852
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
6853
|
+
Button,
|
|
6854
|
+
{
|
|
6855
|
+
type: "button",
|
|
6856
|
+
variant: "ghost",
|
|
6857
|
+
size: "icon",
|
|
6858
|
+
className: sidebarActionBtnClass,
|
|
6859
|
+
"aria-label": "Account settings",
|
|
6860
|
+
onClick: () => setOpen(true),
|
|
6861
|
+
children: /* @__PURE__ */ jsx(Settings, { className: "size-3.5", strokeWidth: 2 })
|
|
6862
|
+
}
|
|
6863
|
+
) }),
|
|
6864
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Settings" })
|
|
6865
|
+
] }),
|
|
6866
|
+
/* @__PURE__ */ jsxs(ChatDialogContent, { className: "gap-0 overflow-hidden p-0 sm:max-w-[380px]", children: [
|
|
6867
|
+
/* @__PURE__ */ jsx("div", { className: "border-b border-(--chat-border) px-5 py-4", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-left text-base font-semibold text-(--chat-text)", children: "Account settings" }) }),
|
|
6868
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-5 px-5 py-5", children: [
|
|
6869
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center", children: [
|
|
6870
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
6871
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "size-16 ring-2 ring-(--chat-theme-20)", children: [
|
|
6872
|
+
user.image ? /* @__PURE__ */ jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
|
|
6873
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-lg font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
|
|
6874
|
+
] }),
|
|
6875
|
+
/* @__PURE__ */ jsx("span", { className: "absolute bottom-0.5 right-0.5 size-3 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
|
|
6876
|
+
] }),
|
|
6877
|
+
/* @__PURE__ */ jsx("h3", { className: "mt-3 text-base font-semibold text-(--chat-text)", children: user.name }),
|
|
6878
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-sm text-(--chat-muted)", children: user.email }),
|
|
6879
|
+
/* @__PURE__ */ 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: [
|
|
6880
|
+
/* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-(--chat-online)" }),
|
|
6881
|
+
"Online"
|
|
6882
|
+
] })
|
|
6883
|
+
] }),
|
|
6884
|
+
/* @__PURE__ */ jsx("div", { className: "border-t border-(--chat-border) pt-4", children: /* @__PURE__ */ jsx(PushNotificationToggle, { className: "flex items-center justify-between gap-4 rounded-xl border border-(--chat-border) bg-(--chat-theme-10) px-4 py-3" }) })
|
|
6885
|
+
] })
|
|
6886
|
+
] })
|
|
6887
|
+
] });
|
|
6888
|
+
};
|
|
6889
|
+
var LoggedUserSettingsDialog_default = LoggedUserSettingsDialog;
|
|
6890
|
+
var LoggedUserDetails = ({
|
|
6891
|
+
loggedUserDetails,
|
|
6892
|
+
onUserSelect,
|
|
6893
|
+
isCreateModalOpen = false,
|
|
6894
|
+
setIsCreateModalOpen,
|
|
6895
|
+
searchQuery = "",
|
|
6896
|
+
setSearchQuery
|
|
6897
|
+
}) => {
|
|
6898
|
+
const { showColorModeToggle } = useChatTheme();
|
|
6899
|
+
const user = {
|
|
6900
|
+
_id: loggedUserDetails?._id || "1",
|
|
6901
|
+
name: formatLoggedUserName(loggedUserDetails?.name),
|
|
6902
|
+
email: loggedUserDetails?.email || "user@example.com",
|
|
6903
|
+
role: loggedUserDetails?.role || "user",
|
|
6904
|
+
isActive: loggedUserDetails?.isActive ?? true,
|
|
6905
|
+
createdAt: loggedUserDetails?.createdAt ? new Date(loggedUserDetails.createdAt) : /* @__PURE__ */ new Date(),
|
|
6906
|
+
updatedAt: loggedUserDetails?.updatedAt ? new Date(loggedUserDetails.updatedAt) : /* @__PURE__ */ new Date(),
|
|
6907
|
+
image: loggedUserDetails?.image || void 0
|
|
6908
|
+
};
|
|
6909
|
+
return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b border-(--chat-border) bg-(--chat-surface) px-3 pb-3 pt-3", children: [
|
|
6910
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
6911
|
+
/* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
|
|
6912
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "size-8 ring-1 ring-(--chat-surface)", children: [
|
|
6913
|
+
user.image ? /* @__PURE__ */ jsx(AvatarImage, { src: user.image, alt: user.name }) : null,
|
|
6914
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "bg-(--chat-theme-10) text-[10px] font-medium text-(--chat-theme)", children: (user.name || "?").charAt(0).toUpperCase() })
|
|
6915
|
+
] }),
|
|
6916
|
+
/* @__PURE__ */ jsx("span", { className: "absolute -bottom-0.5 -right-0.5 size-2 rounded-full border-2 border-(--chat-surface) bg-(--chat-online)" })
|
|
6917
|
+
] }),
|
|
6918
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
6919
|
+
/* @__PURE__ */ jsxs("h2", { className: "truncate text-xs font-medium leading-tight text-(--chat-text)", children: [
|
|
6920
|
+
user.name,
|
|
6921
|
+
"123"
|
|
6922
|
+
] }),
|
|
6923
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-[10px] text-(--chat-muted)", children: user.email })
|
|
6924
|
+
] }),
|
|
6925
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
6926
|
+
/* @__PURE__ */ jsx(LoggedUserSettingsDialog_default, { loggedUserDetails }),
|
|
6927
|
+
showColorModeToggle ? /* @__PURE__ */ jsx(ChatThemeToggle_default, {}) : null
|
|
6928
|
+
] })
|
|
6929
|
+
] }),
|
|
6930
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center gap-1.5", children: [
|
|
6931
|
+
/* @__PURE__ */ jsxs("div", { className: chatSidebarSearchShellClass, children: [
|
|
6932
|
+
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none size-3.5 shrink-0 text-(--chat-muted)" }),
|
|
6933
|
+
/* @__PURE__ */ jsx(
|
|
6934
|
+
"input",
|
|
6935
|
+
{
|
|
6936
|
+
type: "text",
|
|
6937
|
+
inputMode: "search",
|
|
6938
|
+
enterKeyHint: "search",
|
|
6939
|
+
placeholder: "Search conversations...",
|
|
6940
|
+
value: searchQuery,
|
|
6941
|
+
onChange: (e) => setSearchQuery?.(e.target.value),
|
|
6942
|
+
className: chatSidebarSearchInputClass
|
|
6943
|
+
}
|
|
6944
|
+
),
|
|
6945
|
+
searchQuery ? /* @__PURE__ */ jsx(
|
|
6946
|
+
"button",
|
|
6947
|
+
{
|
|
6948
|
+
type: "button",
|
|
6949
|
+
onClick: () => setSearchQuery?.(""),
|
|
6950
|
+
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)",
|
|
6951
|
+
"aria-label": "Clear search",
|
|
6952
|
+
children: /* @__PURE__ */ jsx(X, { size: 12 })
|
|
6953
|
+
}
|
|
6954
|
+
) : null
|
|
6955
|
+
] }),
|
|
6956
|
+
/* @__PURE__ */ jsx(
|
|
6957
|
+
CreateChatDialog_default,
|
|
6958
|
+
{
|
|
6959
|
+
loggedUserDetails,
|
|
6960
|
+
onUserSelect,
|
|
6961
|
+
isCreateModalOpen,
|
|
6962
|
+
setIsCreateModalOpen
|
|
6963
|
+
}
|
|
6964
|
+
)
|
|
6965
|
+
] })
|
|
6966
|
+
] });
|
|
6967
|
+
};
|
|
6968
|
+
var LoggedUserDetails_default = LoggedUserDetails;
|
|
6969
|
+
function ScrollArea({
|
|
6970
|
+
className,
|
|
6971
|
+
children,
|
|
6972
|
+
...props
|
|
6973
|
+
}) {
|
|
6974
|
+
return /* @__PURE__ */ jsxs(
|
|
6975
|
+
ScrollArea$1.Root,
|
|
6976
|
+
{
|
|
6977
|
+
"data-slot": "scroll-area",
|
|
6978
|
+
className: cn("relative", className),
|
|
6979
|
+
...props,
|
|
6980
|
+
children: [
|
|
6981
|
+
/* @__PURE__ */ jsx(
|
|
6982
|
+
ScrollArea$1.Viewport,
|
|
6983
|
+
{
|
|
6984
|
+
"data-slot": "scroll-area-viewport",
|
|
6985
|
+
className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
|
|
6986
|
+
children
|
|
6987
|
+
}
|
|
6988
|
+
),
|
|
6989
|
+
/* @__PURE__ */ jsx(ScrollBar, {}),
|
|
6990
|
+
/* @__PURE__ */ jsx(ScrollArea$1.Corner, {})
|
|
6991
|
+
]
|
|
6992
|
+
}
|
|
6993
|
+
);
|
|
6994
|
+
}
|
|
6995
|
+
function ScrollBar({
|
|
6996
|
+
className,
|
|
6997
|
+
orientation = "vertical",
|
|
6998
|
+
...props
|
|
6999
|
+
}) {
|
|
7000
|
+
return /* @__PURE__ */ jsx(
|
|
7001
|
+
ScrollArea$1.ScrollAreaScrollbar,
|
|
7002
|
+
{
|
|
7003
|
+
"data-slot": "scroll-area-scrollbar",
|
|
7004
|
+
orientation,
|
|
7005
|
+
className: cn(
|
|
7006
|
+
"flex touch-none p-px transition-colors select-none",
|
|
7007
|
+
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
7008
|
+
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
|
|
7009
|
+
className
|
|
7010
|
+
),
|
|
7011
|
+
...props,
|
|
7012
|
+
children: /* @__PURE__ */ jsx(
|
|
7013
|
+
ScrollArea$1.ScrollAreaThumb,
|
|
7014
|
+
{
|
|
7015
|
+
"data-slot": "scroll-area-thumb",
|
|
7016
|
+
className: "bg-border relative flex-1 rounded-full"
|
|
7017
|
+
}
|
|
7018
|
+
)
|
|
7019
|
+
}
|
|
7020
|
+
);
|
|
7021
|
+
}
|
|
7022
|
+
|
|
7023
|
+
// src/chat/channel-list/useChannelList.ts
|
|
7024
|
+
init_useStore();
|
|
7025
|
+
init_store_helpers();
|
|
7026
|
+
var conversationDrafts = /* @__PURE__ */ new Map();
|
|
7027
|
+
var DRAFT_PREVIEW_MAX_LENGTH = 50;
|
|
7028
|
+
var emptyDraft = () => ({
|
|
7029
|
+
messageInput: "",
|
|
7030
|
+
attachments: []
|
|
7031
|
+
});
|
|
7032
|
+
var draftRevision = 0;
|
|
7033
|
+
var draftListeners = /* @__PURE__ */ new Set();
|
|
7034
|
+
function notifyDraftChange() {
|
|
7035
|
+
draftRevision += 1;
|
|
7036
|
+
draftListeners.forEach((listener) => listener());
|
|
7037
|
+
}
|
|
7038
|
+
function subscribeToDrafts(listener) {
|
|
7039
|
+
draftListeners.add(listener);
|
|
7040
|
+
return () => {
|
|
7041
|
+
draftListeners.delete(listener);
|
|
7042
|
+
};
|
|
7043
|
+
}
|
|
7044
|
+
function getDraftRevision() {
|
|
7045
|
+
return draftRevision;
|
|
7046
|
+
}
|
|
7047
|
+
function useDraftRevision() {
|
|
7048
|
+
return useSyncExternalStore(subscribeToDrafts, getDraftRevision, getDraftRevision);
|
|
7049
|
+
}
|
|
7050
|
+
function getConversationDraft(conversationId) {
|
|
7051
|
+
if (!conversationId) return emptyDraft();
|
|
7052
|
+
return conversationDrafts.get(conversationId) ?? emptyDraft();
|
|
7053
|
+
}
|
|
7054
|
+
function updateConversationDraft(conversationId, draft) {
|
|
7055
|
+
if (!conversationId) return;
|
|
7056
|
+
if (draft.messageInput.trim() || draft.attachments.length > 0) {
|
|
7057
|
+
conversationDrafts.set(conversationId, {
|
|
7058
|
+
messageInput: draft.messageInput,
|
|
7059
|
+
attachments: draft.attachments
|
|
7060
|
+
});
|
|
7061
|
+
} else {
|
|
7062
|
+
conversationDrafts.delete(conversationId);
|
|
7063
|
+
}
|
|
7064
|
+
notifyDraftChange();
|
|
7065
|
+
}
|
|
7066
|
+
function clearConversationDraft(conversationId) {
|
|
7067
|
+
if (!conversationId) return;
|
|
7068
|
+
if (!conversationDrafts.has(conversationId)) return;
|
|
7069
|
+
conversationDrafts.delete(conversationId);
|
|
7070
|
+
notifyDraftChange();
|
|
7071
|
+
}
|
|
7072
|
+
function getConversationDraftPreview(conversationId) {
|
|
7073
|
+
if (!conversationId) return null;
|
|
6542
7074
|
const draft = conversationDrafts.get(conversationId);
|
|
6543
7075
|
if (!draft) return null;
|
|
6544
7076
|
const text = draft.messageInput.trim();
|
|
@@ -12103,52 +12635,23 @@ var ChannelDetailsDrawer = (props) => {
|
|
|
12103
12635
|
participantCount > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 pb-1", children: participants.map((p, index) => {
|
|
12104
12636
|
const pId = typeof p === "string" ? p : p._id;
|
|
12105
12637
|
const pName = typeof p === "string" ? "Unknown" : p.name;
|
|
12106
|
-
if (!pId) return null;
|
|
12107
|
-
return /* @__PURE__ */ jsx(
|
|
12108
|
-
"span",
|
|
12109
|
-
{
|
|
12110
|
-
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)",
|
|
12111
|
-
children: pName
|
|
12112
|
-
},
|
|
12113
|
-
`${pId}-${index}`
|
|
12114
|
-
);
|
|
12115
|
-
}) })
|
|
12116
|
-
] })
|
|
12117
|
-
] })
|
|
12118
|
-
] })
|
|
12119
|
-
] })
|
|
12120
|
-
] }) });
|
|
12121
|
-
};
|
|
12122
|
-
var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
|
|
12123
|
-
function Switch({
|
|
12124
|
-
className,
|
|
12125
|
-
size = "default",
|
|
12126
|
-
...props
|
|
12127
|
-
}) {
|
|
12128
|
-
return /* @__PURE__ */ jsx(
|
|
12129
|
-
Switch$1.Root,
|
|
12130
|
-
{
|
|
12131
|
-
"data-slot": "switch",
|
|
12132
|
-
"data-size": size,
|
|
12133
|
-
className: cn(
|
|
12134
|
-
"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",
|
|
12135
|
-
className
|
|
12136
|
-
),
|
|
12137
|
-
...props,
|
|
12138
|
-
children: /* @__PURE__ */ jsx(
|
|
12139
|
-
Switch$1.Thumb,
|
|
12140
|
-
{
|
|
12141
|
-
"data-slot": "switch-thumb",
|
|
12142
|
-
className: cn(
|
|
12143
|
-
"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"
|
|
12144
|
-
)
|
|
12145
|
-
}
|
|
12146
|
-
)
|
|
12147
|
-
}
|
|
12148
|
-
);
|
|
12149
|
-
}
|
|
12150
|
-
|
|
12151
|
-
// src/chat/header/PermissionDrawer.tsx
|
|
12638
|
+
if (!pId) return null;
|
|
12639
|
+
return /* @__PURE__ */ jsx(
|
|
12640
|
+
"span",
|
|
12641
|
+
{
|
|
12642
|
+
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)",
|
|
12643
|
+
children: pName
|
|
12644
|
+
},
|
|
12645
|
+
`${pId}-${index}`
|
|
12646
|
+
);
|
|
12647
|
+
}) })
|
|
12648
|
+
] })
|
|
12649
|
+
] })
|
|
12650
|
+
] })
|
|
12651
|
+
] })
|
|
12652
|
+
] }) });
|
|
12653
|
+
};
|
|
12654
|
+
var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
|
|
12152
12655
|
init_useStore();
|
|
12153
12656
|
var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo }) => {
|
|
12154
12657
|
const updateGroupPermissions = useStore((s) => s.updateGroupPermissions);
|
|
@@ -17545,246 +18048,10 @@ function ChatViewport({
|
|
|
17545
18048
|
children
|
|
17546
18049
|
}
|
|
17547
18050
|
);
|
|
17548
|
-
}
|
|
17549
|
-
var ChatViewport_default = ChatViewport;
|
|
17550
|
-
|
|
17551
|
-
|
|
17552
|
-
icon,
|
|
17553
|
-
duration
|
|
17554
|
-
};
|
|
17555
|
-
switch (type) {
|
|
17556
|
-
case "success":
|
|
17557
|
-
toast.success(message, options);
|
|
17558
|
-
break;
|
|
17559
|
-
case "error":
|
|
17560
|
-
toast.error(message, options);
|
|
17561
|
-
break;
|
|
17562
|
-
case "info":
|
|
17563
|
-
toast(message, options);
|
|
17564
|
-
break;
|
|
17565
|
-
case "warning":
|
|
17566
|
-
toast(message, { ...options, icon: "\u26A0\uFE0F" });
|
|
17567
|
-
break;
|
|
17568
|
-
default:
|
|
17569
|
-
toast(message, options);
|
|
17570
|
-
}
|
|
17571
|
-
};
|
|
17572
|
-
var downloadFile = async (src, name) => {
|
|
17573
|
-
try {
|
|
17574
|
-
const link = document.createElement("a");
|
|
17575
|
-
link.href = src;
|
|
17576
|
-
link.setAttribute("download", name);
|
|
17577
|
-
link.setAttribute("rel", "noopener noreferrer");
|
|
17578
|
-
link.click();
|
|
17579
|
-
showNotification("File Downloaded Successfully", "success");
|
|
17580
|
-
} catch (err) {
|
|
17581
|
-
console.error("File download failed:", err);
|
|
17582
|
-
showNotification("Failed to download file", "error");
|
|
17583
|
-
}
|
|
17584
|
-
};
|
|
17585
|
-
var getResponsiveWidth = (width) => {
|
|
17586
|
-
const screenWidth = window.innerWidth;
|
|
17587
|
-
if (width) {
|
|
17588
|
-
return width;
|
|
17589
|
-
} else if (screenWidth < 640) {
|
|
17590
|
-
return 350;
|
|
17591
|
-
} else if (screenWidth >= 640 && screenWidth < 1024) {
|
|
17592
|
-
return 600;
|
|
17593
|
-
} else if (screenWidth >= 1024 && screenWidth < 1280) {
|
|
17594
|
-
return 800;
|
|
17595
|
-
} else {
|
|
17596
|
-
return 1e3;
|
|
17597
|
-
}
|
|
17598
|
-
};
|
|
17599
|
-
var isEmpty = (value) => {
|
|
17600
|
-
if (value === null || value === void 0) return true;
|
|
17601
|
-
if (typeof value === "string") return value.trim().length === 0;
|
|
17602
|
-
if (Array.isArray(value)) {
|
|
17603
|
-
return value.length === 0 || value.every((item) => isEmpty(item));
|
|
17604
|
-
}
|
|
17605
|
-
if (typeof value === "object") {
|
|
17606
|
-
return Object.keys(value).length === 0;
|
|
17607
|
-
}
|
|
17608
|
-
return false;
|
|
17609
|
-
};
|
|
17610
|
-
function uniqueList(list, key) {
|
|
17611
|
-
const seen = /* @__PURE__ */ new Set();
|
|
17612
|
-
return list.filter((item) => {
|
|
17613
|
-
const value = item[key];
|
|
17614
|
-
if (seen.has(value)) return false;
|
|
17615
|
-
seen.add(value);
|
|
17616
|
-
return true;
|
|
17617
|
-
});
|
|
17618
|
-
}
|
|
17619
|
-
var capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
17620
|
-
var getFirstAndLastNameOneCharacter = (name) => {
|
|
17621
|
-
const names = name.split(" ");
|
|
17622
|
-
return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
|
|
17623
|
-
};
|
|
17624
|
-
|
|
17625
|
-
// src/notifications/ForegroundPushBridge.tsx
|
|
17626
|
-
init_normalize_helpers();
|
|
17627
|
-
init_useStore();
|
|
17628
|
-
|
|
17629
|
-
// src/notifications/push.service.ts
|
|
17630
|
-
init_client();
|
|
17631
|
-
var PUSH_TOKEN_STORAGE_KEY = "realtimex-push-token";
|
|
17632
|
-
var SERVICE_WORKER_PATH = "/firebase-messaging-sw.js";
|
|
17633
|
-
var PUSH_CHANGED_EVENT = "realtimex:push-changed";
|
|
17634
|
-
var emitPushChanged = (enabled) => {
|
|
17635
|
-
try {
|
|
17636
|
-
window.dispatchEvent(
|
|
17637
|
-
new CustomEvent(PUSH_CHANGED_EVENT, { detail: { enabled } })
|
|
17638
|
-
);
|
|
17639
|
-
} catch {
|
|
17640
|
-
}
|
|
17641
|
-
};
|
|
17642
|
-
var v2Url = "https://realtimex.softwareco.com/api/v2";
|
|
17643
|
-
var apiGetPushConfig = async () => {
|
|
17644
|
-
const { data } = await apiClient.get(`${v2Url}/notifications/push/config`);
|
|
17645
|
-
return data?.data;
|
|
17646
|
-
};
|
|
17647
|
-
var apiRegisterPushToken = async (token, deviceLabel) => {
|
|
17648
|
-
const { data } = await apiClient.post(`${v2Url}/notifications/push/token`, {
|
|
17649
|
-
token,
|
|
17650
|
-
deviceLabel
|
|
17651
|
-
});
|
|
17652
|
-
return data?.data;
|
|
17653
|
-
};
|
|
17654
|
-
var apiRemovePushToken = async (token) => {
|
|
17655
|
-
const { data } = await apiClient.delete(`${v2Url}/notifications/push/token`, {
|
|
17656
|
-
data: { token }
|
|
17657
|
-
});
|
|
17658
|
-
return data;
|
|
17659
|
-
};
|
|
17660
|
-
var apiGetPushPreference = async () => {
|
|
17661
|
-
const { data } = await apiClient.get(
|
|
17662
|
-
`${v2Url}/notifications/push/preference`
|
|
17663
|
-
);
|
|
17664
|
-
return data?.data;
|
|
17665
|
-
};
|
|
17666
|
-
var apiUpdatePushPreference = async (enabled) => {
|
|
17667
|
-
const { data } = await apiClient.patch(
|
|
17668
|
-
`${v2Url}/notifications/push/preference`,
|
|
17669
|
-
{ enabled }
|
|
17670
|
-
);
|
|
17671
|
-
return data?.data;
|
|
17672
|
-
};
|
|
17673
|
-
var isPushSupported = () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator && "PushManager" in window;
|
|
17674
|
-
var getStoredPushToken = () => {
|
|
17675
|
-
try {
|
|
17676
|
-
return localStorage.getItem(PUSH_TOKEN_STORAGE_KEY);
|
|
17677
|
-
} catch {
|
|
17678
|
-
return null;
|
|
17679
|
-
}
|
|
17680
|
-
};
|
|
17681
|
-
var storePushToken = (token) => {
|
|
17682
|
-
try {
|
|
17683
|
-
if (token) localStorage.setItem(PUSH_TOKEN_STORAGE_KEY, token);
|
|
17684
|
-
else localStorage.removeItem(PUSH_TOKEN_STORAGE_KEY);
|
|
17685
|
-
} catch {
|
|
17686
|
-
}
|
|
17687
|
-
};
|
|
17688
|
-
var defaultDeviceLabel = () => {
|
|
17689
|
-
const ua = navigator.userAgent;
|
|
17690
|
-
const browser = /edg\//i.test(ua) ? "Edge" : /chrome/i.test(ua) ? "Chrome" : /safari/i.test(ua) ? "Safari" : /firefox/i.test(ua) ? "Firefox" : "Browser";
|
|
17691
|
-
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";
|
|
17692
|
-
return `${browser} on ${os}`;
|
|
17693
|
-
};
|
|
17694
|
-
var loadFirebaseMessaging = async () => {
|
|
17695
|
-
try {
|
|
17696
|
-
const [{ initializeApp, getApps }, messagingModule] = await Promise.all([
|
|
17697
|
-
import('firebase/app'),
|
|
17698
|
-
import('firebase/messaging')
|
|
17699
|
-
]);
|
|
17700
|
-
return { initializeApp, getApps, ...messagingModule };
|
|
17701
|
-
} catch {
|
|
17702
|
-
throw new Error(
|
|
17703
|
-
'Push notifications need the "firebase" package \u2014 run: npm install firebase'
|
|
17704
|
-
);
|
|
17705
|
-
}
|
|
17706
|
-
};
|
|
17707
|
-
var getFirebaseMessaging = async (firebaseConfig) => {
|
|
17708
|
-
const fb = await loadFirebaseMessaging();
|
|
17709
|
-
const app = fb.getApps().length ? fb.getApps()[0] : fb.initializeApp(firebaseConfig);
|
|
17710
|
-
return { fb, messaging: fb.getMessaging(app) };
|
|
17711
|
-
};
|
|
17712
|
-
var enablePushOnThisDevice = async () => {
|
|
17713
|
-
if (!isPushSupported()) {
|
|
17714
|
-
throw new Error("Push notifications are not supported in this browser");
|
|
17715
|
-
}
|
|
17716
|
-
const config = await apiGetPushConfig();
|
|
17717
|
-
if (!config?.enabled) {
|
|
17718
|
-
throw new Error("Push notifications are disabled for this workspace");
|
|
17719
|
-
}
|
|
17720
|
-
if (!config.configured || !config.firebaseConfig || !config.vapidKey) {
|
|
17721
|
-
throw new Error(
|
|
17722
|
-
"Push notifications are not configured on the server yet"
|
|
17723
|
-
);
|
|
17724
|
-
}
|
|
17725
|
-
const permission = await Notification.requestPermission();
|
|
17726
|
-
if (permission !== "granted") {
|
|
17727
|
-
throw new Error("Notification permission was not granted");
|
|
17728
|
-
}
|
|
17729
|
-
let registration;
|
|
17730
|
-
try {
|
|
17731
|
-
registration = await navigator.serviceWorker.register(
|
|
17732
|
-
`${SERVICE_WORKER_PATH}?config=${encodeURIComponent(
|
|
17733
|
-
JSON.stringify(config.firebaseConfig)
|
|
17734
|
-
)}`
|
|
17735
|
-
);
|
|
17736
|
-
} catch {
|
|
17737
|
-
throw new Error(
|
|
17738
|
-
`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`
|
|
17739
|
-
);
|
|
17740
|
-
}
|
|
17741
|
-
const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
|
|
17742
|
-
const token = await fb.getToken(messaging, {
|
|
17743
|
-
vapidKey: config.vapidKey,
|
|
17744
|
-
serviceWorkerRegistration: registration
|
|
17745
|
-
});
|
|
17746
|
-
if (!token) {
|
|
17747
|
-
throw new Error("Could not obtain a push token from Firebase");
|
|
17748
|
-
}
|
|
17749
|
-
await apiRegisterPushToken(token, defaultDeviceLabel());
|
|
17750
|
-
storePushToken(token);
|
|
17751
|
-
emitPushChanged(true);
|
|
17752
|
-
return token;
|
|
17753
|
-
};
|
|
17754
|
-
var disablePushOnThisDevice = async () => {
|
|
17755
|
-
const token = getStoredPushToken();
|
|
17756
|
-
if (!token) return;
|
|
17757
|
-
try {
|
|
17758
|
-
const config = await apiGetPushConfig();
|
|
17759
|
-
if (config?.firebaseConfig) {
|
|
17760
|
-
const { fb, messaging } = await getFirebaseMessaging(
|
|
17761
|
-
config.firebaseConfig
|
|
17762
|
-
);
|
|
17763
|
-
await fb.deleteToken(messaging).catch(() => void 0);
|
|
17764
|
-
}
|
|
17765
|
-
} catch {
|
|
17766
|
-
}
|
|
17767
|
-
await apiRemovePushToken(token).catch(() => void 0);
|
|
17768
|
-
storePushToken(null);
|
|
17769
|
-
emitPushChanged(false);
|
|
17770
|
-
};
|
|
17771
|
-
var onForegroundPush = async (callback) => {
|
|
17772
|
-
const config = await apiGetPushConfig();
|
|
17773
|
-
if (!config?.configured || !config.firebaseConfig) {
|
|
17774
|
-
throw new Error("Push config unavailable (not configured or API not ready)");
|
|
17775
|
-
}
|
|
17776
|
-
const { fb, messaging } = await getFirebaseMessaging(config.firebaseConfig);
|
|
17777
|
-
return fb.onMessage(messaging, (payload) => {
|
|
17778
|
-
console.log("[realtimex-push] FCM foreground payload (raw):", payload);
|
|
17779
|
-
console.log("[realtimex-push] FCM foreground data:", payload?.data);
|
|
17780
|
-
console.log("[realtimex-push] FCM foreground notification:", payload?.notification);
|
|
17781
|
-
callback({
|
|
17782
|
-
title: payload?.notification?.title,
|
|
17783
|
-
body: payload?.notification?.body,
|
|
17784
|
-
data: payload?.data
|
|
17785
|
-
});
|
|
17786
|
-
});
|
|
17787
|
-
};
|
|
18051
|
+
}
|
|
18052
|
+
var ChatViewport_default = ChatViewport;
|
|
18053
|
+
init_normalize_helpers();
|
|
18054
|
+
init_useStore();
|
|
17788
18055
|
var RETRY_DELAYS_MS = [1e3, 3e3, 8e3, 2e4];
|
|
17789
18056
|
var recentToastIds = /* @__PURE__ */ new Set();
|
|
17790
18057
|
var rememberToastId = (id) => {
|
|
@@ -17798,48 +18065,95 @@ var rememberToastId = (id) => {
|
|
|
17798
18065
|
}
|
|
17799
18066
|
return true;
|
|
17800
18067
|
};
|
|
17801
|
-
var
|
|
17802
|
-
|
|
17803
|
-
|
|
18068
|
+
var truncate = (value, max) => value.length > max ? `${value.slice(0, max - 1)}\u2026` : value;
|
|
18069
|
+
var PushMessageToast = ({
|
|
18070
|
+
t,
|
|
18071
|
+
title,
|
|
18072
|
+
body,
|
|
18073
|
+
onOpen
|
|
18074
|
+
}) => {
|
|
18075
|
+
const dismiss = () => toast$1.dismiss(t.id);
|
|
18076
|
+
const handleDismiss = (event) => {
|
|
18077
|
+
event.stopPropagation();
|
|
18078
|
+
dismiss();
|
|
18079
|
+
};
|
|
18080
|
+
const handleOpen = () => {
|
|
18081
|
+
dismiss();
|
|
18082
|
+
onOpen?.();
|
|
18083
|
+
};
|
|
18084
|
+
return /* @__PURE__ */ jsxs(
|
|
18085
|
+
"div",
|
|
18086
|
+
{
|
|
18087
|
+
role: "alert",
|
|
18088
|
+
"aria-live": "polite",
|
|
18089
|
+
onClick: onOpen ? handleOpen : void 0,
|
|
18090
|
+
onKeyDown: onOpen ? (event) => {
|
|
18091
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
18092
|
+
event.preventDefault();
|
|
18093
|
+
handleOpen();
|
|
18094
|
+
}
|
|
18095
|
+
} : void 0,
|
|
18096
|
+
tabIndex: onOpen ? 0 : void 0,
|
|
18097
|
+
className: cn(
|
|
18098
|
+
"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",
|
|
18099
|
+
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)",
|
|
18100
|
+
t.visible ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"
|
|
18101
|
+
),
|
|
18102
|
+
children: [
|
|
18103
|
+
/* @__PURE__ */ jsx(
|
|
18104
|
+
"div",
|
|
18105
|
+
{
|
|
18106
|
+
"aria-hidden": true,
|
|
18107
|
+
className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-(--chat-theme-10) text-(--chat-theme)",
|
|
18108
|
+
children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-4", strokeWidth: 2.25 })
|
|
18109
|
+
}
|
|
18110
|
+
),
|
|
18111
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
18112
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-semibold uppercase tracking-wide text-(--chat-muted)", children: "New message" }),
|
|
18113
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 truncate text-sm font-semibold leading-snug text-(--chat-text)", children: truncate(title, 40) }),
|
|
18114
|
+
body ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-relaxed text-(--chat-muted)", children: truncate(body, 72) }) : null
|
|
18115
|
+
] }),
|
|
18116
|
+
/* @__PURE__ */ jsx(
|
|
18117
|
+
"button",
|
|
18118
|
+
{
|
|
18119
|
+
type: "button",
|
|
18120
|
+
"aria-label": "Dismiss notification",
|
|
18121
|
+
onClick: handleDismiss,
|
|
18122
|
+
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)",
|
|
18123
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4", strokeWidth: 2 })
|
|
18124
|
+
}
|
|
18125
|
+
)
|
|
18126
|
+
]
|
|
18127
|
+
}
|
|
18128
|
+
);
|
|
17804
18129
|
};
|
|
17805
18130
|
var emitToast = (payload, onPush) => {
|
|
17806
18131
|
if (onPush && onPush(payload) !== false) return;
|
|
17807
|
-
const title = payload.title || payload.data?.title;
|
|
17808
|
-
const body = payload.body || payload.data?.body || payload.data?.message;
|
|
17809
|
-
const text = resolveToastText(title, body);
|
|
18132
|
+
const title = payload.title || payload.data?.title || "New message";
|
|
18133
|
+
const body = payload.body || payload.data?.body || payload.data?.message || "";
|
|
17810
18134
|
const conversationId = resolveConversationIdFromPushData(payload.data);
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
font: "inherit"
|
|
17834
|
-
},
|
|
17835
|
-
children: text
|
|
17836
|
-
}
|
|
17837
|
-
),
|
|
17838
|
-
{ duration: 5e3 }
|
|
17839
|
-
);
|
|
17840
|
-
return;
|
|
17841
|
-
}
|
|
17842
|
-
showNotification(text, "info");
|
|
18135
|
+
const messageId2 = String(
|
|
18136
|
+
payload.data?.messageId || payload.data?.message_id || payload.data?.messageID || ""
|
|
18137
|
+
);
|
|
18138
|
+
if (!title && !body) return;
|
|
18139
|
+
toast$1.custom(
|
|
18140
|
+
(t) => /* @__PURE__ */ jsx(
|
|
18141
|
+
PushMessageToast,
|
|
18142
|
+
{
|
|
18143
|
+
t,
|
|
18144
|
+
title,
|
|
18145
|
+
body: body || void 0,
|
|
18146
|
+
onOpen: conversationId ? () => requestOpenConversation(
|
|
18147
|
+
conversationId,
|
|
18148
|
+
payload.data
|
|
18149
|
+
) : void 0
|
|
18150
|
+
}
|
|
18151
|
+
),
|
|
18152
|
+
{
|
|
18153
|
+
duration: 5e3,
|
|
18154
|
+
id: messageId2 || void 0
|
|
18155
|
+
}
|
|
18156
|
+
);
|
|
17843
18157
|
};
|
|
17844
18158
|
var ForegroundPushBridge = ({ onPush }) => {
|
|
17845
18159
|
const lastDM = useStore((s) => s.lastDM);
|
|
@@ -17977,8 +18291,28 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
17977
18291
|
Toaster,
|
|
17978
18292
|
{
|
|
17979
18293
|
position: "top-right",
|
|
17980
|
-
|
|
17981
|
-
|
|
18294
|
+
gutter: 12,
|
|
18295
|
+
containerClassName: "realtimex-push-toaster",
|
|
18296
|
+
containerStyle: {
|
|
18297
|
+
zIndex: 99999,
|
|
18298
|
+
top: 16,
|
|
18299
|
+
right: 16,
|
|
18300
|
+
width: "auto",
|
|
18301
|
+
maxWidth: "none"
|
|
18302
|
+
},
|
|
18303
|
+
toastOptions: {
|
|
18304
|
+
duration: 5e3,
|
|
18305
|
+
className: "!w-auto !max-w-none",
|
|
18306
|
+
style: {
|
|
18307
|
+
padding: 0,
|
|
18308
|
+
margin: 0,
|
|
18309
|
+
background: "transparent",
|
|
18310
|
+
boxShadow: "none",
|
|
18311
|
+
border: "none",
|
|
18312
|
+
width: "auto",
|
|
18313
|
+
maxWidth: "none"
|
|
18314
|
+
}
|
|
18315
|
+
}
|
|
17982
18316
|
}
|
|
17983
18317
|
);
|
|
17984
18318
|
};
|
|
@@ -18135,6 +18469,80 @@ var getSocketConfig = (accessToken, tenantId, options) => {
|
|
|
18135
18469
|
}
|
|
18136
18470
|
};
|
|
18137
18471
|
};
|
|
18472
|
+
var showNotification = (message, type = "info", icon, duration) => {
|
|
18473
|
+
const options = {
|
|
18474
|
+
icon,
|
|
18475
|
+
duration
|
|
18476
|
+
};
|
|
18477
|
+
switch (type) {
|
|
18478
|
+
case "success":
|
|
18479
|
+
toast.success(message, options);
|
|
18480
|
+
break;
|
|
18481
|
+
case "error":
|
|
18482
|
+
toast.error(message, options);
|
|
18483
|
+
break;
|
|
18484
|
+
case "info":
|
|
18485
|
+
toast(message, options);
|
|
18486
|
+
break;
|
|
18487
|
+
case "warning":
|
|
18488
|
+
toast(message, { ...options, icon: "\u26A0\uFE0F" });
|
|
18489
|
+
break;
|
|
18490
|
+
default:
|
|
18491
|
+
toast(message, options);
|
|
18492
|
+
}
|
|
18493
|
+
};
|
|
18494
|
+
var downloadFile = async (src, name) => {
|
|
18495
|
+
try {
|
|
18496
|
+
const link = document.createElement("a");
|
|
18497
|
+
link.href = src;
|
|
18498
|
+
link.setAttribute("download", name);
|
|
18499
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
18500
|
+
link.click();
|
|
18501
|
+
showNotification("File Downloaded Successfully", "success");
|
|
18502
|
+
} catch (err) {
|
|
18503
|
+
console.error("File download failed:", err);
|
|
18504
|
+
showNotification("Failed to download file", "error");
|
|
18505
|
+
}
|
|
18506
|
+
};
|
|
18507
|
+
var getResponsiveWidth = (width) => {
|
|
18508
|
+
const screenWidth = window.innerWidth;
|
|
18509
|
+
if (width) {
|
|
18510
|
+
return width;
|
|
18511
|
+
} else if (screenWidth < 640) {
|
|
18512
|
+
return 350;
|
|
18513
|
+
} else if (screenWidth >= 640 && screenWidth < 1024) {
|
|
18514
|
+
return 600;
|
|
18515
|
+
} else if (screenWidth >= 1024 && screenWidth < 1280) {
|
|
18516
|
+
return 800;
|
|
18517
|
+
} else {
|
|
18518
|
+
return 1e3;
|
|
18519
|
+
}
|
|
18520
|
+
};
|
|
18521
|
+
var isEmpty = (value) => {
|
|
18522
|
+
if (value === null || value === void 0) return true;
|
|
18523
|
+
if (typeof value === "string") return value.trim().length === 0;
|
|
18524
|
+
if (Array.isArray(value)) {
|
|
18525
|
+
return value.length === 0 || value.every((item) => isEmpty(item));
|
|
18526
|
+
}
|
|
18527
|
+
if (typeof value === "object") {
|
|
18528
|
+
return Object.keys(value).length === 0;
|
|
18529
|
+
}
|
|
18530
|
+
return false;
|
|
18531
|
+
};
|
|
18532
|
+
function uniqueList(list, key) {
|
|
18533
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18534
|
+
return list.filter((item) => {
|
|
18535
|
+
const value = item[key];
|
|
18536
|
+
if (seen.has(value)) return false;
|
|
18537
|
+
seen.add(value);
|
|
18538
|
+
return true;
|
|
18539
|
+
});
|
|
18540
|
+
}
|
|
18541
|
+
var capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
18542
|
+
var getFirstAndLastNameOneCharacter = (name) => {
|
|
18543
|
+
const names = name.split(" ");
|
|
18544
|
+
return names.map((name2) => name2.charAt(0).toUpperCase()).join("");
|
|
18545
|
+
};
|
|
18138
18546
|
var SIZE_MAP = {
|
|
18139
18547
|
xs: "size-6",
|
|
18140
18548
|
sm: "size-8",
|
|
@@ -18308,139 +18716,10 @@ var packageDefaultComponents = {
|
|
|
18308
18716
|
ChatDateTimeSettings: ChatDateTimeSettings_default,
|
|
18309
18717
|
ChatSocketStatus: ChatSocketStatus_default
|
|
18310
18718
|
};
|
|
18311
|
-
var usePushNotifications = () => {
|
|
18312
|
-
const [state, setState] = useState({
|
|
18313
|
-
supported: false,
|
|
18314
|
-
allowedByWorkspace: false,
|
|
18315
|
-
configured: false,
|
|
18316
|
-
permission: "unsupported",
|
|
18317
|
-
userEnabled: true,
|
|
18318
|
-
deviceEnabled: false,
|
|
18319
|
-
loading: true,
|
|
18320
|
-
error: null
|
|
18321
|
-
});
|
|
18322
|
-
const refresh = useCallback(async () => {
|
|
18323
|
-
if (!isPushSupported()) {
|
|
18324
|
-
setState((prev) => ({
|
|
18325
|
-
...prev,
|
|
18326
|
-
supported: false,
|
|
18327
|
-
loading: false
|
|
18328
|
-
}));
|
|
18329
|
-
return;
|
|
18330
|
-
}
|
|
18331
|
-
try {
|
|
18332
|
-
const [config, preference] = await Promise.all([
|
|
18333
|
-
apiGetPushConfig(),
|
|
18334
|
-
apiGetPushPreference().catch(() => null)
|
|
18335
|
-
]);
|
|
18336
|
-
setState({
|
|
18337
|
-
supported: true,
|
|
18338
|
-
allowedByWorkspace: Boolean(config?.enabled),
|
|
18339
|
-
configured: Boolean(config?.configured),
|
|
18340
|
-
permission: Notification.permission,
|
|
18341
|
-
userEnabled: preference?.enabled ?? true,
|
|
18342
|
-
deviceEnabled: Notification.permission === "granted" && Boolean(getStoredPushToken()),
|
|
18343
|
-
loading: false,
|
|
18344
|
-
error: null
|
|
18345
|
-
});
|
|
18346
|
-
} catch (error) {
|
|
18347
|
-
setState((prev) => ({
|
|
18348
|
-
...prev,
|
|
18349
|
-
supported: true,
|
|
18350
|
-
loading: false,
|
|
18351
|
-
error: error instanceof Error ? error.message : "Could not load push settings"
|
|
18352
|
-
}));
|
|
18353
|
-
}
|
|
18354
|
-
}, []);
|
|
18355
|
-
useEffect(() => {
|
|
18356
|
-
void refresh();
|
|
18357
|
-
}, [refresh]);
|
|
18358
|
-
const enable = useCallback(async () => {
|
|
18359
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
18360
|
-
try {
|
|
18361
|
-
await enablePushOnThisDevice();
|
|
18362
|
-
await refresh();
|
|
18363
|
-
return true;
|
|
18364
|
-
} catch (error) {
|
|
18365
|
-
setState((prev) => ({
|
|
18366
|
-
...prev,
|
|
18367
|
-
loading: false,
|
|
18368
|
-
permission: isPushSupported() ? Notification.permission : "unsupported",
|
|
18369
|
-
error: error instanceof Error ? error.message : "Could not enable push notifications"
|
|
18370
|
-
}));
|
|
18371
|
-
return false;
|
|
18372
|
-
}
|
|
18373
|
-
}, [refresh]);
|
|
18374
|
-
const disable = useCallback(async () => {
|
|
18375
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
18376
|
-
try {
|
|
18377
|
-
await disablePushOnThisDevice();
|
|
18378
|
-
} finally {
|
|
18379
|
-
await refresh();
|
|
18380
|
-
}
|
|
18381
|
-
}, [refresh]);
|
|
18382
|
-
const setUserEnabled = useCallback(
|
|
18383
|
-
async (enabled) => {
|
|
18384
|
-
setState((prev) => ({ ...prev, userEnabled: enabled }));
|
|
18385
|
-
try {
|
|
18386
|
-
await apiUpdatePushPreference(enabled);
|
|
18387
|
-
} catch (error) {
|
|
18388
|
-
setState((prev) => ({
|
|
18389
|
-
...prev,
|
|
18390
|
-
userEnabled: !enabled,
|
|
18391
|
-
error: error instanceof Error ? error.message : "Could not update push preference"
|
|
18392
|
-
}));
|
|
18393
|
-
}
|
|
18394
|
-
},
|
|
18395
|
-
[]
|
|
18396
|
-
);
|
|
18397
|
-
return { ...state, enable, disable, setUserEnabled, refresh };
|
|
18398
|
-
};
|
|
18399
|
-
var PushNotificationToggle = ({
|
|
18400
|
-
className,
|
|
18401
|
-
label = "Push notifications",
|
|
18402
|
-
description = "Get notified about new messages on this device"
|
|
18403
|
-
}) => {
|
|
18404
|
-
const push = usePushNotifications();
|
|
18405
|
-
if (!push.supported || !push.allowedByWorkspace || !push.configured) {
|
|
18406
|
-
return null;
|
|
18407
|
-
}
|
|
18408
|
-
const isOn = push.deviceEnabled && push.userEnabled;
|
|
18409
|
-
const permissionBlocked = push.permission === "denied";
|
|
18410
|
-
const handleChange = async (checked) => {
|
|
18411
|
-
if (checked) {
|
|
18412
|
-
if (!push.userEnabled) await push.setUserEnabled(true);
|
|
18413
|
-
if (!push.deviceEnabled) await push.enable();
|
|
18414
|
-
} else {
|
|
18415
|
-
await push.disable();
|
|
18416
|
-
}
|
|
18417
|
-
};
|
|
18418
|
-
return /* @__PURE__ */ jsxs(
|
|
18419
|
-
"div",
|
|
18420
|
-
{
|
|
18421
|
-
className: className ?? "flex items-center justify-between gap-4 rounded-xl border border-border bg-background px-4 py-3",
|
|
18422
|
-
children: [
|
|
18423
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
18424
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: label }),
|
|
18425
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description })
|
|
18426
|
-
] }),
|
|
18427
|
-
/* @__PURE__ */ jsx(
|
|
18428
|
-
Switch,
|
|
18429
|
-
{
|
|
18430
|
-
checked: isOn,
|
|
18431
|
-
disabled: push.loading || permissionBlocked,
|
|
18432
|
-
onCheckedChange: (checked) => void handleChange(checked),
|
|
18433
|
-
"aria-label": `Toggle ${label}`
|
|
18434
|
-
}
|
|
18435
|
-
)
|
|
18436
|
-
]
|
|
18437
|
-
}
|
|
18438
|
-
);
|
|
18439
|
-
};
|
|
18440
18719
|
|
|
18441
18720
|
// src/index.ts
|
|
18442
18721
|
var index_default = ChatMain_default;
|
|
18443
18722
|
|
|
18444
|
-
export { CHAT_API_KEYS, CHAT_GET_API_KEYS, Calendar, CalendarDayButton, Channel, ChannelHeaderView_default as ChannelHeader, ChannelListView_default as ChannelList, ChannelListItem_default as ChannelListItem, Chat, ChatAlertsProvider, ChatAvatar_default as ChatAvatar, ChatCustomizationProvider, ChatDateJumpMenu, ChatLayout_default as ChatLayout, ChatLocaleProvider, ChatMain_default as ChatMain, ChatThemeProvider, ChatViewport, DefaultChannelListItem, DefaultChatAvatar, DefaultChatLayout_default as DefaultChatLayout, ForegroundPushBridge, ForwardModalView as ForwardModal, HeaderCallActions_default as HeaderCallActions, LoggedUserDetails_default as LoggedUserDetails, ChannelMessageBoxView_default as MessageInput, MessageItemView as MessageItem, ActiveChannelMessagesView_default as MessageList, NOTIFICATION_CLICK_SW_TYPE, OPEN_CONVERSATION_EVENT, PUSH_CHANGED_EVENT, PushNotificationToggle, apiGetPushConfig, apiGetPushPreference, apiRegisterPushToken, apiRemovePushToken, apiUpdatePushPreference, capitalizeFirst, clampJumpDate, consumePendingOpenConversation, index_default as default, defaultChatClassNames, defaultChatComponents, defaultChatFeatures, defaultChatLayoutConfig, disablePushOnThisDevice, downloadFile, enablePushOnThisDevice, getChatBaseUrl, getChatQueryParamApis, getChatQueryParams, getChatQueryParamsByApi, getChatSocketUrl, getFirstAndLastNameOneCharacter, getResponsiveWidth, getSocketConfig, getStoredPushToken, installNotificationClickBridge, isEmpty, isPushSupported, mergeChatCustomization, mergeChatLayoutConfig, onForegroundPush, packageDefaultComponents, peekPendingOpenConversation, requestOpenConversation, resolveApiUrl, resolveChatApiKey, resolveConversationIdFromPushData, resolveJumpDateBounds, resolveJumpPreset, resolveJumpStep, resolveSocketUrl, setChatAccessToken, setChatBaseURL, setChatClientId, setChatQueryParamApis, setChatQueryParams, setChatQueryParamsByApi, setChatSocketUrl, showNotification, smoothScrollToMessage, socket_service_default as socketService, startOfLocalDay, toDateInputValue, uniqueList, useChatAlerts, useChatContext, useChatController, useChatCustomization, useChatCustomizationOptional, useChatFeatures, useChatFeaturesOptional, useChatLocale, useStore as useChatStore, useChatTheme, usePushNotifications };
|
|
18723
|
+
export { CHAT_API_KEYS, CHAT_GET_API_KEYS, Calendar, CalendarDayButton, Channel, ChannelHeaderView_default as ChannelHeader, ChannelListView_default as ChannelList, ChannelListItem_default as ChannelListItem, Chat, ChatAlertsProvider, ChatAvatar_default as ChatAvatar, ChatCustomizationProvider, ChatDateJumpMenu, ChatLayout_default as ChatLayout, ChatLocaleProvider, ChatMain_default as ChatMain, ChatThemeProvider, ChatViewport, DefaultChannelListItem, DefaultChatAvatar, DefaultChatLayout_default as DefaultChatLayout, ForegroundPushBridge, ForwardModalView as ForwardModal, HeaderCallActions_default as HeaderCallActions, LoggedUserDetails_default as LoggedUserDetails, ChannelMessageBoxView_default as MessageInput, MessageItemView as MessageItem, ActiveChannelMessagesView_default as MessageList, NOTIFICATION_CLICK_SW_TYPE, OPEN_CONVERSATION_EVENT, PUSH_BROADCAST_CHANNEL, PUSH_CHANGED_EVENT, PUSH_DATA_CACHE_NAME, PushNotificationToggle, apiGetPushConfig, apiGetPushPreference, apiRegisterPushToken, apiRemovePushToken, apiUpdatePushPreference, buildChannelFromPushRequest, capitalizeFirst, clampJumpDate, consumePendingOpenConversation, consumePendingOpenFromPushCache, consumePendingOpenRequest, index_default as default, defaultChatClassNames, defaultChatComponents, defaultChatFeatures, defaultChatLayoutConfig, disablePushOnThisDevice, downloadFile, enablePushOnThisDevice, getChatBaseUrl, getChatQueryParamApis, getChatQueryParams, getChatQueryParamsByApi, getChatSocketUrl, getFirstAndLastNameOneCharacter, getResponsiveWidth, getSocketConfig, getStoredPushToken, installNotificationClickBridge, isEmpty, isPushSupported, mergeChatCustomization, mergeChatLayoutConfig, onForegroundPush, packageDefaultComponents, peekPendingOpenConversation, peekPendingOpenRequest, requestOpenConversation, resolveApiUrl, resolveChatApiKey, resolveConversationIdFromPushData, resolveJumpDateBounds, resolveJumpPreset, resolveJumpStep, resolveSocketUrl, setChatAccessToken, setChatBaseURL, setChatClientId, setChatQueryParamApis, setChatQueryParams, setChatQueryParamsByApi, setChatSocketUrl, showNotification, smoothScrollToMessage, socket_service_default as socketService, startOfLocalDay, toDateInputValue, uniqueList, useChatAlerts, useChatContext, useChatController, useChatCustomization, useChatCustomizationOptional, useChatFeatures, useChatFeaturesOptional, useChatLocale, useStore as useChatStore, useChatTheme, usePushNotifications };
|
|
18445
18724
|
//# sourceMappingURL=index.mjs.map
|
|
18446
18725
|
//# sourceMappingURL=index.mjs.map
|