diff --git a/web/pages/chat.tsx b/web/pages/chat.tsx index 1d3a1531b..8deef3750 100644 --- a/web/pages/chat.tsx +++ b/web/pages/chat.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import { Table, Typography, Tooltip, Button } from "antd"; -import { CheckCircleFilled, ExclamationCircleFilled, StopOutlined } from "@ant-design/icons"; +import { CheckCircleFilled, ExclamationCircleFilled } from "@ant-design/icons"; import classNames from 'classnames'; import { ColumnsType } from 'antd/es/table'; import format from 'date-fns/format' @@ -8,6 +8,7 @@ import format from 'date-fns/format' import { CHAT_HISTORY, fetchData, FETCH_INTERVAL, UPDATE_CHAT_MESSGAE_VIZ } from "../utils/apis"; import { MessageType } from '../types/chat'; import { isEmptyObject } from "../utils/format"; +import MessageVisiblityToggle from "./components/message-visiblity-toggle"; const { Title } = Typography; @@ -80,6 +81,11 @@ export default function Chat() { }, }; + const updateMessage = message => { + const messageIndex = messages.findIndex(m => m.id === message.id); + messages.splice(messageIndex, 1, message) + setMessages([...messages]); + }; const resetBulkOutcome = () => { outcomeTimeout = setTimeout(() => { @@ -179,7 +185,13 @@ export default function Chat() { className: 'toggle-col', filters: [{ text: 'Visible messages', value: true }, { text: 'Hidden messages', value: false }], onFilter: (value, record) => record.visible === value, - render: visible => visible ? null : , + render: (visible, record) => ( + + ), width: 30, }, ]; @@ -235,4 +247,3 @@ export default function Chat() { ) } - diff --git a/web/pages/components/message-visiblity-toggle.tsx b/web/pages/components/message-visiblity-toggle.tsx new file mode 100644 index 000000000..c202e8d1e --- /dev/null +++ b/web/pages/components/message-visiblity-toggle.tsx @@ -0,0 +1,83 @@ +// Custom component for AntDesign Button that makes an api call, then displays a confirmation icon upon +import React, { useState, useEffect } from "react"; +import { Button, Tooltip } from "antd"; +import { EyeOutlined, EyeInvisibleOutlined, CheckCircleFilled, ExclamationCircleFilled } from "@ant-design/icons"; +import { fetchData, UPDATE_CHAT_MESSGAE_VIZ } from "../../utils/apis"; +import { MessageType } from '../../types/chat'; +import { OUTCOME_TIMEOUT } from "../chat"; +import { isEmptyObject } from "../../utils/format"; + +interface MessageToggleProps { + isVisible: boolean; + message: MessageType; + setMessage: (message: MessageType) => void, +}; + + +export default function MessageVisiblityToggle({ isVisible, message, setMessage }: MessageToggleProps) { + if (!message || isEmptyObject(message)) { + return null; + } + + let outcomeTimeout = null; + const [outcome, setOutcome] = useState(0); + + const { id: messageId } = message || {}; + + const resetOutcome = () => { + outcomeTimeout = setTimeout(() => { setOutcome(0)}, OUTCOME_TIMEOUT); + }; + + useEffect(() => { + return () => { + clearTimeout(outcomeTimeout); + }; + }); + + + const updateChatMessage = async () => { + clearTimeout(outcomeTimeout); + setOutcome(0); + const result = await fetchData(UPDATE_CHAT_MESSGAE_VIZ, { + auth: true, + method: 'POST', + data: { + visible: !isVisible, + idArray: [messageId], + }, + }); + + if (result.success && result.message === "changed") { + setMessage({ ...message, visible: !isVisible }); + setOutcome(1); + } else { + setMessage({ ...message, visible: isVisible }); + setOutcome(-1); + } + resetOutcome(); + } + + + let outcomeIcon = ; + if (outcome) { + outcomeIcon = outcome > 0 ? + : + ; + } + + const toolTipMessage = `Click to ${isVisible ? 'hide' : 'show'} this message`; + return ( +
+ {outcomeIcon} + +
+ ); +} \ No newline at end of file diff --git a/web/styles/chat.scss b/web/styles/chat.scss index 2d7ab68e1..13a84a0cc 100644 --- a/web/styles/chat.scss +++ b/web/styles/chat.scss @@ -4,13 +4,17 @@ min-width: 20px; } .ant-table-tbody > tr > td { - transition: background 0.15s; + transition: background-color 0.15s; } .ant-table-row.hidden { .ant-table-cell { - color: #444450; + color: rgba(0,0,0,.25) + } + @media (prefers-color-scheme: dark) { + .ant-table-cell { + color: rgba(255,255,255,.25) + } } - } .ant-table-cell { font-size: 12px; @@ -43,16 +47,23 @@ .bulk-editor { margin: .5rem 0; padding: .5rem; - border: 1px solid #333; + border: 1px solid #ccc; display: flex; flex-direction: row; align-items: center; justify-content: flex-end; border-radius: 4px; + opacity: .5; &.active { + opacity: 1; .label { - color: #ccc; + color: #000; + } + @media (prefers-color-scheme: dark) { + .label { + color: #fff; + } } } @@ -79,8 +90,33 @@ align-items: center; flex-wrap: nowrap; justify-content: flex-end; + transition: opacity .15s; .outcome-icon { margin-right: .5rem; } + &.hidden { + opacity: .25; + &:hover { + opacity: 1; + } + } + .ant-btn { + .anticon { + opacity: .5; + } + &:hover { + .anticon { + opacity: 1; + } + } + } + .ant-btn-text:hover { + background-color: rgba(0,0,0,.1) + } + @media (prefers-color-scheme: dark) { + .ant-btn-text:hover { + background-color: rgba(255,255,255,.3) + } + } } diff --git a/web/styles/globals.scss b/web/styles/globals.scss index 49e7e41d8..d0f2d8d9c 100644 --- a/web/styles/globals.scss +++ b/web/styles/globals.scss @@ -34,6 +34,10 @@ pre { .ant-card { border-radius: .5em; } +.ant-btn { + transition-duration: .15s; + transition-delay: 0s; +} @media (prefers-color-scheme: dark) { @import "~antd/dist/antd.dark";