@droppii-org/chat-sdk
Version:
Droppii React Chat SDK
142 lines (141 loc) • 9.54 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useBoolean, useDebounce } from "ahooks";
import { Icon } from "../icon";
import { Button, Select, Spin, Tag, Input, message, Avatar } from "antd";
import { useGetLabelSession } from "../../hooks/session/useGetLabelSession";
import { useUpdateSessionInfo } from "../../hooks/session/useUpdateSessionInfo";
import { useCloseSession } from "../../hooks/session/useCloseSession";
import { useQueryClient } from "@tanstack/react-query";
import { QUERY_KEYS } from "../../services/query";
import { useEffect, useState } from "react";
const { TextArea } = Input;
const formatSessionDate = (dateString) => {
if (!dateString)
return "";
const date = new Date(dateString);
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const month = String(date.getMonth() + 1).padStart(2, "0");
return `${hours}:${minutes} ${day}/${month}`;
};
export const SessionDetailCard = ({ session, isActive, }) => {
var _a, _b, _c, _d, _e;
const queryClient = useQueryClient();
const { data: availableLabels, isLoading: isLoadingLabels } = useGetLabelSession();
const { mutate: updateSession } = useUpdateSessionInfo();
const { mutate: closeSession, isPending: isClosing } = useCloseSession();
const [noteInput, setNoteInput] = useState({
value: session.note || "",
sessionId: session.id,
});
const [issueDetailInput, setIssueDetailInput] = useState({
value: session.issueDetail || "",
sessionId: session.id,
});
const debouncedNoteInput = useDebounce(noteInput, { wait: 500 });
const debouncedIssueDetailInput = useDebounce(issueDetailInput, {
wait: 500,
});
useEffect(() => {
setNoteInput({ value: session.note || "", sessionId: session.id });
setIssueDetailInput({
value: session.issueDetail || "",
sessionId: session.id,
});
}, [session.id]);
useEffect(() => {
if (debouncedNoteInput.sessionId === session.id &&
debouncedNoteInput.value !== (session.note || "")) {
updateSession({ sessionId: session.id, note: debouncedNoteInput.value }, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.GET_LIST_SESSION_BY_CONVERSATION],
});
},
});
}
}, [
debouncedNoteInput,
session.note,
session.id,
updateSession,
queryClient,
]);
useEffect(() => {
if (debouncedIssueDetailInput.sessionId === session.id &&
debouncedIssueDetailInput.value !== (session.issueDetail || "")) {
updateSession({
sessionId: session.id,
issueDetail: debouncedIssueDetailInput.value,
}, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.GET_LIST_SESSION_BY_CONVERSATION],
});
},
});
}
}, [
debouncedIssueDetailInput,
session.issueDetail,
session.id,
updateSession,
queryClient,
]);
const handleUpdateLabels = (labelIds) => {
updateSession({ sessionId: session.id, labelIds }, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.GET_LIST_SESSION_BY_CONVERSATION],
});
},
});
};
const handleCloseSession = () => {
closeSession(session.id, {
onSuccess: () => {
message.success("Đóng phiên chat thành công");
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.GET_LIST_SESSION_BY_CONVERSATION],
});
},
onError: () => {
message.error("Đóng phiên chat thất bại");
},
});
};
const labelOptions = availableLabels === null || availableLabels === void 0 ? void 0 : availableLabels.map((label) => ({
value: label.id,
label: label.name,
}));
return (_jsxs("div", { className: `p-3 border rounded-lg shadow-md ${isActive ? "border-blue-500" : "border-gray-300"}`, children: [_jsxs("div", { className: "flex justify-between items-start mb-3", children: [_jsx("div", { className: "flex items-center gap-2", children: _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Icon, { icon: "chat-square-b", size: 16, className: "text-gray-500" }), _jsxs("p", { className: "font-semibold text-sm", children: ["Session ", session.order] })] }), _jsx("p", { className: "text-xs text-gray-400", children: formatSessionDate(session.closedDate || session.createdDate) })] }) }), isActive ? (_jsx(Tag, { color: "processing", children: "\u0110ang ho\u1EA1t \u0111\u1ED9ng" })) : (_jsx(Avatar, { src: (_a = session.supporter) === null || _a === void 0 ? void 0 : _a.avatar, size: 24, children: ((_d = (_c = (_b = session.supporter) === null || _b === void 0 ? void 0 : _b.username) === null || _c === void 0 ? void 0 : _c.charAt) === null || _d === void 0 ? void 0 : _d.call(_c, 0)) || "A" }))] }), _jsxs("div", { className: "flex flex-col gap-3 text-sm", children: [_jsxs("div", { className: "flex items-center gap-2 text-gray-500", children: [_jsx(Icon, { icon: "tag-o", size: 16, className: "mt-1" }), _jsx(Select, { mode: "multiple", loading: isLoadingLabels, className: "w-full", placeholder: "Th\u00EAm th\u1EBB...", options: labelOptions, value: (_e = session.labels) === null || _e === void 0 ? void 0 : _e.map((label) => label.id), onChange: handleUpdateLabels, removeIcon: true })] }), _jsxs("div", { className: "flex items-start gap-2 text-gray-500", children: [_jsx(Icon, { icon: "info-circle-o", size: 16, className: "mt-1" }), _jsx(TextArea, { value: issueDetailInput.value, onChange: (e) => setIssueDetailInput({
value: e.target.value,
sessionId: session.id,
}), placeholder: "V\u1EA5n \u0111\u1EC1 c\u1EE5 th\u1EC3...", className: "border-none !shadow-none py-0 px-2", autoSize: { minRows: 1, maxRows: 3 } })] }), _jsxs("div", { className: "flex items-start gap-2 text-gray-500", children: [_jsx(Icon, { icon: "paper-o", size: 16, className: "mt-1" }), _jsx(TextArea, { value: noteInput.value, onChange: (e) => setNoteInput({ value: e.target.value, sessionId: session.id }), placeholder: "Ghi ch\u00FA...", className: "border-none !shadow-none py-0 px-2", autoSize: { minRows: 1, maxRows: 3 } })] })] }), isActive && (_jsx(Button, { type: "primary", block: true, className: "mt-4", onClick: handleCloseSession, loading: isClosing, children: "\u0110\u00F3ng" }))] }));
};
const ClosedSessionItem = ({ session, expandedSessionId, onToggleExpand, }) => {
var _a, _b, _c, _d;
const isExpanded = session.id === expandedSessionId;
const handleClick = () => {
onToggleExpand(session.id);
};
if (isExpanded) {
return (_jsx("div", { children: _jsx(SessionDetailCard, { session: session, isActive: false }) }));
}
return (_jsxs("div", { className: "flex justify-between items-center p-2 rounded-md hover:bg-gray-100 cursor-pointer", onClick: handleClick, children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Icon, { icon: "chat-square-b", size: 16, className: "text-gray-500" }), _jsxs("span", { className: "font-semibold", children: ["Session ", session.order] }), _jsx("span", { className: "text-gray-400 text-xs", children: formatSessionDate(session.closedDate || session.createdDate) })] }), _jsx(Avatar, { src: (_a = session.supporter) === null || _a === void 0 ? void 0 : _a.avatar, size: 24, children: ((_d = (_c = (_b = session.supporter) === null || _b === void 0 ? void 0 : _b.username) === null || _c === void 0 ? void 0 : _c.charAt) === null || _d === void 0 ? void 0 : _d.call(_c, 0)) || "A" })] }));
};
const SessionSection = ({ sessions, isLoading }) => {
const [isOpen, { toggle }] = useBoolean(true);
const [expandedSessionId, setExpandedSessionId] = useState(null);
const handleToggleExpand = (sessionId) => {
setExpandedSessionId((prevId) => (prevId === sessionId ? null : sessionId));
};
useEffect(() => {
if (!isOpen) {
setExpandedSessionId(null);
}
}, [isOpen]);
return (_jsxs("div", { className: "flex flex-col border-b", children: [_jsxs("div", { role: "button", onClick: toggle, className: "flex items-center justify-between px-4 py-2 rounded-md hover:bg-gray-100 sticky top-0 bg-white z-10", children: [_jsx("h3", { className: "font-bold text-gray-500 text-xs tracking-wider", children: "SESSIONS" }), _jsx(Icon, { icon: isOpen ? "angle-up-o" : "angle-down-o", size: 18 })] }), isOpen && (_jsx("div", { className: "px-4 pt-2 pb-4", children: isLoading ? (_jsx("div", { className: "text-center mt-4", children: _jsx(Spin, {}) })) : (_jsx("div", { className: "flex flex-col gap-1", children: sessions.map((session) => (_jsx(ClosedSessionItem, { session: session, expandedSessionId: expandedSessionId, onToggleExpand: handleToggleExpand }, session.id))) })) }))] }));
};
export default SessionSection;