435 lines
12 KiB
TypeScript
435 lines
12 KiB
TypeScript
import React, { useEffect, useState } from 'react'
|
|
import { getCookie, setCookie } from 'cookies-next'
|
|
import { useRouter } from 'next/router'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
import {
|
|
Dialog,
|
|
DialogTrigger,
|
|
DialogClose,
|
|
DialogTitle,
|
|
} from '~components/Dialog'
|
|
import DialogContent from '~components/DialogContent'
|
|
|
|
import Button from '~components/Button'
|
|
import InputTableField from '~components/InputTableField'
|
|
import SelectTableField from '~components/SelectTableField'
|
|
import SliderTableField from '~components/SliderTableField'
|
|
import SwitchTableField from '~components/SwitchTableField'
|
|
import SelectItem from '~components/SelectItem'
|
|
|
|
import type { DialogProps } from '@radix-ui/react-dialog'
|
|
|
|
import CrossIcon from '~public/icons/Cross.svg'
|
|
import './index.scss'
|
|
|
|
interface Props extends DialogProps {
|
|
defaultFilterSet: FilterSet
|
|
filterSet: FilterSet
|
|
sendAdvancedFilters: (filters: FilterSet) => void
|
|
}
|
|
|
|
const MAX_CHARACTERS = 5
|
|
const MAX_WEAPONS = 13
|
|
const MAX_SUMMONS = 8
|
|
|
|
const FilterModal = (props: Props) => {
|
|
// Set up router
|
|
const router = useRouter()
|
|
const locale = router.locale
|
|
|
|
// Set up translation
|
|
const { t } = useTranslation('common')
|
|
|
|
// Refs
|
|
const headerRef = React.createRef<HTMLDivElement>()
|
|
const footerRef = React.createRef<HTMLDivElement>()
|
|
|
|
// States
|
|
const [open, setOpen] = useState(false)
|
|
const [chargeAttackOpen, setChargeAttackOpen] = useState(false)
|
|
const [fullAutoOpen, setFullAutoOpen] = useState(false)
|
|
const [autoGuardOpen, setAutoGuardOpen] = useState(false)
|
|
const [filterSet, setFilterSet] = useState<FilterSet>({})
|
|
|
|
// Filter states
|
|
const [fullAuto, setFullAuto] = useState(props.defaultFilterSet.full_auto)
|
|
const [autoGuard, setAutoGuard] = useState(props.defaultFilterSet.auto_guard)
|
|
const [chargeAttack, setChargeAttack] = useState(
|
|
props.defaultFilterSet.charge_attack
|
|
)
|
|
const [minCharacterCount, setMinCharacterCount] = useState(
|
|
props.defaultFilterSet.characters_count
|
|
)
|
|
const [minWeaponCount, setMinWeaponCount] = useState(
|
|
props.defaultFilterSet.weapons_count
|
|
)
|
|
const [minSummonCount, setMinSummonCount] = useState(
|
|
props.defaultFilterSet.summons_count
|
|
)
|
|
const [maxButtonsCount, setMaxButtonsCount] = useState(
|
|
props.defaultFilterSet.button_count
|
|
)
|
|
const [maxTurnsCount, setMaxTurnsCount] = useState(
|
|
props.defaultFilterSet.turn_count
|
|
)
|
|
const [userQuality, setUserQuality] = useState(
|
|
props.defaultFilterSet.user_quality
|
|
)
|
|
const [nameQuality, setNameQuality] = useState(
|
|
props.defaultFilterSet.name_quality
|
|
)
|
|
const [originalOnly, setOriginalOnly] = useState(
|
|
props.defaultFilterSet.original
|
|
)
|
|
|
|
// Hooks
|
|
useEffect(() => {
|
|
if (props.open !== undefined) setOpen(props.open)
|
|
})
|
|
|
|
useEffect(() => {
|
|
setFilterSet(props.filterSet)
|
|
}, [props.filterSet])
|
|
|
|
useEffect(() => {
|
|
setFullAuto(filterSet.full_auto)
|
|
setAutoGuard(filterSet.auto_guard)
|
|
setChargeAttack(filterSet.charge_attack)
|
|
|
|
setMinCharacterCount(filterSet.characters_count)
|
|
setMinSummonCount(filterSet.summons_count)
|
|
setMinWeaponCount(filterSet.weapons_count)
|
|
|
|
setMaxButtonsCount(filterSet.button_count)
|
|
setMaxTurnsCount(filterSet.turn_count)
|
|
|
|
setNameQuality(filterSet.name_quality)
|
|
setUserQuality(filterSet.user_quality)
|
|
setOriginalOnly(filterSet.original)
|
|
}, [filterSet])
|
|
|
|
function openSelect(name: 'charge_attack' | 'full_auto' | 'auto_guard') {
|
|
setChargeAttackOpen(name === 'charge_attack' ? !chargeAttackOpen : false)
|
|
setFullAutoOpen(name === 'full_auto' ? !fullAutoOpen : false)
|
|
setAutoGuardOpen(name === 'auto_guard' ? !autoGuardOpen : false)
|
|
}
|
|
|
|
function saveFilters() {
|
|
const filters: FilterSet = {}
|
|
filters.full_auto = fullAuto
|
|
filters.auto_guard = autoGuard
|
|
filters.charge_attack = chargeAttack
|
|
filters.characters_count = minCharacterCount
|
|
filters.weapons_count = minWeaponCount
|
|
filters.summons_count = minSummonCount
|
|
filters.name_quality = nameQuality
|
|
filters.user_quality = userQuality
|
|
filters.original = originalOnly
|
|
|
|
if (maxButtonsCount) filters.button_count = maxButtonsCount
|
|
if (maxTurnsCount) filters.turn_count = maxTurnsCount
|
|
|
|
setCookie('filters', filters, { path: '/' })
|
|
props.sendAdvancedFilters(filters)
|
|
openChange()
|
|
}
|
|
|
|
function resetFilters() {
|
|
setFullAuto(props.defaultFilterSet.full_auto)
|
|
setAutoGuard(props.defaultFilterSet.auto_guard)
|
|
setChargeAttack(props.defaultFilterSet.charge_attack)
|
|
setMinCharacterCount(props.defaultFilterSet.characters_count)
|
|
setMinWeaponCount(props.defaultFilterSet.weapons_count)
|
|
setMinSummonCount(props.defaultFilterSet.summons_count)
|
|
setMaxButtonsCount(props.defaultFilterSet.button_count)
|
|
setMaxTurnsCount(props.defaultFilterSet.turn_count)
|
|
setUserQuality(props.defaultFilterSet.user_quality)
|
|
setNameQuality(props.defaultFilterSet.name_quality)
|
|
setOriginalOnly(props.defaultFilterSet.original)
|
|
}
|
|
|
|
function openChange() {
|
|
if (open) {
|
|
setOpen(false)
|
|
if (props.onOpenChange) props.onOpenChange(false)
|
|
} else {
|
|
setOpen(true)
|
|
if (props.onOpenChange) props.onOpenChange(true)
|
|
}
|
|
}
|
|
|
|
function onEscapeKeyDown(event: KeyboardEvent) {
|
|
event.preventDefault()
|
|
openChange()
|
|
}
|
|
|
|
function onOpenAutoFocus(event: Event) {
|
|
event.preventDefault()
|
|
}
|
|
|
|
// Value listeners
|
|
function handleChargeAttackValueChange(value: string) {
|
|
setChargeAttack(parseInt(value))
|
|
}
|
|
|
|
function handleFullAutoValueChange(value: string) {
|
|
const newValue = parseInt(value)
|
|
setFullAuto(newValue)
|
|
if (newValue === 0 || (newValue === -1 && autoGuard === 1))
|
|
setAutoGuard(newValue)
|
|
}
|
|
|
|
function handleAutoGuardValueChange(value: string) {
|
|
const newValue = parseInt(value)
|
|
setAutoGuard(newValue)
|
|
if (newValue === 1 || (newValue === -1 && fullAuto === 0))
|
|
setFullAuto(newValue)
|
|
}
|
|
|
|
function handleMinCharactersValueChange(value: number) {
|
|
setMinCharacterCount(value)
|
|
}
|
|
|
|
function handleMinSummonsValueChange(value: number) {
|
|
setMinSummonCount(value)
|
|
}
|
|
|
|
function handleMinWeaponsValueChange(value: number) {
|
|
setMinWeaponCount(value)
|
|
}
|
|
|
|
function handleMaxButtonsCountValueChange(value: number) {
|
|
setMaxButtonsCount(value)
|
|
}
|
|
|
|
function handleMaxTurnsCountValueChange(value: number) {
|
|
setMaxTurnsCount(value)
|
|
}
|
|
|
|
function handleNameQualityValueChange(value: boolean) {
|
|
setNameQuality(value)
|
|
}
|
|
|
|
function handleUserQualityValueChange(value: boolean) {
|
|
setUserQuality(value)
|
|
}
|
|
|
|
function handleOriginalOnlyValueChange(value: boolean) {
|
|
setOriginalOnly(value)
|
|
}
|
|
|
|
// Sliders
|
|
const minCharactersField = () => (
|
|
<SliderTableField
|
|
name="min_characters"
|
|
description={t('modals.filters.descriptions.min_characters')}
|
|
label={t('modals.filters.labels.min_characters')}
|
|
value={minCharacterCount}
|
|
min={0}
|
|
max={MAX_CHARACTERS}
|
|
step={1}
|
|
onValueChange={handleMinCharactersValueChange}
|
|
/>
|
|
)
|
|
|
|
const minWeaponsField = () => (
|
|
<SliderTableField
|
|
name="min_weapons"
|
|
description={t('modals.filters.descriptions.min_weapons')}
|
|
label={t('modals.filters.labels.min_weapons')}
|
|
value={minWeaponCount}
|
|
min={0}
|
|
max={MAX_WEAPONS}
|
|
step={1}
|
|
onValueChange={handleMinWeaponsValueChange}
|
|
/>
|
|
)
|
|
|
|
const minSummonsField = () => (
|
|
<SliderTableField
|
|
name="min_summons"
|
|
description={t('modals.filters.descriptions.min_summons')}
|
|
label={t('modals.filters.labels.min_summons')}
|
|
value={minSummonCount}
|
|
min={0}
|
|
max={MAX_SUMMONS}
|
|
step={1}
|
|
onValueChange={handleMinSummonsValueChange}
|
|
/>
|
|
)
|
|
|
|
// Selects
|
|
const fullAutoField = () => (
|
|
<SelectTableField
|
|
name="full_auto"
|
|
label={t('modals.filters.labels.full_auto')}
|
|
open={fullAutoOpen}
|
|
value={`${fullAuto}`}
|
|
onOpenChange={() => openSelect('full_auto')}
|
|
onClose={() => setFullAutoOpen(false)}
|
|
onChange={handleFullAutoValueChange}
|
|
>
|
|
<SelectItem key="on-off" value="-1">
|
|
{t('modals.filters.options.on_and_off')}
|
|
</SelectItem>
|
|
<SelectItem key="on" value="1">
|
|
{t('modals.filters.options.on')}
|
|
</SelectItem>
|
|
<SelectItem key="off" value="0">
|
|
{t('modals.filters.options.off')}
|
|
</SelectItem>
|
|
</SelectTableField>
|
|
)
|
|
|
|
const autoGuardField = () => (
|
|
<SelectTableField
|
|
name="auto_guard"
|
|
label={t('modals.filters.labels.auto_guard')}
|
|
open={autoGuardOpen}
|
|
value={`${autoGuard}`}
|
|
onOpenChange={() => openSelect('auto_guard')}
|
|
onClose={() => setAutoGuardOpen(false)}
|
|
onChange={handleAutoGuardValueChange}
|
|
>
|
|
<SelectItem key="on-off" value="-1">
|
|
{t('modals.filters.options.on_and_off')}
|
|
</SelectItem>
|
|
<SelectItem key="on" value="1">
|
|
{t('modals.filters.options.on')}
|
|
</SelectItem>
|
|
<SelectItem key="off" value="0">
|
|
{t('modals.filters.options.off')}
|
|
</SelectItem>
|
|
</SelectTableField>
|
|
)
|
|
|
|
const chargeAttackField = () => (
|
|
<SelectTableField
|
|
name="charge_attack"
|
|
label={t('modals.filters.labels.charge_attack')}
|
|
open={chargeAttackOpen}
|
|
value={`${chargeAttack}`}
|
|
onOpenChange={() => openSelect('charge_attack')}
|
|
onClose={() => setChargeAttackOpen(false)}
|
|
onChange={handleChargeAttackValueChange}
|
|
>
|
|
<SelectItem key="on-off" value="-1">
|
|
{t('modals.filters.options.on_and_off')}
|
|
</SelectItem>
|
|
<SelectItem key="on" value="1">
|
|
{t('modals.filters.options.on')}
|
|
</SelectItem>
|
|
<SelectItem key="off" value="0">
|
|
{t('modals.filters.options.off')}
|
|
</SelectItem>
|
|
</SelectTableField>
|
|
)
|
|
|
|
// Switches
|
|
const nameQualityField = () => (
|
|
<SwitchTableField
|
|
name="name_quality"
|
|
label={t('modals.filters.labels.name_quality')}
|
|
value={nameQuality}
|
|
onValueChange={handleNameQualityValueChange}
|
|
/>
|
|
)
|
|
|
|
const userQualityField = () => (
|
|
<SwitchTableField
|
|
name="user_quality"
|
|
label={t('modals.filters.labels.user_quality')}
|
|
value={userQuality}
|
|
onValueChange={handleUserQualityValueChange}
|
|
/>
|
|
)
|
|
|
|
const originalOnlyField = () => (
|
|
<SwitchTableField
|
|
name="original_only"
|
|
label={t('modals.filters.labels.original_only')}
|
|
value={originalOnly}
|
|
onValueChange={handleOriginalOnlyValueChange}
|
|
/>
|
|
)
|
|
|
|
// Inputs
|
|
const maxButtonsField = () => (
|
|
<InputTableField
|
|
name="min_characters"
|
|
description={t('modals.filters.descriptions.max_buttons')}
|
|
placeholder="0"
|
|
label={t('modals.filters.labels.max_buttons')}
|
|
value={maxButtonsCount}
|
|
onValueChange={handleMaxButtonsCountValueChange}
|
|
/>
|
|
)
|
|
|
|
const maxTurnsField = () => (
|
|
<InputTableField
|
|
name="min_turns"
|
|
description={t('modals.filters.descriptions.max_turns')}
|
|
placeholder="0"
|
|
label={t('modals.filters.labels.max_turns')}
|
|
value={maxTurnsCount}
|
|
onValueChange={handleMaxTurnsCountValueChange}
|
|
/>
|
|
)
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={openChange}>
|
|
<DialogTrigger asChild>{props.children}</DialogTrigger>
|
|
<DialogContent
|
|
className="Filter"
|
|
headerref={headerRef}
|
|
footerref={footerRef}
|
|
onEscapeKeyDown={onEscapeKeyDown}
|
|
onOpenAutoFocus={onOpenAutoFocus}
|
|
>
|
|
<div className="DialogHeader" ref={headerRef}>
|
|
<div className="DialogTop">
|
|
<DialogTitle className="DialogTitle">
|
|
{t('modals.filters.title')}
|
|
</DialogTitle>
|
|
</div>
|
|
<DialogClose className="DialogClose" asChild>
|
|
<span>
|
|
<CrossIcon />
|
|
</span>
|
|
</DialogClose>
|
|
</div>
|
|
|
|
<div className="Fields">
|
|
{chargeAttackField()}
|
|
{fullAutoField()}
|
|
{autoGuardField()}
|
|
{/* {maxButtonsField()} */}
|
|
{/* {maxTurnsField()} */}
|
|
{minCharactersField()}
|
|
{minSummonsField()}
|
|
{minWeaponsField()}
|
|
{nameQualityField()}
|
|
{userQualityField()}
|
|
{originalOnlyField()}
|
|
</div>
|
|
<div className="DialogFooter" ref={footerRef}>
|
|
<div className="Buttons Spaced">
|
|
<Button
|
|
blended={true}
|
|
text={t('modals.filters.buttons.clear')}
|
|
onClick={resetFilters}
|
|
/>
|
|
<Button
|
|
contained={true}
|
|
text={t('modals.filters.buttons.confirm')}
|
|
onClick={saveFilters}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|
|
|
|
export default FilterModal
|