on 329f1a9 help sign in
bridge/src/lib/useInputs.js
241 lines 5.8 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 ];
60const kMnemonicValidators = [validateMnemonic, validateNotEmpty];
61export function useMnemonicInput(props) {
62 return useFirstOf(
63 useForm([
64 {
65 type: 'textarea',
66 autoComplete: 'off',
67 placeholder: PLACEHOLDER_MNEMONIC,
68 validators: kMnemonicValidators,
69 ...props,
70 },
71 ])
72 );
75export function useHdPathInput(props) {
76 return useFirstOf(
77 useForm([
78 {
79 type: 'text',
80 autoComplete: 'off',
81 placeholder: PLACEHOLDER_HD_PATH,
82 ...props,
83 },
84 ])
85 );
88const kTicketValidators = [validateTicket, validateNotEmpty];
89//TODO needs to be fancier, displaying sig and dashes instead of •ing all
90const kTicketTransformers = [prependSig];
91export function useTicketInput({ validators = [], deriving = false, ...rest }) {
92 return useFirstOf(
93 useForm([
94 {
95 type: 'password',
96 label: 'Ticket',
97 placeholder: PLACEHOLDER_TICKET,
98 validators: useMemo(() => [...validators, ...kTicketValidators], [
99 validators,
100 ]),
101 transformers: kTicketTransformers,
102 mono: true,
103 ...rest,
104 },
105 ]),
106 ({ error, pass }) => ({
107 accessory: error ? (
108 <AccessoryIcon.Failure />
109 ) : deriving ? (
110 <AccessoryIcon.Pending />
111 ) : pass ? (
112 <AccessoryIcon.Success />
113 ) : null,
114 })
115 );
118const kPointTransformers = [prependSig];
119export function usePointInput({ size = 4, validators = [], ...rest }) {
120 const _validators = useMemo(
121 () => [
122 ...validators,
123 validatePoint,
124 validateMaximumPatpByteLength(size),
125 validateNotEmpty,
126 ],
127 [size, validators]
128 );
130 return useFirstOf(
131 useForm([
132 {
133 type: 'text',
134 label: 'Point',
135 placeholder: PLACEHOLDER_POINT,
136 validators: _validators,
137 transformers: kPointTransformers,
138 mono: true,
139 ...rest,
140 },
141 ]),
142 ({ error, pass, focused, value }) => ({
143 accessory: value ? (
144 <InputSigil
145 patp={value}
146 size={44}
147 margin={8}
148 pass={pass}
149 focused={focused}
150 error={error}
151 />
152 ) : null,
153 })
154 );
157export function useGalaxyInput(props) {
158 return usePointInput({
159 label: 'Galaxy Name',
160 size: 1,
161 ...props,
162 });
165export function useCheckboxInput({ initialValue, ...rest }) {
166 return useFirstOf(
167 useForm([
168 {
169 type: 'checkbox',
170 ...rest,
171 },
172 ])
173 );
176export function useSelectInput({ initialValue, options, ...rest }) {
177 return useFirstOf(
178 useForm([
179 {
180 type: 'select',
181 validators: useMemo(
182 () => [
183 validateOneOf(options.map(option => option.value)),
184 validateNotEmpty,
185 ],
186 [options]
187 ),
188 options,
189 initialValue: initialValue || options[0].value,
190 ...rest,
191 },
192 ])
193 );
196const kAddressValidators = [
197 validateEthereumAddress,
198 validateNotNullAddress,
199 validateNotEmpty,
200];
201export function useAddressInput({ ...rest }) {
202 return useFirstOf(
203 useForm([
204 {
205 type: 'string',
206 label: 'Ethereum Address',
207 placeholder: PLACEHOLDER_ADDRESS,
208 autoComplete: 'off',
209 validators: kAddressValidators,
210 mono: true,
211 ...rest,
212 },
213 ])
214 );
217const kNumberTransformers = [convertToNumber];
218const kNumberValidators = [validateGreaterThan(0)];
219export function useNumberInput({ ...rest }) {
220 return useFirstOf(
221 useForm([
222 {
223 type: 'number',
224 label: 'Number',
225 autoComplete: 'off',
226 transformers: kNumberTransformers,
227 validators: kNumberValidators,
228 ...rest,
229 },
230 ])
231 );
234const kEmailValidators = [validateEmail, validateNotEmpty];
235export const buildEmailInputConfig = extra => ({
236 type: 'email',
237 autoComplete: 'off',
238 validators: kEmailValidators,
239 initialValue: '',
240 ...extra,
241});