UNPKG

@droppii-org/chat-sdk

Version:

Droppii React Chat SDK

142 lines (141 loc) 9.54 kB
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;