React players page and fix constant rerender

This commit is contained in:
Aurora Lahtela 2022-06-05 22:09:46 +03:00
parent df0c0fa8a5
commit 56a3be1835
7 changed files with 122 additions and 19 deletions

View File

@ -25,6 +25,8 @@ import ServerSessions from "./views/server/ServerSessions";
import ServerPvpPve from "./views/server/ServerPvpPve";
import PlayerbaseOverview from "./views/server/PlayerbaseOverview";
import ServerPlayers from "./views/server/ServerPlayers";
import PlayersPage from "./views/layout/PlayersPage";
import AllPlayers from "./views/players/AllPlayers";
const OverviewRedirect = () => {
return (<Navigate to={"overview"} replace={true}/>)
@ -65,6 +67,10 @@ function App() {
icon: faMapSigns
}}/>}/>
</Route>
<Route path="/players" element={<PlayersPage/>}>
<Route path="" element={<AllPlayers/>}/>
<Route path="*" element={<AllPlayers/>}/>
</Route>
<Route path="/server/:identifier" element={<ServerPage/>}>
<Route path="" element={<OverviewRedirect/>}/>
<Route path="overview" element={<ServerOverview/>}/>

View File

@ -19,7 +19,7 @@ const PlayerListCard = ({data}) => {
responsive: true,
deferRender: true,
columns: data.columns,
data: data?.data,
data: data.data,
order: [[5, "desc"]]
});
}, [data])

View File

@ -19,8 +19,8 @@ const Logo = () => (
</a>
)
const Divider = () => (
<hr className="sidebar-divider my-0"/>
const Divider = ({showMargin}) => (
<hr className={"sidebar-divider" + (showMargin ? '' : " my-0")}/>
)
const InnerItem = ({href, icon, name, nameShort}) => {
@ -180,7 +180,7 @@ const renderItem = (item, i, openCollapse, setOpenCollapse, t) => {
setOpen={() => setOpenCollapse(i)}/>
}
if (item.href) {
if (item.href !== undefined) {
return <Item key={i}
active={false}
href={item.href}
@ -217,16 +217,18 @@ const Sidebar = ({items, showBackButton}) => {
const collapseSidebar = () => setSidebarExpanded(windowWidth > 1350);
useEffect(collapseSidebar, [windowWidth, currentTab, setSidebarExpanded]);
if (!items.length) return <></>
return (
<>
{sidebarExpanded &&
<ul className={"navbar-nav sidebar sidebar-dark accordion bg-" + color} id="accordionSidebar">
<Logo/>
<Divider/>
{showBackButton ? <>
{showBackButton && <>
<Item active={false} href="/" icon={faArrowLeft} name={t('html.label.toMainPage')}/>
<Divider/>
</> : ''}
<Divider showMargin={!items[0].contents && items[0].href === undefined}/>
</>}
{items.map((item, i) => renderItem(item, i, openCollapse, toggleCollapse, t))}
<Divider/>
<FooterButtons/>

View File

@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react';
import React, {useEffect, useRef} from 'react';
import DataTable from 'datatables.net'
import 'datatables.net-bs5'
import 'datatables.net-responsive-bs5'
@ -6,24 +6,22 @@ import 'datatables.net-bs5/css/dataTables.bootstrap5.min.css';
import 'datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css';
const DataTablesTable = ({id, options}) => {
const [dataTable, setDataTable] = useState(null);
const dataTableRef = useRef(null);
useEffect(() => {
if (dataTable) {
dataTable.destroy();
setDataTable(null);
const idSelector = `#${id}`;
if (dataTableRef.current && DataTable.isDataTable(idSelector)) {
dataTableRef.current.destroy();
}
const createdDataTable = new DataTable(`#${id}`, options);
setDataTable(createdDataTable);
dataTableRef.current = new DataTable(idSelector, options);
return () => {
if (dataTable) {
dataTable.clear();
dataTable.destroy();
if (dataTableRef.current) {
dataTableRef.current.destroy();
}
};
}, [id, options, dataTable]);
}, [id, options, dataTableRef]);
return (
<table id={id} className="table table-bordered table-striped" style={{width: "100%"}}/>

View File

@ -44,7 +44,7 @@ export const fetchKills = async (identifier) => {
export const fetchPlayers = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/players?server=${identifier}&timestamp=${timestamp}`;
const url = identifier ? `/v1/players?server=${identifier}&timestamp=${timestamp}` : `/v1/players?timestamp=${timestamp}`;
return doGetRequest(url);
}

View File

@ -0,0 +1,74 @@
import React, {useEffect, useState} from "react";
import {useTranslation} from "react-i18next";
import {Outlet} from "react-router-dom";
import {useNavigation} from "../../hooks/navigationHook";
import {faSearch} from "@fortawesome/free-solid-svg-icons";
import {useAuth} from "../../hooks/authenticationHook";
import {NightModeCss} from "../../hooks/themeHook";
import Sidebar from "../../components/navigation/Sidebar";
import Header from "../../components/navigation/Header";
import ErrorView from "../ErrorView";
import ColorSelectorModal from "../../components/modal/ColorSelectorModal";
import {useMetadata} from "../../hooks/metadataHook";
const PlayersPage = () => {
const {t, i18n} = useTranslation();
const {isProxy, serverName} = useMetadata();
const [error] = useState(undefined);
const [sidebarItems, setSidebarItems] = useState([]);
const {currentTab} = useNavigation();
useEffect(() => {
const items = [
{name: 'html.label.links'},
{name: 'html.label.query', icon: faSearch, href: "/query"},
]
setSidebarItems(items);
window.document.title = `Plan | Player list`;
}, [t, i18n])
const {authRequired, user} = useAuth();
const showBackButton = isProxy && (!authRequired || user.permissions.filter(perm => perm !== 'page.network').length);
if (error) {
return <>
<NightModeCss/>
<Sidebar items={[]} showBackButton={true}/>
<div className="d-flex flex-column" id="content-wrapper">
<Header page={error.title ? error.title : 'Unexpected error occurred'}/>
<div id="content" style={{display: 'flex'}}>
<main className="container-fluid mt-4">
<ErrorView error={error}/>
</main>
<aside>
<ColorSelectorModal/>
</aside>
</div>
</div>
</>
}
const displayedServerName = !isProxy && serverName && serverName.startsWith('Server') ? "Plan" : serverName;
return (
<>
<NightModeCss/>
<Sidebar items={sidebarItems} showBackButton={true}/>
<div className="d-flex flex-column" id="content-wrapper">
<Header page={displayedServerName} tab={currentTab}/>
<div id="content" style={{display: 'flex'}}>
<main className="container-fluid mt-4">
<Outlet context={{}}/>
</main>
<aside>
<ColorSelectorModal/>
</aside>
</div>
</div>
</>
)
}
export default PlayersPage;

View File

@ -0,0 +1,23 @@
import React from 'react';
import {useDataRequest} from "../../hooks/dataFetchHook";
import {fetchPlayers} from "../../service/serverService";
import ErrorView from "../ErrorView";
import {Col, Row} from "react-bootstrap-v5";
import PlayerListCard from "../../components/cards/common/PlayerListCard";
const AllPlayers = () => {
const {data, loadingError} = useDataRequest(fetchPlayers, [null]);
if (!data) return <></>;
if (loadingError) return <ErrorView error={loadingError}/>
return (
<Row>
<Col md={12}>
<PlayerListCard data={data}/>
</Col>
</Row>
)
};
export default AllPlayers