@@ -1,26 +1,23 @@
1import { Just, Nothing } from 'folktale/maybe';
1import { Just, Nothing } from 'folktale/maybe';
2−import React from 'react';
2+import React, { 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';
6+import View from '../../components/View';
13 PointInput,
8 PointInput,
14 TicketInput,
9 TicketInput,
15−} from '../../components/old/Base';
11+} from '../../components/Inputs';
12+import { ForwardButton } from '../../components/Buttons';
17import * as need from '../../lib/need';
14import * as need from '../../lib/need';
18import { compose } from '../../lib/lib';
15import { compose } from '../../lib/lib';
19import { WALLET_TYPES, urbitWalletFromTicket } from '../../lib/wallet';
16import { WALLET_TYPES, urbitWalletFromTicket } from '../../lib/wallet';
18+import { useNetwork } from '../../store/network';
21−import { withWallet } from '../../store/wallet';
19+import { useWallet } from '../../store/wallet';
22−import { withNetwork } from '../../store/network';
23−import { withPointCursor } from '../../store/pointCursor';
20+import { usePointCursor } from '../../store/pointCursor';
25//TODO should be part of InputWithStatus component
22//TODO should be part of InputWithStatus component
26const INPUT_STATUS = {
23const INPUT_STATUS = {
@@ -29,174 +26,125 @@ const INPUT_STATUS = {
29 FAIL: Symbol('FAIL'),
26 FAIL: Symbol('FAIL'),
32−class Ticket extends React.Component {
29+export default function Ticket({ advanced, loginCompleted }) {
33− constructor(props) {
30+ // globals
34− super(props);
31+ const { contracts } = useNetwork();
35−
32+ const { wallet, setWalletType, setUrbitWallet } = useWallet();
36− this.state = {
33+ const { setPointCursor } = usePointCursor();
38− ticket: '',
35+ // inputs
39− ticketStatus: Nothing(),
43− this.handlePointNameInput = this.handlePointNameInput.bind(this);
44− this.handleTicketInput = this.handleTicketInput.bind(this);
45− this.handlePassphraseInput = this.handlePassphraseInput.bind(this);
46− this.verifyTicket = this.verifyTicket.bind(this);
47− this.continue = this.continue.bind(this);
50− componentDidMount() {
51− //TODO deduce point name from URL if we can, prefill input if we found it
36+ //TODO deduce point name from URL if we can, prefill input if we found it
52− }
37+ const [pointName, setPointName] = useState('');
53−
38+ const [ticket, setTicket] = useState('');
54− handlePointNameInput(pointName) {
39+ const [passphrase, setPassphrase] = useState('');
55− if (pointName.length < 15) {
56− this.setState({ pointName });
57− this.verifyTicket(pointName, this.state.ticket, this.state.passphrase);
61− handleTicketInput(ticket) {
41+ // display state
62− this.setState({ ticket });
42+ const [ticketStatus, setTicketStatus] = useState(Nothing());
63− this.verifyTicket(this.state.pointName, ticket, this.state.passphrase);
66− handlePassphraseInput(passphrase) {
44+ useEffect(() => {
67− this.setState({ passphrase });
45+ console.log('something changed?');
68− this.verifyTicket(this.state.pointName, this.state.ticket, passphrase);
46+ verifyTicket(pointName, ticket, passphrase);
69− }
47+ return () => {};
48+ }, [pointName, ticket, passphrase]);
71 //TODO maybe want to do this only on-go, because wallet derivation is slow...
50 //TODO maybe want to do this only on-go, because wallet derivation is slow...
72− async verifyTicket(pointName, ticket, passphrase) {
51+ const verifyTicket = async (pointName, ticket, passphrase) => {
52+ setUrbitWallet(Nothing());
73 if (!ob.isValidPatq(ticket) || !ob.isValidPatp(pointName)) {
53 if (!ob.isValidPatq(ticket) || !ob.isValidPatp(pointName)) {
74− this.props.setUrbitWallet(Nothing());
54+ setTicketStatus(Nothing());
75− this.setState({ ticketStatus: Nothing() });
78− this.setState({ ticketStatus: Just(INPUT_STATUS.SPIN) });
57+ setTicketStatus(Just(INPUT_STATUS.SPIN));
79− const contracts = need.contracts(this.props);
58+ const realContracts = need.contracts(contracts);
80 const pointNumber = ob.patp2dec(pointName);
59 const pointNumber = ob.patp2dec(pointName);
81 const uhdw = await urbitWalletFromTicket(ticket, pointName, passphrase);
60 const uhdw = await urbitWalletFromTicket(ticket, pointName, passphrase);
82 const isOwner = azimuth.azimuth.isOwner(
61 const isOwner = azimuth.azimuth.isOwner(
83− contracts,
62+ realContracts,
84 pointNumber,
63 pointNumber,
85 uhdw.ownership.keys.address
64 uhdw.ownership.keys.address
87 const isTransferProxy = azimuth.azimuth.isTransferProxy(
66 const isTransferProxy = azimuth.azimuth.isTransferProxy(
88− contracts,
67+ realContracts,
89 pointNumber,
68 pointNumber,
90 uhdw.ownership.keys.address
69 uhdw.ownership.keys.address
92− this.props.setUrbitWallet(Just(uhdw));
71+ setUrbitWallet(Just(uhdw));
93− this.setState({
72+ const newStatus =
95− (await isOwner) || (await isTransferProxy)
73+ (await isOwner) || (await isTransferProxy)
96− ? Just(INPUT_STATUS.GOOD)
74+ ? INPUT_STATUS.GOOD
97− : Just(INPUT_STATUS.FAIL),
75+ : INPUT_STATUS.FAIL;
98− });
76+ setTicketStatus(Just(newStatus));
101− canContinue() {
79+ const canContinue = () => {
102 // this is our only requirement, since we still want people with
80 // this is our only requirement, since we still want people with
103 // non-standard wallet setups to be able to log in
81 // non-standard wallet setups to be able to log in
104− return Just.hasInstance(this.props.wallet);
82+ return Just.hasInstance(wallet);
107− continue() {
85+ const doContinue = () => {
108− //TODO maybe do on-mount?
109− this.props.setWalletType(WALLET_TYPES.TICKET);
86+ setWalletType(WALLET_TYPES.TICKET);
110− this.props.setPointCursor(Just(ob.patp2dec(this.state.pointName)));
87+ setPointCursor(Just(ob.patp2dec(pointName)));
111− this.props.loginCompleted();
88+ loginCompleted();
115− const pointInput = (
91+ const pointInput = (
116− <PointInput
92+ <PointInput
117− className="mono mt-8"
93+ name="point"
118− prop-size="lg"
94+ label="Point"
119− prop-format="innerLabel"
95+ initialValue={pointName}
120− type="text"
96+ onValue={setPointName}
121− autoFocus
97+ autoFocus
122− value={this.state.pointName}
98+ />
123− onChange={this.handlePointNameInput}>
99+ );
124− <InnerLabel>{'Point name'}</InnerLabel>
100+
125− <ValidatedSigil
101+ //TODO integrate into TicketInput?
126− className={'tr-0 mt-05 mr-0 abs'}
127− patp={this.state.pointName}
134− const ticketStatus = this.state.ticketStatus.matchWith({
102+ const displayTicketStatus = ticketStatus.matchWith({
135− Nothing: () => <span />,
103+ Nothing: () => <span />,
136− Just: status => {
104+ Just: status => {
137− switch (status.value) {
105+ switch (status.value) {
138− case INPUT_STATUS.SPIN:
106+ case INPUT_STATUS.SPIN:
139− return <span>⋯</span>;
107+ return <span>⋯</span>;
140− case INPUT_STATUS.GOOD:
108+ case INPUT_STATUS.GOOD:
141− return <span>✓</span>;
109+ return <span>✓</span>;
142− case INPUT_STATUS.FAIL:
110+ case INPUT_STATUS.FAIL:
143− return <span>𐄂</span>;
111+ return <span>𐄂</span>;
144− default:
112+ default:
145− throw new Error('weird input status ' + status.value);
113+ throw new Error('weird input status ' + status.value);
150− const ticketInput = (
118+ const ticketInput = (
151− //TODO NewTicketInput component, that does dashes etc
152− <TicketInput
119+ <TicketInput
153− className="mono mt-8"
155− prop-format="innerLabel"
157− name="ticket"
120+ name="ticket"
158− value={this.state.ticket}
159− onChange={this.handleTicketInput}>
160− <InnerLabel>{'Master ticket'}</InnerLabel>
121+ label="Master ticket"
161− {ticketStatus}
122+ initialValue={ticket}
162− </TicketInput>
123+ onValue={setTicket}
165− const passphraseInput = !this.props.advanced ? null : (
127+ const passphraseInput = !advanced ? null : (
166− <Input
128+ <PassphraseInput
169− prop-format="innerLabel"
170− name="passphrase"
129+ name="passphrase"
171− type="password"
130+ label="(Optional) Wallet Passphrase"
172− value={this.state.passphrase}
131+ initialValue={passphrase}
173− autocomplete="off"
132+ onValue={setPassphrase}
174− onChange={this.handlePassphraseInput}>
133+ />
175− <InnerLabel>{'Passphrase'}</InnerLabel>
179− return (
136+ return (
182− {pointInput}
138+ {pointInput}
183− {ticketInput}
139+ {ticketInput}
184− {passphraseInput}
140+ {passphraseInput}
186− <Button
142+ <ForwardButton
187− className={'mt-10'}
143+ className={'mt3'}
188− disabled={!this.canContinue()}
144+ disabled={!canContinue()}
189− onClick={this.continue}>
145+ onClick={doContinue}>
190− {'Go →'}
146+ Continue
191− </Button>
147+ </ForwardButton>
198−export default compose(