From 05b9634180342a03fe96c008e1814e437d86a6cf Mon Sep 17 00:00:00 2001 From: gingervitis Date: Tue, 22 Dec 2020 22:05:17 -0800 Subject: [PATCH] add nav item and page for chat; set up data table of messages --- web/pages/chat.tsx | 134 +++++++++++++++++++++++++++ web/pages/components/main-layout.tsx | 3 + web/utils/apis.ts | 21 ++++- 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 web/pages/chat.tsx diff --git a/web/pages/chat.tsx b/web/pages/chat.tsx new file mode 100644 index 000000000..f5b90d12c --- /dev/null +++ b/web/pages/chat.tsx @@ -0,0 +1,134 @@ +import React, { useState, useEffect } from "react"; +import { Table, Typography } from "antd"; +import { ColumnsType } from 'antd/es/table'; +import format from 'date-fns/format' + +import { + CHAT_HISTORY, + fetchDataFromMain, +} from "../utils/apis"; + +const { Title } = Typography; + +interface Message { + key: string; + author: string; + body: string; + id: string; + name: string; + timestamp: string; + type: string; + visible: boolean; +} + + +function createUserNameFilters(messages) { + const filtered = messages.reduce((acc, curItem) => { + const curAuthor = curItem.author; + if (!acc.some(item => item.text === curAuthor)) { + acc.push({ text: curAuthor, value: curAuthor }); + } + return acc; + }, []); + + // sort by name + return filtered.sort((a, b) => { + const nameA = a.text.toUpperCase(); // ignore upper and lowercase + const nameB = b.text.toUpperCase(); // ignore upper and lowercase + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + // names must be equal + return 0; + }); +} + +export default function Chat() { + const [messages, setMessages] = useState([]); + + const getInfo = async () => { + try { + const result = await fetchDataFromMain(CHAT_HISTORY); + setMessages(result); + } catch (error) { + console.log("==== error", error); + } + }; + + useEffect(() => { + getInfo(); + }, []); + + + const nameFilters = createUserNameFilters(messages); + const rowSelection = { + onChange: (selectedRowKeys, selectedRows) => { + console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); + }, + getCheckboxProps: record => ({ + disabled: record.name === 'Disabled User', // Column configuration not to be checked + name: record.name, + }), + }; + + const chatColumns: ColumnsType = [ + { + title: 'Time', + dataIndex: 'timestamp', + key: 'timestamp', + defaultSortOrder: 'descend', + render: (timestamp) => { + const dateObject = new Date(timestamp); + return format(dateObject, 'P pp'); + }, + sorter: (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(), + }, + { + title: 'User', + dataIndex: 'author', + key: 'author', + className: 'name-col', + filters: nameFilters, + onFilter: (value, record) => record.name.indexOf(value) === 0, + sorter: (a, b) => a.name.toUppercase() - b.name.toUppercase(), + sortDirections: ['ascend', 'descend'], + }, + { + title: 'Message', + dataIndex: 'body', + key: 'body', + className: 'message-col', + }, + { + title: 'Show/Hide', + dataIndex: 'visible', + key: 'visible', + }, + ]; + + + return ( +
+ Chat Messages + !record.visible ? 'hidden' : ''} + dataSource={messages} + columns={chatColumns} + rowKey={(row) => row.id} + + rowSelection={{ + type: "checkbox", + ...rowSelection, + }} + + /> + ) +} + + diff --git a/web/pages/components/main-layout.tsx b/web/pages/components/main-layout.tsx index 6d2f9fcaf..eea871a0a 100644 --- a/web/pages/components/main-layout.tsx +++ b/web/pages/components/main-layout.tsx @@ -128,6 +128,9 @@ export default function MainLayout(props) { icon={} title="Utilities" > + + Chat Moderation + Hardware diff --git a/web/utils/apis.ts b/web/utils/apis.ts index a480a5493..736b41463 100644 --- a/web/utils/apis.ts +++ b/web/utils/apis.ts @@ -34,10 +34,14 @@ export const LOGS_ALL = `${API_LOCATION}logs`; // Get warnings + errors export const LOGS_WARN = `${API_LOCATION}logs/warnings`; +// Chat history +export const CHAT_HISTORY = `${NEXT_PUBLIC_API_HOST}api/chat`; + + const GITHUB_RELEASE_URL = "https://api.github.com/repos/owncast/owncast/releases/latest"; export async function fetchData(url) { - let options: RequestInit = {}; + const options: RequestInit = {}; if (ADMIN_USERNAME && ADMIN_STREAMKEY) { const encoded = btoa(`${ADMIN_USERNAME}:${ADMIN_STREAMKEY}`); @@ -62,6 +66,21 @@ export async function fetchData(url) { return {}; } +export async function fetchDataFromMain(url) { + try { + const response = await fetch(url); + if (!response.ok) { + const message = `An error has occured: ${response.status}`; + throw new Error(message); + } + const json = await response.json(); + return json; + } catch (error) { + console.log(error) + } + return {}; +} + export async function getGithubRelease() { try { const response = await fetch(GITHUB_RELEASE_URL);