on master help sign in
bridge/src/views/Invite/GenerateInvites.tsx
152 lines 5.4 kB history raw
1import { Button } from 'indigo-react';
2import { Box, Row, StatelessTextInput } from '@tlon/indigo-react';
3import L2BackHeader from 'components/L2/Headers/L2BackHeader';
4import BodyPane from 'components/L2/Window/BodyPane';
5import HeaderPane from 'components/L2/Window/HeaderPane';
6import Window from 'components/L2/Window/Window';
7import View from 'components/View';
8import useRoller from 'lib/useRoller';
9import { useLocalRouter } from 'lib/LocalRouter';
10import { ddmmmYYYY } from 'lib/utils/date';
11import { isExternalWallet } from 'lib/utils/wallet';
12import { useCallback, useState } from 'react';
13import { useRollerStore } from 'store/rollerStore';
14import { GeneratingModal } from './GeneratingModal';
15import {
16 InviteGeneratingStatus,
17 useInvites,
18 useInviteStore,
19} from './useInvites';
20import { DEFAULT_NUM_INVITES } from 'lib/constants';
21import { useTimerStore } from 'store/timerStore';
22import { useWallet } from 'store/wallet';
23import { UnspawnedPoints } from '@urbit/roller-api';
24import { getPendingSpawns } from 'lib/utils/roller';
26export const GenerateInvites = () => {
27 const { pop } = useLocalRouter();
28 const { walletType }: any = useWallet();
29 const { point, nextQuotaTime } = useRollerStore();
30 const { api, getPendingTransactions, getAndUpdatePoint } = useRoller();
31 const { nextRoll } = useTimerStore();
32 const { inviteJobs } = useInviteStore();
33 const { generateInviteCodes } = useInvites();
34 const [generatingStatus, setGeneratingStatus] = useState<
35 InviteGeneratingStatus
36 >('initial');
37 const [error, setError] = useState('');
38 const [numInvites, setNumInvites] = useState(DEFAULT_NUM_INVITES);
40 const createInvites = useCallback(async () => {
41 setGeneratingStatus('generating');
42 try {
43 let planets: UnspawnedPoints = await api.getUnspawned(point.value);
44 const pendingTxs = await api.getPendingByShip(point.value);
45 const pendingSpawns = getPendingSpawns(pendingTxs);
46 planets = planets
47 .filter((point: number) => !pendingSpawns.has(point))
48 .slice(0, numInvites);
50 await generateInviteCodes(point, planets);
51 getPendingTransactions();
52 getAndUpdatePoint(point.value);
53 setGeneratingStatus('finished');
54 } catch (error) {
55 if (typeof error === 'object' && (error as Error)?.message) {
56 setError((error as Error).message);
57 } else if (typeof error === 'string') {
58 setError(error);
59 } else {
60 setError('Generating invites failed');
61 }
62 setGeneratingStatus('errored');
63 }
64 }, [
65 api,
66 point,
67 numInvites,
68 generateInviteCodes,
69 getPendingTransactions,
70 getAndUpdatePoint,
71 setGeneratingStatus,
72 ]);
74 const overQuota = numInvites > point.l2Quota && numInvites > 0;
75 const generateDisabled = overQuota; //loading?
76 const showTxnNote = isExternalWallet(walletType);
78 return (
79 <View
80 pop={pop}
81 className="cohort show-invite-form"
82 hideBack
83 header={<L2BackHeader back={pop} />}>
84 <Window>
85 <HeaderPane>
86 <h5>Generate Invite Codes</h5>
87 </HeaderPane>
88 <BodyPane>
89 <Box className="upper">
90 <Row className="points-input">
91 I want to generate
92 <StatelessTextInput
93 className={`input-box ${overQuota ? 'over-quota' : ''}`}
94 value={numInvites}
95 maxLength={3}
96 onChange={e => {
97 const target = e.target as HTMLInputElement;
98 setNumInvites(Number(target.value.replace(/\D/g, '')));
99 }}
100 />
101 planet invite code{numInvites > 1 ? 's' : ''}
102 </Row>
103 <Box className="mb4" lineHeight="1.4em">
104 You can generate up to
105 <strong>{` ${point.l2Quota} `}</strong>
106 invites. You will be able to generate another
107 <strong>{` ${point.l2Allowance}`}</strong> invites on
108 <strong>{` ${ddmmmYYYY(nextQuotaTime)}`}</strong>.
109 </Box>
110 {showTxnNote && (
111 <Box className="mb6" lineHeight="1.4em">
112 Note: you will have to sign <strong>4</strong> transactions per
113 invite, for a total of <strong>{4 * numInvites}</strong>{' '}
114 signatures.
115 </Box>
116 )}
117 </Box>
118 <Box className="lower">
119 <Row className="next-roll">
120 <span>Next Roll in</span>
121 <span className="timer">{nextRoll}</span>
122 </Row>
123 {/*
124 // @ts-ignore */}
125 <Button
126 as={'button'}
127 className={`generate-codes ${generateDisabled ? 'disabled' : ''}`}
128 disabled={generateDisabled}
129 center
130 onClick={createInvites}>
131 {overQuota
132 ? `You can only generate ${point.l2Quota} codes`
133 : `Generate Invite Codes (${numInvites})`}
134 </Button>
135 </Box>
136 </BodyPane>
137 </Window>
138 <GeneratingModal
139 status={generatingStatus}
140 current={inviteJobs[point.value]?.generatingNum || 0}
141 total={numInvites}
142 error={error}
143 hide={() => {
144 setGeneratingStatus('initial');
145 if (generatingStatus !== 'errored') {
146 pop();
147 }
148 }}
149 />
150 </View>
151 );
152};