Skip to content

Commit

Permalink
pools: Drag drop to create pools
Browse files Browse the repository at this point in the history
  • Loading branch information
SibiAkkash committed Nov 6, 2023
1 parent 251abbc commit 6b8a5d4
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 3 deletions.
18 changes: 17 additions & 1 deletion frontend/src/components/TournamentManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ import UpdateSpiritScoreForm from "./tournament/UpdateSpiritScoreForm";
import { initFlowbite } from "flowbite";
import clsx from "clsx";
import ReorderTeams from "./tournament/ReorderTeams";
import CreatePools from "./tournament/CreatePools";

const TournamentManager = () => {
const queryClient = useQueryClient();
const [store] = useStore();
const [selectedTournament, setSelectedTournament] = createSignal();
const [selectedTournamentID, setSelectedTournamentID] = createSignal(0);
const [teams, setTeams] = createSignal([]);
const [poolTeams, setPoolTeams] = createSignal([]);
const [teamsMap, setTeamsMap] = createSignal({});
const [enteredPoolName, setEnteredPoolName] = createSignal("");
const [enteredSeedingList, setEnteredSeedingList] = createSignal("[]");
Expand Down Expand Up @@ -87,6 +89,7 @@ const TournamentManager = () => {

if (seeding) {
setTeams(Object.values(seeding));
setPoolTeams(Object.values(seeding));
}

let newDatesList = [];
Expand Down Expand Up @@ -144,6 +147,12 @@ const TournamentManager = () => {
}
});

// createEffect(() => {
// if (updateSeedingMutation.isSuccess) {
// setPoolTeams(Object.values(updateSeedingMutation.data?.initial_seeding));
// }
// })

