@droppii-org/chat-sdk 0.1.25 → 0.1.27
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/canned-response.d.ts +7 -0
- package/dist/assets/svg/canned-response.d.ts.map +1 -0
- package/dist/assets/svg/canned-response.js +3 -0
- package/dist/assets/svg/canned-response.tsx +48 -0
- package/dist/assets/svg/index.d.ts +1 -1
- package/dist/assets/svg/index.d.ts.map +1 -1
- package/dist/assets/svg/index.js +1 -1
- package/dist/assets/svg/index.ts +1 -1
- package/dist/components/biz-thread-detail/BizMessageBubble.d.ts +10 -0
- package/dist/components/biz-thread-detail/BizMessageBubble.d.ts.map +1 -0
- package/dist/components/biz-thread-detail/BizMessageBubble.js +15 -0
- package/dist/components/biz-thread-detail/BizMessageList.d.ts +3 -0
- package/dist/components/biz-thread-detail/BizMessageList.d.ts.map +1 -0
- package/dist/components/biz-thread-detail/BizMessageList.js +28 -0
- package/dist/components/biz-thread-detail/BizThreadDetailHeader.d.ts +8 -0
- package/dist/components/biz-thread-detail/BizThreadDetailHeader.d.ts.map +1 -0
- package/dist/components/biz-thread-detail/BizThreadDetailHeader.js +18 -0
- package/dist/components/biz-thread-detail/BizThreadDetailInput.d.ts +8 -0
- package/dist/components/biz-thread-detail/BizThreadDetailInput.d.ts.map +1 -0
- package/dist/components/biz-thread-detail/BizThreadDetailInput.js +147 -0
- package/dist/components/biz-thread-detail/index.d.ts +8 -0
- package/dist/components/biz-thread-detail/index.d.ts.map +1 -0
- package/dist/components/biz-thread-detail/index.js +4 -0
- package/dist/components/biz-thread-detail/item/BizMessageItem.d.ts +8 -0
- package/dist/components/biz-thread-detail/item/BizMessageItem.d.ts.map +1 -0
- package/dist/components/biz-thread-detail/item/BizMessageItem.js +20 -0
- package/dist/components/bizThreadDetail/BizMessageBubble.d.ts.map +1 -1
- package/dist/components/bizThreadDetail/BizMessageBubble.js +5 -1
- package/dist/components/canned-response/CannedResponseBody.d.ts +8 -0
- package/dist/components/canned-response/CannedResponseBody.d.ts.map +1 -0
- package/dist/components/canned-response/CannedResponseBody.js +109 -0
- package/dist/components/canned-response/CannedResponseFooter.d.ts +6 -0
- package/dist/components/canned-response/CannedResponseFooter.d.ts.map +1 -0
- package/dist/components/canned-response/CannedResponseFooter.js +8 -0
- package/dist/components/canned-response/CannedResponseHeader.d.ts +8 -0
- package/dist/components/canned-response/CannedResponseHeader.d.ts.map +1 -0
- package/dist/components/canned-response/CannedResponseHeader.js +11 -0
- package/dist/components/canned-response/index.d.ts +8 -0
- package/dist/components/canned-response/index.d.ts.map +1 -0
- package/dist/components/canned-response/index.js +34 -0
- package/dist/components/canned-response/team/TeamItem.d.ts +11 -0
- package/dist/components/canned-response/team/TeamItem.d.ts.map +1 -0
- package/dist/components/canned-response/team/TeamItem.js +31 -0
- package/dist/components/chat-bubble/ChatBubble.d.ts +6 -0
- package/dist/components/chat-bubble/ChatBubble.d.ts.map +1 -0
- package/dist/components/chat-bubble/ChatBubble.js +35 -0
- package/dist/components/conversation/DeskConversationList.js +1 -1
- package/dist/components/media-collection/FileCollection.d.ts +3 -0
- package/dist/components/media-collection/FileCollection.d.ts.map +1 -0
- package/dist/components/media-collection/FileCollection.js +53 -0
- package/dist/components/media-collection/ImageCollection.d.ts +3 -0
- package/dist/components/media-collection/ImageCollection.d.ts.map +1 -0
- package/dist/components/media-collection/ImageCollection.js +52 -0
- package/dist/components/media-collection/LinkCollection.d.ts +5 -0
- package/dist/components/media-collection/LinkCollection.d.ts.map +1 -0
- package/dist/components/media-collection/LinkCollection.js +92 -0
- package/dist/components/media-collection/VideoCollection.d.ts +3 -0
- package/dist/components/media-collection/VideoCollection.d.ts.map +1 -0
- package/dist/components/media-collection/VideoCollection.js +51 -0
- package/dist/components/media-collection/index.d.ts +9 -0
- package/dist/components/media-collection/index.d.ts.map +1 -0
- package/dist/components/media-collection/index.js +57 -0
- package/dist/components/message/MessageHeader.js +2 -2
- package/dist/components/message/footer/MediaActions.js +1 -1
- package/dist/components/message/footer/index.js +1 -1
- package/dist/components/rich-text-editor/RichTextEditor.d.ts +12 -0
- package/dist/components/rich-text-editor/RichTextEditor.d.ts.map +1 -0
- package/dist/components/rich-text-editor/RichTextEditor.js +62 -0
- package/dist/components/search-conversation/SearchAll.d.ts +8 -0
- package/dist/components/search-conversation/SearchAll.d.ts.map +1 -0
- package/dist/components/search-conversation/SearchAll.js +37 -0
- package/dist/components/search-conversation/SearchConversationAsMessages.d.ts +6 -0
- package/dist/components/search-conversation/SearchConversationAsMessages.d.ts.map +1 -0
- package/dist/components/search-conversation/SearchConversationAsMessages.js +23 -0
- package/dist/components/search-conversation/SearchConversationAsUsers.d.ts +6 -0
- package/dist/components/search-conversation/SearchConversationAsUsers.d.ts.map +1 -0
- package/dist/components/search-conversation/SearchConversationAsUsers.js +21 -0
- package/dist/components/search-conversation/SearchConversationMyInbox.d.ts +6 -0
- package/dist/components/search-conversation/SearchConversationMyInbox.d.ts.map +1 -0
- package/dist/components/search-conversation/SearchConversationMyInbox.js +24 -0
- package/dist/components/search-conversation/SearchDrawer.d.ts +3 -0
- package/dist/components/search-conversation/SearchDrawer.d.ts.map +1 -0
- package/dist/components/search-conversation/SearchDrawer.js +33 -0
- package/dist/components/search-conversation/SearchMessageOnCurrentConversation.d.ts +7 -0
- package/dist/components/search-conversation/SearchMessageOnCurrentConversation.d.ts.map +1 -0
- package/dist/components/search-conversation/SearchMessageOnCurrentConversation.js +28 -0
- package/dist/components/search-conversation/index.d.ts +12 -0
- package/dist/components/search-conversation/index.d.ts.map +1 -0
- package/dist/components/search-conversation/index.js +46 -0
- package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts +12 -0
- package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -0
- package/dist/components/search-conversation/item/SearchItemAsMessage.js +72 -0
- package/dist/components/search-conversation/item/SearchItemAsUser.d.ts +8 -0
- package/dist/components/search-conversation/item/SearchItemAsUser.d.ts.map +1 -0
- package/dist/components/search-conversation/item/SearchItemAsUser.js +25 -0
- package/dist/hooks/biz/useBizSendMessage.d.ts.map +1 -1
- package/dist/hooks/biz/useBizSendMessage.js +4 -0
- package/dist/hooks/canned-response/useFetchCannedCategories.d.ts +3 -0
- package/dist/hooks/canned-response/useFetchCannedCategories.d.ts.map +1 -0
- package/dist/hooks/canned-response/useFetchCannedCategories.js +13 -0
- package/dist/hooks/canned-response/useFetchCannedResponse.d.ts +219 -0
- package/dist/hooks/canned-response/useFetchCannedResponse.d.ts.map +1 -0
- package/dist/hooks/canned-response/useFetchCannedResponse.js +55 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/screens/biz-message/index.d.ts +9 -0
- package/dist/screens/biz-message/index.d.ts.map +1 -0
- package/dist/screens/biz-message/index.js +55 -0
- package/dist/screens/biz-thread-detail/index.d.ts +9 -0
- package/dist/screens/biz-thread-detail/index.d.ts.map +1 -0
- package/dist/screens/biz-thread-detail/index.js +36 -0
- package/dist/screens/chat-bubble/index.d.ts +7 -0
- package/dist/screens/chat-bubble/index.d.ts.map +1 -0
- package/dist/screens/chat-bubble/index.js +41 -0
- package/dist/screens/desk-message/index.d.ts +6 -0
- package/dist/screens/desk-message/index.d.ts.map +1 -0
- package/dist/screens/desk-message/index.js +17 -0
- package/dist/styles/global.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import CannedResponseIcon from "../../assets/svg/canned-response";
|
|
4
|
+
import { Button, Input } from "antd";
|
|
5
|
+
import { Icon } from "../../components/icon";
|
|
6
|
+
const CannedResponseHeader = (props) => {
|
|
7
|
+
const { onClose, search, setSearch } = props;
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
return (_jsxs("div", { className: "px-3 py-2 flex flex-row items-center gap-2 border-b border-gray-200", children: [_jsxs("div", { className: "flex flex-row items-center gap-2", children: [_jsx(CannedResponseIcon, { size: 20, className: "text-blue-500" }), _jsx("span", { className: "text-base font-medium", children: t("canned_responses") })] }), _jsxs("div", { className: "flex flex-1 flex-row items-center justify-end gap-2", children: [_jsx(Input, { size: "large", placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 20, className: "text-gray-500" }), style: { width: 260 }, className: "text-sm", value: search, onChange: (e) => setSearch === null || setSearch === void 0 ? void 0 : setSearch(e.target.value) }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 16 }) })] })] }));
|
|
10
|
+
};
|
|
11
|
+
export default CannedResponseHeader;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface ICannedResponseProps {
|
|
2
|
+
onClose?: () => void;
|
|
3
|
+
openCreateCannedModal?: () => void;
|
|
4
|
+
cannedQuery?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const CannedResponse: ({ onClose, openCreateCannedModal, cannedQuery, }: ICannedResponseProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default CannedResponse;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/canned-response/index.tsx"],"names":[],"mappings":"AASA,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,cAAc,GAAI,kDAIrB,oBAAoB,4CAgDtB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useDebounce } from "ahooks";
|
|
3
|
+
import CannedResponseBody from "./CannedResponseBody";
|
|
4
|
+
import CannedResponseHeader from "./CannedResponseHeader";
|
|
5
|
+
import { useCallback, useState } from "react";
|
|
6
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
7
|
+
import { $getRoot } from "lexical";
|
|
8
|
+
import { $generateNodesFromDOM } from "@lexical/html";
|
|
9
|
+
import CannedResponseFooter from "./CannedResponseFooter";
|
|
10
|
+
const CannedResponse = ({ onClose, openCreateCannedModal, cannedQuery = "", }) => {
|
|
11
|
+
const [editor] = useLexicalComposerContext();
|
|
12
|
+
const [search, setSearch] = useState("");
|
|
13
|
+
const debouncedSearch = useDebounce(search, {
|
|
14
|
+
wait: 300,
|
|
15
|
+
});
|
|
16
|
+
const onSelectCannedResponse = useCallback((content) => {
|
|
17
|
+
editor.update(() => {
|
|
18
|
+
const root = $getRoot();
|
|
19
|
+
// 1. Clear content cũ
|
|
20
|
+
root.clear();
|
|
21
|
+
// 2. Parse HTML -> DOM
|
|
22
|
+
const parser = new DOMParser();
|
|
23
|
+
const dom = parser.parseFromString(content, "text/html");
|
|
24
|
+
// 3. Convert DOM -> Lexical nodes
|
|
25
|
+
const nodes = $generateNodesFromDOM(editor, dom);
|
|
26
|
+
// 4. Append vào editor
|
|
27
|
+
root.append(...nodes);
|
|
28
|
+
// 5. Move cursor về cuối (optional nhưng nên có)
|
|
29
|
+
root.selectEnd();
|
|
30
|
+
});
|
|
31
|
+
}, [editor]);
|
|
32
|
+
return (_jsxs("div", { className: "w-[600px]", children: [_jsx(CannedResponseHeader, { onClose: onClose, search: search, setSearch: setSearch }), _jsx(CannedResponseBody, { search: debouncedSearch, onSelectCannedResponse: onSelectCannedResponse, cannedQuery: cannedQuery }), _jsx(CannedResponseFooter, { openCreateCannedModal: openCreateCannedModal })] }));
|
|
33
|
+
};
|
|
34
|
+
export default CannedResponse;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IMyTeamResponse } from "../../../types/dto";
|
|
2
|
+
interface TeamItemProps {
|
|
3
|
+
team: IMyTeamResponse;
|
|
4
|
+
onSelectCategory?: (teamId: string, categoryId?: string) => void;
|
|
5
|
+
selectedTeamId?: string;
|
|
6
|
+
selectedCategoryId?: string;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const TeamItem: ({ team, onSelectCategory, selectedTeamId, selectedCategoryId, defaultOpen, }: TeamItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default TeamItem;
|
|
11
|
+
//# sourceMappingURL=TeamItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamItem.d.ts","sourceRoot":"","sources":["../../../../src/components/canned-response/team/TeamItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAQ9C,UAAU,aAAa;IACrB,IAAI,EAAE,eAAe,CAAC;IACtB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,QAAQ,GAAI,8EAMf,aAAa,4CAiFf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useFetchCannedCategories } from "../../../hooks/canned-response/useFetchCannedCategories";
|
|
3
|
+
import { useBoolean } from "ahooks";
|
|
4
|
+
import { Icon } from "../../../components/icon";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
7
|
+
import { useCallback } from "react";
|
|
8
|
+
const TeamItem = ({ team, onSelectCategory, selectedTeamId, selectedCategoryId, defaultOpen = false, }) => {
|
|
9
|
+
const { t } = useTranslation();
|
|
10
|
+
const [isOpen, { toggle }] = useBoolean(defaultOpen);
|
|
11
|
+
const { data: categories } = useFetchCannedCategories(team.teamId, isOpen);
|
|
12
|
+
const onToggle = useCallback(() => {
|
|
13
|
+
if (!isOpen && !selectedTeamId && !!(team === null || team === void 0 ? void 0 : team.teamId)) {
|
|
14
|
+
onSelectCategory === null || onSelectCategory === void 0 ? void 0 : onSelectCategory(team === null || team === void 0 ? void 0 : team.teamId, undefined);
|
|
15
|
+
}
|
|
16
|
+
toggle();
|
|
17
|
+
}, [toggle, isOpen, onSelectCategory, team === null || team === void 0 ? void 0 : team.teamId, selectedTeamId]);
|
|
18
|
+
return (_jsxs("div", { className: "border-b border-gray-200", children: [_jsxs("div", { className: "flex items-center justify-between py-2 cursor-pointer", onClick: onToggle, children: [_jsx("span", { className: "text-sm font-medium truncate flex-1", children: (team === null || team === void 0 ? void 0 : team.name) || "" }), _jsx(Icon, { icon: isOpen ? "angle-up-b" : "angle-down-b", size: 16, className: clsx(!isOpen && "text-gray-500") })] }), isOpen && (_jsxs("div", { className: "mb-2", children: [_jsx("div", { className: clsx("px-3 py-1 cursor-pointer hover:bg-gray-100 rounded-md", selectedTeamId &&
|
|
19
|
+
selectedTeamId === (team === null || team === void 0 ? void 0 : team.teamId) &&
|
|
20
|
+
!selectedCategoryId &&
|
|
21
|
+
"bg-gray-100"), onClick: () => onSelectCategory === null || onSelectCategory === void 0 ? void 0 : onSelectCategory(team === null || team === void 0 ? void 0 : team.teamId, undefined), children: _jsx("span", { className: clsx("text-sm truncate", selectedTeamId === (team === null || team === void 0 ? void 0 : team.teamId) && !selectedCategoryId
|
|
22
|
+
? "font-medium text-blue-500"
|
|
23
|
+
: "text-gray-500"), children: t("all") }) }, `${team.teamId}-all`), categories === null || categories === void 0 ? void 0 : categories.map((category) => {
|
|
24
|
+
const isSelected = selectedTeamId &&
|
|
25
|
+
selectedCategoryId &&
|
|
26
|
+
selectedTeamId === (category === null || category === void 0 ? void 0 : category.teamId) &&
|
|
27
|
+
selectedCategoryId === (category === null || category === void 0 ? void 0 : category.id);
|
|
28
|
+
return (_jsx("div", { className: clsx("px-3 py-1 cursor-pointer hover:bg-gray-100 rounded-md", isSelected && "bg-gray-100"), onClick: () => onSelectCategory === null || onSelectCategory === void 0 ? void 0 : onSelectCategory(team === null || team === void 0 ? void 0 : team.teamId, category === null || category === void 0 ? void 0 : category.id), children: _jsx("span", { className: clsx("text-sm truncate", isSelected ? "font-medium text-blue-500" : "text-gray-500"), children: category === null || category === void 0 ? void 0 : category.name }) }, `${team.teamId}-${category.id}`));
|
|
29
|
+
})] }))] }));
|
|
30
|
+
};
|
|
31
|
+
export default TeamItem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatBubble.d.ts","sourceRoot":"","sources":["../../../src/components/chat-bubble/ChatBubble.tsx"],"names":[],"mappings":"AAQA,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,UAAU,GAAI,eAAe,eAAe,4CA4FjD,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { FloatButton, Drawer, Popover } from "antd";
|
|
4
|
+
import { MessageOutlined, CloseOutlined } from "@ant-design/icons";
|
|
5
|
+
import MessageList from "../../components/message/MessageList";
|
|
6
|
+
import useConversationStore from "../../store/conversation";
|
|
7
|
+
import { useIsMobile } from "../../hooks/common/useIsMobile";
|
|
8
|
+
import { useBoolean } from "ahooks";
|
|
9
|
+
const ChatBubble = ({ className }) => {
|
|
10
|
+
const isMobile = useIsMobile();
|
|
11
|
+
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
12
|
+
const searchClientMsgID = useConversationStore((state) => state.searchClientMsgID);
|
|
13
|
+
const unreadCount = useConversationStore((state) => { var _a; return ((_a = state.conversationData) === null || _a === void 0 ? void 0 : _a.unreadCount) || 0; });
|
|
14
|
+
const displayUnread = unreadCount > 99 ? "99+" : unreadCount;
|
|
15
|
+
const [isOpen, { setFalse: setOpenFalse, toggle: toggleChat }] = useBoolean(false);
|
|
16
|
+
if (isMobile) {
|
|
17
|
+
return (_jsxs(_Fragment, { children: [_jsx(FloatButton, { icon: isOpen ? _jsx(CloseOutlined, {}) : _jsx(MessageOutlined, {}), type: "primary", style: {
|
|
18
|
+
right: 24,
|
|
19
|
+
bottom: 24,
|
|
20
|
+
width: 60,
|
|
21
|
+
height: 60,
|
|
22
|
+
}, onClick: toggleChat, className: className, badge: { count: displayUnread, color: "red" } }), _jsx(Drawer, { placement: "right", onClose: setOpenFalse, open: isOpen, mask: true, closable: false, styles: {
|
|
23
|
+
body: { padding: 0 },
|
|
24
|
+
}, classNames: {
|
|
25
|
+
wrapper: "!z-[9999]",
|
|
26
|
+
}, width: "100%", push: false, children: _jsx(MessageList, { conversationId: selectedConversationId, className: "flex-1", onClose: setOpenFalse, searchClientMsgID: searchClientMsgID }) })] }));
|
|
27
|
+
}
|
|
28
|
+
return (_jsx(Popover, { placement: "topLeft", trigger: "click", open: isOpen, destroyOnHidden: true, content: () => (_jsx("div", { className: "w-[400px] h-[600px]", children: _jsx(MessageList, { conversationId: selectedConversationId, className: "flex-1", onClose: setOpenFalse, searchClientMsgID: searchClientMsgID }) })), styles: { body: { padding: 0 } }, children: _jsx(FloatButton, { icon: isOpen ? _jsx(CloseOutlined, {}) : _jsx(MessageOutlined, {}), type: "primary", style: {
|
|
29
|
+
right: 24,
|
|
30
|
+
bottom: 24,
|
|
31
|
+
width: 60,
|
|
32
|
+
height: 60,
|
|
33
|
+
}, className: className, badge: { count: displayUnread, color: "red" }, onClick: toggleChat }) }));
|
|
34
|
+
};
|
|
35
|
+
export default ChatBubble;
|
|
@@ -7,7 +7,7 @@ import { Icon } from "../../components/icon";
|
|
|
7
7
|
import useConversationStore from "../../store/conversation";
|
|
8
8
|
import { useTranslation } from "react-i18next";
|
|
9
9
|
import { useBoolean, useDebounce } from "ahooks";
|
|
10
|
-
import SearchConversation from "../../components/
|
|
10
|
+
import SearchConversation from "../../components/search-conversation";
|
|
11
11
|
import useSessionStore from "../../store/session";
|
|
12
12
|
import InfiniteScroll from "react-infinite-scroll-component";
|
|
13
13
|
import ConversationBySessionItem from "./ConversationBySessionItem";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/FileCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,cAAc,+CAqGnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { useSearchMessage } from "../../hooks/search/useSearchMessage";
|
|
4
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
5
|
+
import { Empty, Spin } from "antd";
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import useConversationStore from "../../store/conversation";
|
|
9
|
+
import { useTranslation } from "react-i18next";
|
|
10
|
+
import { documentIcon } from "../../assets/svg";
|
|
11
|
+
import { shortenFileName } from "../../components/message/footer/FilePreview";
|
|
12
|
+
import { renderFileSize } from "../../utils/common";
|
|
13
|
+
const FileCollection = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
16
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useSearchMessage({
|
|
17
|
+
payload: {
|
|
18
|
+
recvID: selectedSourceId,
|
|
19
|
+
contentType: MessageType.FileMessage,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const handleDownload = (url, fileName) => {
|
|
23
|
+
if (!url) {
|
|
24
|
+
console.warn("Không có link file để tải");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const link = document.createElement("a");
|
|
28
|
+
link.href = url;
|
|
29
|
+
if (fileName) {
|
|
30
|
+
link.setAttribute("download", fileName);
|
|
31
|
+
}
|
|
32
|
+
link.setAttribute("target", "_blank");
|
|
33
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
34
|
+
document.body.appendChild(link);
|
|
35
|
+
link.click();
|
|
36
|
+
link.remove();
|
|
37
|
+
};
|
|
38
|
+
const renderItem = useCallback((date, items) => {
|
|
39
|
+
return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
|
|
40
|
+
var _a, _b, _c;
|
|
41
|
+
const fileContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
42
|
+
return (_jsxs("div", { className: "relative flex flex-row items-center gap-2 align-center bg-gray-100 rounded-md p-2 cursor-pointer", onClick: () => handleDownload((fileContent === null || fileContent === void 0 ? void 0 : fileContent.sourceUrl) || "", (fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || ""), children: [documentIcon, _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("span", { className: "text-sm font-medium", children: shortenFileName((fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || "", {
|
|
43
|
+
maxLength: 32,
|
|
44
|
+
}) }), _jsx("span", { className: "text-xs text-gray-500", children: `${renderFileSize(fileContent.fileSize || 0)} - ${dayjs(((_b = item === null || item === void 0 ? void 0 : item.chatLog) === null || _b === void 0 ? void 0 : _b.sendTime) || 0).format("HH:mm")}` })] })] }, (_c = item.chatLog) === null || _c === void 0 ? void 0 : _c.clientMsgID));
|
|
45
|
+
}) })] }, date));
|
|
46
|
+
}, []);
|
|
47
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
48
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
49
|
+
if (isLoading)
|
|
50
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
51
|
+
return (_jsx("div", { id: "scrollableFileDiv", className: "h-full overflow-auto", children: _jsx(InfiniteScroll, { dataLength: Object.keys(groupedData).length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableFileDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }) }));
|
|
52
|
+
};
|
|
53
|
+
export default FileCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/ImageCollection.tsx"],"names":[],"mappings":"AAYA,QAAA,MAAM,eAAe,+CA+GpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { useSearchMessage } from "../../hooks/search/useSearchMessage";
|
|
4
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
5
|
+
import { Button, Empty, Image, Spin } from "antd";
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import useConversationStore from "../../store/conversation";
|
|
9
|
+
import { images } from "../../constants/images";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
11
|
+
import { DownloadOutlined } from "@ant-design/icons";
|
|
12
|
+
const ImageCollection = () => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
15
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useSearchMessage({
|
|
16
|
+
payload: {
|
|
17
|
+
recvID: selectedSourceId,
|
|
18
|
+
contentType: MessageType.PictureMessage,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
const handleDownload = (imageUrl) => {
|
|
22
|
+
if (!imageUrl)
|
|
23
|
+
return;
|
|
24
|
+
const link = document.createElement("a");
|
|
25
|
+
link.href = imageUrl;
|
|
26
|
+
link.download = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
|
|
27
|
+
document.body.appendChild(link);
|
|
28
|
+
link.click();
|
|
29
|
+
document.body.removeChild(link);
|
|
30
|
+
};
|
|
31
|
+
const renderItem = useCallback((date, items) => {
|
|
32
|
+
return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
|
|
33
|
+
var _a, _b, _c, _d;
|
|
34
|
+
const imageContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
35
|
+
const sourceUrl = ((_b = imageContent.sourcePicture) === null || _b === void 0 ? void 0 : _b.url) ||
|
|
36
|
+
((_c = imageContent.snapshotPicture) === null || _c === void 0 ? void 0 : _c.url);
|
|
37
|
+
return (_jsx("div", { className: "border inline-block w-full h-full aspect-square", children: _jsx(Image, { rootClassName: "cursor-pointer w-full h-full", className: "w-full !h-full object-cover", src: sourceUrl, preview: true, placeholder: _jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }), fallback: images.imageFailed }) }, (_d = item === null || item === void 0 ? void 0 : item.chatLog) === null || _d === void 0 ? void 0 : _d.clientMsgID));
|
|
38
|
+
}) })] }, date));
|
|
39
|
+
}, []);
|
|
40
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
41
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
42
|
+
if (isLoading)
|
|
43
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
44
|
+
return (_jsx("div", { id: "scrollableImageDiv", className: "h-full overflow-auto", children: _jsx(Image.PreviewGroup, { preview: {
|
|
45
|
+
toolbarRender: (originalNode, info) => {
|
|
46
|
+
var _a;
|
|
47
|
+
const imageUrl = (_a = info === null || info === void 0 ? void 0 : info.image) === null || _a === void 0 ? void 0 : _a.url;
|
|
48
|
+
return (_jsxs("div", { className: "flex flex-col justify-center gap-2", children: [originalNode, imageUrl && (_jsx(Button, { type: "primary", icon: _jsx(DownloadOutlined, {}), className: "self-center", onClick: () => handleDownload(imageUrl), children: t("download") }))] }));
|
|
49
|
+
},
|
|
50
|
+
}, children: _jsx(InfiniteScroll, { dataLength: dataFlatten.length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableImageDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }) }) }));
|
|
51
|
+
};
|
|
52
|
+
export default ImageCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/LinkCollection.tsx"],"names":[],"mappings":"AA8DA,QAAA,MAAM,cAAc,GAAI,aAAa;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,4CAyH3D,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Dropdown, Empty, Spin } from "antd";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import useConversationStore from "../../store/conversation";
|
|
5
|
+
import { useSearchMessage } from "../../hooks/search/useSearchMessage";
|
|
6
|
+
import { useCallback, useEffect, useState } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
9
|
+
import { MessageType, SessionType } from "@openim/wasm-client-sdk";
|
|
10
|
+
import { Icon } from "../../components/icon";
|
|
11
|
+
import { DChatSDK } from "../../constants/sdk";
|
|
12
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
13
|
+
import { message as antdMessage } from "antd";
|
|
14
|
+
const LinkPreview = ({ url }) => {
|
|
15
|
+
const [title, setTitle] = useState("");
|
|
16
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!url)
|
|
19
|
+
return;
|
|
20
|
+
setIsLoading(true);
|
|
21
|
+
fetch(`https://api.microlink.io?url=${encodeURIComponent(url)}`)
|
|
22
|
+
.then((res) => res.json())
|
|
23
|
+
.then((res) => {
|
|
24
|
+
var _a;
|
|
25
|
+
if ((_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.title) {
|
|
26
|
+
setTitle(res.data.title);
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
.catch(() => {
|
|
30
|
+
setTitle("");
|
|
31
|
+
})
|
|
32
|
+
.finally(() => {
|
|
33
|
+
setIsLoading(false);
|
|
34
|
+
});
|
|
35
|
+
}, [url]);
|
|
36
|
+
return (_jsxs("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "flex flex-col truncate text-blue-600 cursor-pointer", title: title || url, children: [isLoading && (_jsx("span", { className: "font-medium truncate text-gray-900", children: url })), !isLoading &&
|
|
37
|
+
(title ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium truncate text-gray-900", children: title }), _jsx("span", { className: "text-sm text-gray-500 truncate", children: url })] })) : (_jsx("span", { className: "font-medium truncate text-gray-900", children: url })))] }));
|
|
38
|
+
};
|
|
39
|
+
const LinkCollection = ({ onClose }) => {
|
|
40
|
+
const { t } = useTranslation();
|
|
41
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
42
|
+
const { user } = useChatContext();
|
|
43
|
+
const onPressItem = async (message) => {
|
|
44
|
+
const { data } = await DChatSDK.getOneConversation({
|
|
45
|
+
sourceID: message.sessionType === SessionType.Group
|
|
46
|
+
? message.groupID
|
|
47
|
+
: (user === null || user === void 0 ? void 0 : user.userID) !== message.sendID
|
|
48
|
+
? message.sendID
|
|
49
|
+
: message.recvID,
|
|
50
|
+
sessionType: message.sessionType,
|
|
51
|
+
});
|
|
52
|
+
if (!data) {
|
|
53
|
+
return antdMessage.error(t("err_get_conversation"));
|
|
54
|
+
}
|
|
55
|
+
useConversationStore
|
|
56
|
+
.getState()
|
|
57
|
+
.setConversationData(data, message.clientMsgID);
|
|
58
|
+
useConversationStore
|
|
59
|
+
.getState()
|
|
60
|
+
.setSelectedConversationId(data.conversationID);
|
|
61
|
+
onClose();
|
|
62
|
+
};
|
|
63
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useSearchMessage({
|
|
64
|
+
payload: {
|
|
65
|
+
recvID: selectedSourceId,
|
|
66
|
+
contentType: MessageType.UrlTextMessage,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
const renderItem = useCallback((date, items) => {
|
|
70
|
+
return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
|
|
71
|
+
var _a, _b, _c;
|
|
72
|
+
const urls = ((_b = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}")) === null || _b === void 0 ? void 0 : _b.urls) || [];
|
|
73
|
+
const menuItems = [
|
|
74
|
+
{
|
|
75
|
+
key: "open",
|
|
76
|
+
label: t("view_message"),
|
|
77
|
+
onClick: () => onPressItem(item.chatLog),
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
return (_jsx("div", { children: urls.map((url, index) => {
|
|
81
|
+
var _a;
|
|
82
|
+
return (_jsxs("div", { className: "bg-gray-100 flex gap-2 items-center p-2 mb-1", children: [_jsx("div", { className: "flex items-center justify-center shrink-0", children: _jsx(Icon, { icon: "link-b", size: 16 }) }), _jsx("div", { className: "flex-1 min-w-0", children: _jsx(LinkPreview, { url: url }) }), _jsx(Dropdown, { menu: { items: menuItems }, trigger: ["click"], placement: "bottomRight", children: _jsx("div", { className: "flex items-center justify-center shrink-0 cursor-pointer p-1 hover:bg-gray-200 rounded ml-2", onClick: (e) => e.stopPropagation(), children: _jsx(Icon, { icon: "more-horizontal-b", size: 16 }) }) })] }, `${(_a = item.chatLog) === null || _a === void 0 ? void 0 : _a.clientMsgID}-${index}`));
|
|
83
|
+
}) }, (_c = item.chatLog) === null || _c === void 0 ? void 0 : _c.clientMsgID));
|
|
84
|
+
}) })] }, date));
|
|
85
|
+
}, []);
|
|
86
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
87
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
88
|
+
if (isLoading)
|
|
89
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
90
|
+
return (_jsx("div", { id: "scrollableFileDiv", className: "h-full overflow-auto", children: _jsx(InfiniteScroll, { dataLength: Object.keys(groupedData).length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableFileDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }) }));
|
|
91
|
+
};
|
|
92
|
+
export default LinkCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/VideoCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,eAAe,+CAyHpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { useSearchMessage } from "../../hooks/search/useSearchMessage";
|
|
4
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
5
|
+
import { Carousel, Empty, Image, Modal, Spin } from "antd";
|
|
6
|
+
import { useCallback, useState } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import useConversationStore from "../../store/conversation";
|
|
9
|
+
import { useBoolean } from "ahooks";
|
|
10
|
+
import { images } from "../../constants/images";
|
|
11
|
+
import { Icon } from "../../components/icon";
|
|
12
|
+
import { useTranslation } from "react-i18next";
|
|
13
|
+
const VideoCollection = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
16
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useSearchMessage({
|
|
17
|
+
payload: {
|
|
18
|
+
recvID: selectedSourceId,
|
|
19
|
+
contentType: MessageType.VideoMessage,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const [open, { setTrue, setFalse }] = useBoolean(false);
|
|
23
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
24
|
+
const handleOpenPreview = (index) => {
|
|
25
|
+
setCurrentIndex(index);
|
|
26
|
+
setTrue();
|
|
27
|
+
};
|
|
28
|
+
const renderItem = useCallback((date, items) => {
|
|
29
|
+
return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
const videoContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
32
|
+
const globalIndex = dataFlatten.findIndex((v) => { var _a, _b; return ((_a = v.chatLog) === null || _a === void 0 ? void 0 : _a.clientMsgID) === ((_b = item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID); });
|
|
33
|
+
return (_jsxs("div", { className: "border relative w-full h-full aspect-square cursor-pointer", onClick: () => handleOpenPreview(globalIndex), children: [_jsx(Image, { rootClassName: "w-full h-full", src: videoContent.snapshotUrl, alt: "video thumbnail", className: "w-full !h-full object-cover", fallback: images.imageFailed }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/30 text-white text-2xl", children: _jsx(Icon, { icon: "play-b", size: 24, color: "white" }) })] }, (_b = item === null || item === void 0 ? void 0 : item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID));
|
|
34
|
+
}) })] }, date));
|
|
35
|
+
}, []);
|
|
36
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
37
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
38
|
+
if (isLoading)
|
|
39
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
40
|
+
return (_jsxs("div", { id: "scrollableVideoDiv", className: "h-full overflow-auto", children: [_jsx(InfiniteScroll, { dataLength: Object.keys(groupedData).length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableVideoDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }), _jsx(Modal, { open: open, onCancel: setFalse, footer: null, centered: true, styles: {
|
|
41
|
+
content: {
|
|
42
|
+
padding: 0,
|
|
43
|
+
},
|
|
44
|
+
}, children: _jsx(Carousel, { dots: true, infinite: false, initialSlide: currentIndex, afterChange: (i) => setCurrentIndex(i), children: dataFlatten.map((item, idx) => {
|
|
45
|
+
var _a;
|
|
46
|
+
const videoContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
47
|
+
const sourceUrl = videoContent.videoUrl;
|
|
48
|
+
return (_jsx("div", { style: { textAlign: "center" }, children: _jsx("video", { src: sourceUrl, controls: true, autoPlay: idx === currentIndex, style: { width: "100%", maxHeight: "80vh" } }) }, idx));
|
|
49
|
+
}) }) })] }));
|
|
50
|
+
};
|
|
51
|
+
export default VideoCollection;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare enum MediaCollectionTabKey {
|
|
2
|
+
Image = "image",
|
|
3
|
+
Video = "video",
|
|
4
|
+
File = "file",
|
|
5
|
+
Link = "link"
|
|
6
|
+
}
|
|
7
|
+
declare const MediaCollection: () => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default MediaCollection;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/index.tsx"],"names":[],"mappings":"AAaA,oBAAY,qBAAqB;IAC/B,KAAK,UAAU;IACf,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,QAAA,MAAM,eAAe,+CA8EpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useBoolean } from "ahooks";
|
|
4
|
+
import { Button, Drawer, Tabs } from "antd";
|
|
5
|
+
import { Icon } from "../../components/icon";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
7
|
+
import ImageCollection from "./ImageCollection";
|
|
8
|
+
import VideoCollection from "./VideoCollection";
|
|
9
|
+
import { useIsMobile } from "../../hooks/common/useIsMobile";
|
|
10
|
+
import { useMemo } from "react";
|
|
11
|
+
import FileCollection from "./FileCollection";
|
|
12
|
+
import LinkCollection from "./LinkCollection";
|
|
13
|
+
export var MediaCollectionTabKey;
|
|
14
|
+
(function (MediaCollectionTabKey) {
|
|
15
|
+
MediaCollectionTabKey["Image"] = "image";
|
|
16
|
+
MediaCollectionTabKey["Video"] = "video";
|
|
17
|
+
MediaCollectionTabKey["File"] = "file";
|
|
18
|
+
MediaCollectionTabKey["Link"] = "link";
|
|
19
|
+
})(MediaCollectionTabKey || (MediaCollectionTabKey = {}));
|
|
20
|
+
const MediaCollection = () => {
|
|
21
|
+
const { t } = useTranslation();
|
|
22
|
+
const [isOpen, { toggle }] = useBoolean(false);
|
|
23
|
+
const isMobile = useIsMobile();
|
|
24
|
+
const items = useMemo(() => {
|
|
25
|
+
if (!isOpen)
|
|
26
|
+
return [];
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
key: MediaCollectionTabKey.Image,
|
|
30
|
+
label: t("image"),
|
|
31
|
+
children: _jsx(ImageCollection, {}),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: MediaCollectionTabKey.Video,
|
|
35
|
+
label: t("video"),
|
|
36
|
+
children: _jsx(VideoCollection, {}),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: MediaCollectionTabKey.File,
|
|
40
|
+
label: t("file"),
|
|
41
|
+
children: _jsx(FileCollection, {}),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
key: MediaCollectionTabKey.Link,
|
|
45
|
+
label: t("link"),
|
|
46
|
+
children: _jsx(LinkCollection, { onClose: toggle }),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}, [isOpen, t]);
|
|
50
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "folder-o", size: 22 }) }), _jsx(Drawer, { open: isOpen, onClose: toggle, mask: false, closeIcon: false, styles: {
|
|
51
|
+
body: {
|
|
52
|
+
padding: 0,
|
|
53
|
+
height: "100%",
|
|
54
|
+
},
|
|
55
|
+
}, getContainer: false, width: isMobile ? "100%" : 360, children: _jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsx("span", { className: "text-lg font-medium", children: t("library") }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "close-b", size: 22 }) })] }), _jsx("div", { className: "flex-1 overflow-hidden", children: _jsx(Tabs, { defaultActiveKey: MediaCollectionTabKey.Image, items: items, className: "h-full" }) })] }) })] }));
|
|
56
|
+
};
|
|
57
|
+
export default MediaCollection;
|
|
@@ -4,14 +4,14 @@ import { Avatar, Button, message } from "antd";
|
|
|
4
4
|
import { Icon } from "../../components/icon";
|
|
5
5
|
import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
|
|
6
6
|
import useConversationStore from "../../store/conversation";
|
|
7
|
-
import MediaCollection from "../../components/
|
|
7
|
+
import MediaCollection from "../../components/media-collection";
|
|
8
8
|
import { useEffect, useMemo, useState } from "react";
|
|
9
9
|
import { useTranslation } from "react-i18next";
|
|
10
10
|
import { SessionStatus, SessionTag } from "../../types/chat";
|
|
11
11
|
import SelectSession from "./SelectSession";
|
|
12
12
|
import { useUpdateSession } from "../../hooks/session/useUpdateSession";
|
|
13
13
|
import useAuthStore from "../../store/auth";
|
|
14
|
-
import SearchDrawer from "../../components/
|
|
14
|
+
import SearchDrawer from "../../components/search-conversation/SearchDrawer";
|
|
15
15
|
import { isGroupSession } from "../../utils/imCommon";
|
|
16
16
|
import GroupMembersDrawer from "./GroupMembersDrawer";
|
|
17
17
|
const MessageHeader = ({ onClose, currentSession, isJoined, }) => {
|
|
@@ -10,7 +10,7 @@ import EmojiPicker from "./EmojiPicker";
|
|
|
10
10
|
import { Icon } from "../../../components/icon";
|
|
11
11
|
import { validateFile, validateVideoLimit, } from "../../../utils/fileValidation";
|
|
12
12
|
import { DOCUMENT_TYPES } from "./editorConfig";
|
|
13
|
-
import CannedResponseIcon from "../../../assets/svg/
|
|
13
|
+
import CannedResponseIcon from "../../../assets/svg/canned-response";
|
|
14
14
|
import { useMessageFooterContext } from ".";
|
|
15
15
|
import useAuthStore from "../../../store/auth";
|
|
16
16
|
const EmojiIcon = (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M7.59997 12.4C7.59997 12.4 8.49997 13.2 9.99997 13.2C11.5 13.2 12.4 12.4 12.4 12.4M14 8.39997C14 8.8418 13.6418 9.19997 13.2 9.19997C12.7581 9.19997 12.4 8.8418 12.4 8.39997C12.4 7.95814 12.7581 7.59997 13.2 7.59997C13.6418 7.59997 14 7.95814 14 8.39997ZM18 9.99997C18 14.4182 14.4182 18 9.99997 18C5.58169 18 1.99997 14.4182 1.99997 9.99997C1.99997 5.58169 5.58169 1.99997 9.99997 1.99997C14.4182 1.99997 18 5.58169 18 9.99997ZM7.59997 8.39997C7.59997 8.8418 7.2418 9.19997 6.79997 9.19997C6.35814 9.19997 5.99997 8.8418 5.99997 8.39997C5.99997 7.95814 6.35814 7.59997 6.79997 7.59997C7.2418 7.59997 7.59997 7.95814 7.59997 8.39997Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
@@ -15,7 +15,7 @@ import FilePreview from "./FilePreview";
|
|
|
15
15
|
import { useTranslation } from "react-i18next";
|
|
16
16
|
import PasteAndDropPlugin from "./PasteAndDropPlugin";
|
|
17
17
|
import { QuotedMessageFooter } from "./QuotedMessage";
|
|
18
|
-
import CannedResponse from "../../../components/
|
|
18
|
+
import CannedResponse from "../../../components/canned-response";
|
|
19
19
|
import { CannedResponseTriggerPlugin } from "./CannedResponsePlugin";
|
|
20
20
|
import { useBoolean } from "ahooks";
|
|
21
21
|
import useAuthStore from "../../../store/auth";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UploadFile } from "antd";
|
|
2
|
+
interface RichTextEditorProps {
|
|
3
|
+
initialHtml?: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
onChange?: (html: string, plainText: string) => void;
|
|
6
|
+
onFilesChange?: (files: UploadFile[]) => void;
|
|
7
|
+
minHeight?: string;
|
|
8
|
+
showMediaUpload?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight, showMediaUpload, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=RichTextEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/rich-text-editor/RichTextEditor.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AA0ClC,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,WAAW,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,SAAmB,EACnB,eAAsB,GACvB,EAAE,mBAAmB,2CA6DrB"}
|