on 261ea40 help sign in
bridge/src/lib/useInputs.js
277 lines 6.4 kB history raw
1import React, { useCallback, useMemo } from 'react';
2import { AccessoryIcon, useForm } from 'indigo-react';
3import { identity } from 'lodash';
5import { DEFAULT_HD_PATH } from 'lib/wallet';
6import {
7 validateNotEmpty,
8 validateMnemonic,
9 validatePoint,
10 validateTicket,
11 validateEmail,
12 validateLength,
13 validateHexString,
14 validateOneOf,
15 validateMaximumPatpByteLength,
16 validateEthereumAddress,
17 validateNotNullAddress,
18 validateGreaterThan,
19} from 'lib/validators';
20import { prependSig, convertToNumber } from 'lib/transformers';
22import InputSigil from 'components/InputSigil';
24const PLACEHOLDER_POINT = '~sampel-ponnym';
25const PLACEHOLDER_HD_PATH = DEFAULT_HD_PATH;
26const PLACEHOLDER_MNEMONIC =
27 'example crew supreme gesture quantum web media hazard theory mercy wing kitten';
28const PLACEHOLDER_TICKET = '~sampel-ticlyt-migfun-falmel';
29const PLACEHOLDER_ADDRESS = '0x12345abcdeDB11D175F123F6891AA64F01c24F7d';
30const PLACEHOLDER_PRIVATE_KEY =
31 '0x12345abcdee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
33// pulls out the first input from a useForm() call
34function useFirstOf({ inputs, setValue, ...rest }, mapper = identity) {
35 // ask the mapper function for any values to overwrite
36 const input = {
37 ...inputs[0],
38 ...mapper(inputs[0]),
39 };
40 // memoize the setValue callback for manually setting the value
41 // in response to some imperative event
42 const _setValue = useCallback(value => setValue(input.name, value), [
43 setValue,
44 input.name,
45 ]);
47 // provide the first input as the first element
48 // _and_ as the second element to facilitate destructuring
49 // and then provide the pass/error/setValue/etc properties at the end
50 return [
51 input,
52 input,
53 {
54 ...rest,
55 setValue: _setValue,
56 },
57 ];
60export function usePassphraseInput(props) {
61 return useFirstOf(
62 useForm([
63 {
64 type: 'password',
65 autoComplete: 'off',
66 placeholder: 'Passphrase',
67 ...props,
68 },
69 ])
70 );
73export function useHexInput({ length, ...rest }) {
74 return useFirstOf(
75 useForm([
76 {
77 type: 'text', // or password
78 autoComplete: 'off',
79 placeholder: PLACEHOLDER_PRIVATE_KEY,
80 validators: useMemo(
81 () => [
82 validateHexString,
83 validateLength(length + 2),
84 validateNotEmpty,
85 ],
86 [length]
87 ),
88 ...rest,
89 },
90 ])
91 );
94const kMnemonicValidators = [validateMnemonic, validateNotEmpty];
95export function useMnemonicInput(props) {
96 return useFirstOf(
97 useForm([
98 {
99 type: 'textarea',
100 autoComplete: 'off',
101 placeholder: PLACEHOLDER_MNEMONIC,
102 validators: kMnemonicValidators,
103 ...props,
104 },
105 ])
106 );
109export function useHdPathInput(props) {
110 return useFirstOf(
111 useForm([
112 {
113 type: 'text',
114 autoComplete: 'off',
115 placeholder: PLACEHOLDER_HD_PATH,
116 ...props,
117 },
118 ])
119 );
122const kTicketValidators = [validateTicket, validateNotEmpty];
123//TODO needs to be fancier, displaying sig and dashes instead of •ing all
124const kTicketTransformers = [prependSig];
125export function useTicketInput({ validators = [], deriving = false, ...rest }) {
126 return useFirstOf(
127 useForm([
128 {
129 type: 'password',
130 label: 'Ticket',
131 placeholder: PLACEHOLDER_TICKET,
132 validators: useMemo(() => [...validators, ...kTicketValidators], [
133 validators,
134 ]),
135 transformers: kTicketTransformers,
136 mono: true,
137 ...rest,
138 },
139 ]),
140 ({ error, pass }) => ({
141 accessory: error ? (
142 <AccessoryIcon.Failure />
143 ) : deriving ? (
144 <AccessoryIcon.Pending />
145 ) : pass ? (
146 <AccessoryIcon.Success />
147 ) : null,
148 })
149 );
152const kPointTransformers = [prependSig];
153export function usePointInput({ size = 4, validators = [], ...rest }) {
154 const _validators = useMemo(
155 () => [
156 ...validators,
157 validatePoint,
158 validateMaximumPatpByteLength(size),
159 validateNotEmpty,
160 ],
161 [size, validators]
162 );
164 return useFirstOf(
165 useForm([
166 {
167 type: 'text',
168 label: 'Point',
169 placeholder: PLACEHOLDER_POINT,
170 validators: _validators,
171 transformers: kPointTransformers,
172 mono: true,
173 ...rest,
174 },
175 ]),
176 ({ error, pass, focused, value }) => ({
177 accessory: value ? (
178 <InputSigil
179 patp={value}
180 size={44}
181 margin={8}
182 pass={pass}
183 focused={focused}
184 error={error}
185 />
186 ) : null,
187 })
188 );
191export function useGalaxyInput(props) {
192 return usePointInput({
193 label: 'Galaxy Name',
194 size: 1,
195 ...props,
196 });
199export function useCheckboxInput({ initialValue, ...rest }) {
200 return useFirstOf(
201 useForm([
202 {
203 type: 'checkbox',
204 ...rest,
205 },
206 ])
207 );
210export function useSelectInput({ initialValue, options, ...rest }) {
211 return useFirstOf(
212 useForm([
213 {
214 type: 'select',
215 validators: useMemo(
216 () => [
217 validateOneOf(
218 options.map(option => option.value),
219 validateNotEmpty
220 ),
221 ],
222 [options]
223 ),
224 options,
225 initialValue: initialValue || options[0].value,
226 ...rest,
227 },
228 ])
229 );
232const kAddressValidators = [
233 validateEthereumAddress,
234 validateNotNullAddress,
235 validateNotEmpty,
236];
237export function useAddressInput({ ...rest }) {
238 return useFirstOf(
239 useForm([
240 {
241 type: 'string',
242 label: 'Ethereum Address',
243 placeholder: PLACEHOLDER_ADDRESS,
244 autoComplete: 'off',
245 validators: kAddressValidators,
246 mono: true,
247 ...rest,
248 },
249 ])
250 );
253const kNumberTransformers = [convertToNumber];
254const kNumberValidators = [validateGreaterThan(0)];
255export function useNumberInput({ ...rest }) {
256 return useFirstOf(
257 useForm([
258 {
259 type: 'number',
260 label: 'Number',
261 autoComplete: 'off',
262 transformers: kNumberTransformers,
263 validators: kNumberValidators,
264 ...rest,
265 },
266 ])
267 );
270const kEmailValidators = [validateEmail, validateNotEmpty];
271export const buildEmailInputConfig = extra => ({
272 type: 'email',
273 autoComplete: 'off',
274 validators: kEmailValidators,
275 initialValue: '',
276 ...extra,
277});