const teamsQuery = createQuery(() => ["teams"], fetchTeams);
const tournamentsQuery = createQuery(() => ["tournaments"], fetchTournaments);
const poolsQuery = createQuery(
Expand Down Expand Up @@ -384,7 +393,7 @@ const TournamentManager = () => {
onClick={() => {
updateSeedingMutation.mutate({
id: selectedTournamentID(),
teamSeeding: teams()
teams: teams()
});
setIsStandingsEdited(false);
}}
Expand Down Expand Up @@ -414,6 +423,12 @@ const TournamentManager = () => {
Delete Tournament
</button>
</div>

<div class="my-10">
<div class="text-blue-500 text-xl font-bold mb-4">Pools</div>
<CreatePools allTeams={poolTeams()} teamsMap={teamsMap()} />
</div>

<div>
<h2 class="text-blue-500 text-xl font-bold mb-5">Pools</h2>
<Show
Expand Down Expand Up @@ -516,6 +531,7 @@ const TournamentManager = () => {
</div>
</Show>
</div>

<div>
<h3 class="text-blue-500 text-xl font-bold my-5">Cross Pool</h3>
<Show
Expand Down
223 changes: 223 additions & 0 deletions frontend/src/components/tournament/CreatePools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import {
DragDropProvider,
DragDropSensors,
createDraggable,
createDroppable,
closestCenter
} from "@thisbeyond/solid-dnd";
import { For, batch, createSignal, createEffect, Show } from "solid-js";
import { createStore } from "solid-js/store";

const allTeamsName = "All";

/**
*
* @param {object} props
* @param {object} props.team
* @param {int} props.team.seed
* @param {str} props.team.name
* @returns
*/
const TeamInfo = props => (
<div class="p-2 text-start flex gap-4 cursor-grab text-sm">
<div class="basis-1/6 text-center text-white dark:text-white-400 rounded-xl border-b bg-green-400 border-green-200 dark:bg-green-800 dark:border-green-700">
{props.team.seed}
</div>
<div class="basis-5/6">{props.team.name}</div>
</div>
);

/**
*
* @param {object} props
* @param {{seed: int, name: str}} props.team
*/
const Draggable = props => {
const draggable = createDraggable(props.team.seed);
return (
<div
use:draggable
class="text-gray-500 dark:text-gray-400 my-2 rounded-lg bg-gray-200 border-gray-300 border-b dark:bg-gray-800 dark:border-gray-700"
>
<TeamInfo team={props.team} />
</div>
);
};

/**
*
* @param {object} props
* @param {str} props.id
* @param {str} props.name
* @param {{seed: int, name: str}[]} props.teams
*/
const Droppable = props => {
const droppable = createDroppable(props.id);
return (
<>
<div
use:droppable
class="flex flex-col justify-items-center justify-start gap-y-2 content-center h-full p-4 rounded-xl dark:text-gray-400 bg-white text-center select-none border dark:border-gray-700"
classList={{
"ring-4 ring-blue-500": droppable.isActiveDroppable,
"justify-between dark:bg-gray-700": props.id !== allTeamsName,
"dark:bg-gray-900": props.id === allTeamsName
}}
>
{/* bg-gray-200 dark:bg-gray-700 border-b dark:border-gray-600 rounded-b-xl */}
<h4 class="text-center text-white p-2 justify-self-start">
<Show when={props.id !== allTeamsName} fallback={"All teams"}>
Pool - {props.name}
</Show>
</h4>
<div class="">
<For each={props.teams}>{team => <Draggable team={team} />}</For>
</div>
<Show when={props.id !== allTeamsName}>
<button
class="justify-self-end p-2 text-sm font-normal text-white rounded-lg bg-red-700 hover:bg-red-800 dark:bg-red-500/75 dark:hover:bg-red-700/75"
onClick={() => props.removePool(props.id)}
>
Remove pool
</button>
</Show>
</div>
</>
);
};

const CreatePools = props => {
const [enteredPoolName, setEnteredPoolName] = createSignal("");
const [draggedTeam, setDraggedTeam] = createSignal({});
const [draggableStartPool, setDraggableStartPool] = createSignal("");

const [pools, setPools] = createStore({});

createEffect(() => {
let allTeams = [];
props.allTeams.forEach((teamId, idx) =>
allTeams.push({
seed: idx + 1,
name: props.teamsMap[teamId]
})
);

setPools(allTeamsName, allTeams);
});

const onDragStart = ({ draggable }) => {
if (draggable) {
console.log(draggable.id);

for (const [poolName, teams] of Object.entries(pools)) {
const teamIdx = teams.findIndex(team => team.seed == draggable.id);
if (teamIdx !== -1) {
setDraggedTeam(teams[teamIdx]);
setDraggableStartPool(poolName);
break;
}
}
}
};

const onDragEnd = ({ draggable, droppable }) => {
if (draggable && droppable) {
console.log(draggable.id, droppable.id);

if (draggableStartPool() == droppable.id) {
return;
}

console.log("drag start:", draggableStartPool());
console.log("drag end:", droppable.id);

batch(() => {
setPools(draggableStartPool(), teams =>
teams.filter(team => team.seed !== draggable.id)
);
setPools(droppable.id, teams => [...teams, draggedTeam()]);
});
}
};

const removePool = droppableId => {
batch(() => {
setPools(allTeamsName, teams => [...teams, ...pools[droppableId]]);
// setting value undefined to delete it from the store
setPools(droppableId, undefined);
});
};

const addPool = poolName => {
console.log("creating pool", poolName);
if (Object.keys(pools).includes(poolName)) {
return;
}
setPools(poolName, []);
};

return (
<>
<div class="w-1/2 mb-4 flex gap-4 justify-start items-center rounded-md">
<input
type="text"
id="pool-name"
placeholder="Enter Pool Name"
value={enteredPoolName()}
onChange={e => setEnteredPoolName(e.target.value.trim())}
class="basis-2/3 p-2 placeholder:text-md placeholder:italic text-gray-900 rounded-lg bg-gray-50 border border-gray-300 dark:border-gray-600 sm:text-xs focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
/>
<button
type="button"
onClick={() => {
addPool(enteredPoolName());
setEnteredPoolName("");
}}
class="basis-1/3 p-2 font-normal text-sm rounded-lg text-white bg-blue-700 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700 disabled:dark:bg-gray-400"
>
Add Pool
</button>
</div>
<DragDropProvider
onDragStart={onDragStart}
onDragEnd={onDragEnd}
collisionDetector={closestCenter}
>
<DragDropSensors>
<div class="w-full grid grid-rows-2 grid-cols-3 grid-flow-row gap-4">
<div class="row-span-2 col-span-1">
<Droppable
id={allTeamsName}
name={allTeamsName}
teams={pools[allTeamsName]}
/>
</div>

<For each={Object.entries(pools)}>
{([poolName, teams], idx) => (
<Show when={poolName !== allTeamsName}>
<div class="row-span-1 col-span-1">
<Droppable
id={poolName}
name={poolName}
teams={teams}
removePool={removePool}
/>
</div>
</Show>
)}
</For>
</div>
</DragDropSensors>
</DragDropProvider>
<button
type="button"
class="basis-1/3 px-4 py-2 my-4 text-sm font-normal rounded-lg text-white bg-blue-700 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700 disabled:dark:bg-gray-400"
>
Submit Pools
</button>
</>
);
};

export default CreatePools;
4 changes: 2 additions & 2 deletions frontend/src/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ export const createTournament = async formData => {
return data;
};

export const updateSeeding = async ({ id, teamSeeding }) => {
export const updateSeeding = async ({ id, teams }) => {
let seedToTeamId = {};
teamSeeding.forEach(
teams.forEach(
(teamId, seeding) => (seedToTeamId[(seeding + 1).toString()] = teamId)
);
const response = await fetch(`/api/tournament/update/${id}`, {
Expand Down

0 comments on commit 6b8a5d4

Please sign in to comment.