@droppii-org/chat-sdk 0.1.50 → 0.1.52
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/assets/svg/index.d.ts +0 -1
- package/dist/assets/svg/index.d.ts.map +1 -1
- package/dist/assets/svg/index.js +0 -1
- package/dist/assets/svg/index.ts +1 -2
- package/dist/components/biz-inbox/BizInboxHeader.js +1 -1
- package/dist/components/biz-inbox/BizThreadAvatar.js +2 -2
- package/dist/components/biz-inbox/BizThreadCard.d.ts.map +1 -1
- package/dist/components/biz-inbox/BizThreadCard.js +3 -11
- package/dist/components/biz-inbox/BizThreadTitle.js +1 -1
- package/dist/components/biz-thread-detail/BizMessageList.js +2 -2
- package/dist/components/biz-thread-detail/BizMoreOptionItem.js +2 -2
- package/dist/components/biz-thread-detail/BizThreadDetailHeader.js +2 -2
- package/dist/components/biz-thread-detail/BizThreadDetailInput.d.ts.map +1 -1
- package/dist/components/biz-thread-detail/BizThreadDetailInput.js +12 -21
- package/dist/components/biz-thread-detail/index.d.ts +0 -4
- package/dist/components/biz-thread-detail/index.d.ts.map +1 -1
- package/dist/components/biz-thread-detail/index.js +0 -2
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +6 -5
- package/dist/components/conversation/ThreadCard.d.ts +14 -0
- package/dist/components/conversation/ThreadCard.d.ts.map +1 -0
- package/dist/components/conversation/ThreadCard.js +16 -0
- package/dist/components/media-collection/ImageCollection.d.ts.map +1 -1
- package/dist/components/media-collection/ImageCollection.js +3 -17
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +1 -7
- package/dist/components/message/footer/ComposerTextSyncPlugin.d.ts +6 -0
- package/dist/components/message/footer/ComposerTextSyncPlugin.d.ts.map +1 -0
- package/dist/components/message/footer/ComposerTextSyncPlugin.js +16 -0
- package/dist/components/message/footer/FilePreview.d.ts +3 -2
- package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
- package/dist/components/message/footer/FilePreview.js +61 -21
- package/dist/components/message/footer/LinkInputPreview.d.ts +7 -0
- package/dist/components/message/footer/LinkInputPreview.d.ts.map +1 -0
- package/dist/components/message/footer/LinkInputPreview.js +16 -0
- package/dist/components/message/footer/MediaActions.d.ts.map +1 -1
- package/dist/components/message/footer/MediaActions.js +8 -5
- package/dist/components/message/footer/index.d.ts.map +1 -1
- package/dist/components/message/footer/index.js +48 -35
- package/dist/components/message/item/FileMessage.d.ts +2 -2
- package/dist/components/message/item/FileMessage.d.ts.map +1 -1
- package/dist/components/message/item/FileMessage.js +20 -12
- package/dist/components/message/item/ImageMessage.d.ts.map +1 -1
- package/dist/components/message/item/ImageMessage.js +17 -15
- package/dist/components/message/item/LinkCard.d.ts +7 -0
- package/dist/components/message/item/LinkCard.d.ts.map +1 -0
- package/dist/components/message/item/LinkCard.js +17 -0
- package/dist/components/message/item/LinkText.d.ts +6 -0
- package/dist/components/message/item/LinkText.d.ts.map +1 -0
- package/dist/components/message/item/LinkText.js +13 -0
- package/dist/components/message/item/MergeImageMessage.d.ts +7 -0
- package/dist/components/message/item/MergeImageMessage.d.ts.map +1 -0
- package/dist/components/message/item/MergeImageMessage.js +30 -0
- package/dist/components/message/item/MessageBubble.d.ts +13 -0
- package/dist/components/message/item/MessageBubble.d.ts.map +1 -0
- package/dist/components/message/item/MessageBubble.js +23 -0
- package/dist/components/message/item/RevokeMessage.js +1 -1
- package/dist/components/message/item/TextMessage.d.ts.map +1 -1
- package/dist/components/message/item/TextMessage.js +20 -9
- package/dist/components/message/item/UrlTextMessage.d.ts.map +1 -1
- package/dist/components/message/item/UrlTextMessage.js +19 -17
- package/dist/components/message/item/VideoMessage.d.ts.map +1 -1
- package/dist/components/message/item/VideoMessage.js +10 -12
- package/dist/components/message/item/imagePreviewToolbar.d.ts +5 -0
- package/dist/components/message/item/imagePreviewToolbar.d.ts.map +1 -0
- package/dist/components/message/item/imagePreviewToolbar.js +14 -0
- package/dist/components/message/item/index.d.ts +2 -1
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +40 -44
- package/dist/components/message/item/mediaSize.d.ts +16 -0
- package/dist/components/message/item/mediaSize.d.ts.map +1 -0
- package/dist/components/message/item/mediaSize.js +20 -0
- package/dist/components/message/item/textStyle.d.ts +2 -0
- package/dist/components/message/item/textStyle.d.ts.map +1 -0
- package/dist/components/message/item/textStyle.js +1 -0
- package/dist/components/thread/ManualAssignPopover.js +1 -1
- package/dist/hooks/message/useSendMessage.d.ts +3 -10
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +27 -44
- package/dist/styles/global.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/bizConversation.d.ts +1 -1
- package/dist/utils/bizConversation.js +2 -2
- package/dist/utils/bizMessage.d.ts +1 -14
- package/dist/utils/bizMessage.d.ts.map +1 -1
- package/dist/utils/bizMessage.js +0 -26
- package/dist/utils/common.d.ts +2 -1
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +9 -3
- package/dist/utils/fileValidation.d.ts +1 -0
- package/dist/utils/fileValidation.d.ts.map +1 -1
- package/dist/utils/fileValidation.js +10 -17
- package/dist/utils/link.d.ts +13 -0
- package/dist/utils/link.d.ts.map +1 -0
- package/dist/utils/link.js +77 -0
- package/dist/utils/openLink.d.ts +3 -0
- package/dist/utils/openLink.d.ts.map +1 -0
- package/dist/utils/openLink.js +19 -0
- package/package.json +1 -1
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
4
|
import { useMessageFooterContext } from ".";
|
|
5
|
-
import { Button } from "antd";
|
|
6
5
|
import { Icon } from "../../../components/icon";
|
|
7
6
|
import { documentIcon } from "../../../assets/svg";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"application/msword",
|
|
11
|
-
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
12
|
-
];
|
|
7
|
+
import { DOCUMENT_MIME_TYPES } from "../../../utils/fileValidation";
|
|
8
|
+
import { formatDuration } from "../../../utils/common";
|
|
13
9
|
export const shortenFileName = (name, options = {}) => {
|
|
10
|
+
if (!name)
|
|
11
|
+
return "";
|
|
14
12
|
const { maxLength = 20, keepStart = 8, keepEnd = 3 } = options;
|
|
15
13
|
if (name.length <= maxLength)
|
|
16
14
|
return name;
|
|
@@ -24,23 +22,65 @@ export const shortenFileName = (name, options = {}) => {
|
|
|
24
22
|
const end = base.slice(-endLen);
|
|
25
23
|
return `${start}...${end}${ext}`;
|
|
26
24
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
const formatFileSize = (bytes) => {
|
|
26
|
+
if (bytes === 0)
|
|
27
|
+
return "0 B";
|
|
28
|
+
if (bytes < 1024)
|
|
29
|
+
return `${bytes} B`;
|
|
30
|
+
const kb = bytes / 1024;
|
|
31
|
+
if (kb < 1024)
|
|
32
|
+
return `${Math.round(kb)} KB`;
|
|
33
|
+
return `${(kb / 1024).toFixed(1)} MB`;
|
|
34
|
+
};
|
|
35
|
+
const getFileType = (file) => {
|
|
36
|
+
var _a, _b, _c;
|
|
37
|
+
const mimeType = (_c = (_b = (_a = file.originFileObj) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : file.type) !== null && _c !== void 0 ? _c : "";
|
|
38
|
+
if (DOCUMENT_MIME_TYPES.includes(mimeType))
|
|
39
|
+
return "document";
|
|
40
|
+
if (mimeType.startsWith("video/"))
|
|
41
|
+
return "video";
|
|
42
|
+
return "image";
|
|
43
|
+
};
|
|
44
|
+
const RemoveButton = ({ file, onRemove }) => (_jsx("button", { type: "button", onClick: () => onRemove(file), className: "absolute -right-1 -top-1 flex h-5 w-5 items-center justify-center rounded-full bg-gray-900", "aria-label": "X\u00F3a", children: _jsx(Icon, { icon: "close-o", size: 12, className: "text-white" }) }));
|
|
45
|
+
const MediaThumb = ({ file, onRemove, onVideoReady }) => {
|
|
46
|
+
var _a;
|
|
47
|
+
const [src, setSrc] = useState("");
|
|
48
|
+
const [duration, setDuration] = useState(null);
|
|
49
|
+
const isVideo = getFileType(file) === "video";
|
|
50
|
+
const isLoading = file.status === "uploading";
|
|
51
|
+
const percent = Math.round((_a = file.percent) !== null && _a !== void 0 ? _a : 0);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
var _a;
|
|
54
|
+
const originFile = file.originFileObj;
|
|
55
|
+
if (!originFile) {
|
|
56
|
+
setSrc((_a = file.url) !== null && _a !== void 0 ? _a : "");
|
|
57
|
+
return;
|
|
38
58
|
}
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
const url = URL.createObjectURL(originFile);
|
|
60
|
+
setSrc(url);
|
|
61
|
+
return () => URL.revokeObjectURL(url);
|
|
62
|
+
}, [file.originFileObj, file.url]);
|
|
63
|
+
const handleLoadedMetadata = (event) => {
|
|
64
|
+
setDuration(event.currentTarget.duration);
|
|
65
|
+
onVideoReady === null || onVideoReady === void 0 ? void 0 : onVideoReady();
|
|
66
|
+
};
|
|
67
|
+
return (_jsxs("div", { className: "relative h-12 w-12 shrink-0", children: [isVideo ? (_jsx("video", { src: src, className: "h-12 w-12 rounded-lg object-cover", preload: "metadata", muted: true, onLoadedMetadata: handleLoadedMetadata })) : (_jsx("img", { src: src, alt: file.name, className: "h-12 w-12 rounded-lg object-cover" })), isLoading && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center rounded-lg bg-black/60", children: _jsxs("span", { className: "text-xs font-semibold text-white", children: [percent, "%"] }) })), isVideo && duration !== null && (_jsx("div", { className: "absolute bottom-1 left-1/2 flex w-9 -translate-x-1/2 items-center justify-center rounded-xl bg-black/70 px-1 text-center text-[10px] font-normal leading-4 text-white", children: formatDuration(duration) })), _jsx(RemoveButton, { file: file, onRemove: onRemove })] }));
|
|
68
|
+
};
|
|
69
|
+
const DocumentCard = ({ file, onRemove }) => {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const isLoading = file.status === "uploading";
|
|
72
|
+
const percent = Math.round((_a = file.percent) !== null && _a !== void 0 ? _a : 0);
|
|
73
|
+
return (_jsxs("div", { className: "relative flex h-12 w-40 shrink-0 items-center gap-[7px] rounded-lg bg-chat-bubble-neutral/10 py-[4px] pl-2 pr-5", children: [_jsx("div", { className: "flex h-full w-8 shrink-0 items-center justify-center overflow-hidden [&>svg]:h-8 [&>svg]:w-8", children: documentIcon }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-[11px] font-normal leading-[160%] text-gray-900", children: shortenFileName(file.name) }), isLoading ? (_jsxs("span", { className: "text-[10px] leading-[160%] tracking-[0.1px] text-gray-400", children: [percent, "%"] })) : (_jsx("span", { className: "text-[10px] leading-[160%] tracking-[0.1px] text-gray-400", children: formatFileSize((_b = file.size) !== null && _b !== void 0 ? _b : 0) }))] }), _jsx(RemoveButton, { file: file, onRemove: onRemove })] }));
|
|
74
|
+
};
|
|
75
|
+
export function FilePreviewList({ files, onRemove, onVideoReady, }) {
|
|
41
76
|
if (files.length === 0)
|
|
42
77
|
return null;
|
|
43
|
-
return (_jsx("div", { className: "
|
|
78
|
+
return (_jsx("div", { className: "flex items-center gap-3 self-stretch overflow-x-auto px-2 pb-2 pt-3", children: files.map((file) => {
|
|
79
|
+
if (getFileType(file) === "document") {
|
|
80
|
+
return (_jsx(DocumentCard, { file: file, onRemove: onRemove }, file.uid));
|
|
81
|
+
}
|
|
82
|
+
return (_jsx(MediaThumb, { file: file, onRemove: onRemove, onVideoReady: onVideoReady }, file.uid));
|
|
83
|
+
}) }));
|
|
44
84
|
}
|
|
45
85
|
const FilePreview = () => {
|
|
46
86
|
const { listUploadFiles, setListUploadFiles } = useMessageFooterContext();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface LinkInputPreviewProps {
|
|
2
|
+
url: string;
|
|
3
|
+
onRemove: () => void;
|
|
4
|
+
}
|
|
5
|
+
declare const LinkInputPreview: ({ url, onRemove }: LinkInputPreviewProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default LinkInputPreview;
|
|
7
|
+
//# sourceMappingURL=LinkInputPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkInputPreview.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/LinkInputPreview.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,gBAAgB,GAAI,mBAAmB,qBAAqB,4CAoEjE,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Icon } from "../../../components/icon";
|
|
4
|
+
import { useFetchUrlMetadata } from "../../../hooks/common/useFetchUrlMetadata";
|
|
5
|
+
import { getHostLabel } from "../../../utils/link";
|
|
6
|
+
import { openLink } from "../../../utils/openLink";
|
|
7
|
+
import { useTranslation } from "react-i18next";
|
|
8
|
+
const LinkInputPreview = ({ url, onRemove }) => {
|
|
9
|
+
const { t } = useTranslation("biz-inbox");
|
|
10
|
+
const { data, isLoading, isError } = useFetchUrlMetadata(url);
|
|
11
|
+
const handleOpen = () => {
|
|
12
|
+
openLink(url, t);
|
|
13
|
+
};
|
|
14
|
+
return (_jsxs("div", { "data-testid": "link-input-preview", className: "flex w-full shrink-0 items-center gap-2 overflow-hidden bg-blue-25 pr-2", children: [_jsxs("button", { type: "button", onClick: handleOpen, className: "flex min-w-0 flex-1 items-center gap-2 py-0 pl-0 text-left", children: [_jsx("div", { className: "flex h-[51px] w-[51px] shrink-0 items-center justify-center overflow-hidden bg-blue-25", children: isLoading ? (_jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-primary-400 border-t-transparent" })) : (data === null || data === void 0 ? void 0 : data.image) ? (_jsx("img", { src: data.image, alt: "", className: "h-full w-full object-cover" })) : (_jsx(Icon, { icon: "link-alt-b", size: 24, className: "text-primary-400" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [isLoading ? (_jsx("p", { className: "truncate text-[14px] font-medium leading-[1.6] text-gray-900", children: t("link_preview.loading") })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "truncate text-[14px] font-medium leading-[1.6] text-gray-900", children: (data === null || data === void 0 ? void 0 : data.title) || getHostLabel(url) }), ((data === null || data === void 0 ? void 0 : data.description) || !(data === null || data === void 0 ? void 0 : data.title)) && (_jsx("p", { className: "truncate text-[13px] leading-[1.6] text-gray-400", children: (data === null || data === void 0 ? void 0 : data.description) || getHostLabel(url) }))] })), isError && !isLoading && (_jsx("p", { className: "truncate text-[13px] leading-[1.6] text-gray-400", children: getHostLabel(url) }))] })] }), _jsx("button", { type: "button", onClick: onRemove, "data-testid": "link-input-preview-remove", className: "flex h-4 w-4 shrink-0 items-center justify-center", "aria-label": t("link_preview.remove"), children: _jsx(Icon, { icon: "close-b", size: 16, className: "text-gray-900" }) })] }));
|
|
15
|
+
};
|
|
16
|
+
export default LinkInputPreview;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaActions.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/MediaActions.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAkB,UAAU,EAA0B,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"MediaActions.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/MediaActions.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAkB,UAAU,EAA0B,MAAM,MAAM,CAAC;AAqD1E,UAAU,iBAAiB;IACzB,eAAe,EAAE,UAAU,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,eAAe,EACf,aAAa,EACb,eAAe,EACf,eAAsB,GACvB,EAAE,iBAAiB,2CAyKnB"}
|
|
@@ -8,7 +8,7 @@ import clsx from "clsx";
|
|
|
8
8
|
import { useTranslation } from "react-i18next";
|
|
9
9
|
import EmojiPicker from "./EmojiPicker";
|
|
10
10
|
import { Icon } from "../../../components/icon";
|
|
11
|
-
import { validateFile, validateVideoLimit, } from "../../../utils/fileValidation";
|
|
11
|
+
import { createUploadFile, validateFile, validateVideoLimit, } from "../../../utils/fileValidation";
|
|
12
12
|
import { DOCUMENT_TYPES } from "./editorConfig";
|
|
13
13
|
import CannedResponseIcon from "../../../assets/svg/canned-response";
|
|
14
14
|
import { useMessageFooterContext } from ".";
|
|
@@ -58,15 +58,18 @@ export default function MediaActions({ listUploadFiles, onFilesChange, buttonCla
|
|
|
58
58
|
return false;
|
|
59
59
|
};
|
|
60
60
|
const handleChange = (info) => {
|
|
61
|
-
var _a;
|
|
62
61
|
let newList = [...info.fileList];
|
|
63
62
|
const lastFile = info.file;
|
|
64
63
|
if (DOCUMENT_TYPES.includes(lastFile.type || "")) {
|
|
65
64
|
newList = newList.filter((f) => !DOCUMENT_TYPES.includes(f.type || ""));
|
|
66
|
-
|
|
67
|
-
newList.push(Object.assign(Object.assign({}, lastFile), { originFileObj: originFile }));
|
|
65
|
+
newList.push(lastFile);
|
|
68
66
|
}
|
|
69
|
-
|
|
67
|
+
const normalizedList = newList.map((file) => {
|
|
68
|
+
var _a;
|
|
69
|
+
const originFile = ((_a = file.originFileObj) !== null && _a !== void 0 ? _a : file);
|
|
70
|
+
return Object.assign(Object.assign({}, createUploadFile(originFile)), { uid: file.uid });
|
|
71
|
+
});
|
|
72
|
+
onFilesChange(normalizedList);
|
|
70
73
|
};
|
|
71
74
|
const onPressCanned = useCallback(async () => {
|
|
72
75
|
if (!isOpenCanned) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAEL,wBAAwB,EAEzB,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAkB/C,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AASD,eAAO,MAAM,oBAAoB,mDAY/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,gCAAyC,CAAC;AAE9E,QAAA,MAAM,qBAAqB,GAAI,4CAG5B,kBAAkB,4CAuSpB,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -5,13 +5,17 @@ import { ToolbarPlugin } from "./ToolbarPlugin";
|
|
|
5
5
|
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
6
6
|
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
7
7
|
import { editorTheme, editorNodes, editorOnError } from "./editorConfig";
|
|
8
|
-
import { createContext, useCallback, useContext, useEffect, useRef, useState, } from "react";
|
|
8
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
9
9
|
import EnterHandler from "./EnterHandler";
|
|
10
10
|
import ActionBar from "./ActionBar";
|
|
11
|
-
import { AccountType } from "../../../types/chat";
|
|
11
|
+
import { AccountType, } from "../../../types/chat";
|
|
12
12
|
import { useSendMessage } from "../../../hooks/message/useSendMessage";
|
|
13
13
|
import { Modal, Popover } from "antd";
|
|
14
14
|
import FilePreview from "./FilePreview";
|
|
15
|
+
import LinkInputPreview from "./LinkInputPreview";
|
|
16
|
+
import ComposerTextSyncPlugin from "./ComposerTextSyncPlugin";
|
|
17
|
+
import { extractLinkUrls } from "../../../utils/link";
|
|
18
|
+
import { useFetchUrlMetadata } from "../../../hooks/common/useFetchUrlMetadata";
|
|
15
19
|
import { useTranslation } from "react-i18next";
|
|
16
20
|
import PasteAndDropPlugin from "./PasteAndDropPlugin";
|
|
17
21
|
import { QuotedMessageFooter } from "./QuotedMessage";
|
|
@@ -48,9 +52,11 @@ export const MessageFooterContext = createContext({
|
|
|
48
52
|
export const useMessageFooterContext = () => useContext(MessageFooterContext);
|
|
49
53
|
const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
50
54
|
const { t } = useTranslation();
|
|
51
|
-
const {
|
|
55
|
+
const { sendMergeMessage } = useSendMessage();
|
|
52
56
|
const accountType = useCurrentUserAccountType();
|
|
53
57
|
const [listUploadFiles, setListUploadFiles] = useState([]);
|
|
58
|
+
const [composerText, setComposerText] = useState("");
|
|
59
|
+
const [isLinkPreviewDismissed, setIsLinkPreviewDismissed] = useState(false);
|
|
54
60
|
const [isOpenCanned, { setTrue: openCanned, setFalse: closeCanned }] = useBoolean(false);
|
|
55
61
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
56
62
|
const [cannedQuery, setCannedQuery] = useState("");
|
|
@@ -61,6 +67,25 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
61
67
|
const quotedMessage = useConversationStore((state) => state.quotedMessage);
|
|
62
68
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
63
69
|
const lockToInternal = Boolean((quotedMessage === null || quotedMessage === void 0 ? void 0 : quotedMessage.clientMsgID) && (quotedMessage === null || quotedMessage === void 0 ? void 0 : quotedMessage.isInternal));
|
|
70
|
+
const previewUrl = useMemo(() => {
|
|
71
|
+
const urls = extractLinkUrls(composerText);
|
|
72
|
+
return urls.length === 1 ? urls[0] : null;
|
|
73
|
+
}, [composerText]);
|
|
74
|
+
const showLinkPreview = !!previewUrl && !isLinkPreviewDismissed && !isInternal;
|
|
75
|
+
const { data: previewMetadata } = useFetchUrlMetadata(previewUrl !== null && previewUrl !== void 0 ? previewUrl : "", showLinkPreview);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
setIsLinkPreviewDismissed(false);
|
|
78
|
+
}, [previewUrl]);
|
|
79
|
+
const resolveUrlMetadata = useCallback(() => {
|
|
80
|
+
if (!showLinkPreview || !previewUrl || !previewMetadata)
|
|
81
|
+
return undefined;
|
|
82
|
+
return {
|
|
83
|
+
url: previewUrl,
|
|
84
|
+
title: previewMetadata.title,
|
|
85
|
+
description: previewMetadata.description,
|
|
86
|
+
image: previewMetadata.image,
|
|
87
|
+
};
|
|
88
|
+
}, [showLinkPreview, previewUrl, previewMetadata]);
|
|
64
89
|
const [isSessionClosedModalOpen, { setTrue: openSessionClosedModal, setFalse: closeSessionClosedModal },] = useBoolean(false);
|
|
65
90
|
const pendingMessageRef = useRef(null);
|
|
66
91
|
const { mutateAsync: createSession, isPending: isCreatingSession } = useCreateSession();
|
|
@@ -90,57 +115,45 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
90
115
|
type,
|
|
91
116
|
isInternal,
|
|
92
117
|
files: [...listUploadFiles],
|
|
118
|
+
urlMetadata: resolveUrlMetadata(),
|
|
93
119
|
};
|
|
94
120
|
openSessionClosedModal();
|
|
95
121
|
return false;
|
|
96
122
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
currentSession,
|
|
106
|
-
isInternal,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
123
|
+
sendMergeMessage({
|
|
124
|
+
plainText,
|
|
125
|
+
richText,
|
|
126
|
+
files: listUploadFiles,
|
|
127
|
+
currentSession,
|
|
128
|
+
isInternal,
|
|
129
|
+
urlMetadata: resolveUrlMetadata(),
|
|
130
|
+
});
|
|
109
131
|
setListUploadFiles([]);
|
|
110
132
|
return true;
|
|
111
133
|
}, [
|
|
112
134
|
sendMergeMessage,
|
|
113
|
-
sendTextMessage,
|
|
114
135
|
listUploadFiles,
|
|
115
136
|
currentSession,
|
|
116
137
|
openSessionClosedModal,
|
|
138
|
+
resolveUrlMetadata,
|
|
117
139
|
]);
|
|
118
140
|
const executePendingSend = useCallback((newSession) => {
|
|
119
141
|
const pending = pendingMessageRef.current;
|
|
120
142
|
if (!pending)
|
|
121
143
|
return;
|
|
122
144
|
const sessionToUse = newSession || currentSession;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
sendMergeMessage({
|
|
133
|
-
plainText: pending.plainText,
|
|
134
|
-
richText: pending.richText,
|
|
135
|
-
files: pending.files,
|
|
136
|
-
currentSession: sessionToUse,
|
|
137
|
-
isInternal: pending.isInternal,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
145
|
+
sendMergeMessage({
|
|
146
|
+
plainText: pending.plainText,
|
|
147
|
+
richText: pending.richText,
|
|
148
|
+
files: pending.files,
|
|
149
|
+
currentSession: sessionToUse,
|
|
150
|
+
isInternal: pending.isInternal,
|
|
151
|
+
urlMetadata: pending.urlMetadata,
|
|
152
|
+
});
|
|
140
153
|
setListUploadFiles([]);
|
|
141
154
|
pendingMessageRef.current = null;
|
|
142
155
|
emit("CLEAR_COMPOSER");
|
|
143
|
-
}, [
|
|
156
|
+
}, [sendMergeMessage, currentSession]);
|
|
144
157
|
const handleSessionAction = useCallback(async (action) => {
|
|
145
158
|
const conversationId = conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID;
|
|
146
159
|
if (!conversationId)
|
|
@@ -202,6 +215,6 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
202
215
|
setMaxActiveCannedIndex,
|
|
203
216
|
}, children: [_jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Popover, { open: isOpenCanned, content: _jsx(CannedResponse, { onClose: closeCanned, openCreateCannedModal: onOpenCreateCannedModal, cannedQuery: cannedQuery }), placement: "topLeft", trigger: "click", arrow: false, classNames: {
|
|
204
217
|
body: "mx-1 !p-0",
|
|
205
|
-
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(QuotedMessageFooter, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), _jsx(ToolbarPlugin, {}), _jsxs("div", { children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, hintText: t("canned_response_hint"), isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), _jsx(ComposerEditor, { isInternal: isInternal, placeholderText: placeholderText })] }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }), _jsx(SessionClosedModal, { open: isSessionClosedModalOpen, loading: isSessionActionLoading, onReopen: handleReopenSession, onCreateNew: handleCreateNewSession, onClose: handleCloseSessionModal })] }));
|
|
218
|
+
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(QuotedMessageFooter, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setIsLinkPreviewDismissed(true) })), _jsx(ToolbarPlugin, {}), _jsxs("div", { children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, hintText: t("canned_response_hint"), isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), _jsx(ComposerEditor, { isInternal: isInternal, placeholderText: placeholderText })] }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(ComposerTextSyncPlugin, { onChange: setComposerText }), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }), _jsx(SessionClosedModal, { open: isSessionClosedModalOpen, loading: isSessionActionLoading, onReopen: handleReopenSession, onCreateNew: handleCreateNewSession, onClose: handleCloseSessionModal })] }));
|
|
206
219
|
};
|
|
207
220
|
export default MessageFooterProvider;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MessageItem } from "@openim/wasm-client-sdk";
|
|
2
|
-
interface
|
|
2
|
+
interface FileMessageItemProps {
|
|
3
3
|
message: MessageItem;
|
|
4
4
|
}
|
|
5
|
-
declare const FileMessageItem: (props:
|
|
5
|
+
declare const FileMessageItem: (props: FileMessageItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export default FileMessageItem;
|
|
7
7
|
//# sourceMappingURL=FileMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/FileMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"FileMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/FileMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,yBAAyB,CAAC;AAOrE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,GAAI,OAAO,oBAAoB,4CAiEnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { MessageStatus } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { Spin } from "antd";
|
|
4
|
+
import { Icon } from "../../../components/icon";
|
|
3
5
|
import { documentIcon } from "../../../assets/svg";
|
|
6
|
+
import { shortenFileName } from "../../../components/message/footer/FilePreview";
|
|
7
|
+
import { renderFileSize } from "../../../utils/common";
|
|
4
8
|
const FileMessageItem = (props) => {
|
|
5
9
|
var _a;
|
|
6
10
|
const { message } = props;
|
|
11
|
+
const fileElem = message.fileElem;
|
|
12
|
+
const fileName = (fileElem === null || fileElem === void 0 ? void 0 : fileElem.fileName) || "";
|
|
13
|
+
const fileSize = (_a = fileElem === null || fileElem === void 0 ? void 0 : fileElem.fileSize) !== null && _a !== void 0 ? _a : 0;
|
|
14
|
+
const sourceUrl = (fileElem === null || fileElem === void 0 ? void 0 : fileElem.sourceUrl) || "";
|
|
15
|
+
const isSending = message.status === MessageStatus.Sending;
|
|
16
|
+
const hasUrl = !!sourceUrl;
|
|
17
|
+
const handleView = () => {
|
|
18
|
+
if (!hasUrl)
|
|
19
|
+
return;
|
|
20
|
+
window.open(sourceUrl, "_blank", "noopener,noreferrer");
|
|
21
|
+
};
|
|
7
22
|
const handleDownload = () => {
|
|
8
|
-
|
|
9
|
-
const url = ((_a = message.fileElem) === null || _a === void 0 ? void 0 : _a.sourceUrl) || "";
|
|
10
|
-
const fileName = ((_b = message.fileElem) === null || _b === void 0 ? void 0 : _b.fileName) || "";
|
|
11
|
-
if (!url) {
|
|
12
|
-
console.warn("Không có link file để tải");
|
|
23
|
+
if (!hasUrl)
|
|
13
24
|
return;
|
|
14
|
-
}
|
|
15
25
|
const link = document.createElement("a");
|
|
16
|
-
link.href =
|
|
17
|
-
|
|
18
|
-
link.setAttribute("download", fileName);
|
|
19
|
-
}
|
|
26
|
+
link.href = sourceUrl;
|
|
27
|
+
link.setAttribute("download", fileName);
|
|
20
28
|
link.setAttribute("target", "_blank");
|
|
21
29
|
link.setAttribute("rel", "noopener noreferrer");
|
|
22
30
|
document.body.appendChild(link);
|
|
23
31
|
link.click();
|
|
24
32
|
link.remove();
|
|
25
33
|
};
|
|
26
|
-
return (_jsxs("div", { className: "
|
|
34
|
+
return (_jsx(Spin, { spinning: isSending, children: _jsxs("div", { className: "flex h-[51px] w-[292px] items-center gap-3 rounded-xl border border-gray-200/20 bg-white px-3 py-1", children: [_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden [&>svg]:h-6 [&>svg]:w-6", children: documentIcon }), _jsxs("div", { className: "flex min-w-0 w-[168px] flex-col justify-center", children: [_jsx("span", { className: "truncate text-[14px] font-medium leading-[160%] text-gray-900", children: shortenFileName(fileName) }), _jsx("span", { className: "truncate text-[13px] leading-[160%] text-gray-600", children: renderFileSize(fileSize) })] }), _jsxs("div", { className: "flex w-[52px] shrink-0 items-center justify-end gap-3", children: [_jsx("button", { type: "button", onClick: handleView, disabled: !hasUrl, "aria-label": "Xem file", className: !hasUrl ? "opacity-30" : undefined, children: _jsx(Icon, { icon: "eye-o", size: 20, className: "text-gray-900" }) }), _jsx("button", { type: "button", onClick: handleDownload, disabled: !hasUrl, "aria-label": "T\u1EA3i xu\u1ED1ng", className: !hasUrl ? "opacity-30" : undefined, children: _jsx(Icon, { icon: "download-o", size: 20, className: "text-gray-900" }) })] })] }) }));
|
|
27
35
|
};
|
|
28
36
|
export default FileMessageItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/ImageMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"ImageMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/ImageMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,yBAAyB,CAAC;AAMrE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CAyCrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { MessageStatus } from "@openim/wasm-client-sdk";
|
|
3
3
|
import { Image, Spin } from "antd";
|
|
4
|
-
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { renderImagePreviewToolbar } from "./imagePreviewToolbar";
|
|
6
|
+
import { getImageMessageMinStyle } from "./mediaSize";
|
|
5
7
|
const ImageMessageItem = (props) => {
|
|
6
|
-
var _a, _b, _c, _d;
|
|
8
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
7
9
|
const { message } = props;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
(
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
const pictureElem = message.pictureElem;
|
|
12
|
+
const sourceUrl = ((_a = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.sourcePicture) === null || _a === void 0 ? void 0 : _a.url) || ((_b = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.snapshotPicture) === null || _b === void 0 ? void 0 : _b.url) || "";
|
|
13
|
+
const bigUrl = ((_c = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.bigPicture) === null || _c === void 0 ? void 0 : _c.url) || sourceUrl;
|
|
14
|
+
const minStyle = getImageMessageMinStyle({
|
|
15
|
+
imageWidth: (_e = (_d = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.sourcePicture) === null || _d === void 0 ? void 0 : _d.width) !== null && _e !== void 0 ? _e : (_f = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.snapshotPicture) === null || _f === void 0 ? void 0 : _f.width,
|
|
16
|
+
imageHeight: (_h = (_g = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.sourcePicture) === null || _g === void 0 ? void 0 : _g.height) !== null && _h !== void 0 ? _h : (_j = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.snapshotPicture) === null || _j === void 0 ? void 0 : _j.height,
|
|
17
|
+
snapshotHeight: (_k = pictureElem === null || pictureElem === void 0 ? void 0 : pictureElem.snapshotPicture) === null || _k === void 0 ? void 0 : _k.height,
|
|
18
|
+
});
|
|
16
19
|
const isSending = message.status === MessageStatus.Sending;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return (_jsx(Spin, { spinning: isSending, children: _jsx("div", { className: "relative max-w-[200px]", style: minStyle, children: _jsx(Image, { rootClassName: "message-image cursor-pointer", className: "rounded-md", src: sourceUrl, preview: true, placeholder: _jsx("div", { style: minStyle, className: "flex items-center justify-center", children: _jsx(Spin, {}) }) }) }) }));
|
|
20
|
+
return (_jsx(Spin, { spinning: isSending, children: _jsx("div", { className: "relative max-w-[200px]", style: minStyle, children: _jsx(Image, { src: sourceUrl, width: minStyle.width, className: "cursor-pointer rounded-xl object-contain", preview: {
|
|
21
|
+
src: bigUrl,
|
|
22
|
+
toolbarRender: (originalNode, info) => { var _a; return renderImagePreviewToolbar(originalNode, (_a = info === null || info === void 0 ? void 0 : info.image) === null || _a === void 0 ? void 0 : _a.url, t); },
|
|
23
|
+
}, placeholder: _jsx("div", { className: "flex items-center justify-center rounded-xl bg-black/10", style: minStyle, children: _jsx(Spin, {}) }) }) }) }));
|
|
22
24
|
};
|
|
23
25
|
export default ImageMessageItem;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { UrlMetadataInfo } from "../../../types/chat";
|
|
2
|
+
export interface LinkCardProps {
|
|
3
|
+
metadata: UrlMetadataInfo;
|
|
4
|
+
}
|
|
5
|
+
declare const LinkCard: ({ metadata }: LinkCardProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export default LinkCard;
|
|
7
|
+
//# sourceMappingURL=LinkCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkCard.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/LinkCard.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,QAAA,MAAM,QAAQ,GAAI,cAAc,aAAa,mDA0C5C,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { getHostLabel } from "../../../utils/link";
|
|
5
|
+
import { openLink } from "../../../utils/openLink";
|
|
6
|
+
const LinkCard = ({ metadata }) => {
|
|
7
|
+
const { t } = useTranslation("biz-inbox");
|
|
8
|
+
const { url, title, description, image } = metadata;
|
|
9
|
+
if (!title && !description && !image) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const handleOpen = () => {
|
|
13
|
+
openLink(url, t);
|
|
14
|
+
};
|
|
15
|
+
return (_jsxs("button", { type: "button", onClick: handleOpen, "data-testid": "link-message-card", className: "flex w-full max-w-[292px] flex-col overflow-hidden rounded-[12px] border border-gray-900/10 bg-white text-left", children: [image && (_jsx("div", { className: "aspect-[16/9] w-full overflow-hidden", children: _jsx("img", { src: image, alt: "", className: "h-full w-full object-cover" }) })), _jsxs("div", { className: "flex flex-col px-3 py-2", children: [title && (_jsx("p", { className: "truncate text-[14px] font-medium leading-[1.6] text-gray-900", children: title })), _jsx("p", { className: "truncate text-[12px] font-medium leading-[1.6] tracking-[0.12px] text-primary-400", children: getHostLabel(url) }), description && (_jsx("p", { className: "line-clamp-2 text-[12px] leading-[1.6] text-gray-600", children: description }))] })] }));
|
|
16
|
+
};
|
|
17
|
+
export default LinkCard;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkText.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/LinkText.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,QAAA,MAAM,QAAQ,GAAI,UAAU,aAAa,4CA2BxC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { parseTextWithLinks } from "../../../utils/link";
|
|
6
|
+
import { openLink } from "../../../utils/openLink";
|
|
7
|
+
import { MESSAGE_TEXT_CLASS } from "./textStyle";
|
|
8
|
+
const LinkText = ({ text }) => {
|
|
9
|
+
const { t } = useTranslation("biz-inbox");
|
|
10
|
+
const segments = parseTextWithLinks(text);
|
|
11
|
+
return (_jsx("span", { className: clsx("min-w-0 whitespace-pre-wrap text-left [overflow-wrap:anywhere]", MESSAGE_TEXT_CLASS), children: segments.map((segment, index) => segment.type === "link" ? (_jsx("button", { type: "button", onClick: () => openLink(segment.url, t), className: "inline text-left font-medium text-primary-400 underline-offset-2 hover:underline", children: segment.value }, `${segment.url}-${index}`)) : (_jsx("span", { children: segment.value }, `text-${index}`))) }));
|
|
12
|
+
};
|
|
13
|
+
export default LinkText;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { MessageItem } from "@openim/wasm-client-sdk";
|
|
2
|
+
interface MergeImageMessageItemProps {
|
|
3
|
+
message: MessageItem;
|
|
4
|
+
}
|
|
5
|
+
declare const MergeImageMessageItem: (props: MergeImageMessageItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default MergeImageMessageItem;
|
|
7
|
+
//# sourceMappingURL=MergeImageMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MergeImageMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MergeImageMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,yBAAyB,CAAC;AAMrE,UAAU,0BAA0B;IAClC,OAAO,EAAE,WAAW,CAAC;CACtB;AAQD,QAAA,MAAM,qBAAqB,GAAI,OAAO,0BAA0B,4CA4C/D,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { MessageStatus } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { Image, Spin } from "antd";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import { renderImagePreviewToolbar } from "./imagePreviewToolbar";
|
|
7
|
+
const MERGE_IMAGE_GRID_COLS_CLASS = {
|
|
8
|
+
1: "grid-cols-[repeat(1,100px)]",
|
|
9
|
+
2: "grid-cols-[repeat(2,100px)]",
|
|
10
|
+
3: "grid-cols-[repeat(3,100px)]",
|
|
11
|
+
};
|
|
12
|
+
const MergeImageMessageItem = (props) => {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
const { message } = props;
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
const subMessages = (_b = (_a = message.mergeElem) === null || _a === void 0 ? void 0 : _a.multiMessage) !== null && _b !== void 0 ? _b : [];
|
|
17
|
+
const isSending = message.status === MessageStatus.Sending;
|
|
18
|
+
const cols = Math.min(subMessages.length, 3);
|
|
19
|
+
return (_jsx("div", { className: "-mx-1", children: _jsx(Spin, { spinning: isSending, children: _jsx(Image.PreviewGroup, { preview: {
|
|
20
|
+
toolbarRender: (originalNode, info) => { var _a; return renderImagePreviewToolbar(originalNode, (_a = info === null || info === void 0 ? void 0 : info.image) === null || _a === void 0 ? void 0 : _a.url, t); },
|
|
21
|
+
}, children: _jsx("div", { className: clsx("grid gap-1", MERGE_IMAGE_GRID_COLS_CLASS[cols]), children: subMessages.map((item) => {
|
|
22
|
+
var _a, _b, _c, _d, _e, _f;
|
|
23
|
+
const sourceUrl = ((_b = (_a = item.pictureElem) === null || _a === void 0 ? void 0 : _a.sourcePicture) === null || _b === void 0 ? void 0 : _b.url) ||
|
|
24
|
+
((_d = (_c = item.pictureElem) === null || _c === void 0 ? void 0 : _c.snapshotPicture) === null || _d === void 0 ? void 0 : _d.url) ||
|
|
25
|
+
"";
|
|
26
|
+
const bigUrl = ((_f = (_e = item.pictureElem) === null || _e === void 0 ? void 0 : _e.bigPicture) === null || _f === void 0 ? void 0 : _f.url) || sourceUrl;
|
|
27
|
+
return (_jsx(Image, { src: sourceUrl, width: 100, height: 100, className: "cursor-pointer rounded-xl object-cover", preview: { src: bigUrl }, placeholder: _jsx("div", { className: "flex h-[100px] w-[100px] items-center justify-center rounded-xl bg-black/10", children: _jsx(Spin, {}) }) }, item.clientMsgID));
|
|
28
|
+
}) }) }) }) }));
|
|
29
|
+
};
|
|
30
|
+
export default MergeImageMessageItem;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface MessageBubbleProps {
|
|
3
|
+
isMine: boolean;
|
|
4
|
+
content: ReactNode;
|
|
5
|
+
senderName?: string;
|
|
6
|
+
showSenderName?: boolean;
|
|
7
|
+
showTip?: boolean;
|
|
8
|
+
isInternal?: boolean;
|
|
9
|
+
id?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const MessageBubble: ({ isMine, content, senderName, showSenderName, showTip, isInternal, id, }: MessageBubbleProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default MessageBubble;
|
|
13
|
+
//# sourceMappingURL=MessageBubble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AA4CD,QAAA,MAAM,aAAa,GAAI,2EAQpB,kBAAkB,4CAsCpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
const INCOMING_TAIL_PATH = "M1.3798 18H4V0C3.51762 4.5 3.34269 10.5 0.966518 14C-0.568384 16.2608 -0.159364 18 1.3798 18Z";
|
|
5
|
+
const OUTGOING_TAIL_PATH = "M2.6202 18H0V0C0.482375 4.5 0.657308 10.5 3.03348 14C4.56838 16.2608 4.15936 18 2.6202 18Z";
|
|
6
|
+
const MessageBubbleTail = ({ isMine, isInternal, }) => (_jsx("div", { className: clsx("flex shrink-0 items-center justify-center", isInternal
|
|
7
|
+
? "text-chat-internal"
|
|
8
|
+
: isMine
|
|
9
|
+
? "text-chat-bubble-mine"
|
|
10
|
+
: "text-chat-bubble-neutral"), children: _jsx("div", { className: "flex-none", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "4", height: "18", viewBox: "0 0 4 18", fill: "none", "aria-hidden": true, children: _jsx("path", { d: isMine ? OUTGOING_TAIL_PATH : INCOMING_TAIL_PATH, fill: "currentColor", fillOpacity: "0.1" }) }) }) }));
|
|
11
|
+
const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip = true, isInternal = false, id, }) => {
|
|
12
|
+
const bubbleClass = clsx("relative max-w-full p-2", showTip
|
|
13
|
+
? isMine
|
|
14
|
+
? "rounded-[20px] rounded-br-none"
|
|
15
|
+
: "rounded-[20px] rounded-bl-none"
|
|
16
|
+
: "rounded-[20px]", isInternal
|
|
17
|
+
? "bg-chat-internal/10"
|
|
18
|
+
: isMine
|
|
19
|
+
? "bg-chat-bubble-mine/10"
|
|
20
|
+
: "bg-chat-bubble-neutral/10");
|
|
21
|
+
return (_jsxs("div", { className: "relative flex items-end", "data-testid": "message-bubble", children: [!isMine && showTip && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), _jsx("div", { className: bubbleClass, id: id, children: _jsxs("div", { className: "flex flex-col gap-1 px-1", children: [showSenderName && senderName && (_jsx("span", { className: "text-[12px] font-medium leading-[160%] tracking-[0.12px] text-gray-400", children: senderName })), _jsx("div", { className: "flex flex-col gap-2", children: content })] }) }), isMine && showTip && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal }))] }));
|
|
22
|
+
};
|
|
23
|
+
export default MessageBubble;
|
|
@@ -3,6 +3,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
const RevokeMessageItem = (_) => {
|
|
5
5
|
const { t } = useTranslation();
|
|
6
|
-
return (_jsx("span", { className: "
|
|
6
|
+
return (_jsx("span", { className: "whitespace-pre-wrap text-[16px] leading-[160%] italic text-gray-500", children: t("revoked") }));
|
|
7
7
|
};
|
|
8
8
|
export default RevokeMessageItem;
|