@realtimexsco/live-chat 1.4.11 → 1.4.13
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/LICENSE +2 -2
- package/README.md +14 -6
- package/dist/index.cjs +1170 -453
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +142 -66
- package/dist/index.d.ts +142 -66
- package/dist/index.mjs +901 -187
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +7 -7
- package/package.json +19 -4
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ var socket_ioClient = require('socket.io-client');
|
|
|
6
6
|
var axios = require('axios');
|
|
7
7
|
var zustand = require('zustand');
|
|
8
8
|
var middleware = require('zustand/middleware');
|
|
9
|
-
var
|
|
9
|
+
var React3 = require('react');
|
|
10
10
|
var radixUi = require('radix-ui');
|
|
11
11
|
var clsx = require('clsx');
|
|
12
12
|
var tailwindMerge = require('tailwind-merge');
|
|
@@ -39,7 +39,7 @@ function _interopNamespace(e) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
42
|
-
var
|
|
42
|
+
var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
|
|
43
43
|
var EmojiPicker__default = /*#__PURE__*/_interopDefault(EmojiPicker);
|
|
44
44
|
var toast__default = /*#__PURE__*/_interopDefault(toast);
|
|
45
45
|
|
|
@@ -1082,16 +1082,27 @@ var init_connection_actions = __esm({
|
|
|
1082
1082
|
setActiveConversationId: (conversationId) => {
|
|
1083
1083
|
set((state) => {
|
|
1084
1084
|
const nextId = conversationId ?? null;
|
|
1085
|
-
|
|
1085
|
+
const prevId = state.activeConversationId ?? null;
|
|
1086
|
+
if (String(prevId ?? "") === String(nextId ?? "")) {
|
|
1086
1087
|
return state;
|
|
1087
1088
|
}
|
|
1089
|
+
const nextErrors = { ...state.conversationErrors };
|
|
1090
|
+
if (prevId) {
|
|
1091
|
+
delete nextErrors[String(prevId)];
|
|
1092
|
+
}
|
|
1088
1093
|
if (!nextId) {
|
|
1089
|
-
return {
|
|
1094
|
+
return {
|
|
1095
|
+
activeConversationId: null,
|
|
1096
|
+
globalAppError: null,
|
|
1097
|
+
conversationErrors: nextErrors
|
|
1098
|
+
};
|
|
1090
1099
|
}
|
|
1091
1100
|
const target = state.conversations.find((c) => String(c._id) === String(nextId));
|
|
1092
1101
|
const unreadAlreadyZero = !normalizeUnreadCount(target?.unreadCount, state.loggedUserDetails?._id);
|
|
1093
1102
|
return {
|
|
1094
1103
|
activeConversationId: nextId,
|
|
1104
|
+
globalAppError: null,
|
|
1105
|
+
conversationErrors: nextErrors,
|
|
1095
1106
|
conversations: unreadAlreadyZero ? state.conversations : state.conversations.map(
|
|
1096
1107
|
(c) => String(c._id) === String(nextId) ? { ...c, unreadCount: 0 } : c
|
|
1097
1108
|
)
|
|
@@ -1132,25 +1143,32 @@ var init_connection_actions = __esm({
|
|
|
1132
1143
|
type = "rate_limit";
|
|
1133
1144
|
return;
|
|
1134
1145
|
}
|
|
1146
|
+
if (conversationId) {
|
|
1147
|
+
set((state) => ({
|
|
1148
|
+
conversationErrors: {
|
|
1149
|
+
...state.conversationErrors,
|
|
1150
|
+
[conversationId]: { message, type }
|
|
1151
|
+
},
|
|
1152
|
+
globalAppError: null
|
|
1153
|
+
}));
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1135
1156
|
set({ globalAppError: { message, type } });
|
|
1136
1157
|
},
|
|
1137
1158
|
clearAppError: (conversationId) => {
|
|
1138
1159
|
set((state) => {
|
|
1139
|
-
|
|
1140
|
-
if (targetId) {
|
|
1160
|
+
if (conversationId) {
|
|
1141
1161
|
const nextErrors = { ...state.conversationErrors };
|
|
1142
1162
|
const nextComposer = { ...state.composerDisabledByConversation };
|
|
1143
|
-
delete nextErrors[
|
|
1144
|
-
delete nextComposer[
|
|
1163
|
+
delete nextErrors[conversationId];
|
|
1164
|
+
delete nextComposer[conversationId];
|
|
1145
1165
|
return {
|
|
1146
1166
|
conversationErrors: nextErrors,
|
|
1147
1167
|
composerDisabledByConversation: nextComposer
|
|
1148
1168
|
};
|
|
1149
1169
|
}
|
|
1150
1170
|
return {
|
|
1151
|
-
globalAppError: null
|
|
1152
|
-
conversationErrors: {},
|
|
1153
|
-
composerDisabledByConversation: {}
|
|
1171
|
+
globalAppError: null
|
|
1154
1172
|
};
|
|
1155
1173
|
});
|
|
1156
1174
|
},
|
|
@@ -1190,6 +1208,7 @@ function resolveChatApiKey(url) {
|
|
|
1190
1208
|
}
|
|
1191
1209
|
if (path.includes("/message/search-messages")) return "searchMessages";
|
|
1192
1210
|
if (path.includes("/message/searched-message/context")) return "searchMessagesContext";
|
|
1211
|
+
if (path.includes("/settings/effective")) return "effectiveSettings";
|
|
1193
1212
|
if (path.includes("/conversation/group/create")) return "createGroup";
|
|
1194
1213
|
if (path.includes("/conversation/group/permission/update")) return "updateGroupPermissions";
|
|
1195
1214
|
if (path.includes("/conversation/group/information/update")) return "updateGroupInfo";
|
|
@@ -1233,7 +1252,8 @@ var init_query_params = __esm({
|
|
|
1233
1252
|
"pinnedMessages",
|
|
1234
1253
|
"starredMessages",
|
|
1235
1254
|
"searchMessages",
|
|
1236
|
-
"searchMessagesContext"
|
|
1255
|
+
"searchMessagesContext",
|
|
1256
|
+
"effectiveSettings"
|
|
1237
1257
|
];
|
|
1238
1258
|
exports.CHAT_API_KEYS = [
|
|
1239
1259
|
"all",
|
|
@@ -1258,8 +1278,8 @@ var init_api_version = __esm({
|
|
|
1258
1278
|
"src/services/api/api-version.ts"() {
|
|
1259
1279
|
init_client();
|
|
1260
1280
|
DEFAULT_VERSIONS = {
|
|
1261
|
-
|
|
1262
|
-
|
|
1281
|
+
v1: "v1",
|
|
1282
|
+
v2: "v2"
|
|
1263
1283
|
};
|
|
1264
1284
|
apiVersions = { ...DEFAULT_VERSIONS };
|
|
1265
1285
|
normalizeApiVersion = (version) => {
|
|
@@ -1278,7 +1298,7 @@ var init_api_version = __esm({
|
|
|
1278
1298
|
exports.buildVersionedApiUrl = (path, options) => {
|
|
1279
1299
|
const root = exports.resolveApiRoot(options?.baseUrl);
|
|
1280
1300
|
const version = normalizeApiVersion(
|
|
1281
|
-
options?.version ?? (options?.service ? apiVersions[options.service] : apiVersions.
|
|
1301
|
+
options?.version ?? (options?.service ? apiVersions[options.service] : apiVersions.v1)
|
|
1282
1302
|
);
|
|
1283
1303
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1284
1304
|
if (!root) {
|
|
@@ -1288,23 +1308,23 @@ var init_api_version = __esm({
|
|
|
1288
1308
|
};
|
|
1289
1309
|
exports.setChatApiVersions = (config) => {
|
|
1290
1310
|
if (!config) return;
|
|
1291
|
-
if (config.
|
|
1292
|
-
apiVersions.
|
|
1311
|
+
if (config.v1) {
|
|
1312
|
+
apiVersions.v1 = normalizeApiVersion(config.v1);
|
|
1293
1313
|
}
|
|
1294
|
-
if (config.
|
|
1295
|
-
apiVersions.
|
|
1314
|
+
if (config.v2) {
|
|
1315
|
+
apiVersions.v2 = normalizeApiVersion(config.v2);
|
|
1296
1316
|
}
|
|
1297
1317
|
};
|
|
1298
1318
|
exports.getChatApiVersions = () => ({
|
|
1299
1319
|
...apiVersions
|
|
1300
1320
|
});
|
|
1301
1321
|
exports.setChatPushApiVersion = (version) => {
|
|
1302
|
-
apiVersions.
|
|
1322
|
+
apiVersions.v2 = normalizeApiVersion(version);
|
|
1303
1323
|
};
|
|
1304
1324
|
syncDefaultApiVersionFromBaseUrl = (baseUrl) => {
|
|
1305
1325
|
const match = String(baseUrl || "").trim().match(/\/(v\d+)\/?$/i);
|
|
1306
1326
|
if (match?.[1]) {
|
|
1307
|
-
apiVersions.
|
|
1327
|
+
apiVersions.v1 = normalizeApiVersion(match[1]);
|
|
1308
1328
|
}
|
|
1309
1329
|
};
|
|
1310
1330
|
}
|
|
@@ -1449,6 +1469,9 @@ var init_api_constants = __esm({
|
|
|
1449
1469
|
SEARCH_MESSAGES: "/message/search-messages",
|
|
1450
1470
|
SEARCH_MESSAGES_CONTEXT: (messageId2) => `/message/searched-message/context?messageId=${messageId2}`,
|
|
1451
1471
|
BLOCK_UNBLOCK_USER: "/user/block-unblock"
|
|
1472
|
+
},
|
|
1473
|
+
SETTINGS: {
|
|
1474
|
+
PERMISSIONS: "/settings/effective"
|
|
1452
1475
|
}
|
|
1453
1476
|
};
|
|
1454
1477
|
}
|
|
@@ -1485,13 +1508,11 @@ var init_auth_api = __esm({
|
|
|
1485
1508
|
});
|
|
1486
1509
|
|
|
1487
1510
|
// src/constants/chat.constants.ts
|
|
1488
|
-
var DEFAULT_MESSAGES_LIMIT, DEFAULT_CONVERSATIONS_LIMIT,
|
|
1511
|
+
var DEFAULT_MESSAGES_LIMIT, DEFAULT_CONVERSATIONS_LIMIT, MAX_ATTACHMENT_CAPTION_LENGTH, ATTACHMENT_FILENAME_TIMESTAMP_LENGTH;
|
|
1489
1512
|
var init_chat_constants = __esm({
|
|
1490
1513
|
"src/constants/chat.constants.ts"() {
|
|
1491
1514
|
DEFAULT_MESSAGES_LIMIT = 20;
|
|
1492
1515
|
DEFAULT_CONVERSATIONS_LIMIT = 20;
|
|
1493
|
-
DM_EDIT_WINDOW_MS = 5 * 60 * 1e3;
|
|
1494
|
-
GROUP_EDIT_WINDOW_MS = 10 * 60 * 1e3;
|
|
1495
1516
|
MAX_ATTACHMENT_CAPTION_LENGTH = 100;
|
|
1496
1517
|
ATTACHMENT_FILENAME_TIMESTAMP_LENGTH = 13;
|
|
1497
1518
|
}
|
|
@@ -1694,6 +1715,212 @@ var init_uploads_api = __esm({
|
|
|
1694
1715
|
}
|
|
1695
1716
|
});
|
|
1696
1717
|
|
|
1718
|
+
// src/types/settings.types.ts
|
|
1719
|
+
exports.DEFAULT_EFFECTIVE_SETTINGS = void 0; exports.ADMIN_PERMISSION_DENIED_MESSAGE = void 0; exports.CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE = void 0; exports.CALLS_NOT_CONFIGURED_MESSAGE = void 0;
|
|
1720
|
+
var init_settings_types = __esm({
|
|
1721
|
+
"src/types/settings.types.ts"() {
|
|
1722
|
+
exports.DEFAULT_EFFECTIVE_SETTINGS = {
|
|
1723
|
+
pushNotificationEnabled: true,
|
|
1724
|
+
videoCallEnabled: true,
|
|
1725
|
+
audioCallEnabled: true,
|
|
1726
|
+
blockUsersEnabled: true,
|
|
1727
|
+
calls: {
|
|
1728
|
+
allowedByPlatform: true,
|
|
1729
|
+
enabled: true,
|
|
1730
|
+
configured: true
|
|
1731
|
+
},
|
|
1732
|
+
groupPolicy: {
|
|
1733
|
+
defaults: {
|
|
1734
|
+
onlyAdminCanSendMessage: false,
|
|
1735
|
+
onlyAdminCanEditInfo: false,
|
|
1736
|
+
senderCanEditMessage: true,
|
|
1737
|
+
allowMemberAdd: true,
|
|
1738
|
+
allowMemberRemove: false,
|
|
1739
|
+
moderationEnabled: false
|
|
1740
|
+
},
|
|
1741
|
+
locked: []
|
|
1742
|
+
},
|
|
1743
|
+
messageTimers: {
|
|
1744
|
+
dmEditMinutes: 5,
|
|
1745
|
+
dmDeleteMinutes: 5,
|
|
1746
|
+
groupEditMinutes: 10,
|
|
1747
|
+
groupDeleteMinutes: 10
|
|
1748
|
+
},
|
|
1749
|
+
attachments: {
|
|
1750
|
+
enabled: true,
|
|
1751
|
+
maxFileSizeMB: 10,
|
|
1752
|
+
allowedMimeTypes: ["image/*", "video/*", "audio/*", "application/pdf"],
|
|
1753
|
+
maxAttachmentsPerMessage: 10
|
|
1754
|
+
},
|
|
1755
|
+
maxAdminsPerGroup: 5,
|
|
1756
|
+
maxParticipantsPerGroup: 100,
|
|
1757
|
+
maxPinnedMessagesPerConversation: 10,
|
|
1758
|
+
groupCreationEnabled: true
|
|
1759
|
+
};
|
|
1760
|
+
exports.ADMIN_PERMISSION_DENIED_MESSAGE = "This feature is disabled by your administrator.";
|
|
1761
|
+
exports.CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE = "Calls are not allowed on this platform. Please contact your administrator.";
|
|
1762
|
+
exports.CALLS_NOT_CONFIGURED_MESSAGE = "Calls are not configured. Please contact your administrator.";
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1765
|
+
|
|
1766
|
+
// src/services/api/settings.api.ts
|
|
1767
|
+
function asBoolean(value, fallback) {
|
|
1768
|
+
return typeof value === "boolean" ? value : fallback;
|
|
1769
|
+
}
|
|
1770
|
+
function asPositiveNumber(value, fallback) {
|
|
1771
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
1772
|
+
}
|
|
1773
|
+
function asStringArray(value, fallback) {
|
|
1774
|
+
if (!Array.isArray(value)) return fallback;
|
|
1775
|
+
const next = value.filter((item) => typeof item === "string");
|
|
1776
|
+
return next.length > 0 ? next : fallback;
|
|
1777
|
+
}
|
|
1778
|
+
function normalizeGroupPermissions(value, fallback) {
|
|
1779
|
+
if (!value || typeof value !== "object") return { ...fallback };
|
|
1780
|
+
const raw = value;
|
|
1781
|
+
return {
|
|
1782
|
+
onlyAdminCanSendMessage: asBoolean(
|
|
1783
|
+
raw.onlyAdminCanSendMessage,
|
|
1784
|
+
fallback.onlyAdminCanSendMessage
|
|
1785
|
+
),
|
|
1786
|
+
onlyAdminCanEditInfo: asBoolean(
|
|
1787
|
+
raw.onlyAdminCanEditInfo,
|
|
1788
|
+
fallback.onlyAdminCanEditInfo
|
|
1789
|
+
),
|
|
1790
|
+
senderCanEditMessage: asBoolean(
|
|
1791
|
+
raw.senderCanEditMessage,
|
|
1792
|
+
fallback.senderCanEditMessage
|
|
1793
|
+
),
|
|
1794
|
+
allowMemberAdd: asBoolean(raw.allowMemberAdd, fallback.allowMemberAdd),
|
|
1795
|
+
allowMemberRemove: asBoolean(
|
|
1796
|
+
raw.allowMemberRemove,
|
|
1797
|
+
fallback.allowMemberRemove
|
|
1798
|
+
),
|
|
1799
|
+
moderationEnabled: asBoolean(
|
|
1800
|
+
raw.moderationEnabled,
|
|
1801
|
+
fallback.moderationEnabled
|
|
1802
|
+
)
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
function normalizeCalls(value, fallback) {
|
|
1806
|
+
if (!value || typeof value !== "object") return { ...fallback };
|
|
1807
|
+
const raw = value;
|
|
1808
|
+
return {
|
|
1809
|
+
allowedByPlatform: asBoolean(
|
|
1810
|
+
raw.allowedByPlatform,
|
|
1811
|
+
fallback.allowedByPlatform
|
|
1812
|
+
),
|
|
1813
|
+
enabled: asBoolean(raw.enabled, fallback.enabled),
|
|
1814
|
+
configured: asBoolean(raw.configured, fallback.configured)
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
function normalizeGroupPolicy(value, fallback) {
|
|
1818
|
+
if (!value || typeof value !== "object") {
|
|
1819
|
+
return {
|
|
1820
|
+
defaults: { ...fallback.defaults },
|
|
1821
|
+
locked: [...fallback.locked]
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
const raw = value;
|
|
1825
|
+
return {
|
|
1826
|
+
defaults: normalizeGroupPermissions(raw.defaults, fallback.defaults),
|
|
1827
|
+
locked: asStringArray(raw.locked, fallback.locked)
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
function normalizeMessageTimers(value, fallback) {
|
|
1831
|
+
if (!value || typeof value !== "object") return { ...fallback };
|
|
1832
|
+
const raw = value;
|
|
1833
|
+
return {
|
|
1834
|
+
dmEditMinutes: asPositiveNumber(raw.dmEditMinutes, fallback.dmEditMinutes),
|
|
1835
|
+
dmDeleteMinutes: asPositiveNumber(
|
|
1836
|
+
raw.dmDeleteMinutes,
|
|
1837
|
+
fallback.dmDeleteMinutes
|
|
1838
|
+
),
|
|
1839
|
+
groupEditMinutes: asPositiveNumber(
|
|
1840
|
+
raw.groupEditMinutes,
|
|
1841
|
+
fallback.groupEditMinutes
|
|
1842
|
+
),
|
|
1843
|
+
groupDeleteMinutes: asPositiveNumber(
|
|
1844
|
+
raw.groupDeleteMinutes,
|
|
1845
|
+
fallback.groupDeleteMinutes
|
|
1846
|
+
)
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
function normalizeAttachments(value, fallback) {
|
|
1850
|
+
if (!value || typeof value !== "object") return { ...fallback };
|
|
1851
|
+
const raw = value;
|
|
1852
|
+
return {
|
|
1853
|
+
enabled: asBoolean(raw.enabled, fallback.enabled),
|
|
1854
|
+
maxFileSizeMB: asPositiveNumber(raw.maxFileSizeMB, fallback.maxFileSizeMB),
|
|
1855
|
+
allowedMimeTypes: asStringArray(
|
|
1856
|
+
raw.allowedMimeTypes,
|
|
1857
|
+
fallback.allowedMimeTypes
|
|
1858
|
+
),
|
|
1859
|
+
maxAttachmentsPerMessage: asPositiveNumber(
|
|
1860
|
+
raw.maxAttachmentsPerMessage,
|
|
1861
|
+
fallback.maxAttachmentsPerMessage
|
|
1862
|
+
)
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
function normalizeEffectiveSettings(raw) {
|
|
1866
|
+
const payload = raw && typeof raw === "object" ? raw.data ?? raw : null;
|
|
1867
|
+
const source = payload && typeof payload === "object" ? payload : {};
|
|
1868
|
+
const defaults = exports.DEFAULT_EFFECTIVE_SETTINGS;
|
|
1869
|
+
return {
|
|
1870
|
+
pushNotificationEnabled: asBoolean(
|
|
1871
|
+
source.pushNotificationEnabled,
|
|
1872
|
+
defaults.pushNotificationEnabled
|
|
1873
|
+
),
|
|
1874
|
+
videoCallEnabled: asBoolean(
|
|
1875
|
+
source.videoCallEnabled,
|
|
1876
|
+
defaults.videoCallEnabled
|
|
1877
|
+
),
|
|
1878
|
+
audioCallEnabled: asBoolean(
|
|
1879
|
+
source.audioCallEnabled,
|
|
1880
|
+
defaults.audioCallEnabled
|
|
1881
|
+
),
|
|
1882
|
+
blockUsersEnabled: asBoolean(
|
|
1883
|
+
source.blockUsersEnabled,
|
|
1884
|
+
defaults.blockUsersEnabled
|
|
1885
|
+
),
|
|
1886
|
+
calls: normalizeCalls(source.calls, defaults.calls),
|
|
1887
|
+
groupPolicy: normalizeGroupPolicy(source.groupPolicy, defaults.groupPolicy),
|
|
1888
|
+
messageTimers: normalizeMessageTimers(
|
|
1889
|
+
source.messageTimers,
|
|
1890
|
+
defaults.messageTimers
|
|
1891
|
+
),
|
|
1892
|
+
attachments: normalizeAttachments(source.attachments, defaults.attachments),
|
|
1893
|
+
maxAdminsPerGroup: asPositiveNumber(
|
|
1894
|
+
source.maxAdminsPerGroup,
|
|
1895
|
+
defaults.maxAdminsPerGroup
|
|
1896
|
+
),
|
|
1897
|
+
maxParticipantsPerGroup: asPositiveNumber(
|
|
1898
|
+
source.maxParticipantsPerGroup,
|
|
1899
|
+
defaults.maxParticipantsPerGroup
|
|
1900
|
+
),
|
|
1901
|
+
maxPinnedMessagesPerConversation: asPositiveNumber(
|
|
1902
|
+
source.maxPinnedMessagesPerConversation,
|
|
1903
|
+
defaults.maxPinnedMessagesPerConversation
|
|
1904
|
+
),
|
|
1905
|
+
groupCreationEnabled: asBoolean(
|
|
1906
|
+
source.groupCreationEnabled,
|
|
1907
|
+
defaults.groupCreationEnabled
|
|
1908
|
+
)
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
exports.fetchEffectiveSettings = void 0;
|
|
1912
|
+
var init_settings_api = __esm({
|
|
1913
|
+
"src/services/api/settings.api.ts"() {
|
|
1914
|
+
init_api_constants();
|
|
1915
|
+
init_client();
|
|
1916
|
+
init_settings_types();
|
|
1917
|
+
exports.fetchEffectiveSettings = async () => {
|
|
1918
|
+
const response = await apiClient.get(API_ENDPOINTS.SETTINGS.PERMISSIONS);
|
|
1919
|
+
return normalizeEffectiveSettings(response.data);
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1697
1924
|
// src/services/api/index.ts
|
|
1698
1925
|
var init_api = __esm({
|
|
1699
1926
|
"src/services/api/index.ts"() {
|
|
@@ -1702,6 +1929,7 @@ var init_api = __esm({
|
|
|
1702
1929
|
init_messages_api();
|
|
1703
1930
|
init_groups_api();
|
|
1704
1931
|
init_uploads_api();
|
|
1932
|
+
init_settings_api();
|
|
1705
1933
|
}
|
|
1706
1934
|
});
|
|
1707
1935
|
|
|
@@ -4385,7 +4613,7 @@ var syncLocalMessagesOnDmMarkRead = (prev, lastDMMarkRead, conversations, logged
|
|
|
4385
4613
|
|
|
4386
4614
|
// src/hooks/chat-sync/useChatSync.ts
|
|
4387
4615
|
var useChatSync = () => {
|
|
4388
|
-
const [localMessages, setLocalMessages] =
|
|
4616
|
+
const [localMessages, setLocalMessages] = React3.useState({});
|
|
4389
4617
|
const lastDM = useSocketStore((s) => s.lastDM);
|
|
4390
4618
|
const lastEditDM = useSocketStore((s) => s.lastEditDM);
|
|
4391
4619
|
const lastDeleteDM = useSocketStore((s) => s.lastDeleteDM);
|
|
@@ -4398,17 +4626,17 @@ var useChatSync = () => {
|
|
|
4398
4626
|
const messagesByConversation = useSocketStore((s) => s.messagesByConversation);
|
|
4399
4627
|
const messagesMetadata = useSocketStore((s) => s.messagesMetadata);
|
|
4400
4628
|
const loggedUserDetails = useAuthStore((s) => s.loggedUserDetails);
|
|
4401
|
-
|
|
4629
|
+
React3.useEffect(() => {
|
|
4402
4630
|
setLocalMessages(
|
|
4403
4631
|
(prev) => syncLocalMessagesOnStoreClear(prev, messagesByConversation, messagesMetadata)
|
|
4404
4632
|
);
|
|
4405
4633
|
}, [messagesByConversation, messagesMetadata]);
|
|
4406
|
-
|
|
4634
|
+
React3.useEffect(() => {
|
|
4407
4635
|
if (lastPinUpdate) {
|
|
4408
4636
|
setLocalMessages((prev) => syncLocalMessagesOnPinUpdate(prev, lastPinUpdate));
|
|
4409
4637
|
}
|
|
4410
4638
|
}, [lastPinUpdate]);
|
|
4411
|
-
|
|
4639
|
+
React3.useEffect(() => {
|
|
4412
4640
|
if (lastStarUpdate) {
|
|
4413
4641
|
setLocalMessages((prev) => {
|
|
4414
4642
|
const next = syncLocalMessagesOnStarUpdate(
|
|
@@ -4420,18 +4648,18 @@ var useChatSync = () => {
|
|
|
4420
4648
|
});
|
|
4421
4649
|
}
|
|
4422
4650
|
}, [lastStarUpdate, loggedUserDetails?._id]);
|
|
4423
|
-
|
|
4651
|
+
React3.useEffect(() => {
|
|
4424
4652
|
if (!lastReactionUpdate) return;
|
|
4425
4653
|
setLocalMessages(
|
|
4426
4654
|
(prev) => syncLocalMessagesOnReactionUpdate(prev, lastReactionUpdate, messagesByConversation)
|
|
4427
4655
|
);
|
|
4428
4656
|
}, [lastReactionUpdate, messagesByConversation]);
|
|
4429
|
-
|
|
4657
|
+
React3.useEffect(() => {
|
|
4430
4658
|
if (lastDeleteDM) {
|
|
4431
4659
|
setLocalMessages((prev) => syncLocalMessagesOnDelete(prev, lastDeleteDM));
|
|
4432
4660
|
}
|
|
4433
4661
|
}, [lastDeleteDM]);
|
|
4434
|
-
|
|
4662
|
+
React3.useEffect(() => {
|
|
4435
4663
|
if (lastEditDM) {
|
|
4436
4664
|
setLocalMessages((prev) => {
|
|
4437
4665
|
const next = syncLocalMessagesOnEdit(prev, lastEditDM);
|
|
@@ -4439,7 +4667,7 @@ var useChatSync = () => {
|
|
|
4439
4667
|
});
|
|
4440
4668
|
}
|
|
4441
4669
|
}, [lastEditDM]);
|
|
4442
|
-
|
|
4670
|
+
React3.useEffect(() => {
|
|
4443
4671
|
if (!lastDM) return;
|
|
4444
4672
|
const result = buildIncomingMessageFromDM(
|
|
4445
4673
|
lastDM,
|
|
@@ -4451,14 +4679,14 @@ var useChatSync = () => {
|
|
|
4451
4679
|
(prev) => applyMessageUpdate(prev, result.storageKey, result.incomingMsg, result.isMe)
|
|
4452
4680
|
);
|
|
4453
4681
|
}, [lastDM, loggedUserDetails, conversations]);
|
|
4454
|
-
|
|
4682
|
+
React3.useEffect(() => {
|
|
4455
4683
|
if (lastStatusUpdate) {
|
|
4456
4684
|
setLocalMessages(
|
|
4457
4685
|
(prev) => syncLocalMessagesOnStatusUpdate(prev, lastStatusUpdate, loggedUserDetails)
|
|
4458
4686
|
);
|
|
4459
4687
|
}
|
|
4460
4688
|
}, [lastStatusUpdate, loggedUserDetails]);
|
|
4461
|
-
|
|
4689
|
+
React3.useEffect(() => {
|
|
4462
4690
|
if (lastDMMarkRead) {
|
|
4463
4691
|
setLocalMessages((prev) => {
|
|
4464
4692
|
const next = syncLocalMessagesOnDmMarkRead(
|
|
@@ -4488,16 +4716,16 @@ var mergeChatCustomization = (config) => ({
|
|
|
4488
4716
|
classNames: { ...defaultChatClassNames, ...config?.classNames ?? {} },
|
|
4489
4717
|
features: { ...defaultChatFeatures, ...config?.features ?? {} }
|
|
4490
4718
|
});
|
|
4491
|
-
var ChatCustomizationContext =
|
|
4719
|
+
var ChatCustomizationContext = React3.createContext(void 0);
|
|
4492
4720
|
var ChatCustomizationProvider = ({
|
|
4493
4721
|
children,
|
|
4494
4722
|
customization
|
|
4495
4723
|
}) => {
|
|
4496
|
-
const merged =
|
|
4724
|
+
const merged = React3.useMemo(
|
|
4497
4725
|
() => mergeChatCustomization(customization),
|
|
4498
4726
|
[customization]
|
|
4499
4727
|
);
|
|
4500
|
-
const value =
|
|
4728
|
+
const value = React3.useMemo(
|
|
4501
4729
|
() => ({
|
|
4502
4730
|
components: merged.components,
|
|
4503
4731
|
classNames: merged.classNames,
|
|
@@ -4513,7 +4741,7 @@ var ChatCustomizationProvider = ({
|
|
|
4513
4741
|
return /* @__PURE__ */ jsxRuntime.jsx(ChatCustomizationContext.Provider, { value, children });
|
|
4514
4742
|
};
|
|
4515
4743
|
var useChatCustomization = () => {
|
|
4516
|
-
const context =
|
|
4744
|
+
const context = React3.useContext(ChatCustomizationContext);
|
|
4517
4745
|
if (!context) {
|
|
4518
4746
|
throw new Error(
|
|
4519
4747
|
"useChatCustomization must be used within ChatCustomizationProvider"
|
|
@@ -4522,7 +4750,7 @@ var useChatCustomization = () => {
|
|
|
4522
4750
|
return context;
|
|
4523
4751
|
};
|
|
4524
4752
|
var useChatCustomizationOptional = () => {
|
|
4525
|
-
const context =
|
|
4753
|
+
const context = React3.useContext(ChatCustomizationContext);
|
|
4526
4754
|
return context ?? {
|
|
4527
4755
|
components: {},
|
|
4528
4756
|
classNames: {},
|
|
@@ -4533,9 +4761,153 @@ var useChatCustomizationOptional = () => {
|
|
|
4533
4761
|
};
|
|
4534
4762
|
var useChatFeatures = () => useChatCustomization().features;
|
|
4535
4763
|
var useChatFeaturesOptional = () => useChatCustomizationOptional().features;
|
|
4536
|
-
|
|
4764
|
+
|
|
4765
|
+
// src/context/ChatEffectiveSettingsContext.tsx
|
|
4766
|
+
init_settings_api();
|
|
4767
|
+
init_settings_types();
|
|
4768
|
+
var ChatEffectiveSettingsContext = React3.createContext(null);
|
|
4769
|
+
function buildCallGate(settings, featureEnabled) {
|
|
4770
|
+
if (!settings.calls.allowedByPlatform) {
|
|
4771
|
+
return {
|
|
4772
|
+
visible: true,
|
|
4773
|
+
enabled: false,
|
|
4774
|
+
disabledReason: exports.CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE
|
|
4775
|
+
};
|
|
4776
|
+
}
|
|
4777
|
+
if (!settings.calls.configured) {
|
|
4778
|
+
return {
|
|
4779
|
+
visible: true,
|
|
4780
|
+
enabled: false,
|
|
4781
|
+
disabledReason: exports.CALLS_NOT_CONFIGURED_MESSAGE
|
|
4782
|
+
};
|
|
4783
|
+
}
|
|
4784
|
+
if (!settings.calls.enabled) {
|
|
4785
|
+
return {
|
|
4786
|
+
visible: true,
|
|
4787
|
+
enabled: false,
|
|
4788
|
+
disabledReason: exports.ADMIN_PERMISSION_DENIED_MESSAGE
|
|
4789
|
+
};
|
|
4790
|
+
}
|
|
4791
|
+
if (!featureEnabled) {
|
|
4792
|
+
return {
|
|
4793
|
+
visible: true,
|
|
4794
|
+
enabled: false,
|
|
4795
|
+
disabledReason: exports.ADMIN_PERMISSION_DENIED_MESSAGE
|
|
4796
|
+
};
|
|
4797
|
+
}
|
|
4798
|
+
return { visible: true, enabled: true, disabledReason: null };
|
|
4799
|
+
}
|
|
4800
|
+
function ChatEffectiveSettingsProvider({
|
|
4801
|
+
children,
|
|
4802
|
+
enabled = true
|
|
4803
|
+
}) {
|
|
4804
|
+
const [settings, setSettings] = React3.useState(
|
|
4805
|
+
exports.DEFAULT_EFFECTIVE_SETTINGS
|
|
4806
|
+
);
|
|
4807
|
+
const [loading, setLoading] = React3.useState(true);
|
|
4808
|
+
const [error, setError] = React3.useState(null);
|
|
4809
|
+
const refresh = React3.useCallback(async () => {
|
|
4810
|
+
if (!enabled) {
|
|
4811
|
+
setLoading(false);
|
|
4812
|
+
return;
|
|
4813
|
+
}
|
|
4814
|
+
setLoading(true);
|
|
4815
|
+
try {
|
|
4816
|
+
const next = await exports.fetchEffectiveSettings();
|
|
4817
|
+
setSettings(next);
|
|
4818
|
+
setError(null);
|
|
4819
|
+
} catch (err) {
|
|
4820
|
+
console.error("Failed to fetch effective settings:", err);
|
|
4821
|
+
setError(
|
|
4822
|
+
err instanceof Error ? err.message : "Could not load chat permissions"
|
|
4823
|
+
);
|
|
4824
|
+
setSettings(exports.DEFAULT_EFFECTIVE_SETTINGS);
|
|
4825
|
+
} finally {
|
|
4826
|
+
setLoading(false);
|
|
4827
|
+
}
|
|
4828
|
+
}, [enabled]);
|
|
4829
|
+
React3.useEffect(() => {
|
|
4830
|
+
void refresh();
|
|
4831
|
+
}, [refresh]);
|
|
4832
|
+
const value = React3.useMemo(() => {
|
|
4833
|
+
const isGroupPermissionLocked = (key) => settings.groupPolicy.locked.includes(key);
|
|
4834
|
+
return {
|
|
4835
|
+
settings,
|
|
4836
|
+
loading,
|
|
4837
|
+
error,
|
|
4838
|
+
refresh,
|
|
4839
|
+
isGroupPermissionLocked,
|
|
4840
|
+
getAudioCallGate: () => buildCallGate(settings, settings.audioCallEnabled),
|
|
4841
|
+
getVideoCallGate: () => buildCallGate(settings, settings.videoCallEnabled),
|
|
4842
|
+
getPushNotificationGate: () => ({
|
|
4843
|
+
visible: true,
|
|
4844
|
+
enabled: settings.pushNotificationEnabled,
|
|
4845
|
+
disabledReason: settings.pushNotificationEnabled ? null : exports.ADMIN_PERMISSION_DENIED_MESSAGE
|
|
4846
|
+
}),
|
|
4847
|
+
getBlockUsersGate: () => ({
|
|
4848
|
+
visible: true,
|
|
4849
|
+
enabled: settings.blockUsersEnabled,
|
|
4850
|
+
disabledReason: settings.blockUsersEnabled ? null : exports.ADMIN_PERMISSION_DENIED_MESSAGE
|
|
4851
|
+
}),
|
|
4852
|
+
getAttachmentsGate: () => ({
|
|
4853
|
+
visible: true,
|
|
4854
|
+
enabled: settings.attachments.enabled,
|
|
4855
|
+
disabledReason: settings.attachments.enabled ? null : exports.ADMIN_PERMISSION_DENIED_MESSAGE
|
|
4856
|
+
}),
|
|
4857
|
+
getGroupCreationGate: () => ({
|
|
4858
|
+
visible: true,
|
|
4859
|
+
enabled: settings.groupCreationEnabled,
|
|
4860
|
+
disabledReason: settings.groupCreationEnabled ? null : exports.ADMIN_PERMISSION_DENIED_MESSAGE
|
|
4861
|
+
})
|
|
4862
|
+
};
|
|
4863
|
+
}, [settings, loading, error, refresh]);
|
|
4864
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ChatEffectiveSettingsContext.Provider, { value, children });
|
|
4865
|
+
}
|
|
4866
|
+
function useEffectiveSettings() {
|
|
4867
|
+
const ctx = React3.useContext(ChatEffectiveSettingsContext);
|
|
4868
|
+
if (!ctx) {
|
|
4869
|
+
throw new Error(
|
|
4870
|
+
"useEffectiveSettings must be used within ChatEffectiveSettingsProvider"
|
|
4871
|
+
);
|
|
4872
|
+
}
|
|
4873
|
+
return ctx;
|
|
4874
|
+
}
|
|
4875
|
+
function useEffectiveSettingsOptional() {
|
|
4876
|
+
const ctx = React3.useContext(ChatEffectiveSettingsContext);
|
|
4877
|
+
if (ctx) return ctx;
|
|
4878
|
+
return {
|
|
4879
|
+
settings: exports.DEFAULT_EFFECTIVE_SETTINGS,
|
|
4880
|
+
loading: false,
|
|
4881
|
+
error: null,
|
|
4882
|
+
refresh: async () => void 0,
|
|
4883
|
+
isGroupPermissionLocked: () => false,
|
|
4884
|
+
getAudioCallGate: () => buildCallGate(exports.DEFAULT_EFFECTIVE_SETTINGS, true),
|
|
4885
|
+
getVideoCallGate: () => buildCallGate(exports.DEFAULT_EFFECTIVE_SETTINGS, true),
|
|
4886
|
+
getPushNotificationGate: () => ({
|
|
4887
|
+
visible: true,
|
|
4888
|
+
enabled: true,
|
|
4889
|
+
disabledReason: null
|
|
4890
|
+
}),
|
|
4891
|
+
getBlockUsersGate: () => ({
|
|
4892
|
+
visible: true,
|
|
4893
|
+
enabled: true,
|
|
4894
|
+
disabledReason: null
|
|
4895
|
+
}),
|
|
4896
|
+
getAttachmentsGate: () => ({
|
|
4897
|
+
visible: true,
|
|
4898
|
+
enabled: true,
|
|
4899
|
+
disabledReason: null
|
|
4900
|
+
}),
|
|
4901
|
+
getGroupCreationGate: () => ({
|
|
4902
|
+
visible: true,
|
|
4903
|
+
enabled: true,
|
|
4904
|
+
disabledReason: null
|
|
4905
|
+
})
|
|
4906
|
+
};
|
|
4907
|
+
}
|
|
4908
|
+
var ChatContext = React3.createContext(void 0);
|
|
4537
4909
|
var useChatContext = () => {
|
|
4538
|
-
const context =
|
|
4910
|
+
const context = React3.useContext(ChatContext);
|
|
4539
4911
|
if (!context) {
|
|
4540
4912
|
throw new Error("useChatContext must be used within a Chat provider");
|
|
4541
4913
|
}
|
|
@@ -4572,7 +4944,7 @@ var Chat = ({
|
|
|
4572
4944
|
const status = exports.useChatStore((s) => s.status);
|
|
4573
4945
|
const error = exports.useChatStore((s) => s.error);
|
|
4574
4946
|
useChatSync();
|
|
4575
|
-
|
|
4947
|
+
React3__namespace.default.useEffect(() => {
|
|
4576
4948
|
const clientId = client?.id;
|
|
4577
4949
|
const initializeChat = async () => {
|
|
4578
4950
|
if (!clientId || !loggedUserDetails) return;
|
|
@@ -4662,28 +5034,28 @@ var Chat = ({
|
|
|
4662
5034
|
queryParamApis: queryParamApis ?? ["get"],
|
|
4663
5035
|
queryParamsByApi: queryParamsByApi ?? {}
|
|
4664
5036
|
});
|
|
4665
|
-
|
|
5037
|
+
React3__namespace.default.useEffect(() => {
|
|
4666
5038
|
exports.setChatQueryParams(queryParams);
|
|
4667
5039
|
exports.setChatQueryParamApis(queryParamApis);
|
|
4668
5040
|
exports.setChatQueryParamsByApi(queryParamsByApi);
|
|
4669
5041
|
}, [queryConfigKey]);
|
|
4670
|
-
|
|
5042
|
+
React3__namespace.default.useEffect(() => {
|
|
4671
5043
|
if (lastDM && onMessageReceived) {
|
|
4672
5044
|
onMessageReceived(lastDM);
|
|
4673
5045
|
}
|
|
4674
5046
|
}, [lastDM, onMessageReceived]);
|
|
4675
|
-
|
|
5047
|
+
React3__namespace.default.useEffect(() => {
|
|
4676
5048
|
if (status === "connected" && onSocketConnected) {
|
|
4677
5049
|
const socketId = exports.useChatStore.getState().socketId;
|
|
4678
5050
|
if (socketId) onSocketConnected(socketId);
|
|
4679
5051
|
}
|
|
4680
5052
|
}, [status, onSocketConnected]);
|
|
4681
|
-
|
|
5053
|
+
React3__namespace.default.useEffect(() => {
|
|
4682
5054
|
if (status === "error" && error && onSocketError) {
|
|
4683
5055
|
onSocketError(error);
|
|
4684
5056
|
}
|
|
4685
5057
|
}, [status, error, onSocketError]);
|
|
4686
|
-
const contextValue =
|
|
5058
|
+
const contextValue = React3__namespace.default.useMemo(
|
|
4687
5059
|
() => ({
|
|
4688
5060
|
onSendMessage,
|
|
4689
5061
|
client,
|
|
@@ -4703,7 +5075,7 @@ var Chat = ({
|
|
|
4703
5075
|
messagesData
|
|
4704
5076
|
]
|
|
4705
5077
|
);
|
|
4706
|
-
const customization =
|
|
5078
|
+
const customization = React3__namespace.default.useMemo(
|
|
4707
5079
|
() => ({
|
|
4708
5080
|
components: uiConfig.components,
|
|
4709
5081
|
classNames: uiConfig.classNames,
|
|
@@ -4711,7 +5083,7 @@ var Chat = ({
|
|
|
4711
5083
|
}),
|
|
4712
5084
|
[uiConfig.components, uiConfig.classNames, uiConfig.features]
|
|
4713
5085
|
);
|
|
4714
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(ChatCustomizationProvider, { customization, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-container-root flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden", children: isSessionReady ? children : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-gray-400 font-bold", children: "Initializing session..." }) }) }) }) });
|
|
5086
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(ChatCustomizationProvider, { customization, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-container-root flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden", children: isSessionReady ? /* @__PURE__ */ jsxRuntime.jsx(ChatEffectiveSettingsProvider, { enabled: true, children }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-gray-400 font-bold", children: "Initializing session..." }) }) }) }) });
|
|
4715
5087
|
};
|
|
4716
5088
|
|
|
4717
5089
|
// src/hooks/useChatController.ts
|
|
@@ -5009,7 +5381,7 @@ function toDisplayAttachments(attachments) {
|
|
|
5009
5381
|
}));
|
|
5010
5382
|
}
|
|
5011
5383
|
var useChatController = () => {
|
|
5012
|
-
const [state, setState] =
|
|
5384
|
+
const [state, setState] = React3.useState({
|
|
5013
5385
|
activeChannel: null,
|
|
5014
5386
|
activeConversationId: null,
|
|
5015
5387
|
replyToMessage: null,
|
|
@@ -5019,15 +5391,15 @@ var useChatController = () => {
|
|
|
5019
5391
|
debouncedSearch: "",
|
|
5020
5392
|
isCreateModalOpen: false
|
|
5021
5393
|
});
|
|
5022
|
-
const updateState =
|
|
5394
|
+
const updateState = React3.useCallback((updates) => {
|
|
5023
5395
|
setState((prev) => ({ ...prev, ...updates }));
|
|
5024
5396
|
}, []);
|
|
5025
|
-
const handleSelectionModeChange =
|
|
5397
|
+
const handleSelectionModeChange = React3.useCallback((active) => {
|
|
5026
5398
|
setState(
|
|
5027
5399
|
(prev) => prev.isMessageSelectionMode === active ? prev : { ...prev, isMessageSelectionMode: active }
|
|
5028
5400
|
);
|
|
5029
5401
|
}, []);
|
|
5030
|
-
const handleActiveChannelPatch =
|
|
5402
|
+
const handleActiveChannelPatch = React3.useCallback((patch) => {
|
|
5031
5403
|
setState(
|
|
5032
5404
|
(prev) => prev.activeChannel ? { ...prev, activeChannel: { ...prev.activeChannel, ...patch } } : prev
|
|
5033
5405
|
);
|
|
@@ -5051,11 +5423,11 @@ var useChatController = () => {
|
|
|
5051
5423
|
const allUsers = exports.useChatStore((s) => s.allUsers);
|
|
5052
5424
|
const isFetchingConversations = exports.useChatStore((s) => s.isFetchingConversations);
|
|
5053
5425
|
const conversations = exports.useChatStore((s) => s.conversations);
|
|
5054
|
-
const [pendingOpenRequest, setPendingOpenRequest] =
|
|
5426
|
+
const [pendingOpenRequest, setPendingOpenRequest] = React3.useState(() => peekPendingOpenRequest());
|
|
5055
5427
|
const conversationsLength = exports.useChatStore(
|
|
5056
5428
|
(s) => state.activeChannel?.conversationId ? 0 : s.conversations.length
|
|
5057
5429
|
);
|
|
5058
|
-
const lastConversationActionsRef =
|
|
5430
|
+
const lastConversationActionsRef = React3.useRef(null);
|
|
5059
5431
|
const activeChannelId = state.activeChannel?.id;
|
|
5060
5432
|
const activeChannelConvId = state.activeChannel?.conversationId;
|
|
5061
5433
|
const activeChannelIsGroup = !!state.activeChannel?.isGroup;
|
|
@@ -5080,7 +5452,7 @@ var useChatController = () => {
|
|
|
5080
5452
|
isGroupConversation(latestInfo)
|
|
5081
5453
|
].join("|");
|
|
5082
5454
|
});
|
|
5083
|
-
|
|
5455
|
+
React3.useEffect(() => {
|
|
5084
5456
|
const onOpen = (event) => {
|
|
5085
5457
|
const detail = event.detail;
|
|
5086
5458
|
if (detail?.conversationId) {
|
|
@@ -5097,7 +5469,7 @@ var useChatController = () => {
|
|
|
5097
5469
|
window.addEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
5098
5470
|
return () => window.removeEventListener(OPEN_CONVERSATION_EVENT, onOpen);
|
|
5099
5471
|
}, []);
|
|
5100
|
-
|
|
5472
|
+
React3.useEffect(() => {
|
|
5101
5473
|
if (!pendingOpenRequest?.conversationId || !loggedUserDetails) return;
|
|
5102
5474
|
let cancelled = false;
|
|
5103
5475
|
const openPending = async () => {
|
|
@@ -5163,13 +5535,13 @@ var useChatController = () => {
|
|
|
5163
5535
|
allUsers,
|
|
5164
5536
|
fetchConversationInfo2
|
|
5165
5537
|
]);
|
|
5166
|
-
|
|
5538
|
+
React3.useEffect(() => {
|
|
5167
5539
|
const handler = setTimeout(() => {
|
|
5168
5540
|
updateState({ debouncedSearch: state.searchQuery });
|
|
5169
5541
|
}, 400);
|
|
5170
5542
|
return () => clearTimeout(handler);
|
|
5171
5543
|
}, [state.searchQuery, updateState]);
|
|
5172
|
-
|
|
5544
|
+
React3.useEffect(() => {
|
|
5173
5545
|
if (!state.activeChannel || !loggedUserDetails) {
|
|
5174
5546
|
setState(
|
|
5175
5547
|
(prev) => prev.activeConversationId === null ? prev : { ...prev, activeConversationId: null }
|
|
@@ -5185,7 +5557,7 @@ var useChatController = () => {
|
|
|
5185
5557
|
(prev) => prev.activeConversationId === nextId ? prev : { ...prev, activeConversationId: nextId }
|
|
5186
5558
|
);
|
|
5187
5559
|
}, [state.activeChannel, loggedUserDetails, conversationsLength]);
|
|
5188
|
-
|
|
5560
|
+
React3.useEffect(() => {
|
|
5189
5561
|
if (!lastDM?.conversationId || !loggedUserDetails) return;
|
|
5190
5562
|
const convId = String(lastDM.conversationId);
|
|
5191
5563
|
const senderId = String(lastDM.sender?._id || lastDM.sender || "");
|
|
@@ -5218,7 +5590,7 @@ var useChatController = () => {
|
|
|
5218
5590
|
};
|
|
5219
5591
|
});
|
|
5220
5592
|
}, [lastDM, loggedUserDetails]);
|
|
5221
|
-
const resolvedLocalMessages =
|
|
5593
|
+
const resolvedLocalMessages = React3.useMemo(
|
|
5222
5594
|
() => resolveLocalMessagesForChannel(
|
|
5223
5595
|
localMessages,
|
|
5224
5596
|
state.activeConversationId,
|
|
@@ -5226,7 +5598,7 @@ var useChatController = () => {
|
|
|
5226
5598
|
),
|
|
5227
5599
|
[localMessages, state.activeConversationId, state.activeChannel?.id]
|
|
5228
5600
|
);
|
|
5229
|
-
const resolvedConversationMessages =
|
|
5601
|
+
const resolvedConversationMessages = React3.useMemo(() => {
|
|
5230
5602
|
if (state.activeConversationId) {
|
|
5231
5603
|
return messagesByConversation[state.activeConversationId] || [];
|
|
5232
5604
|
}
|
|
@@ -5234,7 +5606,7 @@ var useChatController = () => {
|
|
|
5234
5606
|
const groupConversationId = String(state.activeChannel.id);
|
|
5235
5607
|
return messagesByConversation[groupConversationId] || [];
|
|
5236
5608
|
}, [messagesByConversation, state.activeConversationId, state.activeChannel]);
|
|
5237
|
-
|
|
5609
|
+
React3.useEffect(() => {
|
|
5238
5610
|
if (!activeChannelSyncKey || !state.activeChannel) return;
|
|
5239
5611
|
const [convId, pinned, starred, isLeft, isBlocked, isGroup] = activeChannelSyncKey.split("|");
|
|
5240
5612
|
setState((prev) => {
|
|
@@ -5257,10 +5629,10 @@ var useChatController = () => {
|
|
|
5257
5629
|
};
|
|
5258
5630
|
});
|
|
5259
5631
|
}, [activeChannelSyncKey, state.activeChannel]);
|
|
5260
|
-
|
|
5632
|
+
React3.useEffect(() => {
|
|
5261
5633
|
setActiveConversationId(state.activeConversationId);
|
|
5262
5634
|
}, [state.activeConversationId, setActiveConversationId]);
|
|
5263
|
-
|
|
5635
|
+
React3.useEffect(() => {
|
|
5264
5636
|
if (!state.activeConversationId || !state.activeChannel || !loggedUserDetails) {
|
|
5265
5637
|
lastConversationActionsRef.current = null;
|
|
5266
5638
|
return;
|
|
@@ -5307,7 +5679,7 @@ var useChatController = () => {
|
|
|
5307
5679
|
emitGroupMarkRead,
|
|
5308
5680
|
emitMarkAsRead
|
|
5309
5681
|
]);
|
|
5310
|
-
|
|
5682
|
+
React3.useEffect(() => {
|
|
5311
5683
|
if (globalAppError?.type === "participant" && state.activeChannel) {
|
|
5312
5684
|
updateState({ activeChannel: null, activeConversationId: null });
|
|
5313
5685
|
}
|
|
@@ -5484,7 +5856,7 @@ function withThemeTransition(apply) {
|
|
|
5484
5856
|
}
|
|
5485
5857
|
reactDom.flushSync(apply);
|
|
5486
5858
|
}
|
|
5487
|
-
var ChatThemeContext =
|
|
5859
|
+
var ChatThemeContext = React3.createContext(null);
|
|
5488
5860
|
var ChatThemeProvider = ({
|
|
5489
5861
|
children,
|
|
5490
5862
|
themeColor,
|
|
@@ -5494,10 +5866,10 @@ var ChatThemeProvider = ({
|
|
|
5494
5866
|
showColorModeToggle = true
|
|
5495
5867
|
}) => {
|
|
5496
5868
|
const isControlled = colorMode !== void 0;
|
|
5497
|
-
const [internalMode, setInternalMode] =
|
|
5498
|
-
const [isThemeTransitionReady, setIsThemeTransitionReady] =
|
|
5499
|
-
const skipThemeTransitionRef =
|
|
5500
|
-
|
|
5869
|
+
const [internalMode, setInternalMode] = React3.useState(defaultColorMode);
|
|
5870
|
+
const [isThemeTransitionReady, setIsThemeTransitionReady] = React3.useState(false);
|
|
5871
|
+
const skipThemeTransitionRef = React3.useRef(true);
|
|
5872
|
+
React3.useLayoutEffect(() => {
|
|
5501
5873
|
if (!isControlled) {
|
|
5502
5874
|
const stored = loadChatColorMode();
|
|
5503
5875
|
if (stored) {
|
|
@@ -5512,7 +5884,7 @@ var ChatThemeProvider = ({
|
|
|
5512
5884
|
}, [isControlled]);
|
|
5513
5885
|
const resolvedMode = isControlled ? colorMode : internalMode;
|
|
5514
5886
|
const isDark = resolvedMode === "dark";
|
|
5515
|
-
const setColorMode =
|
|
5887
|
+
const setColorMode = React3.useCallback(
|
|
5516
5888
|
(mode) => {
|
|
5517
5889
|
const apply = () => {
|
|
5518
5890
|
if (!isControlled) {
|
|
@@ -5529,10 +5901,10 @@ var ChatThemeProvider = ({
|
|
|
5529
5901
|
},
|
|
5530
5902
|
[isControlled, onColorModeChange]
|
|
5531
5903
|
);
|
|
5532
|
-
const toggleColorMode =
|
|
5904
|
+
const toggleColorMode = React3.useCallback(() => {
|
|
5533
5905
|
setColorMode(resolvedMode === "dark" ? "light" : "dark");
|
|
5534
5906
|
}, [resolvedMode, setColorMode]);
|
|
5535
|
-
const value =
|
|
5907
|
+
const value = React3.useMemo(
|
|
5536
5908
|
() => ({
|
|
5537
5909
|
colorMode: resolvedMode,
|
|
5538
5910
|
isDark,
|
|
@@ -5560,7 +5932,7 @@ var ChatThemeProvider = ({
|
|
|
5560
5932
|
return /* @__PURE__ */ jsxRuntime.jsx(ChatThemeContext.Provider, { value, children });
|
|
5561
5933
|
};
|
|
5562
5934
|
var useChatTheme = () => {
|
|
5563
|
-
const context =
|
|
5935
|
+
const context = React3.useContext(ChatThemeContext);
|
|
5564
5936
|
if (!context) {
|
|
5565
5937
|
throw new Error("useChatTheme must be used within ChatThemeProvider");
|
|
5566
5938
|
}
|
|
@@ -6105,7 +6477,7 @@ function useCreateChatDialog({
|
|
|
6105
6477
|
onUserSelect,
|
|
6106
6478
|
setIsCreateModalOpen
|
|
6107
6479
|
}) {
|
|
6108
|
-
const [state, setState] =
|
|
6480
|
+
const [state, setState] = React3.useState(initialState);
|
|
6109
6481
|
const updateState = (updates) => {
|
|
6110
6482
|
setState((prev) => ({ ...prev, ...updates }));
|
|
6111
6483
|
};
|
|
@@ -6114,8 +6486,10 @@ function useCreateChatDialog({
|
|
|
6114
6486
|
const fetchAllUsers = exports.useChatStore((storeState) => storeState.fetchAllUsers);
|
|
6115
6487
|
const accessToken = exports.useChatStore((storeState) => storeState.accessToken);
|
|
6116
6488
|
const fetchConversations2 = exports.useChatStore((storeState) => storeState.fetchConversations);
|
|
6117
|
-
const
|
|
6118
|
-
|
|
6489
|
+
const { settings } = useEffectiveSettingsOptional();
|
|
6490
|
+
const maxParticipants = settings.maxParticipantsPerGroup;
|
|
6491
|
+
const fileInputRef = React3.useRef(null);
|
|
6492
|
+
React3.useEffect(() => {
|
|
6119
6493
|
if (accessToken) {
|
|
6120
6494
|
fetchAllUsers();
|
|
6121
6495
|
}
|
|
@@ -6127,9 +6501,18 @@ function useCreateChatDialog({
|
|
|
6127
6501
|
setState((prev) => {
|
|
6128
6502
|
const memberId = String(member._id);
|
|
6129
6503
|
const exists = prev.selectedMembers.some((m) => String(m._id) === memberId);
|
|
6504
|
+
if (exists) {
|
|
6505
|
+
return {
|
|
6506
|
+
...prev,
|
|
6507
|
+
selectedMembers: prev.selectedMembers.filter((m) => String(m._id) !== memberId)
|
|
6508
|
+
};
|
|
6509
|
+
}
|
|
6510
|
+
if (prev.selectedMembers.length + 1 >= maxParticipants) {
|
|
6511
|
+
return prev;
|
|
6512
|
+
}
|
|
6130
6513
|
return {
|
|
6131
6514
|
...prev,
|
|
6132
|
-
selectedMembers:
|
|
6515
|
+
selectedMembers: [...prev.selectedMembers, member]
|
|
6133
6516
|
};
|
|
6134
6517
|
});
|
|
6135
6518
|
};
|
|
@@ -6513,8 +6896,25 @@ function GroupCreateTab({
|
|
|
6513
6896
|
) })
|
|
6514
6897
|
] });
|
|
6515
6898
|
}
|
|
6899
|
+
function AdminPermissionTooltip({
|
|
6900
|
+
disabled,
|
|
6901
|
+
message,
|
|
6902
|
+
side = "top",
|
|
6903
|
+
className,
|
|
6904
|
+
children
|
|
6905
|
+
}) {
|
|
6906
|
+
if (!disabled || !message) {
|
|
6907
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
6908
|
+
}
|
|
6909
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
6910
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("inline-flex", className), children }) }),
|
|
6911
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side, className: "max-w-[240px] text-xs", children: message })
|
|
6912
|
+
] });
|
|
6913
|
+
}
|
|
6516
6914
|
var CreateChatDialog = (props) => {
|
|
6517
6915
|
const { isCreateModalOpen = false, setIsCreateModalOpen } = props;
|
|
6916
|
+
const { getGroupCreationGate } = useEffectiveSettingsOptional();
|
|
6917
|
+
const groupCreationGate = getGroupCreationGate();
|
|
6518
6918
|
const {
|
|
6519
6919
|
state,
|
|
6520
6920
|
updateState,
|
|
@@ -6568,24 +6968,39 @@ var CreateChatDialog = (props) => {
|
|
|
6568
6968
|
) })
|
|
6569
6969
|
] }),
|
|
6570
6970
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid shrink-0 grid-cols-2 gap-2 px-5", children: [
|
|
6571
|
-
{ id: "dm", label: "Message", icon: lucideReact.MessageCircle },
|
|
6572
|
-
{ id: "group", label: "New group", icon: lucideReact.Users }
|
|
6573
|
-
].map(({ id, label, icon: Icon }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6574
|
-
"button",
|
|
6971
|
+
{ id: "dm", label: "Message", icon: lucideReact.MessageCircle, disabled: false, reason: null },
|
|
6575
6972
|
{
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6973
|
+
id: "group",
|
|
6974
|
+
label: "New group",
|
|
6975
|
+
icon: lucideReact.Users,
|
|
6976
|
+
disabled: !groupCreationGate.enabled,
|
|
6977
|
+
reason: groupCreationGate.disabledReason
|
|
6978
|
+
}
|
|
6979
|
+
].map(({ id, label, icon: Icon, disabled, reason }) => {
|
|
6980
|
+
const tabButton = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6981
|
+
"button",
|
|
6982
|
+
{
|
|
6983
|
+
type: "button",
|
|
6984
|
+
disabled,
|
|
6985
|
+
onClick: () => {
|
|
6986
|
+
if (disabled) return;
|
|
6987
|
+
updateState({ activeTab: id });
|
|
6988
|
+
},
|
|
6989
|
+
className: cn(
|
|
6990
|
+
"flex w-full items-center justify-center gap-2 rounded-full border py-2 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-40",
|
|
6991
|
+
state.activeTab === id ? "border-(--chat-theme-20) bg-(--chat-theme-5) text-(--chat-theme)" : "border-(--chat-border) text-(--chat-muted) hover:border-(--chat-theme-20) hover:text-(--chat-text)"
|
|
6992
|
+
),
|
|
6993
|
+
children: [
|
|
6994
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }),
|
|
6995
|
+
label
|
|
6996
|
+
]
|
|
6997
|
+
}
|
|
6998
|
+
);
|
|
6999
|
+
if (!disabled || !reason) {
|
|
7000
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: tabButton }, id);
|
|
7001
|
+
}
|
|
7002
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AdminPermissionTooltip, { disabled: true, message: reason, children: tabButton }, id);
|
|
7003
|
+
}) }),
|
|
6589
7004
|
state.activeTab === "dm" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6590
7005
|
DmContactsTab,
|
|
6591
7006
|
{
|
|
@@ -6596,7 +7011,7 @@ var CreateChatDialog = (props) => {
|
|
|
6596
7011
|
onStartDM: handleStartDM
|
|
6597
7012
|
}
|
|
6598
7013
|
),
|
|
6599
|
-
state.activeTab === "group" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7014
|
+
state.activeTab === "group" && groupCreationGate.enabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6600
7015
|
GroupCreateTab,
|
|
6601
7016
|
{
|
|
6602
7017
|
state,
|
|
@@ -6660,7 +7075,7 @@ var emitPushChanged = (enabled) => {
|
|
|
6660
7075
|
} catch {
|
|
6661
7076
|
}
|
|
6662
7077
|
};
|
|
6663
|
-
var pushApiUrl = (path) => exports.buildVersionedApiUrl(path, { service: "
|
|
7078
|
+
var pushApiUrl = (path) => exports.buildVersionedApiUrl(path, { service: "v2" });
|
|
6664
7079
|
var apiGetPushConfig = async () => {
|
|
6665
7080
|
const { data } = await apiClient.get(pushApiUrl("/notifications/push/config"));
|
|
6666
7081
|
return data?.data;
|
|
@@ -6809,7 +7224,7 @@ var onForegroundPush = async (callback) => {
|
|
|
6809
7224
|
|
|
6810
7225
|
// src/notifications/usePushNotifications.ts
|
|
6811
7226
|
var usePushNotifications = () => {
|
|
6812
|
-
const [state, setState] =
|
|
7227
|
+
const [state, setState] = React3.useState({
|
|
6813
7228
|
supported: false,
|
|
6814
7229
|
allowedByWorkspace: false,
|
|
6815
7230
|
configured: false,
|
|
@@ -6819,7 +7234,7 @@ var usePushNotifications = () => {
|
|
|
6819
7234
|
loading: true,
|
|
6820
7235
|
error: null
|
|
6821
7236
|
});
|
|
6822
|
-
const refresh =
|
|
7237
|
+
const refresh = React3.useCallback(async () => {
|
|
6823
7238
|
if (!isPushSupported()) {
|
|
6824
7239
|
setState((prev) => ({
|
|
6825
7240
|
...prev,
|
|
@@ -6852,10 +7267,10 @@ var usePushNotifications = () => {
|
|
|
6852
7267
|
}));
|
|
6853
7268
|
}
|
|
6854
7269
|
}, []);
|
|
6855
|
-
|
|
7270
|
+
React3.useEffect(() => {
|
|
6856
7271
|
void refresh();
|
|
6857
7272
|
}, [refresh]);
|
|
6858
|
-
const enable =
|
|
7273
|
+
const enable = React3.useCallback(async () => {
|
|
6859
7274
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
6860
7275
|
try {
|
|
6861
7276
|
await enablePushOnThisDevice();
|
|
@@ -6871,7 +7286,7 @@ var usePushNotifications = () => {
|
|
|
6871
7286
|
return false;
|
|
6872
7287
|
}
|
|
6873
7288
|
}, [refresh]);
|
|
6874
|
-
const disable =
|
|
7289
|
+
const disable = React3.useCallback(async () => {
|
|
6875
7290
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
6876
7291
|
try {
|
|
6877
7292
|
await disablePushOnThisDevice();
|
|
@@ -6879,7 +7294,7 @@ var usePushNotifications = () => {
|
|
|
6879
7294
|
await refresh();
|
|
6880
7295
|
}
|
|
6881
7296
|
}, [refresh]);
|
|
6882
|
-
const setUserEnabled =
|
|
7297
|
+
const setUserEnabled = React3.useCallback(
|
|
6883
7298
|
async (enabled) => {
|
|
6884
7299
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
6885
7300
|
try {
|
|
@@ -6905,14 +7320,20 @@ var PushNotificationToggle = ({
|
|
|
6905
7320
|
children
|
|
6906
7321
|
}) => {
|
|
6907
7322
|
const push = usePushNotifications();
|
|
6908
|
-
const
|
|
6909
|
-
|
|
7323
|
+
const { getPushNotificationGate } = useEffectiveSettingsOptional();
|
|
7324
|
+
const adminGate = getPushNotificationGate();
|
|
7325
|
+
const [isToggling, setIsToggling] = React3.useState(false);
|
|
7326
|
+
if (!push.supported) {
|
|
6910
7327
|
return null;
|
|
6911
7328
|
}
|
|
6912
7329
|
const isOn = push.deviceEnabled && push.userEnabled;
|
|
6913
7330
|
const permissionBlocked = push.permission === "denied";
|
|
7331
|
+
const adminBlocked = !adminGate.enabled;
|
|
7332
|
+
const notConfigured = !push.configured;
|
|
6914
7333
|
const showLoader = isToggling;
|
|
7334
|
+
const isDisabled = showLoader || permissionBlocked || push.loading || adminBlocked || notConfigured;
|
|
6915
7335
|
const handleChange = async (checked) => {
|
|
7336
|
+
if (adminBlocked || notConfigured) return;
|
|
6916
7337
|
setIsToggling(true);
|
|
6917
7338
|
try {
|
|
6918
7339
|
if (checked) {
|
|
@@ -6925,11 +7346,12 @@ var PushNotificationToggle = ({
|
|
|
6925
7346
|
setIsToggling(false);
|
|
6926
7347
|
}
|
|
6927
7348
|
};
|
|
7349
|
+
const descriptionText = adminBlocked ? adminGate.disabledReason || description : notConfigured ? "Push notifications are not configured. Please contact your administrator." : permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description;
|
|
6928
7350
|
const renderProps = {
|
|
6929
7351
|
label,
|
|
6930
|
-
description:
|
|
6931
|
-
checked: isOn,
|
|
6932
|
-
disabled:
|
|
7352
|
+
description: descriptionText,
|
|
7353
|
+
checked: adminBlocked || notConfigured ? false : isOn,
|
|
7354
|
+
disabled: isDisabled,
|
|
6933
7355
|
loading: showLoader || push.loading,
|
|
6934
7356
|
permissionBlocked,
|
|
6935
7357
|
error: push.error,
|
|
@@ -6957,12 +7379,20 @@ var PushNotificationToggle = ({
|
|
|
6957
7379
|
"aria-label": "Updating push notifications"
|
|
6958
7380
|
}
|
|
6959
7381
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
6960
|
-
|
|
7382
|
+
AdminPermissionTooltip,
|
|
6961
7383
|
{
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
7384
|
+
disabled: adminBlocked || notConfigured,
|
|
7385
|
+
message: adminBlocked ? adminGate.disabledReason : "Push notifications are not configured. Please contact your administrator.",
|
|
7386
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7387
|
+
Switch,
|
|
7388
|
+
{
|
|
7389
|
+
checked: adminBlocked || notConfigured ? false : isOn,
|
|
7390
|
+
disabled: isDisabled,
|
|
7391
|
+
onCheckedChange: (checked) => void handleChange(checked),
|
|
7392
|
+
"aria-label": `Toggle ${label}`,
|
|
7393
|
+
className: "data-[state=checked]:bg-(--chat-theme) data-[state=unchecked]:bg-(--chat-border)"
|
|
7394
|
+
}
|
|
7395
|
+
)
|
|
6966
7396
|
}
|
|
6967
7397
|
)
|
|
6968
7398
|
]
|
|
@@ -7076,7 +7506,7 @@ var LoggedUserSettingsDialog = ({
|
|
|
7076
7506
|
className
|
|
7077
7507
|
}) => {
|
|
7078
7508
|
const { resolveComponent, slotClassName } = useChatCustomization();
|
|
7079
|
-
const [internalOpen, setInternalOpen] =
|
|
7509
|
+
const [internalOpen, setInternalOpen] = React3.useState(false);
|
|
7080
7510
|
const open = controlledOpen ?? internalOpen;
|
|
7081
7511
|
const onOpenChange = controlledOnOpenChange ?? setInternalOpen;
|
|
7082
7512
|
const TriggerSlot = resolveComponent(
|
|
@@ -7264,7 +7694,7 @@ function getDraftRevision() {
|
|
|
7264
7694
|
return draftRevision;
|
|
7265
7695
|
}
|
|
7266
7696
|
function useDraftRevision() {
|
|
7267
|
-
return
|
|
7697
|
+
return React3.useSyncExternalStore(subscribeToDrafts, getDraftRevision, getDraftRevision);
|
|
7268
7698
|
}
|
|
7269
7699
|
function getConversationDraft(conversationId) {
|
|
7270
7700
|
if (!conversationId) return emptyDraft();
|
|
@@ -7302,11 +7732,11 @@ function getConversationDraftPreview(conversationId) {
|
|
|
7302
7732
|
return null;
|
|
7303
7733
|
}
|
|
7304
7734
|
function useConversationDraft(conversationId) {
|
|
7305
|
-
const composerRef =
|
|
7306
|
-
const syncComposerRef =
|
|
7735
|
+
const composerRef = React3.useRef(emptyDraft());
|
|
7736
|
+
const syncComposerRef = React3.useCallback((draft) => {
|
|
7307
7737
|
composerRef.current = draft;
|
|
7308
7738
|
}, []);
|
|
7309
|
-
|
|
7739
|
+
React3.useEffect(() => {
|
|
7310
7740
|
const id = conversationId;
|
|
7311
7741
|
return () => {
|
|
7312
7742
|
if (!id) return;
|
|
@@ -7525,7 +7955,7 @@ var saveChatDateTimePreferences = (prefs) => {
|
|
|
7525
7955
|
} catch {
|
|
7526
7956
|
}
|
|
7527
7957
|
};
|
|
7528
|
-
var ChatLocaleContext =
|
|
7958
|
+
var ChatLocaleContext = React3.createContext(null);
|
|
7529
7959
|
var resolveInitialPrefs = (defaults) => {
|
|
7530
7960
|
const stored = loadChatDateTimePreferences();
|
|
7531
7961
|
const fallback = resolveStoredPrefs(defaults);
|
|
@@ -7552,7 +7982,7 @@ var ChatLocaleProvider = ({
|
|
|
7552
7982
|
const localeControlled = controlledLocale !== void 0;
|
|
7553
7983
|
const timeZoneControlled = controlledTimeZone !== void 0;
|
|
7554
7984
|
const hour12Controlled = controlledHour12 !== void 0;
|
|
7555
|
-
const [internalPrefs, setInternalPrefs] =
|
|
7985
|
+
const [internalPrefs, setInternalPrefs] = React3.useState(
|
|
7556
7986
|
() => resolveInitialPrefs({
|
|
7557
7987
|
locale: defaultLocale,
|
|
7558
7988
|
timeZone: defaultTimeZone,
|
|
@@ -7562,7 +7992,7 @@ var ChatLocaleProvider = ({
|
|
|
7562
7992
|
const resolvedLocale = localeControlled ? controlledLocale : internalPrefs.locale;
|
|
7563
7993
|
const resolvedTimeZone = timeZoneControlled ? controlledTimeZone : internalPrefs.timeZone;
|
|
7564
7994
|
const resolvedHour12 = hour12Controlled ? controlledHour12 ?? getDefaultHour12() : internalPrefs.hour12 ?? getDefaultHour12();
|
|
7565
|
-
const updatePrefs =
|
|
7995
|
+
const updatePrefs = React3.useCallback(
|
|
7566
7996
|
(updates) => {
|
|
7567
7997
|
const next = {
|
|
7568
7998
|
locale: updates.locale !== void 0 ? updates.locale : resolvedLocale,
|
|
@@ -7591,19 +8021,19 @@ var ChatLocaleProvider = ({
|
|
|
7591
8021
|
onDateTimePreferencesChange
|
|
7592
8022
|
]
|
|
7593
8023
|
);
|
|
7594
|
-
const setLocale =
|
|
8024
|
+
const setLocale = React3.useCallback(
|
|
7595
8025
|
(locale) => updatePrefs({ locale }),
|
|
7596
8026
|
[updatePrefs]
|
|
7597
8027
|
);
|
|
7598
|
-
const setTimeZone =
|
|
8028
|
+
const setTimeZone = React3.useCallback(
|
|
7599
8029
|
(timeZone) => updatePrefs({ timeZone }),
|
|
7600
8030
|
[updatePrefs]
|
|
7601
8031
|
);
|
|
7602
|
-
const setHour12 =
|
|
8032
|
+
const setHour12 = React3.useCallback(
|
|
7603
8033
|
(hour12) => updatePrefs({ hour12 }),
|
|
7604
8034
|
[updatePrefs]
|
|
7605
8035
|
);
|
|
7606
|
-
const prefs =
|
|
8036
|
+
const prefs = React3.useMemo(
|
|
7607
8037
|
() => ({
|
|
7608
8038
|
locale: resolvedLocale,
|
|
7609
8039
|
timeZone: resolvedTimeZone,
|
|
@@ -7611,8 +8041,8 @@ var ChatLocaleProvider = ({
|
|
|
7611
8041
|
}),
|
|
7612
8042
|
[resolvedLocale, resolvedTimeZone, resolvedHour12]
|
|
7613
8043
|
);
|
|
7614
|
-
const formatters =
|
|
7615
|
-
const value =
|
|
8044
|
+
const formatters = React3.useMemo(() => createChatDateTimeFormatters(prefs), [prefs]);
|
|
8045
|
+
const value = React3.useMemo(
|
|
7616
8046
|
() => ({
|
|
7617
8047
|
...formatters,
|
|
7618
8048
|
locale: resolvedLocale,
|
|
@@ -7637,7 +8067,7 @@ var ChatLocaleProvider = ({
|
|
|
7637
8067
|
return /* @__PURE__ */ jsxRuntime.jsx(ChatLocaleContext.Provider, { value, children });
|
|
7638
8068
|
};
|
|
7639
8069
|
var useChatLocale = () => {
|
|
7640
|
-
const context =
|
|
8070
|
+
const context = React3.useContext(ChatLocaleContext);
|
|
7641
8071
|
if (!context) {
|
|
7642
8072
|
throw new Error("useChatLocale must be used within ChatLocaleProvider");
|
|
7643
8073
|
}
|
|
@@ -7759,15 +8189,15 @@ function useChannelList({ debouncedSearch = "" }) {
|
|
|
7759
8189
|
const conversationsPage = exports.useChatStore((s) => s.conversationsPage);
|
|
7760
8190
|
const accessToken = exports.useChatStore((s) => s.accessToken);
|
|
7761
8191
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
7762
|
-
const lastFetchKeyRef =
|
|
8192
|
+
const lastFetchKeyRef = React3.useRef(null);
|
|
7763
8193
|
useDraftRevision();
|
|
7764
8194
|
const { formatSidebarTime } = useChatLocale();
|
|
7765
|
-
|
|
8195
|
+
React3.useEffect(() => {
|
|
7766
8196
|
if (accessToken) {
|
|
7767
8197
|
exports.useChatStore.getState().fetchAllUsers();
|
|
7768
8198
|
}
|
|
7769
8199
|
}, [accessToken]);
|
|
7770
|
-
|
|
8200
|
+
React3.useEffect(() => {
|
|
7771
8201
|
if (!accessToken) return;
|
|
7772
8202
|
const fetchKey = debouncedSearch;
|
|
7773
8203
|
if (lastFetchKeyRef.current === fetchKey) return;
|
|
@@ -7779,7 +8209,7 @@ function useChannelList({ debouncedSearch = "" }) {
|
|
|
7779
8209
|
}
|
|
7780
8210
|
fetchConversations2(DEFAULT_CONVERSATIONS_LIMIT, 1, debouncedSearch, true);
|
|
7781
8211
|
}, [accessToken, debouncedSearch]);
|
|
7782
|
-
const mappedChannels =
|
|
8212
|
+
const mappedChannels = React3.useMemo(() => {
|
|
7783
8213
|
const safeConversations = Array.isArray(conversations) ? conversations : [];
|
|
7784
8214
|
const seenConversationIds = /* @__PURE__ */ new Set();
|
|
7785
8215
|
return safeConversations.map((c) => {
|
|
@@ -8383,7 +8813,7 @@ function highlightSearchMatch(text, query) {
|
|
|
8383
8813
|
children: part
|
|
8384
8814
|
},
|
|
8385
8815
|
`${part}-${index}`
|
|
8386
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8816
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(React3__namespace.default.Fragment, { children: part }, `${part}-${index}`)
|
|
8387
8817
|
);
|
|
8388
8818
|
}
|
|
8389
8819
|
function getMessagePreview(message) {
|
|
@@ -8430,14 +8860,14 @@ var HeaderSearchPopover = ({
|
|
|
8430
8860
|
}) => {
|
|
8431
8861
|
const { scopeClassName, themeStyles } = useChatTheme();
|
|
8432
8862
|
const { formatMessageTime, formatShortDate } = useChatLocale();
|
|
8433
|
-
const inputRef =
|
|
8434
|
-
|
|
8863
|
+
const inputRef = React3.useRef(null);
|
|
8864
|
+
React3.useEffect(() => {
|
|
8435
8865
|
if (!open) return;
|
|
8436
8866
|
const timer = window.setTimeout(() => inputRef.current?.focus(), 0);
|
|
8437
8867
|
return () => window.clearTimeout(timer);
|
|
8438
8868
|
}, [open]);
|
|
8439
8869
|
const showResults = searchQuery.trim().length > 0;
|
|
8440
|
-
const resultCountLabel =
|
|
8870
|
+
const resultCountLabel = React3.useMemo(() => {
|
|
8441
8871
|
if (!searchResults.length) return "0 results";
|
|
8442
8872
|
return `${searchResults.length}${hasMore ? "+" : ""} result${searchResults.length === 1 ? "" : "s"}`;
|
|
8443
8873
|
}, [hasMore, searchResults.length]);
|
|
@@ -8563,7 +8993,7 @@ var HeaderSearchPopover = ({
|
|
|
8563
8993
|
] });
|
|
8564
8994
|
};
|
|
8565
8995
|
var HeaderSearchPopover_default = HeaderSearchPopover;
|
|
8566
|
-
var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text)";
|
|
8996
|
+
var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text) disabled:opacity-40";
|
|
8567
8997
|
var DefaultHeaderCallActions = ({
|
|
8568
8998
|
activeChannel,
|
|
8569
8999
|
conversationId,
|
|
@@ -8574,48 +9004,91 @@ var DefaultHeaderCallActions = ({
|
|
|
8574
9004
|
className
|
|
8575
9005
|
}) => {
|
|
8576
9006
|
const { components, slotClassName, features } = useChatCustomizationOptional();
|
|
9007
|
+
const { getAudioCallGate, getVideoCallGate } = useEffectiveSettingsOptional();
|
|
8577
9008
|
const PhoneSlot = components.PhoneCallButton;
|
|
8578
9009
|
const VideoSlot = components.VideoCallButton;
|
|
8579
9010
|
const hideInGroups = features.hideCallActionsInGroupChats ?? false;
|
|
9011
|
+
const audioGate = getAudioCallGate();
|
|
9012
|
+
const videoGate = getVideoCallGate();
|
|
8580
9013
|
if (hideInGroups && activeChannel.isGroup) return null;
|
|
8581
9014
|
if (!showPhoneCall && !showVideoCall) return null;
|
|
9015
|
+
const phoneEnabled = showPhoneCall && audioGate.enabled;
|
|
9016
|
+
const videoEnabled = showVideoCall && videoGate.enabled;
|
|
8582
9017
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8583
9018
|
showPhoneCall && (PhoneSlot ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8584
|
-
|
|
9019
|
+
AdminPermissionTooltip,
|
|
8585
9020
|
{
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
9021
|
+
disabled: !audioGate.enabled,
|
|
9022
|
+
message: audioGate.disabledReason,
|
|
9023
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9024
|
+
PhoneSlot,
|
|
9025
|
+
{
|
|
9026
|
+
activeChannel,
|
|
9027
|
+
conversationId,
|
|
9028
|
+
onPhoneCall: phoneEnabled ? onPhoneCall : void 0,
|
|
9029
|
+
className: cn(
|
|
9030
|
+
className,
|
|
9031
|
+
slotClassName("phoneCallButton"),
|
|
9032
|
+
!audioGate.enabled && "pointer-events-none opacity-40"
|
|
9033
|
+
)
|
|
9034
|
+
}
|
|
9035
|
+
) })
|
|
8590
9036
|
}
|
|
8591
9037
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8592
|
-
|
|
9038
|
+
AdminPermissionTooltip,
|
|
8593
9039
|
{
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
9040
|
+
disabled: !audioGate.enabled,
|
|
9041
|
+
message: audioGate.disabledReason,
|
|
9042
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9043
|
+
Button,
|
|
9044
|
+
{
|
|
9045
|
+
variant: "ghost",
|
|
9046
|
+
size: "icon",
|
|
9047
|
+
className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
|
|
9048
|
+
"aria-label": "Voice call",
|
|
9049
|
+
disabled: !audioGate.enabled,
|
|
9050
|
+
onClick: phoneEnabled ? onPhoneCall : void 0,
|
|
9051
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 15 })
|
|
9052
|
+
}
|
|
9053
|
+
)
|
|
8600
9054
|
}
|
|
8601
9055
|
)),
|
|
8602
9056
|
showVideoCall && (VideoSlot ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8603
|
-
|
|
9057
|
+
AdminPermissionTooltip,
|
|
8604
9058
|
{
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
9059
|
+
disabled: !videoGate.enabled,
|
|
9060
|
+
message: videoGate.disabledReason,
|
|
9061
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9062
|
+
VideoSlot,
|
|
9063
|
+
{
|
|
9064
|
+
activeChannel,
|
|
9065
|
+
conversationId,
|
|
9066
|
+
onVideoCall: videoEnabled ? onVideoCall : void 0,
|
|
9067
|
+
className: cn(
|
|
9068
|
+
className,
|
|
9069
|
+
slotClassName("videoCallButton"),
|
|
9070
|
+
!videoGate.enabled && "pointer-events-none opacity-40"
|
|
9071
|
+
)
|
|
9072
|
+
}
|
|
9073
|
+
) })
|
|
8609
9074
|
}
|
|
8610
9075
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8611
|
-
|
|
9076
|
+
AdminPermissionTooltip,
|
|
8612
9077
|
{
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
9078
|
+
disabled: !videoGate.enabled,
|
|
9079
|
+
message: videoGate.disabledReason,
|
|
9080
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9081
|
+
Button,
|
|
9082
|
+
{
|
|
9083
|
+
variant: "ghost",
|
|
9084
|
+
size: "icon",
|
|
9085
|
+
className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
|
|
9086
|
+
"aria-label": "Video call",
|
|
9087
|
+
disabled: !videoGate.enabled,
|
|
9088
|
+
onClick: videoEnabled ? onVideoCall : void 0,
|
|
9089
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 15 })
|
|
9090
|
+
}
|
|
9091
|
+
)
|
|
8619
9092
|
}
|
|
8620
9093
|
))
|
|
8621
9094
|
] });
|
|
@@ -8637,19 +9110,38 @@ function OptionsMenuItem({
|
|
|
8637
9110
|
icon: Icon,
|
|
8638
9111
|
label,
|
|
8639
9112
|
onSelect,
|
|
8640
|
-
destructive = false
|
|
9113
|
+
destructive = false,
|
|
9114
|
+
disabled = false,
|
|
9115
|
+
disabledReason
|
|
8641
9116
|
}) {
|
|
8642
|
-
|
|
9117
|
+
const item = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8643
9118
|
DropdownMenuItem,
|
|
8644
9119
|
{
|
|
8645
|
-
className:
|
|
8646
|
-
|
|
9120
|
+
className: cn(
|
|
9121
|
+
destructive ? chatOptionsMenuItemDestructiveClass : chatOptionsMenuItemClass,
|
|
9122
|
+
disabled && "pointer-events-none opacity-40"
|
|
9123
|
+
),
|
|
9124
|
+
disabled,
|
|
9125
|
+
onSelect: (event) => {
|
|
9126
|
+
if (disabled) {
|
|
9127
|
+
event.preventDefault();
|
|
9128
|
+
return;
|
|
9129
|
+
}
|
|
9130
|
+
onSelect?.();
|
|
9131
|
+
},
|
|
8647
9132
|
children: [
|
|
8648
9133
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { strokeWidth: 1.75 }),
|
|
8649
9134
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: label })
|
|
8650
9135
|
]
|
|
8651
9136
|
}
|
|
8652
9137
|
);
|
|
9138
|
+
if (!disabled || !disabledReason) {
|
|
9139
|
+
return item;
|
|
9140
|
+
}
|
|
9141
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
9142
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", children: item }) }),
|
|
9143
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "left", className: "max-w-[220px] text-xs", children: disabledReason })
|
|
9144
|
+
] });
|
|
8653
9145
|
}
|
|
8654
9146
|
var HeaderRightSide = ({
|
|
8655
9147
|
activeChannel,
|
|
@@ -8684,6 +9176,8 @@ var HeaderRightSide = ({
|
|
|
8684
9176
|
const { scopeClassName, themeStyles, showColorModeToggle } = useChatTheme();
|
|
8685
9177
|
const { showDateTimeSettings } = useChatLocale();
|
|
8686
9178
|
const features = useChatFeaturesOptional();
|
|
9179
|
+
const { getBlockUsersGate } = useEffectiveSettingsOptional();
|
|
9180
|
+
const blockUsersGate = getBlockUsersGate();
|
|
8687
9181
|
const showPhoneCall = features.showPhoneCall ?? defaultChatFeatures.showPhoneCall;
|
|
8688
9182
|
const showVideoCall = features.showVideoCall ?? defaultChatFeatures.showVideoCall;
|
|
8689
9183
|
const handlePhoneCall = () => {
|
|
@@ -8832,7 +9326,9 @@ var HeaderRightSide = ({
|
|
|
8832
9326
|
icon: lucideReact.Ban,
|
|
8833
9327
|
label: isBlocked ? "Unblock User" : "Block User",
|
|
8834
9328
|
onSelect: onToggleBlock,
|
|
8835
|
-
destructive: true
|
|
9329
|
+
destructive: true,
|
|
9330
|
+
disabled: !blockUsersGate.enabled,
|
|
9331
|
+
disabledReason: blockUsersGate.disabledReason
|
|
8836
9332
|
}
|
|
8837
9333
|
)
|
|
8838
9334
|
]
|
|
@@ -9203,13 +9699,13 @@ function AudioAttachmentPlayer({
|
|
|
9203
9699
|
showDownload = true,
|
|
9204
9700
|
downloadName
|
|
9205
9701
|
}) {
|
|
9206
|
-
const audioRef =
|
|
9207
|
-
const [isPlaying, setIsPlaying] =
|
|
9208
|
-
const [currentTime, setCurrentTime] =
|
|
9209
|
-
const [duration, setDuration] =
|
|
9702
|
+
const audioRef = React3.useRef(null);
|
|
9703
|
+
const [isPlaying, setIsPlaying] = React3.useState(false);
|
|
9704
|
+
const [currentTime, setCurrentTime] = React3.useState(0);
|
|
9705
|
+
const [duration, setDuration] = React3.useState(durationProp ?? 0);
|
|
9210
9706
|
const resolvedDuration = duration > 0 ? duration : 0;
|
|
9211
9707
|
const progressPercent = resolvedDuration > 0 ? Math.min(100, currentTime / resolvedDuration * 100) : 0;
|
|
9212
|
-
const togglePlay =
|
|
9708
|
+
const togglePlay = React3.useCallback(async () => {
|
|
9213
9709
|
const audio = audioRef.current;
|
|
9214
9710
|
if (!audio || !url) return;
|
|
9215
9711
|
if (audio.paused) {
|
|
@@ -9231,7 +9727,7 @@ function AudioAttachmentPlayer({
|
|
|
9231
9727
|
audio.currentTime = next;
|
|
9232
9728
|
setCurrentTime(next);
|
|
9233
9729
|
};
|
|
9234
|
-
|
|
9730
|
+
React3.useEffect(() => {
|
|
9235
9731
|
const audio = audioRef.current;
|
|
9236
9732
|
if (!audio) return;
|
|
9237
9733
|
const onTimeUpdate = () => setCurrentTime(audio.currentTime);
|
|
@@ -9259,7 +9755,7 @@ function AudioAttachmentPlayer({
|
|
|
9259
9755
|
audio.removeEventListener("play", onPlay);
|
|
9260
9756
|
};
|
|
9261
9757
|
}, [url]);
|
|
9262
|
-
|
|
9758
|
+
React3.useEffect(() => {
|
|
9263
9759
|
if (durationProp && durationProp > 0) {
|
|
9264
9760
|
setDuration(durationProp);
|
|
9265
9761
|
}
|
|
@@ -9381,12 +9877,12 @@ function VideoAttachmentPlayer({
|
|
|
9381
9877
|
downloadName,
|
|
9382
9878
|
onOpenPreview
|
|
9383
9879
|
}) {
|
|
9384
|
-
const videoRef =
|
|
9385
|
-
const [isPlaying, setIsPlaying] =
|
|
9386
|
-
const [duration, setDuration] =
|
|
9880
|
+
const videoRef = React3.useRef(null);
|
|
9881
|
+
const [isPlaying, setIsPlaying] = React3.useState(false);
|
|
9882
|
+
const [duration, setDuration] = React3.useState(durationProp ?? 0);
|
|
9387
9883
|
const onThemeBubble = inBubble && isSender;
|
|
9388
9884
|
const resolvedDuration = duration > 0 ? duration : 0;
|
|
9389
|
-
const togglePlay =
|
|
9885
|
+
const togglePlay = React3.useCallback(async () => {
|
|
9390
9886
|
const video = videoRef.current;
|
|
9391
9887
|
if (!video || !url) return;
|
|
9392
9888
|
if (video.paused) {
|
|
@@ -9401,7 +9897,7 @@ function VideoAttachmentPlayer({
|
|
|
9401
9897
|
setIsPlaying(false);
|
|
9402
9898
|
}
|
|
9403
9899
|
}, [url]);
|
|
9404
|
-
|
|
9900
|
+
React3.useEffect(() => {
|
|
9405
9901
|
if (durationProp && durationProp > 0) {
|
|
9406
9902
|
setDuration(durationProp);
|
|
9407
9903
|
}
|
|
@@ -9679,10 +10175,10 @@ async function fetchAuthenticatedBlob(url) {
|
|
|
9679
10175
|
return response.blob();
|
|
9680
10176
|
}
|
|
9681
10177
|
function PdfPreviewPanel({ url, name }) {
|
|
9682
|
-
const [blobUrl, setBlobUrl] =
|
|
9683
|
-
const [fallbackUrl, setFallbackUrl] =
|
|
9684
|
-
const [loading, setLoading] =
|
|
9685
|
-
|
|
10178
|
+
const [blobUrl, setBlobUrl] = React3.useState(null);
|
|
10179
|
+
const [fallbackUrl, setFallbackUrl] = React3.useState(null);
|
|
10180
|
+
const [loading, setLoading] = React3.useState(true);
|
|
10181
|
+
React3.useEffect(() => {
|
|
9686
10182
|
let active = true;
|
|
9687
10183
|
let objectUrl = null;
|
|
9688
10184
|
const loadPdf = async () => {
|
|
@@ -10186,60 +10682,60 @@ function AttachmentImageLightbox({
|
|
|
10186
10682
|
onSaveCaption,
|
|
10187
10683
|
initialCaptionEditing = false
|
|
10188
10684
|
}) {
|
|
10189
|
-
const [index, setIndex] =
|
|
10190
|
-
const [zoom, setZoom] =
|
|
10191
|
-
const [pan, setPan] =
|
|
10192
|
-
const [imageVersion, setImageVersion] =
|
|
10193
|
-
const [localCaptions, setLocalCaptions] =
|
|
10194
|
-
const [captionDraft, setCaptionDraft] =
|
|
10195
|
-
const [isCaptionEditing, setIsCaptionEditing] =
|
|
10196
|
-
const thumbRefs =
|
|
10197
|
-
const captionInputRef =
|
|
10198
|
-
const touchStartX =
|
|
10199
|
-
const isPanning =
|
|
10200
|
-
const panStart =
|
|
10685
|
+
const [index, setIndex] = React3.useState(initialIndex);
|
|
10686
|
+
const [zoom, setZoom] = React3.useState(1);
|
|
10687
|
+
const [pan, setPan] = React3.useState({ x: 0, y: 0 });
|
|
10688
|
+
const [imageVersion, setImageVersion] = React3.useState(0);
|
|
10689
|
+
const [localCaptions, setLocalCaptions] = React3.useState({});
|
|
10690
|
+
const [captionDraft, setCaptionDraft] = React3.useState("");
|
|
10691
|
+
const [isCaptionEditing, setIsCaptionEditing] = React3.useState(false);
|
|
10692
|
+
const thumbRefs = React3.useRef([]);
|
|
10693
|
+
const captionInputRef = React3.useRef(null);
|
|
10694
|
+
const touchStartX = React3.useRef(null);
|
|
10695
|
+
const isPanning = React3.useRef(false);
|
|
10696
|
+
const panStart = React3.useRef({ x: 0, y: 0, originX: 0, originY: 0 });
|
|
10201
10697
|
const canEdit = canEditCaption && !!onSaveCaption;
|
|
10202
|
-
|
|
10698
|
+
React3.useEffect(() => {
|
|
10203
10699
|
setIndex(initialIndex);
|
|
10204
10700
|
}, [initialIndex]);
|
|
10205
|
-
const resetView =
|
|
10701
|
+
const resetView = React3.useCallback(() => {
|
|
10206
10702
|
setZoom(1);
|
|
10207
10703
|
setPan({ x: 0, y: 0 });
|
|
10208
10704
|
}, []);
|
|
10209
|
-
const reloadImage =
|
|
10705
|
+
const reloadImage = React3.useCallback(() => {
|
|
10210
10706
|
resetView();
|
|
10211
10707
|
setImageVersion((version) => version + 1);
|
|
10212
10708
|
}, [resetView]);
|
|
10213
|
-
|
|
10709
|
+
React3.useEffect(() => {
|
|
10214
10710
|
resetView();
|
|
10215
10711
|
setIsCaptionEditing(false);
|
|
10216
10712
|
}, [index, resetView]);
|
|
10217
|
-
|
|
10713
|
+
React3.useEffect(() => {
|
|
10218
10714
|
if (!initialCaptionEditing || !canEdit) return;
|
|
10219
10715
|
setIsCaptionEditing(true);
|
|
10220
10716
|
}, [initialCaptionEditing, canEdit]);
|
|
10221
|
-
|
|
10717
|
+
React3.useEffect(() => {
|
|
10222
10718
|
if (!isCaptionEditing) return;
|
|
10223
10719
|
const id = window.setTimeout(() => captionInputRef.current?.focus(), 40);
|
|
10224
10720
|
return () => window.clearTimeout(id);
|
|
10225
10721
|
}, [isCaptionEditing]);
|
|
10226
|
-
const goPrev =
|
|
10722
|
+
const goPrev = React3.useCallback(() => {
|
|
10227
10723
|
setIndex((current2) => current2 > 0 ? current2 - 1 : images.length - 1);
|
|
10228
10724
|
}, [images.length]);
|
|
10229
|
-
const goNext =
|
|
10725
|
+
const goNext = React3.useCallback(() => {
|
|
10230
10726
|
setIndex((current2) => current2 < images.length - 1 ? current2 + 1 : 0);
|
|
10231
10727
|
}, [images.length]);
|
|
10232
|
-
const zoomIn =
|
|
10728
|
+
const zoomIn = React3.useCallback(() => {
|
|
10233
10729
|
setZoom((current2) => clampZoom(Number((current2 + ZOOM_STEP).toFixed(2))));
|
|
10234
10730
|
}, []);
|
|
10235
|
-
const zoomOut =
|
|
10731
|
+
const zoomOut = React3.useCallback(() => {
|
|
10236
10732
|
setZoom((current2) => {
|
|
10237
10733
|
const next = clampZoom(Number((current2 - ZOOM_STEP).toFixed(2)));
|
|
10238
10734
|
if (next <= MIN_ZOOM) setPan({ x: 0, y: 0 });
|
|
10239
10735
|
return next;
|
|
10240
10736
|
});
|
|
10241
10737
|
}, []);
|
|
10242
|
-
|
|
10738
|
+
React3.useEffect(() => {
|
|
10243
10739
|
const onKeyDown = (event) => {
|
|
10244
10740
|
const tag = event.target?.tagName;
|
|
10245
10741
|
const isTyping = tag === "INPUT" || tag === "TEXTAREA";
|
|
@@ -10253,14 +10749,14 @@ function AttachmentImageLightbox({
|
|
|
10253
10749
|
window.addEventListener("keydown", onKeyDown);
|
|
10254
10750
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
10255
10751
|
}, [goPrev, goNext, zoomIn, zoomOut, resetView]);
|
|
10256
|
-
|
|
10752
|
+
React3.useEffect(() => {
|
|
10257
10753
|
thumbRefs.current[index]?.scrollIntoView({
|
|
10258
10754
|
behavior: "smooth",
|
|
10259
10755
|
block: "nearest",
|
|
10260
10756
|
inline: "center"
|
|
10261
10757
|
});
|
|
10262
10758
|
}, [index]);
|
|
10263
|
-
|
|
10759
|
+
React3.useEffect(() => {
|
|
10264
10760
|
const attachment = images[index];
|
|
10265
10761
|
if (!attachment) return;
|
|
10266
10762
|
setCaptionDraft(getCaptionForAttachment(attachment, localCaptions));
|
|
@@ -10731,7 +11227,7 @@ function MessageAttachmentGrid({
|
|
|
10731
11227
|
onToggleAttachmentSelect,
|
|
10732
11228
|
onAttachmentHover
|
|
10733
11229
|
}) {
|
|
10734
|
-
const [lightboxIndex, setLightboxIndex] =
|
|
11230
|
+
const [lightboxIndex, setLightboxIndex] = React3.useState(null);
|
|
10735
11231
|
if (!images.length) return null;
|
|
10736
11232
|
const visible = images.slice(0, MAX_VISIBLE);
|
|
10737
11233
|
const overflow = images.length - MAX_VISIBLE;
|
|
@@ -10951,7 +11447,7 @@ function MessageAttachmentsImageSection({
|
|
|
10951
11447
|
hoveredAttachmentId,
|
|
10952
11448
|
onAttachmentHover
|
|
10953
11449
|
}) {
|
|
10954
|
-
const [lightboxIndex, setLightboxIndex] =
|
|
11450
|
+
const [lightboxIndex, setLightboxIndex] = React3.useState(null);
|
|
10955
11451
|
if (images.length === 0) return null;
|
|
10956
11452
|
const renderMediaMetaOverlay = () => /* @__PURE__ */ jsxRuntime.jsx(
|
|
10957
11453
|
MediaMetaOverlay,
|
|
@@ -11426,7 +11922,7 @@ function MessageAttachmentsView({
|
|
|
11426
11922
|
senderName,
|
|
11427
11923
|
senderId
|
|
11428
11924
|
}) {
|
|
11429
|
-
const [documentPreview, setDocumentPreview] =
|
|
11925
|
+
const [documentPreview, setDocumentPreview] = React3.useState(null);
|
|
11430
11926
|
const visibleAttachments = getVisibleAttachments(attachments);
|
|
11431
11927
|
if (isDeletedForEveryone || visibleAttachments.length === 0) return null;
|
|
11432
11928
|
const messageCaption = caption?.trim() || "";
|
|
@@ -11811,8 +12307,8 @@ var SavedMessagesDrawer = ({
|
|
|
11811
12307
|
const conversationMessages = exports.useChatStore(
|
|
11812
12308
|
(s) => conversationId ? s.messagesByConversation[conversationId] ?? EMPTY_CONVERSATION_MESSAGES : EMPTY_CONVERSATION_MESSAGES
|
|
11813
12309
|
);
|
|
11814
|
-
const [searchQuery, setSearchQuery] =
|
|
11815
|
-
const parsedEntries =
|
|
12310
|
+
const [searchQuery, setSearchQuery] = React3.useState("");
|
|
12311
|
+
const parsedEntries = React3.useMemo(() => {
|
|
11816
12312
|
return messages.map((msg) => ({
|
|
11817
12313
|
msg,
|
|
11818
12314
|
item: parseSavedMessage(msg, {
|
|
@@ -11833,7 +12329,7 @@ var SavedMessagesDrawer = ({
|
|
|
11833
12329
|
variant,
|
|
11834
12330
|
prefs
|
|
11835
12331
|
]);
|
|
11836
|
-
const groupedEntries =
|
|
12332
|
+
const groupedEntries = React3.useMemo(() => {
|
|
11837
12333
|
const query = searchQuery.trim().toLowerCase();
|
|
11838
12334
|
const filtered = parsedEntries.filter(({ item, msg }) => {
|
|
11839
12335
|
if (!query) return true;
|
|
@@ -12106,15 +12602,15 @@ function SectionScrollArea({
|
|
|
12106
12602
|
onLoadMore,
|
|
12107
12603
|
dependencyKey
|
|
12108
12604
|
}) {
|
|
12109
|
-
const scrollRef =
|
|
12110
|
-
const [showArrow, setShowArrow] =
|
|
12111
|
-
const updateArrow =
|
|
12605
|
+
const scrollRef = React3.useRef(null);
|
|
12606
|
+
const [showArrow, setShowArrow] = React3.useState(false);
|
|
12607
|
+
const updateArrow = React3.useCallback(() => {
|
|
12112
12608
|
const el = scrollRef.current;
|
|
12113
12609
|
if (!el) return;
|
|
12114
12610
|
const canScrollDown = el.scrollHeight - el.scrollTop - el.clientHeight > 6;
|
|
12115
12611
|
setShowArrow(canScrollDown || hasMoreToLoad);
|
|
12116
12612
|
}, [hasMoreToLoad]);
|
|
12117
|
-
|
|
12613
|
+
React3.useEffect(() => {
|
|
12118
12614
|
updateArrow();
|
|
12119
12615
|
const el = scrollRef.current;
|
|
12120
12616
|
if (!el) return;
|
|
@@ -12290,31 +12786,31 @@ var AttachmentsDrawer = ({ isOpen, onOpenChange, conversationId }) => {
|
|
|
12290
12786
|
const messagesByConversation = exports.useChatStore((s) => s.messagesByConversation);
|
|
12291
12787
|
const messagesMetadata = exports.useChatStore((s) => s.messagesMetadata);
|
|
12292
12788
|
const fetchMessages2 = exports.useChatStore((s) => s.fetchMessages);
|
|
12293
|
-
const [sectionVisibleCount, setSectionVisibleCount] =
|
|
12294
|
-
const [documentPreview, setDocumentPreview] =
|
|
12295
|
-
const [imageLightboxIndex, setImageLightboxIndex] =
|
|
12789
|
+
const [sectionVisibleCount, setSectionVisibleCount] = React3.useState({});
|
|
12790
|
+
const [documentPreview, setDocumentPreview] = React3.useState(null);
|
|
12791
|
+
const [imageLightboxIndex, setImageLightboxIndex] = React3.useState(null);
|
|
12296
12792
|
const hasLoadedMessages = conversationId ? Boolean(messagesMetadata[conversationId]?.isFirstPage) : false;
|
|
12297
12793
|
const isLoading = isOpen && !!conversationId && !hasLoadedMessages;
|
|
12298
|
-
|
|
12794
|
+
React3.useEffect(() => {
|
|
12299
12795
|
if (!isOpen) {
|
|
12300
12796
|
setSectionVisibleCount({});
|
|
12301
12797
|
setDocumentPreview(null);
|
|
12302
12798
|
setImageLightboxIndex(null);
|
|
12303
12799
|
}
|
|
12304
12800
|
}, [isOpen]);
|
|
12305
|
-
|
|
12801
|
+
React3.useEffect(() => {
|
|
12306
12802
|
setSectionVisibleCount({});
|
|
12307
12803
|
}, [conversationId]);
|
|
12308
|
-
|
|
12804
|
+
React3.useEffect(() => {
|
|
12309
12805
|
if (!isOpen || !conversationId || hasLoadedMessages) return;
|
|
12310
12806
|
fetchMessages2(conversationId);
|
|
12311
12807
|
}, [isOpen, conversationId, hasLoadedMessages, fetchMessages2]);
|
|
12312
|
-
const attachments =
|
|
12808
|
+
const attachments = React3.useMemo(() => {
|
|
12313
12809
|
if (!conversationId) return [];
|
|
12314
12810
|
const messages = messagesByConversation[conversationId] || [];
|
|
12315
12811
|
return collectConversationAttachments(messages);
|
|
12316
12812
|
}, [conversationId, messagesByConversation]);
|
|
12317
|
-
const imageLightboxItems =
|
|
12813
|
+
const imageLightboxItems = React3.useMemo(
|
|
12318
12814
|
() => attachments.filter((item) => item.type === "image").map((item) => ({
|
|
12319
12815
|
id: item.id,
|
|
12320
12816
|
url: item.url,
|
|
@@ -12323,14 +12819,14 @@ var AttachmentsDrawer = ({ isOpen, onOpenChange, conversationId }) => {
|
|
|
12323
12819
|
})),
|
|
12324
12820
|
[attachments]
|
|
12325
12821
|
);
|
|
12326
|
-
const openImagePreview =
|
|
12822
|
+
const openImagePreview = React3.useCallback(
|
|
12327
12823
|
(item) => {
|
|
12328
12824
|
const index = imageLightboxItems.findIndex((entry) => entry.id === item.id);
|
|
12329
12825
|
if (index >= 0) setImageLightboxIndex(index);
|
|
12330
12826
|
},
|
|
12331
12827
|
[imageLightboxItems]
|
|
12332
12828
|
);
|
|
12333
|
-
const grouped =
|
|
12829
|
+
const grouped = React3.useMemo(() => {
|
|
12334
12830
|
const map = /* @__PURE__ */ new Map();
|
|
12335
12831
|
for (const item of attachments) {
|
|
12336
12832
|
const bucket = map.get(item.type) ?? [];
|
|
@@ -12430,13 +12926,13 @@ var useGroupInfo = (conversationId) => {
|
|
|
12430
12926
|
const conversationInfos = exports.useChatStore((s) => s.conversationInfos);
|
|
12431
12927
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
12432
12928
|
const info = conversationId ? conversationInfos[conversationId] : null;
|
|
12433
|
-
const isAdmin =
|
|
12929
|
+
const isAdmin = React3.useMemo(() => {
|
|
12434
12930
|
if (!info || !loggedUserDetails) return false;
|
|
12435
12931
|
return info.groupAdmins?.some(
|
|
12436
12932
|
(admin) => (typeof admin === "string" ? admin : admin._id) === String(loggedUserDetails._id)
|
|
12437
12933
|
) || false;
|
|
12438
12934
|
}, [info, loggedUserDetails]);
|
|
12439
|
-
const isOwner =
|
|
12935
|
+
const isOwner = React3.useMemo(() => {
|
|
12440
12936
|
if (!info || !loggedUserDetails) return false;
|
|
12441
12937
|
let ownerId = null;
|
|
12442
12938
|
if (info.owner) {
|
|
@@ -12445,7 +12941,7 @@ var useGroupInfo = (conversationId) => {
|
|
|
12445
12941
|
return String(ownerId) === String(loggedUserDetails._id);
|
|
12446
12942
|
}, [info, loggedUserDetails]);
|
|
12447
12943
|
const permissions = info?.groupPermissions || null;
|
|
12448
|
-
const userPermissions =
|
|
12944
|
+
const userPermissions = React3.useMemo(() => {
|
|
12449
12945
|
return {
|
|
12450
12946
|
canSendMessage: isOwner || isAdmin || !permissions?.onlyAdminCanSendMessage,
|
|
12451
12947
|
canEditInfo: isOwner || isAdmin || !permissions?.onlyAdminCanEditInfo,
|
|
@@ -12494,21 +12990,21 @@ function useChannelDetailsDrawer({
|
|
|
12494
12990
|
const conversationId = conversationInfo?._id || activeChannel?.conversationId || storeActiveConversationId || null;
|
|
12495
12991
|
const { userPermissions } = useGroupInfo(conversationId);
|
|
12496
12992
|
const { formatLongDate } = useChatLocale();
|
|
12497
|
-
const storeConversation =
|
|
12993
|
+
const storeConversation = React3.useMemo(
|
|
12498
12994
|
() => conversations.find((c) => conversationId && String(c._id) === String(conversationId)),
|
|
12499
12995
|
[conversations, conversationId]
|
|
12500
12996
|
);
|
|
12501
|
-
const isGroupChannel =
|
|
12997
|
+
const isGroupChannel = React3.useMemo(() => {
|
|
12502
12998
|
if (storeConversation) {
|
|
12503
12999
|
return storeConversation.conversationType === "group" || !!storeConversation.isGroup;
|
|
12504
13000
|
}
|
|
12505
13001
|
return !!activeChannel?.isGroup;
|
|
12506
13002
|
}, [storeConversation, activeChannel?.isGroup]);
|
|
12507
|
-
const participantsSource =
|
|
13003
|
+
const participantsSource = React3.useMemo(
|
|
12508
13004
|
() => conversationInfo?.participants || storeConversation?.participants || [],
|
|
12509
13005
|
[conversationInfo?.participants, storeConversation?.participants]
|
|
12510
13006
|
);
|
|
12511
|
-
const resolvedOtherParticipant =
|
|
13007
|
+
const resolvedOtherParticipant = React3.useMemo(() => {
|
|
12512
13008
|
if (isGroupChannel) return { id: "", user: null };
|
|
12513
13009
|
return resolveOtherParticipant(
|
|
12514
13010
|
{
|
|
@@ -12527,7 +13023,7 @@ function useChannelDetailsDrawer({
|
|
|
12527
13023
|
allUsers
|
|
12528
13024
|
]);
|
|
12529
13025
|
const otherUser = resolvedOtherParticipant.user;
|
|
12530
|
-
const otherUserEmail =
|
|
13026
|
+
const otherUserEmail = React3.useMemo(() => {
|
|
12531
13027
|
if (isGroupChannel) return null;
|
|
12532
13028
|
const fromResolved = resolvedOtherParticipant.user?.email?.trim();
|
|
12533
13029
|
if (fromResolved) return fromResolved;
|
|
@@ -12535,7 +13031,7 @@ function useChannelDetailsDrawer({
|
|
|
12535
13031
|
if (!otherId) return null;
|
|
12536
13032
|
return allUsers.find((user) => String(user._id) === String(otherId))?.email?.trim() || activeChannel?.email?.trim() || null;
|
|
12537
13033
|
}, [isGroupChannel, resolvedOtherParticipant.id, resolvedOtherParticipant.user?.email, allUsers, activeChannel?.email]);
|
|
12538
|
-
const resolvedCreatedAt =
|
|
13034
|
+
const resolvedCreatedAt = React3.useMemo(
|
|
12539
13035
|
() => pickDate(
|
|
12540
13036
|
conversationInfo?.createdAt,
|
|
12541
13037
|
conversationInfo?.updatedAt,
|
|
@@ -12548,9 +13044,9 @@ function useChannelDetailsDrawer({
|
|
|
12548
13044
|
),
|
|
12549
13045
|
[conversationInfo, storeConversation, otherUser, conversationId, messagesByConversation]
|
|
12550
13046
|
);
|
|
12551
|
-
const [detailsLoading, setDetailsLoading] =
|
|
12552
|
-
const fetchStartedRef =
|
|
12553
|
-
|
|
13047
|
+
const [detailsLoading, setDetailsLoading] = React3.useState(false);
|
|
13048
|
+
const fetchStartedRef = React3.useRef(null);
|
|
13049
|
+
React3.useEffect(() => {
|
|
12554
13050
|
if (!isOpen) {
|
|
12555
13051
|
fetchStartedRef.current = null;
|
|
12556
13052
|
setDetailsLoading(false);
|
|
@@ -12592,16 +13088,16 @@ function useChannelDetailsDrawer({
|
|
|
12592
13088
|
};
|
|
12593
13089
|
}, [isOpen, conversationId, isGroupChannel, fetchAllUsers]);
|
|
12594
13090
|
const canEditInfo = activeChannel ? userPermissions.canEditInfo : false;
|
|
12595
|
-
const [isEditing, setIsEditing] =
|
|
12596
|
-
const [name, setName] =
|
|
12597
|
-
const [description, setDescription] =
|
|
12598
|
-
const [image, setImage] =
|
|
12599
|
-
const [uploadedImageUrl, setUploadedImageUrl] =
|
|
12600
|
-
const [imageUploadStatus, setImageUploadStatus] =
|
|
12601
|
-
const [imageUploadError, setImageUploadError] =
|
|
12602
|
-
const [isSaving, setIsSaving] =
|
|
12603
|
-
const fileInputRef =
|
|
12604
|
-
|
|
13091
|
+
const [isEditing, setIsEditing] = React3.useState(false);
|
|
13092
|
+
const [name, setName] = React3.useState("");
|
|
13093
|
+
const [description, setDescription] = React3.useState("");
|
|
13094
|
+
const [image, setImage] = React3.useState(null);
|
|
13095
|
+
const [uploadedImageUrl, setUploadedImageUrl] = React3.useState(null);
|
|
13096
|
+
const [imageUploadStatus, setImageUploadStatus] = React3.useState("idle");
|
|
13097
|
+
const [imageUploadError, setImageUploadError] = React3.useState(null);
|
|
13098
|
+
const [isSaving, setIsSaving] = React3.useState(false);
|
|
13099
|
+
const fileInputRef = React3.useRef(null);
|
|
13100
|
+
React3.useEffect(() => {
|
|
12605
13101
|
if (conversationInfo) {
|
|
12606
13102
|
setName(conversationInfo.groupName || activeChannel?.name || "");
|
|
12607
13103
|
setDescription(conversationInfo.groupDescription || "");
|
|
@@ -12872,17 +13368,24 @@ var ChannelDetailsDrawer = (props) => {
|
|
|
12872
13368
|
};
|
|
12873
13369
|
var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
|
|
12874
13370
|
init_useStore();
|
|
13371
|
+
init_settings_types();
|
|
12875
13372
|
var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo }) => {
|
|
12876
13373
|
const updateGroupPermissions = exports.useChatStore((s) => s.updateGroupPermissions);
|
|
12877
|
-
const
|
|
12878
|
-
const [
|
|
12879
|
-
|
|
13374
|
+
const { settings, isGroupPermissionLocked } = useEffectiveSettingsOptional();
|
|
13375
|
+
const [permissions, setPermissions] = React3.useState(null);
|
|
13376
|
+
const [isSaving, setIsSaving] = React3.useState(false);
|
|
13377
|
+
React3.useEffect(() => {
|
|
12880
13378
|
if (conversationInfo?.groupPermissions) {
|
|
12881
13379
|
setPermissions(conversationInfo.groupPermissions);
|
|
13380
|
+
return;
|
|
13381
|
+
}
|
|
13382
|
+
if (isOpen) {
|
|
13383
|
+
setPermissions({ ...settings.groupPolicy.defaults });
|
|
12882
13384
|
}
|
|
12883
|
-
}, [conversationInfo]);
|
|
13385
|
+
}, [conversationInfo, isOpen, settings.groupPolicy.defaults]);
|
|
12884
13386
|
if (!conversationId || !permissions) return null;
|
|
12885
13387
|
const handleToggle = (key) => {
|
|
13388
|
+
if (isGroupPermissionLocked(key)) return;
|
|
12886
13389
|
setPermissions((prev) => prev ? { ...prev, [key]: !prev[key] } : null);
|
|
12887
13390
|
};
|
|
12888
13391
|
const handleSave = async () => {
|
|
@@ -12914,31 +13417,43 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
|
|
|
12914
13417
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(chatSheetBodyClass, "flex flex-col px-2.5 py-2"), children: [
|
|
12915
13418
|
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "mb-2.5 flex-1", children: [
|
|
12916
13419
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-1 px-0.5 text-[10px] font-semibold uppercase tracking-wide text-(--chat-muted)", children: "Permissions" }),
|
|
12917
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-(--chat-border) px-3", children: permissionItems.map((item, index) =>
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
13420
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-(--chat-border) px-3", children: permissionItems.map((item, index) => {
|
|
13421
|
+
const locked = isGroupPermissionLocked(item.key);
|
|
13422
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13423
|
+
"div",
|
|
13424
|
+
{
|
|
13425
|
+
className: cn(
|
|
13426
|
+
"flex items-start justify-between gap-3 py-2.5",
|
|
13427
|
+
index < permissionItems.length - 1 && "border-b border-(--chat-border)"
|
|
13428
|
+
),
|
|
13429
|
+
children: [
|
|
13430
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-0.5", children: [
|
|
13431
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[12px] font-semibold leading-snug text-(--chat-text)", children: item.label }),
|
|
13432
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] leading-relaxed text-(--chat-muted)", children: item.desc }),
|
|
13433
|
+
locked ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-medium text-(--chat-theme)", children: "Locked by administrator" }) : null
|
|
13434
|
+
] }),
|
|
13435
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13436
|
+
AdminPermissionTooltip,
|
|
13437
|
+
{
|
|
13438
|
+
disabled: locked,
|
|
13439
|
+
message: exports.ADMIN_PERMISSION_DENIED_MESSAGE,
|
|
13440
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13441
|
+
Switch,
|
|
13442
|
+
{
|
|
13443
|
+
size: "sm",
|
|
13444
|
+
className: "mt-0.5 shrink-0 data-[state=checked]:bg-(--chat-theme) data-[state=unchecked]:bg-(--chat-border)",
|
|
13445
|
+
disabled: locked,
|
|
13446
|
+
checked: item.inverted ? !permissions[item.key] : permissions[item.key],
|
|
13447
|
+
onCheckedChange: () => handleToggle(item.key)
|
|
13448
|
+
}
|
|
13449
|
+
)
|
|
13450
|
+
}
|
|
13451
|
+
)
|
|
13452
|
+
]
|
|
13453
|
+
},
|
|
13454
|
+
item.key
|
|
13455
|
+
);
|
|
13456
|
+
}) })
|
|
12942
13457
|
] }),
|
|
12943
13458
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky bottom-0 border-t border-(--chat-border) bg-(--chat-surface) px-0.5 pt-2.5 pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12944
13459
|
Button,
|
|
@@ -12964,51 +13479,61 @@ var PermissionDrawer_default = PermissionDrawer;
|
|
|
12964
13479
|
// src/chat/header/admins-drawer/useAdminsDrawer.ts
|
|
12965
13480
|
init_useStore();
|
|
12966
13481
|
function useAdminsDrawer({ conversationId, conversationInfo }) {
|
|
12967
|
-
const [searchQuery, setSearchQuery] =
|
|
12968
|
-
const [isManaging, setIsManaging] =
|
|
13482
|
+
const [searchQuery, setSearchQuery] = React3.useState("");
|
|
13483
|
+
const [isManaging, setIsManaging] = React3.useState(null);
|
|
12969
13484
|
const manageGroupAdmins = exports.useChatStore((s) => s.manageGroupAdmins);
|
|
12970
13485
|
const { isOwner } = useGroupInfo(conversationId);
|
|
12971
|
-
const
|
|
13486
|
+
const { settings } = useEffectiveSettingsOptional();
|
|
13487
|
+
const maxAdmins = settings.maxAdminsPerGroup;
|
|
13488
|
+
const participants = React3.useMemo(
|
|
12972
13489
|
() => conversationInfo?.participants ?? [],
|
|
12973
13490
|
[conversationInfo?.participants]
|
|
12974
13491
|
);
|
|
12975
|
-
const admins =
|
|
13492
|
+
const admins = React3.useMemo(
|
|
12976
13493
|
() => conversationInfo?.groupAdmins ?? [],
|
|
12977
13494
|
[conversationInfo?.groupAdmins]
|
|
12978
13495
|
);
|
|
12979
|
-
const ownerId =
|
|
13496
|
+
const ownerId = React3.useMemo(() => {
|
|
12980
13497
|
if (!conversationInfo?.owner) return null;
|
|
12981
13498
|
return typeof conversationInfo.owner === "object" && conversationInfo.owner !== null ? conversationInfo.owner._id || conversationInfo.owner.id : conversationInfo.owner;
|
|
12982
13499
|
}, [conversationInfo?.owner]);
|
|
12983
|
-
const adminIds =
|
|
13500
|
+
const adminIds = React3.useMemo(
|
|
12984
13501
|
() => new Set(
|
|
12985
13502
|
admins.map((a) => typeof a === "string" ? a : a._id).filter((id) => Boolean(id))
|
|
12986
13503
|
),
|
|
12987
13504
|
[admins]
|
|
12988
13505
|
);
|
|
12989
|
-
const isAdmin =
|
|
12990
|
-
const filteredParticipants =
|
|
13506
|
+
const isAdmin = React3.useCallback((userId) => adminIds.has(userId), [adminIds]);
|
|
13507
|
+
const filteredParticipants = React3.useMemo(() => {
|
|
12991
13508
|
if (!searchQuery.trim()) return participants;
|
|
12992
13509
|
return participants.filter(
|
|
12993
13510
|
(p) => p.name?.toLowerCase().includes(searchQuery.toLowerCase()) || p.email?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
12994
13511
|
);
|
|
12995
13512
|
}, [participants, searchQuery]);
|
|
12996
|
-
const adminParticipants =
|
|
13513
|
+
const adminParticipants = React3.useMemo(
|
|
12997
13514
|
() => filteredParticipants.filter((p) => {
|
|
12998
13515
|
const id = typeof p === "string" ? p : p._id;
|
|
12999
13516
|
return id && (adminIds.has(id) || id === ownerId);
|
|
13000
13517
|
}),
|
|
13001
13518
|
[filteredParticipants, adminIds, ownerId]
|
|
13002
13519
|
);
|
|
13003
|
-
const promotableParticipants =
|
|
13520
|
+
const promotableParticipants = React3.useMemo(
|
|
13004
13521
|
() => filteredParticipants.filter((p) => {
|
|
13005
13522
|
const id = typeof p === "string" ? p : p._id;
|
|
13006
13523
|
return id && id !== ownerId && !adminIds.has(id);
|
|
13007
13524
|
}),
|
|
13008
13525
|
[filteredParticipants, adminIds, ownerId]
|
|
13009
13526
|
);
|
|
13527
|
+
const adminCount = admins.length + (ownerId ? 1 : 0);
|
|
13528
|
+
const atAdminLimit = adminCount >= maxAdmins;
|
|
13010
13529
|
const handleManageAdmin = async (userId, type) => {
|
|
13011
13530
|
if (!conversationId) return;
|
|
13531
|
+
if (type === "add" && adminCount >= maxAdmins) {
|
|
13532
|
+
exports.useChatStore.getState().handleAppError(
|
|
13533
|
+
`You can have up to ${maxAdmins} admins in this group.`
|
|
13534
|
+
);
|
|
13535
|
+
return;
|
|
13536
|
+
}
|
|
13012
13537
|
setIsManaging(userId);
|
|
13013
13538
|
try {
|
|
13014
13539
|
await manageGroupAdmins({
|
|
@@ -13020,7 +13545,6 @@ function useAdminsDrawer({ conversationId, conversationInfo }) {
|
|
|
13020
13545
|
setIsManaging(null);
|
|
13021
13546
|
}
|
|
13022
13547
|
};
|
|
13023
|
-
const adminCount = admins.length + (ownerId ? 1 : 0);
|
|
13024
13548
|
return {
|
|
13025
13549
|
searchQuery,
|
|
13026
13550
|
setSearchQuery,
|
|
@@ -13032,6 +13556,8 @@ function useAdminsDrawer({ conversationId, conversationInfo }) {
|
|
|
13032
13556
|
promotableParticipants,
|
|
13033
13557
|
handleManageAdmin,
|
|
13034
13558
|
adminCount,
|
|
13559
|
+
maxAdmins,
|
|
13560
|
+
atAdminLimit,
|
|
13035
13561
|
hasRequiredData: Boolean(conversationId && conversationInfo)
|
|
13036
13562
|
};
|
|
13037
13563
|
}
|
|
@@ -13044,6 +13570,8 @@ function AdminParticipantRow({
|
|
|
13044
13570
|
isAdmin,
|
|
13045
13571
|
showPromote,
|
|
13046
13572
|
showDemote,
|
|
13573
|
+
promoteDisabled = false,
|
|
13574
|
+
promoteDisabledReason,
|
|
13047
13575
|
isOwnerViewer,
|
|
13048
13576
|
isManaging,
|
|
13049
13577
|
onManageAdmin
|
|
@@ -13084,14 +13612,24 @@ function AdminParticipantRow({
|
|
|
13084
13612
|
}
|
|
13085
13613
|
),
|
|
13086
13614
|
showPromote && isOwnerViewer && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13087
|
-
|
|
13615
|
+
AdminPermissionTooltip,
|
|
13088
13616
|
{
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13617
|
+
disabled: promoteDisabled,
|
|
13618
|
+
message: promoteDisabledReason,
|
|
13619
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13620
|
+
Button,
|
|
13621
|
+
{
|
|
13622
|
+
variant: "ghost",
|
|
13623
|
+
size: "sm",
|
|
13624
|
+
className: "size-7 rounded-md p-0 text-(--chat-muted) hover:bg-(--chat-theme-10) hover:text-(--chat-theme) disabled:opacity-40",
|
|
13625
|
+
onClick: () => {
|
|
13626
|
+
if (promoteDisabled) return;
|
|
13627
|
+
onManageAdmin(memberId, "add");
|
|
13628
|
+
},
|
|
13629
|
+
disabled: isManaging === memberId || promoteDisabled,
|
|
13630
|
+
children: isManaging === memberId ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserPlus, { size: 13 })
|
|
13631
|
+
}
|
|
13632
|
+
)
|
|
13095
13633
|
}
|
|
13096
13634
|
)
|
|
13097
13635
|
] })
|
|
@@ -13115,7 +13653,9 @@ function AdminParticipantList({
|
|
|
13115
13653
|
isAdmin,
|
|
13116
13654
|
onManageAdmin,
|
|
13117
13655
|
showPromote,
|
|
13118
|
-
showDemoteForAdmins
|
|
13656
|
+
showDemoteForAdmins,
|
|
13657
|
+
promoteDisabled = false,
|
|
13658
|
+
promoteDisabledReason
|
|
13119
13659
|
}) {
|
|
13120
13660
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: members.map((member, index) => {
|
|
13121
13661
|
const { memberId, memberName, memberEmail, memberImage } = getMemberFields(member);
|
|
@@ -13133,6 +13673,8 @@ function AdminParticipantList({
|
|
|
13133
13673
|
isAdmin: userIsAdmin,
|
|
13134
13674
|
showPromote: showPromote && !userIsAdmin && !userIsOwner,
|
|
13135
13675
|
showDemote: showDemoteForAdmins ? userIsAdmin && !userIsOwner : false,
|
|
13676
|
+
promoteDisabled,
|
|
13677
|
+
promoteDisabledReason,
|
|
13136
13678
|
isOwnerViewer,
|
|
13137
13679
|
isManaging,
|
|
13138
13680
|
onManageAdmin
|
|
@@ -13152,6 +13694,8 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13152
13694
|
promotableParticipants,
|
|
13153
13695
|
handleManageAdmin,
|
|
13154
13696
|
adminCount,
|
|
13697
|
+
maxAdmins,
|
|
13698
|
+
atAdminLimit,
|
|
13155
13699
|
hasRequiredData
|
|
13156
13700
|
} = useAdminsDrawer({ conversationId, conversationInfo });
|
|
13157
13701
|
if (!hasRequiredData) return null;
|
|
@@ -13171,7 +13715,10 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13171
13715
|
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: chatSheetTitleClass, children: "Group Administrators" }),
|
|
13172
13716
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-(--chat-theme-10) px-2 py-0.5 text-[11px] font-medium leading-none text-(--chat-theme)", children: adminCount })
|
|
13173
13717
|
] }),
|
|
13174
|
-
/* @__PURE__ */ jsxRuntime.
|
|
13718
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: chatSheetSubtitleClass, children: [
|
|
13719
|
+
"Manage who can adjust group settings and members",
|
|
13720
|
+
maxAdmins ? ` (max ${maxAdmins}).` : "."
|
|
13721
|
+
] })
|
|
13175
13722
|
] }),
|
|
13176
13723
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(chatSheetBodyClass, "px-2.5 py-2"), children: [
|
|
13177
13724
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2.5 px-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -13214,7 +13761,9 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13214
13761
|
ownerId,
|
|
13215
13762
|
isAdmin,
|
|
13216
13763
|
onManageAdmin: handleManageAdmin,
|
|
13217
|
-
showPromote: true
|
|
13764
|
+
showPromote: true,
|
|
13765
|
+
promoteDisabled: atAdminLimit,
|
|
13766
|
+
promoteDisabledReason: `Maximum ${maxAdmins} admins allowed in this group.`
|
|
13218
13767
|
}
|
|
13219
13768
|
) })
|
|
13220
13769
|
] }),
|
|
@@ -13231,7 +13780,9 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13231
13780
|
isAdmin,
|
|
13232
13781
|
onManageAdmin: handleManageAdmin,
|
|
13233
13782
|
showPromote: true,
|
|
13234
|
-
showDemoteForAdmins: true
|
|
13783
|
+
showDemoteForAdmins: true,
|
|
13784
|
+
promoteDisabled: atAdminLimit,
|
|
13785
|
+
promoteDisabledReason: `Maximum ${maxAdmins} admins allowed in this group.`
|
|
13235
13786
|
}
|
|
13236
13787
|
) })
|
|
13237
13788
|
] }),
|
|
@@ -13247,21 +13798,24 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13247
13798
|
var AdminsDrawer_default = AdminsDrawer;
|
|
13248
13799
|
init_useStore();
|
|
13249
13800
|
var MembersDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo }) => {
|
|
13250
|
-
const [searchQuery, setSearchQuery] =
|
|
13251
|
-
const [isManaging, setIsManaging] =
|
|
13801
|
+
const [searchQuery, setSearchQuery] = React3.useState("");
|
|
13802
|
+
const [isManaging, setIsManaging] = React3.useState(null);
|
|
13252
13803
|
const allUsers = exports.useChatStore((s) => s.allUsers);
|
|
13253
13804
|
const manageGroupMembers = exports.useChatStore((s) => s.manageGroupMembers);
|
|
13254
13805
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
13255
|
-
const filteredUsers =
|
|
13806
|
+
const filteredUsers = React3.useMemo(() => {
|
|
13256
13807
|
if (!searchQuery.trim()) return allUsers;
|
|
13257
13808
|
return allUsers.filter(
|
|
13258
13809
|
(u) => u.name?.toLowerCase().includes(searchQuery.toLowerCase()) || u.email?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
13259
13810
|
);
|
|
13260
13811
|
}, [allUsers, searchQuery]);
|
|
13261
13812
|
const { userPermissions } = useGroupInfo(conversationId);
|
|
13813
|
+
const { settings } = useEffectiveSettingsOptional();
|
|
13814
|
+
const maxParticipants = settings.maxParticipantsPerGroup;
|
|
13262
13815
|
if (!conversationId || !conversationInfo) return null;
|
|
13263
13816
|
const participants = conversationInfo.participants || [];
|
|
13264
13817
|
const admins = conversationInfo.groupAdmins || [];
|
|
13818
|
+
const atParticipantLimit = participants.length >= maxParticipants;
|
|
13265
13819
|
let ownerId = null;
|
|
13266
13820
|
if (conversationInfo.owner) {
|
|
13267
13821
|
ownerId = typeof conversationInfo.owner === "object" && conversationInfo.owner !== null ? conversationInfo.owner._id || conversationInfo.owner.id : conversationInfo.owner;
|
|
@@ -13315,14 +13869,24 @@ var MembersDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13315
13869
|
}
|
|
13316
13870
|
),
|
|
13317
13871
|
options.showAdd && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13318
|
-
|
|
13872
|
+
AdminPermissionTooltip,
|
|
13319
13873
|
{
|
|
13320
|
-
|
|
13321
|
-
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13874
|
+
disabled: atParticipantLimit,
|
|
13875
|
+
message: `Maximum ${maxParticipants} participants allowed in this group.`,
|
|
13876
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13877
|
+
Button,
|
|
13878
|
+
{
|
|
13879
|
+
variant: "ghost",
|
|
13880
|
+
size: "sm",
|
|
13881
|
+
className: "size-7 rounded-md p-0 text-(--chat-muted) hover:bg-(--chat-theme-10) hover:text-(--chat-theme) disabled:opacity-40",
|
|
13882
|
+
onClick: () => {
|
|
13883
|
+
if (atParticipantLimit) return;
|
|
13884
|
+
handleManageMember(memberId, "add");
|
|
13885
|
+
},
|
|
13886
|
+
disabled: isManaging === memberId || atParticipantLimit,
|
|
13887
|
+
children: isManaging === memberId ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserPlus, { size: 13 })
|
|
13888
|
+
}
|
|
13889
|
+
)
|
|
13326
13890
|
}
|
|
13327
13891
|
)
|
|
13328
13892
|
] })
|
|
@@ -13344,7 +13908,11 @@ var MembersDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
|
|
|
13344
13908
|
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: chatSheetTitleClass, children: "Group Management" }),
|
|
13345
13909
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-(--chat-theme-10) px-2 py-0.5 text-[11px] font-medium leading-none text-(--chat-theme)", children: participants.length })
|
|
13346
13910
|
] }),
|
|
13347
|
-
/* @__PURE__ */ jsxRuntime.
|
|
13911
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: chatSheetSubtitleClass, children: [
|
|
13912
|
+
"Manage members and invite people (max ",
|
|
13913
|
+
maxParticipants,
|
|
13914
|
+
")."
|
|
13915
|
+
] })
|
|
13348
13916
|
] }),
|
|
13349
13917
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(chatSheetBodyClass, "px-2.5 py-2"), children: [
|
|
13350
13918
|
!searchQuery && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "mb-2.5", children: [
|
|
@@ -13465,8 +14033,8 @@ var ChatActionModal_default = ChatActionModal;
|
|
|
13465
14033
|
// src/chat/channel-header/useChannelHeader.ts
|
|
13466
14034
|
init_useStore();
|
|
13467
14035
|
function useDebounce(value, delay) {
|
|
13468
|
-
const [debouncedValue, setDebouncedValue] =
|
|
13469
|
-
|
|
14036
|
+
const [debouncedValue, setDebouncedValue] = React3.useState(value);
|
|
14037
|
+
React3.useEffect(() => {
|
|
13470
14038
|
const timer = setTimeout(() => setDebouncedValue(value), delay);
|
|
13471
14039
|
return () => {
|
|
13472
14040
|
clearTimeout(timer);
|
|
@@ -13486,7 +14054,9 @@ init_store_helpers();
|
|
|
13486
14054
|
function useBlockUser(activeChannel, conversationId, onActiveChannelPatch) {
|
|
13487
14055
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
13488
14056
|
const composerDisabledByConversation = exports.useChatStore((s) => s.composerDisabledByConversation);
|
|
13489
|
-
const
|
|
14057
|
+
const { getBlockUsersGate } = useEffectiveSettingsOptional();
|
|
14058
|
+
const blockUsersGate = getBlockUsersGate();
|
|
14059
|
+
const [isBlocking, setIsBlocking] = React3.useState(false);
|
|
13490
14060
|
const resolvedConversationId = conversationId ?? activeChannel?.conversationId ?? null;
|
|
13491
14061
|
const composerDisabledReason = resolvedConversationId ? composerDisabledByConversation[resolvedConversationId] : void 0;
|
|
13492
14062
|
const isBlockedFromConversation = exports.useChatStore((s) => {
|
|
@@ -13504,9 +14074,15 @@ function useBlockUser(activeChannel, conversationId, onActiveChannelPatch) {
|
|
|
13504
14074
|
return !!conv?.isBlocked || !!activeChannel.isBlocked;
|
|
13505
14075
|
});
|
|
13506
14076
|
const isBlocked = isBlockedFromConversation || !activeChannel?.isGroup && !!composerDisabledReason && /block/i.test(composerDisabledReason);
|
|
13507
|
-
const toggleBlock =
|
|
14077
|
+
const toggleBlock = React3.useCallback(async () => {
|
|
13508
14078
|
if (!activeChannel?.id || activeChannel.isGroup) return false;
|
|
13509
14079
|
const nextBlocked = !isBlocked;
|
|
14080
|
+
if (nextBlocked && !blockUsersGate.enabled) {
|
|
14081
|
+
exports.useChatStore.getState().handleAppError(
|
|
14082
|
+
blockUsersGate.disabledReason || "Blocking users is disabled by your administrator."
|
|
14083
|
+
);
|
|
14084
|
+
return false;
|
|
14085
|
+
}
|
|
13510
14086
|
const type = nextBlocked ? "block" : "unblock";
|
|
13511
14087
|
try {
|
|
13512
14088
|
setIsBlocking(true);
|
|
@@ -13527,8 +14103,8 @@ function useBlockUser(activeChannel, conversationId, onActiveChannelPatch) {
|
|
|
13527
14103
|
} finally {
|
|
13528
14104
|
setIsBlocking(false);
|
|
13529
14105
|
}
|
|
13530
|
-
}, [activeChannel, isBlocked, onActiveChannelPatch, resolvedConversationId]);
|
|
13531
|
-
return { isBlocked, isBlocking, toggleBlock };
|
|
14106
|
+
}, [activeChannel, isBlocked, onActiveChannelPatch, resolvedConversationId, blockUsersGate]);
|
|
14107
|
+
return { isBlocked, isBlocking, toggleBlock, blockUsersGate };
|
|
13532
14108
|
}
|
|
13533
14109
|
|
|
13534
14110
|
// src/chat/channel-header/useChannelHeader.ts
|
|
@@ -13561,8 +14137,8 @@ function useChannelHeader({
|
|
|
13561
14137
|
onBack,
|
|
13562
14138
|
onActiveChannelPatch
|
|
13563
14139
|
}) {
|
|
13564
|
-
const [state, setState] =
|
|
13565
|
-
const updateState =
|
|
14140
|
+
const [state, setState] = React3.useState(initialState2);
|
|
14141
|
+
const updateState = React3.useCallback((updates) => {
|
|
13566
14142
|
setState((prev) => ({ ...prev, ...updates }));
|
|
13567
14143
|
}, []);
|
|
13568
14144
|
const { formatLongDate } = useChatLocale();
|
|
@@ -13602,7 +14178,7 @@ function useChannelHeader({
|
|
|
13602
14178
|
const setSearchedMessageId = exports.useChatStore((s) => s.setSearchedMessageId);
|
|
13603
14179
|
const isSearchActive = exports.useChatStore((s) => s.isSearchActive);
|
|
13604
14180
|
const debouncedSearch = useDebounce(state.searchQuery, 800);
|
|
13605
|
-
const handleSearch =
|
|
14181
|
+
const handleSearch = React3.useCallback(async (query, cursor) => {
|
|
13606
14182
|
if (!conversationId) return;
|
|
13607
14183
|
const isFirstPage = !cursor;
|
|
13608
14184
|
updateState({ isSearching: isFirstPage, isLoadingMoreSearch: !isFirstPage });
|
|
@@ -13623,7 +14199,7 @@ function useChannelHeader({
|
|
|
13623
14199
|
updateState({ isSearching: false, isLoadingMoreSearch: false });
|
|
13624
14200
|
}
|
|
13625
14201
|
}, [conversationId, updateState]);
|
|
13626
|
-
|
|
14202
|
+
React3.useEffect(() => {
|
|
13627
14203
|
if (debouncedSearch && conversationId) {
|
|
13628
14204
|
updateState({ searchCursor: null, searchHasMore: false });
|
|
13629
14205
|
handleSearch(debouncedSearch);
|
|
@@ -13657,32 +14233,32 @@ function useChannelHeader({
|
|
|
13657
14233
|
handleCloseSearch();
|
|
13658
14234
|
};
|
|
13659
14235
|
const canViewMembers = isAdmin || userPermissions.canAddMember || userPermissions.canRemoveMember;
|
|
13660
|
-
const prevIsClearingRef =
|
|
13661
|
-
|
|
14236
|
+
const prevIsClearingRef = React3.useRef(isClearingChat);
|
|
14237
|
+
React3.useEffect(() => {
|
|
13662
14238
|
if (prevIsClearingRef.current === true && !isClearingChat) {
|
|
13663
14239
|
updateState({ isClearChatAlertOpen: false });
|
|
13664
14240
|
}
|
|
13665
14241
|
prevIsClearingRef.current = isClearingChat;
|
|
13666
14242
|
}, [isClearingChat, updateState]);
|
|
13667
|
-
const prevIsDeletingRef =
|
|
13668
|
-
|
|
14243
|
+
const prevIsDeletingRef = React3.useRef(isDeletingConversation);
|
|
14244
|
+
React3.useEffect(() => {
|
|
13669
14245
|
if (prevIsDeletingRef.current === true && !isDeletingConversation) {
|
|
13670
14246
|
updateState({ isDeletingConversationAlertOpen: false });
|
|
13671
14247
|
onBack?.();
|
|
13672
14248
|
}
|
|
13673
14249
|
prevIsDeletingRef.current = isDeletingConversation;
|
|
13674
14250
|
}, [isDeletingConversation, onBack, updateState]);
|
|
13675
|
-
|
|
14251
|
+
React3.useEffect(() => {
|
|
13676
14252
|
if (state.isPinOpen && conversationId) {
|
|
13677
14253
|
fetchPinnedMessages2(conversationId);
|
|
13678
14254
|
}
|
|
13679
14255
|
}, [state.isPinOpen, conversationId, fetchPinnedMessages2]);
|
|
13680
|
-
|
|
14256
|
+
React3.useEffect(() => {
|
|
13681
14257
|
if (state.isFavoriteOpen && conversationId) {
|
|
13682
14258
|
fetchStarredMessages2(conversationId);
|
|
13683
14259
|
}
|
|
13684
14260
|
}, [state.isFavoriteOpen, conversationId, fetchStarredMessages2]);
|
|
13685
|
-
|
|
14261
|
+
React3.useEffect(() => {
|
|
13686
14262
|
if (state.isAttachmentsOpen && conversationId) {
|
|
13687
14263
|
const meta = exports.useChatStore.getState().messagesMetadata[conversationId];
|
|
13688
14264
|
if (!meta?.isFirstPage) {
|
|
@@ -14064,6 +14640,7 @@ var MessageReactions_default = MessageReactions;
|
|
|
14064
14640
|
var MessageToolbar = ({
|
|
14065
14641
|
isSender,
|
|
14066
14642
|
isRecent,
|
|
14643
|
+
isWithinDeleteWindow = isRecent,
|
|
14067
14644
|
isPinned,
|
|
14068
14645
|
isStarred,
|
|
14069
14646
|
isPinPending,
|
|
@@ -14087,7 +14664,7 @@ var MessageToolbar = ({
|
|
|
14087
14664
|
}) => {
|
|
14088
14665
|
const { isDark, scopeClassName, themeStyles } = useChatTheme();
|
|
14089
14666
|
const showDeleteMenu = isSender || hasAttachments || attachmentDeleteMode;
|
|
14090
|
-
const showDeleteForEveryone = isSender &&
|
|
14667
|
+
const showDeleteForEveryone = isSender && isWithinDeleteWindow;
|
|
14091
14668
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14092
14669
|
"div",
|
|
14093
14670
|
{
|
|
@@ -14242,8 +14819,8 @@ function SentAttachmentCaptionModal({
|
|
|
14242
14819
|
canEdit = false,
|
|
14243
14820
|
onSave
|
|
14244
14821
|
}) {
|
|
14245
|
-
const [draft, setDraft] =
|
|
14246
|
-
|
|
14822
|
+
const [draft, setDraft] = React3.useState("");
|
|
14823
|
+
React3.useEffect(() => {
|
|
14247
14824
|
if (open && attachment) {
|
|
14248
14825
|
setDraft(attachment.caption || "");
|
|
14249
14826
|
}
|
|
@@ -14409,16 +14986,68 @@ function resolveForwardItems(selectedKeys, messages) {
|
|
|
14409
14986
|
}
|
|
14410
14987
|
|
|
14411
14988
|
// src/chat/lib/chat-edit-window.ts
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14989
|
+
init_settings_types();
|
|
14990
|
+
|
|
14991
|
+
// src/lib/effective-settings.helpers.ts
|
|
14992
|
+
function minutesToMs(minutes) {
|
|
14993
|
+
return Math.max(0, minutes) * 60 * 1e3;
|
|
14994
|
+
}
|
|
14995
|
+
function getEditWindowMs(timers, isGroup) {
|
|
14996
|
+
return minutesToMs(isGroup ? timers.groupEditMinutes : timers.dmEditMinutes);
|
|
14415
14997
|
}
|
|
14416
|
-
function
|
|
14998
|
+
function getDeleteWindowMs(timers, isGroup) {
|
|
14999
|
+
return minutesToMs(
|
|
15000
|
+
isGroup ? timers.groupDeleteMinutes : timers.dmDeleteMinutes
|
|
15001
|
+
);
|
|
15002
|
+
}
|
|
15003
|
+
function isWithinWindow(createdAt, windowMs) {
|
|
14417
15004
|
if (!createdAt) return false;
|
|
14418
15005
|
const date = new Date(createdAt);
|
|
14419
15006
|
if (isNaN(date.getTime())) return false;
|
|
14420
15007
|
const diff = Date.now() - date.getTime();
|
|
14421
|
-
return diff >= 0 && diff <
|
|
15008
|
+
return diff >= 0 && diff < windowMs;
|
|
15009
|
+
}
|
|
15010
|
+
function isWithinMessageEditWindow(createdAt, timers, isGroup) {
|
|
15011
|
+
return isWithinWindow(createdAt, getEditWindowMs(timers, isGroup));
|
|
15012
|
+
}
|
|
15013
|
+
function isWithinMessageDeleteWindow(createdAt, timers, isGroup) {
|
|
15014
|
+
return isWithinWindow(createdAt, getDeleteWindowMs(timers, isGroup));
|
|
15015
|
+
}
|
|
15016
|
+
function allowsAllMimeTypes(allowedMimeTypes) {
|
|
15017
|
+
return allowedMimeTypes.some((pattern) => {
|
|
15018
|
+
const normalized = pattern.trim().toLowerCase();
|
|
15019
|
+
return normalized === "*" || normalized === "*/*";
|
|
15020
|
+
});
|
|
15021
|
+
}
|
|
15022
|
+
function matchesAllowedMimeType(fileType, allowedMimeTypes) {
|
|
15023
|
+
if (!allowedMimeTypes.length) return false;
|
|
15024
|
+
if (allowsAllMimeTypes(allowedMimeTypes)) return true;
|
|
15025
|
+
const mime = (fileType || "application/octet-stream").toLowerCase();
|
|
15026
|
+
return allowedMimeTypes.some((pattern) => {
|
|
15027
|
+
const normalized = pattern.trim().toLowerCase();
|
|
15028
|
+
if (!normalized) return false;
|
|
15029
|
+
if (normalized.endsWith("/*")) {
|
|
15030
|
+
const prefix = normalized.slice(0, -1);
|
|
15031
|
+
return mime.startsWith(prefix);
|
|
15032
|
+
}
|
|
15033
|
+
return mime === normalized;
|
|
15034
|
+
});
|
|
15035
|
+
}
|
|
15036
|
+
function buildAcceptFromMimeTypes(allowedMimeTypes) {
|
|
15037
|
+
if (allowsAllMimeTypes(allowedMimeTypes)) return "";
|
|
15038
|
+
return allowedMimeTypes.map((type) => type.trim()).filter(Boolean).join(",");
|
|
15039
|
+
}
|
|
15040
|
+
function formatFileSizeMB(sizeBytes) {
|
|
15041
|
+
return `${(sizeBytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
15042
|
+
}
|
|
15043
|
+
|
|
15044
|
+
// src/chat/lib/chat-edit-window.ts
|
|
15045
|
+
var FALLBACK_TIMERS = exports.DEFAULT_EFFECTIVE_SETTINGS.messageTimers;
|
|
15046
|
+
function isWithinMessageEditWindow2(createdAt, isGroup, timers = FALLBACK_TIMERS) {
|
|
15047
|
+
return isWithinMessageEditWindow(createdAt, timers, isGroup);
|
|
15048
|
+
}
|
|
15049
|
+
function isWithinMessageDeleteWindow2(createdAt, isGroup, timers = FALLBACK_TIMERS) {
|
|
15050
|
+
return isWithinMessageDeleteWindow(createdAt, timers, isGroup);
|
|
14422
15051
|
}
|
|
14423
15052
|
|
|
14424
15053
|
// src/chat/message-item/useMessageItemActions.ts
|
|
@@ -14443,7 +15072,7 @@ function useMessageItemActions({
|
|
|
14443
15072
|
selectionMode = false,
|
|
14444
15073
|
selectedKeys
|
|
14445
15074
|
}) {
|
|
14446
|
-
const [state, setState] =
|
|
15075
|
+
const [state, setState] = React3.useState({
|
|
14447
15076
|
isHoverMessage: false,
|
|
14448
15077
|
isEditing: false,
|
|
14449
15078
|
editValue: String(message || ""),
|
|
@@ -14456,7 +15085,7 @@ function useMessageItemActions({
|
|
|
14456
15085
|
const updateState = (updates) => {
|
|
14457
15086
|
setState((prev) => ({ ...prev, ...updates }));
|
|
14458
15087
|
};
|
|
14459
|
-
|
|
15088
|
+
React3.useEffect(() => {
|
|
14460
15089
|
setState((prev) => ({ ...prev, editValue: String(message || "") }));
|
|
14461
15090
|
}, [message]);
|
|
14462
15091
|
const emitDmEdit = exports.useChatStore((s) => s.emitDmEdit);
|
|
@@ -14496,6 +15125,9 @@ function useMessageItemActions({
|
|
|
14496
15125
|
const canUnpin = !isPinned || isPinnedByMe;
|
|
14497
15126
|
const { userPermissions } = useGroupInfo(conversationId || null);
|
|
14498
15127
|
const { formatMessageTime } = useChatLocale();
|
|
15128
|
+
const { settings } = useEffectiveSettingsOptional();
|
|
15129
|
+
const messageTimers = settings.messageTimers;
|
|
15130
|
+
const maxPinnedMessages = settings.maxPinnedMessagesPerConversation;
|
|
14499
15131
|
const visibleAttachments = getVisibleAttachments(attachments);
|
|
14500
15132
|
const hasAttachments = visibleAttachments.length > 0;
|
|
14501
15133
|
const hasMultiAttachments = hasAttachments && messageUsesAttachmentSelection({ attachments: visibleAttachments });
|
|
@@ -14512,7 +15144,8 @@ function useMessageItemActions({
|
|
|
14512
15144
|
const hasText = Boolean(message?.trim());
|
|
14513
15145
|
const isSelected = !!mid && !!selectedKeys && isMessageWhollySelected(selectedKeys, mid) && !hasMultiAttachments;
|
|
14514
15146
|
const canEdit = (!isGroup || userPermissions.canEditMessage) && hasText;
|
|
14515
|
-
const isWithinEditWindow = () =>
|
|
15147
|
+
const isWithinEditWindow = () => isWithinMessageEditWindow2(createdAt, isGroup, messageTimers);
|
|
15148
|
+
const isWithinDeleteWindow = () => isWithinMessageDeleteWindow2(createdAt, isGroup, messageTimers);
|
|
14516
15149
|
const canEditAttachmentCaption = isSender && isWithinEditWindow() && (!isGroup || userPermissions.canEditMessage) && !isDeletedForEveryone && !!mid;
|
|
14517
15150
|
const handleAttachmentCaptionClick = (attachment) => {
|
|
14518
15151
|
if (!canEditAttachmentCaption) return;
|
|
@@ -14681,6 +15314,15 @@ function useMessageItemActions({
|
|
|
14681
15314
|
});
|
|
14682
15315
|
}
|
|
14683
15316
|
} else {
|
|
15317
|
+
if (conversationId) {
|
|
15318
|
+
const pinnedCount = (pinnedMessagesByConversation[conversationId] || []).length || exports.useChatStore.getState().liveConversationCounts[conversationId]?.pinnedCount || 0;
|
|
15319
|
+
if (pinnedCount >= maxPinnedMessages) {
|
|
15320
|
+
exports.useChatStore.getState().handleAppError(
|
|
15321
|
+
`You can pin up to ${maxPinnedMessages} messages in this conversation.`
|
|
15322
|
+
);
|
|
15323
|
+
return;
|
|
15324
|
+
}
|
|
15325
|
+
}
|
|
14684
15326
|
if (isGroup) {
|
|
14685
15327
|
if (!conversationId) return;
|
|
14686
15328
|
emitGroupPin({
|
|
@@ -14739,6 +15381,7 @@ function useMessageItemActions({
|
|
|
14739
15381
|
canUnpin,
|
|
14740
15382
|
canEdit,
|
|
14741
15383
|
isWithinEditWindow,
|
|
15384
|
+
isWithinDeleteWindow,
|
|
14742
15385
|
canEditAttachmentCaption,
|
|
14743
15386
|
visibleAttachments,
|
|
14744
15387
|
hasAttachments,
|
|
@@ -14770,7 +15413,7 @@ function useMessageItemActions({
|
|
|
14770
15413
|
}
|
|
14771
15414
|
|
|
14772
15415
|
// src/chat/lib/reply-preview.ts
|
|
14773
|
-
function
|
|
15416
|
+
function normalizeAttachments2(replyTo, loggedUserId) {
|
|
14774
15417
|
const raw = replyTo?.attachments;
|
|
14775
15418
|
if (!Array.isArray(raw) || raw.length === 0) return [];
|
|
14776
15419
|
return raw.map((att, index) => {
|
|
@@ -14783,7 +15426,7 @@ function resolveReplyToMessage(replyTo, messagesById, loggedUserId) {
|
|
|
14783
15426
|
if (typeof replyTo === "object" && (replyTo.content?.trim() || replyTo.attachments?.length)) {
|
|
14784
15427
|
return {
|
|
14785
15428
|
...replyTo,
|
|
14786
|
-
attachments:
|
|
15429
|
+
attachments: normalizeAttachments2(replyTo, loggedUserId)
|
|
14787
15430
|
};
|
|
14788
15431
|
}
|
|
14789
15432
|
const replyId = String(
|
|
@@ -15220,6 +15863,7 @@ function MessageItemView(props) {
|
|
|
15220
15863
|
canUnpin,
|
|
15221
15864
|
canEdit,
|
|
15222
15865
|
isWithinEditWindow,
|
|
15866
|
+
isWithinDeleteWindow,
|
|
15223
15867
|
canEditAttachmentCaption,
|
|
15224
15868
|
visibleAttachments,
|
|
15225
15869
|
hasAttachments,
|
|
@@ -15311,6 +15955,7 @@ function MessageItemView(props) {
|
|
|
15311
15955
|
{
|
|
15312
15956
|
isSender,
|
|
15313
15957
|
isRecent: isWithinEditWindow(),
|
|
15958
|
+
isWithinDeleteWindow: isWithinDeleteWindow(),
|
|
15314
15959
|
messageId: mid,
|
|
15315
15960
|
isPinned,
|
|
15316
15961
|
isStarred,
|
|
@@ -15500,7 +16145,7 @@ function MessageSelectionBar({
|
|
|
15500
16145
|
className
|
|
15501
16146
|
}) {
|
|
15502
16147
|
const { scopeClassName, themeStyles } = useChatTheme();
|
|
15503
|
-
const [isDeleteOpen, setIsDeleteOpen] =
|
|
16148
|
+
const [isDeleteOpen, setIsDeleteOpen] = React3.useState(false);
|
|
15504
16149
|
if (count === 0) return null;
|
|
15505
16150
|
const countLabel = selectionLabel === "files" ? count === 1 ? "file" : "files" : count === 1 ? "message" : "messages";
|
|
15506
16151
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -15605,6 +16250,7 @@ function MessageSelectionBar({
|
|
|
15605
16250
|
}
|
|
15606
16251
|
|
|
15607
16252
|
// src/chat/active-channel-messages/utils.ts
|
|
16253
|
+
init_settings_types();
|
|
15608
16254
|
var getMessageSenderId2 = (msg) => msg ? String(msg.senderId || msg.sender?._id || "") : "";
|
|
15609
16255
|
var isLikelyObjectId = (value) => /^[a-f\d]{24}$/i.test(value);
|
|
15610
16256
|
function resolveGroupSenderDisplay(message, allUsers = [], participants = []) {
|
|
@@ -15636,7 +16282,7 @@ var isSameMessageSide = (a, b, isGroupChat) => {
|
|
|
15636
16282
|
const bId = getMessageSenderId2(b);
|
|
15637
16283
|
return aId !== "" && aId === bId;
|
|
15638
16284
|
};
|
|
15639
|
-
function canDeleteSelectionForEveryone(selectedKeys, messages, isGroup) {
|
|
16285
|
+
function canDeleteSelectionForEveryone(selectedKeys, messages, isGroup, timers = exports.DEFAULT_EFFECTIVE_SETTINGS.messageTimers) {
|
|
15640
16286
|
if (selectedKeys.size === 0) return false;
|
|
15641
16287
|
const parsed = [...selectedKeys].map((key) => parseSelectionKey(key));
|
|
15642
16288
|
const messageIds = new Set(parsed.map((entry) => entry.messageId));
|
|
@@ -15644,7 +16290,7 @@ function canDeleteSelectionForEveryone(selectedKeys, messages, isGroup) {
|
|
|
15644
16290
|
const messageId2 = [...messageIds][0];
|
|
15645
16291
|
const message = messages.find((entry) => String(entry._id || entry.id) === messageId2);
|
|
15646
16292
|
if (!message?.isOwnMessage) return false;
|
|
15647
|
-
if (!
|
|
16293
|
+
if (!isWithinMessageDeleteWindow2(message.timestamp, isGroup, timers)) return false;
|
|
15648
16294
|
const hasAttachmentKey = parsed.some((entry) => entry.attachmentId);
|
|
15649
16295
|
if (!hasAttachmentKey) {
|
|
15650
16296
|
return selectedKeys.size === 1;
|
|
@@ -15808,22 +16454,24 @@ function useActiveChannelMessages({
|
|
|
15808
16454
|
onSelectionModeChange,
|
|
15809
16455
|
conversationInfo
|
|
15810
16456
|
}) {
|
|
15811
|
-
const [selectionMode, setSelectionMode] =
|
|
15812
|
-
const [selectedKeys, setSelectedKeys] =
|
|
16457
|
+
const [selectionMode, setSelectionMode] = React3.useState(false);
|
|
16458
|
+
const [selectedKeys, setSelectedKeys] = React3.useState(/* @__PURE__ */ new Set());
|
|
15813
16459
|
const emitDmDelete = exports.useChatStore((s) => s.emitDmDelete);
|
|
15814
16460
|
const emitGroupDelete = exports.useChatStore((s) => s.emitGroupDelete);
|
|
15815
16461
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
15816
|
-
const
|
|
15817
|
-
const
|
|
15818
|
-
const
|
|
15819
|
-
const
|
|
15820
|
-
const
|
|
15821
|
-
const
|
|
15822
|
-
const
|
|
15823
|
-
const
|
|
15824
|
-
const
|
|
15825
|
-
const
|
|
15826
|
-
const
|
|
16462
|
+
const { settings } = useEffectiveSettingsOptional();
|
|
16463
|
+
const messageTimers = settings.messageTimers;
|
|
16464
|
+
const scrollContainerRef = React3.useRef(null);
|
|
16465
|
+
const bottomRef = React3.useRef(null);
|
|
16466
|
+
const messageListInitializedRef = React3.useRef(false);
|
|
16467
|
+
const previousMessageCountRef = React3.useRef(0);
|
|
16468
|
+
const previousLastMessageIdRef = React3.useRef(null);
|
|
16469
|
+
const [enteringMessageIds, setEnteringMessageIds] = React3.useState(/* @__PURE__ */ new Set());
|
|
16470
|
+
const [showScrollToBottom, setShowScrollToBottom] = React3.useState(false);
|
|
16471
|
+
const stickToBottomRef = React3.useRef(true);
|
|
16472
|
+
const pendingJumpRef = React3.useRef(null);
|
|
16473
|
+
const jumpPagesRef = React3.useRef(0);
|
|
16474
|
+
const [jumpNonce, setJumpNonce] = React3.useState(0);
|
|
15827
16475
|
const { fetchMessages: fetchMessages2, messagesMetadata, deletedForMeIds, searchedMessageId, isSearchActive, setSearchActive, setSearchedMessageId, fetchSearchMessageContext } = exports.useChatStore();
|
|
15828
16476
|
const loggedUserImage = exports.useChatStore((s) => s.loggedUserDetails?.image);
|
|
15829
16477
|
const conversations = exports.useChatStore((s) => s.conversations);
|
|
@@ -15832,29 +16480,29 @@ function useActiveChannelMessages({
|
|
|
15832
16480
|
const mappedApiMessages = conversationMessages.map(
|
|
15833
16481
|
(m) => mapApiMessage(m, activeChannel, conversationId, loggedUserId, activeConversation)
|
|
15834
16482
|
);
|
|
15835
|
-
const displayMessages =
|
|
16483
|
+
const displayMessages = React3.useMemo(
|
|
15836
16484
|
() => mergeChatMessages(mappedApiMessages, localMessages, loggedUserId).filter((m) => !deletedForMeIds.includes(String(m._id || m.id)) && !m.isDeletedForMe).filter((m) => !conversationId || String(m.conversationId || "") === String(conversationId)).sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()),
|
|
15837
16485
|
[mappedApiMessages, localMessages, loggedUserId, deletedForMeIds, conversationId]
|
|
15838
16486
|
);
|
|
15839
|
-
const messagesById =
|
|
16487
|
+
const messagesById = React3.useMemo(
|
|
15840
16488
|
() => new Map(displayMessages.map((message) => [String(message._id || message.id), message])),
|
|
15841
16489
|
[displayMessages]
|
|
15842
16490
|
);
|
|
15843
|
-
const messagesWithResolvedReplies =
|
|
16491
|
+
const messagesWithResolvedReplies = React3.useMemo(
|
|
15844
16492
|
() => displayMessages.map((message) => ({
|
|
15845
16493
|
...message,
|
|
15846
16494
|
replyTo: resolveReplyToMessage(message.replyTo, messagesById, loggedUserId)
|
|
15847
16495
|
})),
|
|
15848
16496
|
[displayMessages, messagesById, loggedUserId]
|
|
15849
16497
|
);
|
|
15850
|
-
const jumpDateBounds =
|
|
16498
|
+
const jumpDateBounds = React3.useMemo(
|
|
15851
16499
|
() => resolveJumpDateBounds(
|
|
15852
16500
|
conversationInfo?.createdAt,
|
|
15853
16501
|
displayMessages[0]?.timestamp
|
|
15854
16502
|
),
|
|
15855
16503
|
[conversationInfo?.createdAt, displayMessages]
|
|
15856
16504
|
);
|
|
15857
|
-
|
|
16505
|
+
React3.useEffect(() => {
|
|
15858
16506
|
const messages = messagesWithResolvedReplies;
|
|
15859
16507
|
const lastMessage = messages[messages.length - 1];
|
|
15860
16508
|
const lastMessageId = lastMessage ? String(lastMessage._id || lastMessage.id) : null;
|
|
@@ -15881,11 +16529,11 @@ function useActiveChannelMessages({
|
|
|
15881
16529
|
}, [messagesWithResolvedReplies]);
|
|
15882
16530
|
const isInitialLoading = isLoading && currentMeta?.isFirstPage;
|
|
15883
16531
|
const isLoadingMore = isLoading && !currentMeta?.isFirstPage;
|
|
15884
|
-
const clearSelection =
|
|
16532
|
+
const clearSelection = React3.useCallback(() => {
|
|
15885
16533
|
setSelectionMode(false);
|
|
15886
16534
|
setSelectedKeys(/* @__PURE__ */ new Set());
|
|
15887
16535
|
}, []);
|
|
15888
|
-
|
|
16536
|
+
React3.useEffect(() => {
|
|
15889
16537
|
clearSelection();
|
|
15890
16538
|
messageListInitializedRef.current = false;
|
|
15891
16539
|
previousMessageCountRef.current = 0;
|
|
@@ -15896,14 +16544,14 @@ function useActiveChannelMessages({
|
|
|
15896
16544
|
stickToBottomRef.current = true;
|
|
15897
16545
|
setShowScrollToBottom(false);
|
|
15898
16546
|
}, [conversationId, clearSelection]);
|
|
15899
|
-
const onSelectionModeChangeRef =
|
|
15900
|
-
|
|
16547
|
+
const onSelectionModeChangeRef = React3.useRef(onSelectionModeChange);
|
|
16548
|
+
React3.useEffect(() => {
|
|
15901
16549
|
onSelectionModeChangeRef.current = onSelectionModeChange;
|
|
15902
16550
|
}, [onSelectionModeChange]);
|
|
15903
|
-
|
|
16551
|
+
React3.useEffect(() => {
|
|
15904
16552
|
onSelectionModeChangeRef.current?.(selectionMode);
|
|
15905
16553
|
}, [selectionMode]);
|
|
15906
|
-
const toggleSelection =
|
|
16554
|
+
const toggleSelection = React3.useCallback((message, attachmentId) => {
|
|
15907
16555
|
const messageId2 = String(message._id || message.id);
|
|
15908
16556
|
if (!messageId2) return;
|
|
15909
16557
|
const useAttachmentSelection = messageUsesAttachmentSelection(message);
|
|
@@ -15916,7 +16564,7 @@ function useActiveChannelMessages({
|
|
|
15916
16564
|
return next;
|
|
15917
16565
|
});
|
|
15918
16566
|
}, []);
|
|
15919
|
-
const enterSelectionMode =
|
|
16567
|
+
const enterSelectionMode = React3.useCallback((message, attachmentId) => {
|
|
15920
16568
|
const messageId2 = String(message._id || message.id);
|
|
15921
16569
|
if (!messageId2) return;
|
|
15922
16570
|
setSelectionMode(true);
|
|
@@ -15930,17 +16578,23 @@ function useActiveChannelMessages({
|
|
|
15930
16578
|
setSelectedKeys((prev) => new Set(prev).add(messageId2));
|
|
15931
16579
|
}, []);
|
|
15932
16580
|
const selectedForwardItems = resolveForwardItems(selectedKeys, displayMessages);
|
|
15933
|
-
const canDeleteForEveryone =
|
|
15934
|
-
() => canDeleteSelectionForEveryone(
|
|
15935
|
-
|
|
16581
|
+
const canDeleteForEveryone = React3.useMemo(
|
|
16582
|
+
() => canDeleteSelectionForEveryone(
|
|
16583
|
+
selectedKeys,
|
|
16584
|
+
displayMessages,
|
|
16585
|
+
!!activeChannel?.isGroup,
|
|
16586
|
+
messageTimers
|
|
16587
|
+
),
|
|
16588
|
+
[selectedKeys, displayMessages, activeChannel?.isGroup, messageTimers]
|
|
15936
16589
|
);
|
|
15937
|
-
const emitSelectionDelete =
|
|
16590
|
+
const emitSelectionDelete = React3.useCallback(
|
|
15938
16591
|
(deleteType) => {
|
|
15939
16592
|
if (!loggedUserDetails || selectedKeys.size === 0) return;
|
|
15940
16593
|
if (deleteType === "everyone" && !canDeleteSelectionForEveryone(
|
|
15941
16594
|
selectedKeys,
|
|
15942
16595
|
displayMessages,
|
|
15943
|
-
!!activeChannel?.isGroup
|
|
16596
|
+
!!activeChannel?.isGroup,
|
|
16597
|
+
messageTimers
|
|
15944
16598
|
)) {
|
|
15945
16599
|
return;
|
|
15946
16600
|
}
|
|
@@ -15981,13 +16635,14 @@ function useActiveChannelMessages({
|
|
|
15981
16635
|
conversationId,
|
|
15982
16636
|
emitGroupDelete,
|
|
15983
16637
|
emitDmDelete,
|
|
15984
|
-
clearSelection
|
|
16638
|
+
clearSelection,
|
|
16639
|
+
messageTimers
|
|
15985
16640
|
]
|
|
15986
16641
|
);
|
|
15987
|
-
const handleBatchDeleteForMe =
|
|
16642
|
+
const handleBatchDeleteForMe = React3.useCallback(() => {
|
|
15988
16643
|
emitSelectionDelete("me");
|
|
15989
16644
|
}, [emitSelectionDelete]);
|
|
15990
|
-
const handleBatchDeleteForEveryone =
|
|
16645
|
+
const handleBatchDeleteForEveryone = React3.useCallback(() => {
|
|
15991
16646
|
emitSelectionDelete("everyone");
|
|
15992
16647
|
}, [emitSelectionDelete]);
|
|
15993
16648
|
const handleBatchForward = () => {
|
|
@@ -16011,7 +16666,7 @@ function useActiveChannelMessages({
|
|
|
16011
16666
|
}
|
|
16012
16667
|
await fetchSearchMessageContext(messageId2, { searchMode: false });
|
|
16013
16668
|
};
|
|
16014
|
-
const handleJumpTo =
|
|
16669
|
+
const handleJumpTo = React3.useCallback((preset, specificDate) => {
|
|
16015
16670
|
stickToBottomRef.current = false;
|
|
16016
16671
|
if (preset === "beginning") {
|
|
16017
16672
|
pendingJumpRef.current = { kind: "beginning" };
|
|
@@ -16032,7 +16687,7 @@ function useActiveChannelMessages({
|
|
|
16032
16687
|
jumpPagesRef.current = 0;
|
|
16033
16688
|
setJumpNonce((n) => n + 1);
|
|
16034
16689
|
}, [jumpDateBounds.minDay, jumpDateBounds.maxDay]);
|
|
16035
|
-
|
|
16690
|
+
React3.useEffect(() => {
|
|
16036
16691
|
const pending = pendingJumpRef.current;
|
|
16037
16692
|
if (!pending || isLoading) return;
|
|
16038
16693
|
const step = resolveJumpStep(
|
|
@@ -16071,13 +16726,13 @@ function useActiveChannelMessages({
|
|
|
16071
16726
|
fetchMessages2,
|
|
16072
16727
|
setSearchedMessageId
|
|
16073
16728
|
]);
|
|
16074
|
-
const updateScrollToBottomVisibility =
|
|
16729
|
+
const updateScrollToBottomVisibility = React3.useCallback((el) => {
|
|
16075
16730
|
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
16076
16731
|
const nearBottom = distanceFromBottom <= 96;
|
|
16077
16732
|
stickToBottomRef.current = nearBottom;
|
|
16078
16733
|
setShowScrollToBottom(!nearBottom);
|
|
16079
16734
|
}, []);
|
|
16080
|
-
const handleScrollToBottom =
|
|
16735
|
+
const handleScrollToBottom = React3.useCallback(() => {
|
|
16081
16736
|
stickToBottomRef.current = true;
|
|
16082
16737
|
if (isSearchActive) {
|
|
16083
16738
|
setSearchActive(false);
|
|
@@ -16104,12 +16759,12 @@ function useActiveChannelMessages({
|
|
|
16104
16759
|
});
|
|
16105
16760
|
}
|
|
16106
16761
|
};
|
|
16107
|
-
|
|
16762
|
+
React3.useLayoutEffect(() => {
|
|
16108
16763
|
if (!isInitialLoading && stickToBottomRef.current && !pendingJumpRef.current) {
|
|
16109
16764
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
16110
16765
|
}
|
|
16111
16766
|
}, [messagesWithResolvedReplies.length, isInitialLoading]);
|
|
16112
|
-
|
|
16767
|
+
React3.useEffect(() => {
|
|
16113
16768
|
if (searchedMessageId && !isLoading) {
|
|
16114
16769
|
stickToBottomRef.current = false;
|
|
16115
16770
|
const container = scrollContainerRef.current;
|
|
@@ -16319,8 +16974,8 @@ function CalendarDayButton({
|
|
|
16319
16974
|
...props
|
|
16320
16975
|
}) {
|
|
16321
16976
|
const defaultClassNames = reactDayPicker.getDefaultClassNames();
|
|
16322
|
-
const ref =
|
|
16323
|
-
|
|
16977
|
+
const ref = React3__namespace.useRef(null);
|
|
16978
|
+
React3__namespace.useEffect(() => {
|
|
16324
16979
|
if (modifiers.focused) ref.current?.focus();
|
|
16325
16980
|
}, [modifiers.focused]);
|
|
16326
16981
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -16352,12 +17007,12 @@ var PRESETS = [
|
|
|
16352
17007
|
];
|
|
16353
17008
|
function ChatDateJumpMenu({ label, minDay, maxDay, onJump }) {
|
|
16354
17009
|
const { scopeClassName } = useChatTheme();
|
|
16355
|
-
const [open, setOpen] =
|
|
16356
|
-
const [showCalendar, setShowCalendar] =
|
|
16357
|
-
const [calendarMonth, setCalendarMonth] =
|
|
17010
|
+
const [open, setOpen] = React3.useState(false);
|
|
17011
|
+
const [showCalendar, setShowCalendar] = React3.useState(false);
|
|
17012
|
+
const [calendarMonth, setCalendarMonth] = React3.useState(() => new Date(maxDay));
|
|
16358
17013
|
const minDate = new Date(minDay);
|
|
16359
17014
|
const maxDate = new Date(maxDay);
|
|
16360
|
-
|
|
17015
|
+
React3.useEffect(() => {
|
|
16361
17016
|
if (showCalendar) setCalendarMonth(new Date(maxDay));
|
|
16362
17017
|
}, [showCalendar, maxDay]);
|
|
16363
17018
|
const queueJump = (preset, specificDate) => {
|
|
@@ -16691,8 +17346,8 @@ function AttachmentCaptionModal({
|
|
|
16691
17346
|
attachment,
|
|
16692
17347
|
onSave
|
|
16693
17348
|
}) {
|
|
16694
|
-
const [draft, setDraft] =
|
|
16695
|
-
|
|
17349
|
+
const [draft, setDraft] = React3.useState("");
|
|
17350
|
+
React3.useEffect(() => {
|
|
16696
17351
|
if (open && attachment) {
|
|
16697
17352
|
setDraft(attachment.caption || "");
|
|
16698
17353
|
}
|
|
@@ -17069,9 +17724,9 @@ function ComposerAttachmentPreview({
|
|
|
17069
17724
|
embedded = false,
|
|
17070
17725
|
maxAttachments = COMPOSER_MAX_ATTACHMENTS
|
|
17071
17726
|
}) {
|
|
17072
|
-
const [captionTargetId, setCaptionTargetId] =
|
|
17073
|
-
const [lightboxState, setLightboxState] =
|
|
17074
|
-
const { media, files, imageMedia, lightboxImages } =
|
|
17727
|
+
const [captionTargetId, setCaptionTargetId] = React3.useState(null);
|
|
17728
|
+
const [lightboxState, setLightboxState] = React3.useState(null);
|
|
17729
|
+
const { media, files, imageMedia, lightboxImages } = React3.useMemo(() => {
|
|
17075
17730
|
const mediaItems = attachments.filter(
|
|
17076
17731
|
(item) => (item.type === "image" || item.type === "video") && item.previewUrl
|
|
17077
17732
|
);
|
|
@@ -17224,7 +17879,6 @@ var getAttachmentType = (file) => {
|
|
|
17224
17879
|
};
|
|
17225
17880
|
|
|
17226
17881
|
// src/chat/channel-message-box/useChannelMessageBox.ts
|
|
17227
|
-
var MAX_ATTACHMENTS = COMPOSER_MAX_ATTACHMENTS;
|
|
17228
17882
|
function useChannelMessageBox({
|
|
17229
17883
|
activeChannel,
|
|
17230
17884
|
conversationId,
|
|
@@ -17238,7 +17892,13 @@ function useChannelMessageBox({
|
|
|
17238
17892
|
conversationId,
|
|
17239
17893
|
onActiveChannelPatch
|
|
17240
17894
|
);
|
|
17241
|
-
const
|
|
17895
|
+
const { settings, getAttachmentsGate } = useEffectiveSettingsOptional();
|
|
17896
|
+
const attachmentsGate = getAttachmentsGate();
|
|
17897
|
+
const maxAttachments = settings.attachments.maxAttachmentsPerMessage;
|
|
17898
|
+
const maxFileSizeBytes = settings.attachments.maxFileSizeMB * 1024 * 1024;
|
|
17899
|
+
const allowedMimeTypes = settings.attachments.allowedMimeTypes;
|
|
17900
|
+
const acceptAttribute = buildAcceptFromMimeTypes(allowedMimeTypes);
|
|
17901
|
+
const [state, setState] = React3.useState({
|
|
17242
17902
|
messageInput: "",
|
|
17243
17903
|
attachments: [],
|
|
17244
17904
|
isFocused: false,
|
|
@@ -17248,8 +17908,8 @@ function useChannelMessageBox({
|
|
|
17248
17908
|
const updateState = (updates) => {
|
|
17249
17909
|
setState((prev) => ({ ...prev, ...updates }));
|
|
17250
17910
|
};
|
|
17251
|
-
const typingTimeoutRef =
|
|
17252
|
-
const conversationIdRef =
|
|
17911
|
+
const typingTimeoutRef = React3.useRef(null);
|
|
17912
|
+
const conversationIdRef = React3.useRef(conversationId);
|
|
17253
17913
|
conversationIdRef.current = conversationId;
|
|
17254
17914
|
const { syncComposerRef } = useConversationDraft(conversationId);
|
|
17255
17915
|
const emitTypingStart = exports.useChatStore((s) => s.emitTypingStart);
|
|
@@ -17260,12 +17920,12 @@ function useChannelMessageBox({
|
|
|
17260
17920
|
const allUsers = exports.useChatStore((s) => s.allUsers);
|
|
17261
17921
|
const composerDisabledByConversation = exports.useChatStore((s) => s.composerDisabledByConversation);
|
|
17262
17922
|
const composerDisabledReason = conversationId ? composerDisabledByConversation[conversationId] : void 0;
|
|
17263
|
-
const fileInputRef =
|
|
17264
|
-
const attachmentsCountRef =
|
|
17265
|
-
|
|
17923
|
+
const fileInputRef = React3.useRef(null);
|
|
17924
|
+
const attachmentsCountRef = React3.useRef(0);
|
|
17925
|
+
React3__namespace.default.useEffect(() => {
|
|
17266
17926
|
attachmentsCountRef.current = state.attachments.length;
|
|
17267
17927
|
}, [state.attachments.length]);
|
|
17268
|
-
|
|
17928
|
+
React3__namespace.default.useEffect(() => {
|
|
17269
17929
|
const draft = {
|
|
17270
17930
|
messageInput: state.messageInput,
|
|
17271
17931
|
attachments: state.attachments
|
|
@@ -17273,7 +17933,7 @@ function useChannelMessageBox({
|
|
|
17273
17933
|
syncComposerRef(draft);
|
|
17274
17934
|
updateConversationDraft(conversationIdRef.current, draft);
|
|
17275
17935
|
}, [state.messageInput, state.attachments, syncComposerRef]);
|
|
17276
|
-
|
|
17936
|
+
React3__namespace.default.useEffect(() => {
|
|
17277
17937
|
if (typingTimeoutRef.current) {
|
|
17278
17938
|
clearTimeout(typingTimeoutRef.current);
|
|
17279
17939
|
typingTimeoutRef.current = null;
|
|
@@ -17333,21 +17993,52 @@ function useChannelMessageBox({
|
|
|
17333
17993
|
const handleFileChange = (e) => {
|
|
17334
17994
|
const files = e.target.files ? Array.from(e.target.files) : [];
|
|
17335
17995
|
if (!files.length) return;
|
|
17996
|
+
if (!attachmentsGate.enabled) {
|
|
17997
|
+
updateState({
|
|
17998
|
+
attachmentError: attachmentsGate.disabledReason || "Attachments are disabled by your administrator."
|
|
17999
|
+
});
|
|
18000
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
18001
|
+
return;
|
|
18002
|
+
}
|
|
17336
18003
|
const currentCount = attachmentsCountRef.current;
|
|
17337
|
-
const remaining =
|
|
18004
|
+
const remaining = maxAttachments - currentCount;
|
|
17338
18005
|
if (remaining <= 0) {
|
|
17339
|
-
updateState({ attachmentError: `Maximum ${
|
|
18006
|
+
updateState({ attachmentError: `Maximum ${maxAttachments} files allowed` });
|
|
18007
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
18008
|
+
return;
|
|
18009
|
+
}
|
|
18010
|
+
const validFiles = [];
|
|
18011
|
+
const rejectionMessages = [];
|
|
18012
|
+
for (const file of files) {
|
|
18013
|
+
if (!matchesAllowedMimeType(file.type, allowedMimeTypes)) {
|
|
18014
|
+
rejectionMessages.push(`"${file.name}" type is not allowed`);
|
|
18015
|
+
continue;
|
|
18016
|
+
}
|
|
18017
|
+
if (file.size > maxFileSizeBytes) {
|
|
18018
|
+
rejectionMessages.push(
|
|
18019
|
+
`"${file.name}" exceeds ${settings.attachments.maxFileSizeMB} MB (got ${formatFileSizeMB(file.size)})`
|
|
18020
|
+
);
|
|
18021
|
+
continue;
|
|
18022
|
+
}
|
|
18023
|
+
validFiles.push(file);
|
|
18024
|
+
}
|
|
18025
|
+
if (validFiles.length === 0) {
|
|
18026
|
+
updateState({
|
|
18027
|
+
attachmentError: rejectionMessages[0] || "Selected files are not allowed"
|
|
18028
|
+
});
|
|
17340
18029
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
17341
18030
|
return;
|
|
17342
18031
|
}
|
|
17343
|
-
if (
|
|
18032
|
+
if (validFiles.length > remaining) {
|
|
17344
18033
|
updateState({
|
|
17345
18034
|
attachmentError: `You can upload only ${remaining} more file${remaining > 1 ? "s" : ""}`
|
|
17346
18035
|
});
|
|
18036
|
+
} else if (rejectionMessages.length > 0) {
|
|
18037
|
+
updateState({ attachmentError: rejectionMessages[0] });
|
|
17347
18038
|
} else {
|
|
17348
18039
|
updateState({ attachmentError: "" });
|
|
17349
18040
|
}
|
|
17350
|
-
const filesToAdd =
|
|
18041
|
+
const filesToAdd = validFiles.slice(0, remaining);
|
|
17351
18042
|
attachmentsCountRef.current = currentCount + filesToAdd.length;
|
|
17352
18043
|
const newAttachments = filesToAdd.map((file) => ({
|
|
17353
18044
|
id: `att-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
@@ -17404,7 +18095,7 @@ function useChannelMessageBox({
|
|
|
17404
18095
|
return {
|
|
17405
18096
|
...prev,
|
|
17406
18097
|
attachments: nextAttachments,
|
|
17407
|
-
attachmentError: nextAttachments.length <
|
|
18098
|
+
attachmentError: nextAttachments.length < maxAttachments ? "" : prev.attachmentError
|
|
17408
18099
|
};
|
|
17409
18100
|
});
|
|
17410
18101
|
};
|
|
@@ -17511,7 +18202,10 @@ function useChannelMessageBox({
|
|
|
17511
18202
|
onlyAdminCanSendMessage,
|
|
17512
18203
|
fileInputRef,
|
|
17513
18204
|
hasUploadingAttachments,
|
|
17514
|
-
maxAttachments
|
|
18205
|
+
maxAttachments,
|
|
18206
|
+
acceptAttribute,
|
|
18207
|
+
attachmentsEnabled: attachmentsGate.enabled,
|
|
18208
|
+
attachmentsDisabledReason: attachmentsGate.disabledReason,
|
|
17515
18209
|
handleInputChange,
|
|
17516
18210
|
handleFileChange,
|
|
17517
18211
|
handleRemoveAttachment,
|
|
@@ -17539,6 +18233,9 @@ var ChannelMessageBoxView = (props) => {
|
|
|
17539
18233
|
fileInputRef,
|
|
17540
18234
|
hasUploadingAttachments,
|
|
17541
18235
|
maxAttachments,
|
|
18236
|
+
acceptAttribute,
|
|
18237
|
+
attachmentsEnabled,
|
|
18238
|
+
attachmentsDisabledReason,
|
|
17542
18239
|
handleInputChange,
|
|
17543
18240
|
handleFileChange,
|
|
17544
18241
|
handleRemoveAttachment,
|
|
@@ -17636,16 +18333,23 @@ var ChannelMessageBoxView = (props) => {
|
|
|
17636
18333
|
),
|
|
17637
18334
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-1.5 p-1.5", children: [
|
|
17638
18335
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17639
|
-
|
|
18336
|
+
AdminPermissionTooltip,
|
|
17640
18337
|
{
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
|
|
17647
|
-
|
|
17648
|
-
|
|
18338
|
+
disabled: !attachmentsEnabled,
|
|
18339
|
+
message: attachmentsDisabledReason,
|
|
18340
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18341
|
+
Button,
|
|
18342
|
+
{
|
|
18343
|
+
type: "button",
|
|
18344
|
+
variant: "ghost",
|
|
18345
|
+
size: "icon",
|
|
18346
|
+
className: "shrink-0 size-9 rounded-xl text-(--chat-muted) transition-all hover:bg-(--chat-hover) hover:text-(--chat-text) disabled:opacity-40",
|
|
18347
|
+
onClick: () => attachmentsEnabled && !hasUploadingAttachments && fileInputRef.current?.click(),
|
|
18348
|
+
disabled: !attachmentsEnabled || hasUploadingAttachments,
|
|
18349
|
+
"aria-label": "Attach files",
|
|
18350
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { size: 16 })
|
|
18351
|
+
}
|
|
18352
|
+
)
|
|
17649
18353
|
}
|
|
17650
18354
|
),
|
|
17651
18355
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -17655,8 +18359,9 @@ var ChannelMessageBoxView = (props) => {
|
|
|
17655
18359
|
ref: fileInputRef,
|
|
17656
18360
|
className: "hidden",
|
|
17657
18361
|
multiple: true,
|
|
17658
|
-
accept:
|
|
17659
|
-
onChange: handleFileChange
|
|
18362
|
+
accept: acceptAttribute || void 0,
|
|
18363
|
+
onChange: handleFileChange,
|
|
18364
|
+
disabled: !attachmentsEnabled
|
|
17660
18365
|
}
|
|
17661
18366
|
),
|
|
17662
18367
|
/* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
|
|
@@ -17735,11 +18440,11 @@ var ChannelMessageBoxView_default = ChannelMessageBoxView;
|
|
|
17735
18440
|
// src/chat/forward-modal/useForwardModal.ts
|
|
17736
18441
|
init_useStore();
|
|
17737
18442
|
function useForwardModal({ isOpen, onClose, items, onForwardComplete }) {
|
|
17738
|
-
const [search, setSearch] =
|
|
17739
|
-
const [debouncedSearch, setDebouncedSearch] =
|
|
17740
|
-
const targetChannelRef =
|
|
17741
|
-
const wasForwardingRef =
|
|
17742
|
-
const completionHandledRef =
|
|
18443
|
+
const [search, setSearch] = React3.useState("");
|
|
18444
|
+
const [debouncedSearch, setDebouncedSearch] = React3.useState("");
|
|
18445
|
+
const targetChannelRef = React3.useRef(null);
|
|
18446
|
+
const wasForwardingRef = React3.useRef(false);
|
|
18447
|
+
const completionHandledRef = React3.useRef(false);
|
|
17743
18448
|
const emitDmForward = exports.useChatStore((s) => s.emitDmForward);
|
|
17744
18449
|
const emitGroupForward = exports.useChatStore((s) => s.emitGroupForward);
|
|
17745
18450
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
@@ -17747,23 +18452,23 @@ function useForwardModal({ isOpen, onClose, items, onForwardComplete }) {
|
|
|
17747
18452
|
const storeConversations = exports.useChatStore((s) => s.conversations);
|
|
17748
18453
|
const allUsers = exports.useChatStore((s) => s.allUsers);
|
|
17749
18454
|
const sourceMessage = items[0]?.message ?? null;
|
|
17750
|
-
const mids =
|
|
18455
|
+
const mids = React3.useMemo(
|
|
17751
18456
|
() => items.map((item) => String(item.message._id || item.message.id || "")).filter(Boolean),
|
|
17752
18457
|
[items]
|
|
17753
18458
|
);
|
|
17754
18459
|
const isForwarding = mids.some((id) => pendingActions[id]?.includes("forward"));
|
|
17755
|
-
const onCloseRef =
|
|
17756
|
-
const onForwardCompleteRef =
|
|
17757
|
-
|
|
18460
|
+
const onCloseRef = React3.useRef(onClose);
|
|
18461
|
+
const onForwardCompleteRef = React3.useRef(onForwardComplete);
|
|
18462
|
+
React3.useEffect(() => {
|
|
17758
18463
|
onCloseRef.current = onClose;
|
|
17759
18464
|
}, [onClose]);
|
|
17760
|
-
|
|
18465
|
+
React3.useEffect(() => {
|
|
17761
18466
|
onForwardCompleteRef.current = onForwardComplete;
|
|
17762
18467
|
}, [onForwardComplete]);
|
|
17763
|
-
const handleOpenChange =
|
|
18468
|
+
const handleOpenChange = React3.useCallback((open) => {
|
|
17764
18469
|
if (!open) onCloseRef.current();
|
|
17765
18470
|
}, []);
|
|
17766
|
-
|
|
18471
|
+
React3.useEffect(() => {
|
|
17767
18472
|
if (isForwarding) {
|
|
17768
18473
|
wasForwardingRef.current = true;
|
|
17769
18474
|
const timeout = setTimeout(() => {
|
|
@@ -17781,7 +18486,7 @@ function useForwardModal({ isOpen, onClose, items, onForwardComplete }) {
|
|
|
17781
18486
|
queueMicrotask(() => onForwardCompleteRef.current(target));
|
|
17782
18487
|
}
|
|
17783
18488
|
}, [isForwarding, mids]);
|
|
17784
|
-
|
|
18489
|
+
React3.useEffect(() => {
|
|
17785
18490
|
if (!isOpen) {
|
|
17786
18491
|
setSearch("");
|
|
17787
18492
|
setDebouncedSearch("");
|
|
@@ -17790,11 +18495,11 @@ function useForwardModal({ isOpen, onClose, items, onForwardComplete }) {
|
|
|
17790
18495
|
completionHandledRef.current = false;
|
|
17791
18496
|
}
|
|
17792
18497
|
}, [isOpen]);
|
|
17793
|
-
|
|
18498
|
+
React3.useEffect(() => {
|
|
17794
18499
|
const handler = setTimeout(() => setDebouncedSearch(search), 400);
|
|
17795
18500
|
return () => clearTimeout(handler);
|
|
17796
18501
|
}, [search]);
|
|
17797
|
-
const mappedChannels =
|
|
18502
|
+
const mappedChannels = React3.useMemo(() => {
|
|
17798
18503
|
const sourceConversationId = sourceMessage?.conversationId ? String(sourceMessage.conversationId) : null;
|
|
17799
18504
|
const query = debouncedSearch.trim().toLowerCase();
|
|
17800
18505
|
return storeConversations.filter((c) => !sourceConversationId || String(c._id) !== sourceConversationId).map((c) => {
|
|
@@ -17922,7 +18627,7 @@ function ForwardModalView(props) {
|
|
|
17922
18627
|
|
|
17923
18628
|
// src/chat/ChatPanelAlerts.tsx
|
|
17924
18629
|
init_useStore();
|
|
17925
|
-
var ChatAlertsContext =
|
|
18630
|
+
var ChatAlertsContext = React3.createContext({});
|
|
17926
18631
|
function ChatAlertsProvider({
|
|
17927
18632
|
children,
|
|
17928
18633
|
value
|
|
@@ -17930,7 +18635,7 @@ function ChatAlertsProvider({
|
|
|
17930
18635
|
return /* @__PURE__ */ jsxRuntime.jsx(ChatAlertsContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 h-full w-full flex-1 flex-col overflow-hidden", children }) });
|
|
17931
18636
|
}
|
|
17932
18637
|
function useChatAlerts() {
|
|
17933
|
-
return
|
|
18638
|
+
return React3.useContext(ChatAlertsContext);
|
|
17934
18639
|
}
|
|
17935
18640
|
var normalizeMessage = (message) => message.trim().toLowerCase();
|
|
17936
18641
|
var alertStyles = {
|
|
@@ -17944,15 +18649,16 @@ var ChatPanelAlerts = () => {
|
|
|
17944
18649
|
const globalAppError = exports.useChatStore((s) => s.globalAppError);
|
|
17945
18650
|
const conversationErrors = exports.useChatStore((s) => s.conversationErrors);
|
|
17946
18651
|
const clearAppError = exports.useChatStore((s) => s.clearAppError);
|
|
18652
|
+
const setRateLimitResetAt = exports.useChatStore((s) => s.setRateLimitResetAt);
|
|
17947
18653
|
const rateLimitResetAt2 = exports.useChatStore((s) => s.rateLimitResetAt);
|
|
17948
|
-
const [now, setNow] =
|
|
18654
|
+
const [now, setNow] = React3.useState(() => Date.now());
|
|
17949
18655
|
const conversationAppError = activeConversationId ? conversationErrors[activeConversationId] ?? null : null;
|
|
17950
|
-
|
|
18656
|
+
React3.useEffect(() => {
|
|
17951
18657
|
if (rateLimitResetAt2 <= Date.now()) return;
|
|
17952
18658
|
const id = window.setInterval(() => setNow(Date.now()), 1e3);
|
|
17953
18659
|
return () => window.clearInterval(id);
|
|
17954
18660
|
}, [rateLimitResetAt2]);
|
|
17955
|
-
const alerts =
|
|
18661
|
+
const alerts = React3.useMemo(() => {
|
|
17956
18662
|
const items = [];
|
|
17957
18663
|
const seen = /* @__PURE__ */ new Set();
|
|
17958
18664
|
const push = (item) => {
|
|
@@ -17980,7 +18686,7 @@ var ChatPanelAlerts = () => {
|
|
|
17980
18686
|
onDismiss: () => clearAppError(activeConversationId)
|
|
17981
18687
|
});
|
|
17982
18688
|
}
|
|
17983
|
-
if (globalAppError?.message) {
|
|
18689
|
+
if (!activeConversationId && globalAppError?.message) {
|
|
17984
18690
|
push({
|
|
17985
18691
|
id: `global-app-error-${globalAppError.type}`,
|
|
17986
18692
|
type: "error",
|
|
@@ -17995,7 +18701,8 @@ var ChatPanelAlerts = () => {
|
|
|
17995
18701
|
id: "rate-limit",
|
|
17996
18702
|
type: "warning",
|
|
17997
18703
|
message: `Too many requests. Please wait ${seconds}s before trying again.`,
|
|
17998
|
-
icon: lucideReact.AlertCircle
|
|
18704
|
+
icon: lucideReact.AlertCircle,
|
|
18705
|
+
onDismiss: () => setRateLimitResetAt(0)
|
|
17999
18706
|
});
|
|
18000
18707
|
}
|
|
18001
18708
|
if (info?.trim()) {
|
|
@@ -18018,7 +18725,8 @@ var ChatPanelAlerts = () => {
|
|
|
18018
18725
|
onDismissError,
|
|
18019
18726
|
onDismissInfo,
|
|
18020
18727
|
info,
|
|
18021
|
-
clearAppError
|
|
18728
|
+
clearAppError,
|
|
18729
|
+
setRateLimitResetAt
|
|
18022
18730
|
]);
|
|
18023
18731
|
if (alerts.length === 0) return null;
|
|
18024
18732
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 space-y-2 border-b border-(--chat-border) bg-(--chat-surface) px-4 py-2.5", children: alerts.map((alert) => {
|
|
@@ -18034,16 +18742,20 @@ var ChatPanelAlerts = () => {
|
|
|
18034
18742
|
children: [
|
|
18035
18743
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
18036
18744
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "min-w-0 flex-1 leading-relaxed", children: alert.message }),
|
|
18037
|
-
alert.onDismiss
|
|
18745
|
+
alert.onDismiss ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
18038
18746
|
"button",
|
|
18039
18747
|
{
|
|
18040
18748
|
type: "button",
|
|
18041
|
-
onClick:
|
|
18749
|
+
onClick: (event) => {
|
|
18750
|
+
event.preventDefault();
|
|
18751
|
+
event.stopPropagation();
|
|
18752
|
+
alert.onDismiss?.();
|
|
18753
|
+
},
|
|
18042
18754
|
className: "shrink-0 rounded-md p-0.5 opacity-70 transition-opacity hover:opacity-100",
|
|
18043
18755
|
"aria-label": "Dismiss",
|
|
18044
18756
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5" })
|
|
18045
18757
|
}
|
|
18046
|
-
)
|
|
18758
|
+
) : null
|
|
18047
18759
|
]
|
|
18048
18760
|
},
|
|
18049
18761
|
alert.id
|
|
@@ -18376,9 +19088,9 @@ var emitToast = (payload, onPush) => {
|
|
|
18376
19088
|
};
|
|
18377
19089
|
var ForegroundPushBridge = ({ onPush }) => {
|
|
18378
19090
|
const lastDM = exports.useChatStore((s) => s.lastDM);
|
|
18379
|
-
const onPushRef =
|
|
19091
|
+
const onPushRef = React3.useRef(onPush);
|
|
18380
19092
|
onPushRef.current = onPush;
|
|
18381
|
-
|
|
19093
|
+
React3.useEffect(() => {
|
|
18382
19094
|
if (!lastDM) return;
|
|
18383
19095
|
if (typeof document !== "undefined" && document.visibilityState !== "visible") {
|
|
18384
19096
|
return;
|
|
@@ -18418,7 +19130,7 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
18418
19130
|
onPushRef.current
|
|
18419
19131
|
);
|
|
18420
19132
|
}, [lastDM]);
|
|
18421
|
-
|
|
19133
|
+
React3.useEffect(() => {
|
|
18422
19134
|
let unsubscribe = null;
|
|
18423
19135
|
let retryTimer = null;
|
|
18424
19136
|
let cancelled = false;
|
|
@@ -18494,7 +19206,7 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
18494
19206
|
window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
18495
19207
|
};
|
|
18496
19208
|
}, []);
|
|
18497
|
-
|
|
19209
|
+
React3.useEffect(() => {
|
|
18498
19210
|
const onOpen = (event) => {
|
|
18499
19211
|
const id = String(
|
|
18500
19212
|
event.detail?.conversationId || ""
|
|
@@ -18571,8 +19283,8 @@ var ChatMain = ({
|
|
|
18571
19283
|
viewportHeight = "full",
|
|
18572
19284
|
viewportClassName
|
|
18573
19285
|
}) => {
|
|
18574
|
-
const clientObj =
|
|
18575
|
-
const uiConfigObj =
|
|
19286
|
+
const clientObj = React3__namespace.default.useMemo(() => ({ id: clientId }), [clientId]);
|
|
19287
|
+
const uiConfigObj = React3__namespace.default.useMemo(
|
|
18576
19288
|
() => ({
|
|
18577
19289
|
...uiConfig || {},
|
|
18578
19290
|
components: { ...uiConfig?.components, ...components },
|
|
@@ -18943,6 +19655,8 @@ var packageDefaultComponents = {
|
|
|
18943
19655
|
};
|
|
18944
19656
|
|
|
18945
19657
|
// src/index.ts
|
|
19658
|
+
init_settings_types();
|
|
19659
|
+
init_api_service();
|
|
18946
19660
|
var index_default = ChatMain_default;
|
|
18947
19661
|
|
|
18948
19662
|
exports.Calendar = Calendar;
|
|
@@ -18956,6 +19670,7 @@ exports.ChatAlertsProvider = ChatAlertsProvider;
|
|
|
18956
19670
|
exports.ChatAvatar = ChatAvatar_default;
|
|
18957
19671
|
exports.ChatCustomizationProvider = ChatCustomizationProvider;
|
|
18958
19672
|
exports.ChatDateJumpMenu = ChatDateJumpMenu;
|
|
19673
|
+
exports.ChatEffectiveSettingsProvider = ChatEffectiveSettingsProvider;
|
|
18959
19674
|
exports.ChatLayout = ChatLayout_default;
|
|
18960
19675
|
exports.ChatLocaleProvider = ChatLocaleProvider;
|
|
18961
19676
|
exports.ChatMain = ChatMain_default;
|
|
@@ -19035,6 +19750,8 @@ exports.useChatFeatures = useChatFeatures;
|
|
|
19035
19750
|
exports.useChatFeaturesOptional = useChatFeaturesOptional;
|
|
19036
19751
|
exports.useChatLocale = useChatLocale;
|
|
19037
19752
|
exports.useChatTheme = useChatTheme;
|
|
19753
|
+
exports.useEffectiveSettings = useEffectiveSettings;
|
|
19754
|
+
exports.useEffectiveSettingsOptional = useEffectiveSettingsOptional;
|
|
19038
19755
|
exports.usePushNotifications = usePushNotifications;
|
|
19039
19756
|
//# sourceMappingURL=index.cjs.map
|
|
19040
19757
|
//# sourceMappingURL=index.cjs.map
|