@realtimexsco/live-chat 1.4.14 → 1.4.16
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/README.md +5 -3
- package/dist/index.cjs +169 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +169 -87
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +18 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@realtimexsco/live-chat)
|
|
6
6
|
[](https://www.npmjs.com/package/@realtimexsco/live-chat)
|
|
7
|
-
[](
|
|
7
|
+
[](#license)
|
|
8
8
|
|
|
9
9
|
| | |
|
|
10
10
|
|---|---|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
| **Styles** | `@realtimexsco/live-chat/styles.css` |
|
|
13
13
|
| **Requires** | React 17+, Tailwind CSS **v4**, Zustand 4+ |
|
|
14
14
|
| **Docs** | [Package documentation](https://realtimex.softwareco.com/documentations/package) |
|
|
15
|
-
| **License** | [MIT](
|
|
15
|
+
| **License** | [MIT](#license) |
|
|
16
16
|
|
|
17
17
|
Socket.IO, REST client, Zustand store, Radix UI, emoji picker, and chat UI are **bundled**. Your app only installs peer dependencies.
|
|
18
18
|
|
|
@@ -61,10 +61,12 @@ DMs · groups · Socket.IO · reactions · replies · forward · edit/delete ·
|
|
|
61
61
|
|-------|------|
|
|
62
62
|
| Full setup & docs | [https://realtimex.softwareco.com/documentations/package](https://realtimex.softwareco.com/documentations/package) |
|
|
63
63
|
| npm package | [npmjs.com/package/@realtimexsco/live-chat](https://www.npmjs.com/package/@realtimexsco/live-chat) |
|
|
64
|
-
| License | [MIT](
|
|
64
|
+
| License | [MIT](#license) |
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
+
<a id="license"></a>
|
|
69
|
+
|
|
68
70
|
## License
|
|
69
71
|
|
|
70
72
|
The MIT License (MIT)
|
package/dist/index.cjs
CHANGED
|
@@ -6906,8 +6906,21 @@ function AdminPermissionTooltip({
|
|
|
6906
6906
|
if (!disabled || !message) {
|
|
6907
6907
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
6908
6908
|
}
|
|
6909
|
+
const gatedChildren = React3__namespace.default.Children.map(children, (child) => {
|
|
6910
|
+
if (!React3__namespace.default.isValidElement(child)) return child;
|
|
6911
|
+
return React3__namespace.default.cloneElement(child, {
|
|
6912
|
+
className: cn(child.props.className, "pointer-events-none")
|
|
6913
|
+
});
|
|
6914
|
+
});
|
|
6909
6915
|
return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
6910
|
-
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6916
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6917
|
+
"span",
|
|
6918
|
+
{
|
|
6919
|
+
className: cn("inline-flex cursor-not-allowed", className),
|
|
6920
|
+
tabIndex: 0,
|
|
6921
|
+
children: gatedChildren
|
|
6922
|
+
}
|
|
6923
|
+
) }),
|
|
6911
6924
|
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side, className: "max-w-[240px] text-xs", children: message })
|
|
6912
6925
|
] });
|
|
6913
6926
|
}
|
|
@@ -7320,9 +7333,34 @@ var PushNotificationToggle = ({
|
|
|
7320
7333
|
children
|
|
7321
7334
|
}) => {
|
|
7322
7335
|
const push = usePushNotifications();
|
|
7323
|
-
const { getPushNotificationGate } = useEffectiveSettingsOptional();
|
|
7336
|
+
const { loading: settingsLoading, getPushNotificationGate } = useEffectiveSettingsOptional();
|
|
7324
7337
|
const adminGate = getPushNotificationGate();
|
|
7325
7338
|
const [isToggling, setIsToggling] = React3.useState(false);
|
|
7339
|
+
const isBootstrapping = push.loading || settingsLoading;
|
|
7340
|
+
if (isBootstrapping && !push.supported) {
|
|
7341
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7342
|
+
"div",
|
|
7343
|
+
{
|
|
7344
|
+
className: cn(
|
|
7345
|
+
"flex items-center justify-between gap-4 rounded-xl border border-(--chat-border) bg-(--chat-surface) px-4 py-3",
|
|
7346
|
+
className
|
|
7347
|
+
),
|
|
7348
|
+
children: [
|
|
7349
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
|
|
7350
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-(--chat-text)", children: label }),
|
|
7351
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-(--chat-muted)", children: "Loading\u2026" })
|
|
7352
|
+
] }),
|
|
7353
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7354
|
+
lucideReact.Loader2,
|
|
7355
|
+
{
|
|
7356
|
+
className: "size-5 shrink-0 animate-spin text-(--chat-theme)",
|
|
7357
|
+
"aria-label": "Loading push notification settings"
|
|
7358
|
+
}
|
|
7359
|
+
)
|
|
7360
|
+
]
|
|
7361
|
+
}
|
|
7362
|
+
);
|
|
7363
|
+
}
|
|
7326
7364
|
if (!push.supported) {
|
|
7327
7365
|
return null;
|
|
7328
7366
|
}
|
|
@@ -7330,8 +7368,8 @@ var PushNotificationToggle = ({
|
|
|
7330
7368
|
const permissionBlocked = push.permission === "denied";
|
|
7331
7369
|
const adminBlocked = !adminGate.enabled;
|
|
7332
7370
|
const notConfigured = !push.configured;
|
|
7333
|
-
const showLoader = isToggling;
|
|
7334
|
-
const isDisabled = showLoader || permissionBlocked || push.loading || adminBlocked || notConfigured;
|
|
7371
|
+
const showLoader = isToggling || isBootstrapping;
|
|
7372
|
+
const isDisabled = showLoader || permissionBlocked || push.loading || settingsLoading || adminBlocked || notConfigured;
|
|
7335
7373
|
const handleChange = async (checked) => {
|
|
7336
7374
|
if (adminBlocked || notConfigured) return;
|
|
7337
7375
|
setIsToggling(true);
|
|
@@ -9003,14 +9041,12 @@ var DefaultHeaderCallActions = ({
|
|
|
9003
9041
|
onVideoCall,
|
|
9004
9042
|
className
|
|
9005
9043
|
}) => {
|
|
9006
|
-
const { components, slotClassName
|
|
9044
|
+
const { components, slotClassName } = useChatCustomizationOptional();
|
|
9007
9045
|
const { getAudioCallGate, getVideoCallGate } = useEffectiveSettingsOptional();
|
|
9008
9046
|
const PhoneSlot = components.PhoneCallButton;
|
|
9009
9047
|
const VideoSlot = components.VideoCallButton;
|
|
9010
|
-
const hideInGroups = features.hideCallActionsInGroupChats ?? false;
|
|
9011
9048
|
const audioGate = getAudioCallGate();
|
|
9012
9049
|
const videoGate = getVideoCallGate();
|
|
9013
|
-
if (hideInGroups && activeChannel.isGroup) return null;
|
|
9014
9050
|
if (!showPhoneCall && !showVideoCall) return null;
|
|
9015
9051
|
const phoneEnabled = showPhoneCall && audioGate.enabled;
|
|
9016
9052
|
const videoEnabled = showVideoCall && videoGate.enabled;
|
|
@@ -9020,6 +9056,7 @@ var DefaultHeaderCallActions = ({
|
|
|
9020
9056
|
{
|
|
9021
9057
|
disabled: !audioGate.enabled,
|
|
9022
9058
|
message: audioGate.disabledReason,
|
|
9059
|
+
side: "bottom",
|
|
9023
9060
|
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9024
9061
|
PhoneSlot,
|
|
9025
9062
|
{
|
|
@@ -9029,7 +9066,7 @@ var DefaultHeaderCallActions = ({
|
|
|
9029
9066
|
className: cn(
|
|
9030
9067
|
className,
|
|
9031
9068
|
slotClassName("phoneCallButton"),
|
|
9032
|
-
!audioGate.enabled && "
|
|
9069
|
+
!audioGate.enabled && "opacity-40"
|
|
9033
9070
|
)
|
|
9034
9071
|
}
|
|
9035
9072
|
) })
|
|
@@ -9039,6 +9076,7 @@ var DefaultHeaderCallActions = ({
|
|
|
9039
9076
|
{
|
|
9040
9077
|
disabled: !audioGate.enabled,
|
|
9041
9078
|
message: audioGate.disabledReason,
|
|
9079
|
+
side: "bottom",
|
|
9042
9080
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9043
9081
|
Button,
|
|
9044
9082
|
{
|
|
@@ -9058,6 +9096,7 @@ var DefaultHeaderCallActions = ({
|
|
|
9058
9096
|
{
|
|
9059
9097
|
disabled: !videoGate.enabled,
|
|
9060
9098
|
message: videoGate.disabledReason,
|
|
9099
|
+
side: "bottom",
|
|
9061
9100
|
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9062
9101
|
VideoSlot,
|
|
9063
9102
|
{
|
|
@@ -9067,7 +9106,7 @@ var DefaultHeaderCallActions = ({
|
|
|
9067
9106
|
className: cn(
|
|
9068
9107
|
className,
|
|
9069
9108
|
slotClassName("videoCallButton"),
|
|
9070
|
-
!videoGate.enabled && "
|
|
9109
|
+
!videoGate.enabled && "opacity-40"
|
|
9071
9110
|
)
|
|
9072
9111
|
}
|
|
9073
9112
|
) })
|
|
@@ -9077,6 +9116,7 @@ var DefaultHeaderCallActions = ({
|
|
|
9077
9116
|
{
|
|
9078
9117
|
disabled: !videoGate.enabled,
|
|
9079
9118
|
message: videoGate.disabledReason,
|
|
9119
|
+
side: "bottom",
|
|
9080
9120
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9081
9121
|
Button,
|
|
9082
9122
|
{
|
|
@@ -9094,16 +9134,13 @@ var DefaultHeaderCallActions = ({
|
|
|
9094
9134
|
] });
|
|
9095
9135
|
};
|
|
9096
9136
|
var HeaderCallActions = (props) => {
|
|
9097
|
-
const { components, slotClassName
|
|
9137
|
+
const { components, slotClassName } = useChatCustomizationOptional();
|
|
9098
9138
|
const Custom = components.HeaderCallActions;
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
if (!showPhoneCall && !showVideoCall) return null;
|
|
9105
|
-
}
|
|
9106
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center gap-0.5", slotClassName("headerCallActions")), children: Custom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeaderCallActions, { ...props }) });
|
|
9139
|
+
const showPhoneCall = props.showPhoneCall ?? true;
|
|
9140
|
+
const showVideoCall = props.showVideoCall ?? true;
|
|
9141
|
+
if (!showPhoneCall && !showVideoCall) return null;
|
|
9142
|
+
const useCustom = Custom != null && Custom !== HeaderCallActions;
|
|
9143
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center gap-0.5", slotClassName("headerCallActions")), children: useCustom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeaderCallActions, { ...props }) });
|
|
9107
9144
|
};
|
|
9108
9145
|
var HeaderCallActions_default = HeaderCallActions;
|
|
9109
9146
|
function OptionsMenuItem({
|
|
@@ -12922,9 +12959,91 @@ init_useStore();
|
|
|
12922
12959
|
|
|
12923
12960
|
// src/hooks/useGroupInfo.ts
|
|
12924
12961
|
init_useStore();
|
|
12962
|
+
|
|
12963
|
+
// src/lib/effective-settings.helpers.ts
|
|
12964
|
+
function minutesToMs(minutes) {
|
|
12965
|
+
return Math.max(0, minutes) * 60 * 1e3;
|
|
12966
|
+
}
|
|
12967
|
+
function getEditWindowMs(timers, isGroup) {
|
|
12968
|
+
return minutesToMs(isGroup ? timers.groupEditMinutes : timers.dmEditMinutes);
|
|
12969
|
+
}
|
|
12970
|
+
function getDeleteWindowMs(timers, isGroup) {
|
|
12971
|
+
return minutesToMs(
|
|
12972
|
+
isGroup ? timers.groupDeleteMinutes : timers.dmDeleteMinutes
|
|
12973
|
+
);
|
|
12974
|
+
}
|
|
12975
|
+
function isWithinWindow(createdAt, windowMs) {
|
|
12976
|
+
if (!createdAt) return false;
|
|
12977
|
+
const date = new Date(createdAt);
|
|
12978
|
+
if (isNaN(date.getTime())) return false;
|
|
12979
|
+
const diff = Date.now() - date.getTime();
|
|
12980
|
+
return diff >= 0 && diff < windowMs;
|
|
12981
|
+
}
|
|
12982
|
+
function isWithinMessageEditWindow(createdAt, timers, isGroup) {
|
|
12983
|
+
return isWithinWindow(createdAt, getEditWindowMs(timers, isGroup));
|
|
12984
|
+
}
|
|
12985
|
+
function isWithinMessageDeleteWindow(createdAt, timers, isGroup) {
|
|
12986
|
+
return isWithinWindow(createdAt, getDeleteWindowMs(timers, isGroup));
|
|
12987
|
+
}
|
|
12988
|
+
function allowsAllMimeTypes(allowedMimeTypes) {
|
|
12989
|
+
return allowedMimeTypes.some((pattern) => {
|
|
12990
|
+
const normalized = pattern.trim().toLowerCase();
|
|
12991
|
+
return normalized === "*" || normalized === "*/*";
|
|
12992
|
+
});
|
|
12993
|
+
}
|
|
12994
|
+
function matchesAllowedMimeType(fileType, allowedMimeTypes) {
|
|
12995
|
+
if (!allowedMimeTypes.length) return false;
|
|
12996
|
+
if (allowsAllMimeTypes(allowedMimeTypes)) return true;
|
|
12997
|
+
const mime = (fileType || "application/octet-stream").toLowerCase();
|
|
12998
|
+
return allowedMimeTypes.some((pattern) => {
|
|
12999
|
+
const normalized = pattern.trim().toLowerCase();
|
|
13000
|
+
if (!normalized) return false;
|
|
13001
|
+
if (normalized.endsWith("/*")) {
|
|
13002
|
+
const prefix = normalized.slice(0, -1);
|
|
13003
|
+
return mime.startsWith(prefix);
|
|
13004
|
+
}
|
|
13005
|
+
return mime === normalized;
|
|
13006
|
+
});
|
|
13007
|
+
}
|
|
13008
|
+
function buildAcceptFromMimeTypes(allowedMimeTypes) {
|
|
13009
|
+
if (allowsAllMimeTypes(allowedMimeTypes)) return "";
|
|
13010
|
+
return allowedMimeTypes.map((type) => type.trim()).filter(Boolean).join(",");
|
|
13011
|
+
}
|
|
13012
|
+
function formatFileSizeMB(sizeBytes) {
|
|
13013
|
+
return `${(sizeBytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
13014
|
+
}
|
|
13015
|
+
var GROUP_PERMISSION_KEYS = [
|
|
13016
|
+
"onlyAdminCanSendMessage",
|
|
13017
|
+
"onlyAdminCanEditInfo",
|
|
13018
|
+
"senderCanEditMessage",
|
|
13019
|
+
"allowMemberAdd",
|
|
13020
|
+
"allowMemberRemove",
|
|
13021
|
+
"moderationEnabled"
|
|
13022
|
+
];
|
|
13023
|
+
function resolveGroupPermissions(conversationPermissions, defaults, locked = []) {
|
|
13024
|
+
const next = { ...defaults };
|
|
13025
|
+
if (conversationPermissions) {
|
|
13026
|
+
for (const key of GROUP_PERMISSION_KEYS) {
|
|
13027
|
+
const value = conversationPermissions[key];
|
|
13028
|
+
if (typeof value === "boolean") {
|
|
13029
|
+
next[key] = value;
|
|
13030
|
+
}
|
|
13031
|
+
}
|
|
13032
|
+
}
|
|
13033
|
+
for (const key of locked) {
|
|
13034
|
+
if (GROUP_PERMISSION_KEYS.includes(String(key))) {
|
|
13035
|
+
const typedKey = key;
|
|
13036
|
+
next[typedKey] = defaults[typedKey];
|
|
13037
|
+
}
|
|
13038
|
+
}
|
|
13039
|
+
return next;
|
|
13040
|
+
}
|
|
13041
|
+
|
|
13042
|
+
// src/hooks/useGroupInfo.ts
|
|
12925
13043
|
var useGroupInfo = (conversationId) => {
|
|
12926
13044
|
const conversationInfos = exports.useChatStore((s) => s.conversationInfos);
|
|
12927
13045
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
13046
|
+
const { settings } = useEffectiveSettingsOptional();
|
|
12928
13047
|
const info = conversationId ? conversationInfos[conversationId] : null;
|
|
12929
13048
|
const isAdmin = React3.useMemo(() => {
|
|
12930
13049
|
if (!info || !loggedUserDetails) return false;
|
|
@@ -12940,7 +13059,14 @@ var useGroupInfo = (conversationId) => {
|
|
|
12940
13059
|
}
|
|
12941
13060
|
return String(ownerId) === String(loggedUserDetails._id);
|
|
12942
13061
|
}, [info, loggedUserDetails]);
|
|
12943
|
-
const permissions =
|
|
13062
|
+
const permissions = React3.useMemo(() => {
|
|
13063
|
+
if (!info) return null;
|
|
13064
|
+
return resolveGroupPermissions(
|
|
13065
|
+
info.groupPermissions,
|
|
13066
|
+
settings.groupPolicy.defaults,
|
|
13067
|
+
settings.groupPolicy.locked
|
|
13068
|
+
);
|
|
13069
|
+
}, [info, settings.groupPolicy.defaults, settings.groupPolicy.locked]);
|
|
12944
13070
|
const userPermissions = React3.useMemo(() => {
|
|
12945
13071
|
return {
|
|
12946
13072
|
canSendMessage: isOwner || isAdmin || !permissions?.onlyAdminCanSendMessage,
|
|
@@ -12948,7 +13074,6 @@ var useGroupInfo = (conversationId) => {
|
|
|
12948
13074
|
canAddMember: isOwner || !!permissions?.allowMemberAdd,
|
|
12949
13075
|
canRemoveMember: isOwner || !!permissions?.allowMemberRemove,
|
|
12950
13076
|
canEditMessage: isOwner || isAdmin || !!permissions?.senderCanEditMessage
|
|
12951
|
-
// You can add more derived permissions here as needed
|
|
12952
13077
|
};
|
|
12953
13078
|
}, [isOwner, isAdmin, permissions]);
|
|
12954
13079
|
return {
|
|
@@ -13375,14 +13500,20 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
|
|
|
13375
13500
|
const [permissions, setPermissions] = React3.useState(null);
|
|
13376
13501
|
const [isSaving, setIsSaving] = React3.useState(false);
|
|
13377
13502
|
React3.useEffect(() => {
|
|
13378
|
-
if (
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
|
|
13503
|
+
if (!isOpen) return;
|
|
13504
|
+
setPermissions(
|
|
13505
|
+
resolveGroupPermissions(
|
|
13506
|
+
conversationInfo?.groupPermissions,
|
|
13507
|
+
settings.groupPolicy.defaults,
|
|
13508
|
+
settings.groupPolicy.locked
|
|
13509
|
+
)
|
|
13510
|
+
);
|
|
13511
|
+
}, [
|
|
13512
|
+
isOpen,
|
|
13513
|
+
conversationInfo?.groupPermissions,
|
|
13514
|
+
settings.groupPolicy.defaults,
|
|
13515
|
+
settings.groupPolicy.locked
|
|
13516
|
+
]);
|
|
13386
13517
|
if (!conversationId || !permissions) return null;
|
|
13387
13518
|
const handleToggle = (key) => {
|
|
13388
13519
|
if (isGroupPermissionLocked(key)) return;
|
|
@@ -13392,7 +13523,12 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
|
|
|
13392
13523
|
if (!conversationId || !permissions) return;
|
|
13393
13524
|
setIsSaving(true);
|
|
13394
13525
|
try {
|
|
13395
|
-
|
|
13526
|
+
const payload = resolveGroupPermissions(
|
|
13527
|
+
permissions,
|
|
13528
|
+
settings.groupPolicy.defaults,
|
|
13529
|
+
settings.groupPolicy.locked
|
|
13530
|
+
);
|
|
13531
|
+
await updateGroupPermissions(conversationId, payload);
|
|
13396
13532
|
onOpenChange(false);
|
|
13397
13533
|
} finally {
|
|
13398
13534
|
setIsSaving(false);
|
|
@@ -13402,8 +13538,8 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
|
|
|
13402
13538
|
{ key: "onlyAdminCanSendMessage", label: "Only Admin Can Send Message", desc: "Restricts message sending to group administrators only." },
|
|
13403
13539
|
{ key: "onlyAdminCanEditInfo", label: "Only Admin Can Edit Info", desc: "Only admins can change group name, description, and avatar." },
|
|
13404
13540
|
{ key: "senderCanEditMessage", label: "Sender Can Edit Message", desc: "Allows users to edit their own sent messages." },
|
|
13405
|
-
{ key: "allowMemberAdd", label: "
|
|
13406
|
-
{ key: "allowMemberRemove", label: "
|
|
13541
|
+
{ key: "allowMemberAdd", label: "Allow Members to Add", desc: "Allows group members to add new participants." },
|
|
13542
|
+
{ key: "allowMemberRemove", label: "Allow Members to Remove", desc: "Allows group members to remove other participants." },
|
|
13407
13543
|
{ key: "moderationEnabled", label: "Moderation Enabled", desc: "Enables advanced message moderation features." }
|
|
13408
13544
|
];
|
|
13409
13545
|
return /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open: isOpen, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ChatSheetContent, { showCloseButton: true, className: "sm:max-w-[380px]", children: [
|
|
@@ -13419,6 +13555,7 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
|
|
|
13419
13555
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-1 px-0.5 text-[10px] font-semibold uppercase tracking-wide text-(--chat-muted)", children: "Permissions" }),
|
|
13420
13556
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-(--chat-border) px-3", children: permissionItems.map((item, index) => {
|
|
13421
13557
|
const locked = isGroupPermissionLocked(item.key);
|
|
13558
|
+
const checked = permissions[item.key];
|
|
13422
13559
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13423
13560
|
"div",
|
|
13424
13561
|
{
|
|
@@ -13443,7 +13580,7 @@ var PermissionDrawer = ({ isOpen, onOpenChange, conversationId, conversationInfo
|
|
|
13443
13580
|
size: "sm",
|
|
13444
13581
|
className: "mt-0.5 shrink-0 data-[state=checked]:bg-(--chat-theme) data-[state=unchecked]:bg-(--chat-border)",
|
|
13445
13582
|
disabled: locked,
|
|
13446
|
-
checked
|
|
13583
|
+
checked,
|
|
13447
13584
|
onCheckedChange: () => handleToggle(item.key)
|
|
13448
13585
|
}
|
|
13449
13586
|
)
|
|
@@ -14987,61 +15124,6 @@ function resolveForwardItems(selectedKeys, messages) {
|
|
|
14987
15124
|
|
|
14988
15125
|
// src/chat/lib/chat-edit-window.ts
|
|
14989
15126
|
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);
|
|
14997
|
-
}
|
|
14998
|
-
function getDeleteWindowMs(timers, isGroup) {
|
|
14999
|
-
return minutesToMs(
|
|
15000
|
-
isGroup ? timers.groupDeleteMinutes : timers.dmDeleteMinutes
|
|
15001
|
-
);
|
|
15002
|
-
}
|
|
15003
|
-
function isWithinWindow(createdAt, windowMs) {
|
|
15004
|
-
if (!createdAt) return false;
|
|
15005
|
-
const date = new Date(createdAt);
|
|
15006
|
-
if (isNaN(date.getTime())) return false;
|
|
15007
|
-
const diff = Date.now() - date.getTime();
|
|
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
15127
|
var FALLBACK_TIMERS = exports.DEFAULT_EFFECTIVE_SETTINGS.messageTimers;
|
|
15046
15128
|
function isWithinMessageEditWindow2(createdAt, isGroup, timers = FALLBACK_TIMERS) {
|
|
15047
15129
|
return isWithinMessageEditWindow(createdAt, timers, isGroup);
|