Implemented some more structure for server page

This commit is contained in:
Aurora Lahtela 2022-05-21 20:25:49 +03:00
parent e77a9ee8b5
commit 45baebfb01
19 changed files with 346 additions and 103 deletions

View File

@ -21,6 +21,7 @@ import ServerPage from "./views/ServerPage";
import ServerOverview from "./views/ServerOverview";
import MainPageRedirect from "./components/navigation/MainPageRedirect";
import ServerOnlineActivity from "./views/ServerOnlineActivity";
import ServerSessions from "./views/ServerSessions";
const OverviewRedirect = () => {
return (<Navigate to={"overview"} replace={true}/>)
@ -65,7 +66,7 @@ function App() {
<Route path="" element={<OverviewRedirect/>}/>
<Route path="overview" element={<ServerOverview/>}/>
<Route path="online-activity" element={<ServerOnlineActivity/>}/>
<Route path="sessions" element={<></>}/>
<Route path="sessions" element={<ServerSessions/>}/>
<Route path="pvppve" element={<></>}/>
<Route path="playerbase" element={<></>}/>
<Route path="players" element={<></>}/>

View File

@ -0,0 +1,23 @@
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faLifeRing} from "@fortawesome/free-solid-svg-icons";
import React from "react";
const InsightsFor30DaysCard = ({children}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black">
<Fa icon={faLifeRing} className="col-red"/> {t('html.label.insights30days')}
</h6>
</Card.Header>
<Card.Body>
{children}
</Card.Body>
</Card>
)
}
export default InsightsFor30DaysCard;

View File

@ -0,0 +1,28 @@
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faCalendar, faHandPointer} from "@fortawesome/free-regular-svg-icons";
import Scrollable from "../../Scrollable";
import SessionAccordion from "../../accordion/SessionAccordion";
import React from "react";
const RecentSessionsCard = ({sessions}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black" style={{width: '100%'}}>
<Fa icon={faCalendar} className="col-teal"/> {t('html.label.recentSessions')}
<span className="float-end">
<Fa icon={faHandPointer}/> <small>{t('html.text.clickToExpand')}</small>
</span>
</h6>
</Card.Header>
<Scrollable>
<SessionAccordion sessions={sessions}/>
</Scrollable>
</Card>
)
}
export default RecentSessionsCard;

View File

@ -0,0 +1,26 @@
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faClock} from "@fortawesome/free-regular-svg-icons";
import WorldPie from "../../graphs/WorldPie";
import React from "react";
const WorldPieCard = ({worldSeries, gmSeries}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black" style={{width: '100%'}}>
<Fa icon={faClock} className="col-teal"/> {t('html.label.worldPlaytime')}
</h6>
</Card.Header>
<WorldPie
id="world-pie"
worldSeries={worldSeries}
gmSeries={gmSeries}
/>
</Card>
)
}
export default WorldPieCard;

View File

@ -0,0 +1,10 @@
import React from "react";
import RecentSessionsCard from "../common/RecentSessionsCard";
const PlayerRecentSessionsCard = ({player}) => {
return (
<RecentSessionsCard sessions={player.sessions}/>
)
}
export default PlayerRecentSessionsCard;

View File

@ -0,0 +1,13 @@
import React from "react";
import WorldPieCard from "../common/WorldPieCard";
const PlayerWorldPieCard = ({player}) => {
return (
<WorldPieCard
worldSeries={player.world_pie_series}
gmSeries={player.gm_series}
/>
)
}
export default PlayerWorldPieCard;

View File

@ -0,0 +1,22 @@
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faCampground} from "@fortawesome/free-solid-svg-icons";
import React from "react";
import PvpPveAsNumbersTable from "../../table/PvpPveAsNumbersTable";
const PvpPveAsNumbersCard = ({player}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black">
<Fa icon={faCampground} className="col-red"/> {t('html.label.pvpPveAsNumbers')}
</h6>
</Card.Header>
<PvpPveAsNumbersTable killData={player.kill_data}/>
</Card>
)
}
export default PvpPveAsNumbersCard;

View File

