feat: error handling on forms

This commit is contained in:
Taranto 2020-10-26 19:48:53 +00:00 committed by Josh Harvey
parent a6bb503b95
commit 7d5d963685
20 changed files with 119 additions and 71 deletions

View file

@ -165,7 +165,7 @@ const groupStriped = elements => {
} }
const ERow = ({ editing, disabled, lastOfGroup }) => { const ERow = ({ editing, disabled, lastOfGroup }) => {
const { errors } = useFormikContext() const { touched, errors, values } = useFormikContext()
const { const {
elements, elements,
enableEdit, enableEdit,
@ -177,7 +177,6 @@ const ERow = ({ editing, disabled, lastOfGroup }) => {
const classes = useStyles() const classes = useStyles()
const { values } = useFormikContext()
const shouldStripe = stripeWhen && stripeWhen(values) && !editing const shouldStripe = stripeWhen && stripeWhen(values) && !editing
const innerElements = shouldStripe ? groupStriped(elements) : elements const innerElements = shouldStripe ? groupStriped(elements) : elements
@ -199,12 +198,14 @@ const ERow = ({ editing, disabled, lastOfGroup }) => {
[classes.lastOfGroup]: lastOfGroup [classes.lastOfGroup]: lastOfGroup
} }
const touchedErrors = R.pick(R.keys(touched), errors)
return ( return (
<Tr <Tr
className={classnames(classNames)} className={classnames(classNames)}
size={rowSize} size={rowSize}
error={errors && errors.length} error={touchedErrors && R.keys(touchedErrors).length > 0}
errorMessage={errors && errors.toString()}> errorMessage={touchedErrors && R.values(touchedErrors).join(', ')}>
{innerElements.map((it, idx) => { {innerElements.map((it, idx) => {
return ( return (
<ECol <ECol

View file

@ -7,7 +7,8 @@ import {
spacer, spacer,
white, white,
tableDoubleHeaderHeight, tableDoubleHeaderHeight,
offColor offColor,
errorColor
} from 'src/styling/variables' } from 'src/styling/variables'
const { tl2, p, label1 } = typographyStyles const { tl2, p, label1 } = typographyStyles
@ -97,5 +98,9 @@ export default {
}, },
actionCol: { actionCol: {
marginLeft: 'auto' marginLeft: 'auto'
},
errorContent: {
padding: [[12, 0, 12, 24]],
color: errorColor
} }
} }

View file

@ -81,7 +81,7 @@ const initialValues = {
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
name: Yup.string() name: Yup.string()
.required() .required()
.max(50, 'Too long') .max(50)
}) })
const MachineNameComponent = ({ nextStep, classes, setQrCode, setName }) => { const MachineNameComponent = ({ nextStep, classes, setQrCode, setName }) => {

View file

@ -5,15 +5,18 @@ import { NumberInput } from 'src/components/inputs/formik'
const currencyMax = 999999999 const currencyMax = 999999999
const DenominationsSchema = Yup.object().shape({ const DenominationsSchema = Yup.object().shape({
top: Yup.number() top: Yup.number()
.required('Required') .label('Cassette 1 (Top)')
.required()
.min(0) .min(0)
.max(currencyMax), .max(currencyMax),
bottom: Yup.number() bottom: Yup.number()
.required('Required') .label('Cassette 2 (Bottom)')
.required()
.min(0) .min(0)
.max(currencyMax), .max(currencyMax),
zeroConfLimit: Yup.number() zeroConfLimit: Yup.number()
.required('Required') .label('0-conf Limit')
.required()
.min(0) .min(0)
.max(currencyMax) .max(currencyMax)
}) })

View file

@ -204,42 +204,55 @@ const percentMax = 100
const currencyMax = 9999999 const currencyMax = 9999999
const schema = Yup.object().shape({ const schema = Yup.object().shape({
cashIn: Yup.number() cashIn: Yup.number()
.label('Cash-in')
.min(0) .min(0)
.max(percentMax) .max(percentMax)
.required('Required'), .required(),
cashOut: Yup.number() cashOut: Yup.number()
.label('Cash-out')
.min(0) .min(0)
.max(percentMax) .max(percentMax)
.required('Required'), .required(),
fixedFee: Yup.number() fixedFee: Yup.number()
.label('Fixed Fee')
.min(0) .min(0)
.max(currencyMax) .max(currencyMax)
.required('Required'), .required(),
minimumTx: Yup.number() minimumTx: Yup.number()
.label('Minimum Tx')
.min(0) .min(0)
.max(currencyMax) .max(currencyMax)
.required('Required') .required()
}) })
const OverridesSchema = Yup.object().shape({ const OverridesSchema = Yup.object().shape({
machine: Yup.string().required('Required'), machine: Yup.string()
cryptoCurrencies: Yup.array().required('Required'), .nullable()
.label('Machine')
.required(),
cryptoCurrencies: Yup.array()
.label('Crypto Currencies')
.required(),
cashIn: Yup.number() cashIn: Yup.number()
.label('Cash-in')
.min(0) .min(0)
.max(percentMax) .max(percentMax)
.required('Required'), .required(),
cashOut: Yup.number() cashOut: Yup.number()
.label('Cash-out')
.min(0) .min(0)
.max(percentMax) .max(percentMax)
.required('Required'), .required(),
fixedFee: Yup.number() fixedFee: Yup.number()
.label('Fixed Fee')
.min(0) .min(0)
.max(currencyMax) .max(currencyMax)
.required('Required'), .required(),
minimumTx: Yup.number() minimumTx: Yup.number()
.label('Minimum Tx')
.min(0) .min(0)
.max(currencyMax) .max(currencyMax)
.required('Required') .required()
}) })
const defaults = { const defaults = {

View file

@ -3,8 +3,6 @@ import * as Yup from 'yup'
import Autocomplete from 'src/components/inputs/formik/Autocomplete.js' import Autocomplete from 'src/components/inputs/formik/Autocomplete.js'
const LANGUAGE_SELECTION_LIMIT = 4
const getFields = (getData, names, configureCoin, auxElements = []) => { const getFields = (getData, names, configureCoin, auxElements = []) => {
return R.filter( return R.filter(
it => R.includes(it.name, names), it => R.includes(it.name, names),
@ -92,8 +90,7 @@ const allFields = (getData, configureCoin, auxElements = []) => {
options: languageData, options: languageData,
valueProp: 'code', valueProp: 'code',
getLabel: R.path(['display']), getLabel: R.path(['display']),
multiple: true, multiple: true
limit: LANGUAGE_SELECTION_LIMIT
} }
}, },
{ {
@ -137,17 +134,34 @@ const overrides = (auxData, auxElements, configureCoin) => {
} }
const LocaleSchema = Yup.object().shape({ const LocaleSchema = Yup.object().shape({
country: Yup.string().required('Required'), country: Yup.string()
fiatCurrency: Yup.string().required('Required'), .label('Country')
languages: Yup.array().required('Required'), .required(),
cryptoCurrencies: Yup.array().required('Required') fiatCurrency: Yup.string()
.label('Fiat Currency')
.required(),
languages: Yup.array()
.label('Languages')
.required()
.max(4),
cryptoCurrencies: Yup.array()
.label('Crypto Currencies')
.required()
}) })
const OverridesSchema = Yup.object().shape({ const OverridesSchema = Yup.object().shape({
machine: Yup.string().required('Required'), machine: Yup.string()
country: Yup.string().required('Required'), .label('Machine')
languages: Yup.array().required('Required'), .required(),
cryptoCurrencies: Yup.array().required('Required') country: Yup.string()
.label('Country')
.required(),
languages: Yup.array()
.label('Languages')
.required(),
cryptoCurrencies: Yup.array()
.label('Crypto Currencies')
.required()
}) })
const localeDefaults = { const localeDefaults = {

View file

@ -15,14 +15,16 @@ import styles from './CashCassettes.styles.js'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const ValidationSchema = Yup.object().shape({ const ValidationSchema = Yup.object().shape({
name: Yup.string().required('Required'), name: Yup.string().required(),
cassette1: Yup.number() cassette1: Yup.number()
.required('Required') .label('Cassette 1 (top)')
.required()
.integer() .integer()
.min(0) .min(0)
.max(500), .max(500),
cassette2: Yup.number() cassette2: Yup.number()
.required('Required') .label('Cassette 2 (bottom)')
.required()
.integer() .integer()
.min(0) .min(0)
.max(500) .max(500)

View file

@ -56,8 +56,12 @@ const CryptoBalanceOverrides = ({ section }) => {
const currencyMax = 9999999 const currencyMax = 9999999
const validationSchema = Yup.object().shape( const validationSchema = Yup.object().shape(
{ {
[CRYPTOCURRENCY_KEY]: Yup.string().required(), [CRYPTOCURRENCY_KEY]: Yup.string()
.label('Cryptocurrency')
.nullable()
.required(),
[LOW_BALANCE_KEY]: Yup.number() [LOW_BALANCE_KEY]: Yup.number()
.label('Low Balance')
.when(HIGH_BALANCE_KEY, { .when(HIGH_BALANCE_KEY, {
is: HIGH_BALANCE_KEY => !HIGH_BALANCE_KEY, is: HIGH_BALANCE_KEY => !HIGH_BALANCE_KEY,
then: Yup.number().required() then: Yup.number().required()
@ -68,6 +72,7 @@ const CryptoBalanceOverrides = ({ section }) => {
.max(currencyMax) .max(currencyMax)
.nullable(), .nullable(),
[HIGH_BALANCE_KEY]: Yup.number() [HIGH_BALANCE_KEY]: Yup.number()
.label('High Balance')
.when(LOW_BALANCE_KEY, { .when(LOW_BALANCE_KEY, {
is: LOW_BALANCE_KEY => !LOW_BALANCE_KEY, is: LOW_BALANCE_KEY => !LOW_BALANCE_KEY,
then: Yup.number().required() then: Yup.number().required()

View file

@ -43,8 +43,12 @@ const FiatBalanceOverrides = ({ section }) => {
const notesMax = 9999999 const notesMax = 9999999
const validationSchema = Yup.object().shape( const validationSchema = Yup.object().shape(
{ {
[MACHINE_KEY]: Yup.string().required(), [MACHINE_KEY]: Yup.string()
.label('Machine')
.nullable()
.required(),
[CASSETTE_1_KEY]: Yup.number() [CASSETTE_1_KEY]: Yup.number()
.label('Cassette 1 (top)')
.when(CASSETTE_2_KEY, { .when(CASSETTE_2_KEY, {
is: CASSETTE_2_KEY => !CASSETTE_2_KEY, is: CASSETTE_2_KEY => !CASSETTE_2_KEY,
then: Yup.number().required() then: Yup.number().required()
@ -55,6 +59,7 @@ const FiatBalanceOverrides = ({ section }) => {
.max(notesMax) .max(notesMax)
.nullable(), .nullable(),
[CASSETTE_2_KEY]: Yup.number() [CASSETTE_2_KEY]: Yup.number()
.label('Cassette 1 (bottom)')
.when(CASSETTE_1_KEY, { .when(CASSETTE_1_KEY, {
is: CASSETTE_1_KEY => !CASSETTE_1_KEY, is: CASSETTE_1_KEY => !CASSETTE_1_KEY,
then: Yup.number().required() then: Yup.number().required()

View file

@ -83,7 +83,7 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
token: Yup.string() token: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
BTCWalletId: Yup.string().max(100, 'Too long'), BTCWalletId: Yup.string().max(100, 'Too long'),
BTCWalletPassphrase: Yup.string() BTCWalletPassphrase: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
@ -121,6 +121,6 @@ export default {
}), }),
environment: Yup.string() environment: Yup.string()
.matches(/(prod|test)/) .matches(/(prod|test)/)
.required('Required') .required()
}) })
} }

View file

@ -32,12 +32,12 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
clientId: Yup.string() clientId: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
key: Yup.string() key: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
secret: Yup.string() secret: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required') .required()
}) })
} }

View file

@ -25,10 +25,10 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
token: Yup.string() token: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
confidenceFactor: Yup.number() confidenceFactor: Yup.number()
.integer('Please input a positive integer') .integer('Please input a positive integer')
.positive('Please input a positive integer') .positive('Please input a positive integer')
.required('Required') .required()
}) })
} }

View file

@ -30,12 +30,12 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
apiKey: Yup.string() apiKey: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
apiSecret: Yup.string() apiSecret: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
endpoint: Yup.string() endpoint: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required') .required()
}) })
} }

View file

@ -36,15 +36,15 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
userId: Yup.string() userId: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
walletId: Yup.string() walletId: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
clientKey: Yup.string() clientKey: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
clientSecret: Yup.string() clientSecret: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required') .required()
}) })
} }

View file

@ -24,9 +24,9 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
apiKey: Yup.string() apiKey: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
privateKey: Yup.string() privateKey: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required') .required()
}) })
} }

View file

@ -33,17 +33,17 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
apiKey: Yup.string() apiKey: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
domain: Yup.string() domain: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
fromEmail: Yup.string() fromEmail: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.email('Please input a valid email address') .email('Please input a valid email address')
.required('Required'), .required(),
toEmail: Yup.string() toEmail: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.email('Please input a valid email address') .email('Please input a valid email address')
.required('Required') .required()
}) })
} }

View file

@ -41,15 +41,15 @@ export default code => ({
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
token: Yup.string() token: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
environment: Yup.string() environment: Yup.string()
.matches(/(prod|test)/) .matches(/(prod|test)/)
.required('Required'), .required(),
[`${code}WalletId`]: Yup.string() [`${code}WalletId`]: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
[`${code}WalletPassphrase`]: Yup.string() [`${code}WalletPassphrase`]: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required') .required()
}) })
}) })

