@@ -1,14 +1,15 @@
11import {
22 Checkbox,
33 Col,
4− H3,
54 Row,
65 Button as IndigoButton,
76 Text,
7+ Action,
88} from '@tlon/indigo-react';
99import { Button } from 'indigo-react';
1010import Modal from './Modal';
1111import { useCallback, useEffect, useState } from 'react';
12+import { ReactComponent as InviteIcon } from 'assets/invite.svg';
1213import Point from 'lib/types/Point';
1314import useRoller from 'lib/useRoller';
1415import BodyPane from './Window/BodyPane';
@@ -17,8 +18,8 @@ import {
1718 useInvites,
1819 useInviteStore,
1920} from 'views/Invite/useInvites';
20−import { GeneratingModal } from 'views/Invite/GeneratingModal';
2121import { usePointCache } from 'store/pointCache';
22+import { CreatingInvitesModal } from './CreatingInvitesModal';
2223
2324interface StarMap {
2425 [key: string]: {
@@ -60,8 +61,11 @@ export const InviteConverter = ({ points }: InviteConverterProps) => {
6061 const [generatingStatus, setGeneratingStatus] = useState<
6162 InviteGeneratingStatus
6263 >('initial');
64+ const [error, setError] = useState('');
65+ const [created, setCreated] = useState(0);
6366 const [currentPoint, setCurrentPoint] = useState<Point>();
6467 const currentJob = inviteJobs[currentPoint?.value || 0];
68+ const signatureCount = selected.length * 3;
6569
6670 useEffect(() => {
6771 if (!points) {
@@ -70,11 +74,13 @@ export const InviteConverter = ({ points }: InviteConverterProps) => {
7074
7175 async function collect() {
7276 const pointMap: StarMap = {};
73− const stars = points.filter(point => point.isStar);
77+ const stars = points.filter(point => point.isStar && point.isL2Spawn);
7478
7579 for (const star of stars) {
7680 const spawns = await api.getSpawned(star.value);
77− const filteredPoints = points.filter(p => spawns.includes(p.value));
81+ const filteredPoints = points.filter(
82+ p => spawns.includes(p.value) && p.isL2Spawn
83+ );
7884
7985 if (filteredPoints.length !== 0) {
8086 pointMap[star.patp] = {
@@ -126,56 +132,65 @@ export const InviteConverter = ({ points }: InviteConverterProps) => {
126132
127133 setGeneratingStatus('generating');
128134
129− for (const { point, children } of Object.values(starMap)) {
130− debugger;
131− const filtered = children
132− .filter(p => selected.includes(p.patp))
133− .map(p => p.value);
135+ try {
136+ for (const { point, children } of Object.values(starMap)) {
137+ debugger;
138+ const filtered = children
139+ .filter(p => selected.includes(p.patp))
140+ .map(p => p.value);
134141
135− if (filtered.length <= 0) {
136− continue;
142+ if (filtered.length <= 0) {
143+ continue;
144+ }
145+
146+ setCurrentPoint(point);
147+ await generateInviteCodes(point, filtered, false);
148+ await getAndUpdatePoint(point.value);
149+ setCreated(children.length);
137150 }
138151
139− setCurrentPoint(point);
140− await generateInviteCodes(point, filtered, false);
141− await getAndUpdatePoint(point.value);
152+ setGeneratingStatus('finished');
153+ } catch (error) {
154+ if (typeof error === 'object' && (error as Error)?.message) {
155+ setError((error as Error).message);
156+ } else if (typeof error === 'string') {
157+ setError(error);
158+ } else {
159+ setError('Creating invites failed');
160+ }
161+ setGeneratingStatus('errored');
142162 }
143−
144− getPendingTransactions();
145− syncControlledPoints();
146− setGeneratingStatus('finished');
147163 }, [
148164 generatingStatus,
149165 selected,
150166 starMap,
151167 generateInviteCodes,
152168 getAndUpdatePoint,
153− getPendingTransactions,
154− syncControlledPoints,
155169 ]);
156170
171+ const hasPlanets =
172+ Object.entries(starMap).reduce((sum, [, star]) => {
173+ return (sum += star.children.length);
174+ }, 0) > 0;
175+
176+ if (!hasPlanets) {
177+ return null;
178+ }
179+
157180 if (generatingStatus !== 'initial') {
158181 return (
159− <GeneratingModal
182+ <CreatingInvitesModal
160183 status={generatingStatus}
161− current={currentJob?.generatingNum}
162− total={
163− generatingStatus === 'finished'
164− ? selected.length
165− : selected.filter(p => {
166− const children = starMap[currentPoint?.patp || '']?.children;
167− return children.map(c => c.patp).includes(p);
168− }).length
169− }
170− fromStar={currentPoint?.patp}
171− spawn={false}
184+ current={created + currentJob?.generatingNum}
185+ total={selected.length}
186+ error={error}
172187 hide={() => {
173188 setGeneratingStatus('initial');
174189 setSelected([]);
175190 setShow(false);
176− if (generatingStatus !== 'errored') {
177− //pop();
178− }
191+ setCreated(0);
192+ getPendingTransactions();
193+ syncControlledPoints();
179194 }}
180195 />
181196 );
@@ -185,51 +200,57 @@ export const InviteConverter = ({ points }: InviteConverterProps) => {
185200 <>
186201 {/*
187202 @ts-ignore */}
188− <Button solid center onClick={() => setShow(true)}>
189− Convert to Invites
203+ <Button className="create-invites" center onClick={() => setShow(true)}>
204+ Create Invites from Planets
190205 </Button>
191− <Modal show={show} hide={() => setShow(false)}>
206+ <Modal small show={show} hide={() => setShow(false)}>
192207 <BodyPane p={0}>
193− <Col width="420px">
194− <H3 mb={2}>Convert Planet Spawns to Invites</H3>
195− <Text>
196− This allows you to convert a spawned planets into invites. After
197− this operation, invites will show up under the point they were
198− spawned from.
208+ <Col width="368px">
209+ <Row alignItems="center" mb={3}>
210+ <InviteIcon />
211+ <Text bold ml={2}>
212+ Create Invites for Existing Planets
213+ </Text>
214+ </Row>
215+ <Text mb={5}>
216+ Select L2 planets you own to convert them back into invite links
217+ under each star.{' '}
218+ <Text color="red" lineHeight="24px">
219+ Note: this will re-ticket the planets and render their existing
220+ keys invalid.
221+ </Text>
222+ </Text>
223+ <Text bold className={!!signatureCount ? '' : 'hidden'}>
224+ {signatureCount} manual signatures will be required.
199225 </Text>
200226 <Col
201227 bg="washedGray"
202228 height="300px"
203229 mt={3}
204− p={2}
230+ p={3}
205231 borderRadius={2}
206232 overflowY="auto">
207233 {Object.entries(starMap).map(([patp, { children }]) => (
208234 <Col mb={4}>
209235 <Row>
210− <Text mb={2} fontSize={2}>
211− Spawned by{' '}
212− <Text bold fontSize={2}>
213− {patp}
214− </Text>
236+ <Text bold mb={2}>
237+ Owned by {patp}
215238 </Text>
216− <IndigoButton
217− height="18px"
218− px={2}
219− fontSize={0}
239+ <Action
240+ backgroundColor="transparent"
220241 ml="auto"
221242 onClick={() => selectChildren(children)}>
222243 {selectText(selected, children)}
223− </IndigoButton>
244+ </Action>
224245 </Row>
225− {children.map(point => (
246+ {children.map((point, index) => (
226247 <Row
227248 alignItems="center"
228249 justifyContent="space-between"
229− ml={3}
230− mb={2}
231250 py={1}
232− borderBottomWidth="1px"
251+ borderBottomWidth={
252+ index === children.length - 1 ? '0px' : '1px'
253+ }
233254 borderBottomStyle="solid"
234255 borderBottomColor="washedGray">
235256 <Text>{point.patp}</Text>
@@ -241,8 +262,9 @@ export const InviteConverter = ({ points }: InviteConverterProps) => {
241262 ))}
242263 </Col>
243264 ))}
265+ {}
244266 </Col>
245− <Row mt={4} justifyContent="end">
267+ <Row mt={3} justifyContent="end">
246268 <IndigoButton
247269 className="secondary"
248270 onClick={() => setShow(false)}>
@@ -255,7 +277,7 @@ export const InviteConverter = ({ points }: InviteConverterProps) => {
255277 ml={2}
256278 onClick={convert}
257279 disabled={selected.length === 0}>
258− Convert
280+ Convert Selected
259281 </IndigoButton>
260282 </Row>
261283 </Col>