feat: loads of improvements (see comments)

1) check whether submitting user is submitting for himself
2) some refactoring of the tabs in `Ranking`
3) get chemistry and mvps from DB
4) restore previous
5) start over
6) (hopefully) improve logout
This commit is contained in:
2025-03-13 20:11:34 +01:00
parent 9afa4a88a8
commit 453d7ca951
5 changed files with 186 additions and 32 deletions

View File

@@ -1,7 +1,8 @@
import { useEffect, useRef, useState } from "react";
import { ButtonHTMLAttributes, useEffect, useRef, useState } from "react";
import { ReactSortable, ReactSortableProps } from "react-sortablejs";
import { apiAuth, User } from "./api";
import { useSession } from "./Session";
import { Chemistry, MVPRanking } from "./types";
type PlayerListProps = Partial<ReactSortableProps<any>> & {
orderedList?: boolean;
@@ -21,15 +22,37 @@ function PlayerList(props: PlayerListProps) {
);
}
const LoadButton = (props: ButtonHTMLAttributes<HTMLButtonElement>) => {
return (
<button {...props} style={{ padding: "4px 16px" }}>
🗃 restore previous
</button>
);
};
const ClearButton = (props: ButtonHTMLAttributes<HTMLButtonElement>) => {
return (
<button {...props} style={{ padding: "4px 16px" }}>
🗑 start over
</button>
);
};
function filterSort(list: User[], ids: number[]): User[] {
const objectMap = new Map(list.map((obj) => [obj.id, obj]));
const filteredAndSortedObjects = ids
.map((id) => objectMap.get(id))
.filter((obj) => obj !== undefined);
return filteredAndSortedObjects;
}
interface PlayerInfoProps {
user: User;
players: User[];
}
export function Chemistry({ user, players }: PlayerInfoProps) {
const index = players.indexOf(user);
var otherPlayers = players.slice();
otherPlayers.splice(index, 1);
function ChemistryDnD({ user, players }: PlayerInfoProps) {
var otherPlayers = players.filter((player) => player.id !== user.id);
const [playersLeft, setPlayersLeft] = useState<User[]>([]);
const [playersMiddle, setPlayersMiddle] = useState<User[]>(otherPlayers);
const [playersRight, setPlayersRight] = useState<User[]>([]);
@@ -48,12 +71,27 @@ export function Chemistry({ user, players }: PlayerInfoProps) {
let middle = playersMiddle.map(({ id }) => id);
let right = playersRight.map(({ id }) => id);
const data = { user: user.id, hate: left, undecided: middle, love: right };
const response = await apiAuth("chemistry", data, "POST");
response ? setDialog(response) : setDialog("try sending again");
const response = await apiAuth("chemistry", data, "PUT");
setDialog(response || "try sending again");
}
async function handleGet() {
const chemistry = (await apiAuth("chemistry", null, "GET")) as Chemistry;
setPlayersLeft(filterSort(otherPlayers, chemistry.hate));
setPlayersMiddle(filterSort(otherPlayers, chemistry.undecided));
setPlayersRight(filterSort(otherPlayers, chemistry.love));
}
return (
<>
<HeaderControl
onLoad={handleGet}
onClear={() => {
setPlayersRight([]);
setPlayersMiddle(otherPlayers);
setPlayersLeft([]);
}}
/>
<div className="container">
<div className="box three">
<h2>😬</h2>
@@ -111,7 +149,7 @@ export function Chemistry({ user, players }: PlayerInfoProps) {
);
}
export function MVP({ user, players }: PlayerInfoProps) {
function MVPDnD({ user, players }: PlayerInfoProps) {
const [availablePlayers, setAvailablePlayers] = useState<User[]>(players);
const [rankedPlayers, setRankedPlayers] = useState<User[]>([]);
@@ -127,12 +165,25 @@ export function MVP({ user, players }: PlayerInfoProps) {
setDialog("sending...");
let mvps = rankedPlayers.map(({ id }) => id);
const data = { user: user.id, mvps: mvps };
const response = await apiAuth("mvps", data, "POST");
const response = await apiAuth("mvps", data, "PUT");
response ? setDialog(response) : setDialog("try sending again");
}
async function handleGet() {
const mvps = (await apiAuth("mvps", null, "GET")) as MVPRanking;
setRankedPlayers(filterSort(players, mvps.mvps));
setAvailablePlayers(players.filter((user) => !mvps.mvps.includes(user.id)));
}
return (
<>
<HeaderControl
onLoad={handleGet}
onClear={() => {
setAvailablePlayers(players);
setRankedPlayers([]);
}}
/>
<div className="container">
<div className="box two">
<h2>🥏🏃</h2>
@@ -190,6 +241,27 @@ export function MVP({ user, players }: PlayerInfoProps) {
);
}
interface HeaderControlProps {
onLoad: () => void;
onClear: () => void;
}
function HeaderControl({ onLoad, onClear }: HeaderControlProps) {
return (
<>
<div>
<LoadButton onClick={onLoad} />
<ClearButton onClick={onClear} />
</div>
<div>
<span className="grey">
assign as many or as few players as you want and don't forget to{" "}
<b>submit</b> 💾 when you're done :)
</span>
</div>
</>
);
}
export default function Rankings() {
const { user } = useSession();
const [players, setPlayers] = useState<User[] | null>(null);
@@ -230,18 +302,13 @@ export default function Rankings() {
</button>
))}
</div>
<span className="grey">
assign as many or as few players as you want
<br />
and don't forget to <b>submit</b> 💾 when you're done :)
</span>
{tabs.map((tab) => {
if (openTab !== tab.id) return null;
switch (tab.id) {
case "Chemistry":
return <Chemistry key={tab.id} {...{ user, players }} />;
return <ChemistryDnD key={tab.id} {...{ user, players }} />;
case "MVP":
return <MVP key={tab.id} {...{ user, players }} />;
return <MVPDnD key={tab.id} {...{ user, players }} />;
default:
return null;
}