diff --git a/common/actions/transaction/actionTypes/fields.ts b/common/actions/transaction/actionTypes/fields.ts index c390844b..3ca3cb1d 100644 --- a/common/actions/transaction/actionTypes/fields.ts +++ b/common/actions/transaction/actionTypes/fields.ts @@ -52,6 +52,7 @@ interface SetToFieldAction { payload: { raw: string; value: Address | null; + error?: string | null; }; } diff --git a/common/actions/transaction/actionTypes/meta.ts b/common/actions/transaction/actionTypes/meta.ts index 3550d79f..3ec3f068 100644 --- a/common/actions/transaction/actionTypes/meta.ts +++ b/common/actions/transaction/actionTypes/meta.ts @@ -7,6 +7,7 @@ interface SetTokenToMetaAction { payload: { raw: string; value: Address | null; + error?: string | null; }; } diff --git a/common/components/AddressField.tsx b/common/components/AddressField.tsx index e70a401a..e1721703 100644 --- a/common/components/AddressField.tsx +++ b/common/components/AddressField.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { AddressFieldFactory } from './AddressFieldFactory'; import { donationAddressMap } from 'config/data'; +import { Aux } from 'components/ui'; interface Props { isReadOnly?: boolean; @@ -8,15 +9,22 @@ interface Props { export const AddressField: React.SFC = ({ isReadOnly }) => ( ( - + withProps={({ currentTo, isValid, onChange, readOnly, errorMsg }) => ( + + + {errorMsg && ( +
+ {errorMsg} +
+ )} +
)} /> ); diff --git a/common/components/AddressFieldFactory/AddressFieldFactory.tsx b/common/components/AddressFieldFactory/AddressFieldFactory.tsx index 813c8ea1..698a7cfc 100644 --- a/common/components/AddressFieldFactory/AddressFieldFactory.tsx +++ b/common/components/AddressFieldFactory/AddressFieldFactory.tsx @@ -18,6 +18,7 @@ export interface CallbackProps { isValid: boolean; readOnly: boolean; currentTo: ICurrentTo; + errorMsg?: string | null; onChange(ev: React.FormEvent): void; } diff --git a/common/components/AddressFieldFactory/AddressInputFactory.tsx b/common/components/AddressFieldFactory/AddressInputFactory.tsx index 3005de68..3b868d17 100644 --- a/common/components/AddressFieldFactory/AddressInputFactory.tsx +++ b/common/components/AddressFieldFactory/AddressInputFactory.tsx @@ -31,7 +31,13 @@ class AddressInputFactoryClass extends Component { - withProps({ currentTo, isValid, onChange, readOnly: !!readOnly }) + withProps({ + currentTo, + isValid, + onChange, + readOnly: !!readOnly, + errorMsg: currentTo.error + }) } /> {/**/} diff --git a/common/reducers/transaction/fields/fields.ts b/common/reducers/transaction/fields/fields.ts index 9cb9c4d0..67d63402 100644 --- a/common/reducers/transaction/fields/fields.ts +++ b/common/reducers/transaction/fields/fields.ts @@ -13,7 +13,7 @@ import { State } from './typings'; import { gasPricetoBase } from 'libs/units'; const INITIAL_STATE: State = { - to: { raw: '', value: null }, + to: { raw: '', value: null, error: null }, data: { raw: '', value: null }, nonce: { raw: '', value: null }, value: { raw: '', value: null }, diff --git a/common/reducers/transaction/meta/meta.ts b/common/reducers/transaction/meta/meta.ts index 57a1e0bf..045c6acb 100644 --- a/common/reducers/transaction/meta/meta.ts +++ b/common/reducers/transaction/meta/meta.ts @@ -18,7 +18,7 @@ const INITIAL_STATE: State = { previousUnit: 'ether', decimal: getDecimalFromEtherUnit('ether'), tokenValue: { raw: '', value: null }, - tokenTo: { raw: '', value: null }, + tokenTo: { raw: '', value: null, error: null }, from: null }; diff --git a/common/sagas/transaction/current/currentTo.ts b/common/sagas/transaction/current/currentTo.ts index 4884a3a7..4bc805f7 100644 --- a/common/sagas/transaction/current/currentTo.ts +++ b/common/sagas/transaction/current/currentTo.ts @@ -3,16 +3,26 @@ import { SetCurrentToAction } from 'actions/transaction/actionTypes/current'; import { setToField } from 'actions/transaction/actionCreators/fields'; import { setTokenTo } from 'actions/transaction/actionCreators/meta'; import { Address } from 'libs/units'; -import { select, call, put, takeEvery } from 'redux-saga/effects'; +import { select, call, put, takeLatest } from 'redux-saga/effects'; import { SagaIterator } from 'redux-saga'; -import { isValidENSorEtherAddress } from 'libs/validators'; +import { isValidENSAddress, isValidETHAddress } from 'libs/validators'; import { TypeKeys } from 'actions/transaction/constants'; export function* setCurrentTo({ payload: raw }: SetCurrentToAction): SagaIterator { - const validAddress: boolean = yield call(isValidENSorEtherAddress, raw); + const validAddress: boolean = yield call(isValidETHAddress, raw); + const validEns: boolean = yield call(isValidENSAddress, raw); const etherTransaction: boolean = yield select(isEtherTransaction); - const value = validAddress ? Address(raw) : null; - const payload = { raw, value }; + + let value: Buffer | null = null; + let error: string | null = null; + if (validAddress) { + value = Address(raw); + } else if (validEns) { + // TODO: Resolve ENS on networks that support it, error on ones that don't + error = 'ENS is not supported yet'; + } + + const payload = { raw, value, error }; if (etherTransaction) { yield put(setToField(payload)); } else { @@ -20,4 +30,4 @@ export function* setCurrentTo({ payload: raw }: SetCurrentToAction): SagaIterato } } -export const currentTo = takeEvery([TypeKeys.CURRENT_TO_SET], setCurrentTo); +export const currentTo = takeLatest([TypeKeys.CURRENT_TO_SET], setCurrentTo); diff --git a/common/selectors/transaction/current.ts b/common/selectors/transaction/current.ts index ee1ce403..e9be7b67 100644 --- a/common/selectors/transaction/current.ts +++ b/common/selectors/transaction/current.ts @@ -12,6 +12,7 @@ interface ICurrentValue { interface ICurrentTo { raw: string; value: Address | null; + error?: string | null; } const isEtherTransaction = (state: AppState) => { diff --git a/spec/sagas/transaction/current/currentTo.spec.ts b/spec/sagas/transaction/current/currentTo.spec.ts index 6f9816f5..7bc601cb 100644 --- a/spec/sagas/transaction/current/currentTo.spec.ts +++ b/spec/sagas/transaction/current/currentTo.spec.ts @@ -3,7 +3,7 @@ import { setToField } from 'actions/transaction/actionCreators/fields'; import { setTokenTo } from 'actions/transaction/actionCreators/meta'; import { Address } from 'libs/units'; import { select, call, put } from 'redux-saga/effects'; -import { isValidENSorEtherAddress } from 'libs/validators'; +import { isValidETHAddress, isValidENSAddress } from 'libs/validators'; import { setCurrentTo } from 'sagas/transaction/current/currentTo'; import { cloneableGenerator } from 'redux-saga/utils'; @@ -13,37 +13,43 @@ describe('setCurrentTo*', () => { payload: raw }; const validAddress = true; + const validEns = false; const etherTransaction = true; const payload = { raw, - value: Address(raw) + value: Address(raw), + error: null }; const gens: any = {}; gens.gen = cloneableGenerator(setCurrentTo)(action); - it('should call isValidENSorEtherAddress', () => { - expect(gens.gen.next().value).toEqual(call(isValidENSorEtherAddress, raw)); + it('should call isValidETHAddress', () => { + expect(gens.gen.next().value).toEqual(call(isValidETHAddress, raw)); + }); + + it('should call isValidENSAddress', () => { + expect(gens.gen.next(validAddress).value).toEqual(call(isValidENSAddress, raw)); }); it('should select isEtherTransaction', () => { - expect(gens.gen.next(validAddress).value).toEqual(select(isEtherTransaction)); + expect(gens.gen.next(validEns).value).toEqual(select(isEtherTransaction)); }); it('should put setToField if etherTransaction', () => { - gens.clone1 = gens.gen.clone(); - expect(gens.clone1.next(etherTransaction).value).toEqual(put(setToField(payload))); + gens.ethTransaction = gens.gen.clone(); + expect(gens.ethTransaction.next(etherTransaction).value).toEqual(put(setToField(payload))); + }); + + it('setToField should be done', () => { + expect(gens.ethTransaction.next().done).toEqual(true); }); it('should put setTokenTo if !etherTransaction', () => { expect(gens.gen.next(!etherTransaction).value).toEqual(put(setTokenTo(payload))); }); - it('should be done', () => { - expect(gens.clone1.next().done).toEqual(true); - }); - - it('should be done', () => { + it('setTokenTo should be done', () => { expect(gens.gen.next().done).toEqual(true); }); });