cutt/src/Rankings.tsx

351 lines
9.9 KiB
TypeScript

import { Dispatch, SetStateAction, useEffect, useMemo, useState } from "react";
import { ReactSortable, ReactSortableProps } from "react-sortablejs";
import api, { baseUrl } from "./api";
interface Player {
id: number;
name: string;
number: string | null;
}
type PlayerListProps = Partial<ReactSortableProps<any>> & {
orderedList?: boolean;
};
function PlayerList(props: PlayerListProps) {
return (
<ReactSortable {...props} animation={200}>
{props.list?.map((item, index) => (
<div key={item.id} className="item">
{props.orderedList ? index + 1 + ". " + item.name : item.name}
</div>
))}
</ReactSortable>
);
}
interface SelectUserProps {
user: Player[];
setUser: Dispatch<SetStateAction<Player[]>>;
players: Player[];
setPlayers: Dispatch<SetStateAction<Player[]>>;
}
export function SelectUser({
user,
setUser,
players,
setPlayers,
}: SelectUserProps) {
return (
<>
<div className="box user">
{user.length < 1 ? (
<>
<span>your name?</span>
<br /> <span className="grey hint">drag your name here</span>
</>
) : (
<>
<span
className="renew"
onClick={() => {
setUser([]);
}}
>
{" ✕"}
</span>
</>
)}
<PlayerList
list={user}
setList={setUser}
group={{
name: "user-shared",
put: function (to) {
return to.el.children.length < 1;
},
}}
className="dragbox"
/>
</div>
{user.length < 1 && (
<div className="box one">
<h2>🥏🏃</h2>
<ReactSortable
list={players}
setList={setPlayers}
group={{ name: "user-shared", pull: "clone" }}
className="dragbox reservoir"
animation={200}
>
{players.length < 1 ? (
<span className="loader"></span>
) : (
players.map((item, _) => (
<div key={"extra" + item.id} className="extra-margin">
<div key={item.id} className="item">
{item.name}
</div>
</div>
))
)}
</ReactSortable>
</div>
)}
</>
);
}
interface PlayerInfoProps {
user: Player[];
players: Player[];
}
export function Chemistry({ user, players }: PlayerInfoProps) {
const index = players.indexOf(user[0]);
var otherPlayers = players.slice();
otherPlayers.splice(index, 1);
const [playersLeft, setPlayersLeft] = useState<Player[]>([]);
const [playersMiddle, setPlayersMiddle] = useState<Player[]>(otherPlayers);
const [playersRight, setPlayersRight] = useState<Player[]>([]);
const [dialog, setDialog] = useState("dialog");
async function handleSubmit() {
const dialog = document.querySelector("dialog[id='ChemistryDialog']");
(dialog as HTMLDialogElement).showModal();
if (user.length < 1) {
setDialog("who are you?");
} else {
setDialog("sending...");
let _user = user.map(({ name }) => name)[0];
let left = playersLeft.map(({ name }) => name);
let middle = playersMiddle.map(({ name }) => name);
let right = playersRight.map(({ name }) => name);
const data = { user: _user, hate: left, undecided: middle, love: right };
const response = await api("chemistry", data);
response.ok ? setDialog("success!") : setDialog("try sending again");
}
}
return (
<>
<div className="container">
<div className="box three">
<h2>😬</h2>
{playersLeft.length < 1 && (
<span className="grey hint">
drag people here that you'd rather not play with
</span>
)}
<PlayerList
list={playersLeft}
setList={setPlayersLeft}
group={"shared"}
className="dragbox"
/>
</div>
<div className="box three">
<h2>🤷</h2>
<PlayerList
list={playersMiddle}
setList={setPlayersMiddle}
group={"shared"}
className="middle dragbox"
/>
</div>
<div className="box three">
<h2>😍</h2>
{playersRight.length < 1 && (
<span className="grey hint">
drag people here that you love playing with from best to ... ok
</span>
)}
<PlayerList
list={playersRight}
setList={setPlayersRight}
group={"shared"}
className="dragbox"
orderedList
/>
</div>
</div>
<button className="submit" onClick={() => handleSubmit()}>
💾 <span className="submit_text">submit</span>
</button>
<dialog
id="ChemistryDialog"
onClick={(event) => {
event.currentTarget.close();
}}
>
{dialog}
</dialog>
</>
);
}
export function MVP({ user, players }: PlayerInfoProps) {
const [availablePlayers, setAvailablePlayers] = useState<Player[]>(players);
const [rankedPlayers, setRankedPlayers] = useState<Player[]>([]);
const [dialog, setDialog] = useState("dialog");
async function handleSubmit() {
const dialog = document.querySelector("dialog[id='MVPDialog']");
(dialog as HTMLDialogElement).showModal();
if (user.length < 1) {
setDialog("who are you?");
} else {
setDialog("sending...");
let _user = user.map(({ name }) => name)[0];
let mvps = rankedPlayers.map(({ name }) => name);
const data = { user: _user, mvps: mvps };
const response = await api("mvps", data);
response.ok ? setDialog("success!") : setDialog("try sending again");
}
}
return (
<>
<div className="container">
<div className="box two">
<h2>🥏🏃</h2>
{availablePlayers.length < 1 && (
<span className="grey hint">all sorted 👍</span>
)}
<PlayerList
list={availablePlayers}
setList={setAvailablePlayers}
group={{
name: "mvp-shared",
pull: function (to) {
return to.el.classList.contains("putclone") ? "clone" : true;
},
}}
className="dragbox"
/>
</div>
<div className="box two">
<h1>🏆</h1>
{rankedPlayers.length < 1 && (
<span className="grey hint">
carefully place as many of the <i>Most Valuable Players</i>{" "}
(according to your humble opinion) in this box
</span>
)}
<PlayerList
list={rankedPlayers}
setList={setRankedPlayers}
group={{
name: "mvp-shared",
pull: function (to) {
return to.el.classList.contains("putclone") ? "clone" : true;
},
}}
className="dragbox"
orderedList
/>
</div>
</div>
<button className="submit" onClick={() => handleSubmit()}>
💾 <span className="submit_text">submit</span>
</button>
<dialog
id="MVPDialog"
onClick={(event) => {
event.currentTarget.close();
}}
>
{dialog}
</dialog>
</>
);
}
export default function Rankings() {
const [user, setUser] = useState<Player[]>([]);
const [players, setPlayers] = useState<Player[]>([]);
const [openTab, setOpenTab] = useState("Chemistry");
async function loadPlayers() {
const response = await fetch(`${baseUrl}api/player/list`, {
method: "GET",
});
const data = await response.json();
setPlayers(data as Player[]);
}
useMemo(() => {
loadPlayers();
}, []);
useEffect(() => {
user.length === 1 && openPage(openTab, "aliceblue");
}, [user]);
function openPage(pageName: string, color: string) {
// Hide all elements with class="tabcontent" by default */
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
(tabcontent[i] as HTMLElement).style.display = "none";
}
// Remove the background color of all tablinks/buttons
tablinks = document.getElementsByClassName("tablink");
for (i = 0; i < tablinks.length; i++) {
let button = tablinks[i] as HTMLElement;
button.style.opacity = "50%";
}
// Show the specific tab content
(document.getElementById(pageName) as HTMLElement).style.display = "block";
// Add the specific color to the button used to open the tab content
let activeButton = document.getElementById(
pageName + "Button"
) as HTMLElement;
activeButton.style.fontWeight = "bold";
activeButton.style.opacity = "100%";
document.body.style.backgroundColor = color;
setOpenTab(pageName);
}
return (
<>
<SelectUser {...{ user, setUser, players, setPlayers }} />
{user.length === 1 && (
<>
<div className="container navbar">
<button
className="tablink"
id="ChemistryButton"
onClick={() => openPage("Chemistry", "aliceblue")}
>
🧪 Chemistry
</button>
<button
className="tablink"
id="MVPButton"
onClick={() => openPage("MVP", "aliceblue")}
>
🏆 MVP
</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>
<div id="Chemistry" className="tabcontent">
<Chemistry {...{ user, players }} />
</div>
<div id="MVP" className="tabcontent">
<MVP {...{ user, players }} />
</div>
</>
)}
</>
);
}