1import * as need from 'lib/need';
2import * as ob from 'urbit-ob';
3import { WARNING } from 'form/helpers';
4import { FORM_ERROR } from 'final-form';
5import { Just } from 'folktale/maybe';
6import BridgeForm from 'form/BridgeForm';
7import { TicketInput } from 'form/Inputs';
12 buildCheckboxValidator,
13} from 'form/validators';
14import FormError from 'form/FormError';
15import { CheckboxInput, Grid } from 'indigo-react';
16import { useCallback, useMemo, useRef } from 'react';
17import { useActivateFlow } from './ActivateFlow';
18import WarningBox from 'components/WarningBox';
19import useRoller from 'lib/useRoller';
20import useImpliedTicket from 'lib/useImpliedTicket';
21import { generateOwnershipWallet } from 'lib/walletgen';
22import { generateWallet } from 'lib/invite';
23import { walletFromMnemonic } from 'lib/wallet';
24import { DEFAULT_HD_PATH, POINT_PROXIES } from 'lib/constants';
25import useBreakpoints from 'lib/useBreakpoints';
26import { Ship } from '@urbit/roller-api';
27import { convertToInt } from 'lib/convertToInt';
28import { Box } from '@tlon/indigo-react';
29import { timeout } from 'lib/timeout';
30import withFadeable from './withFadeable';
31import ActivateButton from './ActivateButton';
33interface ActivateCodeFormProps {
34 afterSubmit: VoidFunction;
37const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
38 const { api, getPoints } = useRoller();
39 const { impliedTicket, impliedPatp } = useImpliedTicket();
40 const didWarn = useRef<boolean>(false);
45 setDerivedPointDominion,
49 } = useActivateFlow();
51 // this is a pretty naive way to detect if we're on a mobile device
52 // (i.e. we're checking the width of the screen)
53 // but it will suffice for the 99% case and if someone wants to get around it
54 // well by golly they're allowed to turn their phone into landscape mode
56 const activationAllowed = useBreakpoints([false, true, true]);
58 const validateForm = useCallback(
60 didWarn.current = false;
62 if (hasErrors(errors)) {
69 const validate = useMemo(
72 { ticket: buildPatqValidator(), showTicket: buildCheckboxValidator() },
78 const getTicketAndPoint = useCallback(
80 const segments = invite.split('-');
82 ticket: segments.slice(0, 4).join('-'),
84 ? ob.patp2dec(impliedPatp)
85 : ob.patp2dec(`~${segments.slice(4, segments.length).join('-')}`),
91 const loadPoints = useCallback(
92 async (address: string): Promise<Ship[]> => {
93 const owned = await getPoints(POINT_PROXIES.OWN, address);
94 const transferring = await getPoints(POINT_PROXIES.TRANSFER, address);
95 const incoming = [...owned, ...transferring];
96 console.log('incoming points', incoming);
102 // derive and set our state on submission
103 const onSubmit = useCallback(
105 // Allow UI animation to start
109 const { ticket, point } = getTicketAndPoint(
110 impliedTicket || values.ticket
112 const { seed } = await generateOwnershipWallet(point, ticket);
113 const inviteWallet = walletFromMnemonic(seed, DEFAULT_HD_PATH);
114 setInviteWallet(inviteWallet);
115 const _inviteWallet = need.wallet(inviteWallet);
116 const inviteAddress = _inviteWallet.address;
118 let incoming = await loadPoints(inviteAddress);
121 if (incoming.length > 0) {
122 if (incoming.length > 1 && !didWarn.current) {
123 didWarn.current = true;
127 'This invite code has multiple points available. ' +
128 "Once you've activated this point, " +
129 'activate the next with the same process.',
133 const point = convertToInt(incoming[0], 10);
134 const rollerPoint = await api.getPoint(point!);
136 setDerivedPatp(Just(ob.patp(point)));
137 setDerivedPoint(Just(point));
138 setDerivedPointDominion(Just(rollerPoint.dominion));
139 setDerivedWallet(Just(await generateWallet(point, true)));
145 'Invite code has no claimable point.\n' +
146 'Check your invite code and try again?',
157 setDerivedPointDominion,
164 const initialValues = useMemo(
165 () => ({ ticket: impliedTicket || '', showTicket: true }),
172 flexDirection="column"
175 justifyContent="flex-end">
179 afterSubmit={afterSubmit}
180 initialValues={initialValues}>
181 {({ valid, validating, values, submitting, handleSubmit }) => (
188 type={values.showTicket ? 'text' : 'password'}
190 label="Activation Code"
191 disabled={!activationAllowed}
203 <Grid.Item full as={FormError} />
207 flexDirection="column"
211 justifyContent="flex-end">
213 disabled={!valid || submitting}
214 onClick={handleSubmit}>
215 {submitting ? 'Generating...' : 'Claim'}
219 {!activationAllowed && (
220 <Grid.Item full as={WarningBox} className="mt4">
221 For your security, please access Bridge on a desktop device.
231export default ActivateCodeForm;
233export const FadeableActivateCodeForm = withFadeable(ActivateCodeForm);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list