View file

@ -34,15 +34,15 @@ export default {
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
accountSid: Yup.string() accountSid: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
authToken: Yup.string() authToken: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
fromNumber: Yup.string() fromNumber: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required'), .required(),
toNumber: Yup.string() toNumber: Yup.string()
.max(100, 'Too long') .max(100, 'Too long')
.required('Required') .required()
}) })
} }

View file

@ -68,14 +68,14 @@ const useStyles = makeStyles({
} }
}) })
// const direction = Yup.string().required('Required') // const direction = Yup.string().required()
const triggerType = Yup.string().required('Required') const triggerType = Yup.string().required()
const threshold = Yup.object().shape({ const threshold = Yup.object().shape({
threshold: Yup.number(), threshold: Yup.number(),
thresholdDays: Yup.number() thresholdDays: Yup.number()
}) })
const requirement = Yup.object().shape({ const requirement = Yup.object().shape({
requirement: Yup.string().required('Required'), requirement: Yup.string().required(),
suspensionDays: Yup.number() suspensionDays: Yup.number()
}) })

View file

@ -7,10 +7,10 @@ const filterClass = type => R.filter(it => it.class === type)
const filterCoins = ({ id }) => R.filter(it => R.contains(id)(it.cryptos)) const filterCoins = ({ id }) => R.filter(it => R.contains(id)(it.cryptos))
const WalletSchema = Yup.object().shape({ const WalletSchema = Yup.object().shape({
ticker: Yup.string().required('Required'), ticker: Yup.string().required(),
wallet: Yup.string().required('Required'), wallet: Yup.string().required(),
exchange: Yup.string().required('Required'), exchange: Yup.string().required(),
zeroConf: Yup.string().required('Required') zeroConf: Yup.string().required()
}) })
const getElements = ( const getElements = (