@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/dist/index.mjs CHANGED
@@ -2,8 +2,8 @@ import { io } from 'socket.io-client';
2
2
  import axios from 'axios';
3
3
  import { create } from 'zustand';
4
4
  import { persist } from 'zustand/middleware';
5
- import * as React2 from 'react';
6
- import React2__default, { createContext, useMemo, useContext, useState, useCallback, useRef, useEffect, useLayoutEffect, useSyncExternalStore } from 'react';
5
+ import * as React3 from 'react';
6
+ import React3__default, { createContext, useMemo, useContext, useState, useCallback, useEffect, useRef, useLayoutEffect, Fragment as Fragment$1, useSyncExternalStore } from 'react';
7
7
  import { Tooltip as Tooltip$1, Slot, Switch as Switch$1, Dialog as Dialog$1, Avatar as Avatar$1, ScrollArea as ScrollArea$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, AlertDialog as AlertDialog$1 } from 'radix-ui';
8
8
  import { clsx } from 'clsx';
9
9
  import { twMerge } from 'tailwind-merge';
@@ -1054,16 +1054,27 @@ var init_connection_actions = __esm({
1054
1054
  setActiveConversationId: (conversationId) => {
1055
1055
  set((state) => {
1056
1056
  const nextId = conversationId ?? null;
1057
- if (String(state.activeConversationId ?? "") === String(nextId ?? "")) {
1057
+ const prevId = state.activeConversationId ?? null;
1058
+ if (String(prevId ?? "") === String(nextId ?? "")) {
1058
1059
  return state;
1059
1060
  }
1061
+ const nextErrors = { ...state.conversationErrors };
1062
+ if (prevId) {
1063
+ delete nextErrors[String(prevId)];
1064
+ }
1060
1065
  if (!nextId) {
1061
- return { activeConversationId: null };
1066
+ return {
1067
+ activeConversationId: null,
1068
+ globalAppError: null,
1069
+ conversationErrors: nextErrors
1070
+ };
1062
1071
  }
1063
1072
  const target = state.conversations.find((c) => String(c._id) === String(nextId));
1064
1073
  const unreadAlreadyZero = !normalizeUnreadCount(target?.unreadCount, state.loggedUserDetails?._id);
1065
1074
  return {
1066
1075
  activeConversationId: nextId,
1076
+ globalAppError: null,
1077
+ conversationErrors: nextErrors,
1067
1078
  conversations: unreadAlreadyZero ? state.conversations : state.conversations.map(
1068
1079
  (c) => String(c._id) === String(nextId) ? { ...c, unreadCount: 0 } : c
1069
1080
  )
@@ -1104,25 +1115,32 @@ var init_connection_actions = __esm({
1104
1115
  type = "rate_limit";
1105
1116
  return;
1106
1117
  }
1118
+ if (conversationId) {
1119
+ set((state) => ({
1120
+ conversationErrors: {
1121
+ ...state.conversationErrors,
1122
+ [conversationId]: { message, type }
1123
+ },
1124
+ globalAppError: null
1125
+ }));
1126
+ return;
1127
+ }
1107
1128
  set({ globalAppError: { message, type } });
1108
1129
  },
1109
1130
  clearAppError: (conversationId) => {
1110
1131
  set((state) => {
1111
- const targetId = conversationId ?? state.activeConversationId;
1112
- if (targetId) {
1132
+ if (conversationId) {
1113
1133
  const nextErrors = { ...state.conversationErrors };
1114
1134
  const nextComposer = { ...state.composerDisabledByConversation };
1115
- delete nextErrors[targetId];
1116
- delete nextComposer[targetId];
1135
+ delete nextErrors[conversationId];
1136
+ delete nextComposer[conversationId];
1117
1137
  return {
1118
1138
  conversationErrors: nextErrors,
1119
1139
  composerDisabledByConversation: nextComposer
1120
1140
  };
1121
1141
  }
1122
1142
  return {
1123
- globalAppError: null,
1124
- conversationErrors: {},
1125
- composerDisabledByConversation: {}
1143
+ globalAppError: null
1126
1144
  };
1127
1145
  });
1128
1146
  },
@@ -1162,6 +1180,7 @@ function resolveChatApiKey(url) {
1162
1180
  }
1163
1181
  if (path.includes("/message/search-messages")) return "searchMessages";
1164
1182
  if (path.includes("/message/searched-message/context")) return "searchMessagesContext";
1183
+ if (path.includes("/settings/effective")) return "effectiveSettings";
1165
1184
  if (path.includes("/conversation/group/create")) return "createGroup";
1166
1185
  if (path.includes("/conversation/group/permission/update")) return "updateGroupPermissions";
1167
1186
  if (path.includes("/conversation/group/information/update")) return "updateGroupInfo";
@@ -1205,7 +1224,8 @@ var init_query_params = __esm({
1205
1224
  "pinnedMessages",
1206
1225
  "starredMessages",
1207
1226
  "searchMessages",
1208
- "searchMessagesContext"
1227
+ "searchMessagesContext",
1228
+ "effectiveSettings"
1209
1229
  ];
1210
1230
  CHAT_API_KEYS = [
1211
1231
  "all",
@@ -1230,8 +1250,8 @@ var init_api_version = __esm({
1230
1250
  "src/services/api/api-version.ts"() {
1231
1251
  init_client();
1232
1252
  DEFAULT_VERSIONS = {
1233
- default: "v1",
1234
- push: "v2"
1253
+ v1: "v1",
1254
+ v2: "v2"
1235
1255
  };
1236
1256
  apiVersions = { ...DEFAULT_VERSIONS };
1237
1257
  normalizeApiVersion = (version) => {
@@ -1250,7 +1270,7 @@ var init_api_version = __esm({
1250
1270
  buildVersionedApiUrl = (path, options) => {
1251
1271
  const root = resolveApiRoot(options?.baseUrl);
1252
1272
  const version = normalizeApiVersion(
1253
- options?.version ?? (options?.service ? apiVersions[options.service] : apiVersions.default)
1273
+ options?.version ?? (options?.service ? apiVersions[options.service] : apiVersions.v1)
1254
1274
  );
1255
1275
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
1256
1276
  if (!root) {
@@ -1260,23 +1280,23 @@ var init_api_version = __esm({
1260
1280
  };
1261
1281
  setChatApiVersions = (config) => {
1262
1282
  if (!config) return;
1263
- if (config.default) {
1264
- apiVersions.default = normalizeApiVersion(config.default);
1283
+ if (config.v1) {
1284
+ apiVersions.v1 = normalizeApiVersion(config.v1);
1265
1285
  }
1266
- if (config.push) {
1267
- apiVersions.push = normalizeApiVersion(config.push);
1286
+ if (config.v2) {
1287
+ apiVersions.v2 = normalizeApiVersion(config.v2);
1268
1288
  }
1269
1289
  };
1270
1290
  getChatApiVersions = () => ({
1271
1291
  ...apiVersions
1272
1292
  });
1273
1293
  setChatPushApiVersion = (version) => {
1274
- apiVersions.push = normalizeApiVersion(version);
1294
+ apiVersions.v2 = normalizeApiVersion(version);
1275
1295
  };
1276
1296
  syncDefaultApiVersionFromBaseUrl = (baseUrl) => {
1277
1297
  const match = String(baseUrl || "").trim().match(/\/(v\d+)\/?$/i);
1278
1298
  if (match?.[1]) {
1279
- apiVersions.default = normalizeApiVersion(match[1]);
1299
+ apiVersions.v1 = normalizeApiVersion(match[1]);
1280
1300
  }
1281
1301
  };
1282
1302
  }
@@ -1421,6 +1441,9 @@ var init_api_constants = __esm({
1421
1441
  SEARCH_MESSAGES: "/message/search-messages",
1422
1442
  SEARCH_MESSAGES_CONTEXT: (messageId2) => `/message/searched-message/context?messageId=${messageId2}`,
1423
1443
  BLOCK_UNBLOCK_USER: "/user/block-unblock"
1444
+ },
1445
+ SETTINGS: {
1446
+ PERMISSIONS: "/settings/effective"
1424
1447
  }
1425
1448
  };
1426
1449
  }
@@ -1457,13 +1480,11 @@ var init_auth_api = __esm({
1457
1480
  });
1458
1481
 
1459
1482
  // src/constants/chat.constants.ts
1460
- var DEFAULT_MESSAGES_LIMIT, DEFAULT_CONVERSATIONS_LIMIT, DM_EDIT_WINDOW_MS, GROUP_EDIT_WINDOW_MS, MAX_ATTACHMENT_CAPTION_LENGTH, ATTACHMENT_FILENAME_TIMESTAMP_LENGTH;
1483
+ var DEFAULT_MESSAGES_LIMIT, DEFAULT_CONVERSATIONS_LIMIT, MAX_ATTACHMENT_CAPTION_LENGTH, ATTACHMENT_FILENAME_TIMESTAMP_LENGTH;
1461
1484
  var init_chat_constants = __esm({
1462
1485
  "src/constants/chat.constants.ts"() {
1463
1486
  DEFAULT_MESSAGES_LIMIT = 20;
1464
1487
  DEFAULT_CONVERSATIONS_LIMIT = 20;
1465
- DM_EDIT_WINDOW_MS = 5 * 60 * 1e3;
1466
- GROUP_EDIT_WINDOW_MS = 10 * 60 * 1e3;
1467
1488
  MAX_ATTACHMENT_CAPTION_LENGTH = 100;
1468
1489
  ATTACHMENT_FILENAME_TIMESTAMP_LENGTH = 13;
1469
1490
  }
@@ -1666,6 +1687,212 @@ var init_uploads_api = __esm({
1666
1687
  }
1667
1688
  });
1668
1689
 
1690
+ // src/types/settings.types.ts
1691
+ var DEFAULT_EFFECTIVE_SETTINGS, ADMIN_PERMISSION_DENIED_MESSAGE, CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE, CALLS_NOT_CONFIGURED_MESSAGE;
1692
+ var init_settings_types = __esm({
1693
+ "src/types/settings.types.ts"() {
1694
+ DEFAULT_EFFECTIVE_SETTINGS = {
1695
+ pushNotificationEnabled: true,
1696
+ videoCallEnabled: true,
1697
+ audioCallEnabled: true,
1698
+ blockUsersEnabled: true,
1699
+ calls: {
1700
+ allowedByPlatform: true,
1701
+ enabled: true,
1702
+ configured: true
1703
+ },
1704
+ groupPolicy: {
1705
+ defaults: {
1706
+ onlyAdminCanSendMessage: false,
1707
+ onlyAdminCanEditInfo: false,
1708
+ senderCanEditMessage: true,
1709
+ allowMemberAdd: true,
1710
+ allowMemberRemove: false,
1711
+ moderationEnabled: false
1712
+ },
1713
+ locked: []
1714
+ },
1715
+ messageTimers: {
1716
+ dmEditMinutes: 5,
1717
+ dmDeleteMinutes: 5,
1718
+ groupEditMinutes: 10,
1719
+ groupDeleteMinutes: 10
1720
+ },
1721
+ attachments: {
1722
+ enabled: true,
1723
+ maxFileSizeMB: 10,
1724
+ allowedMimeTypes: ["image/*", "video/*", "audio/*", "application/pdf"],
1725
+ maxAttachmentsPerMessage: 10
1726
+ },
1727
+ maxAdminsPerGroup: 5,
1728
+ maxParticipantsPerGroup: 100,
1729
+ maxPinnedMessagesPerConversation: 10,
1730
+ groupCreationEnabled: true
1731
+ };
1732
+ ADMIN_PERMISSION_DENIED_MESSAGE = "This feature is disabled by your administrator.";
1733
+ CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE = "Calls are not allowed on this platform. Please contact your administrator.";
1734
+ CALLS_NOT_CONFIGURED_MESSAGE = "Calls are not configured. Please contact your administrator.";
1735
+ }
1736
+ });
1737
+
1738
+ // src/services/api/settings.api.ts
1739
+ function asBoolean(value, fallback) {
1740
+ return typeof value === "boolean" ? value : fallback;
1741
+ }
1742
+ function asPositiveNumber(value, fallback) {
1743
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
1744
+ }
1745
+ function asStringArray(value, fallback) {
1746
+ if (!Array.isArray(value)) return fallback;
1747
+ const next = value.filter((item) => typeof item === "string");
1748
+ return next.length > 0 ? next : fallback;
1749
+ }
1750
+ function normalizeGroupPermissions(value, fallback) {
1751
+ if (!value || typeof value !== "object") return { ...fallback };
1752
+ const raw = value;
1753
+ return {
1754
+ onlyAdminCanSendMessage: asBoolean(
1755
+ raw.onlyAdminCanSendMessage,
1756
+ fallback.onlyAdminCanSendMessage
1757
+ ),
1758
+ onlyAdminCanEditInfo: asBoolean(
1759
+ raw.onlyAdminCanEditInfo,
1760
+ fallback.onlyAdminCanEditInfo
1761
+ ),
1762
+ senderCanEditMessage: asBoolean(
1763
+ raw.senderCanEditMessage,
1764
+ fallback.senderCanEditMessage
1765
+ ),
1766
+ allowMemberAdd: asBoolean(raw.allowMemberAdd, fallback.allowMemberAdd),
1767
+ allowMemberRemove: asBoolean(
1768
+ raw.allowMemberRemove,
1769
+ fallback.allowMemberRemove
1770
+ ),
1771
+ moderationEnabled: asBoolean(
1772
+ raw.moderationEnabled,
1773
+ fallback.moderationEnabled
1774
+ )
1775
+ };
1776
+ }
1777
+ function normalizeCalls(value, fallback) {
1778
+ if (!value || typeof value !== "object") return { ...fallback };
1779
+ const raw = value;
1780
+ return {
1781
+ allowedByPlatform: asBoolean(
1782
+ raw.allowedByPlatform,
1783
+ fallback.allowedByPlatform
1784
+ ),
1785
+ enabled: asBoolean(raw.enabled, fallback.enabled),
1786
+ configured: asBoolean(raw.configured, fallback.configured)
1787
+ };
1788
+ }
1789
+ function normalizeGroupPolicy(value, fallback) {
1790
+ if (!value || typeof value !== "object") {
1791
+ return {
1792
+ defaults: { ...fallback.defaults },
1793
+ locked: [...fallback.locked]
1794
+ };
1795
+ }
1796
+ const raw = value;
1797
+ return {
1798
+ defaults: normalizeGroupPermissions(raw.defaults, fallback.defaults),
1799
+ locked: asStringArray(raw.locked, fallback.locked)
1800
+ };
1801
+ }
1802
+ function normalizeMessageTimers(value, fallback) {
1803
+ if (!value || typeof value !== "object") return { ...fallback };
1804
+ const raw = value;
1805
+ return {
1806
+ dmEditMinutes: asPositiveNumber(raw.dmEditMinutes, fallback.dmEditMinutes),
1807
+ dmDeleteMinutes: asPositiveNumber(
1808
+ raw.dmDeleteMinutes,
1809
+ fallback.dmDeleteMinutes
1810
+ ),
1811
+ groupEditMinutes: asPositiveNumber(
1812
+ raw.groupEditMinutes,
1813
+ fallback.groupEditMinutes
1814
+ ),
1815
+ groupDeleteMinutes: asPositiveNumber(
1816
+ raw.groupDeleteMinutes,
1817
+ fallback.groupDeleteMinutes
1818
+ )
1819
+ };
1820
+ }
1821
+ function normalizeAttachments(value, fallback) {
1822
+ if (!value || typeof value !== "object") return { ...fallback };
1823
+ const raw = value;
1824
+ return {
1825
+ enabled: asBoolean(raw.enabled, fallback.enabled),
1826
+ maxFileSizeMB: asPositiveNumber(raw.maxFileSizeMB, fallback.maxFileSizeMB),
1827
+ allowedMimeTypes: asStringArray(
1828
+ raw.allowedMimeTypes,
1829
+ fallback.allowedMimeTypes
1830
+ ),
1831
+ maxAttachmentsPerMessage: asPositiveNumber(
1832
+ raw.maxAttachmentsPerMessage,
1833
+ fallback.maxAttachmentsPerMessage
1834
+ )
1835
+ };
1836
+ }
1837
+ function normalizeEffectiveSettings(raw) {
1838
+ const payload = raw && typeof raw === "object" ? raw.data ?? raw : null;
1839
+ const source = payload && typeof payload === "object" ? payload : {};
1840
+ const defaults = DEFAULT_EFFECTIVE_SETTINGS;
1841
+ return {
1842
+ pushNotificationEnabled: asBoolean(
1843
+ source.pushNotificationEnabled,
1844
+ defaults.pushNotificationEnabled
1845
+ ),
1846
+ videoCallEnabled: asBoolean(
1847
+ source.videoCallEnabled,
1848
+ defaults.videoCallEnabled
1849
+ ),
1850
+ audioCallEnabled: asBoolean(
1851
+ source.audioCallEnabled,
1852
+ defaults.audioCallEnabled
1853
+ ),
1854
+ blockUsersEnabled: asBoolean(
1855
+ source.blockUsersEnabled,
1856
+ defaults.blockUsersEnabled
1857
+ ),
1858
+ calls: normalizeCalls(source.calls, defaults.calls),
1859
+ groupPolicy: normalizeGroupPolicy(source.groupPolicy, defaults.groupPolicy),
1860
+ messageTimers: normalizeMessageTimers(
1861
+ source.messageTimers,
1862
+ defaults.messageTimers
1863
+ ),
1864
+ attachments: normalizeAttachments(source.attachments, defaults.attachments),
1865
+ maxAdminsPerGroup: asPositiveNumber(
1866
+ source.maxAdminsPerGroup,
1867
+ defaults.maxAdminsPerGroup
1868
+ ),
1869
+ maxParticipantsPerGroup: asPositiveNumber(
1870
+ source.maxParticipantsPerGroup,
1871
+ defaults.maxParticipantsPerGroup
1872
+ ),
1873
+ maxPinnedMessagesPerConversation: asPositiveNumber(
1874
+ source.maxPinnedMessagesPerConversation,
1875
+ defaults.maxPinnedMessagesPerConversation
1876
+ ),
1877
+ groupCreationEnabled: asBoolean(
1878
+ source.groupCreationEnabled,
1879
+ defaults.groupCreationEnabled
1880
+ )
1881
+ };
1882
+ }
1883
+ var fetchEffectiveSettings;
1884
+ var init_settings_api = __esm({
1885
+ "src/services/api/settings.api.ts"() {
1886
+ init_api_constants();
1887
+ init_client();
1888
+ init_settings_types();
1889
+ fetchEffectiveSettings = async () => {
1890
+ const response = await apiClient.get(API_ENDPOINTS.SETTINGS.PERMISSIONS);
1891
+ return normalizeEffectiveSettings(response.data);
1892
+ };
1893
+ }
1894
+ });
1895
+
1669
1896
  // src/services/api/index.ts
1670
1897
  var init_api = __esm({
1671
1898
  "src/services/api/index.ts"() {
@@ -1674,6 +1901,7 @@ var init_api = __esm({
1674
1901
  init_messages_api();
1675
1902
  init_groups_api();
1676
1903
  init_uploads_api();
1904
+ init_settings_api();
1677
1905
  }
1678
1906
  });
1679
1907
 
@@ -4505,6 +4733,150 @@ var useChatCustomizationOptional = () => {
4505
4733
  };
4506
4734
  var useChatFeatures = () => useChatCustomization().features;
4507
4735
  var useChatFeaturesOptional = () => useChatCustomizationOptional().features;
4736
+
4737
+ // src/context/ChatEffectiveSettingsContext.tsx
4738
+ init_settings_api();
4739
+ init_settings_types();
4740
+ var ChatEffectiveSettingsContext = createContext(null);
4741
+ function buildCallGate(settings, featureEnabled) {
4742
+ if (!settings.calls.allowedByPlatform) {
4743
+ return {
4744
+ visible: true,
4745
+ enabled: false,
4746
+ disabledReason: CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE
4747
+ };
4748
+ }
4749
+ if (!settings.calls.configured) {
4750
+ return {
4751
+ visible: true,
4752
+ enabled: false,
4753
+ disabledReason: CALLS_NOT_CONFIGURED_MESSAGE
4754
+ };
4755
+ }
4756
+ if (!settings.calls.enabled) {
4757
+ return {
4758
+ visible: true,
4759
+ enabled: false,
4760
+ disabledReason: ADMIN_PERMISSION_DENIED_MESSAGE
4761
+ };
4762
+ }
4763
+ if (!featureEnabled) {
4764
+ return {
4765
+ visible: true,
4766
+ enabled: false,
4767
+ disabledReason: ADMIN_PERMISSION_DENIED_MESSAGE
4768
+ };
4769
+ }
4770
+ return { visible: true, enabled: true, disabledReason: null };
4771
+ }
4772
+ function ChatEffectiveSettingsProvider({
4773
+ children,
4774
+ enabled = true
4775
+ }) {
4776
+ const [settings, setSettings] = useState(
4777
+ DEFAULT_EFFECTIVE_SETTINGS
4778
+ );
4779
+ const [loading, setLoading] = useState(true);
4780
+ const [error, setError] = useState(null);
4781
+ const refresh = useCallback(async () => {
4782
+ if (!enabled) {
4783
+ setLoading(false);
4784
+ return;
4785
+ }
4786
+ setLoading(true);
4787
+ try {
4788
+ const next = await fetchEffectiveSettings();
4789
+ setSettings(next);
4790
+ setError(null);
4791
+ } catch (err) {
4792
+ console.error("Failed to fetch effective settings:", err);
4793
+ setError(
4794
+ err instanceof Error ? err.message : "Could not load chat permissions"
4795
+ );
4796
+ setSettings(DEFAULT_EFFECTIVE_SETTINGS);
4797
+ } finally {
4798
+ setLoading(false);
4799
+ }
4800
+ }, [enabled]);
4801
+ useEffect(() => {
4802
+ void refresh();
4803
+ }, [refresh]);
4804
+ const value = useMemo(() => {
4805
+ const isGroupPermissionLocked = (key) => settings.groupPolicy.locked.includes(key);
4806
+ return {
4807
+ settings,
4808
+ loading,
4809
+ error,
4810
+ refresh,
4811
+ isGroupPermissionLocked,
4812
+ getAudioCallGate: () => buildCallGate(settings, settings.audioCallEnabled),
4813
+ getVideoCallGate: () => buildCallGate(settings, settings.videoCallEnabled),
4814
+ getPushNotificationGate: () => ({
4815
+ visible: true,
4816
+ enabled: settings.pushNotificationEnabled,
4817
+ disabledReason: settings.pushNotificationEnabled ? null : ADMIN_PERMISSION_DENIED_MESSAGE
4818
+ }),
4819
+ getBlockUsersGate: () => ({
4820
+ visible: true,
4821
+ enabled: settings.blockUsersEnabled,
4822
+ disabledReason: settings.blockUsersEnabled ? null : ADMIN_PERMISSION_DENIED_MESSAGE
4823
+ }),
4824
+ getAttachmentsGate: () => ({
4825
+ visible: true,
4826
+ enabled: settings.attachments.enabled,
4827
+ disabledReason: settings.attachments.enabled ? null : ADMIN_PERMISSION_DENIED_MESSAGE
4828
+ }),
4829
+ getGroupCreationGate: () => ({
4830
+ visible: true,
4831
+ enabled: settings.groupCreationEnabled,
4832
+ disabledReason: settings.groupCreationEnabled ? null : ADMIN_PERMISSION_DENIED_MESSAGE
4833
+ })
4834
+ };
4835
+ }, [settings, loading, error, refresh]);
4836
+ return /* @__PURE__ */ jsx(ChatEffectiveSettingsContext.Provider, { value, children });
4837
+ }
4838
+ function useEffectiveSettings() {
4839
+ const ctx = useContext(ChatEffectiveSettingsContext);
4840
+ if (!ctx) {
4841
+ throw new Error(
4842
+ "useEffectiveSettings must be used within ChatEffectiveSettingsProvider"
4843
+ );
4844
+ }
4845
+ return ctx;
4846
+ }
4847
+ function useEffectiveSettingsOptional() {
4848
+ const ctx = useContext(ChatEffectiveSettingsContext);
4849
+ if (ctx) return ctx;
4850
+ return {
4851
+ settings: DEFAULT_EFFECTIVE_SETTINGS,
4852
+ loading: false,
4853
+ error: null,
4854
+ refresh: async () => void 0,
4855
+ isGroupPermissionLocked: () => false,
4856
+ getAudioCallGate: () => buildCallGate(DEFAULT_EFFECTIVE_SETTINGS, true),
4857
+ getVideoCallGate: () => buildCallGate(DEFAULT_EFFECTIVE_SETTINGS, true),
4858
+ getPushNotificationGate: () => ({
4859
+ visible: true,
4860
+ enabled: true,
4861
+ disabledReason: null
4862
+ }),
4863
+ getBlockUsersGate: () => ({
4864
+ visible: true,
4865
+ enabled: true,
4866
+ disabledReason: null
4867
+ }),
4868
+ getAttachmentsGate: () => ({
4869
+ visible: true,
4870
+ enabled: true,
4871
+ disabledReason: null
4872
+ }),
4873
+ getGroupCreationGate: () => ({
4874
+ visible: true,
4875
+ enabled: true,
4876
+ disabledReason: null
4877
+ })
4878
+ };
4879
+ }
4508
4880
  var ChatContext = createContext(void 0);
4509
4881
  var useChatContext = () => {
4510
4882
  const context = useContext(ChatContext);
@@ -4544,7 +4916,7 @@ var Chat = ({
4544
4916
  const status = useStore((s) => s.status);
4545
4917
  const error = useStore((s) => s.error);
4546
4918
  useChatSync();
4547
- React2__default.useEffect(() => {
4919
+ React3__default.useEffect(() => {
4548
4920
  const clientId = client?.id;
4549
4921
  const initializeChat = async () => {
4550
4922
  if (!clientId || !loggedUserDetails) return;
@@ -4634,28 +5006,28 @@ var Chat = ({
4634
5006
  queryParamApis: queryParamApis ?? ["get"],
4635
5007
  queryParamsByApi: queryParamsByApi ?? {}
4636
5008
  });
4637
- React2__default.useEffect(() => {
5009
+ React3__default.useEffect(() => {
4638
5010
  setChatQueryParams(queryParams);
4639
5011
  setChatQueryParamApis(queryParamApis);
4640
5012
  setChatQueryParamsByApi(queryParamsByApi);
4641
5013
  }, [queryConfigKey]);
4642
- React2__default.useEffect(() => {
5014
+ React3__default.useEffect(() => {
4643
5015
  if (lastDM && onMessageReceived) {
4644
5016
  onMessageReceived(lastDM);
4645
5017
  }
4646
5018
  }, [lastDM, onMessageReceived]);
4647
- React2__default.useEffect(() => {
5019
+ React3__default.useEffect(() => {
4648
5020
  if (status === "connected" && onSocketConnected) {
4649
5021
  const socketId = useStore.getState().socketId;
4650
5022
  if (socketId) onSocketConnected(socketId);
4651
5023
  }
4652
5024
  }, [status, onSocketConnected]);
4653
- React2__default.useEffect(() => {
5025
+ React3__default.useEffect(() => {
4654
5026
  if (status === "error" && error && onSocketError) {
4655
5027
  onSocketError(error);
4656
5028
  }
4657
5029
  }, [status, error, onSocketError]);
4658
- const contextValue = React2__default.useMemo(
5030
+ const contextValue = React3__default.useMemo(
4659
5031
  () => ({
4660
5032
  onSendMessage,
4661
5033
  client,
@@ -4675,7 +5047,7 @@ var Chat = ({
4675
5047
  messagesData
4676
5048
  ]
4677
5049
  );
4678
- const customization = React2__default.useMemo(
5050
+ const customization = React3__default.useMemo(
4679
5051
  () => ({
4680
5052
  components: uiConfig.components,
4681
5053
  classNames: uiConfig.classNames,
@@ -4683,7 +5055,7 @@ var Chat = ({
4683
5055
  }),
4684
5056
  [uiConfig.components, uiConfig.classNames, uiConfig.features]
4685
5057
  );
4686
- return /* @__PURE__ */ jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ChatCustomizationProvider, { customization, children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx("div", { className: "chat-container-root flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden", children: isSessionReady ? children : /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center text-gray-400 font-bold", children: "Initializing session..." }) }) }) }) });
5058
+ return /* @__PURE__ */ jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ChatCustomizationProvider, { customization, children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx("div", { className: "chat-container-root flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden", children: isSessionReady ? /* @__PURE__ */ jsx(ChatEffectiveSettingsProvider, { enabled: true, children }) : /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center text-gray-400 font-bold", children: "Initializing session..." }) }) }) }) });
4687
5059
  };
4688
5060
 
4689
5061
  // src/hooks/useChatController.ts
@@ -6086,6 +6458,8 @@ function useCreateChatDialog({
6086
6458
  const fetchAllUsers = useStore((storeState) => storeState.fetchAllUsers);
6087
6459
  const accessToken = useStore((storeState) => storeState.accessToken);
6088
6460
  const fetchConversations2 = useStore((storeState) => storeState.fetchConversations);
6461
+ const { settings } = useEffectiveSettingsOptional();
6462
+ const maxParticipants = settings.maxParticipantsPerGroup;
6089
6463
  const fileInputRef = useRef(null);
6090
6464
  useEffect(() => {
6091
6465
  if (accessToken) {
@@ -6099,9 +6473,18 @@ function useCreateChatDialog({
6099
6473
  setState((prev) => {
6100
6474
  const memberId = String(member._id);
6101
6475
  const exists = prev.selectedMembers.some((m) => String(m._id) === memberId);
6476
+ if (exists) {
6477
+ return {
6478
+ ...prev,
6479
+ selectedMembers: prev.selectedMembers.filter((m) => String(m._id) !== memberId)
6480
+ };
6481
+ }
6482
+ if (prev.selectedMembers.length + 1 >= maxParticipants) {
6483
+ return prev;
6484
+ }
6102
6485
  return {
6103
6486
  ...prev,
6104
- selectedMembers: exists ? prev.selectedMembers.filter((m) => String(m._id) !== memberId) : [...prev.selectedMembers, member]
6487
+ selectedMembers: [...prev.selectedMembers, member]
6105
6488
  };
6106
6489
  });
6107
6490
  };
@@ -6485,8 +6868,25 @@ function GroupCreateTab({
6485
6868
  ) })
6486
6869
  ] });
6487
6870
  }
6871
+ function AdminPermissionTooltip({
6872
+ disabled,
6873
+ message,
6874
+ side = "top",
6875
+ className,
6876
+ children
6877
+ }) {
6878
+ if (!disabled || !message) {
6879
+ return /* @__PURE__ */ jsx(Fragment, { children });
6880
+ }
6881
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
6882
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: cn("inline-flex", className), children }) }),
6883
+ /* @__PURE__ */ jsx(TooltipContent, { side, className: "max-w-[240px] text-xs", children: message })
6884
+ ] });
6885
+ }
6488
6886
  var CreateChatDialog = (props) => {
6489
6887
  const { isCreateModalOpen = false, setIsCreateModalOpen } = props;
6888
+ const { getGroupCreationGate } = useEffectiveSettingsOptional();
6889
+ const groupCreationGate = getGroupCreationGate();
6490
6890
  const {
6491
6891
  state,
6492
6892
  updateState,
@@ -6540,24 +6940,39 @@ var CreateChatDialog = (props) => {
6540
6940
  ) })
6541
6941
  ] }),
6542
6942
  /* @__PURE__ */ jsx("div", { className: "grid shrink-0 grid-cols-2 gap-2 px-5", children: [
6543
- { id: "dm", label: "Message", icon: MessageCircle },
6544
- { id: "group", label: "New group", icon: Users }
6545
- ].map(({ id, label, icon: Icon }) => /* @__PURE__ */ jsxs(
6546
- "button",
6943
+ { id: "dm", label: "Message", icon: MessageCircle, disabled: false, reason: null },
6547
6944
  {
6548
- type: "button",
6549
- onClick: () => updateState({ activeTab: id }),
6550
- className: cn(
6551
- "flex items-center justify-center gap-2 rounded-full border py-2 text-sm transition-colors",
6552
- 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)"
6553
- ),
6554
- children: [
6555
- /* @__PURE__ */ jsx(Icon, { className: "size-4" }),
6556
- label
6557
- ]
6558
- },
6559
- id
6560
- )) }),
6945
+ id: "group",
6946
+ label: "New group",
6947
+ icon: Users,
6948
+ disabled: !groupCreationGate.enabled,
6949
+ reason: groupCreationGate.disabledReason
6950
+ }
6951
+ ].map(({ id, label, icon: Icon, disabled, reason }) => {
6952
+ const tabButton = /* @__PURE__ */ jsxs(
6953
+ "button",
6954
+ {
6955
+ type: "button",
6956
+ disabled,
6957
+ onClick: () => {
6958
+ if (disabled) return;
6959
+ updateState({ activeTab: id });
6960
+ },
6961
+ className: cn(
6962
+ "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",
6963
+ 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)"
6964
+ ),
6965
+ children: [
6966
+ /* @__PURE__ */ jsx(Icon, { className: "size-4" }),
6967
+ label
6968
+ ]
6969
+ }
6970
+ );
6971
+ if (!disabled || !reason) {
6972
+ return /* @__PURE__ */ jsx(Fragment$1, { children: tabButton }, id);
6973
+ }
6974
+ return /* @__PURE__ */ jsx(AdminPermissionTooltip, { disabled: true, message: reason, children: tabButton }, id);
6975
+ }) }),
6561
6976
  state.activeTab === "dm" && /* @__PURE__ */ jsx(
6562
6977
  DmContactsTab,
6563
6978
  {
@@ -6568,7 +6983,7 @@ var CreateChatDialog = (props) => {
6568
6983
  onStartDM: handleStartDM
6569
6984
  }
6570
6985
  ),
6571
- state.activeTab === "group" && /* @__PURE__ */ jsx(
6986
+ state.activeTab === "group" && groupCreationGate.enabled && /* @__PURE__ */ jsx(
6572
6987
  GroupCreateTab,
6573
6988
  {
6574
6989
  state,
@@ -6632,7 +7047,7 @@ var emitPushChanged = (enabled) => {
6632
7047
  } catch {
6633
7048
  }
6634
7049
  };
6635
- var pushApiUrl = (path) => buildVersionedApiUrl(path, { service: "push" });
7050
+ var pushApiUrl = (path) => buildVersionedApiUrl(path, { service: "v2" });
6636
7051
  var apiGetPushConfig = async () => {
6637
7052
  const { data } = await apiClient.get(pushApiUrl("/notifications/push/config"));
6638
7053
  return data?.data;
@@ -6877,14 +7292,20 @@ var PushNotificationToggle = ({
6877
7292
  children
6878
7293
  }) => {
6879
7294
  const push = usePushNotifications();
7295
+ const { getPushNotificationGate } = useEffectiveSettingsOptional();
7296
+ const adminGate = getPushNotificationGate();
6880
7297
  const [isToggling, setIsToggling] = useState(false);
6881
- if (!push.supported || !push.allowedByWorkspace || !push.configured) {
7298
+ if (!push.supported) {
6882
7299
  return null;
6883
7300
  }
6884
7301
  const isOn = push.deviceEnabled && push.userEnabled;
6885
7302
  const permissionBlocked = push.permission === "denied";
7303
+ const adminBlocked = !adminGate.enabled;
7304
+ const notConfigured = !push.configured;
6886
7305
  const showLoader = isToggling;
7306
+ const isDisabled = showLoader || permissionBlocked || push.loading || adminBlocked || notConfigured;
6887
7307
  const handleChange = async (checked) => {
7308
+ if (adminBlocked || notConfigured) return;
6888
7309
  setIsToggling(true);
6889
7310
  try {
6890
7311
  if (checked) {
@@ -6897,11 +7318,12 @@ var PushNotificationToggle = ({
6897
7318
  setIsToggling(false);
6898
7319
  }
6899
7320
  };
7321
+ 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;
6900
7322
  const renderProps = {
6901
7323
  label,
6902
- description: permissionBlocked ? "Notifications are blocked in your browser settings" : push.error ?? description,
6903
- checked: isOn,
6904
- disabled: showLoader || permissionBlocked || push.loading,
7324
+ description: descriptionText,
7325
+ checked: adminBlocked || notConfigured ? false : isOn,
7326
+ disabled: isDisabled,
6905
7327
  loading: showLoader || push.loading,
6906
7328
  permissionBlocked,
6907
7329
  error: push.error,
@@ -6929,12 +7351,20 @@ var PushNotificationToggle = ({
6929
7351
  "aria-label": "Updating push notifications"
6930
7352
  }
6931
7353
  ) : /* @__PURE__ */ jsx(
6932
- Switch,
7354
+ AdminPermissionTooltip,
6933
7355
  {
6934
- checked: isOn,
6935
- disabled: permissionBlocked || push.loading,
6936
- onCheckedChange: (checked) => void handleChange(checked),
6937
- "aria-label": `Toggle ${label}`
7356
+ disabled: adminBlocked || notConfigured,
7357
+ message: adminBlocked ? adminGate.disabledReason : "Push notifications are not configured. Please contact your administrator.",
7358
+ children: /* @__PURE__ */ jsx(
7359
+ Switch,
7360
+ {
7361
+ checked: adminBlocked || notConfigured ? false : isOn,
7362
+ disabled: isDisabled,
7363
+ onCheckedChange: (checked) => void handleChange(checked),
7364
+ "aria-label": `Toggle ${label}`,
7365
+ className: "data-[state=checked]:bg-(--chat-theme) data-[state=unchecked]:bg-(--chat-border)"
7366
+ }
7367
+ )
6938
7368
  }
6939
7369
  )
6940
7370
  ]
@@ -8355,7 +8785,7 @@ function highlightSearchMatch(text, query) {
8355
8785
  children: part
8356
8786
  },
8357
8787
  `${part}-${index}`
8358
- ) : /* @__PURE__ */ jsx(React2__default.Fragment, { children: part }, `${part}-${index}`)
8788
+ ) : /* @__PURE__ */ jsx(React3__default.Fragment, { children: part }, `${part}-${index}`)
8359
8789
  );
8360
8790
  }
8361
8791
  function getMessagePreview(message) {
@@ -8535,7 +8965,7 @@ var HeaderSearchPopover = ({
8535
8965
  ] });
8536
8966
  };
8537
8967
  var HeaderSearchPopover_default = HeaderSearchPopover;
8538
- var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text)";
8968
+ var actionBtnClass = "size-8 rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-surface) hover:text-(--chat-text) disabled:opacity-40";
8539
8969
  var DefaultHeaderCallActions = ({
8540
8970
  activeChannel,
8541
8971
  conversationId,
@@ -8546,48 +8976,91 @@ var DefaultHeaderCallActions = ({
8546
8976
  className
8547
8977
  }) => {
8548
8978
  const { components, slotClassName, features } = useChatCustomizationOptional();
8979
+ const { getAudioCallGate, getVideoCallGate } = useEffectiveSettingsOptional();
8549
8980
  const PhoneSlot = components.PhoneCallButton;
8550
8981
  const VideoSlot = components.VideoCallButton;
8551
8982
  const hideInGroups = features.hideCallActionsInGroupChats ?? false;
8983
+ const audioGate = getAudioCallGate();
8984
+ const videoGate = getVideoCallGate();
8552
8985
  if (hideInGroups && activeChannel.isGroup) return null;
8553
8986
  if (!showPhoneCall && !showVideoCall) return null;
8987
+ const phoneEnabled = showPhoneCall && audioGate.enabled;
8988
+ const videoEnabled = showVideoCall && videoGate.enabled;
8554
8989
  return /* @__PURE__ */ jsxs(Fragment, { children: [
8555
8990
  showPhoneCall && (PhoneSlot ? /* @__PURE__ */ jsx(
8556
- PhoneSlot,
8991
+ AdminPermissionTooltip,
8557
8992
  {
8558
- activeChannel,
8559
- conversationId,
8560
- onPhoneCall,
8561
- className: cn(className, slotClassName("phoneCallButton"))
8993
+ disabled: !audioGate.enabled,
8994
+ message: audioGate.disabledReason,
8995
+ children: /* @__PURE__ */ jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsx(
8996
+ PhoneSlot,
8997
+ {
8998
+ activeChannel,
8999
+ conversationId,
9000
+ onPhoneCall: phoneEnabled ? onPhoneCall : void 0,
9001
+ className: cn(
9002
+ className,
9003
+ slotClassName("phoneCallButton"),
9004
+ !audioGate.enabled && "pointer-events-none opacity-40"
9005
+ )
9006
+ }
9007
+ ) })
8562
9008
  }
8563
9009
  ) : /* @__PURE__ */ jsx(
8564
- Button,
9010
+ AdminPermissionTooltip,
8565
9011
  {
8566
- variant: "ghost",
8567
- size: "icon",
8568
- className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
8569
- "aria-label": "Voice call",
8570
- onClick: onPhoneCall,
8571
- children: /* @__PURE__ */ jsx(Phone, { size: 15 })
9012
+ disabled: !audioGate.enabled,
9013
+ message: audioGate.disabledReason,
9014
+ children: /* @__PURE__ */ jsx(
9015
+ Button,
9016
+ {
9017
+ variant: "ghost",
9018
+ size: "icon",
9019
+ className: cn(actionBtnClass, className, slotClassName("phoneCallButton")),
9020
+ "aria-label": "Voice call",
9021
+ disabled: !audioGate.enabled,
9022
+ onClick: phoneEnabled ? onPhoneCall : void 0,
9023
+ children: /* @__PURE__ */ jsx(Phone, { size: 15 })
9024
+ }
9025
+ )
8572
9026
  }
8573
9027
  )),
8574
9028
  showVideoCall && (VideoSlot ? /* @__PURE__ */ jsx(
8575
- VideoSlot,
9029
+ AdminPermissionTooltip,
8576
9030
  {
8577
- activeChannel,
8578
- conversationId,
8579
- onVideoCall,
8580
- className: cn(className, slotClassName("videoCallButton"))
9031
+ disabled: !videoGate.enabled,
9032
+ message: videoGate.disabledReason,
9033
+ children: /* @__PURE__ */ jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsx(
9034
+ VideoSlot,
9035
+ {
9036
+ activeChannel,
9037
+ conversationId,
9038
+ onVideoCall: videoEnabled ? onVideoCall : void 0,
9039
+ className: cn(
9040
+ className,
9041
+ slotClassName("videoCallButton"),
9042
+ !videoGate.enabled && "pointer-events-none opacity-40"
9043
+ )
9044
+ }
9045
+ ) })
8581
9046
  }
8582
9047
  ) : /* @__PURE__ */ jsx(
8583
- Button,
9048
+ AdminPermissionTooltip,
8584
9049
  {
8585
- variant: "ghost",
8586
- size: "icon",
8587
- className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
8588
- "aria-label": "Video call",
8589
- onClick: onVideoCall,
8590
- children: /* @__PURE__ */ jsx(Video, { size: 15 })
9050
+ disabled: !videoGate.enabled,
9051
+ message: videoGate.disabledReason,
9052
+ children: /* @__PURE__ */ jsx(
9053
+ Button,
9054
+ {
9055
+ variant: "ghost",
9056
+ size: "icon",
9057
+ className: cn(actionBtnClass, className, slotClassName("videoCallButton")),
9058
+ "aria-label": "Video call",
9059
+ disabled: !videoGate.enabled,
9060
+ onClick: videoEnabled ? onVideoCall : void 0,
9061
+ children: /* @__PURE__ */ jsx(Video, { size: 15 })
9062
+ }
9063
+ )
8591
9064
  }
8592
9065
  ))
8593
9066
  ] });
@@ -8609,19 +9082,38 @@ function OptionsMenuItem({
8609
9082
  icon: Icon,
8610
9083
  label,
8611
9084
  onSelect,
8612
- destructive = false
9085
+ destructive = false,
9086
+ disabled = false,
9087
+ disabledReason
8613
9088
  }) {
8614
- return /* @__PURE__ */ jsxs(
9089
+ const item = /* @__PURE__ */ jsxs(
8615
9090
  DropdownMenuItem,
8616
9091
  {
8617
- className: destructive ? chatOptionsMenuItemDestructiveClass : chatOptionsMenuItemClass,
8618
- onSelect,
9092
+ className: cn(
9093
+ destructive ? chatOptionsMenuItemDestructiveClass : chatOptionsMenuItemClass,
9094
+ disabled && "pointer-events-none opacity-40"
9095
+ ),
9096
+ disabled,
9097
+ onSelect: (event) => {
9098
+ if (disabled) {
9099
+ event.preventDefault();
9100
+ return;
9101
+ }
9102
+ onSelect?.();
9103
+ },
8619
9104
  children: [
8620
9105
  /* @__PURE__ */ jsx(Icon, { strokeWidth: 1.75 }),
8621
9106
  /* @__PURE__ */ jsx("span", { className: "flex-1", children: label })
8622
9107
  ]
8623
9108
  }
8624
9109
  );
9110
+ if (!disabled || !disabledReason) {
9111
+ return item;
9112
+ }
9113
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
9114
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "w-full", children: item }) }),
9115
+ /* @__PURE__ */ jsx(TooltipContent, { side: "left", className: "max-w-[220px] text-xs", children: disabledReason })
9116
+ ] });
8625
9117
  }
8626
9118
  var HeaderRightSide = ({
8627
9119
  activeChannel,
@@ -8656,6 +9148,8 @@ var HeaderRightSide = ({
8656
9148
  const { scopeClassName, themeStyles, showColorModeToggle } = useChatTheme();
8657
9149
  const { showDateTimeSettings } = useChatLocale();
8658
9150
  const features = useChatFeaturesOptional();
9151
+ const { getBlockUsersGate } = useEffectiveSettingsOptional();
9152
+ const blockUsersGate = getBlockUsersGate();
8659
9153
  const showPhoneCall = features.showPhoneCall ?? defaultChatFeatures.showPhoneCall;
8660
9154
  const showVideoCall = features.showVideoCall ?? defaultChatFeatures.showVideoCall;
8661
9155
  const handlePhoneCall = () => {
@@ -8804,7 +9298,9 @@ var HeaderRightSide = ({
8804
9298
  icon: Ban,
8805
9299
  label: isBlocked ? "Unblock User" : "Block User",
8806
9300
  onSelect: onToggleBlock,
8807
- destructive: true
9301
+ destructive: true,
9302
+ disabled: !blockUsersGate.enabled,
9303
+ disabledReason: blockUsersGate.disabledReason
8808
9304
  }
8809
9305
  )
8810
9306
  ]
@@ -12844,17 +13340,24 @@ var ChannelDetailsDrawer = (props) => {
12844
13340
  };
12845
13341
  var ChannelDetailsDrawer_default = ChannelDetailsDrawer;
12846
13342
  init_useStore();
13343
+ init_settings_types();
12847
13344
  var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo }) => {
12848
13345
  const updateGroupPermissions = useStore((s) => s.updateGroupPermissions);
13346
+ const { settings, isGroupPermissionLocked } = useEffectiveSettingsOptional();
12849
13347
  const [permissions, setPermissions] = useState(null);
12850
13348
  const [isSaving, setIsSaving] = useState(false);
12851
13349
  useEffect(() => {
12852
13350
  if (conversationInfo?.groupPermissions) {
12853
13351
  setPermissions(conversationInfo.groupPermissions);
13352
+ return;
12854
13353
  }
12855
- }, [conversationInfo]);
13354
+ if (isOpen) {
13355
+ setPermissions({ ...settings.groupPolicy.defaults });
13356
+ }
13357
+ }, [conversationInfo, isOpen, settings.groupPolicy.defaults]);
12856
13358
  if (!conversationId || !permissions) return null;
12857
13359
  const handleToggle = (key) => {
13360
+ if (isGroupPermissionLocked(key)) return;
12858
13361
  setPermissions((prev) => prev ? { ...prev, [key]: !prev[key] } : null);
12859
13362
  };
12860
13363
  const handleSave = async () => {
@@ -12886,31 +13389,43 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
12886
13389
  /* @__PURE__ */ jsxs("div", { className: cn(chatSheetBodyClass, "flex flex-col px-2.5 py-2"), children: [
12887
13390
  /* @__PURE__ */ jsxs("section", { className: "mb-2.5 flex-1", children: [
12888
13391
  /* @__PURE__ */ jsx("h3", { className: "mb-1 px-0.5 text-[10px] font-semibold uppercase tracking-wide text-(--chat-muted)", children: "Permissions" }),
12889
- /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-(--chat-border) px-3", children: permissionItems.map((item, index) => /* @__PURE__ */ jsxs(
12890
- "div",
12891
- {
12892
- className: cn(
12893
- "flex items-start justify-between gap-3 py-2.5",
12894
- index < permissionItems.length - 1 && "border-b border-(--chat-border)"
12895
- ),
12896
- children: [
12897
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-0.5", children: [
12898
- /* @__PURE__ */ jsx("p", { className: "text-[12px] font-semibold leading-snug text-(--chat-text)", children: item.label }),
12899
- /* @__PURE__ */ jsx("p", { className: "text-[10px] leading-relaxed text-(--chat-muted)", children: item.desc })
12900
- ] }),
12901
- /* @__PURE__ */ jsx(
12902
- Switch,
12903
- {
12904
- size: "sm",
12905
- className: "mt-0.5 shrink-0 data-[state=checked]:bg-(--chat-theme) data-[state=unchecked]:bg-(--chat-border)",
12906
- checked: "inverted" in item && item.inverted ? !permissions[item.key] : permissions[item.key],
12907
- onCheckedChange: () => handleToggle(item.key)
12908
- }
12909
- )
12910
- ]
12911
- },
12912
- item.key
12913
- )) })
13392
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-(--chat-border) px-3", children: permissionItems.map((item, index) => {
13393
+ const locked = isGroupPermissionLocked(item.key);
13394
+ return /* @__PURE__ */ jsxs(
13395
+ "div",
13396
+ {
13397
+ className: cn(
13398
+ "flex items-start justify-between gap-3 py-2.5",
13399
+ index < permissionItems.length - 1 && "border-b border-(--chat-border)"
13400
+ ),
13401
+ children: [
13402
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-0.5", children: [
13403
+ /* @__PURE__ */ jsx("p", { className: "text-[12px] font-semibold leading-snug text-(--chat-text)", children: item.label }),
13404
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] leading-relaxed text-(--chat-muted)", children: item.desc }),
13405
+ locked ? /* @__PURE__ */ jsx("p", { className: "text-[10px] font-medium text-(--chat-theme)", children: "Locked by administrator" }) : null
13406
+ ] }),
13407
+ /* @__PURE__ */ jsx(
13408
+ AdminPermissionTooltip,
13409
+ {
13410
+ disabled: locked,
13411
+ message: ADMIN_PERMISSION_DENIED_MESSAGE,
13412
+ children: /* @__PURE__ */ jsx(
13413
+ Switch,
13414
+ {
13415
+ size: "sm",
13416
+ className: "mt-0.5 shrink-0 data-[state=checked]:bg-(--chat-theme) data-[state=unchecked]:bg-(--chat-border)",
13417
+ disabled: locked,
13418
+ checked: item.inverted ? !permissions[item.key] : permissions[item.key],
13419
+ onCheckedChange: () => handleToggle(item.key)
13420
+ }
13421
+ )
13422
+ }
13423
+ )
13424
+ ]
13425
+ },
13426
+ item.key
13427
+ );
13428
+ }) })
12914
13429
  ] }),
12915
13430
  /* @__PURE__ */ jsx("div", { className: "sticky bottom-0 border-t border-(--chat-border) bg-(--chat-surface) px-0.5 pt-2.5 pb-1", children: /* @__PURE__ */ jsx(
12916
13431
  Button,
@@ -12940,6 +13455,8 @@ function useAdminsDrawer({ conversationId, conversationInfo }) {
12940
13455
  const [isManaging, setIsManaging] = useState(null);
12941
13456
  const manageGroupAdmins = useStore((s) => s.manageGroupAdmins);
12942
13457
  const { isOwner } = useGroupInfo(conversationId);
13458
+ const { settings } = useEffectiveSettingsOptional();
13459
+ const maxAdmins = settings.maxAdminsPerGroup;
12943
13460
  const participants = useMemo(
12944
13461
  () => conversationInfo?.participants ?? [],
12945
13462
  [conversationInfo?.participants]
@@ -12979,8 +13496,16 @@ function useAdminsDrawer({ conversationId, conversationInfo }) {
12979
13496
  }),
12980
13497
  [filteredParticipants, adminIds, ownerId]
12981
13498
  );
13499
+ const adminCount = admins.length + (ownerId ? 1 : 0);
13500
+ const atAdminLimit = adminCount >= maxAdmins;
12982
13501
  const handleManageAdmin = async (userId, type) => {
12983
13502
  if (!conversationId) return;
13503
+ if (type === "add" && adminCount >= maxAdmins) {
13504
+ useStore.getState().handleAppError(
13505
+ `You can have up to ${maxAdmins} admins in this group.`
13506
+ );
13507
+ return;
13508
+ }
12984
13509
  setIsManaging(userId);
12985
13510
  try {
12986
13511
  await manageGroupAdmins({
@@ -12992,7 +13517,6 @@ function useAdminsDrawer({ conversationId, conversationInfo }) {
12992
13517
  setIsManaging(null);
12993
13518
  }
12994
13519
  };
12995
- const adminCount = admins.length + (ownerId ? 1 : 0);
12996
13520
  return {
12997
13521
  searchQuery,
12998
13522
  setSearchQuery,
@@ -13004,6 +13528,8 @@ function useAdminsDrawer({ conversationId, conversationInfo }) {
13004
13528
  promotableParticipants,
13005
13529
  handleManageAdmin,
13006
13530
  adminCount,
13531
+ maxAdmins,
13532
+ atAdminLimit,
13007
13533
  hasRequiredData: Boolean(conversationId && conversationInfo)
13008
13534
  };
13009
13535
  }
@@ -13016,6 +13542,8 @@ function AdminParticipantRow({
13016
13542
  isAdmin,
13017
13543
  showPromote,
13018
13544
  showDemote,
13545
+ promoteDisabled = false,
13546
+ promoteDisabledReason,
13019
13547
  isOwnerViewer,
13020
13548
  isManaging,
13021
13549
  onManageAdmin
@@ -13056,14 +13584,24 @@ function AdminParticipantRow({
13056
13584
  }
13057
13585
  ),
13058
13586
  showPromote && isOwnerViewer && /* @__PURE__ */ jsx(
13059
- Button,
13587
+ AdminPermissionTooltip,
13060
13588
  {
13061
- variant: "ghost",
13062
- size: "sm",
13063
- className: "size-7 rounded-md p-0 text-(--chat-muted) hover:bg-(--chat-theme-10) hover:text-(--chat-theme)",
13064
- onClick: () => onManageAdmin(memberId, "add"),
13065
- disabled: isManaging === memberId,
13066
- children: isManaging === memberId ? /* @__PURE__ */ jsx(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx(UserPlus, { size: 13 })
13589
+ disabled: promoteDisabled,
13590
+ message: promoteDisabledReason,
13591
+ children: /* @__PURE__ */ jsx(
13592
+ Button,
13593
+ {
13594
+ variant: "ghost",
13595
+ size: "sm",
13596
+ className: "size-7 rounded-md p-0 text-(--chat-muted) hover:bg-(--chat-theme-10) hover:text-(--chat-theme) disabled:opacity-40",
13597
+ onClick: () => {
13598
+ if (promoteDisabled) return;
13599
+ onManageAdmin(memberId, "add");
13600
+ },
13601
+ disabled: isManaging === memberId || promoteDisabled,
13602
+ children: isManaging === memberId ? /* @__PURE__ */ jsx(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx(UserPlus, { size: 13 })
13603
+ }
13604
+ )
13067
13605
  }
13068
13606
  )
13069
13607
  ] })
@@ -13087,7 +13625,9 @@ function AdminParticipantList({
13087
13625
  isAdmin,
13088
13626
  onManageAdmin,
13089
13627
  showPromote,
13090
- showDemoteForAdmins
13628
+ showDemoteForAdmins,
13629
+ promoteDisabled = false,
13630
+ promoteDisabledReason
13091
13631
  }) {
13092
13632
  return /* @__PURE__ */ jsx(Fragment, { children: members.map((member, index) => {
13093
13633
  const { memberId, memberName, memberEmail, memberImage } = getMemberFields(member);
@@ -13105,6 +13645,8 @@ function AdminParticipantList({
13105
13645
  isAdmin: userIsAdmin,
13106
13646
  showPromote: showPromote && !userIsAdmin && !userIsOwner,
13107
13647
  showDemote: showDemoteForAdmins ? userIsAdmin && !userIsOwner : false,
13648
+ promoteDisabled,
13649
+ promoteDisabledReason,
13108
13650
  isOwnerViewer,
13109
13651
  isManaging,
13110
13652
  onManageAdmin
@@ -13124,6 +13666,8 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13124
13666
  promotableParticipants,
13125
13667
  handleManageAdmin,
13126
13668
  adminCount,
13669
+ maxAdmins,
13670
+ atAdminLimit,
13127
13671
  hasRequiredData
13128
13672
  } = useAdminsDrawer({ conversationId, conversationInfo });
13129
13673
  if (!hasRequiredData) return null;
@@ -13143,7 +13687,10 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13143
13687
  /* @__PURE__ */ jsx(SheetTitle, { className: chatSheetTitleClass, children: "Group Administrators" }),
13144
13688
  /* @__PURE__ */ 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 })
13145
13689
  ] }),
13146
- /* @__PURE__ */ jsx("p", { className: chatSheetSubtitleClass, children: "Manage who can adjust group settings and members." })
13690
+ /* @__PURE__ */ jsxs("p", { className: chatSheetSubtitleClass, children: [
13691
+ "Manage who can adjust group settings and members",
13692
+ maxAdmins ? ` (max ${maxAdmins}).` : "."
13693
+ ] })
13147
13694
  ] }),
13148
13695
  /* @__PURE__ */ jsxs("div", { className: cn(chatSheetBodyClass, "px-2.5 py-2"), children: [
13149
13696
  /* @__PURE__ */ jsx("div", { className: "mb-2.5 px-0.5", children: /* @__PURE__ */ jsx(
@@ -13186,7 +13733,9 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13186
13733
  ownerId,
13187
13734
  isAdmin,
13188
13735
  onManageAdmin: handleManageAdmin,
13189
- showPromote: true
13736
+ showPromote: true,
13737
+ promoteDisabled: atAdminLimit,
13738
+ promoteDisabledReason: `Maximum ${maxAdmins} admins allowed in this group.`
13190
13739
  }
13191
13740
  ) })
13192
13741
  ] }),
@@ -13203,7 +13752,9 @@ var AdminsDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13203
13752
  isAdmin,
13204
13753
  onManageAdmin: handleManageAdmin,
13205
13754
  showPromote: true,
13206
- showDemoteForAdmins: true
13755
+ showDemoteForAdmins: true,
13756
+ promoteDisabled: atAdminLimit,
13757
+ promoteDisabledReason: `Maximum ${maxAdmins} admins allowed in this group.`
13207
13758
  }
13208
13759
  ) })
13209
13760
  ] }),
@@ -13231,9 +13782,12 @@ var MembersDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13231
13782
  );
13232
13783
  }, [allUsers, searchQuery]);
13233
13784
  const { userPermissions } = useGroupInfo(conversationId);
13785
+ const { settings } = useEffectiveSettingsOptional();
13786
+ const maxParticipants = settings.maxParticipantsPerGroup;
13234
13787
  if (!conversationId || !conversationInfo) return null;
13235
13788
  const participants = conversationInfo.participants || [];
13236
13789
  const admins = conversationInfo.groupAdmins || [];
13790
+ const atParticipantLimit = participants.length >= maxParticipants;
13237
13791
  let ownerId = null;
13238
13792
  if (conversationInfo.owner) {
13239
13793
  ownerId = typeof conversationInfo.owner === "object" && conversationInfo.owner !== null ? conversationInfo.owner._id || conversationInfo.owner.id : conversationInfo.owner;
@@ -13287,14 +13841,24 @@ var MembersDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13287
13841
  }
13288
13842
  ),
13289
13843
  options.showAdd && /* @__PURE__ */ jsx(
13290
- Button,
13844
+ AdminPermissionTooltip,
13291
13845
  {
13292
- variant: "ghost",
13293
- size: "sm",
13294
- className: "size-7 rounded-md p-0 text-(--chat-muted) hover:bg-(--chat-theme-10) hover:text-(--chat-theme)",
13295
- onClick: () => handleManageMember(memberId, "add"),
13296
- disabled: isManaging === memberId,
13297
- children: isManaging === memberId ? /* @__PURE__ */ jsx(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx(UserPlus, { size: 13 })
13846
+ disabled: atParticipantLimit,
13847
+ message: `Maximum ${maxParticipants} participants allowed in this group.`,
13848
+ children: /* @__PURE__ */ jsx(
13849
+ Button,
13850
+ {
13851
+ variant: "ghost",
13852
+ size: "sm",
13853
+ className: "size-7 rounded-md p-0 text-(--chat-muted) hover:bg-(--chat-theme-10) hover:text-(--chat-theme) disabled:opacity-40",
13854
+ onClick: () => {
13855
+ if (atParticipantLimit) return;
13856
+ handleManageMember(memberId, "add");
13857
+ },
13858
+ disabled: isManaging === memberId || atParticipantLimit,
13859
+ children: isManaging === memberId ? /* @__PURE__ */ jsx(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx(UserPlus, { size: 13 })
13860
+ }
13861
+ )
13298
13862
  }
13299
13863
  )
13300
13864
  ] })
@@ -13316,7 +13880,11 @@ var MembersDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo })
13316
13880
  /* @__PURE__ */ jsx(SheetTitle, { className: chatSheetTitleClass, children: "Group Management" }),
13317
13881
  /* @__PURE__ */ 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 })
13318
13882
  ] }),
13319
- /* @__PURE__ */ jsx("p", { className: chatSheetSubtitleClass, children: "Manage members and invite people." })
13883
+ /* @__PURE__ */ jsxs("p", { className: chatSheetSubtitleClass, children: [
13884
+ "Manage members and invite people (max ",
13885
+ maxParticipants,
13886
+ ")."
13887
+ ] })
13320
13888
  ] }),
13321
13889
  /* @__PURE__ */ jsxs("div", { className: cn(chatSheetBodyClass, "px-2.5 py-2"), children: [
13322
13890
  !searchQuery && /* @__PURE__ */ jsxs("section", { className: "mb-2.5", children: [
@@ -13458,6 +14026,8 @@ init_store_helpers();
13458
14026
  function useBlockUser(activeChannel, conversationId, onActiveChannelPatch) {
13459
14027
  const loggedUserDetails = useStore((s) => s.loggedUserDetails);
13460
14028
  const composerDisabledByConversation = useStore((s) => s.composerDisabledByConversation);
14029
+ const { getBlockUsersGate } = useEffectiveSettingsOptional();
14030
+ const blockUsersGate = getBlockUsersGate();
13461
14031
  const [isBlocking, setIsBlocking] = useState(false);
13462
14032
  const resolvedConversationId = conversationId ?? activeChannel?.conversationId ?? null;
13463
14033
  const composerDisabledReason = resolvedConversationId ? composerDisabledByConversation[resolvedConversationId] : void 0;
@@ -13479,6 +14049,12 @@ function useBlockUser(activeChannel, conversationId, onActiveChannelPatch) {
13479
14049
  const toggleBlock = useCallback(async () => {
13480
14050
  if (!activeChannel?.id || activeChannel.isGroup) return false;
13481
14051
  const nextBlocked = !isBlocked;
14052
+ if (nextBlocked && !blockUsersGate.enabled) {
14053
+ useStore.getState().handleAppError(
14054
+ blockUsersGate.disabledReason || "Blocking users is disabled by your administrator."
14055
+ );
14056
+ return false;
14057
+ }
13482
14058
  const type = nextBlocked ? "block" : "unblock";
13483
14059
  try {
13484
14060
  setIsBlocking(true);
@@ -13499,8 +14075,8 @@ function useBlockUser(activeChannel, conversationId, onActiveChannelPatch) {
13499
14075
  } finally {
13500
14076
  setIsBlocking(false);
13501
14077
  }
13502
- }, [activeChannel, isBlocked, onActiveChannelPatch, resolvedConversationId]);
13503
- return { isBlocked, isBlocking, toggleBlock };
14078
+ }, [activeChannel, isBlocked, onActiveChannelPatch, resolvedConversationId, blockUsersGate]);
14079
+ return { isBlocked, isBlocking, toggleBlock, blockUsersGate };
13504
14080
  }
13505
14081
 
13506
14082
  // src/chat/channel-header/useChannelHeader.ts
@@ -14036,6 +14612,7 @@ var MessageReactions_default = MessageReactions;
14036
14612
  var MessageToolbar = ({
14037
14613
  isSender,
14038
14614
  isRecent,
14615
+ isWithinDeleteWindow = isRecent,
14039
14616
  isPinned,
14040
14617
  isStarred,
14041
14618
  isPinPending,
@@ -14059,7 +14636,7 @@ var MessageToolbar = ({
14059
14636
  }) => {
14060
14637
  const { isDark, scopeClassName, themeStyles } = useChatTheme();
14061
14638
  const showDeleteMenu = isSender || hasAttachments || attachmentDeleteMode;
14062
- const showDeleteForEveryone = isSender && isRecent;
14639
+ const showDeleteForEveryone = isSender && isWithinDeleteWindow;
14063
14640
  return /* @__PURE__ */ jsxs(
14064
14641
  "div",
14065
14642
  {
@@ -14381,16 +14958,68 @@ function resolveForwardItems(selectedKeys, messages) {
14381
14958
  }
14382
14959
 
14383
14960
  // src/chat/lib/chat-edit-window.ts
14384
- init_chat_constants();
14385
- function getMessageEditWindowMs(isGroup) {
14386
- return isGroup ? GROUP_EDIT_WINDOW_MS : DM_EDIT_WINDOW_MS;
14961
+ init_settings_types();
14962
+
14963
+ // src/lib/effective-settings.helpers.ts
14964
+ function minutesToMs(minutes) {
14965
+ return Math.max(0, minutes) * 60 * 1e3;
14966
+ }
14967
+ function getEditWindowMs(timers, isGroup) {
14968
+ return minutesToMs(isGroup ? timers.groupEditMinutes : timers.dmEditMinutes);
14387
14969
  }
14388
- function isWithinMessageEditWindow(createdAt, isGroup) {
14970
+ function getDeleteWindowMs(timers, isGroup) {
14971
+ return minutesToMs(
14972
+ isGroup ? timers.groupDeleteMinutes : timers.dmDeleteMinutes
14973
+ );
14974
+ }
14975
+ function isWithinWindow(createdAt, windowMs) {
14389
14976
  if (!createdAt) return false;
14390
14977
  const date = new Date(createdAt);
14391
14978
  if (isNaN(date.getTime())) return false;
14392
14979
  const diff = Date.now() - date.getTime();
14393
- return diff >= 0 && diff < getMessageEditWindowMs(isGroup);
14980
+ return diff >= 0 && diff < windowMs;
14981
+ }
14982
+ function isWithinMessageEditWindow(createdAt, timers, isGroup) {
14983
+ return isWithinWindow(createdAt, getEditWindowMs(timers, isGroup));
14984
+ }
14985
+ function isWithinMessageDeleteWindow(createdAt, timers, isGroup) {
14986
+ return isWithinWindow(createdAt, getDeleteWindowMs(timers, isGroup));
14987
+ }
14988
+ function allowsAllMimeTypes(allowedMimeTypes) {
14989
+ return allowedMimeTypes.some((pattern) => {
14990
+ const normalized = pattern.trim().toLowerCase();
14991
+ return normalized === "*" || normalized === "*/*";
14992
+ });
14993
+ }
14994
+ function matchesAllowedMimeType(fileType, allowedMimeTypes) {
14995
+ if (!allowedMimeTypes.length) return false;
14996
+ if (allowsAllMimeTypes(allowedMimeTypes)) return true;
14997
+ const mime = (fileType || "application/octet-stream").toLowerCase();
14998
+ return allowedMimeTypes.some((pattern) => {
14999
+ const normalized = pattern.trim().toLowerCase();
15000
+ if (!normalized) return false;
15001
+ if (normalized.endsWith("/*")) {
15002
+ const prefix = normalized.slice(0, -1);
15003
+ return mime.startsWith(prefix);
15004
+ }
15005
+ return mime === normalized;
15006
+ });
15007
+ }
15008
+ function buildAcceptFromMimeTypes(allowedMimeTypes) {
15009
+ if (allowsAllMimeTypes(allowedMimeTypes)) return "";
15010
+ return allowedMimeTypes.map((type) => type.trim()).filter(Boolean).join(",");
15011
+ }
15012
+ function formatFileSizeMB(sizeBytes) {
15013
+ return `${(sizeBytes / (1024 * 1024)).toFixed(1)} MB`;
15014
+ }
15015
+
15016
+ // src/chat/lib/chat-edit-window.ts
15017
+ var FALLBACK_TIMERS = DEFAULT_EFFECTIVE_SETTINGS.messageTimers;
15018
+ function isWithinMessageEditWindow2(createdAt, isGroup, timers = FALLBACK_TIMERS) {
15019
+ return isWithinMessageEditWindow(createdAt, timers, isGroup);
15020
+ }
15021
+ function isWithinMessageDeleteWindow2(createdAt, isGroup, timers = FALLBACK_TIMERS) {
15022
+ return isWithinMessageDeleteWindow(createdAt, timers, isGroup);
14394
15023
  }
14395
15024
 
14396
15025
  // src/chat/message-item/useMessageItemActions.ts
@@ -14468,6 +15097,9 @@ function useMessageItemActions({
14468
15097
  const canUnpin = !isPinned || isPinnedByMe;
14469
15098
  const { userPermissions } = useGroupInfo(conversationId || null);
14470
15099
  const { formatMessageTime } = useChatLocale();
15100
+ const { settings } = useEffectiveSettingsOptional();
15101
+ const messageTimers = settings.messageTimers;
15102
+ const maxPinnedMessages = settings.maxPinnedMessagesPerConversation;
14471
15103
  const visibleAttachments = getVisibleAttachments(attachments);
14472
15104
  const hasAttachments = visibleAttachments.length > 0;
14473
15105
  const hasMultiAttachments = hasAttachments && messageUsesAttachmentSelection({ attachments: visibleAttachments });
@@ -14484,7 +15116,8 @@ function useMessageItemActions({
14484
15116
  const hasText = Boolean(message?.trim());
14485
15117
  const isSelected = !!mid && !!selectedKeys && isMessageWhollySelected(selectedKeys, mid) && !hasMultiAttachments;
14486
15118
  const canEdit = (!isGroup || userPermissions.canEditMessage) && hasText;
14487
- const isWithinEditWindow = () => isWithinMessageEditWindow(createdAt, isGroup);
15119
+ const isWithinEditWindow = () => isWithinMessageEditWindow2(createdAt, isGroup, messageTimers);
15120
+ const isWithinDeleteWindow = () => isWithinMessageDeleteWindow2(createdAt, isGroup, messageTimers);
14488
15121
  const canEditAttachmentCaption = isSender && isWithinEditWindow() && (!isGroup || userPermissions.canEditMessage) && !isDeletedForEveryone && !!mid;
14489
15122
  const handleAttachmentCaptionClick = (attachment) => {
14490
15123
  if (!canEditAttachmentCaption) return;
@@ -14653,6 +15286,15 @@ function useMessageItemActions({
14653
15286
  });
14654
15287
  }
14655
15288
  } else {
15289
+ if (conversationId) {
15290
+ const pinnedCount = (pinnedMessagesByConversation[conversationId] || []).length || useStore.getState().liveConversationCounts[conversationId]?.pinnedCount || 0;
15291
+ if (pinnedCount >= maxPinnedMessages) {
15292
+ useStore.getState().handleAppError(
15293
+ `You can pin up to ${maxPinnedMessages} messages in this conversation.`
15294
+ );
15295
+ return;
15296
+ }
15297
+ }
14656
15298
  if (isGroup) {
14657
15299
  if (!conversationId) return;
14658
15300
  emitGroupPin({
@@ -14711,6 +15353,7 @@ function useMessageItemActions({
14711
15353
  canUnpin,
14712
15354
  canEdit,
14713
15355
  isWithinEditWindow,
15356
+ isWithinDeleteWindow,
14714
15357
  canEditAttachmentCaption,
14715
15358
  visibleAttachments,
14716
15359
  hasAttachments,
@@ -14742,7 +15385,7 @@ function useMessageItemActions({
14742
15385
  }
14743
15386
 
14744
15387
  // src/chat/lib/reply-preview.ts
14745
- function normalizeAttachments(replyTo, loggedUserId) {
15388
+ function normalizeAttachments2(replyTo, loggedUserId) {
14746
15389
  const raw = replyTo?.attachments;
14747
15390
  if (!Array.isArray(raw) || raw.length === 0) return [];
14748
15391
  return raw.map((att, index) => {
@@ -14755,7 +15398,7 @@ function resolveReplyToMessage(replyTo, messagesById, loggedUserId) {
14755
15398
  if (typeof replyTo === "object" && (replyTo.content?.trim() || replyTo.attachments?.length)) {
14756
15399
  return {
14757
15400
  ...replyTo,
14758
- attachments: normalizeAttachments(replyTo, loggedUserId)
15401
+ attachments: normalizeAttachments2(replyTo, loggedUserId)
14759
15402
  };
14760
15403
  }
14761
15404
  const replyId = String(
@@ -15192,6 +15835,7 @@ function MessageItemView(props) {
15192
15835
  canUnpin,
15193
15836
  canEdit,
15194
15837
  isWithinEditWindow,
15838
+ isWithinDeleteWindow,
15195
15839
  canEditAttachmentCaption,
15196
15840
  visibleAttachments,
15197
15841
  hasAttachments,
@@ -15283,6 +15927,7 @@ function MessageItemView(props) {
15283
15927
  {
15284
15928
  isSender,
15285
15929
  isRecent: isWithinEditWindow(),
15930
+ isWithinDeleteWindow: isWithinDeleteWindow(),
15286
15931
  messageId: mid,
15287
15932
  isPinned,
15288
15933
  isStarred,
@@ -15577,6 +16222,7 @@ function MessageSelectionBar({
15577
16222
  }
15578
16223
 
15579
16224
  // src/chat/active-channel-messages/utils.ts
16225
+ init_settings_types();
15580
16226
  var getMessageSenderId2 = (msg) => msg ? String(msg.senderId || msg.sender?._id || "") : "";
15581
16227
  var isLikelyObjectId = (value) => /^[a-f\d]{24}$/i.test(value);
15582
16228
  function resolveGroupSenderDisplay(message, allUsers = [], participants = []) {
@@ -15608,7 +16254,7 @@ var isSameMessageSide = (a, b, isGroupChat) => {
15608
16254
  const bId = getMessageSenderId2(b);
15609
16255
  return aId !== "" && aId === bId;
15610
16256
  };
15611
- function canDeleteSelectionForEveryone(selectedKeys, messages, isGroup) {
16257
+ function canDeleteSelectionForEveryone(selectedKeys, messages, isGroup, timers = DEFAULT_EFFECTIVE_SETTINGS.messageTimers) {
15612
16258
  if (selectedKeys.size === 0) return false;
15613
16259
  const parsed = [...selectedKeys].map((key) => parseSelectionKey(key));
15614
16260
  const messageIds = new Set(parsed.map((entry) => entry.messageId));
@@ -15616,7 +16262,7 @@ function canDeleteSelectionForEveryone(selectedKeys, messages, isGroup) {
15616
16262
  const messageId2 = [...messageIds][0];
15617
16263
  const message = messages.find((entry) => String(entry._id || entry.id) === messageId2);
15618
16264
  if (!message?.isOwnMessage) return false;
15619
- if (!isWithinMessageEditWindow(message.timestamp, isGroup)) return false;
16265
+ if (!isWithinMessageDeleteWindow2(message.timestamp, isGroup, timers)) return false;
15620
16266
  const hasAttachmentKey = parsed.some((entry) => entry.attachmentId);
15621
16267
  if (!hasAttachmentKey) {
15622
16268
  return selectedKeys.size === 1;
@@ -15785,6 +16431,8 @@ function useActiveChannelMessages({
15785
16431
  const emitDmDelete = useStore((s) => s.emitDmDelete);
15786
16432
  const emitGroupDelete = useStore((s) => s.emitGroupDelete);
15787
16433
  const loggedUserDetails = useStore((s) => s.loggedUserDetails);
16434
+ const { settings } = useEffectiveSettingsOptional();
16435
+ const messageTimers = settings.messageTimers;
15788
16436
  const scrollContainerRef = useRef(null);
15789
16437
  const bottomRef = useRef(null);
15790
16438
  const messageListInitializedRef = useRef(false);
@@ -15903,8 +16551,13 @@ function useActiveChannelMessages({
15903
16551
  }, []);
15904
16552
  const selectedForwardItems = resolveForwardItems(selectedKeys, displayMessages);
15905
16553
  const canDeleteForEveryone = useMemo(
15906
- () => canDeleteSelectionForEveryone(selectedKeys, displayMessages, !!activeChannel?.isGroup),
15907
- [selectedKeys, displayMessages, activeChannel?.isGroup]
16554
+ () => canDeleteSelectionForEveryone(
16555
+ selectedKeys,
16556
+ displayMessages,
16557
+ !!activeChannel?.isGroup,
16558
+ messageTimers
16559
+ ),
16560
+ [selectedKeys, displayMessages, activeChannel?.isGroup, messageTimers]
15908
16561
  );
15909
16562
  const emitSelectionDelete = useCallback(
15910
16563
  (deleteType) => {
@@ -15912,7 +16565,8 @@ function useActiveChannelMessages({
15912
16565
  if (deleteType === "everyone" && !canDeleteSelectionForEveryone(
15913
16566
  selectedKeys,
15914
16567
  displayMessages,
15915
- !!activeChannel?.isGroup
16568
+ !!activeChannel?.isGroup,
16569
+ messageTimers
15916
16570
  )) {
15917
16571
  return;
15918
16572
  }
@@ -15953,7 +16607,8 @@ function useActiveChannelMessages({
15953
16607
  conversationId,
15954
16608
  emitGroupDelete,
15955
16609
  emitDmDelete,
15956
- clearSelection
16610
+ clearSelection,
16611
+ messageTimers
15957
16612
  ]
15958
16613
  );
15959
16614
  const handleBatchDeleteForMe = useCallback(() => {
@@ -16291,8 +16946,8 @@ function CalendarDayButton({
16291
16946
  ...props
16292
16947
  }) {
16293
16948
  const defaultClassNames = getDefaultClassNames();
16294
- const ref = React2.useRef(null);
16295
- React2.useEffect(() => {
16949
+ const ref = React3.useRef(null);
16950
+ React3.useEffect(() => {
16296
16951
  if (modifiers.focused) ref.current?.focus();
16297
16952
  }, [modifiers.focused]);
16298
16953
  return /* @__PURE__ */ jsx(
@@ -17196,7 +17851,6 @@ var getAttachmentType = (file) => {
17196
17851
  };
17197
17852
 
17198
17853
  // src/chat/channel-message-box/useChannelMessageBox.ts
17199
- var MAX_ATTACHMENTS = COMPOSER_MAX_ATTACHMENTS;
17200
17854
  function useChannelMessageBox({
17201
17855
  activeChannel,
17202
17856
  conversationId,
@@ -17210,6 +17864,12 @@ function useChannelMessageBox({
17210
17864
  conversationId,
17211
17865
  onActiveChannelPatch
17212
17866
  );
17867
+ const { settings, getAttachmentsGate } = useEffectiveSettingsOptional();
17868
+ const attachmentsGate = getAttachmentsGate();
17869
+ const maxAttachments = settings.attachments.maxAttachmentsPerMessage;
17870
+ const maxFileSizeBytes = settings.attachments.maxFileSizeMB * 1024 * 1024;
17871
+ const allowedMimeTypes = settings.attachments.allowedMimeTypes;
17872
+ const acceptAttribute = buildAcceptFromMimeTypes(allowedMimeTypes);
17213
17873
  const [state, setState] = useState({
17214
17874
  messageInput: "",
17215
17875
  attachments: [],
@@ -17234,10 +17894,10 @@ function useChannelMessageBox({
17234
17894
  const composerDisabledReason = conversationId ? composerDisabledByConversation[conversationId] : void 0;
17235
17895
  const fileInputRef = useRef(null);
17236
17896
  const attachmentsCountRef = useRef(0);
17237
- React2__default.useEffect(() => {
17897
+ React3__default.useEffect(() => {
17238
17898
  attachmentsCountRef.current = state.attachments.length;
17239
17899
  }, [state.attachments.length]);
17240
- React2__default.useEffect(() => {
17900
+ React3__default.useEffect(() => {
17241
17901
  const draft = {
17242
17902
  messageInput: state.messageInput,
17243
17903
  attachments: state.attachments
@@ -17245,7 +17905,7 @@ function useChannelMessageBox({
17245
17905
  syncComposerRef(draft);
17246
17906
  updateConversationDraft(conversationIdRef.current, draft);
17247
17907
  }, [state.messageInput, state.attachments, syncComposerRef]);
17248
- React2__default.useEffect(() => {
17908
+ React3__default.useEffect(() => {
17249
17909
  if (typingTimeoutRef.current) {
17250
17910
  clearTimeout(typingTimeoutRef.current);
17251
17911
  typingTimeoutRef.current = null;
@@ -17305,21 +17965,52 @@ function useChannelMessageBox({
17305
17965
  const handleFileChange = (e) => {
17306
17966
  const files = e.target.files ? Array.from(e.target.files) : [];
17307
17967
  if (!files.length) return;
17968
+ if (!attachmentsGate.enabled) {
17969
+ updateState({
17970
+ attachmentError: attachmentsGate.disabledReason || "Attachments are disabled by your administrator."
17971
+ });
17972
+ if (fileInputRef.current) fileInputRef.current.value = "";
17973
+ return;
17974
+ }
17308
17975
  const currentCount = attachmentsCountRef.current;
17309
- const remaining = MAX_ATTACHMENTS - currentCount;
17976
+ const remaining = maxAttachments - currentCount;
17310
17977
  if (remaining <= 0) {
17311
- updateState({ attachmentError: `Maximum ${MAX_ATTACHMENTS} files allowed` });
17978
+ updateState({ attachmentError: `Maximum ${maxAttachments} files allowed` });
17979
+ if (fileInputRef.current) fileInputRef.current.value = "";
17980
+ return;
17981
+ }
17982
+ const validFiles = [];
17983
+ const rejectionMessages = [];
17984
+ for (const file of files) {
17985
+ if (!matchesAllowedMimeType(file.type, allowedMimeTypes)) {
17986
+ rejectionMessages.push(`"${file.name}" type is not allowed`);
17987
+ continue;
17988
+ }
17989
+ if (file.size > maxFileSizeBytes) {
17990
+ rejectionMessages.push(
17991
+ `"${file.name}" exceeds ${settings.attachments.maxFileSizeMB} MB (got ${formatFileSizeMB(file.size)})`
17992
+ );
17993
+ continue;
17994
+ }
17995
+ validFiles.push(file);
17996
+ }
17997
+ if (validFiles.length === 0) {
17998
+ updateState({
17999
+ attachmentError: rejectionMessages[0] || "Selected files are not allowed"
18000
+ });
17312
18001
  if (fileInputRef.current) fileInputRef.current.value = "";
17313
18002
  return;
17314
18003
  }
17315
- if (files.length > remaining) {
18004
+ if (validFiles.length > remaining) {
17316
18005
  updateState({
17317
18006
  attachmentError: `You can upload only ${remaining} more file${remaining > 1 ? "s" : ""}`
17318
18007
  });
18008
+ } else if (rejectionMessages.length > 0) {
18009
+ updateState({ attachmentError: rejectionMessages[0] });
17319
18010
  } else {
17320
18011
  updateState({ attachmentError: "" });
17321
18012
  }
17322
- const filesToAdd = files.slice(0, remaining);
18013
+ const filesToAdd = validFiles.slice(0, remaining);
17323
18014
  attachmentsCountRef.current = currentCount + filesToAdd.length;
17324
18015
  const newAttachments = filesToAdd.map((file) => ({
17325
18016
  id: `att-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
@@ -17376,7 +18067,7 @@ function useChannelMessageBox({
17376
18067
  return {
17377
18068
  ...prev,
17378
18069
  attachments: nextAttachments,
17379
- attachmentError: nextAttachments.length < MAX_ATTACHMENTS ? "" : prev.attachmentError
18070
+ attachmentError: nextAttachments.length < maxAttachments ? "" : prev.attachmentError
17380
18071
  };
17381
18072
  });
17382
18073
  };
@@ -17483,7 +18174,10 @@ function useChannelMessageBox({
17483
18174
  onlyAdminCanSendMessage,
17484
18175
  fileInputRef,
17485
18176
  hasUploadingAttachments,
17486
- maxAttachments: MAX_ATTACHMENTS,
18177
+ maxAttachments,
18178
+ acceptAttribute,
18179
+ attachmentsEnabled: attachmentsGate.enabled,
18180
+ attachmentsDisabledReason: attachmentsGate.disabledReason,
17487
18181
  handleInputChange,
17488
18182
  handleFileChange,
17489
18183
  handleRemoveAttachment,
@@ -17511,6 +18205,9 @@ var ChannelMessageBoxView = (props) => {
17511
18205
  fileInputRef,
17512
18206
  hasUploadingAttachments,
17513
18207
  maxAttachments,
18208
+ acceptAttribute,
18209
+ attachmentsEnabled,
18210
+ attachmentsDisabledReason,
17514
18211
  handleInputChange,
17515
18212
  handleFileChange,
17516
18213
  handleRemoveAttachment,
@@ -17608,16 +18305,23 @@ var ChannelMessageBoxView = (props) => {
17608
18305
  ),
17609
18306
  /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1.5 p-1.5", children: [
17610
18307
  /* @__PURE__ */ jsx(
17611
- Button,
18308
+ AdminPermissionTooltip,
17612
18309
  {
17613
- type: "button",
17614
- variant: "ghost",
17615
- size: "icon",
17616
- className: "shrink-0 size-9 rounded-xl text-(--chat-muted) transition-all hover:bg-(--chat-hover) hover:text-(--chat-text)",
17617
- onClick: () => !hasUploadingAttachments && fileInputRef.current?.click(),
17618
- disabled: hasUploadingAttachments,
17619
- "aria-label": "Attach files",
17620
- children: /* @__PURE__ */ jsx(Paperclip, { size: 16 })
18310
+ disabled: !attachmentsEnabled,
18311
+ message: attachmentsDisabledReason,
18312
+ children: /* @__PURE__ */ jsx(
18313
+ Button,
18314
+ {
18315
+ type: "button",
18316
+ variant: "ghost",
18317
+ size: "icon",
18318
+ className: "shrink-0 size-9 rounded-xl text-(--chat-muted) transition-all hover:bg-(--chat-hover) hover:text-(--chat-text) disabled:opacity-40",
18319
+ onClick: () => attachmentsEnabled && !hasUploadingAttachments && fileInputRef.current?.click(),
18320
+ disabled: !attachmentsEnabled || hasUploadingAttachments,
18321
+ "aria-label": "Attach files",
18322
+ children: /* @__PURE__ */ jsx(Paperclip, { size: 16 })
18323
+ }
18324
+ )
17621
18325
  }
17622
18326
  ),
17623
18327
  /* @__PURE__ */ jsx(
@@ -17627,8 +18331,9 @@ var ChannelMessageBoxView = (props) => {
17627
18331
  ref: fileInputRef,
17628
18332
  className: "hidden",
17629
18333
  multiple: true,
17630
- accept: "image/*,video/*,audio/*,.pdf,.doc,.docx,.xls,.xlsx",
17631
- onChange: handleFileChange
18334
+ accept: acceptAttribute || void 0,
18335
+ onChange: handleFileChange,
18336
+ disabled: !attachmentsEnabled
17632
18337
  }
17633
18338
  ),
17634
18339
  /* @__PURE__ */ jsxs(Popover, { children: [
@@ -17916,6 +18621,7 @@ var ChatPanelAlerts = () => {
17916
18621
  const globalAppError = useStore((s) => s.globalAppError);
17917
18622
  const conversationErrors = useStore((s) => s.conversationErrors);
17918
18623
  const clearAppError = useStore((s) => s.clearAppError);
18624
+ const setRateLimitResetAt = useStore((s) => s.setRateLimitResetAt);
17919
18625
  const rateLimitResetAt2 = useStore((s) => s.rateLimitResetAt);
17920
18626
  const [now, setNow] = useState(() => Date.now());
17921
18627
  const conversationAppError = activeConversationId ? conversationErrors[activeConversationId] ?? null : null;
@@ -17952,7 +18658,7 @@ var ChatPanelAlerts = () => {
17952
18658
  onDismiss: () => clearAppError(activeConversationId)
17953
18659
  });
17954
18660
  }
17955
- if (globalAppError?.message) {
18661
+ if (!activeConversationId && globalAppError?.message) {
17956
18662
  push({
17957
18663
  id: `global-app-error-${globalAppError.type}`,
17958
18664
  type: "error",
@@ -17967,7 +18673,8 @@ var ChatPanelAlerts = () => {
17967
18673
  id: "rate-limit",
17968
18674
  type: "warning",
17969
18675
  message: `Too many requests. Please wait ${seconds}s before trying again.`,
17970
- icon: AlertCircle
18676
+ icon: AlertCircle,
18677
+ onDismiss: () => setRateLimitResetAt(0)
17971
18678
  });
17972
18679
  }
17973
18680
  if (info?.trim()) {
@@ -17990,7 +18697,8 @@ var ChatPanelAlerts = () => {
17990
18697
  onDismissError,
17991
18698
  onDismissInfo,
17992
18699
  info,
17993
- clearAppError
18700
+ clearAppError,
18701
+ setRateLimitResetAt
17994
18702
  ]);
17995
18703
  if (alerts.length === 0) return null;
17996
18704
  return /* @__PURE__ */ 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) => {
@@ -18006,16 +18714,20 @@ var ChatPanelAlerts = () => {
18006
18714
  children: [
18007
18715
  /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
18008
18716
  /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 leading-relaxed", children: alert.message }),
18009
- alert.onDismiss && /* @__PURE__ */ jsx(
18717
+ alert.onDismiss ? /* @__PURE__ */ jsx(
18010
18718
  "button",
18011
18719
  {
18012
18720
  type: "button",
18013
- onClick: alert.onDismiss,
18721
+ onClick: (event) => {
18722
+ event.preventDefault();
18723
+ event.stopPropagation();
18724
+ alert.onDismiss?.();
18725
+ },
18014
18726
  className: "shrink-0 rounded-md p-0.5 opacity-70 transition-opacity hover:opacity-100",
18015
18727
  "aria-label": "Dismiss",
18016
18728
  children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
18017
18729
  }
18018
- )
18730
+ ) : null
18019
18731
  ]
18020
18732
  },
18021
18733
  alert.id
@@ -18543,8 +19255,8 @@ var ChatMain = ({
18543
19255
  viewportHeight = "full",
18544
19256
  viewportClassName
18545
19257
  }) => {
18546
- const clientObj = React2__default.useMemo(() => ({ id: clientId }), [clientId]);
18547
- const uiConfigObj = React2__default.useMemo(
19258
+ const clientObj = React3__default.useMemo(() => ({ id: clientId }), [clientId]);
19259
+ const uiConfigObj = React3__default.useMemo(
18548
19260
  () => ({
18549
19261
  ...uiConfig || {},
18550
19262
  components: { ...uiConfig?.components, ...components },
@@ -18915,8 +19627,10 @@ var packageDefaultComponents = {
18915
19627
  };
18916
19628
 
18917
19629
  // src/index.ts
19630
+ init_settings_types();
19631
+ init_api_service();
18918
19632
  var index_default = ChatMain_default;
18919
19633
 
18920
- export { CHAT_API_KEYS, CHAT_GET_API_KEYS, Calendar, CalendarDayButton, Channel, ChannelHeaderView_default as ChannelHeader, ChannelListView_default as ChannelList, ChannelListItem_default as ChannelListItem, Chat, ChatAlertsProvider, ChatAvatar_default as ChatAvatar, ChatCustomizationProvider, ChatDateJumpMenu, ChatLayout_default as ChatLayout, ChatLocaleProvider, ChatMain_default as ChatMain, ChatThemeProvider, ChatViewport, DefaultChannelListItem, DefaultChatAvatar, DefaultChatLayout_default as DefaultChatLayout, ForegroundPushBridge, ForwardModalView as ForwardModal, HeaderCallActions_default as HeaderCallActions, LoggedUserDetails_default as LoggedUserDetails, LoggedUserSettingsContent_default as LoggedUserSettingsContent, LoggedUserSettingsDialog_default as LoggedUserSettingsDialog, LoggedUserSettingsTrigger_default as LoggedUserSettingsTrigger, ChannelMessageBoxView_default as MessageInput, MessageItemView as MessageItem, ActiveChannelMessagesView_default as MessageList, NOTIFICATION_CLICK_SW_TYPE, OPEN_CONVERSATION_EVENT, PUSH_BROADCAST_CHANNEL, PUSH_CHANGED_EVENT, PUSH_DATA_CACHE_NAME, PushNotificationToggle, apiGetPushConfig, apiGetPushPreference, apiRegisterPushToken, apiRemovePushToken, apiUpdatePushPreference, buildChannelFromPushRequest, buildLoggedUserProfile, buildVersionedApiUrl, capitalizeFirst, clampJumpDate, consumePendingOpenConversation, consumePendingOpenFromPushCache, consumePendingOpenRequest, index_default as default, defaultChatClassNames, defaultChatComponents, defaultChatFeatures, defaultChatLayoutConfig, disablePushOnThisDevice, downloadFile, enablePushOnThisDevice, getChatApiVersions, getChatBaseUrl, getChatQueryParamApis, getChatQueryParams, getChatQueryParamsByApi, getChatSocketUrl, getFirstAndLastNameOneCharacter, getResponsiveWidth, getSocketConfig, getStoredPushToken, installNotificationClickBridge, isEmpty, isPushSupported, mergeChatCustomization, mergeChatLayoutConfig, onForegroundPush, packageDefaultComponents, peekPendingOpenConversation, peekPendingOpenRequest, requestOpenConversation, resolveApiRoot, resolveApiUrl, resolveChatApiKey, resolveConversationIdFromPushData, resolveJumpDateBounds, resolveJumpPreset, resolveJumpStep, resolveSocketUrl, setChatAccessToken, setChatApiVersions, setChatBaseURL, setChatClientId, setChatPushApiVersion, setChatQueryParamApis, setChatQueryParams, setChatQueryParamsByApi, setChatSocketUrl, showNotification, smoothScrollToMessage, socket_service_default as socketService, startOfLocalDay, toDateInputValue, uniqueList, useChatAlerts, useChatContext, useChatController, useChatCustomization, useChatCustomizationOptional, useChatFeatures, useChatFeaturesOptional, useChatLocale, useStore as useChatStore, useChatTheme, usePushNotifications };
19634
+ export { ADMIN_PERMISSION_DENIED_MESSAGE, CALLS_NOT_ALLOWED_BY_PLATFORM_MESSAGE, CALLS_NOT_CONFIGURED_MESSAGE, CHAT_API_KEYS, CHAT_GET_API_KEYS, Calendar, CalendarDayButton, Channel, ChannelHeaderView_default as ChannelHeader, ChannelListView_default as ChannelList, ChannelListItem_default as ChannelListItem, Chat, ChatAlertsProvider, ChatAvatar_default as ChatAvatar, ChatCustomizationProvider, ChatDateJumpMenu, ChatEffectiveSettingsProvider, ChatLayout_default as ChatLayout, ChatLocaleProvider, ChatMain_default as ChatMain, ChatThemeProvider, ChatViewport, DEFAULT_EFFECTIVE_SETTINGS, DefaultChannelListItem, DefaultChatAvatar, DefaultChatLayout_default as DefaultChatLayout, ForegroundPushBridge, ForwardModalView as ForwardModal, HeaderCallActions_default as HeaderCallActions, LoggedUserDetails_default as LoggedUserDetails, LoggedUserSettingsContent_default as LoggedUserSettingsContent, LoggedUserSettingsDialog_default as LoggedUserSettingsDialog, LoggedUserSettingsTrigger_default as LoggedUserSettingsTrigger, ChannelMessageBoxView_default as MessageInput, MessageItemView as MessageItem, ActiveChannelMessagesView_default as MessageList, NOTIFICATION_CLICK_SW_TYPE, OPEN_CONVERSATION_EVENT, PUSH_BROADCAST_CHANNEL, PUSH_CHANGED_EVENT, PUSH_DATA_CACHE_NAME, PushNotificationToggle, apiGetPushConfig, apiGetPushPreference, apiRegisterPushToken, apiRemovePushToken, apiUpdatePushPreference, buildChannelFromPushRequest, buildLoggedUserProfile, buildVersionedApiUrl, capitalizeFirst, clampJumpDate, consumePendingOpenConversation, consumePendingOpenFromPushCache, consumePendingOpenRequest, index_default as default, defaultChatClassNames, defaultChatComponents, defaultChatFeatures, defaultChatLayoutConfig, disablePushOnThisDevice, downloadFile, enablePushOnThisDevice, fetchEffectiveSettings, getChatApiVersions, getChatBaseUrl, getChatQueryParamApis, getChatQueryParams, getChatQueryParamsByApi, getChatSocketUrl, getFirstAndLastNameOneCharacter, getResponsiveWidth, getSocketConfig, getStoredPushToken, installNotificationClickBridge, isEmpty, isPushSupported, mergeChatCustomization, mergeChatLayoutConfig, onForegroundPush, packageDefaultComponents, peekPendingOpenConversation, peekPendingOpenRequest, requestOpenConversation, resolveApiRoot, resolveApiUrl, resolveChatApiKey, resolveConversationIdFromPushData, resolveJumpDateBounds, resolveJumpPreset, resolveJumpStep, resolveSocketUrl, setChatAccessToken, setChatApiVersions, setChatBaseURL, setChatClientId, setChatPushApiVersion, setChatQueryParamApis, setChatQueryParams, setChatQueryParamsByApi, setChatSocketUrl, showNotification, smoothScrollToMessage, socket_service_default as socketService, startOfLocalDay, toDateInputValue, uniqueList, useChatAlerts, useChatContext, useChatController, useChatCustomization, useChatCustomizationOptional, useChatFeatures, useChatFeaturesOptional, useChatLocale, useStore as useChatStore, useChatTheme, useEffectiveSettings, useEffectiveSettingsOptional, usePushNotifications };
18921
19635
  //# sourceMappingURL=index.mjs.map
18922
19636
  //# sourceMappingURL=index.mjs.map