@@ -1,16 +1,11 @@
11import { useCallback, useState } from 'react';
22import { Button } from 'indigo-react';
3−import { Icon, Row, Box, LoadingSpinner } from '@tlon/indigo-react';
3+import { Icon, Row, Box, LoadingSpinner, Text, H3 } from '@tlon/indigo-react';
44
55import { useRollerStore } from 'store/rollerStore';
66import { useLocalRouter } from 'lib/LocalRouter';
7−import {
8− generateUrl,
9− generateUrlAbbreviation,
10− generateCsvLine,
11− generateCsvName,
12−} from 'lib/utils/invite';
13−import { INVITES_PER_PAGE, DEFAULT_CSV_NAME } from 'lib/constants';
7+import { generateUrl, generateUrlAbbreviation } from 'lib/utils/invite';
8+import { INVITES_PER_PAGE } from 'lib/constants';
149import { useTimerStore } from 'store/timerStore';
1510import { Invite } from 'lib/types/Invite';
1611import { ddmmmYYYY } from 'lib/utils/date';
@@ -24,8 +19,8 @@ import CopiableWithTooltip from 'components/copiable/CopiableWithTooltip';
2419import Paginator from 'components/L2/Paginator';
2520
2621import './Cohort.scss';
27−import Modal from 'components/L2/Modal';
28−import { useInvites, useInviteStore } from './useInvites';
22+import { useInviteStore } from './useInvites';
23+import { CSVModal } from './CSVModal';
2924
3025export default function InviteCohort() {
3126 const { names, pop, push } = useLocalRouter();
@@ -33,15 +28,11 @@ export default function InviteCohort() {
3328
3429 const { nextRoll } = useTimerStore();
3530
36− const { invites, generatingNum } = useInviteStore();
37− const { getInvites } = useInvites();
31+ const { invites, loading } = useInviteStore();
3832 const currentL2 = Boolean(point.isL2Spawn);
3933
40− const [loading, setLoading] = useState(false);
4134 const [showCsvModal, setShowCsvModal] = useState(false);
42− const [csvElement, setCsvElement] = useState<HTMLAnchorElement | null>();
4335 // TODO: do we need to read this error? currently unused
44− const [error, setError] = useState('');
4536 const [page, setPage] = useState(0);
4637
4738 const invitePoints = invites[point.value];
@@ -54,40 +45,6 @@ export default function InviteCohort() {
5445 const hasPending = Boolean(pendingTransactions.length);
5546 const hasInvites = Boolean(invitePoints.length);
5647
57− const generateCsv = useCallback(() => {
58− const generateCsvElement = async () => {
59− setLoading(true);
60− setShowCsvModal(true);
61− const invites = await getInvites();
62− if (invites) {
63− const csv = invites.reduce(
64− (csvData, { ticket, planet }, ind) =>
65− (csvData += generateCsvLine(ind, ticket, planet)),
66− 'Number,Planet,Invite URL,Point,Ticket\n'
67− );
68− document.getElementById('csv')?.remove();
69− const hiddenElement = document.createElement('a');
70− hiddenElement.href = `data:text/csv;charset=utf-8,${encodeURIComponent(
71− csv
72− )}`;
73− hiddenElement.target = '_blank';
74− hiddenElement.id = 'csv';
75−
76− //provide the name for the CSV file to be downloaded
77− hiddenElement.download = generateCsvName(
78− DEFAULT_CSV_NAME,
79− point.patp?.slice(1) || 'bridge'
80− );
81− setCsvElement(hiddenElement);
82− } else {
83− setError('There was an error creating the CSV');
84− }
85− setLoading(false);
86− useInviteStore.setState({ generatingNum: 0 });
87− };
88− generateCsvElement();
89− }, [getInvites, setError, setLoading, setShowCsvModal, point]);
90−
9148 const goNextPage = useCallback(() => {
9249 setPage(page + 1);
9350 }, [page]);
@@ -155,18 +112,28 @@ export default function InviteCohort() {
155112 );
156113 };
157114
158− const header = (
159− <h5>
160− You have
161− <span className="number-emphasis"> {invitePoints.length} </span>
162− Invite Code{invitePoints.length === 1 ? '' : 's'}
163− </h5>
164− );
115+ const header = () => {
116+ if (loading) {
117+ return (
118+ <Row alignItems="center">
119+ <LoadingSpinner dark />
120+ <H3 ml={2}>Checking and Updating Invites...</H3>
121+ </Row>
122+ );
123+ }
124+
125+ return (
126+ <h5>
127+ You have
128+ <span className="number-emphasis"> {invitePoints.length} </span>
129+ Invite Code{invitePoints.length === 1 ? '' : 's'}
130+ </h5>
131+ );
132+ };
165133
166134 const showGenerateButton = !hasPending && !hasInvites && point.canSpawn;
167135 const showAddMoreButton =
168136 (hasInvites || hasPending) && point.canSpawn && point.l2Quota > 0;
169− const generatingCodesText = `Generating ${generatingNum} of ${invitePoints.length} codes...`;
170137
171138 return (
172139 <View
@@ -178,11 +145,13 @@ export default function InviteCohort() {
178145 <Window>
179146 <HeaderPane>
180147 {!hasInvites ? (
181− header
148+ header()
182149 ) : (
183150 <Row className="has-invites-header">
184− {header}
185− <Row className="download-csv" onClick={generateCsv}>
151+ {header()}
152+ <Row
153+ className="download-csv"
154+ onClick={() => setShowCsvModal(true)}>
186155 <Icon icon="Download" />
187156 <Box>CSV</Box>
188157 </Row>
@@ -230,40 +199,12 @@ export default function InviteCohort() {
230199 <strong>{` ${ddmmmYYYY(nextQuotaTime)}`}</strong>.
231200 </Box>
232201 ) : null}
233− <Modal show={showCsvModal} hide={() => setShowCsvModal(false)} hideClose>
234− <Box className="download-csv-modal">
235− <Box>
236− <Box>Download CSV</Box>
237− {loading && <Box>{generatingCodesText}</Box>}
238− </Box>
239− <Row className="download-buttons">
240− {/*
241− // @ts-ignore */}
242− <Button
243− center
244− className="ph4 close-button"
245− solid
246− onClick={() => setShowCsvModal(false)}>
247− Close
248− </Button>
249− {/*
250− // @ts-ignore */}
251− <Button
252− center
253− className="ph4 download-button"
254− disabled={loading}
255− solid
256− onClick={() => csvElement?.click()}>
257− Download CSV
258− </Button>
259− </Row>
260− </Box>
261− {loading && (
262− <Box className="csv-loading">
263− <LoadingSpinner background="#BCDCFF" foreground="#219DFF" />
264− </Box>
265− )}
266− </Modal>
202+ <CSVModal
203+ point={point.value}
204+ show={showCsvModal}
205+ hide={() => setShowCsvModal(false)}
206+ hideClose
207+ />
267208 </View>
268209 );
269210}