Skip to content

Commit

Permalink
fetch tokens while syncing mobile & web
Browse files Browse the repository at this point in the history
  • Loading branch information
pvicensSpacedev committed Apr 17, 2024
1 parent f000929 commit 2454cc9
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 88 deletions.
70 changes: 56 additions & 14 deletions apps/mobile/src/screens/NftSelectorScreen/NftSelectorPickerGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { ResizeMode } from 'expo-av';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { View, ViewProps } from 'react-native';
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
import { useFragment, useLazyLoadQuery } from 'react-relay';
import { graphql } from 'relay-runtime';
import { useFragment, useLazyLoadQuery, useRelayEnvironment } from 'react-relay';
import { fetchQuery, graphql } from 'relay-runtime';

import { TokenFailureBoundary } from '~/components/Boundaries/TokenFailureBoundary/TokenFailureBoundary';
import { Button } from '~/components/Button';
Expand All @@ -27,6 +27,7 @@ import {
NftSelectorPickerGridTokensFragment$data,
NftSelectorPickerGridTokensFragment$key,
} from '~/generated/NftSelectorPickerGridTokensFragment.graphql';
import { NftSelectorPickerGridTokensQuery } from '~/generated/NftSelectorPickerGridTokensQuery.graphql';
import { LoginStackNavigatorProp } from '~/navigation/types';
import {
NetworkChoice,
Expand All @@ -37,8 +38,6 @@ import { contexts } from '~/shared/analytics/constants';
import { removeNullValues } from '~/shared/relay/removeNullValues';
import { doesUserOwnWalletFromChainFamily } from '~/shared/utils/doesUserOwnWalletFromChainFamily';

import { NftSelectorLoadingSkeleton } from './NftSelectorLoadingSkeleton';

type NftSelectorPickerGridProps = {
style?: ViewProps['style'];
searchCriteria: {
Expand Down Expand Up @@ -89,7 +88,7 @@ export function NftSelectorPickerGrid({
);
const tokenRefs = removeNullValues(query.viewer?.user?.tokens);

const tokens = useFragment<NftSelectorPickerGridTokensFragment$key>(
const tokensData = useFragment<NftSelectorPickerGridTokensFragment$key>(
graphql`
fragment NftSelectorPickerGridTokensFragment on Token @relay(plural: true) {
dbid
Expand Down Expand Up @@ -120,12 +119,55 @@ export function NftSelectorPickerGrid({
tokenRefs
);

const { isSyncing, isSyncingCreatedTokens } = useSyncTokensActions();

const relayEnvironment = useRelayEnvironment();

useEffect(() => {
let intervalId: number | undefined;

if (isSyncing) {
const fetchTokens = async () => {
const tokensQuery = graphql`
query NftSelectorPickerGridTokensQuery {
viewer {
... on Viewer {
user {
tokens {
dbid
creationTime
...NftSelectorPickerGridTokensFragment
}
}
}
}
}
`;

await fetchQuery<NftSelectorPickerGridTokensQuery>(
relayEnvironment,
tokensQuery,
{}
).toPromise();
};

fetchTokens();
intervalId = window.setInterval(fetchTokens, 5000);
}

return () => {
if (intervalId !== undefined) {
clearInterval(intervalId);
}
};
}, [isSyncing, relayEnvironment]);

const { openManageWallet } = useManageWalletActions();

// [GAL-4202] this logic could be consolidated across web editor + web selector + mobile selector
// but also don't overdo it if there's sufficient differentiation between web and mobile UX
const filteredTokens = useMemo(() => {
return tokens
return tokensData
.filter((token) => {
const isSpam = token.definition?.contract?.isSpam || token.isSpamByUser;

Expand Down Expand Up @@ -154,7 +196,7 @@ export function NftSelectorPickerGrid({
searchCriteria.networkFilter,
searchCriteria.ownerFilter,
searchCriteria.searchQuery,
tokens,
tokensData,
]);

const sortedTokens = useMemo(() => {
Expand Down Expand Up @@ -220,8 +262,6 @@ export function NftSelectorPickerGrid({
return groups;
}, [sortedTokens]);

const { isSyncing, isSyncingCreatedTokens } = useSyncTokensActions();

// TODO: this logic is messy and shared with web; should be refactored
const handleRefresh = useCallback(() => {
if (!ownsWalletFromSelectedChainFamily) {
Expand All @@ -245,12 +285,16 @@ export function NftSelectorPickerGrid({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchCriteria.networkFilter, searchCriteria.ownerFilter]);

type Row = { groups: Group[] };
type Row = { groups: Group[]; id: string };
const rows = useMemo(() => {
const rows: Row[] = [];

for (let i = 0; i < Object.keys(groups).length; i += 3) {
rows.push({ groups: Object.values(groups).slice(i, i + 3) });
const groupSlice = Object.values(groups).slice(i, i + 3);
const sliceKey = groupSlice.map((group) => group.address).join('-');
const id = `row-${sliceKey}`;

rows.push({ groups: groupSlice, id });
}

return rows;
Expand Down Expand Up @@ -298,9 +342,6 @@ export function NftSelectorPickerGrid({

const isRefreshing = isSyncing || isSyncingCreatedTokens;

if (isRefreshing) {
return <NftSelectorLoadingSkeleton />;
}
const user = query?.viewer?.user;
if (!user?.primaryWallet) {
return (
Expand Down Expand Up @@ -333,6 +374,7 @@ export function NftSelectorPickerGrid({
return (
<View className="flex flex-col flex-1" style={style}>
<FlashList
keyExtractor={(item) => item.id}
renderItem={renderItem}
data={rows}
estimatedItemSize={200}
Expand Down
87 changes: 37 additions & 50 deletions apps/web/src/components/NftSelector/NftSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Suspense, useCallback, useEffect, useMemo } from 'react';
import { graphql, useFragment, useLazyLoadQuery } from 'react-relay';
import { useCallback, useEffect, useMemo } from 'react';
import { graphql, useLazyLoadQuery } from 'react-relay';
import { useSyncCreatedTokensForExistingContract } from 'src/hooks/api/tokens/useSyncCreatedTokensForExistingContract';
import styled from 'styled-components';

import { usePostComposerContext } from '~/contexts/postComposer/PostComposerContext';
import { NftSelectorQuery } from '~/generated/NftSelectorQuery.graphql';
import { NftSelectorViewerFragment$key } from '~/generated/NftSelectorViewerFragment.graphql';
import useSyncTokens from '~/hooks/api/tokens/useSyncTokens';
import { ChevronLeftIcon } from '~/icons/ChevronLeftIcon';
import { RefreshIcon } from '~/icons/RefreshIcon';
Expand All @@ -26,7 +25,6 @@ import { NftSelectorCollectionGroup } from './groupNftSelectorCollectionsByAddre
import { NftSelectorFilterNetwork } from './NftSelectorFilter/NftSelectorFilterNetwork';
import { NftSelectorFilterSort } from './NftSelectorFilter/NftSelectorFilterSort';
import { NftSelectorViewSelector } from './NftSelectorFilter/NftSelectorViewSelector';
import { NftSelectorLoadingView } from './NftSelectorLoadingView';
import { NftSelectorSearchBar } from './NftSelectorSearchBar';
import NftSelectorTokens from './NftSelectorTokens';

Expand All @@ -40,11 +38,7 @@ type Props = {
export type NftSelectorContractType = Omit<NftSelectorCollectionGroup, 'tokens'> | null;

export function NftSelector(props: Props) {
return (
<Suspense fallback={<NftSelectorLoadingView />}>
<NftSelectorInner {...props} />
</Suspense>
);
return <NftSelectorInner {...props} />;
}

function NftSelectorInner({ onSelectToken, headerText, preSelectedContract, eventFlow }: Props) {
Expand All @@ -56,55 +50,49 @@ function NftSelectorInner({ onSelectToken, headerText, preSelectedContract, even
viewer {
... on Viewer {
...NftSelectorViewerFragment
}
}
...NftSelectorTokensQueryFragment
}
`,
{}
);
user {
dbid
tokens(ownershipFilter: [Creator, Holder]) {
__typename
const viewer = useFragment<NftSelectorViewerFragment$key>(
graphql`
fragment NftSelectorViewerFragment on Viewer {
user {
dbid
tokens(ownershipFilter: [Creator, Holder]) {
__typename
dbid
creationTime
definition {
name
chain
contract {
dbid
name
isSpam
creationTime
definition {
name
chain
contract {
dbid
name
isSpam
}
}
isSpamByUser
ownerIsHolder
ownerIsCreator
...useTokenSearchResultsFragment
...NftSelectorTokensFragment
# Needed for when we select a token, we want to have this already in the cache
# eslint-disable-next-line relay/must-colocate-fragment-spreads
...PostComposerTokenFragment
}
}
isSpamByUser
ownerIsHolder
ownerIsCreator
...useTokenSearchResultsFragment
...NftSelectorTokensFragment
# Needed for when we select a token, we want to have this already in the cache
# eslint-disable-next-line relay/must-colocate-fragment-spreads
...PostComposerTokenFragment
}
}
...NftSelectorTokensQueryFragment
}
`,
query.viewer
{}
);

const tokens = useMemo(() => removeNullValues(viewer?.user?.tokens), [viewer?.user?.tokens]);
const tokens = useMemo(
() => removeNullValues(query.viewer?.user?.tokens),
[query.viewer?.user?.tokens]
);
const { searchQuery, setSearchQuery, tokenSearchResults, isSearching } = useTokenSearchResults<
(typeof tokens)[0]
>({
Expand Down Expand Up @@ -217,7 +205,7 @@ function NftSelectorInner({ onSelectToken, headerText, preSelectedContract, even

const ownsWalletFromSelectedChainFamily = doesUserOwnWalletFromChainFamily(network, query);

const isRefreshDisabledAtUserLevel = isRefreshDisabledForUser(viewer?.user?.dbid ?? '');
const isRefreshDisabledAtUserLevel = isRefreshDisabledForUser(query?.viewer?.user?.dbid ?? '');
const refreshDisabled =
isRefreshDisabledAtUserLevel || !ownsWalletFromSelectedChainFamily || isLocked;

Expand Down Expand Up @@ -358,7 +346,6 @@ function NftSelectorInner({ onSelectToken, headerText, preSelectedContract, even

<NftSelectorTokens
selectedFilter={filterType}
isLocked={isLocked}
tokenRefs={tokensToDisplay}
selectedContractAddress={selectedContract?.address ?? null}
onSelectContract={handleSelectContract}
Expand Down
7 changes: 0 additions & 7 deletions apps/web/src/components/NftSelector/NftSelectorTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ import { Chain } from '~/shared/utils/chains';
import CreatorSupportAnnouncement from '../Announcement/CreatorSupportAnnouncement';
import { VStack } from '../core/Spacer/Stack';
import { NftSelectorContractType } from './NftSelector';
import { NftSelectorLoadingView } from './NftSelectorLoadingView';
import { NftSelectorView } from './NftSelectorView';

type Props = {
selectedFilter: string;
isLocked: boolean;
tokenRefs: NftSelectorTokensFragment$key;
selectedContractAddress: string | null;
onSelectContract: (contract: NftSelectorContractType) => void;
Expand All @@ -31,7 +29,6 @@ type Props = {

export default function NftSelectorTokens({
selectedFilter,
isLocked,
selectedContractAddress,
onSelectContract,
onSelectToken,
Expand Down Expand Up @@ -85,10 +82,6 @@ export default function NftSelectorTokens({
);
}

if (isLocked) {
return <NftSelectorLoadingView />;
}

return (
<NftSelectorView
tokenRefs={tokens}
Expand Down
53 changes: 52 additions & 1 deletion apps/web/src/components/NftSelector/NftSelectorView.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { graphql, useFragment } from 'react-relay';
import { fetchQuery, graphql, useFragment, useRelayEnvironment } from 'react-relay';
import { AutoSizer, List, ListRowProps } from 'react-virtualized';
import styled from 'styled-components';

import { useModalActions } from '~/contexts/modal/ModalContext';
import { NftSelectorQuery } from '~/generated/NftSelectorQuery.graphql';
import { NftSelectorViewFragment$key } from '~/generated/NftSelectorViewFragment.graphql';
import useSyncTokens from '~/hooks/api/tokens/useSyncTokens';
import useAddWalletModal from '~/hooks/useAddWalletModal';
import useWindowSize, { useIsMobileWindowWidth } from '~/hooks/useWindowSize';
import { contexts } from '~/shared/analytics/constants';
Expand Down Expand Up @@ -54,6 +56,55 @@ export function NftSelectorView({
tokenRefs
);

const { isSyncing } = useSyncTokens();

const relayEnvironment = useRelayEnvironment();

useEffect(() => {
let intervalId: number | undefined;


if (isSyncing) {
const fetchTokens = async () => {
const tokensQuery = graphql`
query NftSelectorViewQuery {
viewer {
... on Viewer {
user {
dbid
tokens(ownershipFilter: [Creator, Holder]) {
__typename
dbid
...NftSelectorTokensFragment
# Needed for when we select a token, we want to have this already in the cache
# eslint-disable-next-line relay/must-colocate-fragment-spreads
...PostComposerTokenFragment
}
}
}
}
...NftSelectorTokensQueryFragment
}
`;

await fetchQuery<NftSelectorQuery>(relayEnvironment, tokensQuery, {}).toPromise();
};

fetchTokens();
intervalId = window.setInterval(fetchTokens, 5000);
}

return () => {
if (intervalId !== undefined) {
clearInterval(intervalId);
}
};
}, [isSyncing, relayEnvironment]);

const groupedTokens = groupNftSelectorCollectionsByAddress({
ignoreSpam: false,
tokenRefs: tokens,
Expand Down
Loading

0 comments on commit 2454cc9

Please sign in to comment.