@@ -18,7 +18,7 @@ import { CatRoleDropdown } from "../../components/CatRoleDropdown";
1818import { useCATStorage } from "@/hooks/useCATStorage" ;
1919import { SupportedChainId , CatDetails as StoredCatDetails } from "@/utils/indexedDB" ;
2020import toast from "react-hot-toast" ;
21- import { useRouter , useSearchParams } from "next/navigation" ;
21+ import { useRouter } from "next/navigation" ;
2222
2323// Define supported chain IDs - use the imported type from IndexedDB
2424// type SupportedChainId = 137 | 534351 | 5115 | 61 | 8453;
@@ -67,13 +67,14 @@ const isValidChainId = (
6767
6868export default function MyCATsPage ( ) {
6969 const [ currentPageCATs , setCurrentPageCATs ] = useState < CatDetails [ ] > ( [ ] ) ;
70+ const [ allFilteredCATs , setAllFilteredCATs ] = useState < CatDetails [ ] > ( [ ] ) ; // Cache filtered CATs
7071 const [ isLoading , setIsLoading ] = useState ( true ) ;
7172 const [ error , setError ] = useState < string | null > ( null ) ;
7273 const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
7374 const [ selectedChainId , setSelectedChainId ] = useState < SupportedChainId | "all" > ( "all" ) ;
7475 const [ roleFilter , setRoleFilter ] = useState < "all" | "creator" | "minter" > ( "all" ) ;
7576 const [ pagination , setPagination ] = useState < PaginationInfo > ( {
76- currentPage : 1 ,
77+ currentPage : 0 ,
7778 totalPages : 0 ,
7879 totalCreatorCATs : 0 ,
7980 totalMinterCATs : 0 ,
@@ -86,7 +87,6 @@ export default function MyCATsPage() {
8687 const { address } = useAccount ( ) ;
8788 const currentChainId = useChainId ( ) ;
8889 const router = useRouter ( ) ;
89- const searchParams = useSearchParams ( ) ;
9090 const {
9191 getAllCatDetailsForUser,
9292 getCatDetailsByRole,
@@ -375,63 +375,75 @@ export default function MyCATsPage() {
375375 } ;
376376 } , [ isOnline , address , syncWithBlockchain ] ) ;
377377
378- // Fetch CATs for a specific page using storage-first approach
379- const fetchCATsForPage = useCallback ( async ( page : number ) : Promise < CatDetails [ ] > => {
380- if ( ! address || ! isInitialized ) return [ ] ;
378+ // Update filtered CATs and pagination when filters change
379+ const updateFilteredCATs = useCallback ( async ( ) => {
380+ if ( ! address || ! isInitialized ) return ;
381381
382382 try {
383- // Load all filtered CATs from storage
384- const allStoredCATs = await loadCATsFromStorage ( ) ;
383+ const filteredCATs = await loadCATsFromStorage ( ) ;
384+ setAllFilteredCATs ( filteredCATs ) ;
385385
386- // Calculate pagination indices
387- const catsPerPage = pagination . catsPerPage ;
388- const startIndex = ( page - 1 ) * catsPerPage ;
389- const endIndex = startIndex + catsPerPage ;
386+ // Calculate pagination
387+ const totalCATs = filteredCATs . length ;
388+ const creatorCount = filteredCATs . filter ( cat => cat . userRole === 'admin' ) . length ;
389+ const minterCount = filteredCATs . filter ( cat => cat . userRole === 'minter' ) . length ;
390+ const totalPages = Math . ceil ( totalCATs / pagination . catsPerPage ) ;
391+ const firstPage = totalPages > 0 ? 1 : 0 ;
390392
391- // Return the page slice
392- return allStoredCATs . slice ( startIndex , endIndex ) ;
393+ setPagination ( prev => ( {
394+ ...prev ,
395+ totalPages,
396+ totalCreatorCATs : creatorCount ,
397+ totalMinterCATs : minterCount ,
398+ currentPage : firstPage , // Reset to first page when filters change
399+ } ) ) ;
400+
401+ // Show first page - early return with empty slice when no pages
402+ const firstPageCATs = totalPages === 0 ? [ ] : filteredCATs . slice ( 0 , pagination . catsPerPage ) ;
403+ setCurrentPageCATs ( firstPageCATs ) ;
393404 } catch ( error ) {
394- console . error ( " Error fetching CATs for page from storage:" , error ) ;
395- return [ ] ;
405+ console . error ( ' Error updating filtered CATs:' , error ) ;
406+ setError ( 'Failed to load CATs. Please try again.' ) ;
396407 }
397408 } , [ address , isInitialized , loadCATsFromStorage , pagination . catsPerPage ] ) ;
398409
399- // Handle page navigation with storage-first approach
400- const goToPage = useCallback ( async ( page : number ) => {
401- if ( page < 1 || page > pagination . totalPages || page === pagination . currentPage ) return ;
402-
403- try {
404- setIsLoading ( true ) ;
405-
406- // Load page data from storage
407- const pageCATs = await fetchCATsForPage ( page ) ;
408- setCurrentPageCATs ( pageCATs ) ;
409- setPagination ( prev => ( { ...prev , currentPage : page } ) ) ;
410- } catch ( error ) {
411- console . error ( "Error navigating to page:" , error ) ;
412- setError ( "Failed to load page. Please try again." ) ;
413- } finally {
414- setIsLoading ( false ) ;
410+ // Update current page CATs when page changes (without refetching from storage)
411+ const updateCurrentPageCATs = useCallback ( ( page : number ) => {
412+ // Early return with empty slice when no pages
413+ if ( pagination . totalPages === 0 || page <= 0 ) {
414+ setCurrentPageCATs ( [ ] ) ;
415+ return ;
415416 }
416- } , [ pagination . totalPages , pagination . currentPage , fetchCATsForPage ] ) ;
417+
418+ const startIndex = ( page - 1 ) * pagination . catsPerPage ;
419+ const endIndex = startIndex + pagination . catsPerPage ;
420+ const pageCATs = allFilteredCATs . slice ( startIndex , endIndex ) ;
421+ setCurrentPageCATs ( pageCATs ) ;
422+ } , [ allFilteredCATs , pagination . catsPerPage , pagination . totalPages ] ) ;
423+
424+ // Handle page navigation with cached data
425+ const goToPage = useCallback ( ( page : number ) => {
426+ if ( pagination . totalPages === 0 || page < 1 || page > pagination . totalPages || page === pagination . currentPage ) return ;
427+
428+ setPagination ( prev => ( { ...prev , currentPage : page } ) ) ;
429+ updateCurrentPageCATs ( page ) ;
430+ } , [ pagination . totalPages , pagination . currentPage , updateCurrentPageCATs ] ) ;
417431
418432 const goToPreviousPage = ( ) => goToPage ( pagination . currentPage - 1 ) ;
419433 const goToNextPage = ( ) => goToPage ( pagination . currentPage + 1 ) ;
420434
421- // Filter and search function
422- const filteredCATs = currentPageCATs ?. filter ( ( cat ) => {
423- const matchesSearch = searchQuery === "" ||
424- cat . tokenName . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ||
425- cat . tokenSymbol . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ;
426-
427- const matchesChain = selectedChainId === "all" || cat . chainId === Number ( selectedChainId ) ;
428-
429- const matchesRole = roleFilter === "all" ||
430- ( roleFilter === "creator" && cat . userRole === "admin" ) ||
431- ( roleFilter === "minter" && cat . userRole === "minter" ) ;
432-
433- return matchesSearch && matchesChain && matchesRole ;
434- } ) ;
435+ // Update filtered CATs when filters change
436+ useEffect ( ( ) => {
437+ updateFilteredCATs ( ) ;
438+ } , [ updateFilteredCATs ] ) ;
439+
440+ // Update current page CATs when pagination current page changes
441+ useEffect ( ( ) => {
442+ updateCurrentPageCATs ( pagination . currentPage ) ;
443+ } , [ pagination . currentPage , updateCurrentPageCATs ] ) ;
444+
445+ // Display CATs are now managed in state, no additional filtering needed
446+ const filteredCATs = currentPageCATs ;
435447
436448 // Initialize pagination with IndexedDB integration (offline-first approach)
437449 const initializePagination = useCallback ( async ( ) => {
@@ -448,85 +460,53 @@ export default function MyCATsPage() {
448460 const storedCATs = await loadCATsFromStorage ( ) ;
449461
450462 if ( storedCATs . length > 0 ) {
451- // Calculate pagination from stored data
463+ // Cache the filtered CATs and update pagination
464+ setAllFilteredCATs ( storedCATs ) ;
465+
452466 const totalCATs = storedCATs . length ;
453467 const creatorCount = storedCATs . filter ( cat => cat . userRole === 'admin' ) . length ;
454468 const minterCount = storedCATs . filter ( cat => cat . userRole === 'minter' ) . length ;
455469 const totalPages = Math . ceil ( totalCATs / pagination . catsPerPage ) ;
470+ const firstPage = totalPages > 0 ? 1 : 0 ;
456471
457472 setPagination ( prev => ( {
458473 ...prev ,
459474 totalPages,
460475 totalCreatorCATs : creatorCount ,
461476 totalMinterCATs : minterCount ,
462- currentPage : 1 ,
477+ currentPage : firstPage ,
463478 } ) ) ;
464479
465- // Show first page from stored data
466- const startIndex = 0 ;
467- const endIndex = pagination . catsPerPage ;
468- setCurrentPageCATs ( storedCATs . slice ( startIndex , endIndex ) ) ;
480+ // Show first page from cached data - early return with empty slice when no pages
481+ const firstPageCATs = totalPages === 0 ? [ ] : storedCATs . slice ( 0 , pagination . catsPerPage ) ;
482+ setCurrentPageCATs ( firstPageCATs ) ;
469483
470484 // Show data immediately from storage
471485 setIsLoading ( false ) ;
472486
473487 // Then sync with blockchain in background if online
474488 if ( isOnline ) {
475489 syncWithBlockchain ( false ) . then ( async ( ) => {
476- // Refresh data after successful sync
477- const refreshedCATs = await loadCATsFromStorage ( ) ;
478- if ( refreshedCATs . length !== storedCATs . length ) {
479- // Data changed, refresh the display
480- const newTotalCATs = refreshedCATs . length ;
481- const newCreatorCount = refreshedCATs . filter ( cat => cat . userRole === 'admin' ) . length ;
482- const newMinterCount = refreshedCATs . filter ( cat => cat . userRole === 'minter' ) . length ;
483- const newTotalPages = Math . ceil ( newTotalCATs / pagination . catsPerPage ) ;
484-
485- setPagination ( prev => ( {
486- ...prev ,
487- totalPages : newTotalPages ,
488- totalCreatorCATs : newCreatorCount ,
489- totalMinterCATs : newMinterCount ,
490- } ) ) ;
491-
492- const newStartIndex = 0 ;
493- const newEndIndex = pagination . catsPerPage ;
494- setCurrentPageCATs ( refreshedCATs . slice ( newStartIndex , newEndIndex ) ) ;
495- }
490+ // Refresh data after successful sync by triggering updateFilteredCATs
491+ await updateFilteredCATs ( ) ;
496492 } ) . catch ( console . error ) ;
497493 }
498494 } else {
499495 // No stored data, must fetch from blockchain
500496 if ( isOnline ) {
501497 await syncWithBlockchain ( true ) ; // Force sync
502- // Reload from storage after sync
503- const newStoredCATs = await loadCATsFromStorage ( ) ;
504-
505- const totalCATs = newStoredCATs . length ;
506- const creatorCount = newStoredCATs . filter ( cat => cat . userRole === 'admin' ) . length ;
507- const minterCount = newStoredCATs . filter ( cat => cat . userRole === 'minter' ) . length ;
508- const totalPages = Math . ceil ( totalCATs / pagination . catsPerPage ) ;
509-
510- setPagination ( prev => ( {
511- ...prev ,
512- totalPages,
513- totalCreatorCATs : creatorCount ,
514- totalMinterCATs : minterCount ,
515- currentPage : 1 ,
516- } ) ) ;
517-
518- const startIndex = 0 ;
519- const endIndex = pagination . catsPerPage ;
520- setCurrentPageCATs ( newStoredCATs . slice ( startIndex , endIndex ) ) ;
498+ // Trigger update after sync
499+ await updateFilteredCATs ( ) ;
521500 } else {
522501 setError ( "No data available offline. Please connect to the internet to sync your CATs." ) ;
502+ setAllFilteredCATs ( [ ] ) ;
523503 setCurrentPageCATs ( [ ] ) ;
524504 setPagination ( prev => ( {
525505 ...prev ,
526506 totalPages : 0 ,
527507 totalCreatorCATs : 0 ,
528508 totalMinterCATs : 0 ,
529- currentPage : 1 ,
509+ currentPage : 0 ,
530510 } ) ) ;
531511 }
532512 }
@@ -537,24 +517,13 @@ export default function MyCATsPage() {
537517 } finally {
538518 setIsLoading ( false ) ;
539519 }
540- } , [ address , isInitialized , storageError , loadCATsFromStorage , syncWithBlockchain , isOnline , pagination . catsPerPage ] ) ;
520+ } , [ address , isInitialized , storageError , loadCATsFromStorage , syncWithBlockchain , isOnline , pagination . catsPerPage , updateFilteredCATs ] ) ;
541521
542522 useEffect ( ( ) => {
543523 initializePagination ( ) ;
544524 } , [ initializePagination ] ) ;
545525
546- // Handle sync URL parameter from create page redirect
547- useEffect ( ( ) => {
548- const shouldSync = searchParams . get ( 'sync' ) ;
549- if ( shouldSync === 'true' && isOnline && address && isInitialized ) {
550- console . log ( 'Sync parameter detected, triggering immediate sync...' ) ;
551- toast . success ( 'Welcome back! Syncing your new CAT...' ) ;
552- syncWithBlockchain ( true ) . then ( ( ) => {
553- // Clear the sync parameter from URL
554- router . replace ( '/my-cats' , { scroll : false } ) ;
555- } ) . catch ( console . error ) ;
556- }
557- } , [ searchParams , isOnline , address , isInitialized , syncWithBlockchain , router ] ) ;
526+
558527
559528 // Helper function to add delays between requests
560529 const delay = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
@@ -803,18 +772,18 @@ export default function MyCATsPage() {
803772 >
804773 < motion . button
805774 onClick = { goToPreviousPage }
806- disabled = { pagination . currentPage === 1 }
775+ disabled = { pagination . currentPage <= 1 || pagination . totalPages === 0 }
807776 className = "flex items-center gap-2 px-4 py-2 rounded-xl bg-white/80 dark:bg-[#1a1400]/70 border border-[#bfdbfe] dark:border-yellow-400/20 text-gray-800 dark:text-yellow-100 disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-50 dark:hover:bg-yellow-400/10 transition-all duration-300"
808- whileHover = { { scale : pagination . currentPage === 1 ? 1 : 1.05 } }
809- whileTap = { { scale : pagination . currentPage === 1 ? 1 : 0.95 } }
777+ whileHover = { { scale : ( pagination . currentPage <= 1 || pagination . totalPages === 0 ) ? 1 : 1.05 } }
778+ whileTap = { { scale : ( pagination . currentPage <= 1 || pagination . totalPages === 0 ) ? 1 : 0.95 } }
810779 >
811780 < ChevronLeft className = "w-4 h-4" />
812781 < span > Previous</ span >
813782 </ motion . button >
814783
815784 < div className = "flex items-center gap-2" >
816785 < span className = "text-sm text-gray-600 dark:text-yellow-200" >
817- Page { pagination . currentPage } of { pagination . totalPages }
786+ { pagination . totalPages === 0 ? 'No pages' : ` Page $ {pagination . currentPage } of $ {pagination . totalPages } ` }
818787 </ span >
819788 < span className = "text-xs text-gray-500 dark:text-yellow-200/70" >
820789 ({ pagination . totalCreatorCATs + pagination . totalMinterCATs } total CATs)
@@ -823,10 +792,10 @@ export default function MyCATsPage() {
823792
824793 < motion . button
825794 onClick = { goToNextPage }
826- disabled = { pagination . currentPage === pagination . totalPages }
795+ disabled = { pagination . currentPage >= pagination . totalPages || pagination . totalPages === 0 }
827796 className = "flex items-center gap-2 px-4 py-2 rounded-xl bg-white/80 dark:bg-[#1a1400]/70 border border-[#bfdbfe] dark:border-yellow-400/20 text-gray-800 dark:text-yellow-100 disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-50 dark:hover:bg-yellow-400/10 transition-all duration-300"
828- whileHover = { { scale : pagination . currentPage === pagination . totalPages ? 1 : 1.05 } }
829- whileTap = { { scale : pagination . currentPage === pagination . totalPages ? 1 : 0.95 } }
797+ whileHover = { { scale : ( pagination . currentPage >= pagination . totalPages || pagination . totalPages === 0 ) ? 1 : 1.05 } }
798+ whileTap = { { scale : ( pagination . currentPage >= pagination . totalPages || pagination . totalPages === 0 ) ? 1 : 0.95 } }
830799 >
831800 < span > Next</ span >
832801 < ChevronRight className = "w-4 h-4" />
@@ -889,19 +858,17 @@ export default function MyCATsPage() {
889858 animate = { { opacity : 1 , y : 0 } }
890859 transition = { { duration : 0.5 , delay : index * 0.1 } }
891860 >
892- < div className = "absolute inset-0 bg-gradient-to-r from-[#93c5fd]/30 to-[#60a5fa]/30 dark:from-yellow-400/20 dark:to-blue -400/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all duration-300" > </ div >
861+ < div className = "absolute inset-0 bg-gradient-to-r from-[#93c5fd]/30 to-[#60a5fa]/30 dark:from-yellow-400/20 dark:to-yellow -400/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all duration-300" > </ div >
893862 < motion . div
894863 className = "relative rounded-2xl p-8 bg-white/80 dark:bg-[#1a1400]/70 border border-[#bfdbfe] dark:border-yellow-400/20 backdrop-blur-lg transition-all duration-300 hover:scale-105 hover:shadow-[0_8px_32px_0_rgba(37,99,235,0.25)] dark:hover:shadow-[0_8px_32px_0_rgba(255,217,0,0.25)] hover:border-blue-300 dark:hover:border-yellow-400"
895864 whileHover = { { y : - 8 } }
896865 whileTap = { { scale : 0.98 } }
897866 >
898867 < div className = "relative z-10 flex flex-col" >
899868 < div className = "flex items-center justify-between mb-6" >
900- < div className = "w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-blue-300 dark:from-[#FFD600] dark:to-blue-400 flex items-center justify-center text-white font-bold text-xl" >
901- { cat . tokenSymbol . slice ( 0 , 2 ) }
902- </ div >
869+
903870 < div className = "flex-1 text-center px-4" >
904- < h2 className = "text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-blue-300 dark:from-[#FFD600] dark:to-blue-400 " >
871+ < h2 className = "text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-blue-300 dark:from-[#FFD600] dark:to-white " >
905872 { cat . tokenName || cat . address }
906873 </ h2 >
907874 < p className = "text-sm text-[#1e40af] dark:text-yellow-100" >
0 commit comments