mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-02-09 08:51:44 +01:00
React players page and fix constant rerender
This commit is contained in:
parent
df0c0fa8a5
commit
56a3be1835
@ -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/>}/>
|
||||
|
@ -19,7 +19,7 @@ const PlayerListCard = ({data}) => {
|
||||
responsive: true,
|
||||
deferRender: true,
|
||||
columns: data.columns,
|
||||
data: data?.data,
|
||||
data: data.data,
|
||||
order: [[5, "desc"]]
|
||||
});
|
||||
}, [data])
|
||||
|
@ -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/>
|
||||
|
@ -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%"}}/>
|
||||
|
@ -44,7 +44,7 @@ export const fetchKills = async (identifier) => {
|
||||
|
||||
export const fetchPlayers = async (identifier) => {
|
||||
const timestamp = Date.now();
|
||||
const url = `/v1/players?server=${identifier}×tamp=${timestamp}`;
|
||||
const url = identifier ? `/v1/players?server=${identifier}×tamp=${timestamp}` : `/v1/players?timestamp=${timestamp}`;
|
||||
return doGetRequest(url);
|
||||
}
|
||||
|
||||
|
74
Plan/react/dashboard/src/views/layout/PlayersPage.js
Normal file
74
Plan/react/dashboard/src/views/layout/PlayersPage.js
Normal 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;
|
23
Plan/react/dashboard/src/views/players/AllPlayers.js
Normal file
23
Plan/react/dashboard/src/views/players/AllPlayers.js
Normal 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
|
Loading…
Reference in New Issue
Block a user