11"use client" ;
22
3+ import {
4+ QueryClient ,
5+ QueryClientProvider ,
6+ useQuery ,
7+ } from "@tanstack/react-query" ;
8+ import { ChevronLeftIcon , ChevronRightIcon , SearchIcon } from "lucide-react" ;
39import Image from "next/image" ;
4- import { useState , useEffect , useMemo } from "react" ;
10+ import { useMemo , useState } from "react" ;
511import {
612 getAllWalletsList ,
713 getWalletInfo ,
814 type WalletId ,
915} from "thirdweb/wallets" ;
10- import { DocLink , InlineCode } from "../Document" ;
16+ import { DocLink } from "../Document/DocLink" ;
17+ import { InlineCode } from "../Document/InlineCode" ;
1118import { Table , TBody , Td , Th , Tr } from "../Document/Table" ;
12- import { Input } from "../ui/input" ;
1319import { Button } from "../ui/button" ;
14- import { ChevronLeftIcon , ChevronRightIcon , SearchIcon } from "lucide-react " ;
20+ import { Input } from "../ui/input " ;
1521
1622const specialWallets : {
1723 [ key in WalletId ] ?: boolean ;
@@ -22,46 +28,44 @@ const specialWallets: {
2228
2329const ITEMS_PER_PAGE = 20 ;
2430
25- interface WalletInfo {
26- id : string ;
27- name : string ;
28- }
31+ const queryClient = new QueryClient ( ) ;
2932
3033export function AllSupportedWallets ( ) {
31- const [ wallets , setWallets ] = useState < WalletInfo [ ] > ( [ ] ) ;
32- const [ loading , setLoading ] = useState ( true ) ;
34+ return (
35+ < QueryClientProvider client = { queryClient } >
36+ < AllSupportedWalletsContent />
37+ </ QueryClientProvider >
38+ ) ;
39+ }
40+
41+ function AllSupportedWalletsContent ( ) {
3342 const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
3443 const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
3544
36- useEffect ( ( ) => {
37- async function loadWallets ( ) {
38- try {
39- const allWallets = await getAllWalletsList ( ) ;
40- const filteredWallets = allWallets
41- . filter ( ( w ) => ! ( w . id in specialWallets ) )
42- . map ( ( w ) => ( {
43- id : w . id ,
44- name : w . name ,
45- } ) ) ;
46- setWallets ( filteredWallets ) ;
47- } catch ( error ) {
48- console . error ( "Failed to load wallets:" , error ) ;
49- } finally {
50- setLoading ( false ) ;
51- }
52- }
53-
54- loadWallets ( ) ;
55- } , [ ] ) ;
45+ const { data : wallets , isLoading : loading } = useQuery ( {
46+ queryKey : [ "allWalletsList" ] ,
47+ queryFn : async ( ) => {
48+ const allWallets = await getAllWalletsList ( ) ;
49+ return allWallets
50+ . filter ( ( w ) => ! ( w . id in specialWallets ) )
51+ . map ( ( w ) => ( {
52+ id : w . id ,
53+ name : w . name ,
54+ } ) ) ;
55+ } ,
56+ staleTime : 1000 * 60 * 5 , // 5 minutes
57+ } ) ;
5658
5759 const filteredWallets = useMemo ( ( ) => {
58- if ( ! searchQuery ) return wallets ;
59-
60+ if ( ! searchQuery ) return wallets || [ ] ;
61+ if ( ! wallets ) return [ ] ;
62+
63+ setCurrentPage ( 1 ) ;
6064 const query = searchQuery . toLowerCase ( ) ;
6165 return wallets . filter (
6266 ( wallet ) =>
6367 wallet . name . toLowerCase ( ) . includes ( query ) ||
64- wallet . id . toLowerCase ( ) . includes ( query )
68+ wallet . id . toLowerCase ( ) . includes ( query ) ,
6569 ) ;
6670 } , [ wallets , searchQuery ] ) ;
6771
@@ -70,11 +74,6 @@ export function AllSupportedWallets() {
7074 const endIndex = startIndex + ITEMS_PER_PAGE ;
7175 const currentWallets = filteredWallets . slice ( startIndex , endIndex ) ;
7276
73- // Reset to first page when search changes
74- useEffect ( ( ) => {
75- setCurrentPage ( 1 ) ;
76- } , [ searchQuery ] ) ;
77-
7877 const handlePreviousPage = ( ) => {
7978 setCurrentPage ( ( prev ) => Math . max ( prev - 1 , 1 ) ) ;
8079 } ;
@@ -99,7 +98,7 @@ export function AllSupportedWallets() {
9998 < div className = "space-y-6" >
10099 { /* Search Input */ }
101100 < div className = "relative" >
102- < SearchIcon className = "absolute left-3 top-1/2 h-4 w -4 -translate-y-1/2 text-muted-foreground" />
101+ < SearchIcon className = "absolute left-3 top-1/2 size -4 -translate-y-1/2 text-muted-foreground" />
103102 < Input
104103 type = "text"
105104 placeholder = "Search wallets by name or ID..."
@@ -111,9 +110,9 @@ export function AllSupportedWallets() {
111110
112111 { /* Results count */ }
113112 < div className = "text-sm text-muted-foreground" >
114- { filteredWallets . length === wallets . length
113+ { filteredWallets . length === wallets ? .length
115114 ? `Showing ${ filteredWallets . length } wallets`
116- : `Found ${ filteredWallets . length } of ${ wallets . length } wallets` }
115+ : `Found ${ filteredWallets . length } of ${ wallets ? .length } wallets` }
117116 </ div >
118117
119118 { /* Table */ }
@@ -126,8 +125,13 @@ export function AllSupportedWallets() {
126125
127126 { currentWallets . length === 0 ? (
128127 < Tr >
129- < Td colSpan = { 2 } className = "text-center text-muted-foreground py-8" >
130- { searchQuery ? "No wallets found matching your search." : "No wallets available." }
128+ < Td
129+ colSpan = { 2 }
130+ className = "text-center text-muted-foreground py-8"
131+ >
132+ { searchQuery
133+ ? "No wallets found matching your search."
134+ : "No wallets available." }
131135 </ Td >
132136 </ Tr >
133137 ) : (
@@ -155,30 +159,32 @@ export function AllSupportedWallets() {
155159 { totalPages > 1 && (
156160 < div className = "flex items-center justify-between" >
157161 < div className = "text-sm text-muted-foreground" >
158- Page { currentPage } of { totalPages }
162+ Page { currentPage } of { totalPages }
159163 { filteredWallets . length > 0 && (
160164 < span className = "ml-2" >
161- (showing { startIndex + 1 } -{ Math . min ( endIndex , filteredWallets . length ) } of { filteredWallets . length } )
165+ (showing { startIndex + 1 } -
166+ { Math . min ( endIndex , filteredWallets . length ) } of{ " " }
167+ { filteredWallets . length } )
162168 </ span >
163169 ) }
164170 </ div >
165-
171+
166172 < div className = "flex items-center space-x-2" >
167173 < Button
168174 variant = "outline"
169175 size = "sm"
170176 onClick = { handlePreviousPage }
171177 disabled = { currentPage === 1 }
172178 >
173- < ChevronLeftIcon className = "h-4 w -4" />
179+ < ChevronLeftIcon className = "size -4" />
174180 Previous
175181 </ Button >
176182
177183 { /* Page numbers */ }
178184 < div className = "flex items-center space-x-1" >
179185 { Array . from ( { length : Math . min ( 5 , totalPages ) } , ( _ , i ) => {
180- let pageNumber ;
181-
186+ let pageNumber : number ;
187+
182188 if ( totalPages <= 5 ) {
183189 pageNumber = i + 1 ;
184190 } else if ( currentPage <= 3 ) {
@@ -210,7 +216,7 @@ export function AllSupportedWallets() {
210216 disabled = { currentPage === totalPages }
211217 >
212218 Next
213- < ChevronRightIcon className = "h-4 w -4" />
219+ < ChevronRightIcon className = "size -4" />
214220 </ Button >
215221 </ div >
216222 </ div >
@@ -219,8 +225,19 @@ export function AllSupportedWallets() {
219225 ) ;
220226}
221227
222- async function WalletImage ( props : { id : WalletId } ) {
223- const img = await getWalletInfo ( props . id , true ) ;
228+ function WalletImage ( props : { id : WalletId } ) {
229+ const { data : img } = useQuery ( {
230+ queryKey : [ "wallet-image" , props . id ] ,
231+ queryFn : ( ) => getWalletInfo ( props . id , true ) ,
232+ staleTime : 1000 * 60 * 60 * 24 , // 24 hours
233+ } ) ;
234+
235+ if ( ! img ) {
236+ return (
237+ < div className = "rounded-lg bg-muted" style = { { width : 44 , height : 44 } } />
238+ ) ;
239+ }
240+
224241 return (
225242 < Image alt = "" className = "rounded-lg" height = { 44 } src = { img } width = { 44 } />
226243 ) ;
0 commit comments