on master help sign in
creating-invites: adjust styles to match updated design
commit1d31d97a39edfa8a8bf10904d11435856ab22a31 authorHunter Miller <hunter@hmiller.dev> dateSun 6 Mar 2022, 13:42 (5 years ago) parent2879d31
7 files changed+194−80
src/components/L2/CreatingInvitesModal.tsx+85 src/components/L2/Headers/L2PointHeader.scss+12−8 src/components/L2/Headers/L2PointHeader.tsx+2−2 src/components/L2/InviteConverter.tsx+83−61 src/components/L2/Modal.scss+7−1 src/components/L2/Modal.tsx+3−1 src/views/Invite/GeneratingModal.tsx+2−7
src/components/L2/CreatingInvitesModal.tsxnew file+85
@@ -0,0 +1,85 @@
1+import { Col, H3, LoadingSpinner, Row, Text, Button } from '@tlon/indigo-react';
2+import Modal from 'components/L2/Modal';
3+import { ReactComponent as InviteIcon } from 'assets/invite.svg';
4+import { InviteGeneratingStatus } from '../../views/Invite/useInvites';
5+import BodyPane from './Window/BodyPane';
6+
7+interface GeneratingModalProps {
8+ status: InviteGeneratingStatus;
9+ current: number;
10+ total: number;
11+ error?: string;
12+ hide: () => void;
13+}
14+
15+export const CreatingInvitesModal = ({
16+ status,
17+ current,
18+ total,
19+ hide,
20+ error,
21+}: GeneratingModalProps) => {
22+ const successfulInvites = current > 1 ? current - 1 : 0;
23+ return (
24+ <Modal
25+ small
26+ show={status !== 'initial'}
27+ hide={hide}
28+ hideClose={status !== 'finished'}>
29+ <BodyPane p={0}>
30+ <Col width="350px">
31+ {status === 'generating' && (
32+ <Row alignItems="center">
33+ <LoadingSpinner dark />
34+ <Text bold marginLeft={2}>
35+ Creating Invite {current}/{total}...
36+ </Text>
37+ </Row>
38+ )}
39+ {status === 'finished' && (
40+ <>
41+ <Row mb={3}>
42+ <InviteIcon />
43+ <Text bold ml={2}>
44+ All Invites Created
45+ </Text>
46+ </Row>
47+ <Text mb={3}>
48+ The planets you selected are re-ticketed and appear as new
49+ invitation links under each star.
50+ </Text>
51+ <Row>
52+ <Button className="secondary" ml="auto" onClick={hide}>
53+ Close
54+ </Button>
55+ </Row>
56+ </>
57+ )}
58+ {status === 'errored' && (
59+ <>
60+ <H3 marginBottom={2}>
61+ There was an error while creating your invites:
62+ </H3>
63+ {error && (
64+ <Text color="red" mono marginBottom={3}>
65+ {error}
66+ </Text>
67+ )}
68+ {!!successfulInvites && (
69+ <Text marginY={3}>
70+ At least {successfulInvites} planet
71+ {successfulInvites > 1 ? 's' : ''} were successfully
72+ re-ticketed and appear as new invitation links under each
73+ star.
74+ </Text>
75+ )}
76+ <Button className="secondary" onClick={hide}>
77+ Back
78+ </Button>
79+ </>
80+ )}
81+ </Col>
82+ </BodyPane>
83+ </Modal>
84+ );
85+};
src/components/L2/Headers/L2PointHeader.scss+12−8
@@ -31,14 +31,12 @@
3131 border-radius: $medium-border-radius;
3232 background-color: $washed-gray;
3333 }
34−
35− .info {
36− svg {
37− width: 14px;
38− height: 16px;
39− }
4034
41− .invites, .history, .rollup-timer {
35+ .info {
36+ .invites,
37+ .history,
38+ .create-invites,
39+ .rollup-timer {
4240 border-radius: $medium-border-radius;
4341
4442 &:hover {
@@ -46,11 +44,17 @@
4644 }
4745 }
4846
49− .invites, .history {
47+ .invites,
48+ .history,
49+ .create-invites {
5050 background-color: $washed-gray;
5151 padding: 8px;
5252 }
5353
54+ .create-invites {
55+ margin-left: 4px;
56+ }
57+
5458 .invites {
5559 margin-right: 4px;
5660
src/components/L2/Headers/L2PointHeader.tsx+2−2
@@ -90,13 +90,13 @@ const L2PointHeader = ({
9090 {/* {point.isL1 && point.isL2Spawn && <Box className="l2-spawn">L2 Spawn</Box>} */}
9191 </Row>
9292 <Row>
93− <Row className="info" mr={3}>
93+ <Row className="info">
9494 {renderInviteButton()}
9595 <Box className="history" onClick={goToHistory}>
9696 History
9797 </Box>
98+ {points && <InviteConverter points={points} />}
9899 </Row>
99− {points && <InviteConverter points={points} />}
100100 </Row>
101101 </Row>
102102 );
src/components/L2/InviteConverter.tsx+83−61
@@ -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>
src/components/L2/Modal.scss+7−1
@@ -1,7 +1,7 @@
11@import 'style/shared/variables.scss';
22
33.modal {
4− background-color: rgba(0,0,0,0.2);
4+ background-color: rgba(0, 0, 0, 0.2);
55 position: fixed;
66 top: 0;
77 bottom: 0;
@@ -32,4 +32,10 @@
3232 line-height: 24px;
3333 max-width: calc(100vw - 80px);
3434 }
35+
36+ &.modal-small {
37+ .content {
38+ padding: 16px;
39+ }
40+ }
3541}
src/components/L2/Modal.tsx+3−1
@@ -7,6 +7,7 @@ export interface ModalProps {
77 show: boolean;
88 hide: () => void;
99 hideClose?: boolean;
10+ small?: boolean;
1011 children: React.ReactNode;
1112}
1213
@@ -14,6 +15,7 @@ export default function Modal({
1415 show,
1516 hide,
1617 hideClose = false,
18+ small = false,
1719 children,
1820}: ModalProps) {
1921 const dontHide = (e: MouseEvent) => {
@@ -25,7 +27,7 @@ export default function Modal({
2527 }
2628
2729 return (
28− <Box className="modal" onClick={hide}>
30+ <Box className={`modal${small ? ' modal-small' : ''}`} onClick={hide}>
2931 <Box className="content">
3032 {!hideClose && (
3133 <Box className="close" onClick={hide}>
src/views/Invite/GeneratingModal.tsx+2−7
@@ -7,9 +7,7 @@ interface GeneratingModalProps {
77 status: InviteGeneratingStatus;
88 current: number;
99 total: number;
10− fromStar?: string;
1110 error?: string;
12− spawn?: boolean;
1311 hide: () => void;
1412}
1513
@@ -19,8 +17,6 @@ export const GeneratingModal = ({
1917 total,
2018 hide,
2119 error,
22− fromStar,
23− spawn = true,
2420}: GeneratingModalProps) => {
2521 const successfulInvites = current > 1 ? current - 1 : 0;
2622 return (
@@ -38,11 +34,10 @@ export const GeneratingModal = ({
3834 Generating {current} of {total} Invites
3935 </H3>
4036 </Row>
41− {fromStar && <Text ml={4}>from {fromStar}</Text>}
4237 </Col>
4338 <Text>
44− Each invite will require {spawn ? 'four' : 'three'} transactions
45− to be signed, unless your point is owned by a master ticket.
39+ Each invite will require four transactions to be signed, unless
40+ your point is owned by a master ticket.
4641 </Text>
4742 </>
4843 )}