on master help sign in
New invite system
commit4ca54bd261f8c1c117b7e8d6ff03c745a5904720 authorWill Galebach <willbach@gmail.com> dateTue 16 Nov 2021, 21:17 (5 years ago) parent368f024
10 files changed+86−129
src/components/L2/Headers/L2PointHeader.scss+6 src/components/L2/Headers/L2PointHeader.tsx+8−4 src/lib/types/Invite.ts+4 src/lib/useRoller.ts+26−74 src/lib/walletgen.js−1 src/store/rollerStore.ts+18−20 src/store/storage/roller.ts+4−4 src/views/Invite/Cohort.tsx+16−19 src/views/Point/Point.tsx+4−4 src/worker/worker.ts−3
src/components/L2/Headers/L2PointHeader.scss+6
@@ -41,6 +41,12 @@
4141
4242 svg {
4343 margin-right: 4px;
44+
45+ &:nth-child(2) {
46+ margin: 2px 0 0 4px;
47+ width: 12px;
48+ height: 12px;
49+ }
4450 }
4551 }
4652
src/components/L2/Headers/L2PointHeader.tsx+8−4
@@ -1,5 +1,5 @@
11import React, { useCallback } from 'react';
2−import { Box, Row } from '@tlon/indigo-react';
2+import { Box, LoadingSpinner, Row } from '@tlon/indigo-react';
33
44import { isStar } from 'lib/utils/point';
55
@@ -15,7 +15,7 @@ import AccountsDropdown from '../Dropdowns/AccountsDropdown';
1515import './L2PointHeader.scss';
1616
1717export interface L2PointHeaderProps {
18− numInvites: number;
18+ numInvites?: number;
1919 hideHome?: boolean;
2020 hideTimer?: boolean;
2121 hideInvites?: boolean;
@@ -23,7 +23,7 @@ export interface L2PointHeaderProps {
2323}
2424
2525const L2PointHeader = ({
26− numInvites = 0,
26+ numInvites,
2727 hideHome = false,
2828 hideTimer = false,
2929 hideInvites = false,
@@ -63,7 +63,11 @@ const L2PointHeader = ({
6363 {showInvites && point.showInvites && (
6464 <Row onClick={goToInvites} className="invites">
6565 <InviteIcon />
66− {numInvites}
66+ {numInvites === undefined ? (
67+ <LoadingSpinner foreground="rgba(0,0,0,0.3)" background="white" />
68+ ) : (
69+ numInvites
70+ )}
6771 </Row>
6872 )}
6973 {!hideTimer && point.isL2Spawn && !pendingTransactions.length && (
src/lib/types/Invite.ts+4
@@ -6,5 +6,9 @@ export interface Invite {
66}
77
88export interface Invites {
9+ [key: number]: Invite[];
10+}
11+
12+export interface InviteTickets {
913 [key: number]: Invite;
1014}
src/lib/useRoller.ts+26−74
@@ -40,7 +40,7 @@ import {
4040 detach,
4141 reject,
4242} from './utils/roller';
43−import { ROLLER_HOSTS } from './constants';
43+import { ETH_ZERO_ADDR, ROLLER_HOSTS } from './constants';
4444
4545import {
4646 Config,
@@ -89,12 +89,9 @@ export default function useRoller() {
8989 const {
9090 nextBatchTime,
9191 point,
92− invitePoints,
93− removeInvite,
9492 setNextBatchTime,
9593 setPendingTransactions,
9694 setInvites,
97− setInvitePoints,
9895 setInviteGeneratingNum,
9996 setPoints,
10097 updateInvite,
@@ -319,17 +316,19 @@ export default function useRoller() {
319316 };
320317
321318 const getInvites = useCallback(
322− async (isL2: boolean, getAll = false) => {
319+ async (isL2: boolean) => {
323320 try {
324321 const curPoint: number = Number(need.point(pointCursor));
325− setInvites(invitePoints.map(p => inviteTemplate(p)));
326−
327322 const _authToken = authToken.getOrElse(null);
328323 const _contracts = contracts.getOrElse(null);
329324
330325 if (_authToken && _contracts) {
331326 const spawnedPoints = isL2 ? await api.getSpawned(curPoint) : [];
332327
328+ const newPending = await api.getPendingByShip(curPoint);
329+ setPendingTransactions(newPending);
330+ const pendingSpawns = getPendingSpawns(newPending);
331+
333332 const availablePoints = await azimuth.azimuth.getUnspawnedChildren(
334333 _contracts,
335334 curPoint
@@ -340,9 +339,11 @@ export default function useRoller() {
340339 getDetails
341340 ).filter((p: number) => isPlanet(p) && availablePoints.includes(p));
342341
343− const invitePlanets = spawnedPoints.concat(
344− outgoingPoints.filter((p: number) => !spawnedPoints.includes(p))
345− );
342+ const invitePlanets = spawnedPoints
343+ .concat(
344+ outgoingPoints.filter((p: number) => !spawnedPoints.includes(p))
345+ )
346+ .filter((p: number) => !pendingSpawns.has(p));
346347
347348 const newInvites: Invite[] = [];
348349 // Iterate over all of the stored invites, generating wallet info as necessary
@@ -351,22 +352,28 @@ export default function useRoller() {
351352 for (let i = 0; i < invitePlanets.length; i++) {
352353 setInviteGeneratingNum(i + 1);
353354 const planet = invitePlanets[i];
355+ const storedInvite = storedInvites[planet];
354356 const invite =
355− storedInvites[planet] ||
356− (await generateInviteInfo(planet, _authToken));
357+ storedInvite || (await generateInviteInfo(planet, _authToken));
357358
358359 // TODO: check if the invite point's owner still matches the deterministic wallet address
359360 const planetInfo = await api.getPoint(planet);
360− if (invite.owner === planetInfo.ownership?.transferProxy?.address) {
361+ setStoredInvite(ls, invite);
362+
363+ if (
364+ invite.owner.toLowerCase() ===
365+ planetInfo.ownership?.owner?.address ||
366+ planetInfo.ownership?.transferProxy?.address !== ETH_ZERO_ADDR
367+ ) {
361368 newInvites.push(invite);
362− updateInvite(invite);
369+ updateInvite(curPoint, invite);
370+ }
371+
372+ if (storedInvite) {
363373 setStoredInvite(ls, invite);
364− } else {
365− removeInvite(planet);
366374 }
367375 }
368− setStoredInvites(ls, newInvites);
369− setInvites(newInvites);
376+ setInvites(curPoint, newInvites);
370377
371378 return newInvites;
372379 }
@@ -381,64 +388,11 @@ export default function useRoller() {
381388 controlledPoints,
382389 getDetails,
383390 pointCursor,
384− invitePoints,
385391 ls,
386− removeInvite,
387392 setInvites,
388393 setInviteGeneratingNum,
389− updateInvite,
390− ]
391− );
392−
393− const getNumInvites = useCallback(
394− async (isL2: boolean) => {
395− try {
396− const curPoint: number = Number(need.point(pointCursor));
397− const _authToken = authToken.getOrElse(null);
398− const _contracts = contracts.getOrElse(null);
399−
400− if (_authToken && _contracts) {
401− let spawnedPoints = isL2 ? await api.getSpawned(curPoint) : [];
402−
403− const availablePoints = await azimuth.azimuth.getUnspawnedChildren(
404− _contracts,
405− curPoint
406− );
407−
408− const newPending = await api.getPendingByShip(curPoint);
409− const pendingSpawns = getPendingSpawns(newPending);
410−
411− const outgoingPoints = getOutgoingPoints(
412− controlledPoints,
413− getDetails
414− ).filter((p: number) => isPlanet(p) && availablePoints.includes(p));
415−
416− const invitePoints = spawnedPoints
417− .concat(
418− outgoingPoints.filter((p: number) => !spawnedPoints.includes(p))
419− )
420− .filter((p: number) => !pendingSpawns.has(p));
421−
422− setPendingTransactions(newPending);
423− setInvitePoints(invitePoints);
424−
425− return invitePoints;
426− }
427− } catch (e) {
428− if (isDevelopment) {
429− console.warn(e);
430− }
431− }
432− },
433− [
434− api,
435− pointCursor,
436− authToken,
437− contracts,
438− controlledPoints,
439− getDetails,
440− setInvitePoints,
441394 setPendingTransactions,
395+ updateInvite,
442396 ]
443397 );
444398
@@ -851,7 +805,6 @@ export default function useRoller() {
851805 if (nextBatchTime - ONE_SECOND <= new Date().getTime()) {
852806 api.getRollerConfig().then(response => {
853807 setNextBatchTime(response.nextBatch);
854− getNumInvites(!!point?.isL2);
855808 });
856809 }
857810 }, 10000000);
@@ -866,7 +819,6 @@ export default function useRoller() {
866819 config,
867820 configureNetworkingKeys,
868821 getInvites,
869− getNumInvites,
870822 getPoints,
871823 getPointDetails,
872824 getPendingTransactions,
src/lib/walletgen.js−1
@@ -83,7 +83,6 @@ export const generateWallet = async (point, ticket, boot) => {
8383
8484 return new Promise(async resolve => {
8585 // Use a web worker to process the data
86− console.log(1, config)
8786 const processed = await worker.generateWallet(JSON.stringify(config));
8887
8988 resolve(processed);
src/store/rollerStore.ts+18−20
@@ -2,7 +2,7 @@ import create from 'zustand';
22import { PendingTransaction } from '@urbit/roller-api';
33
44import { HOUR } from 'lib/utils/roller';
5−import { Invite } from 'lib/types/Invite';
5+import { Invite, Invites } from 'lib/types/Invite';
66import Point, { Points, Relationship } from 'lib/types/Point';
77import { toL1Details } from 'lib/utils/point';
88
@@ -14,19 +14,16 @@ export interface RollerStore {
1414 point: Point;
1515 points: Points;
1616 pointList: Point[];
17− invitePoints: number[];
18− invites: Invite[];
17+ invites: Invites;
1918 recentlyCompleted: number;
2019 inviteGeneratingNum: number;
21− removeInvite: (point: number) => void;
2220 setNextBatchTime: (nextBatchTime: number) => void;
2321 setPendingTransactions: (pendingTransactions: PendingTransaction[]) => void;
2422 setPoint: (point: number) => void;
2523 setPoints: (points: Points) => void;
26− setInvitePoints: (points: number[]) => void;
27− setInvites: (invites: Invite[]) => void;
24+ setInvites: (points: number, invites: Invite[]) => void;
2825 setInviteGeneratingNum: (numGenerating: number) => void;
29− updateInvite: (invite: Invite) => void;
26+ updateInvite: (point: number, invite: Invite) => void;
3027}
3128
3229export const useRollerStore = create<RollerStore>(set => ({
@@ -35,14 +32,9 @@ export const useRollerStore = create<RollerStore>(set => ({
3532 point: EMPTY_POINT,
3633 pointList: [],
3734 points: {},
38− invitePoints: [],
39− invites: [],
35+ invites: {},
4036 recentlyCompleted: 0,
4137 inviteGeneratingNum: 0,
42− removeInvite: (point: number) =>
43− set(state => ({
44− invites: state.invites.filter(({ planet }) => point !== planet),
45− })),
4638 setNextBatchTime: (nextBatchTime: number) => set(() => ({ nextBatchTime })),
4739 setPendingTransactions: (pendingTransactions: PendingTransaction[]) =>
4840 set(state => {
@@ -60,14 +52,20 @@ export const useRollerStore = create<RollerStore>(set => ({
6052 set(state => ({ point: state.points[point] || EMPTY_POINT })),
6153 setPoints: (points: Points) =>
6254 set(() => ({ points, pointList: Object.values(points) })),
63− setInvitePoints: (invitePoints: number[]) => set(() => ({ invitePoints })),
64− setInvites: (invites: Invite[]) => set(() => ({ invites })),
55+ setInvites: (point: number, invites: Invite[]) =>
56+ set(state => {
57+ const newInvites: Invites = {};
58+ newInvites[point] = invites;
59+ return { invites: Object.assign(state.invites, newInvites) };
60+ }),
6561 setInviteGeneratingNum: (inviteGeneratingNum: number) =>
6662 set(() => ({ inviteGeneratingNum })),
67− updateInvite: (invite: Invite) =>
68− set(state => ({
69− invites: state.invites.map(i =>
63+ updateInvite: (point: number, invite: Invite) =>
64+ set(state => {
65+ const newInvites: Invites = {};
66+ newInvites[point] = state.invites[point]?.map(i =>
7067 i.planet === invite.planet ? invite : i
71− ),
72− })),
68+ );
69+ return { invites: Object.assign(state.invites, newInvites) };
70+ }),
7371}));
src/store/storage/roller.ts+4−4
@@ -1,10 +1,10 @@
11import SecureLS from 'secure-ls';
2−import { Invite, Invites } from 'lib/types/Invite';
2+import { Invite, InviteTickets } from 'lib/types/Invite';
33
44const INVITES_KEY = 'invites';
55const HIDE_MIGRATION_MESSAGE_KEY = 'hide_migration_message';
66
7−export const getStoredInvites = (ls: SecureLS): Invites => {
7+export const getStoredInvites = (ls: SecureLS): InviteTickets => {
88 let invites = {};
99 try {
1010 invites = ls.get(INVITES_KEY);
@@ -13,7 +13,7 @@ export const getStoredInvites = (ls: SecureLS): Invites => {
1313};
1414
1515export const setStoredInvites = (ls: SecureLS, newInvites: Invite[]) => {
16− let invites: Invites = {};
16+ let invites: InviteTickets = {};
1717 try {
1818 invites = ls.get(INVITES_KEY) || {};
1919 } catch (e) {}
@@ -25,7 +25,7 @@ export const setStoredInvites = (ls: SecureLS, newInvites: Invite[]) => {
2525};
2626
2727export const setStoredInvite = (ls: SecureLS, newInvite: Invite) => {
28− let invites: Invites = {};
28+ let invites: InviteTickets = {};
2929 try {
3030 invites = ls.get(INVITES_KEY) || {};
3131 } catch (e) {}
src/views/Invite/Cohort.tsx+16−19
@@ -59,7 +59,6 @@ export default function InviteCohort() {
5959 point,
6060 pendingTransactions,
6161 invites,
62− invitePoints,
6362 inviteGeneratingNum,
6463 setInviteGeneratingNum,
6564 setInvites,
@@ -75,7 +74,7 @@ export default function InviteCohort() {
7574 } = useRoller();
7675 const { contracts }: any = useNetwork();
7776 const { syncControlledPoints }: any = usePointCache();
78− const currentL2 = Boolean(point?.isL2Spawn);
77+ const currentL2 = Boolean(point.isL2Spawn);
7978
8079 const _contracts = need.contracts(contracts);
8180
@@ -90,12 +89,7 @@ export default function InviteCohort() {
9089 const [page, setPage] = useState(0);
9190
9291 const { construct, unconstruct, completed, bind } = useIssueChild();
93−
94− useEffect(() => {
95− if (invitePoints.length > 0) {
96− getInvites(currentL2, true);
97− }
98− }, []); // eslint-disable-line react-hooks/exhaustive-deps
92+ const invitePoints = invites[point.value] || [];
9993
10094 // Set up the invite spawn if on L1
10195 useEffect(() => {
@@ -116,7 +110,7 @@ export default function InviteCohort() {
116110 for (let i = 0; i < possiblePoints.length; i++) {
117111 const p = possiblePoints[i];
118112 if (
119− !invites.find(({ planet }) => planet === p) &&
113+ !invitePoints.find(({ planet }) => planet === p) &&
120114 isPlanet(p) &&
121115 (await azimuth.azimuth.getOwner(_contracts, p)) === ETH_ZERO_ADDR
122116 ) {
@@ -153,7 +147,7 @@ export default function InviteCohort() {
153147 construct,
154148 showInviteForm,
155149 unconstruct,
156− invites,
150+ invitePoints,
157151 ]);
158152
159153 useEffect(() => {
@@ -169,20 +163,23 @@ export default function InviteCohort() {
169163 }
170164
171165 syncControlledPoints();
172− setInvites([...invites, { ...l1Invite, hash: '', owner: '' }]);
166+ setInvites(point.value, [
167+ ...invitePoints,
168+ { ...l1Invite, hash: '', owner: '' },
169+ ]);
173170 setShowInviteForm(false);
174171 setL1Invite(null);
175172 unconstruct();
176173 pop();
177− }, [completed, currentL2]); // eslint-disable-line react-hooks/exhaustive-deps
174+ }, [completed, currentL2, point]); // eslint-disable-line react-hooks/exhaustive-deps
178175
179− const invitesToDisplay = invites.slice(
176+ const invitesToDisplay = invitePoints.slice(
180177 page * INVITES_PER_PAGE,
181178 (page + 1) * INVITES_PER_PAGE
182179 );
183180
184181 const hasPending = Boolean(pendingTransactions.length);
185− const hasInvites = Boolean(invites.length);
182+ const hasInvites = Boolean(invitePoints.length);
186183
187184 const createInvites = useCallback(async () => {
188185 setLoading(true);
@@ -208,7 +205,7 @@ export default function InviteCohort() {
208205 const downloadCsv = useCallback(() => {
209206 const generateAndDownload = async () => {
210207 setLoading(true);
211− const invites = await getInvites(currentL2, true);
208+ const invites = await getInvites(currentL2);
212209 if (invites) {
213210 const csv = invites.reduce(
214211 (csvData, { ticket, planet }, ind) =>
@@ -224,7 +221,7 @@ export default function InviteCohort() {
224221 //provide the name for the CSV file to be downloaded
225222 hiddenElement.download = generateCsvName(
226223 DEFAULT_CSV_NAME,
227− point?.patp?.slice(1) || 'bridge'
224+ point.patp?.slice(1) || 'bridge'
228225 );
229226 hiddenElement.click();
230227 } else {
@@ -313,8 +310,8 @@ export default function InviteCohort() {
313310 const header = (
314311 <h5>
315312 You have
316− <span className="number-emphasis"> {invites.length} </span>
317− Planet Code{invites.length === 1 ? '' : 's'}
313+ <span className="number-emphasis"> {invitePoints.length} </span>
314+ Planet Code{invitePoints.length === 1 ? '' : 's'}
318315 </h5>
319316 );
320317
@@ -435,7 +432,7 @@ export default function InviteCohort() {
435432 <Paginator
436433 page={page}
437434 numPerPage={INVITES_PER_PAGE}
438− numElements={invites.length}
435+ numElements={invitePoints.length}
439436 goPrevious={() => setPage(page - 1)}
440437 goNext={goNextPage}
441438 />
src/views/Point/Point.tsx+4−4
@@ -33,7 +33,7 @@ export default function Point() {
3333 const { pop, push, names }: any = useLocalRouter();
3434 const { wallet }: any = useWallet();
3535 const { syncExtras }: any = usePointCache();
36− const { getNumInvites, getPendingTransactions } = useRoller();
36+ const { getInvites, getPendingTransactions } = useRoller();
3737 const { pendingTransactions, point, invites } = useRollerStore();
3838 const { nextRoll } = useTimerStore();
3939 const networkKeysSet = useHasNetworkKeysSet();
@@ -69,12 +69,12 @@ export default function Point() {
6969 const getTransactions = async () => {
7070 setLoading(true);
7171 getPendingTransactions();
72− getNumInvites(point.isL2);
72+ getInvites(point.isL2);
7373 setTimeout(() => setLoading(false), 100);
7474 };
7575
7676 await getTransactions();
77− }, [point, getNumInvites, getPendingTransactions, setLoading]);
77+ }, [point, getInvites, getPendingTransactions, setLoading]);
7878
7979 useEffect(() => {
8080 loadL1Info();
@@ -132,7 +132,7 @@ export default function Point() {
132132 header={
133133 <L2PointHeader
134134 hideTimer={!!spawnedPending}
135− numInvites={invitePoints.length}
135+ numInvites={invites[point.value]?.length}
136136 hideInvites={!networkKeysSet}
137137 />
138138 }>
src/worker/worker.ts−3
@@ -1,12 +1,9 @@
11import kg from 'urbit-key-generation';
22
33export async function generateWallet(data: string): Promise<string> {
4− console.log(2, data)
54 // Process the data without stalling the UI
65 const config = JSON.parse(data);
7− console.log(3)
86 const wallet = await kg.generateWallet(config);
9− console.log(4)
107
118 return wallet;
129}