351 lines
9.9 KiB
TypeScript
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>
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
}
|