@ -0,0 +1,22 @@
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faBookOpen} from "@fortawesome/free-solid-svg-icons";
import React from "react";
import OnlineActivityAsNumbersTable from "../../table/OnlineActivityAsNumbersTable";
const OnlineActivityAsNumbersCard = () => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black">
<Fa icon={faBookOpen} className="col-light-blue"/> {t('html.label.onlineActivityAsNumbers')}
</h6>
</Card.Header>
<OnlineActivityAsNumbersTable/>
</Card>
)
}
export default OnlineActivityAsNumbersCard;

View File

@ -0,0 +1,12 @@
import React from "react";
import InsightsFor30DaysCard from "../common/InsightsFor30DaysCard";
const OnlineActivityInsightsCard = () => {
return (
<InsightsFor30DaysCard>
TODO
</InsightsFor30DaysCard>
)
}
export default OnlineActivityInsightsCard;

View File

@ -0,0 +1,22 @@
import React from "react";
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../../hooks/dataFetchHook";
import {fetchSessions} from "../../../service/serverService";
import {ErrorViewBody} from "../../../views/ErrorView";
import RecentSessionsCard from "../common/RecentSessionsCard";
const ServerRecentSessionsCard = () => {
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchSessions, [identifier])
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!data) return <></>;
return (
<RecentSessionsCard sessions={data.sessions}/>
)
}
export default ServerRecentSessionsCard;

View File

@ -0,0 +1,25 @@
import React from "react";
import WorldPieCard from "../common/WorldPieCard";
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../../hooks/dataFetchHook";
import {fetchWorldPie} from "../../../service/serverService";
import {ErrorViewBody} from "../../../views/ErrorView";
const ServerWorldPieCard = () => {
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchWorldPie, [identifier]);
console.log(data);
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!data) return <></>;
return (
<WorldPieCard
worldSeries={data.world_series}
gmSeries={data.gm_series}
/>
)
}
export default ServerWorldPieCard;

View File

@ -0,0 +1,12 @@
import React from "react";
import InsightsFor30DaysCard from "../common/InsightsFor30DaysCard";
const SessionInsightsCard = () => {
return (
<InsightsFor30DaysCard>
TODO
</InsightsFor30DaysCard>
)
}
export default SessionInsightsCard;

View File

@ -0,0 +1,18 @@
import {useTranslation} from "react-i18next";
import AsNumbersTable, {TableRow} from "./AsNumbersTable";
import {faUsers} from "@fortawesome/free-solid-svg-icons";
import React from "react";
const OnlineActivityAsNumbersTable = () => {
const {t} = useTranslation();
return (
<AsNumbersTable
headers={[t('html.label.last30days'), t('html.label.last7days'), t('html.label.last24hours')]}
>
<TableRow icon={faUsers} color="light-blue" text={t('html.label.uniquePlayers')}
values={["TODO"]}/>
</AsNumbersTable>
)
}
export default OnlineActivityAsNumbersTable;

View File

@ -0,0 +1,44 @@
import {useTranslation} from "react-i18next";
import AsNumbersTable, {TableRow} from "./AsNumbersTable";
import {faCrosshairs, faSkull} from "@fortawesome/free-solid-svg-icons";
import React from "react";
const PvpPveAsNumbersTable = ({killData}) => {
const {t} = useTranslation();
return (
<AsNumbersTable
headers={[t('html.label.allTime'), t('html.label.last30days'), t('html.label.last7days')]}
>
<TableRow icon={faCrosshairs} color="red" text={t('html.label.kdr')} bold
values={[killData.player_kdr_total,
killData.player_kdr_30d,
killData.player_kdr_7d]}/>
<TableRow icon={faCrosshairs} color="red" text={t('html.label.playerKills')}
values={[killData.player_kills_total,
killData.player_kills_30d,
killData.player_kills_7d]}/>
<TableRow icon={faSkull} color="red" text={t('html.label.playerDeaths')}
values={[killData.player_deaths_total,
killData.player_deaths_30d,
killData.player_deaths_7d]}/>
<TableRow icon={faCrosshairs} color="green" text={t('html.label.mobKdr')} bold
values={[killData.mob_kdr_total,
killData.mob_kdr_30d,
killData.mob_kdr_7d]}/>
<TableRow icon={faCrosshairs} color="green" text={t('html.label.mobKills')}
values={[killData.mob_kills_total,
killData.mob_kills_30d,
killData.mob_kills_7d]}/>
<TableRow icon={faSkull} color="green" text={t('html.label.mobDeaths')}
values={[killData.mob_deaths_total,
killData.mob_deaths_30d,
killData.mob_deaths_7d]}/>
<TableRow icon={faSkull} color="black" text={t('html.label.deaths')}
values={[killData.deaths_total,
killData.deaths_30d,
killData.deaths_7d]}/>
</AsNumbersTable>
)
}
export default PvpPveAsNumbersTable;

