mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-26 13:17:15 -05:00
build form milestone
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
HeadOnlyAbility,
|
||||
ClothingOnlyAbility,
|
||||
ShoesOnlyAbility,
|
||||
Ability,
|
||||
} from "../../types"
|
||||
import { abilityIcons } from "../../assets/imageImports"
|
||||
|
||||
@@ -37,12 +38,7 @@ const subAbilityStyle = {
|
||||
} as const
|
||||
|
||||
interface AbilityIconProps {
|
||||
ability:
|
||||
| StackableAbility
|
||||
| HeadOnlyAbility
|
||||
| ClothingOnlyAbility
|
||||
| ShoesOnlyAbility
|
||||
| "EMPTY"
|
||||
ability: Ability | "EMPTY"
|
||||
size: "MAIN" | "SUB"
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import { Flex, Box } from "@chakra-ui/core"
|
||||
import { abilitiesGameOrder } from "../../utils/lists"
|
||||
import AbilityIcon from "./AbilityIcon"
|
||||
import { Ability } from "../../types"
|
||||
import { useContext } from "react"
|
||||
import MyThemeContext from "../../themeContext"
|
||||
import Button from "../elements/Button"
|
||||
|
||||
interface AbilitySelectorProps {
|
||||
@@ -18,7 +16,6 @@ const AbilitySelector: React.FC<AbilitySelectorProps> = ({
|
||||
setAbilities,
|
||||
}) => {
|
||||
const [show, setShow] = useState(false)
|
||||
const { themeColor } = useContext(MyThemeContext)
|
||||
return show ? (
|
||||
<>
|
||||
<Button
|
||||
|
||||
@@ -16,7 +16,7 @@ import { FaInfo } from "react-icons/fa"
|
||||
|
||||
import WeaponImage from "../common/WeaponImage"
|
||||
import { top500 } from "../../assets/imageImports"
|
||||
import ViewGear from "./ViewGear"
|
||||
import ViewSlots from "./ViewSlots"
|
||||
import ViewAP from "./ViewAP"
|
||||
import MyThemeContext from "../../themeContext"
|
||||
import { Build } from "../../types"
|
||||
@@ -98,7 +98,7 @@ const BuildCard: React.FC<BuildCardProps & BoxProps> = ({
|
||||
</Box>
|
||||
)}
|
||||
<Gears build={build} />
|
||||
{apView ? <ViewAP build={build} /> : <ViewGear build={build} />}
|
||||
{apView ? <ViewAP build={build} /> : <ViewSlots build={build} />}
|
||||
<Flex justifyContent="space-between" mt="1em">
|
||||
{build.description ? (
|
||||
<Popover placement="top">
|
||||
|
||||
@@ -33,7 +33,6 @@ const BuildsPage: React.FC<RouteComponentProps> = () => {
|
||||
const [prefersAPView, setAPPreference] = useLocalStorage<boolean>(
|
||||
"prefersAPView"
|
||||
)
|
||||
const isSmall = useBreakPoints(870)
|
||||
|
||||
const { data, error, loading } = useQuery<
|
||||
SearchForBuildsData,
|
||||
@@ -53,7 +52,7 @@ const BuildsPage: React.FC<RouteComponentProps> = () => {
|
||||
...build.clothing,
|
||||
...build.shoes,
|
||||
])
|
||||
return abilities.every(ability => abilitiesInBuild.has(ability))
|
||||
return abilities.every(ability => abilitiesInBuild.has(ability as any))
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -71,6 +70,7 @@ const BuildsPage: React.FC<RouteComponentProps> = () => {
|
||||
/>
|
||||
<Box mt="1em">
|
||||
<WeaponSelector
|
||||
label="Select a weapon to start viewing builds"
|
||||
setValue={(weapon: string) => setWeapon(weapon as Weapon)}
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
import React from "react"
|
||||
import { Grid } from "@chakra-ui/core"
|
||||
import GearImage from "./GearImage"
|
||||
import { Build } from "../../types"
|
||||
import { Build, Ability } from "../../types"
|
||||
import AbilityIcon from "./AbilityIcon"
|
||||
import Box from "../elements/Box"
|
||||
|
||||
interface ViewGearProps {
|
||||
build: Build
|
||||
interface ViewSlotsProps {
|
||||
build: Partial<Build>
|
||||
}
|
||||
|
||||
const MARGINX = "3px"
|
||||
|
||||
const ViewGear: React.FC<ViewGearProps> = ({ build }) => {
|
||||
const ViewSlots: React.FC<ViewSlotsProps> = ({ build }) => {
|
||||
return (
|
||||
<>
|
||||
<Box asFlex alignItems="center" justifyContent="center">
|
||||
{build.headgear.map((ability, index) => (
|
||||
<Box mx={MARGINX} key={index}>
|
||||
{(
|
||||
build.headgear ??
|
||||
(["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"] as Ability[])
|
||||
).map((ability, index) => (
|
||||
<Box mx="3px" key={index}>
|
||||
<AbilityIcon
|
||||
key={index}
|
||||
ability={ability}
|
||||
@@ -26,8 +25,11 @@ const ViewGear: React.FC<ViewGearProps> = ({ build }) => {
|
||||
))}
|
||||
</Box>
|
||||
<Box asFlex alignItems="center" justifyContent="center" my="0.5em">
|
||||
{build.clothing.map((ability, index) => (
|
||||
<Box mx={MARGINX} key={index}>
|
||||
{(
|
||||
build.clothing ??
|
||||
(["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"] as Ability[])
|
||||
).map((ability, index) => (
|
||||
<Box mx="3px" key={index}>
|
||||
<AbilityIcon
|
||||
key={index}
|
||||
ability={ability}
|
||||
@@ -37,8 +39,11 @@ const ViewGear: React.FC<ViewGearProps> = ({ build }) => {
|
||||
))}
|
||||
</Box>
|
||||
<Box asFlex alignItems="center" justifyContent="center">
|
||||
{build.shoes.map((ability, index) => (
|
||||
<Box mx={MARGINX} key={index}>
|
||||
{(
|
||||
build.shoes ??
|
||||
(["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"] as Ability[])
|
||||
).map((ability, index) => (
|
||||
<Box mx="3px" key={index}>
|
||||
<AbilityIcon
|
||||
key={index}
|
||||
ability={ability}
|
||||
@@ -51,4 +56,4 @@ const ViewGear: React.FC<ViewGearProps> = ({ build }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default ViewGear
|
||||
export default ViewSlots
|
||||
@@ -7,7 +7,7 @@ import Select from "../elements/Select"
|
||||
|
||||
interface WeaponSelectorProps {
|
||||
setValue: (value: any) => void
|
||||
label?: string
|
||||
label: string
|
||||
required?: boolean
|
||||
autoFocus?: boolean
|
||||
clearable?: boolean
|
||||
@@ -38,7 +38,6 @@ const WeaponSelector: React.FC<WeaponSelectorProps> = ({
|
||||
required={required}
|
||||
options={weaponSelectOptions}
|
||||
setValue={setValue}
|
||||
placeholder="Select weapon"
|
||||
clearable={clearable}
|
||||
components={{
|
||||
IndicatorSeparator: () => null,
|
||||
|
||||
@@ -1,26 +1,47 @@
|
||||
import React, { useContext } from "react"
|
||||
import { Input as ChakraInput } from "@chakra-ui/core"
|
||||
import MyThemeContext from "../../themeContext"
|
||||
import Label from "./Label"
|
||||
import Box from "./Box"
|
||||
|
||||
interface InputProps {
|
||||
value?: string
|
||||
setValue: (value: string) => void
|
||||
placeholder: string
|
||||
label: string
|
||||
limit?: number
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
const Input: React.FC<InputProps> = ({ value, placeholder, setValue }) => {
|
||||
const { themeColorHex } = useContext(MyThemeContext)
|
||||
const Input: React.FC<InputProps> = ({
|
||||
value,
|
||||
setValue,
|
||||
label,
|
||||
required,
|
||||
limit,
|
||||
}) => {
|
||||
const { themeColorHex, grayWithShade } = useContext(MyThemeContext)
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setValue(event.target.value)
|
||||
|
||||
return (
|
||||
<ChakraInput
|
||||
value={value ?? ""}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
focusBorderColor={themeColorHex}
|
||||
/>
|
||||
<>
|
||||
{label && <Label required={required}>{label}</Label>}
|
||||
<ChakraInput
|
||||
value={value ?? ""}
|
||||
onChange={handleChange}
|
||||
focusBorderColor={themeColorHex}
|
||||
/>
|
||||
{limit && (
|
||||
<Box
|
||||
as="span"
|
||||
color={(value ?? "").length > limit ? "red.500" : grayWithShade}
|
||||
>
|
||||
{(value ?? "").length}/{limit}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useContext } from "react"
|
||||
import Button from "./Button"
|
||||
import Box from "./Box"
|
||||
import MyThemeContext from "../../themeContext"
|
||||
import useBreakPoints from "../../hooks/useBreakPoints"
|
||||
@@ -21,11 +20,11 @@ const Modal: React.FC<ModalProps> = ({ children, title }) => {
|
||||
width="100%"
|
||||
height="100%"
|
||||
overflow="auto"
|
||||
bg="rgba(0,0,0,0.4)"
|
||||
bg="rgba(0,0,0,0.75)"
|
||||
>
|
||||
<Box
|
||||
bg={darkerBgColor}
|
||||
margin="15% auto"
|
||||
margin="5% auto"
|
||||
padding="20px"
|
||||
border="1px solid #888"
|
||||
borderRadius="5px"
|
||||
|
||||
@@ -22,9 +22,8 @@ interface SelectProps {
|
||||
label: string
|
||||
value: string
|
||||
}>
|
||||
placeholder: string
|
||||
width?: string
|
||||
label?: string
|
||||
label: string
|
||||
required?: boolean
|
||||
setValue: (value: any) => void
|
||||
autoFocus?: boolean
|
||||
@@ -40,7 +39,6 @@ interface SelectProps {
|
||||
const Select: React.FC<SelectProps> = ({
|
||||
options,
|
||||
components,
|
||||
placeholder,
|
||||
setValue,
|
||||
clearable,
|
||||
autoFocus,
|
||||
@@ -66,7 +64,7 @@ const Select: React.FC<SelectProps> = ({
|
||||
className="basic-single"
|
||||
classNamePrefix="select"
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
placeholder={null}
|
||||
isSearchable
|
||||
isClearable={clearable}
|
||||
options={options}
|
||||
|
||||
64
frontend-react/src/components/user/AbilityButtons.tsx
Normal file
64
frontend-react/src/components/user/AbilityButtons.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import React from "react"
|
||||
import { abilitiesGameOrder } from "../../utils/lists"
|
||||
import AbilityIcon from "../builds/AbilityIcon"
|
||||
import Box from "../elements/Box"
|
||||
import Label from "../elements/Label"
|
||||
import { Ability } from "../../types"
|
||||
|
||||
interface AbilityButtonsProps {
|
||||
onClick: (ability: Ability) => void
|
||||
}
|
||||
|
||||
const AbilityButtons: React.FC<AbilityButtonsProps> = ({ onClick }) => {
|
||||
return (
|
||||
<>
|
||||
<Box my="1em" textAlign="center">
|
||||
<Label>Main abilities (click to select)</Label>
|
||||
</Box>
|
||||
<Box
|
||||
asFlex
|
||||
flexWrap="wrap"
|
||||
justifyContent="center"
|
||||
maxW="340px"
|
||||
mx="auto"
|
||||
>
|
||||
{abilitiesGameOrder
|
||||
.slice(14, abilitiesGameOrder.length)
|
||||
.map(ability => (
|
||||
<Box
|
||||
m="0.3em"
|
||||
key={ability}
|
||||
cursor="pointer"
|
||||
onClick={() => onClick(ability)}
|
||||
>
|
||||
<AbilityIcon ability={ability} size="SUB" />
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
<Box my="1em" textAlign="center">
|
||||
<Label>Sub abilities</Label>
|
||||
</Box>
|
||||
<Box
|
||||
asFlex
|
||||
flexWrap="wrap"
|
||||
justifyContent="center"
|
||||
maxW="350px"
|
||||
mx="auto"
|
||||
>
|
||||
{abilitiesGameOrder.slice(0, 14).map(ability => (
|
||||
<Box
|
||||
m="0.3em"
|
||||
key={ability}
|
||||
cursor="pointer"
|
||||
onClick={() => onClick(ability)}
|
||||
>
|
||||
{ability === "OG" && <br />}
|
||||
<AbilityIcon ability={ability} size="SUB" />
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AbilityButtons
|
||||
@@ -1,25 +1,114 @@
|
||||
import React, { useState } from "react"
|
||||
import Modal from "../elements/Modal"
|
||||
import WeaponSelector from "../common/WeaponSelector"
|
||||
import { Weapon, Build, HeadGear, ClothingGear, ShoesGear } from "../../types"
|
||||
import {
|
||||
Weapon,
|
||||
Build,
|
||||
HeadGear,
|
||||
ClothingGear,
|
||||
ShoesGear,
|
||||
Ability,
|
||||
HeadOnlyAbility,
|
||||
ClothingOnlyAbility,
|
||||
ShoesOnlyAbility,
|
||||
StackableAbility,
|
||||
} from "../../types"
|
||||
import WeaponImage from "../common/WeaponImage"
|
||||
import Select from "../elements/Select"
|
||||
import {
|
||||
headSelectOptions,
|
||||
clothingSelectOptions,
|
||||
shoesSelectOptions,
|
||||
headOnlyAbilities,
|
||||
clothingOnlyAbilities,
|
||||
shoesOnlyAbilities,
|
||||
headGear,
|
||||
} from "../../utils/lists"
|
||||
import Box from "../elements/Box"
|
||||
import GearImage from "../builds/GearImage"
|
||||
import Input from "../elements/Input"
|
||||
import ViewSlots from "../builds/ViewSlots"
|
||||
import AbilityButtons from "./AbilityButtons"
|
||||
|
||||
interface BuildFormModalProps {}
|
||||
interface BuildFormModalProps {
|
||||
existingGear: ExistingGearObject
|
||||
}
|
||||
|
||||
const BuildFormModal: React.FC<BuildFormModalProps> = ({}) => {
|
||||
const [build, setBuild] = useState<Partial<Build>>({})
|
||||
type ExistingGearObject = Record<
|
||||
Partial<HeadGear | ClothingGear | ShoesGear>,
|
||||
Ability[]
|
||||
>
|
||||
|
||||
const BuildFormModal: React.FC<BuildFormModalProps> = ({ existingGear }) => {
|
||||
const [build, setBuild] = useState<Partial<Build>>({
|
||||
headgear: ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
|
||||
clothing: ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
|
||||
shoes: ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
|
||||
})
|
||||
|
||||
const handleChange = (value: Object) => setBuild({ ...build, ...value })
|
||||
|
||||
const handleAbilityClick = (ability: Ability) => {
|
||||
if (headOnlyAbilities.indexOf(ability as any) !== -1) {
|
||||
if (build.headgear![0] === "UNKNOWN") {
|
||||
handleChange({
|
||||
headgear: [
|
||||
ability,
|
||||
build.headgear![1],
|
||||
build.headgear![2],
|
||||
build.headgear![3],
|
||||
],
|
||||
})
|
||||
}
|
||||
} else if (clothingOnlyAbilities.indexOf(ability as any) !== -1) {
|
||||
if (build.clothing![0] === "UNKNOWN") {
|
||||
handleChange({
|
||||
clothing: [
|
||||
ability,
|
||||
build.clothing![1],
|
||||
build.clothing![2],
|
||||
build.clothing![3],
|
||||
],
|
||||
})
|
||||
}
|
||||
} else if (shoesOnlyAbilities.indexOf(ability as any) !== -1) {
|
||||
if (build.shoes![0] === "UNKNOWN") {
|
||||
handleChange({
|
||||
shoes: [ability, build.shoes![1], build.shoes![2], build.shoes![3]],
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const headI = build.headgear!.indexOf("UNKNOWN")
|
||||
if (headI !== -1) {
|
||||
const copy = build.headgear!.slice()
|
||||
copy[headI] = ability as HeadOnlyAbility | StackableAbility
|
||||
handleChange({
|
||||
headgear: copy,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const clothingI = build.clothing!.indexOf("UNKNOWN")
|
||||
if (clothingI !== -1) {
|
||||
const copy = build.clothing!.slice()
|
||||
copy[clothingI] = ability as ClothingOnlyAbility | StackableAbility
|
||||
handleChange({
|
||||
clothing: copy,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const shoesI = build.shoes!.indexOf("UNKNOWN")
|
||||
if (shoesI !== -1) {
|
||||
const copy = build.shoes!.slice()
|
||||
copy[shoesI] = ability as ShoesOnlyAbility | StackableAbility
|
||||
handleChange({
|
||||
shoes: copy,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal title="Adding a new build">
|
||||
<WeaponSelector
|
||||
@@ -33,39 +122,81 @@ const BuildFormModal: React.FC<BuildFormModalProps> = ({}) => {
|
||||
<Box asFlex mt="1em" justifyContent="space-between" flexWrap="wrap">
|
||||
<Box asFlex flexDirection="column" alignItems="center">
|
||||
<Select
|
||||
placeholder="Select headgear"
|
||||
label="Headgear"
|
||||
options={headSelectOptions}
|
||||
clearable
|
||||
setValue={(headgearItem: HeadGear) =>
|
||||
setBuild({ ...build, headgearItem })
|
||||
}
|
||||
setValue={(headgearItem: HeadGear) => {
|
||||
if (
|
||||
(!build.headgear ||
|
||||
build.headgear.every(ability => ability === "UNKNOWN")) &&
|
||||
existingGear.hasOwnProperty(headgearItem)
|
||||
) {
|
||||
handleChange({
|
||||
headgearItem,
|
||||
headgear: existingGear[headgearItem],
|
||||
})
|
||||
} else {
|
||||
handleChange({ headgearItem })
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{build.headgearItem && <GearImage englishName={build.headgearItem} />}
|
||||
{build.headgearItem && (
|
||||
<Box mt="0.5em">
|
||||
<GearImage englishName={build.headgearItem} />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<Box asFlex flexDirection="column" alignItems="center">
|
||||
<Select
|
||||
placeholder="Select headgear"
|
||||
label="Clothing"
|
||||
options={clothingSelectOptions}
|
||||
clearable
|
||||
setValue={(clothingItem: ClothingGear) =>
|
||||
setBuild({ ...build, clothingItem })
|
||||
}
|
||||
setValue={(clothingItem: ClothingGear) => {
|
||||
if (
|
||||
(!build.clothing ||
|
||||
build.clothing.every(ability => ability === "UNKNOWN")) &&
|
||||
existingGear.hasOwnProperty(clothingItem)
|
||||
) {
|
||||
handleChange({
|
||||
clothingItem,
|
||||
clothing: existingGear[clothingItem],
|
||||
})
|
||||
} else {
|
||||
handleChange({ clothingItem })
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{build.clothingItem && <GearImage englishName={build.clothingItem} />}
|
||||
{build.clothingItem && (
|
||||
<Box mt="0.5em">
|
||||
<GearImage englishName={build.clothingItem} />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<Box asFlex flexDirection="column" alignItems="center">
|
||||
<Select
|
||||
placeholder="Select headgear"
|
||||
label="Shoes"
|
||||
options={shoesSelectOptions}
|
||||
clearable
|
||||
setValue={(shoesItem: ShoesGear) =>
|
||||
setBuild({ ...build, shoesItem })
|
||||
}
|
||||
setValue={(shoesItem: ShoesGear) => {
|
||||
if (
|
||||
(!build.shoes ||
|
||||
build.shoes.every(ability => ability === "UNKNOWN")) &&
|
||||
existingGear.hasOwnProperty(shoesItem)
|
||||
) {
|
||||
handleChange({
|
||||
shoesItem,
|
||||
shoes: existingGear[shoesItem],
|
||||
})
|
||||
} else {
|
||||
handleChange({ shoesItem })
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{build.shoesItem && <GearImage englishName={build.shoesItem} />}
|
||||
{build.shoesItem && (
|
||||
<Box mt="0.5em">
|
||||
<GearImage englishName={build.shoesItem} />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box mt="1em">
|
||||
@@ -73,8 +204,16 @@ const BuildFormModal: React.FC<BuildFormModalProps> = ({}) => {
|
||||
value={build.title}
|
||||
setValue={(value: string) => handleChange({ title: value })}
|
||||
placeholder="Title"
|
||||
label="Title"
|
||||
limit={100}
|
||||
/>
|
||||
</Box>
|
||||
<Box mt="1em">
|
||||
<ViewSlots build={build} />
|
||||
</Box>
|
||||
<Box mt="1em">
|
||||
<AbilityButtons onClick={ability => handleAbilityClick(ability)} />
|
||||
</Box>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,48 @@
|
||||
import React from "react"
|
||||
import { Build } from "../../types"
|
||||
import { Flex } from "@chakra-ui/core"
|
||||
import BuildCard from "../builds/BuildCard"
|
||||
import useLocalStorage from "@rehooks/local-storage"
|
||||
import Button from "../elements/Button"
|
||||
import { useState } from "react"
|
||||
import Alert from "../elements/Alert"
|
||||
import { HeadGear, ClothingGear, ShoesGear, Ability } from "../../types"
|
||||
import BuildFormModal from "./BuildFormModal"
|
||||
import Button from "../elements/Button"
|
||||
import Alert from "../elements/Alert"
|
||||
import Box from "../elements/Box"
|
||||
import BuildCard from "../builds/BuildCard"
|
||||
|
||||
interface BuildTabProps {
|
||||
builds: Build[]
|
||||
canModifyBuilds: boolean
|
||||
}
|
||||
|
||||
type ExistingGearObject = Record<
|
||||
Partial<HeadGear | ClothingGear | ShoesGear>,
|
||||
Ability[]
|
||||
>
|
||||
|
||||
const buildsReducer = (acc: ExistingGearObject, cur: Build) => {
|
||||
if (cur.headgearItem) {
|
||||
acc[cur.headgearItem] = [...cur.headgear]
|
||||
}
|
||||
if (cur.clothingItem) {
|
||||
acc[cur.clothingItem] = [...cur.clothing]
|
||||
}
|
||||
if (cur.shoesItem) {
|
||||
acc[cur.shoesItem] = [...cur.shoes]
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
const BuildTab: React.FC<BuildTabProps> = ({ builds, canModifyBuilds }) => {
|
||||
const [APView] = useLocalStorage<boolean>("prefersAPView")
|
||||
const [formOpen, setFormOpen] = useState(true)
|
||||
|
||||
const existingGear = builds
|
||||
? builds.reduce(buildsReducer, {} as ExistingGearObject)
|
||||
: ({} as ExistingGearObject)
|
||||
|
||||
return (
|
||||
<>
|
||||
{formOpen && <BuildFormModal />}
|
||||
{formOpen && <BuildFormModal existingGear={existingGear} />}
|
||||
{canModifyBuilds && builds.length < 100 && (
|
||||
<Button onClick={() => setFormOpen(true)}>Add build</Button>
|
||||
)}
|
||||
@@ -27,7 +51,7 @@ const BuildTab: React.FC<BuildTabProps> = ({ builds, canModifyBuilds }) => {
|
||||
You already have 100 builds. Please delete one before adding a new one
|
||||
</Alert>
|
||||
)}
|
||||
<Flex flexWrap="wrap" justifyContent="center" mt="1em">
|
||||
<Box asFlex flexWrap="wrap" justifyContent="center" mt="1em">
|
||||
{builds.map(build => (
|
||||
<BuildCard
|
||||
key={build.id}
|
||||
@@ -36,7 +60,7 @@ const BuildTab: React.FC<BuildTabProps> = ({ builds, canModifyBuilds }) => {
|
||||
m="0.5em"
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,9 @@ export type ThemeColor = ElementType<typeof themeColors>
|
||||
export type HeadOnlyAbility = ElementType<typeof headOnlyAbilities>
|
||||
export type ClothingOnlyAbility = ElementType<typeof clothingOnlyAbilities>
|
||||
export type ShoesOnlyAbility = ElementType<typeof shoesOnlyAbilities>
|
||||
export type StackableAbility = ElementType<typeof stackableAbilities>
|
||||
export type StackableAbility =
|
||||
| ElementType<typeof stackableAbilities>
|
||||
| "UNKNOWN"
|
||||
export type Ability =
|
||||
| HeadOnlyAbility
|
||||
| ClothingOnlyAbility
|
||||
@@ -90,7 +92,7 @@ export interface Build {
|
||||
HeadOnlyAbility | StackableAbility,
|
||||
StackableAbility,
|
||||
StackableAbility,
|
||||
StackableAbility
|
||||
StackableAbility | "UNKNOWN"
|
||||
]
|
||||
clothing: [
|
||||
ClothingOnlyAbility | StackableAbility,
|
||||
@@ -102,7 +104,7 @@ export interface Build {
|
||||
ShoesOnlyAbility | StackableAbility,
|
||||
StackableAbility,
|
||||
StackableAbility,
|
||||
StackableAbility
|
||||
StackableAbility | "UNKNOWN"
|
||||
]
|
||||
headgearItem?: HeadGear
|
||||
clothingItem?: ClothingGear
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Weapon } from "../types"
|
||||
import { wpnSmall } from "../assets/imageImports"
|
||||
import english_internal from "./english_internal.json"
|
||||
|
||||
export const headOnlyAbilities = ["CB", "LDE", "OG", "T"] as const
|
||||
export const clothingOnlyAbilities = ["H", "NS", "TI", "RP", "AD"] as const
|
||||
|
||||
Reference in New Issue
Block a user