on af19266 help sign in
bridge/src/lib/useInputs.js
244 lines 5.7 kB history raw
1import React, { useCallback, useState, useMemo } from 'react';
2import { AccessoryIcon, useForm } from 'indigo-react';
3import { identity } from 'lodash';
4import * as bip39 from 'bip39';
6import { DEFAULT_HD_PATH } from 'lib/wallet';
7import {
8 validateNotEmpty,
9 validateMnemonic,
10 validatePoint,
11 validateTicket,
12 validateEmail,
13 validateLength,
14 validateHexString,
15 validateOneOf,
16 validateMaximumPatpByteLength,
17 validateEthereumAddress,
18 validateNotNullAddress,
19} from 'lib/validators';
20import { prependSig } from 'lib/transformers';
22import InputSigil from 'components/InputSigil';
24const EXAMPLE_PRIVATE_KEY =
25 '0xa44de2416ee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
27// pulls out the first input from a useForm() call
28function useFirstOf({ inputs, setValue, ...rest }, mapper = identity) {
29 // ask the mapper function for any values to overwrite
30 const input = {
31 ...inputs[0],
32 ...mapper(inputs[0]),
33 };
34 // memoize the setValue callback for manually setting the value
35 // in response to some imperative event
36 const _setValue = useCallback(value => setValue(input.name, value), [
37 setValue,
38 input.name,
39 ]);
41 // provide the first input as the first element
42 // _and_ as the second element to facilitate destructuring
43 // and then provide the pass/error/setValue/etc properties at the end
44 return [
45 input,
46 input,
47 {
48 ...rest,
49 setValue: _setValue,
50 },
51 ];
54export function usePassphraseInput(props) {
55 return useFirstOf(
56 useForm([
57 {
58 type: 'password',
59 autoComplete: 'off',
60 placeholder: 'Passphrase',
61 ...props,
62 },
63 ])
64 );
67export function useHexInput({ length, ...rest }) {
68 return useFirstOf(
69 useForm([
70 {
71 type: 'text', // or password
72 autoComplete: 'off',
73 placeholder: EXAMPLE_PRIVATE_KEY,
74 validators: useMemo(
75 () => [
76 validateHexString,
77 validateLength(length + 2),
78 validateNotEmpty,
79 ],
80 [length]
81 ),
82 ...rest,
83 },
84 ])
85 );
88const kExampleMnemonic = bip39.generateMnemonic();
89const kMnemonicValidators = [validateMnemonic, validateNotEmpty];
90export function useMnemonicInput(props) {
91 return useFirstOf(
92 useForm([
93 {
94 type: 'text',
95 autoComplete: 'off',
96 placeholder: `e.g. ${kExampleMnemonic}`,
97 validators: kMnemonicValidators,
98 ...props,
99 },
100 ])
101 );
104export function useHdPathInput(props) {
105 return useFirstOf(
106 useForm([
107 {
108 type: 'text',
109 autoComplete: 'off',
110 placeholder: `e.g. ${DEFAULT_HD_PATH}`,
111 ...props,
112 },
113 ])
114 );
117const kTicketValidators = [validateTicket, validateNotEmpty];
118//TODO needs to be fancier, displaying sig and dashes instead of •ing all
119const kTicketTransformers = [prependSig];
120export function useTicketInput({ validators = [], deriving = false, ...rest }) {
121 return useFirstOf(
122 useForm([
123 {
124 type: 'password',
125 label: 'Ticket',
126 placeholder: 'e.g. ~ragtyd-modwen-bostec-hinsep',
127 validators: useMemo(() => [...validators, ...kTicketValidators], [
128 validators,
129 ]),
130 transformers: kTicketTransformers,
131 mono: true,
132 ...rest,
133 },
134 ]),
135 ({ error, pass }) => ({
136 accessory: error ? (
137 <AccessoryIcon.Failure />
138 ) : deriving ? (
139 <AccessoryIcon.Pending />
140 ) : pass ? (
141 <AccessoryIcon.Success />
142 ) : null,
143 })
144 );
147const kPointValidators = [
148 validatePoint,
149 validateMaximumPatpByteLength(4),
150 validateNotEmpty,
151];
152const kPointTransformers = [prependSig];
153export function usePointInput(rest) {
154 const [lastValidPoint, setLastValidPoint] = useState('');
155 return useFirstOf(
156 useForm([
157 {
158 type: 'text',
159 label: 'Point',
160 placeholder: 'e.g. ~zod',
161 validators: kPointValidators,
162 transformers: kPointTransformers,
163 mono: true,
164 onValue: setLastValidPoint,
165 ...rest,
166 },
167 ]),
168 ({ error, pass, focused }) => ({
169 accessory: lastValidPoint ? (
170 <InputSigil
171 patp={lastValidPoint}
172 size={44}
173 margin={8}
174 pass={pass}
175 focused={focused}
176 error={error}
177 />
178 ) : null,
179 })
180 );
183export function useCheckboxInput({ initialValue, ...rest }) {
184 return useFirstOf(
185 useForm([
186 {
187 type: 'checkbox',
188 ...rest,
189 },
190 ])
191 );
194export function useSelectInput({ initialValue, options, ...rest }) {
195 return useFirstOf(
196 useForm([
197 {
198 type: 'select',
199 validators: useMemo(
200 () => [
201 validateOneOf(
202 options.map(option => option.value),
203 validateNotEmpty
204 ),
205 ],
206 [options]
207 ),
208 options,
209 initialValue: initialValue || options[0].value,
210 ...rest,
211 },
212 ])
213 );
216const kAddressValidators = [
217 validateEthereumAddress,
218 validateNotNullAddress,
219 validateNotEmpty,
220];
221export function useAddressInput({ ...rest }) {
222 return useFirstOf(
223 useForm([
224 {
225 type: 'string',
226 label: 'Ethereum Address',
227 placeholder: 'e.g. 0x6DEfFb0caFDB11D175F123F6891AA64F01c24F7d',
228 autoComplete: 'off',
229 validators: kAddressValidators,
230 mono: true,
231 ...rest,
232 },
233 ])
234 );
237const kEmailValidators = [validateEmail, validateNotEmpty];
238export const buildEmailInputConfig = extra => ({
239 type: 'email',
240 autoComplete: 'off',
241 validators: kEmailValidators,
242 initialValue: '',
243 ...extra,
244});