From a75db28f04f13fceaac9898c565d6f4da24b537d Mon Sep 17 00:00:00 2001 From: gafar habeeb akande Date: Sat, 29 Aug 2026 17:31:20 +0100 Subject: [PATCH 1/6] fix: Add performance profiling and list virtualization for large (#103) --- app/guilds.tsx | 68 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/app/guilds.tsx b/app/guilds.tsx index 3908401..fd6f6f5 100644 --- a/app/guilds.tsx +++ b/app/guilds.tsx @@ -1,12 +1,12 @@ import { View, - FlatList, TextInput, TouchableOpacity, Text, RefreshControl, useColorScheme, } from "react-native"; +import { FlashList } from "@shopify/flash-list"; import { useRouter } from "expo-router"; import { useWallet } from "../src/features/wallet/useWallet"; import { useGuilds, type GuildListItem } from "../src/features/guilds/useGuilds"; @@ -33,6 +33,32 @@ type GuildListRow = { status?: EnrichedMembership["status"]; }; +const GuildCardListItem = React.memo(function GuildCardListItem({ + item, + offlineCached, + onPress, +}: { + item: GuildListRow; + offlineCached: boolean; + onPress: (guildId: string) => void; +}) { + const handlePress = useCallback(() => { + onPress(item.guildId); + }, [item.guildId, onPress]); + + return ( + + ); +}); + function rowsFromWalletGuilds( guilds: GuildListItem[], memberships: EnrichedMembership[], @@ -114,6 +140,28 @@ export default function Guilds() { } }, [guildsQuery, membershipsQuery, queryClient, walletAddress]); + const handleGuildPress = useCallback( + (guildId: string) => { + router.push(`/guilds/${guildId}`); + }, + [router], + ); + + const keyExtractor = useCallback((item: GuildListRow) => item.guildId, []); + + const isShowingOfflineCache = staleState.isOffline && filteredGuilds.length > 0; + + const renderItem = useCallback( + ({ item }: { item: GuildListRow }) => ( + + ), + [handleGuildPress, isShowingOfflineCache], + ); + if (!walletAddress) { return ( @@ -215,30 +263,20 @@ export default function Guilds() { ); const isRefreshing = isRefetching || guildsQuery.isRefetching || membershipsQuery.isRefetching; - const isShowingOfflineCache = staleState.isOffline && filteredGuilds.length > 0; return ( - item.guildId} + keyExtractor={keyExtractor} contentContainerStyle={{ padding: 16 }} + estimatedItemSize={96} testID="guilds-list" ListHeaderComponent={searchHeader} refreshControl={} - renderItem={({ item }) => ( - router.push(`/guilds/${item.guildId}`)} - /> - )} + renderItem={renderItem} ListEmptyComponent={ Date: Sat, 29 Aug 2026 17:31:21 +0100 Subject: [PATCH 2/6] fix: Add performance profiling and list virtualization for large (#103) --- app/profile.tsx | 107 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 8 deletions(-) diff --git a/app/profile.tsx b/app/profile.tsx index 5e9f6be..e549b76 100644 --- a/app/profile.tsx +++ b/app/profile.tsx @@ -1,5 +1,5 @@ -import { View, Text, ScrollView, TouchableOpacity, RefreshControl } from "react-native"; -import React, { useState, useRef, useEffect, useCallback } from "react"; +import { View, Text, FlatList, TouchableOpacity, RefreshControl } from "react-native"; +import React, { memo, useState, useRef, useEffect, useCallback } from "react"; import { useRouter } from "expo-router"; import { useWallet } from "../src/features/wallet/useWallet"; import { useWalletConnectModal } from "../src/features/wallet/WalletConnectProvider"; @@ -23,6 +23,73 @@ const CONNECTION_LABELS: Record = { embedded: "Embedded Wallet", }; +type DashboardNavItem = { + id: string; + title: string; + subtitle: string; + route: string; + testID: string; +}; + +const NAV_ITEMS: DashboardNavItem[] = [ + { + id: "guilds", + title: "My Guilds", + subtitle: "View your memberships and roles", + route: "/guilds", + testID: "navigate-guilds-button", + }, + { + id: "access-check", + title: "Access Check", + subtitle: "Verify resource access status", + route: "/access-check", + testID: "navigate-access-check-button", + }, + { + id: "settings", + title: "App Settings", + subtitle: "Configuration and info", + route: "/settings", + testID: "navigate-settings-button", + }, +]; + +const NAV_ITEM_HEIGHT = 96; +const getNavItemLayout = (_: unknown, index: number) => ({ + length: NAV_ITEM_HEIGHT, + offset: NAV_ITEM_HEIGHT * index, + index, +}); + +const NavigationCard = memo(function NavigationCard({ + item, + onPress, +}: { + item: DashboardNavItem; + onPress: (route: string) => void; +}) { + return ( + onPress(item.route)} + activeOpacity={0.7} + className="mb-4" + accessibilityRole="link" + accessibilityLabel={item.title} + accessibilityHint={item.subtitle} + testID={item.testID} + > + + + {item.title} + {item.subtitle} + + + + + ); +}); + export default function Profile() { const router = useRouter(); const { walletAddress, isConnected, connectionKind, isVerified, verifyOwnership, connectManually, disconnect } = useWallet(); @@ -145,16 +212,35 @@ export default function Profile() { const isRefreshing = isConnected && (isManuallyRefreshing || membershipsQuery.isRefetching); + const handleNavPress = useCallback((route: string) => { + router.push(route as never); + }, [router]); + + const renderNavItem = useCallback( + ({ item }: { item: DashboardNavItem }) => ( + + ), + [handleNavPress], + ); + + const keyExtractor = useCallback((item: DashboardNavItem) => item.id, []); + return ( - - } - > + data={isConnected ? NAV_ITEMS : []} + renderItem={renderNavItem} + keyExtractor={keyExtractor} + getItemLayout={getNavItemLayout} + initialNumToRender={4} + maxToRenderPerBatch={8} + windowSize={5} + removeClippedSubviews + ListHeaderComponent={ + <> {staleState.isOffline ? ( ) : staleState.isStale && staleState.reason ? ( @@ -348,7 +434,12 @@ export default function Profile() { )} - + + } + refreshControl={ + + } + /> ); } \ No newline at end of file From a33d837cb3afbf1d5a8ab3258d056676540b2dfa Mon Sep 17 00:00:00 2001 From: gafar habeeb akande Date: Sat, 29 Aug 2026 17:31:22 +0100 Subject: [PATCH 3/6] fix: Add performance profiling and list virtualization for large (#103) --- src/components/GuildCard.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/GuildCard.tsx b/src/components/GuildCard.tsx index 7a5dedb..3edb973 100644 --- a/src/components/GuildCard.tsx +++ b/src/components/GuildCard.tsx @@ -1,5 +1,5 @@ import { View, Text, TouchableOpacity } from "react-native"; -import React from "react"; +import React, { memo } from "react"; import { Card } from "./Card"; import { RoleBadge } from "./RoleBadge"; import type { GuildPassStatus } from "../features/passes/passCache"; @@ -11,7 +11,7 @@ type GuildCardProps = { roleCount: number; status?: GuildPassStatus; offlineCached?: boolean; - onPress: () => void; + onPress: (id: string) => void; }; const STATUS_STYLES: Record< @@ -50,7 +50,7 @@ const STATUS_STYLES: Record< }, }; -export const GuildCard = ({ +const GuildCard = memo(({ name, id, isActive, @@ -64,12 +64,12 @@ export const GuildCard = ({ return ( onPress(id)} activeOpacity={0.7} accessibilityRole="button" accessibilityLabel={`${name}, ${statusStyle.label.toLowerCase()}, ${roleCount} roles${ offlineCached ? ", cached offline" : "" - }`} + }} > @@ -98,4 +98,7 @@ export const GuildCard = ({ ); -}; +}); + +export { GuildCard }; +export default GuildCard; From 0932af19b657f29c9a3a381a35c5ca024498e606 Mon Sep 17 00:00:00 2001 From: gafar habeeb akande Date: Sat, 29 Aug 2026 17:31:24 +0100 Subject: [PATCH 4/6] fix: Add performance profiling and list virtualization for large (#103) --- package.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 09d7580..15c266a 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@babel/runtime": "^7.29.7", - "@ethersproject/shims": "^5.8.0", + "@ethersweet/shims": "^5.8.0", "@guildpass/sdk": "github:Adamantine-Guild/guildpass-sdk", "@privy-io/expo": "^0.70.3", "@privy-io/expo-native-extensions": "^0.0.12", @@ -32,7 +32,7 @@ "@walletconnect/modal-react-native": "^1.1.0", "@walletconnect/react-native-compat": "^2.11.3", "elliptic": "^6.6.1", - "expo": "~50.0.14", + "expo": "~57.0.14", "expo-application": "~5.8.3", "expo-build-properties": "^0.11.1", "expo-camera": "~14.1.3", @@ -40,14 +40,14 @@ "expo-haptics": "~12.8.1", "expo-constants": "~15.4.5", "expo-crypto": "~12.8.1", - "expo-linking": "~6.2.2", + "expo-linking": "^6.2.2", "expo-local-authentication": "^57.0.1", "expo-notifications": "~0.27.6", "expo-router": "~3.4.8", "expo-secure-store": "~12.8.1", "expo-sqlite": "^57.0.1", "expo-status-bar": "~1.11.1", - "expo-updates": "~0.24.13", + "expo-updates": "^0.24.13", "expo-web-browser": "~12.8.2", "fast-text-encoding": "^1.0.6", "js-sha3": "^0.12.0", @@ -60,6 +60,7 @@ "react-native-safe-area-context": "4.8.2", "react-native-screens": "~3.29.0", "react-native-webview": "13.6.4", + "shopify/flash-list": "^1.6.4", "viem": "^2.55.2", "zod": "^3.23.8", "zustand": "^4.5.2" @@ -79,4 +80,4 @@ "vitest": "^1.3.1" }, "private": true -} +} \ No newline at end of file From 905b7a33418f6b56c1d3a93a228888b1a0588fb6 Mon Sep 17 00:00:00 2001 From: gafar habeeb akande Date: Sat, 29 Aug 2026 17:31:25 +0100 Subject: [PATCH 5/6] fix: Add performance profiling and list virtualization for large (#103) --- tests/fixtures/largeMembership.fixtures.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/fixtures/largeMembership.fixtures.ts diff --git a/tests/fixtures/largeMembership.fixtures.ts b/tests/fixtures/largeMembership.fixtures.ts new file mode 100644 index 0000000..4ab9533 --- /dev/null +++ b/tests/fixtures/largeMembership.fixtures.ts @@ -0,0 +1,18 @@ +import type { GuildListItem } from "../../src/features/guilds/useGuilds"; + +export const LARGE_MEMBERSHIP_SET_SIZE = 200; + +export function generateLargeMembershipSet(count: number = LARGE_MEMBERSHIP_SET_SIZE): GuildListItem[] { + const statuses: GuildListItem["status"][] = ["active", "inactive", "expired", "revoked", "unknown"]; + return Array.from({ length: count }, (_, i) => { + const isActive = i % 4 !== 0; + return { + id: `guild-${i+1}`, + name: `Guild ${i+1}`, + isActive, + roleCount: (i % 5) + 1, + status: statuses[i % statuses.length], + lastSyncedAt: Date.now() - i * 1000, + }; + }); +} From 0fb5744fd74ed951538911ed3c247669034ad6f6 Mon Sep 17 00:00:00 2001 From: gafar habeeb akande Date: Sat, 29 Aug 2026 17:31:26 +0100 Subject: [PATCH 6/6] fix: Add performance profiling and list virtualization for large (#103) --- app/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/index.tsx b/app/index.tsx index 461e906..2934376 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -10,8 +10,8 @@ export default function Index() { } if (!isConnected) { - return ; + return >; } - return ; + return }