View File

@ -6,6 +6,18 @@ export const fetchServerOverview = async (identifier) => {
return doGetRequest(url);
}
export const fetchOnlineActivityOverview = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/onlineOverview?server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchSessions = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/sessions?server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchPlayersOnlineGraph = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/graph?type=playersOnline&server=${identifier}&timestamp=${timestamp}`;
@ -34,4 +46,10 @@ export const fetchPunchCardGraph = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/graph?type=punchCard&server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchWorldPie = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/graph?type=worldPie&server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}

View File

@ -2,65 +2,12 @@ import React from "react";
import {Card, Col, Row} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faLifeRing} from "@fortawesome/free-regular-svg-icons";
import {faCampground, faCrosshairs, faKhanda, faSkull} from "@fortawesome/free-solid-svg-icons";
import AsNumbersTable, {TableRow} from "../components/table/AsNumbersTable";
import {faCrosshairs, faKhanda, faSkull} from "@fortawesome/free-solid-svg-icons";
import Datapoint from "../components/Datapoint";
import KillsTable from "../components/table/KillsTable";
import {usePlayer} from "./PlayerPage";
import {useTranslation} from "react-i18next";
const PvpPveAsNumbersTable = ({player}) => {
const {t} = useTranslation();
return (
<AsNumbersTable
headers={[t('html.label.allTime'), t('html.label.last30days'), t('html.label.last7days')]}
>
<TableRow icon={faCrosshairs} color="red" text={t('html.label.kdr')} bold
values={[player.kill_data.player_kdr_total,
player.kill_data.player_kdr_30d,
player.kill_data.player_kdr_7d]}/>
<TableRow icon={faCrosshairs} color="red" text={t('html.label.playerKills')}
values={[player.kill_data.player_kills_total,
player.kill_data.player_kills_30d,
player.kill_data.player_kills_7d]}/>
<TableRow icon={faSkull} color="red" text={t('html.label.playerDeaths')}
values={[player.kill_data.player_deaths_total,
player.kill_data.player_deaths_30d,
player.kill_data.player_deaths_7d]}/>
<TableRow icon={faCrosshairs} color="green" text={t('html.label.mobKdr')} bold
values={[player.kill_data.mob_kdr_total,
player.kill_data.mob_kdr_30d,
player.kill_data.mob_kdr_7d]}/>
<TableRow icon={faCrosshairs} color="green" text={t('html.label.mobKills')}
values={[player.kill_data.mob_kills_total,
player.kill_data.mob_kills_30d,
player.kill_data.mob_kills_7d]}/>
<TableRow icon={faSkull} color="green" text={t('html.label.mobDeaths')}
values={[player.kill_data.mob_deaths_total,
player.kill_data.mob_deaths_30d,
player.kill_data.mob_deaths_7d]}/>
<TableRow icon={faSkull} color="black" text={t('html.label.deaths')}
values={[player.kill_data.deaths_total,
player.kill_data.deaths_30d,
player.kill_data.deaths_7d]}/>
</AsNumbersTable>
)
}
const PvpPveNumbersCard = ({player}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black">
<Fa icon={faCampground} className="col-red"/> {t('html.label.pvpPveAsNumbers')}
</h6>
</Card.Header>
<PvpPveAsNumbersTable player={player}/>
</Card>
)
}
import PvpPveAsNumbersCard from "../components/cards/player/PvpPveAsNumbersCard";
const InsightsCard = ({player}) => {
const {t} = useTranslation();
@ -117,7 +64,7 @@ const PlayerPvpPve = () => {
<section className="player_pvp_pve">
<Row>
<Col lg={8}>
<PvpPveNumbersCard player={player}/>
<PvpPveAsNumbersCard player={player}/>
</Col>
<Col lg={4}>
<InsightsCard player={player}/>

View File

@ -1,13 +1,12 @@
import React from "react";
import {Card, Col, Row} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faCalendar, faCalendarAlt, faClock, faHandPointer} from "@fortawesome/free-regular-svg-icons";
import {faCalendarAlt} from "@fortawesome/free-regular-svg-icons";
import PlayerSessionCalendar from "../components/calendar/PlayerSessionCalendar";
import Scrollable from "../components/Scrollable";
import SessionAccordion from "../components/accordion/SessionAccordion";
import WorldPie from "../components/graphs/WorldPie";
import {usePlayer} from "./PlayerPage";
import {useTranslation} from "react-i18next";
import PlayerWorldPieCard from "../components/cards/player/PlayerWorldPieCard";
import PlayerRecentSessionsCard from "../components/cards/player/PlayerRecentSessionsCard";
const SessionCalendarCard = ({player}) => {
const {t} = useTranslation();
@ -23,43 +22,6 @@ const SessionCalendarCard = ({player}) => {
)
}
const RecentSessionsCard = ({player}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black" style={{width: '100%'}}>
<Fa icon={faCalendar} className="col-teal"/> {t('html.label.recentSessions')}
<span className="float-end">
<Fa icon={faHandPointer}/> <small>{t('html.text.clickToExpand')}</small>
</span>
</h6>
</Card.Header>
<Scrollable>
<SessionAccordion sessions={player.sessions}/>
</Scrollable>
</Card>
)
}
const WorldPieCard = ({player}) => {
const {t} = useTranslation();
return (
<Card>
<Card.Header>
<h6 className="col-black" style={{width: '100%'}}>
<Fa icon={faClock} className="col-teal"/> {t('html.label.worldPlaytime')}
</h6>
</Card.Header>
<WorldPie
id="world-pie"
worldSeries={player.world_pie_series}
gmSeries={player.gm_series}
/>
</Card>
)
}
const PlayerSessions = () => {
const {player} = usePlayer();
return (
@ -67,14 +29,14 @@ const PlayerSessions = () => {
<Row>
<Col lg={8}>
<SessionCalendarCard player={player}/>
<RecentSessionsCard player={player}/>
<PlayerRecentSessionsCard player={player}/>
</Col>
<Col lg={4}>
<WorldPieCard player={player}/>
<PlayerWorldPieCard player={player}/>
</Col>
</Row>
</section>
)
}
export default PlayerSessions
export default PlayerSessions;

View File

@ -1,8 +1,21 @@
import React from "react";
import {Col, Row} from "react-bootstrap-v5";
import OnlineActivityGraphsCard from "../components/cards/server/OnlineActivityGraphsCard";
import OnlineActivityAsNumbersCard from "../components/cards/server/OnlineActivityAsNumbersCard";
import {useParams} from "react-router-dom";
import {useDataRequest} from "../hooks/dataFetchHook";
import {fetchOnlineActivityOverview} from "../service/serverService";
import {ErrorViewBody} from "./ErrorView";
import OnlineActivityInsightsCard from "../components/cards/server/OnlineActivityInsightsCard";
const ServerOnlineActivity = () => {
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchOnlineActivityOverview, [identifier])
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!data) return <></>;
return (
<section className="server_online_activity_overview">
<Row>
@ -11,9 +24,11 @@ const ServerOnlineActivity = () => {
</Col>
</Row>
<Row>
<Col lg={4}>
</Col>
<Col lg={8}>
<OnlineActivityAsNumbersCard data={data}/>
</Col>
<Col lg={4}>
<OnlineActivityInsightsCard data={data}/>
</Col>
</Row>
</section>

View File

@ -0,0 +1,23 @@
import {Col, Row} from "react-bootstrap-v5";
import React from "react";
import ServerWorldPieCard from "../components/cards/server/ServerWorldPieCard";
import ServerRecentSessionsCard from "../components/cards/server/ServerRecentSessionsCard";
import SessionInsightsCard from "../components/cards/server/SessionInsightsCard";
const ServerSessions = () => {
return (
<section className="server_sessions">
<Row>
<Col lg={8}>
<ServerRecentSessionsCard/>
</Col>
<Col lg={4}>
<ServerWorldPieCard/>
<SessionInsightsCard/>
</Col>
</Row>
</section>
)
}
export default ServerSessions;