on master help sign in
feat: standardize input accessory and put input sigil into usePointInput
f1ff0cfMatt Condon (shrugs)
src/components/Inputs.js+20−31
@@ -1,5 +1,4 @@
1−import React from 'react';
1+import React, { useState } from 'react';
2−import { Input } from 'indigo-react';
3import * as bip39 from 'bip39';
2import * as bip39 from 'bip39';
4
3
5import InputSigil from 'components/InputSigil';
4import InputSigil from 'components/InputSigil';
@@ -85,34 +84,6 @@ export function useHdPathInput(props) {
85// transformers: [prependSig],
84// transformers: [prependSig],
86// });
85// });
87
86
88−export function PointInput(props) {
89− const input = usePointInput({
90− name: 'point',
91− label: 'Point Name',
92− autoFocus: true,
93− });
94− const { data: validPointName, pass, focused, error } = input;
95−
96− return (
97− <Input
98− {...props}
99− {...input}
100− accessory={
101− validPointName && (
102− <InputSigil
103− patp={validPointName}
104− size={68}
105− margin={8}
106− pass={pass}
107− focused={focused}
108− error={error}
109− />
110− )
111− }
112− />
113− );
114−}
115−
116const kTicketValidators = [validateTicket, validateNotEmpty];
87const kTicketValidators = [validateTicket, validateNotEmpty];
117const kTicketTransformers = [prependSig];
88const kTicketTransformers = [prependSig];
118//TODO needs to be fancier, displaying sig and dashes instead of •ing all
89//TODO needs to be fancier, displaying sig and dashes instead of •ing all
@@ -135,7 +106,8 @@ export function useTicketInput({ initialValue = '~', ...rest }) {
135const kPointValidators = [validatePoint, validateNotEmpty];
106const kPointValidators = [validatePoint, validateNotEmpty];
136const kPointTransformers = [prependSig];
107const kPointTransformers = [prependSig];
137export function usePointInput({ initialValue = '~', ...rest }) {
108export function usePointInput({ initialValue = '~', ...rest }) {
109+ const [lastValidPoint, setLastValidPoint] = useState('');
138− return firstOf(
110+ const input = firstOf(
139 useForm([
111 useForm([
140 {
112 {
141 type: 'text',
113 type: 'text',
@@ -144,10 +116,27 @@ export function usePointInput({ initialValue = '~', ...rest }) {
144 transformers: kPointTransformers,
116 transformers: kPointTransformers,
145 mono: true,
117 mono: true,
146 initialValue,
118 initialValue,
119+ onValue: setLastValidPoint,
147 ...rest,
120 ...rest,
148 },
121 },
149 ])
122 ])
150 );
123 );
124+
125+ const { pass, focused, error } = input;
126+
127+ return {
128+ ...input,
129+ accessory: lastValidPoint && (
130+ <InputSigil
131+ patp={lastValidPoint}
132+ size={68}
133+ margin={8}
134+ pass={pass}
135+ focused={focused}
136+ error={error}
137+ />
138+ ),
139+ };
151}
140}
152
141
153const kEmailValidators = [validateEmail, validateNotEmpty];
142const kEmailValidators = [validateEmail, validateNotEmpty];
src/indigo-react/components/AccessoryIcon.jsnew file+32
@@ -0,0 +1,32 @@
1+import React from 'react';
2+
3+import Flex from './Flex';
4+
5+const kPendingAccessory = '⋯';
6+const kSuccessAccessory = '✔';
7+const kFailureAccessory = '×';
8+
9+function AccessoryIcon({ ...props }) {
10+ return (
11+ <Flex
12+ justify="center"
13+ align="center"
14+ style={{ height: '100%', width: '100%' }}
15+ {...props}
16+ />
17+ );
18+}
19+
20+AccessoryIcon.Pending = () => (
21+ <AccessoryIcon>{kPendingAccessory}</AccessoryIcon>
22+);
23+
24+AccessoryIcon.Success = () => (
25+ <AccessoryIcon>{kSuccessAccessory}</AccessoryIcon>
26+);
27+
28+AccessoryIcon.Failure = () => (
29+ <AccessoryIcon>{kFailureAccessory}</AccessoryIcon>
30+);
31+
32+export default AccessoryIcon;
src/indigo-react/index.js+1
@@ -2,6 +2,7 @@ export { default as IndigoApp } from './components/IndigoApp';
2export { default as Grid } from './components/Grid';
2export { default as Grid } from './components/Grid';
3export { default as Flex } from './components/Flex';
3export { default as Flex } from './components/Flex';
4export { default as Input } from './components/Input';
4export { default as Input } from './components/Input';
5+export { default as AccessoryIcon } from './components/AccessoryIcon';
5export { default as Button } from './components/Button';
6export { default as Button } from './components/Button';
6export { default as IconButton } from './components/IconButton';
7export { default as IconButton } from './components/IconButton';
7
8
src/views/Invite/InviteEmail.js+6−17
@@ -10,6 +10,7 @@ import {
10 HelpText,
10 HelpText,
11 Text,
11 Text,
12 ErrorText,
12 ErrorText,
13+ AccessoryIcon,
13} from 'indigo-react';
14} from 'indigo-react';
14import { uniq } from 'lodash';
15import { uniq } from 'lodash';
15
16
@@ -42,7 +43,6 @@ import { useWallet } from 'store/wallet';
42import useSetState from 'lib/useSetState';
43import useSetState from 'lib/useSetState';
43import pluralize from 'lib/pluralize';
44import pluralize from 'lib/pluralize';
44import useMailer from 'lib/useMailer';
45import useMailer from 'lib/useMailer';
45−import useRenderCount from 'lib/useRenderCount';
46
46
47const GAS_PRICE_GWEI = 20; // we pay the premium for faster ux
47const GAS_PRICE_GWEI = 20; // we pay the premium for faster ux
48const GAS_LIMIT = 400000;
48const GAS_LIMIT = 400000;
@@ -78,10 +78,6 @@ const buttonText = (status, count) => {
78 }
78 }
79};
79};
80
80
81−const kPendingAccessory = '⋯';
82−const kSuccessAccessory = '✔';
83−const kFailureAccessory = '×';
84−
85// world's simplest uid
81// world's simplest uid
86let id = 0;
82let id = 0;
87const buildInputConfig = (extra = {}) =>
83const buildInputConfig = (extra = {}) =>
@@ -91,18 +87,11 @@ const buildInputConfig = (extra = {}) =>
91 ...extra,
87 ...extra,
92 });
88 });
93
89
94−const buildAccessoryFor = (dones, errors) => name => (
90+const buildAccessoryFor = (dones, errors) => name => {
95− <Flex
96− justify="center"
97− align="center"
98− style={{ height: '100%', width: '100%' }}>
99− {(() => {
100− if (dones[name]) return kSuccessAccessory;
91+ if (dones[name]) return <AccessoryIcon.Success />;
101− if (errors[name]) return kFailureAccessory;
92+ if (errors[name]) return <AccessoryIcon.Failure />;
102− return kPendingAccessory;
93+ return <AccessoryIcon.Pending />;
103− })()}
104− </Flex>
105−);
94+};
106
95
107// TODO: test with tank, successful txs
96// TODO: test with tank, successful txs
108export default function InviteEmail() {
97export default function InviteEmail() {
src/views/Login/Ticket.js+5−5
@@ -2,7 +2,7 @@ import { Just, Nothing } from 'folktale/maybe';
2import React, { useCallback, useState, useEffect } from 'react';
2import React, { useCallback, useState, useEffect } from 'react';
3import * as azimuth from 'azimuth-js';
3import * as azimuth from 'azimuth-js';
4import * as ob from 'urbit-ob';
4import * as ob from 'urbit-ob';
5−import { Input } from 'indigo-react';
5+import { Input, AccessoryIcon } from 'indigo-react';
6
6
7import View from 'components/View';
7import View from 'components/View';
8import {
8import {
@@ -112,13 +112,13 @@ export default function Ticket({ advanced, loginCompleted }) {
112 Just: status => {
112 Just: status => {
113 switch (status.value) {
113 switch (status.value) {
114 case INPUT_STATUS.SPIN:
114 case INPUT_STATUS.SPIN:
115− return <span>⋯</span>;
115+ return <AccessoryIcon.Pending />;
116 case INPUT_STATUS.GOOD:
116 case INPUT_STATUS.GOOD:
117− return <span>✓</span>;
117+ return <AccessoryIcon.Success />;
118 case INPUT_STATUS.FAIL:
118 case INPUT_STATUS.FAIL:
119− return <span>𐄂</span>;
119+ return <AccessoryIcon.Failure />;
120 default:
120 default:
121− throw new Error('weird input status ' + status.value);
121+ return null;
122 }
122 }
123 },
123 },
124 });
124 });
src/views/Point.js+10−4
@@ -1,4 +1,5 @@
1import React, { useCallback } from 'react';
1import React, { useCallback } from 'react';
2+import Maybe from 'folktale/maybe';
2import * as need from 'lib/need';
3import * as need from 'lib/need';
3import { Grid } from 'indigo-react';
4import { Grid } from 'indigo-react';
4
5
@@ -16,11 +17,12 @@ import { useSyncOwnedPoints } from 'lib/useSyncPoints';
16import { ROUTE_NAMES } from 'lib/routeNames';
17import { ROUTE_NAMES } from 'lib/routeNames';
17
18
18import Actions from './Point/Actions';
19import Actions from './Point/Actions';
20+import { useWallet } from 'store/wallet';
19
21
20export default function Point() {
22export default function Point() {
21 const history = useHistory();
23 const history = useHistory();
22 const { pointCursor } = usePointCursor();
24 const { pointCursor } = usePointCursor();
23− // const { pointCache } = usePointCache();
25+ const { wallet } = useWallet();
24
26
25 const point = need.pointCursor(pointCursor);
27 const point = need.pointCursor(pointCursor);
26
28
@@ -28,6 +30,8 @@ export default function Point() {
28 const { availableInvites } = useInvites(point);
30 const { availableInvites } = useInvites(point);
29 const availableInvitesText = matchBlinky(availableInvites);
31 const availableInvitesText = matchBlinky(availableInvites);
30
32
33+ const showActions = Maybe.Just.hasInstance(wallet);
34+
31 const goInvite = useCallback(() => history.push(ROUTE_NAMES.INVITE), [
35 const goInvite = useCallback(() => history.push(ROUTE_NAMES.INVITE), [
32 history,
36 history,
33 ]);
37 ]);
@@ -48,9 +52,11 @@ export default function Point() {
48 Boot Arvo
52 Boot Arvo
49 </ForwardButton>
53 </ForwardButton>
50 </Grid.Item>
54 </Grid.Item>
55+ {showActions && (
51− <Grid.Item full>
56+ <Grid.Item full>
52− <Actions />
57+ <Actions />
53− </Grid.Item>
58+ </Grid.Item>
59+ )}
54 </Grid>
60 </Grid>
55
61
56 <FooterButton onClick={goInvite}>
62 <FooterButton onClick={goInvite}>
src/views/ViewPoint.js+2−20
@@ -13,19 +13,16 @@ import { ROUTE_NAMES } from 'lib/routeNames';
13import View from 'components/View';
13import View from 'components/View';
14import { ForwardButton } from 'components/Buttons';
14import { ForwardButton } from 'components/Buttons';
15import { usePointInput } from 'components/Inputs';
15import { usePointInput } from 'components/Inputs';
16−import InputSigil from 'components/InputSigil';
17
16
18export default function ViewPoint() {
17export default function ViewPoint() {
19 const history = useHistory();
18 const history = useHistory();
20 const { setPointCursor } = usePointCursor();
19 const { setPointCursor } = usePointCursor();
21− const [lastValidPoint, setLastValidPoint] = useState('');
22 const pointInput = usePointInput({
20 const pointInput = usePointInput({
23 name: 'point',
21 name: 'point',
24 label: 'Point Name',
22 label: 'Point Name',
25 autoFocus: true,
23 autoFocus: true,
26− onValue: setLastValidPoint,
27 });
24 });
28− const { data: pointName, pass, error, focused } = pointInput;
25+ const { data: pointName, pass } = pointInput;
29
26
30 const disabled = !pass;
27 const disabled = !pass;
31 const goForward = useCallback(() => {
28 const goForward = useCallback(() => {
@@ -40,22 +37,7 @@ export default function ViewPoint() {
40
37
41 <P>Enter a point name to view its public information.</P>
38 <P>Enter a point name to view its public information.</P>
42
39
43− <Input
44− {...pointInput}
45− onEnter={goForward}
40+ <Input {...pointInput} onEnter={goForward} />
46− accessory={
47− lastValidPoint && (
48− <InputSigil
49− patp={lastValidPoint}
50− size={68}
51− margin={8}
52− pass={pass}
53− focused={focused}
54− error={error}
55− />
56− )
57− }
58− />
59
41
60 <ForwardButton
42 <ForwardButton
61 className="mt3"
43 className="mt3"