Refactor PlayerListCard to also have PlayerTable
This commit is contained in:
parent
3ad5d577d4
commit
ff7e7791f3
|
@ -1,157 +1,24 @@
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {Card} from "react-bootstrap";
|
import {Card} from "react-bootstrap";
|
||||||
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
import React, {useCallback, useEffect, useState} from "react";
|
import React from "react";
|
||||||
import {faCheck, faGlobe, faSignal, faUser, faUserPlus, faUsers} from "@fortawesome/free-solid-svg-icons";
|
import {faUsers} from "@fortawesome/free-solid-svg-icons";
|
||||||
import DataTablesTable from "../../table/DataTablesTable";
|
import PlayerTable from "../../table/PlayerTable.jsx";
|
||||||
import {CardLoader} from "../../navigation/Loader";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import {faCalendarCheck, faCalendarPlus, faClock} from "@fortawesome/free-regular-svg-icons";
|
|
||||||
import {formatDate, useDatePreferences} from "../../text/FormattedDate";
|
|
||||||
import {useTimePreferences} from "../../text/FormattedTime";
|
|
||||||
import ExtensionIcon from "../../extensions/ExtensionIcon";
|
|
||||||
import {ExtensionValueTableCell} from "../../extensions/ExtensionCard";
|
|
||||||
import {usePreferences} from "../../../hooks/preferencesHook";
|
|
||||||
import {formatDecimals} from "../../../util/formatters";
|
|
||||||
import {formatTimeAmount} from "../../../util/format/TimeAmountFormat.js";
|
|
||||||
|
|
||||||
const getActivityGroup = value => {
|
|
||||||
const VERY_ACTIVE = 3.75;
|
|
||||||
const ACTIVE = 3.0;
|
|
||||||
const REGULAR = 2.0;
|
|
||||||
const IRREGULAR = 1.0;
|
|
||||||
if (value >= VERY_ACTIVE) {
|
|
||||||
return "html.label.veryActive"
|
|
||||||
} else if (value >= ACTIVE) {
|
|
||||||
return "html.label.active"
|
|
||||||
} else if (value >= REGULAR) {
|
|
||||||
return "html.label.indexRegular"
|
|
||||||
} else if (value >= IRREGULAR) {
|
|
||||||
return "html.label.irregular"
|
|
||||||
} else {
|
|
||||||
return "html.label.indexInactive"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const PlayerListCard = ({data, title, justList, orderBy}) => {
|
const PlayerListCard = ({data, title, orderBy}) => {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const {preferencesLoaded, decimalFormat} = usePreferences();
|
|
||||||
|
|
||||||
const [options, setOptions] = useState(undefined);
|
|
||||||
|
|
||||||
const timePreferences = useTimePreferences();
|
|
||||||
const datePreferences = useDatePreferences();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
const columns = [{
|
|
||||||
title: <><Fa icon={faUser}/> {t('html.label.name')}</>,
|
|
||||||
data: {_: "name", display: "link"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faCheck}/> {t('html.label.activityIndex')}</>,
|
|
||||||
data: {_: "activityIndex", display: "activityIndexAndGroup"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faClock}/> {t('html.label.activePlaytime')}</>,
|
|
||||||
data: {_: "activePlaytime", display: "activePlaytimeFormatted"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faCalendarPlus}/> {t('html.label.sessions')}</>,
|
|
||||||
data: "sessions"
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faUserPlus}/> {t('html.label.registered')}</>,
|
|
||||||
data: {_: "registered", display: "registeredFormatted"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faCalendarCheck}/> {t('html.label.lastSeen')}</>,
|
|
||||||
data: {_: "lastSeen", display: "lastSeenFormatted"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faGlobe}/> {t('html.label.country')}</>,
|
|
||||||
data: "country"
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faSignal}/> {t('html.label.averagePing')}</>,
|
|
||||||
data: {_: "pingAverage", display: "pingAverageFormatted"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faSignal}/> {t('html.label.bestPing')}</>,
|
|
||||||
data: {_: "pingMin", display: "pingMinFormatted"}
|
|
||||||
}, {
|
|
||||||
title: <><Fa icon={faSignal}/> {t('html.label.worstPing')}</>,
|
|
||||||
data: {_: "pingMax", display: "pingMaxFormatted"}
|
|
||||||
}];
|
|
||||||
|
|
||||||
columns.push(...data.extensionDescriptors.map(descriptor => {
|
|
||||||
return {
|
|
||||||
title: <><ExtensionIcon icon={descriptor.icon}/> {descriptor.text}</>,
|
|
||||||
data: {_: descriptor.name + "Value", display: descriptor.name}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const formatDateEasy = date => {
|
|
||||||
return formatDate(date, datePreferences.offset, datePreferences.pattern, false, datePreferences.recentDaysPattern, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = data.players.map(player => {
|
|
||||||
const row = {
|
|
||||||
name: player.playerName,
|
|
||||||
uuid: player.playerUUID,
|
|
||||||
link: <Link to={"/player/" + player.playerUUID}>{player.playerName}</Link>,
|
|
||||||
activityIndex: player.activityIndex,
|
|
||||||
activityGroup: t(getActivityGroup(player.activityIndex)),
|
|
||||||
activityIndexAndGroup: formatDecimals(player.activityIndex, decimalFormat) + " (" + t(getActivityGroup(player.activityIndex)) + ")",
|
|
||||||
activePlaytime: player.playtimeActive,
|
|
||||||
activePlaytimeFormatted: formatTimeAmount(timePreferences, player.playtimeActive),
|
|
||||||
sessions: player.sessionCount,
|
|
||||||
registered: player.registered,
|
|
||||||
registeredFormatted: formatDateEasy(player.registered),
|
|
||||||
lastSeen: player.lastSeen,
|
|
||||||
lastSeenFormatted: formatDateEasy(player.lastSeen),
|
|
||||||
country: player.country,
|
|
||||||
pingAverage: player.pingAverage,
|
|
||||||
pingAverageFormatted: formatDecimals(player.pingAverage, decimalFormat) + "ms",
|
|
||||||
pingMax: player.pingMax,
|
|
||||||
pingMaxFormatted: player.pingMax + "ms",
|
|
||||||
pingMin: player.pingMin,
|
|
||||||
pingMinFormatted: player.pingMin + "ms"
|
|
||||||
};
|
|
||||||
data.extensionDescriptors.forEach(descriptor => {
|
|
||||||
row[descriptor.name] = <ExtensionValueTableCell data={player.extensionValues[descriptor.name]}/>;
|
|
||||||
row[descriptor.name + "Value"] = JSON.stringify(player.extensionValues[descriptor.name]?.value);
|
|
||||||
})
|
|
||||||
return row;
|
|
||||||
});
|
|
||||||
|
|
||||||
setOptions({
|
|
||||||
responsive: true,
|
|
||||||
deferRender: true,
|
|
||||||
columns: columns,
|
|
||||||
data: rows,
|
|
||||||
order: [[orderBy !== undefined ? orderBy : 5, "desc"]]
|
|
||||||
});
|
|
||||||
}, [data, orderBy, t, decimalFormat]);
|
|
||||||
|
|
||||||
const rowKeyFunction = useCallback((row, column) => {
|
|
||||||
return row.uuid + "-" + (column ? JSON.stringify(column.data) : '');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!preferencesLoaded) return <></>;
|
|
||||||
if (!options) return <CardLoader/>;
|
|
||||||
|
|
||||||
if (justList) {
|
|
||||||
return (
|
|
||||||
<DataTablesTable id={"players-table"} rowKeyFunction={rowKeyFunction} options={options}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
<h6 className="col-black">
|
<h6 className="col-black">
|
||||||
<Fa icon={faUsers} className="col-black"/> {title ? title : t('html.label.playerList')}
|
<Fa icon={faUsers} className="col-black"/> {title || t('html.label.playerList')}
|
||||||
</h6>
|
</h6>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<DataTablesTable id={"players-table"}
|
<PlayerTable data={data} orderBy={orderBy}/>
|
||||||
rowKeyFunction={rowKeyFunction}
|
|
||||||
options={options}/>
|
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
};
|
||||||
|
|
||||||
export default PlayerListCard;
|
export default PlayerListCard;
|
|
@ -3,11 +3,11 @@ import {useTranslation} from "react-i18next";
|
||||||
import {Modal} from "react-bootstrap";
|
import {Modal} from "react-bootstrap";
|
||||||
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
import {faArrowRight, faSearch} from "@fortawesome/free-solid-svg-icons";
|
import {faArrowRight, faSearch} from "@fortawesome/free-solid-svg-icons";
|
||||||
import PlayerListCard from "../cards/common/PlayerListCard";
|
|
||||||
import {getViewTitle} from "../../views/query/QueryResultView";
|
import {getViewTitle} from "../../views/query/QueryResultView";
|
||||||
import {ChartLoader} from "../navigation/Loader";
|
import {ChartLoader} from "../navigation/Loader";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {useAuth} from "../../hooks/authenticationHook";
|
import {useAuth} from "../../hooks/authenticationHook";
|
||||||
|
import PlayerTable from "../table/PlayerTable.jsx";
|
||||||
|
|
||||||
const QueryPlayerListModal = ({open, toggle, queryData, title}) => {
|
const QueryPlayerListModal = ({open, toggle, queryData, title}) => {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
@ -22,8 +22,8 @@ const QueryPlayerListModal = ({open, toggle, queryData, title}) => {
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
{!queryData && <ChartLoader/>}
|
{!queryData && <ChartLoader/>}
|
||||||
{queryData &&
|
{queryData &&
|
||||||
<PlayerListCard justList data={queryData?.data?.players || {players: [], extensionDescriptors: []}}
|
<PlayerTable data={queryData?.data?.players || {players: [], extensionDescriptors: []}}
|
||||||
orderBy={2}/>}
|
orderBy={2}/>}
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
{hasPermission('access.query') && Boolean(queryData?.data?.players.players.length) && <Link className="btn bg-theme"
|
{hasPermission('access.query') && Boolean(queryData?.data?.players.players.length) && <Link className="btn bg-theme"
|
||||||
to={"/query/result?timestamp=" + queryData?.timestamp}>
|
to={"/query/result?timestamp=" + queryData?.timestamp}>
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
import {useTranslation} from "react-i18next";
|
||||||
|
import {usePreferences} from "../../hooks/preferencesHook.jsx";
|
||||||
|
import React, {useCallback, useEffect, useState} from "react";
|
||||||
|
import {useTimePreferences} from "../text/FormattedTime.jsx";
|
||||||
|
import {formatDate, useDatePreferences} from "../text/FormattedDate.jsx";
|
||||||
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
|
import {faCheck, faGlobe, faSignal, faUser, faUserPlus} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import {faCalendarCheck, faCalendarPlus, faClock} from "@fortawesome/free-regular-svg-icons";
|
||||||
|
import ExtensionIcon from "../extensions/ExtensionIcon.jsx";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {formatDecimals} from "../../util/formatters.js";
|
||||||
|
import {formatTimeAmount} from "../../util/format/TimeAmountFormat.js";
|
||||||
|
import {ExtensionValueTableCell} from "../extensions/ExtensionCard.jsx";
|
||||||
|
import {CardLoader} from "../navigation/Loader.jsx";
|
||||||
|
import DataTablesTable from "./DataTablesTable.jsx";
|
||||||
|
|
||||||
|
const getActivityGroup = value => {
|
||||||
|
const VERY_ACTIVE = 3.75;
|
||||||
|
const ACTIVE = 3.0;
|
||||||
|
const REGULAR = 2.0;
|
||||||
|
const IRREGULAR = 1.0;
|
||||||
|
if (value >= VERY_ACTIVE) {
|
||||||
|
return "html.label.veryActive"
|
||||||
|
} else if (value >= ACTIVE) {
|
||||||
|
return "html.label.active"
|
||||||
|
} else if (value >= REGULAR) {
|
||||||
|
return "html.label.indexRegular"
|
||||||
|
} else if (value >= IRREGULAR) {
|
||||||
|
return "html.label.irregular"
|
||||||
|
} else {
|
||||||
|
return "html.label.indexInactive"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlayerTable = ({data, orderBy}) => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
const {preferencesLoaded, decimalFormat} = usePreferences();
|
||||||
|
|
||||||
|
const [options, setOptions] = useState(undefined);
|
||||||
|
|
||||||
|
const timePreferences = useTimePreferences();
|
||||||
|
const datePreferences = useDatePreferences();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
title: <><Fa icon={faUser}/> {t('html.label.name')}</>,
|
||||||
|
data: {_: "name", display: "link"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faCheck}/> {t('html.label.activityIndex')}</>,
|
||||||
|
data: {_: "activityIndex", display: "activityIndexAndGroup"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faClock}/> {t('html.label.activePlaytime')}</>,
|
||||||
|
data: {_: "activePlaytime", display: "activePlaytimeFormatted"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faCalendarPlus}/> {t('html.label.sessions')}</>,
|
||||||
|
data: "sessions"
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faUserPlus}/> {t('html.label.registered')}</>,
|
||||||
|
data: {_: "registered", display: "registeredFormatted"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faCalendarCheck}/> {t('html.label.lastSeen')}</>,
|
||||||
|
data: {_: "lastSeen", display: "lastSeenFormatted"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faGlobe}/> {t('html.label.country')}</>,
|
||||||
|
data: "country"
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faSignal}/> {t('html.label.averagePing')}</>,
|
||||||
|
data: {_: "pingAverage", display: "pingAverageFormatted"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faSignal}/> {t('html.label.bestPing')}</>,
|
||||||
|
data: {_: "pingMin", display: "pingMinFormatted"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faSignal}/> {t('html.label.worstPing')}</>,
|
||||||
|
data: {_: "pingMax", display: "pingMaxFormatted"}
|
||||||
|
}];
|
||||||
|
|
||||||
|
columns.push(...data.extensionDescriptors.map(descriptor => {
|
||||||
|
return {
|
||||||
|
title: <><ExtensionIcon icon={descriptor.icon}/> {descriptor.text}</>,
|
||||||
|
data: {_: descriptor.name + "Value", display: descriptor.name}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const formatDateEasy = date => {
|
||||||
|
return formatDate(date, datePreferences.offset, datePreferences.pattern, false, datePreferences.recentDaysPattern, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = data.players.map(player => {
|
||||||
|
const row = {
|
||||||
|
name: player.playerName,
|
||||||
|
uuid: player.playerUUID,
|
||||||
|
link: <Link to={"/player/" + player.playerUUID}>{player.playerName}</Link>,
|
||||||
|
activityIndex: player.activityIndex,
|
||||||
|
activityGroup: t(getActivityGroup(player.activityIndex)),
|
||||||
|
activityIndexAndGroup: formatDecimals(player.activityIndex, decimalFormat) + " (" + t(getActivityGroup(player.activityIndex)) + ")",
|
||||||
|
activePlaytime: player.playtimeActive,
|
||||||
|
activePlaytimeFormatted: formatTimeAmount(timePreferences, player.playtimeActive),
|
||||||
|
sessions: player.sessionCount,
|
||||||
|
registered: player.registered,
|
||||||
|
registeredFormatted: formatDateEasy(player.registered),
|
||||||
|
lastSeen: player.lastSeen,
|
||||||
|
lastSeenFormatted: formatDateEasy(player.lastSeen),
|
||||||
|
country: player.country,
|
||||||
|
pingAverage: player.pingAverage,
|
||||||
|
pingAverageFormatted: formatDecimals(player.pingAverage, decimalFormat) + "ms",
|
||||||
|
pingMax: player.pingMax,
|
||||||
|
pingMaxFormatted: player.pingMax + "ms",
|
||||||
|
pingMin: player.pingMin,
|
||||||
|
pingMinFormatted: player.pingMin + "ms"
|
||||||
|
};
|
||||||
|
data.extensionDescriptors.forEach(descriptor => {
|
||||||
|
row[descriptor.name] = <ExtensionValueTableCell data={player.extensionValues[descriptor.name]}/>;
|
||||||
|
row[descriptor.name + "Value"] = JSON.stringify(player.extensionValues[descriptor.name]?.value);
|
||||||
|
})
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
|
||||||
|
setOptions({
|
||||||
|
responsive: true,
|
||||||
|
deferRender: true,
|
||||||
|
columns: columns,
|
||||||
|
data: rows,
|
||||||
|
order: [[orderBy !== undefined ? orderBy : 5, "desc"]]
|
||||||
|
});
|
||||||
|
}, [data, orderBy, t, decimalFormat]);
|
||||||
|
|
||||||
|
const rowKeyFunction = useCallback((row, column) => {
|
||||||
|
return row.uuid + "-" + (column ? JSON.stringify(column.data) : '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!preferencesLoaded) return <></>;
|
||||||
|
if (!options) return <CardLoader/>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DataTablesTable id={"players-table"} rowKeyFunction={rowKeyFunction} options={options}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlayerTable;
|
Loading…
Reference in New Issue