From c74ff41479dfd5616b8a35f46774d33758738462 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 23 Dec 2022 18:40:50 -0800 Subject: [PATCH] Implement AwakeningSelect * Has modes for weapons and characters * Shows input when awakening is selected * Saves type and level to server * Redisplays type but level is broken --- components/AwakeningSelect/index.scss | 31 +++++ components/AwakeningSelect/index.tsx | 183 ++++++++++++++++++++++++++ components/Input/index.scss | 6 +- components/Select/index.tsx | 1 - components/WeaponModal/index.tsx | 34 ++++- components/WeaponUnit/index.tsx | 1 + 6 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 components/AwakeningSelect/index.scss create mode 100644 components/AwakeningSelect/index.tsx diff --git a/components/AwakeningSelect/index.scss b/components/AwakeningSelect/index.scss new file mode 100644 index 00000000..56c80b35 --- /dev/null +++ b/components/AwakeningSelect/index.scss @@ -0,0 +1,31 @@ +.AwakeningSelect .AwakeningSet { + .errors { + color: $error; + display: none; + padding: $unit 0; + + &.visible { + display: block; + } + } + + .fields { + display: flex; + flex-direction: row; + gap: $unit; + width: 100%; + + .SelectTrigger { + flex-grow: 1; + } + + .Label { + flex-grow: 0; + + .Input { + min-width: $unit * 12; + width: inherit; + } + } + } +} diff --git a/components/AwakeningSelect/index.tsx b/components/AwakeningSelect/index.tsx new file mode 100644 index 00000000..eb8b6267 --- /dev/null +++ b/components/AwakeningSelect/index.tsx @@ -0,0 +1,183 @@ +import React, { ForwardedRef, useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + +import Input from '~components/Input' +import Select from '~components/Select' +import SelectItem from '~components/SelectItem' + +import classNames from 'classnames' + +import { weaponAwakening, characterAwakening } from '~utils/awakening' +import type { Awakening } from '~utils/awakening' + +import './index.scss' + +interface Props { + object: 'character' | 'weapon' + awakeningType?: number + awakeningLevel?: number + sendValues: (type: number, level: number) => void +} + +const AwakeningSelect = (props: Props) => { + const router = useRouter() + const locale = + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' + const { t } = useTranslation('common') + + const [open, setOpen] = useState(false) + + // Refs + const awakeningLevelInput = React.createRef() + + // States + const [awakeningType, setAwakeningType] = useState(-1) + const [awakeningLevel, setAwakeningLevel] = useState(1) + + const [maxValue, setMaxValue] = useState(1) + + const [error, setError] = useState('') + + // Classes + const inputClasses = classNames({ + Bound: true, + Hidden: awakeningType === -1, + }) + + const errorClasses = classNames({ + errors: true, + visible: error !== '', + }) + + // Set max value based on object type + useEffect(() => { + if (props.object === 'character') setMaxValue(9) + else if (props.object === 'weapon') setMaxValue(15) + }, [props.object]) + + // Set default awakening and level based on object type + useEffect(() => { + let defaultAwakening = 0 + if (props.object === 'weapon') defaultAwakening = -1 + + setAwakeningType( + props.awakeningType != undefined ? props.awakeningType : defaultAwakening + ) + setAwakeningLevel(props.awakeningLevel ? props.awakeningLevel : 1) + }, [props.object, props.awakeningType, props.awakeningLevel]) + + useEffect(() => { + props.sendValues(awakeningType, awakeningLevel) + }, [props.sendValues, awakeningType, awakeningLevel]) + + // Classes + function changeOpen() { + setOpen(!open) + } + + function generateOptions(object: 'character' | 'weapon') { + let options: Awakening[] = [] + if (object === 'character') options = characterAwakening + else if (object === 'weapon') options = weaponAwakening + else return + + let optionElements: React.ReactNode[] = options.map((awakening, i) => { + return ( + + {awakening.name[locale]} + + ) + }) + + if (object === 'weapon') { + optionElements?.unshift( + + {t('ax.no_skill')} + + ) + } + + return optionElements + } + + function handleSelectChange(rawValue: string) { + const value = parseInt(rawValue) + setAwakeningType(value) + } + + function handleInputChange(event: React.ChangeEvent) { + const value = parseFloat(event.target.value) + if (handleLevelError(value)) setAwakeningLevel(value) + } + + function handleLevelError(value: number) { + let error = '' + if (value < 1) { + error = t('awakening.errors.value_too_low', { + minValue: 1, + }) + } else if (value > maxValue) { + error = t('awakening.errors.value_too_high', { + maxValue: maxValue, + }) + } else if (!value || value <= 0) { + error = t('awakening.errors.value_empty') + } else { + error = '' + } + + setError(error) + + return error.length === 0 + } + + const rangeString = (object: 'character' | 'weapon') => { + let minValue = 1 + let maxValue = 1 + + if (object === 'weapon') { + minValue = 1 + maxValue = 15 + } else if (object === 'character') { + minValue = 1 + maxValue = 9 + } else return + + return `${minValue}~${maxValue}` + } + + return ( +
+
+
+ + + +
+

{error}

+
+
+ ) +} + +export default AwakeningSelect diff --git a/components/Input/index.scss b/components/Input/index.scss index 9ec5d332..a55cef8b 100644 --- a/components/Input/index.scss +++ b/components/Input/index.scss @@ -5,7 +5,7 @@ border-radius: 6px; box-sizing: border-box; display: block; - padding: ($unit * 1.5) $unit-2x; + padding: $unit-2x; width: 100%; &.Bound { @@ -15,6 +15,10 @@ background-color: var(--input-bound-bg-hover); } } + + &.Hidden { + display: none; + } } .InputError { diff --git a/components/Select/index.tsx b/components/Select/index.tsx index 17867ee1..cf6e244a 100644 --- a/components/Select/index.tsx +++ b/components/Select/index.tsx @@ -33,7 +33,6 @@ const Select = (props: Props) => { if (props.onValueChange) props.onValueChange(newValue) } - console.log(value) return ( { const [element, setElement] = useState(-1) + const [awakeningType, setAwakeningType] = useState(-1) + const [awakeningLevel, setAwakeningLevel] = useState(1) + const [primaryAxModifier, setPrimaryAxModifier] = useState(-1) const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1) const [primaryAxValue, setPrimaryAxValue] = useState(0.0) @@ -99,6 +105,11 @@ const WeaponModal = (props: Props) => { setFormValid(isValid) } + function receiveAwakeningValues(type: number, level: number) { + setAwakeningType(type) + setAwakeningLevel(level) + } + function receiveElementValue(element: string) { setElement(parseInt(element)) } @@ -125,6 +136,11 @@ const WeaponModal = (props: Props) => { object.weapon.ax_strength2 = secondaryAxValue } + if (props.gridWeapon.object.awakening) { + object.weapon.awakening_type = awakeningType + object.weapon.awakening_level = awakeningLevel + } + return object } @@ -137,7 +153,8 @@ const WeaponModal = (props: Props) => { } function processResult(response: AxiosResponse) { - const gridWeapon: GridWeapon = response.data.grid_weapon + console.log(response) + const gridWeapon: GridWeapon = response.data if (gridWeapon.mainhand) appState.grid.weapons.mainWeapon = gridWeapon else appState.grid.weapons.allWeapons[gridWeapon.position] = gridWeapon @@ -221,6 +238,20 @@ const WeaponModal = (props: Props) => { ) } + const awakeningSelect = () => { + return ( +
+

{t('modals.weapon.subtitles.awakening')}

+ +
+ ) + } + function openChange(open: boolean) { setFormValid(false) setOpen(open) @@ -256,6 +287,7 @@ const WeaponModal = (props: Props) => { ? keySelect() : ''} {props.gridWeapon.object.ax > 0 ? axSelect() : ''} + {props.gridWeapon.awakening ? awakeningSelect() : ''}