Add form validation for AxSelect
We're not done yet, there's still some weird behaviors and a case we haven't properly checked (if second AX skill has a value but first AX skill doesn't)
This commit is contained in:
parent
9b39299a3a
commit
e9546293dc
3 changed files with 117 additions and 30 deletions
|
|
@ -1,30 +1,48 @@
|
|||
.AXSet {
|
||||
.AXSelect {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
gap: $unit;
|
||||
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
.AXSet {
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
select {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.errors {
|
||||
color: $error;
|
||||
display: none;
|
||||
padding: $unit 0;
|
||||
|
||||
.Input {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border: none;
|
||||
background-color: $grey-90;
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
color: $grey-00;
|
||||
height: $unit * 6;
|
||||
display: block;
|
||||
font-size: $font-regular;
|
||||
padding: $unit;
|
||||
text-align: right;
|
||||
min-width: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.fields {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $unit;
|
||||
|
||||
select {
|
||||
flex-grow: 1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Input {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border: none;
|
||||
background-color: $grey-90;
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
color: $grey-00;
|
||||
height: $unit * 6;
|
||||
display: block;
|
||||
font-size: $font-regular;
|
||||
padding: $unit;
|
||||
text-align: right;
|
||||
min-width: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,36 @@ import { axData } from '~utils/axData'
|
|||
|
||||
import './index.scss'
|
||||
|
||||
interface ErrorMap {
|
||||
[index: string]: string
|
||||
axValue1: string
|
||||
axValue2: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
axType: number
|
||||
currentSkills?: SimpleAxSkill[],
|
||||
sendValidity: (isValid: boolean) => void
|
||||
sendValues: (primaryAxModifier: number, primaryAxValue: number, secondaryAxModifier: number, secondaryAxValue: number) => void
|
||||
}
|
||||
|
||||
const AXSelect = (props: Props) => {
|
||||
// Set up form states and error handling
|
||||
const [errors, setErrors] = useState<ErrorMap>({
|
||||
axValue1: '',
|
||||
axValue2: ''
|
||||
})
|
||||
|
||||
const primaryErrorClasses = classNames({
|
||||
'errors': true,
|
||||
'visible': errors.axValue1.length > 0
|
||||
})
|
||||
|
||||
const secondaryErrorClasses = classNames({
|
||||
'errors': true,
|
||||
'visible': errors.axValue2.length > 0
|
||||
})
|
||||
|
||||
// Refs
|
||||
const primaryAxModifierSelect = React.createRef<HTMLSelectElement>()
|
||||
const primaryAxValueInput = React.createRef<HTMLInputElement>()
|
||||
|
|
@ -112,11 +135,44 @@ const AXSelect = (props: Props) => {
|
|||
}
|
||||
|
||||
function handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
let newErrors = {...errors}
|
||||
|
||||
if (primaryAxValueInput.current == event.target) {
|
||||
setPrimaryAxValue(parseFloat(event.target.value))
|
||||
const primaryAxSkill = axData[props.axType - 1][primaryAxModifier]
|
||||
const value = parseFloat(event.target.value)
|
||||
|
||||
if (value < primaryAxSkill.minValue) {
|
||||
newErrors.axValue1 = `${primaryAxSkill.name.en} must be at least ${primaryAxSkill.minValue}${ (primaryAxSkill.suffix) ? primaryAxSkill.suffix : ''}`
|
||||
} else if (value > primaryAxSkill.maxValue) {
|
||||
newErrors.axValue1 = `${primaryAxSkill.name.en} cannot be greater than ${primaryAxSkill.maxValue}${ (primaryAxSkill.suffix) ? primaryAxSkill.suffix : ''}`
|
||||
} else {
|
||||
newErrors.axValue1 = ''
|
||||
setPrimaryAxValue(parseFloat(event.target.value))
|
||||
}
|
||||
} else {
|
||||
setSecondaryAxValue(parseFloat(event.target.value))
|
||||
const primaryAxSkill = axData[props.axType - 1][primaryAxModifier]
|
||||
const value = parseFloat(event.target.value)
|
||||
|
||||
if (primaryAxSkill.secondary) {
|
||||
const secondaryAxSkill = primaryAxSkill.secondary.find(skill => skill.id == secondaryAxModifier)
|
||||
|
||||
if (secondaryAxSkill) {
|
||||
if (value < secondaryAxSkill.minValue) {
|
||||
newErrors.axValue2 = `${secondaryAxSkill.name.en} must be at least ${secondaryAxSkill.minValue}${ (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : ''}`
|
||||
} else if (value > secondaryAxSkill.maxValue) {
|
||||
newErrors.axValue2 = `${secondaryAxSkill.name.en} cannot be greater than ${secondaryAxSkill.maxValue}${ (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : ''}`
|
||||
} else if (!secondaryAxSkill.suffix && value % 1 !== 0) {
|
||||
newErrors.axValue2 = `${secondaryAxSkill.name.en} must be a whole number`
|
||||
} else {
|
||||
newErrors.axValue2 = ''
|
||||
setSecondaryAxValue(parseFloat(event.target.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
props.sendValidity(newErrors.axValue1 === '' && newErrors.axValue2 === '')
|
||||
setErrors(newErrors)
|
||||
}
|
||||
|
||||
function setupInput(ax: AxSkill | undefined, element: HTMLInputElement) {
|
||||
|
|
@ -144,13 +200,19 @@ const AXSelect = (props: Props) => {
|
|||
return (
|
||||
<div className="AXSelect">
|
||||
<div className="AXSet">
|
||||
<select key="ax1" defaultValue={ (props.currentSkills && props.currentSkills[0]) ? props.currentSkills[0].modifier : -1 } onChange={handleSelectChange} ref={primaryAxModifierSelect}>{ generateOptions(0) }</select>
|
||||
<input defaultValue={ (props.currentSkills && props.currentSkills[0]) ? props.currentSkills[0].strength : 0 } className="Input" type="number" onChange={handleInputChange} ref={primaryAxValueInput} disabled />
|
||||
<div className="fields">
|
||||
<select key="ax1" defaultValue={ (props.currentSkills && props.currentSkills[0]) ? props.currentSkills[0].modifier : -1 } onChange={handleSelectChange} ref={primaryAxModifierSelect}>{ generateOptions(0) }</select>
|
||||
<input defaultValue={ (props.currentSkills && props.currentSkills[0]) ? props.currentSkills[0].strength : 0 } className="Input" type="number" onChange={handleInputChange} ref={primaryAxValueInput} disabled />
|
||||
</div>
|
||||
<p className={primaryErrorClasses}>{errors.axValue1}</p>
|
||||
</div>
|
||||
|
||||
<div className={secondarySetClasses}>
|
||||
<select key="ax2" defaultValue={ (props.currentSkills && props.currentSkills[1]) ? props.currentSkills[1].modifier : -1 } onChange={handleSelectChange} ref={secondaryAxModifierSelect}>{ generateOptions(1) }</select>
|
||||
<input defaultValue={ (props.currentSkills && props.currentSkills[1]) ? props.currentSkills[1].strength : 0 } className="Input" type="number" onChange={handleInputChange} ref={secondaryAxValueInput} disabled />
|
||||
<div className="fields">
|
||||
<select key="ax2" defaultValue={ (props.currentSkills && props.currentSkills[1]) ? props.currentSkills[1].modifier : -1 } onChange={handleSelectChange} ref={secondaryAxModifierSelect}>{ generateOptions(1) }</select>
|
||||
<input defaultValue={ (props.currentSkills && props.currentSkills[1]) ? props.currentSkills[1].strength : 0 } className="Input" type="number" onChange={handleInputChange} ref={secondaryAxValueInput} disabled />
|
||||
</div>
|
||||
<p className={secondaryErrorClasses}>{errors.axValue2}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ const WeaponModal = (props: Props) => {
|
|||
|
||||
// State
|
||||
const [open, setOpen] = useState(false)
|
||||
const [formValid, setFormValid] = useState(false)
|
||||
|
||||
const [element, setElement] = useState(-1)
|
||||
const [primaryAxModifier, setPrimaryAxModifier] = useState(-1)
|
||||
|
|
@ -64,6 +65,10 @@ const WeaponModal = (props: Props) => {
|
|||
setSecondaryAxValue(secondaryAxValue)
|
||||
}
|
||||
|
||||
function receiveAxValidity(isValid: boolean) {
|
||||
setFormValid(isValid)
|
||||
}
|
||||
|
||||
function receiveElementValue(element: string) {
|
||||
setElement(parseInt(element))
|
||||
}
|
||||
|
|
@ -164,6 +169,7 @@ const WeaponModal = (props: Props) => {
|
|||
<AXSelect
|
||||
axType={props.gridWeapon.object.ax}
|
||||
currentSkills={props.gridWeapon.ax}
|
||||
sendValidity={receiveAxValidity}
|
||||
sendValues={receiveAxValues}
|
||||
/>
|
||||
</section>
|
||||
|
|
@ -171,6 +177,7 @@ const WeaponModal = (props: Props) => {
|
|||
}
|
||||
|
||||
function openChange(open: boolean) {
|
||||
setFormValid(false)
|
||||
setOpen(open)
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +204,7 @@ const WeaponModal = (props: Props) => {
|
|||
{ (props.gridWeapon.object.element == 0) ? elementSelect() : '' }
|
||||
{ ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) ? keySelect() : '' }
|
||||
{ (props.gridWeapon.object.ax > 0) ? axSelect() : '' }
|
||||
<Button click={updateWeapon}>Save Weapon</Button>
|
||||
<Button click={updateWeapon} disabled={!formValid}>Save Weapon</Button>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
<Dialog.Overlay className="Overlay" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue