on master help sign in
checkpoint: initial approach to Activate page in figma
commit82d761d29411b7ed26e20d6aef374e39d72169a4 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateWed 26 Jun 2019, 19:00 (7 years ago) parent01c95c6
24 files changed+235−190
src/Bridge.js+1−7 src/components/AspectRatio.js+22 src/components/InputSigil.js+3−3 src/components/Inputs.js+2 src/components/MaybeSigil.js+21 src/components/Passport.js+22−9 src/components/old/Header.js−62 src/indigo-react/components/Input.js+2−1 src/indigo-react/lib/useForm.js+1−1 src/lib/patp2dec.js+9 src/lib/routeNames.js+1−1 src/lib/router.js+2−50 src/lib/useImpliedPoint.js+14 src/lib/useRenderCount.js+2−2 src/lib/useSyncPoints.js+23−30 src/lib/validators.js+30−7 src/store/lib/usePointStore.js+9−2 src/views/Activate.js+61 src/views/CreateGalaxy.js+1−1 src/views/Landing.js+5−5 src/views/Login/Shards.js−1 src/views/Login/Ticket.js+1−3 src/views/Point.js+1−1 src/views/ViewPoint.js+2−4
src/Bridge.js+1−7
@@ -22,13 +22,7 @@ const kInitialNetworkType = isDevelopment
2222const shouldStubLocal = process.env.REACT_APP_STUB_LOCAL === 'true';
2323const kIsStubbed = isDevelopment && shouldStubLocal;
2424const kInitialRoutes = kIsStubbed
25− ? [
26− { key: ROUTE_NAMES.LANDING },
27− { key: ROUTE_NAMES.LOGIN },
28− { key: ROUTE_NAMES.POINTS },
29− { key: ROUTE_NAMES.POINT },
30− { key: ROUTE_NAMES.INVITE },
31− ]
25+ ? [{ key: ROUTE_NAMES.LANDING }, { key: ROUTE_NAMES.ACTIVATE }]
3226 : [{ key: ROUTE_NAMES.LANDING }];
3327
3428const kInitialWallet = kIsStubbed
src/components/AspectRatio.jsnew file+22
@@ -0,0 +1,22 @@
1+import React from 'react';
2+
3+/**
4+ * A very useful Flutter widget reimplemented with
5+ * the world's dumbest css hack.
6+ *
7+ * Simply: container div with appropriate relative padding,
8+ * then absolutely pin the child.
9+ *
10+ * via: https://www.w3schools.com/howto/howto_css_aspect_ratio.asp
11+ */
12+export default function AspectRatio({ aspectRatio = 1, children }) {
13+ const percent = `${(1 / aspectRatio) * 100}%`;
14+
15+ return (
16+ <div className="rel" style={{ paddingTop: percent }}>
17+ <div className="abs" style={{ top: 0, bottom: 0, left: 0, right: 0 }}>
18+ {children}
19+ </div>
20+ </div>
21+ );
22+}
src/components/InputSigil.js+3−3
@@ -1,8 +1,8 @@
11import React from 'react';
2−import cn from 'classnames';
32import * as ob from 'urbit-ob';
43
54import Sigil from './Sigil';
5+import AspectRatio from './AspectRatio';
66
77const selectColorway = (pass, fail, focused) => {
88 if (pass) {
@@ -20,7 +20,7 @@ const selectColorway = (pass, fail, focused) => {
2020 return ['#FFFFFF', '#7F7F7F'];
2121};
2222
23−export default function ValidatedSigil({
23+export default function InputSigil({
2424 className,
2525 patp,
2626 size,
@@ -35,6 +35,6 @@ export default function ValidatedSigil({
3535 return valid ? (
3636 <Sigil patp={patp} size={size} colorway={colorway} margin={0} {...rest} />
3737 ) : (
38− <div className={cn('bg-transparent', className)} />
38+ <AspectRatio aspectRatio={1} />
3939 );
4040}
src/components/Inputs.js+2
@@ -92,6 +92,7 @@ export function useTicketInput({ initialValue = '~', ...rest }) {
9292 useForm([
9393 {
9494 type: 'password',
95+ label: 'Ticket',
9596 placeholder: '~master-ticket',
9697 validators: kTicketValidators,
9798 transformers: kTicketTransformers,
@@ -111,6 +112,7 @@ export function usePointInput({ initialValue = '~', ...rest }) {
111112 useForm([
112113 {
113114 type: 'text',
115+ label: 'Point',
114116 placeholder: 'e.g. ~zod',
115117 validators: kPointValidators,
116118 transformers: kPointTransformers,
src/components/MaybeSigil.jsnew file+21
@@ -0,0 +1,21 @@
1+import React from 'react';
2+import * as ob from 'urbit-ob';
3+
4+import Sigil from './Sigil';
5+import AspectRatio from './AspectRatio';
6+
7+/**
8+ * patp is Maybe<string>
9+ */
10+export default function MaybeSigil({ className, patp, size, ...rest }) {
11+ const validPatp = patp.matchWith({
12+ Nothing: () => null,
13+ Just: p => (ob.isValidPatp(p.value) ? p.value : null),
14+ });
15+
16+ return validPatp ? (
17+ <Sigil patp={validPatp} size={size} margin={0} {...rest} />
18+ ) : (
19+ <AspectRatio aspectRatio={1} />
20+ );
21+}
src/components/Passport.js+22−9
@@ -1,4 +1,6 @@
11import React from 'react';
2+import cn from 'classnames';
3+import Maybe from 'folktale/maybe';
24import * as ob from 'urbit-ob';
35import { Grid, Flex } from 'indigo-react';
46import { times } from 'lodash';
@@ -6,32 +8,43 @@ import { times } from 'lodash';
68import usePointBirthday from 'lib/usePointBirthday';
79import { formatDots } from 'lib/dateFormat';
810
9−import Sigil from './Sigil';
1011import Blinky, { kLoadingCharacter, kInterstitialCharacter } from './Blinky';
12+import MaybeSigil from './MaybeSigil';
1113
1214const buildDate = char =>
1315 [4, 2, 2].map(t => times(t, () => char).join('')).join('.');
1416const kDateA = buildDate(kLoadingCharacter);
1517const kDateB = buildDate(kInterstitialCharacter);
1618
17−export default function Passport({ point }) {
18− const birthday = usePointBirthday(point);
19− const birthDate = birthday.matchWith({
19+/**
20+ * point is Maybe<number>
21+ */
22+export default function Passport({ point, className }) {
23+ const birthday = usePointBirthday(point.getOrElse(null));
24+ const visualBirthday = birthday.matchWith({
2025 Nothing: () => <Blinky a={kDateA} b={kDateB} />,
2126 Just: p => formatDots(p.value),
2227 });
23− const name = ob.patp(point);
28+
29+ const name = point.matchWith({
30+ Nothing: () => Maybe.Nothing(),
31+ Just: p => Maybe.Just(ob.patp(p.value)),
32+ });
33+ const visualName = name.matchWith({
34+ Nothing: () => '...',
35+ Just: p => p.value,
36+ });
2437
2538 return (
26− <Grid gap={16} className="bg-black r8 p7">
39+ <Grid gap={16} className={cn('bg-black r8 p7', className)}>
2740 <Grid.Item cols={[1, 4]} className="bg-green">
28− <Sigil patp={name} size={64} margin={0} />
41+ <MaybeSigil patp={name} size={64} margin={0} />
2942 </Grid.Item>
3043 <Grid.Item as={Flex} cols={[4, 13]} col justify="between">
31− <Flex.Item className="mono white f5">{name}</Flex.Item>
44+ <Flex.Item className="mono white f5">{visualName}</Flex.Item>
3245 <Flex.Item as={Flex} col>
3346 <Flex.Item className="mono gray4 f6 uppercase">Birth Time</Flex.Item>
34− <Flex.Item className="mono gray4 f6">{birthDate}</Flex.Item>
47+ <Flex.Item className="mono gray4 f6">{visualBirthday}</Flex.Item>
3548 </Flex.Item>
3649 </Grid.Item>
3750 </Grid>
src/components/old/Header.jsdeleted−62
@@ -1,62 +0,0 @@
1−import React from 'react';
2−import { Button } from './Base';
3−
4−import { getRouteBreadcrumb } from '../../lib/router';
5−import { ROUTE_NAMES } from '../../lib/routeNames';
6−import { useHistory } from '../../store/history';
7−import { isLast } from '../../lib/lib';
8−import { usePointCursor } from '../../store/pointCursor';
9−
10−// hook to create a breadcrumb builder function based on the current
11−// global states
12−function useRouteBreadcrumbBuilder() {
13− const { pointCursor } = usePointCursor();
14−
15− return getRouteBreadcrumb({ pointCursor });
16−}
17−
18−function Crumbs(props) {
19− const history = useHistory();
20− const breadcrumbBuilder = useRouteBreadcrumbBuilder();
21−
22− return (
23− <>
24− {history.routes.map((route, idx) => {
25− return (
26− <div key={`history-${idx}`} className={'flex items-center'}>
27− <Button
28− prop-type={'link'}
29− prop-size={'sm'}
30− onClick={() => history.pop(history.size - idx - 1)}>
31− {breadcrumbBuilder(route)}
32− </Button>
33−
34− {isLast(history.size, idx) ? <div /> : '/'}
35− </div>
36− );
37− })}
38− </>
39− );
40−}
41−
42−function Header(props) {
43− const history = useHistory();
44−
45− const showCrumbs = !history.includes(ROUTE_NAMES.INVITE_TICKET);
46−
47− if (showCrumbs) {
48− return (
49− <div className={'flex items-center h-10'}>
50− <Crumbs />
51− </div>
52− );
53− }
54−
55− return (
56− <h2 className="mt-9 clickable" onClick={() => history.pop()}>
57− Bridge
58− </h2>
59− );
60−}
61−
62−export default Header;
src/indigo-react/components/Input.js+2−1
@@ -68,6 +68,7 @@ export default function Input({
6868 onFocus && onFocus(focused);
6969 }, [focused]); // eslint-disable-line react-hooks/exhaustive-deps
7070
71+ console.log(name, visiblyPassed, error);
7172 return (
7273 <Flex className={className} col>
7374 <Flex.Item as="label" className="f6 lh-tall" htmlFor={name}>
@@ -92,7 +93,7 @@ export default function Input({
9293 {
9394 'b-green3': visiblyPassed,
9495 'b-black': focused && !visiblyPassed,
95− 'b-yellow3': !focused && !visiblyPassed && error,
96+ 'b-yellow3': !focused && error,
9697 'b-gray3': !focused && !error && !visiblyPassed,
9798 }
9899 // TODO: inputClassName ?
src/indigo-react/lib/useForm.js+1−1
@@ -85,7 +85,7 @@ export default function useForm(configs = []) {
8585 const onBlur = useCallback(
8686 name => e => {
8787 setFocused({ [name]: false });
88− setHasBeenFocused({ [name]: false });
88+ setHasBeenFocused({ [name]: true });
8989 },
9090 [setFocused, setHasBeenFocused]
9191 );
src/lib/patp2dec.jsnew file+9
@@ -0,0 +1,9 @@
1+import * as ob from 'urbit-ob';
2+
3+/**
4+ * Convert a patp string into a number, or throw.
5+ *
6+ * @throws
7+ * @return number
8+ */
9+export default patp => parseInt(ob.patp2dec(patp), 10);
src/lib/routeNames.js+1−1
@@ -1,7 +1,7 @@
11export const ROUTE_NAMES = {
22 DEFAULT: Symbol('DEFAULT'),
33 //
4− INVITE_TICKET: Symbol('INVITE_TICKET'),
4+ ACTIVATE: Symbol('ACTIVATE'),
55 INVITE_TRANSACTIONS: Symbol('INVITE_TRANSACTIONS'),
66 INVITE: Symbol('INVITE'),
77 INVITES_MANAGE: Symbol('INVITES_MANAGE'),
src/lib/router.js+2−50
@@ -1,9 +1,5 @@
1−import * as ob from 'urbit-ob';
2−import * as need from './need';
3−
41import Landing from '../views/Landing';
52import Login from '../views/Login.js';
6−import InviteTicket from '../views/InviteTicket';
73import InvitesManage from '../views/InvitesManage.js';
84import AcceptTransfer from '../views/AcceptTransfer';
95import CancelTransfer from '../views/CancelTransfer';
@@ -22,13 +18,13 @@ import Point from '../views/Point';
2218import Points from '../views/Points';
2319import Transfer from '../views/Transfer';
2420import Invite from 'views/Invite';
21+import Activate from 'views/Activate';
2522
2623import { ROUTE_NAMES } from './routeNames';
2724
2825export const ROUTES = {
29− [ROUTE_NAMES.DEFAULT]: Landing,
3026 [ROUTE_NAMES.LANDING]: Landing,
31− [ROUTE_NAMES.INVITE_TICKET]: InviteTicket,
27+ [ROUTE_NAMES.ACTIVATE]: Activate,
3228 [ROUTE_NAMES.INVITE]: Invite,
3329 [ROUTE_NAMES.INVITES_MANAGE]: InvitesManage,
3430 [ROUTE_NAMES.LOGIN]: Login,
@@ -47,47 +43,3 @@ export const ROUTES = {
4743 [ROUTE_NAMES.SENT_TRANSACTION]: SentTransaction,
4844 [ROUTE_NAMES.GEN_KEYFILE]: GenKeyfile,
4945};
50−
51−export const getRouteBreadcrumb = ({ pointCursor }) => route => {
52− switch (route.name) {
53− case ROUTE_NAMES.INVITE_TICKET:
54− return 'Invite code';
55− case ROUTE_NAMES.INVITE_TRANSACTIONS:
56− return 'Setting up new wallet';
57− case ROUTE_NAMES.INVITE:
58− return 'Send invites';
59− case ROUTE_NAMES.INVITES_MANAGE:
60− return 'Manage invites';
61− case ROUTE_NAMES.LOGIN:
62− return 'Login to Bridge';
63− case ROUTE_NAMES.POINT:
64− return `Overview: ${ob.patp(need.pointCursor(pointCursor))}`;
65− case ROUTE_NAMES.POINTS:
66− return 'Points';
67− case ROUTE_NAMES.VIEW_POINT:
68− return 'View';
69− case ROUTE_NAMES.SET_TRANSFER_PROXY:
70− case ROUTE_NAMES.SET_MANAGEMENT_PROXY:
71− case ROUTE_NAMES.SET_SPAWN_PROXY:
72− return 'Set Proxy';
73− case ROUTE_NAMES.CREATE_GALAXY:
74− return 'Create Galaxy';
75− case ROUTE_NAMES.ISSUE_CHILD:
76− return 'Issue Child';
77− case ROUTE_NAMES.TRANSFER:
78− return 'Transfer';
79− case ROUTE_NAMES.ACCEPT_TRANSFER:
80− return 'Accept Transfer';
81− case ROUTE_NAMES.CANCEL_TRANSFER:
82− return 'Cancel Transfer';
83− case ROUTE_NAMES.GEN_KEYFILE:
84− return 'Keyfile';
85− case ROUTE_NAMES.SET_KEYS:
86− return 'Configure Keys';
87− case ROUTE_NAMES.SENT_TRANSACTION:
88− return 'Txn';
89− case ROUTE_NAMES.LANDING:
90− default:
91− return 'Bridge';
92− }
93−};
src/lib/useImpliedPoint.jsnew file+14
@@ -0,0 +1,14 @@
1+import * as ob from 'urbit-ob';
2+
3+import { prependSig } from './transformers';
4+
5+/**
6+ * pull the suggested point from the subdomain
7+ */
8+export default function useImpliedPoint() {
9+ const subdomain = window.location.host.split('.')[0];
10+ const patp = prependSig(subdomain);
11+ const isValid = ob.isValidPatp(patp);
12+
13+ return isValid ? patp : null;
14+}
src/lib/useRenderCount.js+2−2
@@ -1,7 +1,7 @@
11import { useRef } from 'react';
22
3−export default function useRenderCount(debubgLabel = 'Component') {
3+export default function useRenderCount(debugLabel = 'Component') {
44 const count = useRef(0);
55 count.current++;
6− console.log(`${debubgLabel} — ${count.current}`);
6+ console.log(`${debugLabel} — ${count.current}`);
77}
src/lib/useSyncPoints.js+23−30
@@ -1,39 +1,32 @@
11import { useEffect } from 'react';
2−import { isEqual } from 'lodash';
2+import { difference } from 'lodash';
33
44import { usePointCache } from 'store/pointCache';
55import usePreviousValue from 'lib/usePreviousValue';
66
7−// sync a known (i.e. mine) point to the cache (i.e display values)
8−export function useSyncKnownPoints(points = []) {
9− // TBD: right now we don't need anything more than the point itself
10− // but soon we'll need to know information around "key type"
11−}
7+const buildSyncHook = getFn =>
8+ function SyncPoint(points = []) {
9+ const fn = getFn();
10+ const prevPoints = usePreviousValue(points);
1211
13−// sync a foreign (not the user's) point to the cache
14−export function useSyncForeignPoints(points = []) {
15− const { syncForeignPoint } = usePointCache();
16− const prevPoints = usePreviousValue(points);
12+ useEffect(() => {
13+ // sync points that are new between renders
14+ const newPoints = difference(points, prevPoints);
15+ Promise.all(newPoints.map(fn));
16+ }, [fn, prevPoints, points]);
17+ };
1718
18− useEffect(() => {
19− if (!isEqual(prevPoints, points)) {
20− // if the actual set of points changes, sync the whole array
21− // TODO: we should get clever about caching
22− points.forEach(point => syncForeignPoint(point));
23− }
24− }, [syncForeignPoint, prevPoints, points]);
25−}
19+export const useSyncKnownPoints = buildSyncHook(function() {
20+ const { syncKnownPoint } = usePointCache();
21+ return syncKnownPoint;
22+});
2623
27−// sync an owned point to the cache
28−export function useSyncOwnedPoints(points = []) {
29− const { syncOwnedPoint } = usePointCache();
30− const prevPoints = usePreviousValue(points);
24+export const useSyncForeignPoints = buildSyncHook(function() {
25+ const { syncForeignPoint } = usePointCache();
26+ return syncForeignPoint;
27+});
3128
32− useEffect(() => {
33− if (!isEqual(prevPoints, points)) {
34− // if the actual set of points changes, sync the whole array
35− // TODO: we should get clever about caching
36− points.forEach(point => syncOwnedPoint(point));
37− }
38− }, [syncOwnedPoint, prevPoints, points]);
39−}
29+export const useSyncOwnedPoints = buildSyncHook(function() {
30+ const { syncOwnedPoint } = usePointCache();
31+ return syncOwnedPoint;
32+});
src/lib/validators.js+30−7
@@ -1,7 +1,9 @@
11import * as bip39 from 'bip39';
22import * as ob from 'urbit-ob';
3+import { identity } from 'lodash';
34
45import { isValidAddress } from './wallet';
6+import patp2dec from './patp2dec';
57
68// via: https://emailregex.com/
79const emailRegExp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@@ -10,19 +12,25 @@ const emailRegExp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))
1012const hexRegExp = /[0-9A-Fa-f]{64}/g;
1113
1214// Wraps single validation functions in a controlled and predictable way.
13−export const simpleValidatorWrapper = config => {
15+export const simpleValidatorWrapper = ({
16+ prevMessage,
17+ transform = identity,
18+ validator,
19+ error,
20+}) => {
1421 // If a previous validation has already failed, skip this validation and
1522 // return the prev message to the next stage in the validation function chain.
1623 // Failed validations should drop all the way down the chain and drop out of
1724 // the output.
18− if (!config.prevMessage.pass) {
19− return config.prevMessage;
25+ if (!prevMessage.pass) {
26+ return prevMessage;
2027 }
2128
2229 // Run the validator and return the result.
23− return config.validator(config.prevMessage.data)
24− ? newMessage(config.prevMessage.data, true, null)
25− : newMessage(config.prevMessage.data, false, config.error);
30+ const pass = validator(prevMessage.data);
31+ const data = pass ? transform(prevMessage.data) : prevMessage.data;
32+ console.log(pass, data);
33+ return newMessage(data, pass, !pass && error);
2634};
2735
2836// Validation message
@@ -73,7 +81,7 @@ export const validateGalaxy = m =>
7381 validator: d => {
7482 let point;
7583 try {
76− point = parseInt(ob.patp2dec(d), 10);
84+ point = patp2dec(d);
7785 return point >= 0 && point < 256;
7886 } catch (e) {
7987 return false;
@@ -162,3 +170,18 @@ export const validateEmail = m =>
162170 validator: d => emailRegExp.test(d),
163171 error: 'This is not a valid email address',
164172 });
173+
174+export const validateInt = m =>
175+ simpleValidatorWrapper({
176+ prevMessage: m,
177+ transform: d => parseInt(d, 10),
178+ validator: d => {
179+ try {
180+ parseInt(d, 10);
181+ return;
182+ } catch {
183+ return false;
184+ }
185+ },
186+ error: 'This is not a valid number',
187+ });
src/store/lib/usePointStore.js+9−2
@@ -14,6 +14,12 @@ export default function usePointStore() {
1414 ...controlledPoints
1515 } = useControlledPointsStore();
1616
17+ // sync all of the on-chain info required to display a known point
18+ const syncKnownPoint = useCallback(
19+ async point => Promise.all([syncBirthday(point)]),
20+ [syncBirthday]
21+ );
22+
1723 // sync all of the on-chain info required to display a foreign point
1824 const syncForeignPoint = useCallback(async point => Promise.all([]), []);
1925
@@ -21,11 +27,11 @@ export default function usePointStore() {
2127 const syncOwnedPoint = useCallback(
2228 async point =>
2329 Promise.all([
30+ syncKnownPoint(point),
2431 syncDetails(point),
25− syncBirthday(point),
2632 syncInvites(point),
2733 ]),
28− [syncDetails, syncBirthday, syncInvites]
34+ [syncKnownPoint, syncDetails, syncInvites]
2935 );
3036
3137 return {
@@ -35,6 +41,7 @@ export default function usePointStore() {
3541 ...controlledPoints,
3642 syncInvites,
3743 syncControlledPoints,
44+ syncKnownPoint,
3845 syncOwnedPoint,
3946 syncForeignPoint,
4047 };
src/views/Activate.jsnew file+61
@@ -0,0 +1,61 @@
1+import React, { useCallback } from 'react';
2+import * as ob from 'urbit-ob';
3+import Maybe from 'folktale/maybe';
4+import useImpliedPoint from 'lib/useImpliedPoint';
5+import { usePointInput, useTicketInput } from 'components/Inputs';
6+import { Grid, Input } from 'indigo-react';
7+
8+import View from 'components/View';
9+import Footer from 'components/Footer';
10+import { ForwardButton } from 'components/Buttons';
11+import Passport from 'components/Passport';
12+
13+import { useHistory } from 'store/history';
14+
15+import { ROUTE_NAMES } from 'lib/routeNames';
16+import { useSyncKnownPoints } from 'lib/useSyncPoints';
17+import patp2dec from 'lib/patp2dec';
18+
19+export default function Activate() {
20+ const { popAndPush } = useHistory();
21+ const impliedPoint = useImpliedPoint();
22+
23+ const pointInput = usePointInput({
24+ name: 'point',
25+ initialValue: impliedPoint || '',
26+ autoFocus: !!impliedPoint,
27+ });
28+
29+ // Maybe<number>
30+ const point = ob.isValidPatp(pointInput.data)
31+ ? Maybe.Just(patp2dec(pointInput.data))
32+ : Maybe.Nothing();
33+
34+ useSyncKnownPoints([point.getOrElse(null)].filter(p => p !== null));
35+
36+ const ticketInput = useTicketInput({
37+ name: 'ticket',
38+ });
39+
40+ const goToLogin = useCallback(() => popAndPush(ROUTE_NAMES.LOGIN), [
41+ popAndPush,
42+ ]);
43+
44+ return (
45+ <View>
46+ <Grid>
47+ <Grid.Item as={Passport} point={point} full />
48+ {!impliedPoint && <Grid.Item as={Input} {...pointInput} full />}
49+ <Grid.Item as={Input} {...ticketInput} full />
50+ </Grid>
51+ <Footer>
52+ <Grid className="pt2">
53+ <Grid.Divider />
54+ <Grid.Item as={ForwardButton} onClick={goToLogin} full>
55+ Login
56+ </Grid.Item>
57+ </Grid>
58+ </Footer>
59+ </View>
60+ );
61+}
src/views/CreateGalaxy.js+1−1
@@ -75,7 +75,7 @@ class CreateGalaxy extends React.Component {
7575
7676 const validContracts = need.contracts(props.contracts);
7777
78− const galaxyDec = parseInt(ob.patp2dec(state.galaxyName), 10);
78+ const galaxyDec = ob.patp2dec(state.galaxyName);
7979
8080 const txn = azimuth.ecliptic.createGalaxy(
8181 validContracts,
src/views/Landing.js+5−5
@@ -7,7 +7,7 @@ import { useHistory } from '../store/history';
77import View from 'components/View';
88import { ForwardButton } from 'components/Buttons';
99
10−function Landing(props) {
10+function Landing() {
1111 const history = useHistory();
1212
1313 return (
@@ -22,13 +22,13 @@ function Landing(props) {
2222 <ForwardButton
2323 className="mt3"
2424 detail="If you were sent an Azimuth invite code."
25− onClick={() => history.push(ROUTE_NAMES.INVITE_TICKET)}>
26− Claim an invite
25+ onClick={() => history.push(ROUTE_NAMES.ACTIVATE)}>
26+ Activate a Point
2727 </ForwardButton>
2828
2929 <ForwardButton
3030 className="mt3"
31− detail="Shiny new Login flow."
31+ detail="Login to an activated point."
3232 onClick={() => history.push(ROUTE_NAMES.LOGIN)}>
3333 Login
3434 </ForwardButton>
@@ -37,7 +37,7 @@ function Landing(props) {
3737 className="mt3"
3838 detail="View an Azimuth point without signing into a wallet."
3939 onClick={() => history.push(ROUTE_NAMES.VIEW_POINT)}>
40− View a point
40+ View a Point
4141 </ForwardButton>
4242 </View>
4343 );
src/views/Login/Shards.js−1
@@ -23,7 +23,6 @@ export default function Shards({ loginCompleted }) {
2323
2424 const pointInput = usePointInput({
2525 name: 'point',
26− label: 'Point',
2726 autoFocus: true,
2827 });
2928 const pointName = pointInput.data;
src/views/Login/Ticket.js+1−3
@@ -37,16 +37,14 @@ export default function Ticket({ advanced, loginCompleted }) {
3737 // inputs
3838 const pointInput = usePointInput({
3939 name: 'point',
40− label: 'Point',
4140 //TODO deduce point name from URL if we can, prefill input if we found it
42− // initialValue: '~',
4341 autoFocus: true,
4442 });
4543 const pointName = pointInput.data;
4644
4745 const ticketInput = useTicketInput({
4846 name: 'ticket',
49− label: 'Master ticket',
47+ label: 'Master Ticket',
5048 });
5149 const ticket = ticketInput.data;
5250
src/views/Point.js+1−1
@@ -41,7 +41,7 @@ export default function Point() {
4141
4242 return (
4343 <View>
44− <Passport point={point} />
44+ <Passport point={Maybe.Just(point)} />
4545 <Grid className="pt2">
4646 <Grid.Item full>
4747 <ForwardButton disabled>Admin</ForwardButton>
src/views/ViewPoint.js+2−4
@@ -1,6 +1,5 @@
11import React, { useCallback } from 'react';
22import Maybe from 'folktale/maybe';
3−import * as ob from 'urbit-ob';
43import { Input } from 'indigo-react';
54
65import { H1, P } from '../components/old/Base';
@@ -9,6 +8,7 @@ import { useHistory } from 'store/history';
98import { usePointCursor } from 'store/pointCursor';
109
1110import { ROUTE_NAMES } from 'lib/routeNames';
11+import patp2dec from 'lib/patp2dec';
1212
1313import View from 'components/View';
1414import { ForwardButton } from 'components/Buttons';
@@ -19,15 +19,13 @@ export default function ViewPoint() {
1919 const { setPointCursor } = usePointCursor();
2020 const pointInput = usePointInput({
2121 name: 'point',
22− label: 'Point Name',
2322 autoFocus: true,
2423 });
2524 const { data: pointName, pass } = pointInput;
2625
2726 const disabled = !pass;
2827 const goForward = useCallback(() => {
29− setPointCursor(Maybe.Just(parseInt(ob.patp2dec(pointName), 10)));
30− // ^ pointCursor expects native number type, not string
28+ setPointCursor(Maybe.Just(patp2dec(pointName)));
3129 history.popAndPush(ROUTE_NAMES.POINT);
3230 }, [setPointCursor, history, pointName]);
3331