rmeove switches;update styles;
This commit is contained in:
@@ -1,16 +1,14 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Table, Typography, Tooltip, Switch, Button } from "antd";
|
import { Table, Typography, Tooltip, Button } from "antd";
|
||||||
import { CheckCircleFilled, ExclamationCircleFilled } from "@ant-design/icons";
|
import { CheckCircleFilled, ExclamationCircleFilled, StopOutlined } from "@ant-design/icons";
|
||||||
|
import classNames from 'classnames';
|
||||||
import { RowSelectionType } from "antd/es/table/interface";
|
import { RowSelectionType } from "antd/es/table/interface";
|
||||||
import { ColumnsType } from 'antd/es/table';
|
import { ColumnsType } from 'antd/es/table';
|
||||||
import format from 'date-fns/format'
|
import format from 'date-fns/format'
|
||||||
|
|
||||||
import MessageVisiblityToggle from './components/message-visiblity-toggle';
|
|
||||||
|
|
||||||
import { CHAT_HISTORY, fetchData, UPDATE_CHAT_MESSGAE_VIZ } from "../utils/apis";
|
import { CHAT_HISTORY, fetchData, UPDATE_CHAT_MESSGAE_VIZ } from "../utils/apis";
|
||||||
import { MessageType } from '../types/chat';
|
import { MessageType } from '../types/chat';
|
||||||
|
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
function createUserNameFilters(messages: MessageType[]) {
|
function createUserNameFilters(messages: MessageType[]) {
|
||||||
@@ -41,9 +39,9 @@ export const OUTCOME_TIMEOUT = 3000;
|
|||||||
export default function Chat() {
|
export default function Chat() {
|
||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
const [selectedRowKeys, setSelectedRows] = useState([]);
|
const [selectedRowKeys, setSelectedRows] = useState([]);
|
||||||
const [bulkVisibility, setBulkVisibility] = useState(false);
|
|
||||||
const [bulkProcessing, setBulkProcessing] = useState(false);
|
const [bulkProcessing, setBulkProcessing] = useState(false);
|
||||||
const [bulkOutcome, setBulkOutcome] = useState(null);
|
const [bulkOutcome, setBulkOutcome] = useState(null);
|
||||||
|
const [bulkAction, setBulkAction] = useState('');
|
||||||
let outcomeTimeout = null;
|
let outcomeTimeout = null;
|
||||||
|
|
||||||
const getInfo = async () => {
|
const getInfo = async () => {
|
||||||
@@ -55,12 +53,6 @@ export default function Chat() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMessage = message => {
|
|
||||||
const messageIndex = messages.findIndex(m => m.id === message.id);
|
|
||||||
messages.splice(messageIndex, 1, message)
|
|
||||||
setMessages([...messages]);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getInfo();
|
getInfo();
|
||||||
return () => {
|
return () => {
|
||||||
@@ -77,13 +69,14 @@ export default function Chat() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBulkToggle = checked => {
|
|
||||||
setBulkVisibility(checked);
|
|
||||||
};
|
|
||||||
const resetBulkOutcome = () => {
|
const resetBulkOutcome = () => {
|
||||||
outcomeTimeout = setTimeout(() => { setBulkOutcome(null)}, OUTCOME_TIMEOUT);
|
outcomeTimeout = setTimeout(() => {
|
||||||
|
setBulkOutcome(null);
|
||||||
|
setBulkAction('');
|
||||||
|
}, OUTCOME_TIMEOUT);
|
||||||
};
|
};
|
||||||
const handleSubmitBulk = async () => {
|
const handleSubmitBulk = async (bulkVisibility) => {
|
||||||
setBulkProcessing(true);
|
setBulkProcessing(true);
|
||||||
const result = await fetchData(UPDATE_CHAT_MESSGAE_VIZ, {
|
const result = await fetchData(UPDATE_CHAT_MESSGAE_VIZ, {
|
||||||
auth: true,
|
auth: true,
|
||||||
@@ -113,9 +106,15 @@ export default function Chat() {
|
|||||||
resetBulkOutcome();
|
resetBulkOutcome();
|
||||||
}
|
}
|
||||||
setBulkProcessing(false);
|
setBulkProcessing(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const handleSubmitBulkShow = () => {
|
||||||
|
setBulkAction('show');
|
||||||
|
handleSubmitBulk(true);
|
||||||
|
}
|
||||||
|
const handleSubmitBulkHide = () => {
|
||||||
|
setBulkAction('hide');
|
||||||
|
handleSubmitBulk(false);
|
||||||
|
}
|
||||||
|
|
||||||
const chatColumns: ColumnsType<MessageType> = [
|
const chatColumns: ColumnsType<MessageType> = [
|
||||||
{
|
{
|
||||||
@@ -129,7 +128,7 @@ export default function Chat() {
|
|||||||
return format(dateObject, 'PP pp');
|
return format(dateObject, 'PP pp');
|
||||||
},
|
},
|
||||||
sorter: (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),
|
sorter: (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),
|
||||||
width: 80,
|
width: 90,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'User',
|
title: 'User',
|
||||||
@@ -146,57 +145,61 @@ export default function Chat() {
|
|||||||
{author}
|
{author}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
),
|
),
|
||||||
width: 80,
|
width: 110,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Message',
|
title: 'Message',
|
||||||
dataIndex: 'body',
|
dataIndex: 'body',
|
||||||
key: 'body',
|
key: 'body',
|
||||||
className: 'message-col',
|
className: 'message-col',
|
||||||
width: 230,
|
width: 320,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Show / Hide',
|
title: '',
|
||||||
dataIndex: 'visible',
|
dataIndex: 'visible',
|
||||||
key: 'visible',
|
key: 'visible',
|
||||||
filters: [{ text: 'visible', value: true }, { text: 'hidden', value: false }],
|
className: 'toggle-col',
|
||||||
|
filters: [{ text: 'Visible messages', value: true }, { text: 'Hidden messages', value: false }],
|
||||||
onFilter: (value, record) => record.visible === value,
|
onFilter: (value, record) => record.visible === value,
|
||||||
render: (visible, record) => (
|
render: visible => visible ? null : <StopOutlined />,
|
||||||
<MessageVisiblityToggle
|
width: 30,
|
||||||
isVisible={visible}
|
|
||||||
message={record}
|
|
||||||
setMessage={updateMessage}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
width: 60,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const bulkDivClasses = classNames({
|
||||||
|
'bulk-editor': true,
|
||||||
|
active: selectedRowKeys.length,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="chat-messages">
|
<div className="chat-messages">
|
||||||
<Title level={2}>Chat Messages</Title>
|
<Title level={2}>Chat Messages</Title>
|
||||||
<div className="bulk-editor">
|
<div className={bulkDivClasses}>
|
||||||
<span className="label">Check multiple messages to change their visibility to: </span>
|
<span className="label">Check multiple messages to change their visibility to: </span>
|
||||||
|
|
||||||
<Switch
|
|
||||||
className="toggler"
|
|
||||||
disabled={!selectedRowKeys.length}
|
|
||||||
checkedChildren="show"
|
|
||||||
unCheckedChildren="hide"
|
|
||||||
onChange={handleBulkToggle}
|
|
||||||
checked={bulkVisibility}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
loading={bulkProcessing}
|
shape="round"
|
||||||
disabled={!selectedRowKeys.length}
|
className="button"
|
||||||
icon={bulkOutcome}
|
loading={bulkAction === 'show' && bulkProcessing}
|
||||||
onClick={handleSubmitBulk}
|
icon={bulkAction === 'show' && bulkOutcome}
|
||||||
|
disabled={!selectedRowKeys.length || (bulkAction && bulkAction !== 'show')}
|
||||||
|
onClick={handleSubmitBulkShow}
|
||||||
>
|
>
|
||||||
Go
|
Show
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
shape="round"
|
||||||
|
className="button"
|
||||||
|
loading={bulkAction === 'hide' && bulkProcessing}
|
||||||
|
icon={bulkAction === 'hide' && bulkOutcome}
|
||||||
|
disabled={!selectedRowKeys.length || (bulkAction && bulkAction !== 'hide')}
|
||||||
|
onClick={handleSubmitBulkHide}
|
||||||
|
>
|
||||||
|
Hide
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
// Wrapper for AntDesign Switch that makes an api call, then displays a confirmation icon upon
|
|
||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import { Switch } from "antd";
|
|
||||||
import { 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";
|
|
||||||
|
|
||||||
interface MessageToggleProps {
|
|
||||||
isVisible: boolean;
|
|
||||||
message: MessageType;
|
|
||||||
setMessage: (message: MessageType) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export default function MessageVisiblityToggle({ isVisible, message, setMessage }: MessageToggleProps) {
|
|
||||||
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 = <CheckCircleFilled style={{ color: 'transparent' }} />;
|
|
||||||
if (outcome) {
|
|
||||||
outcomeIcon = outcome > 0 ?
|
|
||||||
<CheckCircleFilled style={{ color: 'var(--ant-success)' }} /> :
|
|
||||||
<ExclamationCircleFilled style={{ color: 'var(--ant-warning)' }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="toggle-switch">
|
|
||||||
<span className="outcome-icon">{outcomeIcon}</span>
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
onChange={updateChatMessage}
|
|
||||||
checked={isVisible}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,12 @@
|
|||||||
.ant-table-tbody > tr > td {
|
.ant-table-tbody > tr > td {
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
|
.ant-table-row.hidden {
|
||||||
|
.ant-table-cell {
|
||||||
|
color: #444450;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
.ant-table-cell {
|
.ant-table-cell {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
||||||
@@ -13,6 +19,11 @@
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
&.toggle-col {
|
||||||
|
label {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk-editor {
|
.bulk-editor {
|
||||||
@@ -23,14 +34,23 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
.label {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-size: .75rem;
|
font-size: .75rem;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
margin-right: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggler {
|
button {
|
||||||
margin: 0 1rem 0 .5rem;
|
margin: 0 .2rem;
|
||||||
|
font-size: .75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user