import { Alert, AlertIcon, Box, Button, Checkbox, FormLabel, Grid, Input, InputGroup, InputRightElement, NumberDecrementStepper, NumberIncrementStepper, NumberInput, NumberInputField, NumberInputStepper, Radio, RadioGroup, Stack, Textarea, } from "@chakra-ui/react"; import { t, Trans } from "@lingui/macro"; import { useLingui } from "@lingui/react"; import { RankedMode } from "@prisma/client"; import Breadcrumbs from "components/common/Breadcrumbs"; import ModeImage from "components/common/ModeImage"; import SubText from "components/common/SubText"; import { stages } from "lib/lists/stages"; import { setManySearchParams } from "lib/setSearchParams"; import { shuffleArray } from "lib/shuffleArray"; import { useRouter } from "next/router"; import { ChangeEvent, Fragment, useEffect, useState } from "react"; import { FiCheck, FiFilter, FiRotateCw } from "react-icons/fi"; const MapsGeneratorPage = () => { const router = useRouter(); const { i18n } = useLingui(); const [stagesSelected, setStagesSelected] = useState< Record >(getInitialStages()); const [generationMode, setGenerationMode] = useState< "EQUAL" | "SZ_EVERY_OTHER" >("EQUAL"); const [maplist, setMaplist] = useState(""); const [count, setCount] = useState(9); const [editing, setEditing] = useState(false); const [copied, setCopied] = useState(null); function getInitialStages() { const filtersFromUrl = Object.entries(router.query).reduce( (acc: Record, cur) => { if (stages.includes(cur[0]) && typeof cur[1] === "string") { // @ts-ignore acc[cur[0]] = cur[1] .split(",") .filter((mode) => ["SZ", "TC", "RM", "CB"].includes(mode)); } return acc; }, {} ); return Object.keys(filtersFromUrl).length ? filtersFromUrl : stages.reduce((acc: Record, cur) => { acc[cur] = ["SZ", "TC", "RM", "CB"]; return acc; }, {}); } const poolForUrl = (stagesSelectedForUrl: Record) => { return Object.entries(stagesSelectedForUrl).map(([key, stages]) => ({ key, value: stages.join(","), })); }; useEffect(() => { const maplist = localStorage.getItem("maplist"); if (!maplist) return; setMaplist(maplist); }, []); useEffect(() => { if (!copied) return; const timer = setTimeout(() => { setCopied(null); }, 750); return () => clearTimeout(timer); }, [copied]); const handleChange = ( e: ChangeEvent, mode: RankedMode, stage: string ) => { const oldArray = stagesSelected[stage] ?? []; const newArray = e.target.checked ? oldArray.concat(mode) : oldArray.filter((modeInArray) => modeInArray !== mode); const newStagesSelected = { ...stagesSelected, [stage]: newArray }; setStagesSelected(newStagesSelected); setManySearchParams(poolForUrl(newStagesSelected), true); }; const generateMaps = () => { let modeStages = Object.entries(stagesSelected).reduce( (acc: Record, [stage, modes]) => { modes.forEach((mode) => acc[mode].push(stage)); return acc; }, { SZ: [], TC: [], RM: [], CB: [] } ); modeStages = { SZ: shuffleArray(modeStages.SZ), TC: shuffleArray(modeStages.TC), RM: shuffleArray(modeStages.RM), CB: shuffleArray(modeStages.CB), }; const modesFromGenerationMode = generationMode === "SZ_EVERY_OTHER" ? ["TC", "RM", "CB"] : ["SZ", "TC", "RM", "CB"]; const modes = (shuffleArray( modesFromGenerationMode ) as RankedMode[]).filter((mode) => modeStages[mode].length > 0); if (modes.length === 0) { return "I can't generate a maplist without any maps in it you know."; } const stagesAlreadyPicked = new Set(); const isSZFirst = false; return new Array(count) .fill(null) .map((_, i) => { let modeOfRound: RankedMode = "SZ"; if ( generationMode !== "SZ_EVERY_OTHER" || i % 2 === Number(isSZFirst) ) { modes.push(modes.shift() as RankedMode); modeOfRound = modes[0]; } const stageArray = modeStages[modeOfRound]; stageArray.push(stageArray.shift() as string); let shifted = 0; while ( stagesAlreadyPicked.has(stageArray[0]) && shifted < stageArray.length ) { stageArray.push(stageArray.shift() as string); shifted++; } stagesAlreadyPicked.add(stageArray[0]); return `${i + 1}) ${modeOfRound} on ${stageArray[0]}`; }) .join("\n"); }; return ( <> {editing ? ( <> Pro tip: bookmark this page after making your map list to save it {stages.map((stage) => { const buttonIsAdd = (stagesSelected[stage]?.length ?? 0) < 4; return ( {i18n._(stage)} handleChange(e, "SZ", stage)} /> handleChange(e, "TC", stage)} /> handleChange(e, "RM", stage)} /> handleChange(e, "CB", stage)} /> ); })} Share your map pool {window && ( )} ) : ( {Object.entries(stagesSelected).map(([stage, modes]) => modes.includes("SZ") ? ( {stage} ) : null )} {Object.entries(stagesSelected).map(([stage, modes]) => modes.includes("TC") ? ( {stage} ) : null )} {Object.entries(stagesSelected).map(([stage, modes]) => modes.includes("RM") ? ( {stage} ) : null )} {Object.entries(stagesSelected).map(([stage, modes]) => modes.includes("CB") ? ( {stage} ) : null )} )} setGenerationMode(value as "EQUAL" | "SZ_EVERY_OTHER") } value={generationMode} > All modes equally SZ every other Amount of maps to generate { if (!Number.isNaN(value)) setCount(value); }} mb={4} width={24} > {maplist && ( <>