From b8d146506f0aa90f43cf9732ce5d3504c0d1d48d Mon Sep 17 00:00:00 2001 From: Jakz Date: Tue, 30 Apr 2024 13:15:46 +0800 Subject: [PATCH] Add contract nft selector to gallery editor --- .../NftSelectorContractPickerGrid.tsx | 23 ++- .../NftSelectorContractToolbar.tsx | 65 ++++++++ apps/mobile/src/navigation/types.ts | 1 + .../GalleryEditorNftSelector.tsx | 26 +-- ...GalleryEditorNftSelectorContractScreen.tsx | 157 ++++++++++++++++-- .../NftSelectorPickerGrid.tsx | 14 +- .../NftSelectorPickerSingularAsset.tsx | 4 +- 7 files changed, 251 insertions(+), 39 deletions(-) create mode 100644 apps/mobile/src/components/NftSelector/NftSelectorContract/NftSelectorContractToolbar.tsx diff --git a/apps/mobile/src/components/NftSelector/NftSelectorContract/NftSelectorContractPickerGrid.tsx b/apps/mobile/src/components/NftSelector/NftSelectorContract/NftSelectorContractPickerGrid.tsx index bf4cd65a62..b26479dd99 100644 --- a/apps/mobile/src/components/NftSelector/NftSelectorContract/NftSelectorContractPickerGrid.tsx +++ b/apps/mobile/src/components/NftSelector/NftSelectorContract/NftSelectorContractPickerGrid.tsx @@ -6,6 +6,7 @@ import { graphql, useFragment } from 'react-relay'; import { GalleryRefreshControl } from '~/components/GalleryRefreshControl'; import { useSyncTokensActions } from '~/contexts/SyncTokensContext'; import { NftSelectorContractPickerGridFragment$key } from '~/generated/NftSelectorContractPickerGridFragment.graphql'; +import { SelectedItemMultiMode } from '~/screens/GalleryScreen/GalleryEditorNftSelector'; import { NftSelectorLoadingSkeleton } from '~/screens/NftSelectorScreen/NftSelectorLoadingSkeleton'; import { NftSelectorPickerSingularAsset } from '~/screens/NftSelectorScreen/NftSelectorPickerSingularAsset'; @@ -14,9 +15,19 @@ type Props = { tokenRefs: NftSelectorContractPickerGridFragment$key; onSelect: (tokenId: string) => void; style?: ViewProps['style']; + + isMultiselectMode?: boolean; + selectedTokens?: SelectedItemMultiMode[]; }; -export function NftSelectorContractPickerGrid({ isCreator, tokenRefs, onSelect, style }: Props) { +export function NftSelectorContractPickerGrid({ + isCreator, + isMultiselectMode, + tokenRefs, + onSelect, + selectedTokens, + style, +}: Props) { const tokens = useFragment( graphql` fragment NftSelectorContractPickerGridFragment on Token @relay(plural: true) { @@ -43,6 +54,11 @@ export function NftSelectorContractPickerGrid({ isCreator, tokenRefs, onSelect, syncCreatedTokensForExistingContract(contractId); }, [syncCreatedTokensForExistingContract, contractId]); + const isSelected = useMemo(() => { + const selectedTokenIds = selectedTokens?.map((token) => token.id) ?? []; + return (tokenId: string) => selectedTokenIds.includes(tokenId); + }, [selectedTokens]); + const renderItem = useCallback>( ({ item: row }) => { return ( @@ -53,6 +69,8 @@ export function NftSelectorContractPickerGrid({ isCreator, tokenRefs, onSelect, key={token.dbid} onPress={onSelect} tokenRef={token} + isMultiselectMode={isMultiselectMode} + isSelected={isSelected(token.dbid)} /> ); })} @@ -63,7 +81,7 @@ export function NftSelectorContractPickerGrid({ isCreator, tokenRefs, onSelect, ); }, - [onSelect] + [isMultiselectMode, isSelected, onSelect] ); const rows = useMemo(() => { @@ -83,6 +101,7 @@ export function NftSelectorContractPickerGrid({ isCreator, tokenRefs, onSelect, renderItem={renderItem} data={rows} estimatedItemSize={100} + extraData={[isMultiselectMode, selectedTokens]} refreshControl={ isCreator ? ( void; + onSelectedAllPress: () => void; + hasSelectedItems: boolean; +}; + +export function NftSelectorContractToolbar({ + contractName, + isMultiselectMode, + setIsMultiselectMode, + onSelectedAllPress, + hasSelectedItems, +}: Props) { + const handleMultiselectPress = useCallback(() => { + setIsMultiselectMode?.(!isMultiselectMode); + }, [isMultiselectMode, setIsMultiselectMode]); + + return ( + + {contractName} + + + + + {hasSelectedItems ? 'Deselect All' : 'Select All'} + + + } + eventElementId="NftSelectorSelectorSettingsButton" + eventName="NftSelectorSelectorSettingsButton pressed" + eventContext={contexts.Posts} + color={isMultiselectMode ? 'active' : 'default'} + /> + {}} + isSyncing={false} + eventElementId="NftSelectorSelectorRefreshButton" + eventName="NftSelectorSelectorRefreshButton pressed" + /> + + + ); +} diff --git a/apps/mobile/src/navigation/types.ts b/apps/mobile/src/navigation/types.ts index fe136c6f5d..6544fc2cf3 100644 --- a/apps/mobile/src/navigation/types.ts +++ b/apps/mobile/src/navigation/types.ts @@ -31,6 +31,7 @@ export type RootStackNavigatorParamList = { galleryId: string; }; NftSelectorContractGalleryEditor: { + galleryId: string; contractAddress: string; ownerFilter?: 'Collected' | 'Created'; }; diff --git a/apps/mobile/src/screens/GalleryScreen/GalleryEditorNftSelector.tsx b/apps/mobile/src/screens/GalleryScreen/GalleryEditorNftSelector.tsx index 1367ff04f1..10022aa9e4 100644 --- a/apps/mobile/src/screens/GalleryScreen/GalleryEditorNftSelector.tsx +++ b/apps/mobile/src/screens/GalleryScreen/GalleryEditorNftSelector.tsx @@ -1,6 +1,6 @@ import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'; import { Suspense, useCallback, useMemo, useState } from 'react'; -import { Text, View } from 'react-native'; +import { View } from 'react-native'; import { Button } from '~/components/Button'; import { NftSelectorHeader } from '~/components/NftSelector/NftSelectorHeader'; @@ -105,12 +105,13 @@ export function GalleryEditorNftSelector() { navigation.navigate({ name: 'NftSelectorContractGalleryEditor', params: { + galleryId: route.params.galleryId, contractAddress, }, }); } }, - [isMultiselectMode, navigation] + [isMultiselectMode, navigation, route.params.galleryId] ); const handleAddSelectedTokens = useCallback(() => { @@ -142,17 +143,20 @@ export function GalleryEditorNftSelector() { + isMultiselectMode && selectedTokens.length > 0 ? ( +