import Menu from "../../../components/Menu"; import Link from "../../../components/Link"; import Dialog from "../../../components/Dialog"; import { GetServerSideProps } from "next"; import Head from "next/head.js"; import db from "../../../Modules/database"; import { Pictures, Players } from "#type/db"; import Image from "next/image"; import { useContext, useEffect, useState } from "react"; import { Box, Button, LinearProgress, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, alpha, useTheme, } from "@mui/material"; import { result as apiPlayerResult } from "../../api/player/[leagueType]/[uid]"; import { TranslateContext } from "../../../Modules/context"; import { downloadPicture } from "#/scripts/pictures"; import fallbackImg from "../../../public/playerFallback.png"; import { getData } from "#/pages/api/theme"; import { Selectable } from "kysely"; interface extendedPlayers extends Selectable { game?: { opponent: string; gameStart: number; }; } interface props { uid: string; player: extendedPlayers; times: number[]; league: string; otherLeagues: { league: string; uid: string }[]; pictures: Selectable[]; } interface Column { id: | "time" | "value" | "sale_price" | "last_match" | "average_points" | "total_points" | "opponent" | "club" | "position"; label: string; format: (value: string | number) => string; } interface Data { time: number; value: number; sale_price: number; last_match: number; average_points: number; total_points: number; club: string; opponent?: string; position: string; exists: boolean; forecast: string; loading: false; } export default function Home({ player, times, uid, league, otherLeagues, pictures, }: props) { const t = useContext(TranslateContext); // An array of all the columns const columns: Column[] = [ { id: "time", label: "Time", format: (value: string | number) => { const date = new Date(parseInt(String(value)) * 1000); return typeof value === "number" && value > 10 ** 20 ? t("Now") : t("{date}", { date }); }, }, { id: "value", label: "Value", format: (value: string | number) => t("{amount} M", { amount: parseInt(String(value)) / 1000000 }), }, { id: "sale_price", label: "Sale Price", format: (value: string | number) => t("{amount} M", { amount: parseInt(String(value)) / 1000000 }), }, { id: "last_match", label: "Last Match Points", format: (value: string | number) => t("{value}", { value }), }, { id: "average_points", label: "Average Points", format: (value: string | number) => t("{value}", { value }), }, { id: "total_points", label: "Total Points", format: (value: string | number) => t("{value}", { value }), }, { id: "opponent", label: "Opponent", format: (value: string | number | undefined) => value ? String(value) : "", }, { id: "club", label: "Club", format: (value: unknown) => String(value) }, { id: "position", label: "Position", format: (value: string | number) => t(String(value)), }, ]; // Stores the amount of time left until the game starts const [countdown, setCountown] = useState( (player?.game?.gameStart || 0 - Date.now() / 1000) / 60, ); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(5); const [dialogVisible, setDialogVisible] = useState(false); const [rows, setRows] = useState< Record >({}); // Sets the starting piece of data when a new player gets loaded useEffect(() => { setPage(0); // Sets the starting value to crazy high time and sets it to the starting amount setRows({ "9999999999999999": { time: 10 ** 21, value: player.value, sale_price: player.sale_price, last_match: player.last_match, average_points: player.average_points, total_points: player.total_points, opponent: player?.game?.opponent, club: player.club, position: player.position, exists: Boolean(player.exists), forecast: player.forecast, loading: false, }, }); }, [uid, player]); // Loads the data up to that amount(If on the server nothing new is loaded) useEffect(() => { let count = page * rowsPerPage + rowsPerPage; times.forEach((time) => { count--; if (count > 0) { if (rows[String(time)] === undefined) { setRows((rows) => { const newRows = { ...rows }; newRows[String(time)] = { time, loading: true }; return newRows; }); fetch(`/api/player/${league}/${uid}?time=${time}`) .then((e) => e.json()) .then((data: apiPlayerResult) => { setRows((rows) => { const newRows = { ...rows }; newRows[String(time)] = { time, value: data.value, sale_price: data.sale_price, last_match: data.last_match, average_points: data.average_points, total_points: data.total_points, club: data.club, opponent: data.game ? (data.game.opponent ?? "") : "", position: data.position, exists: Boolean(data.exists), forecast: data.forecast, loading: false, }; return newRows; }); }); } } }); }, [page, rowsPerPage, league, rows, times, uid]); // Used to change the page const handleChangePage = (event: unknown, newPage: number) => { setPage(newPage); }; // Used to change the number of rows per page const handleChangeRowsPerPage = ( event: React.ChangeEvent, ) => { setRowsPerPage(+event.target.value); setPage(0); }; // Used to handle the dialog closing const handleDialogToggle = () => { setDialogVisible((e) => !e); }; // Used to search for more data useEffect(() => { const id = setInterval( () => setCountown((countdown) => (countdown > 0 ? countdown - 1 : 0)), 60000, ); return () => { clearInterval(id); }; }, []); // Calculates the number of rows that have not been loaded but should be let tempUnloaded = page * rowsPerPage + rowsPerPage - Object.values(rows).length; if (page * rowsPerPage + rowsPerPage > times.length) { tempUnloaded -= page * rowsPerPage + rowsPerPage - times.length; } const unloadedRows = tempUnloaded > 0 ? tempUnloaded : 0; const theme = useTheme(); // Calculates the height and width for the official picture const mainPicture = pictures.filter((e) => e.id === player.pictureID)[0]; const pictureExists = mainPicture.downloaded; let pictureHeight = pictureExists ? mainPicture.height : 200; let pictureWidth = pictureExists ? mainPicture.width : 200; if (pictureWidth > 200) { pictureHeight = (pictureHeight * 200) / pictureWidth; pictureWidth = 200; } const Row1 = (

<>

{t("The newest pictures are on the top. ")}

{pictures.map((e) => (
))}
); const Row2 = (

{t("Current Player Info")}

{t("League")} : {league}

{t("Value")} : {player.value / 1000000}M

{player.value !== player.sale_price && (

{t("Sale Price")} : {player.sale_price / 1000000}M

)}

{t("Total Points")} : {player.total_points}

{t("Average Points")} : {player.average_points}

{t("Last Match")} : {player.last_match}

{player.game && (

{t("Opponent")} :{" "} {countdown > 0 ? t("{team} in {day} D {hour} H {minute} M ", { team: player.game.opponent, day: String(Math.floor(countdown / 60 / 24)), hour: String(Math.floor(countdown / 60) % 24), minute: String(Math.floor(countdown) % 60), }) : player.game.opponent}

)}
); const Row3 = otherLeagues.length > 0 && (

{t("Other Leagues")}

{t("This player was found in the leagues listed below. ")}

{otherLeagues.map((e) => (
{t(e.league)}
))}
    {otherLeagues.map((e) => (
  • {t(e.league)}
  • ))}
); return ( <> {player.name}

{player.name} ({t(player.position)}) - {player.club}

{Row1} {Row2} {Row3}

{player.name} ({t(player.position)}) - {player.club}

{Row2} {Row3}
{Row1}

{t("Historical Data Table")}

{columns.map((column) => ( {t(column.label)} ))} {Object.values(rows) .sort((e, e2) => e2.time - e.time) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .map((row) => { if (row.loading) { return ( {t("Loading")} ); } // Gets the background color based on the status of the player let background: "main" | "secondary" | "warning" | "error" = "main"; if (row.forecast == "u") { background = "warning"; } else if (row.forecast == "m") { background = "error"; } // Checks if the player exists if (!row.exists) { background = "secondary"; } return ( {columns.map((column) => { const value = row[column.id]; return ( {column.format(value as string | number)} ); })} ); })} {Array(unloadedRows) .fill(0) .map((e, idx) => { return ( Loading... ); })}
= page * rowsPerPage ? page : 0} onPageChange={handleChangePage} onRowsPerPageChange={handleChangeRowsPerPage} />
); } export const getServerSideProps: GetServerSideProps = async (ctx) => { const uid = ctx.params?.uid as string; const league = ctx.params?.league as string; let player = await db .selectFrom("players") .where("uid", "=", uid) .where("league", "=", league) .selectAll() .executeTakeFirst(); if (player === undefined) { return { notFound: true, }; } // Makes sure that this is not invalid data that is being shown to the user while ( player?.exists === 0 && (await db .selectFrom("data") .selectAll() .where("value1", "=", "locked" + league) .executeTakeFirst()) !== undefined ) { await new Promise((res) => setTimeout(res, 1000)); player = await db .selectFrom("players") .where("uid", "=", uid) .where("league", "=", league) .selectAll() .executeTakeFirst(); } if (player === undefined) { return { notFound: true, }; } const otherLeagues = await db .selectFrom("players") .select(["league", "uid"]) .where("nameAscii", "=", player.nameAscii) .where("league", "!=", league) .execute(); // Gets some more player data const gameData = await db .selectFrom("clubs") .select(["opponent", "gameStart"]) .where("club", "=", player.club) .where("league", "=", league) .executeTakeFirst(); // Gets all the pictures in a set const pictures = new Set(); pictures.add(player.pictureID); // Gets all the historical times in an array const times = await db .selectFrom("historicalPlayers") .select(["time", "pictureID"]) .where("uid", "=", uid) .where("league", "=", league) .orderBy("time", "desc") .execute() .then((res) => { const result: number[] = []; res.forEach((e) => { result.push(e.time); pictures.add(e.pictureID); }); return result; }); // Sends a request to download every picture needed const pictureData: Selectable[] = ( await Promise.all( Array.from(pictures).map( (e) => new Promise | undefined>(async (res) => { downloadPicture(e); const data = await db .selectFrom("pictures") .selectAll() .where("id", "=", e) .executeTakeFirst(); if ( data !== undefined && (await db .selectFrom("data") .select("value1") .where("value1", "=", "configDownloadPicture") .where("value2", "=", "no") .executeTakeFirst()) !== undefined ) { res({ ...data, downloaded: 1 }); } res(data); }), ), ) ).filter((e) => e !== undefined); return { props: { uid, player: { ...player, gameData }, times, league, otherLeagues, pictures: pictureData, t: await getData(ctx), }, }; };