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 { PLACEHOLDER_PLANET, PLACEHOLDER_TICKET, TicketInput } from 'form/Inputs';
12 buildCheckboxValidator,
13} from 'form/validators';
14import FormError from 'form/FormError';
15import { 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 { generateWallet } from 'lib/walletgen';
22import { urbitWalletFromTicket, walletFromMnemonic } from 'lib/wallet';
23import { DEFAULT_HD_PATH, POINT_PROXIES } from 'lib/constants';
24import useBreakpoints from 'lib/useBreakpoints';
25import { Ship } from '@urbit/roller-api';
26import { convertToInt } from 'lib/convertToInt';
27import { Box } from '@tlon/indigo-react';
28import { timeout } from 'lib/timeout';
29import withFadeable from './withFadeable';
30import ActivateButton from './ActivateButton';
31import TicketInputAccessory from 'components/form/TicketInputAccessory';
32import { validateActivationTicket } from 'lib/validators';
34interface ActivateCodeFormProps {
35 afterSubmit: VoidFunction;
38const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
39 const { api, getPoints } = useRoller();
40 const { impliedTicket, impliedPatp } = useImpliedTicket();
41 const didWarn = useRef<boolean>(false);
46 setDerivedPointDominion,
47 setInviteMasterTicketWallet,
51 }: any = useActivateFlow();
53 // this is a pretty naive way to detect if we're on a mobile device
54 // (i.e. we're checking the width of the screen)
55 // but it will suffice for the 99% case and if someone wants to get around it
56 // well by golly they're allowed to turn their phone into landscape mode
59 const activationAllowed = useBreakpoints([false, true, true]);
61 const validateForm = useCallback(
63 didWarn.current = false;
65 if (hasErrors(errors)) {
72 const validate = useMemo(
76 ticket: buildPatqValidator([validateActivationTicket]),
77 showTicket: buildCheckboxValidator(),
84 const hasInitialValues = useMemo(
85 () => Boolean(impliedTicket && impliedPatp),
86 [impliedTicket, impliedPatp]
89 const getTicketAndPoint = useCallback(
91 const segments = invite.split('-');
93 ticket: segments.slice(0, 4).join('-'),
95 ? ob.patp2dec(impliedPatp)
96 : ob.patp2dec(`~${segments.slice(4, segments.length).join('-')}`),
102 const loadPoints = useCallback(
103 async (address: string): Promise<Ship[]> => {
104 const owned = await getPoints(POINT_PROXIES.OWN, address);
105 const transferring = await getPoints(POINT_PROXIES.TRANSFER, address);
106 const incoming = [...owned, ...transferring];
107 console.log('incoming points', incoming);
113 // derive and set our state on submission
114 const onSubmit = useCallback(
116 // Allow UI animation to start
120 const { ticket, point } = getTicketAndPoint(
121 impliedTicket || values.ticket
124 const inviteWallet = Just(await urbitWalletFromTicket(ticket, point));
125 setInviteWallet(inviteWallet);
126 const _inviteWallet: UrbitWallet = need.wallet(inviteWallet);
127 const inviteAddress = _inviteWallet.ownership.keys.address;
129 const sendWallet = await walletFromMnemonic(
130 _inviteWallet.ownership.seed,
133 setSendWallet(sendWallet);
135 let incoming = await loadPoints(inviteAddress);
138 if (incoming.length > 0) {
139 if (incoming.length > 1 && !didWarn.current) {
140 didWarn.current = true;
144 'This invite code has multiple points available. ' +
145 "Once you've activated this point, " +
146 'activate the next with the same process.',
150 const point = convertToInt(incoming[0], 10);
151 const rollerPoint = await api.getPoint(point!);
153 setDerivedPatp(Just(ob.patp(point)));
154 setDerivedPoint(Just(point));
155 setDerivedPointDominion(Just(rollerPoint.dominion));
156 setInviteMasterTicketWallet(Just(await generateWallet(point, ticket, true)));
162 'Invite code has no claimable point.\n' +
163 'Check your invite code and try again?',
176 setDerivedPointDominion,
177 setInviteMasterTicketWallet,
183 const initialValues = useMemo(
185 ticket: hasInitialValues
186 ? `${impliedTicket}-${impliedPatp?.slice(1)}`
190 [impliedTicket, impliedPatp, hasInitialValues]
195 className="w-full h-full flex-col"
197 justifyContent="flex-end">
201 afterSubmit={afterSubmit}
202 initialValues={initialValues}>
203 {({ values, valid, submitting, handleSubmit }: any) => (
205 {!hasInitialValues && (
210 accessory={<TicketInputAccessory name="showTicket" />}
211 type={values.showTicket ? 'text' : 'password'}
213 disabled={!activationAllowed}
214 placeholder={`${PLACEHOLDER_TICKET}-${PLACEHOLDER_PLANET.slice(
220 <Grid.Item full as={FormError} className="mb2" />
223 disabled={(!valid && !hasInitialValues) || submitting}
224 onClick={handleSubmit}>
225 {submitting ? 'Activating...' : 'Activate'}
228 {!activationAllowed && (
229 <Grid.Item full as={WarningBox} className="mt4">
230 For your security, please access Bridge on a desktop device.
240export default ActivateCodeForm;
242export 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