Skip to content

Commit

Permalink
Merge pull request #342 from nowcommunity/fix-time-unit-validator-issue
Browse files Browse the repository at this point in the history
Fix time unit validator issue
  • Loading branch information
Deeroil authored Oct 16, 2024
2 parents f0c34e8 + 65a8344 commit d106b7e
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
61 changes: 61 additions & 0 deletions frontend/src/components/DetailView/common/editingComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,64 @@ export const FieldWithTableSelection = <T extends object, ParentType extends obj
)
return <DataValue<ParentType> field={targetField as keyof EditDataType<ParentType>} EditElement={editingComponent} />
}

export const TimeBoundSelection = <T extends object, ParentType extends object>({
targetField,
sourceField,
selectorTable,
disabled,
}: {
targetField: keyof ParentType
sourceField: keyof T
selectorTable: ReactElement
disabled?: boolean
}) => {
const { editData, setEditData, validator } = useDetailContext<ParentType>()
const { error: boundError } = validator(
editData,
(targetField === 'up_bnd' ? 'up_bound' : 'low_bound') as keyof EditDataType<ParentType>
)
const [open, setOpen] = useState(false)

const selectorFn = (selected: T) => {
if (targetField === 'up_bnd') {
setEditData({ ...editData, [targetField]: selected[sourceField], ['up_bound']: selected })
} else if (targetField === 'low_bnd') {
setEditData({ ...editData, [targetField]: selected[sourceField], ['low_bound']: selected })
}
setOpen(false)
}

const selectorTableWithFn = cloneElement(selectorTable, { selectorFn })
if (open)
return (
<Box>
<Modal
open={open}
aria-labelledby={`modal-${targetField as string}`}
aria-describedby={`modal-${targetField as string}`}
>
<Box sx={{ ...modalStyle }}>
<Box marginBottom="2em" marginTop="1em">
{selectorTableWithFn}
</Box>
<Button onClick={() => setOpen(false)}>Cancel</Button>
</Box>
</Modal>
</Box>
)
const editingComponent = (
<TextField
variant="outlined"
size="small"
error={!!boundError}
helperText={boundError ?? ''}
value={editData[targetField as keyof EditDataType<ParentType>]}
onClick={() => setOpen(true)}
disabled={disabled}
sx={{ backgroundColor: disabled ? 'grey' : '' }}
inputProps={{ readOnly: true }}
/>
)
return <DataValue<ParentType> field={targetField as keyof EditDataType<ParentType>} EditElement={editingComponent} />
}
6 changes: 3 additions & 3 deletions frontend/src/components/TimeUnit/Tabs/TimeUnitTab.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SequenceDetailsType, TimeBoundDetailsType, TimeUnitDetailsType } from '@/backendTypes'
import { FieldWithTableSelection } from '@/components/DetailView/common/editingComponents'
import { FieldWithTableSelection, TimeBoundSelection } from '@/components/DetailView/common/editingComponents'
import { emptyOption } from '@/components/DetailView/common/misc'
import { ArrayFrame } from '@/components/DetailView/common/tabLayoutHelpers'
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
Expand Down Expand Up @@ -59,7 +59,7 @@ export const TimeUnitTab = () => {
const time_bound_edit = [
[
'New Upper Bound',
<FieldWithTableSelection<TimeBoundDetailsType, TimeUnitDetailsType>
<TimeBoundSelection<TimeBoundDetailsType, TimeUnitDetailsType>
key="up_bnd"
sourceField="bid"
targetField="up_bnd"
Expand All @@ -68,7 +68,7 @@ export const TimeUnitTab = () => {
],
[
'New Lower Bound',
<FieldWithTableSelection<TimeBoundDetailsType, TimeUnitDetailsType>
<TimeBoundSelection<TimeBoundDetailsType, TimeUnitDetailsType>
key="low_bnd"
sourceField="bid"
targetField="low_bnd"
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/validators/timeUnit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,24 @@ export const validateTimeUnit = (editData: EditDataType<TimeUnitDetailsType>, fi
required: true,
asNumber: true,
},
up_bound: {
name: 'Upper Bound',
required: true,
miscCheck: () => {
if (editData.low_bound && editData.low_bound.age! < editData.up_bound!.age!)
return 'Upper bound age has to be lower than lower bound age'
return
},
},
low_bound: {
name: 'Lower Bound',
required: true,
miscCheck: () => {
if (editData.up_bound && editData.up_bound.age! > editData.low_bound!.age!)
return 'Lower bound age has to be higher than upper bound age'
return
},
},
}

return validator<EditDataType<TimeUnitDetailsType>>(validators, editData, fieldName)
}
4 changes: 3 additions & 1 deletion frontend/src/validators/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ type Validator = {
maxLength?: number
asNumber?: ((num: number) => ValidationError) | boolean
asString?: ((str: string) => ValidationError) | boolean
miscCheck?: (obj: object) => ValidationError
}

export type Validators<T> = { [field in keyof T]: Validator }

const validate: (validator: Validator, value: unknown) => ValidationError = (validator: Validator, value: unknown) => {
const { required, minLength, maxLength, asNumber, asString } = validator
const { required, minLength, maxLength, asNumber, asString, miscCheck } = validator
if (value === null || value === undefined || value === '') return required ? 'This field is required' : null
if (asNumber) {
if (typeof value !== 'number') return 'Value must be a valid number' // If this happens, code is broken somewhere
Expand All @@ -26,6 +27,7 @@ const validate: (validator: Validator, value: unknown) => ValidationError = (val
if (typeof asString === 'function') return asString(value)
return null
}
if (miscCheck) return miscCheck(value)
return null
}

Expand Down

0 comments on commit d106b7e

Please sign in to comment.