@@ -14,16 +14,18 @@ import {
1414 validateEmail,
1515 validateNotNullAddress,
1616} from 'lib/validators';
17+import isPromise from 'lib/isPromise';
1718
1819// iterate over validators, exiting early if there's an error
19−const buildValidator = (validators = []) => async value => {
20+const buildValidator = (validators = []) => value => {
2021 for (const validator of validators) {
2122 try {
22− const error = await validator(value);
23+ const error = validator(value);
2324 if (error) {
2425 return error;
2526 }
2627 } catch (error) {
28+ console.error(error);
2729 return error.message;
2830 }
2931 }
@@ -93,26 +95,48 @@ export const composeValidator = (
9395 );
9496
9597 // async reduce errors per-field into an errors object
96− const fieldLevelValidator = async values => {
97− const errors = await Promise.all(
98− names.map((name, i) => fieldLevelValidators[i](values[name]))
98+ const fieldLevelValidator = values => {
99+ const errorsOrPromises = names.map((name, i) =>
100+ fieldLevelValidators[i](values[name])
99101 );
100102
101− return names.reduce(
102− (memo, name, i) => ({
103− ...memo,
104− [name]: errors[i],
105− }),
106− {}
107− );
103+ const reduce = errors =>
104+ names.reduce(
105+ (memo, name, i) => ({
106+ ...memo,
107+ [name]: errors[i],
108+ }),
109+ {}
110+ );
111+
112+ if (some(errorsOrPromises, isPromise)) {
113+ // if any of these results are a promise, await them all then reduce
114+ return Promise.all(errorsOrPromises).then(reduce);
115+ }
116+
117+ // otherwise return immediately
118+ return reduce(errorsOrPromises);
108119 };
109120
110121 // the final-form `validate` function
111− return async values => {
122+ // NOTE: if we return a Promise to final-form it will toggle the `validating`
123+ // state, which is expected. If our promise resolves immediately, however,
124+ // that means our `validating` state flickers the UI and it looks pretty bad.
125+ // The solution is to conditionally return a promise only when necessary.
126+ return values => {
112127 // ask for field-level errors
113− const errors = await fieldLevelValidator(values);
128+ const errorsOrPromise = fieldLevelValidator(values);
129+
114130 // pass the current values and their validity to the form-level validator
115131 // that can implement conditional logic and more complex validations
116− return await formValidator(values, errors);
132+ const runFormValidator = errors => formValidator(values, errors);
133+
134+ if (errorsOrPromise.then) {
135+ // if promise, promise
136+ return errorsOrPromise.then(runFormValidator);
137+ }
138+
139+ // otherwise, it's an errors object
140+ return runFormValidator(errorsOrPromise);
117141 };
118142};