From 22310801f8432a261bd29b760fb653d7cf16849e Mon Sep 17 00:00:00 2001 From: Obiajulu-gif Date: Thu, 28 May 2026 12:09:51 +0100 Subject: [PATCH] Add creator profile load error state --- src/pages/LandingPage.tsx | 288 +++++++++++++++++++++++--------------- 1 file changed, 176 insertions(+), 112 deletions(-) diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index 37cff2b..fdbc095 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -26,10 +26,13 @@ import NetworkMismatchBanner from '@/components/common/NetworkMismatchBanner'; import { useNetworkMismatch } from '@/hooks/useNetworkMismatch'; import showToast from '@/utils/toast.util'; import { formatCompactNumber, formatNumber } from '@/utils/numberFormat.utils'; -import PrecisionModeToggle, { type PrecisionMode } from '@/components/common/PrecisionModeToggle'; +import PrecisionModeToggle, { + type PrecisionMode, +} from '@/components/common/PrecisionModeToggle'; import ScrollToTop from '@/components/common/ScrollToTop'; import SectionErrorBoundary from '@/components/common/SectionErrorBoundary'; import { useScrollPreservation } from '@/hooks/useScrollPreservation'; +import { AlertCircle, RefreshCw } from 'lucide-react'; const FEATURED_CREATOR_FACTS = [ { label: 'Membership', value: 'Collectors Circle' }, @@ -137,6 +140,46 @@ const getFetchRetryHelperCopy = (attempt: number, maxAttempts: number) => type SortOption = 'featured' | 'price-asc' | 'price-desc' | 'supply-desc'; +interface CreatorProfileLoadErrorProps { + onRetry: () => void; + isRetrying: boolean; +} + +const CreatorProfileLoadError: React.FC = ({ + onRetry, + isRetrying, +}) => ( +
+
+
+

+ Unable to load this creator profile +

+

+ We couldn't load the latest profile details. Check your connection and + try again. +

+ +
+); + function LandingPage() { const [creators, setCreators] = useState([]); const { isMismatch: isNetworkMismatch } = useNetworkMismatch(); @@ -163,6 +206,7 @@ function LandingPage() { return saved ?? 'featured'; }); const [fetchRetryAttempt, setFetchRetryAttempt] = useState(0); + const [fetchRequestId, setFetchRequestId] = useState(0); const [showRetryBanner, setShowRetryBanner] = useState(false); const [finalFetchError, setFinalFetchError] = useState(''); const [page, setPage] = useState(() => { @@ -246,9 +290,7 @@ function LandingPage() { return; } - setFinalFetchError( - FINAL_FETCH_ERROR_COPY - ); + setFinalFetchError(FINAL_FETCH_ERROR_COPY); setShowRetryBanner(false); setFetchRetryAttempt(0); setCreators(DEMO_CREATORS); @@ -258,7 +300,7 @@ function LandingPage() { }; fetchCreators(); - }, [fetchRetryAttempt]); + }, [fetchRetryAttempt, fetchRequestId]); const searchSuggestions = useMemo(() => { const fromCategories = creators @@ -308,12 +350,12 @@ function LandingPage() { // Add loading state for filter changes useEffect(() => { if (creators.length === 0) return; // Don't show filter loading during initial load - + setIsFilterLoading(true); const timer = setTimeout(() => { setIsFilterLoading(false); }, 300); // Short delay to show loading indicator - + return () => clearTimeout(timer); }, [trimmedSearchQuery, sortOption, creators.length]); @@ -347,6 +389,13 @@ function LandingPage() { const handleResetSearch = () => setSearchQuery(''); + const handleRetryCreatorFetch = () => { + setFinalFetchError(''); + setShowRetryBanner(false); + setFetchRetryAttempt(0); + setFetchRequestId(requestId => requestId + 1); + }; + const openTradeDialog = (side: TradeSide) => { setTradeSide(side); setTradeDialogOpen(true); @@ -481,7 +530,9 @@ function LandingPage() {
- Updating results... + + Updating results... +
{pagedCreators.map(creator => ( @@ -499,7 +550,7 @@ function LandingPage() { MAX_CREATOR_FETCH_RETRIES + 1 )} retryLabel={FETCH_RETRY_ACTION_LABEL} - onRetry={() => setFetchRetryAttempt(0)} + onRetry={handleRetryCreatorFetch} /> )} {finalFetchError && ( @@ -579,7 +630,10 @@ function LandingPage() { parentHref="/" currentLabel="Alex Rivers Portfolio" /> - + - -
- - - - Use the same subtitle pattern beneath headings, then drop - repeated creator facts into one responsive grid that stays - tidy on mobile and desktop. - -
-
- - - + {finalFetchError ? ( + + ) : ( + +
+ + + + Use the same subtitle pattern beneath headings, then + drop repeated creator facts into one responsive grid + that stays tidy on mobile and desktop. + +
+
+ + + +
-
-
- -
- - Metrics display - - + +
+ + Metrics display + + +
+ + {isNetworkMismatch && } +
+ + +
- - {isNetworkMismatch && } -
- - -
-
- + + )}