on fdeb086 help sign in
bridge/src/form/Inputs.js
229 lines 5.6 kB history raw
1import React from 'react';
2import { Input, AccessoryIcon } from 'indigo-react';
3import { useField } from 'react-final-form';
4import { some } from 'lodash';
6import {
7 validateNotEmpty,
8 validateTicket,
9 kDefaultValidator,
10 validateMnemonic,
11 validatePoint,
12 validateMaximumPatpByteLength,
13 validateOneOf,
14 validateHexString,
15 validateHexLength,
16 validateEthereumAddress,
17} from 'lib/validators';
18import { compose } from 'lib/lib';
19import { prependSig } from 'lib/transformers';
20import { DEFAULT_HD_PATH } from 'lib/wallet';
21import InputSigil from 'components/InputSigil';
23const PLACEHOLDER_POINT = '~sampel-ponnym';
24const PLACEHOLDER_HD_PATH = DEFAULT_HD_PATH;
25const PLACEHOLDER_MNEMONIC =
26 'example crew supreme gesture quantum web media hazard theory mercy wing kitten';
27const PLACEHOLDER_TICKET = '~sampel-ticlyt-migfun-falmel';
28const PLACEHOLDER_ADDRESS = '0x12345abcdeDB11D175F123F6891AA64F01c24F7d';
29const PLACEHOLDER_PRIVATE_KEY =
30 '0x12345abcdee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
32const buildValidator = (
33 validators = [],
34 fn = () => undefined
35) => async value => {
36 return (
37 compose(
38 ...validators,
39 kDefaultValidator
40 )(value).error || (await fn(value))
41 );
42};
44export const hasErrors = obj => some(obj, v => v !== undefined);
46export const buildTicketValidator = (validators = []) =>
47 buildValidator([...validators, validateTicket, validateNotEmpty]);
48export const buildMnemonicValidator = () =>
49 buildValidator([validateMnemonic, validateNotEmpty]);
50export const buildCheckboxValidator = mustBe =>
51 buildValidator([
52 validateOneOf(mustBe !== undefined ? [mustBe] : [true, false]),
53 ]);
54export const buildPassphraseValidator = () => buildValidator([]);
55// TODO: validate hdpath format
56export const buildHdPathValidator = () => buildValidator([validateNotEmpty]);
57export const buildPointValidator = (size = 4) =>
58 buildValidator([
59 validatePoint,
60 validateMaximumPatpByteLength(size),
61 validateNotEmpty,
62 ]);
63export const buildSelectValidator = options =>
64 buildValidator([validateOneOf(options.map(option => option.value))]);
65export const buildHexValidator = length =>
66 buildValidator([
67 validateHexLength(length),
68 validateHexString,
69 validateNotEmpty,
70 ]);
71export const buildUploadValidator = () => buildValidator([validateNotEmpty]);
72export const buildAddressValidator = () =>
73 buildValidator([
74 validateEthereumAddress,
75 validateHexLength(40),
76 validateHexString,
77 validateNotEmpty,
78 ]);
80// the default form validator just returns field-level validations
81const kDefaultFormValidator = (values, errors) => errors;
82export const composeValidator = (
83 fieldValidators = {},
84 formValidator = kDefaultFormValidator
85) => {
86 const names = Object.keys(fieldValidators);
88 const fieldLevelValidators = names.map(name => value =>
89 fieldValidators[name](value)
90 );
92 const fieldLevelValidator = async values => {
93 const errors = await Promise.all(
94 names.map((name, i) => fieldLevelValidators[i](values[name]))
95 );
97 return names.reduce(
98 (memo, name, i) => ({
99 ...memo,
100 [name]: errors[i],
101 }),
102 {}
103 );
104 };
106 return async values => {
107 const errors = await fieldLevelValidator(values);
108 return await formValidator(values, errors);
109 };
110};
112export function TicketInput({ name, ...rest }) {
113 const {
114 meta: { valid, error, validating, touched, active },
115 } = useField(name, {
116 subscription: {
117 valid: true,
118 error: true,
119 validating: true,
120 touched: true,
121 active: true,
122 },
123 });
125 return (
126 <Input
127 type="text"
128 name={name}
129 placeholder={PLACEHOLDER_TICKET}
130 accessory={
131 touched && !active && error ? (
132 <AccessoryIcon.Failure />
133 ) : validating ? (
134 <AccessoryIcon.Pending />
135 ) : valid ? (
136 <AccessoryIcon.Success />
137 ) : null
138 }
139 config={{ format: prependSig }}
140 mono
141 {...rest}
142 />
143 );
146export function MnemonicInput({ ...rest }) {
147 return (
148 <Input type="textarea" placeholder={PLACEHOLDER_MNEMONIC} mono {...rest} />
149 );
152export function HdPathInput({ ...rest }) {
153 return (
154 <Input
155 type="text"
156 placeholder={PLACEHOLDER_HD_PATH}
157 autoComplete="off"
158 {...rest}
159 />
160 );
163export function PassphraseInput({ ...rest }) {
164 return (
165 <Input
166 type="password"
167 placeholder="Passphrase"
168 autoComplete="off"
169 {...rest}
170 />
171 );
174export function PointInput({ name, size = 4, ...rest }) {
175 const {
176 input: { value },
177 meta: { active, valid, error },
178 } = useField(name, {
179 subscription: { value: true, active: true, valid: true, error: true },
180 });
182 return (
183 <Input
184 type="text"
185 label="Point"
186 name={name}
187 placeholder={PLACEHOLDER_POINT}
188 accessory={
189 value ? (
190 <InputSigil
191 patp={value}
192 size={44}
193 margin={8}
194 pass={valid}
195 focused={active}
196 error={error}
197 />
198 ) : null
199 }
200 config={{ format: prependSig }}
201 mono
202 {...rest}
203 />
204 );
207export function HexInput({ ...rest }) {
208 return (
209 <Input
210 type="text"
211 placeholder={PLACEHOLDER_PRIVATE_KEY}
212 autoComplete="off"
213 mono
214 {...rest}
215 />
216 );
219export function AddressInput({ ...rest }) {
220 return (
221 <Input
222 type="text"
223 placeholder={PLACEHOLDER_ADDRESS}
224 autoComplete="off"
225 mono
226 {...rest}
227 />
228 );