Skip to content

Commit 586874d

Browse files
committed
Enhance PageViewPage with improved error handling and user experience
- Refactored PageViewPage to include better loading states and error handling for various scenarios, including connection errors and page not found. - Introduced a retry mechanism for failed data fetching attempts, enhancing user experience during network issues. - Added an ErrorBoundary component to gracefully handle rendering errors and provide user feedback. - Updated the AddComment component to improve submission handling and error messaging, ensuring a smoother commenting experience. - Enhanced PageComments component with better error display and retry options for loading comments. - Improved hooks for data fetching to ensure valid responses and added retry logic for better resilience.
1 parent 97ed7c5 commit 586874d

File tree

9 files changed

+910
-128
lines changed

9 files changed

+910
-128
lines changed

src/src/app/pages/[slug]/page.tsx

Lines changed: 218 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,240 @@
11
'use client'
2+
import React from 'react'
23
import { VoloCmsKitContentsPageDto } from '@/client'
34
import { PageView } from '@/components/page/PageView'
45
import { Button } from '@/components/ui/button'
6+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
7+
import { Alert, AlertDescription } from '@/components/ui/alert'
58
import Error from '@/components/ui/Error'
69
import Loader from '@/components/ui/Loader'
710
import { usePageBySlug } from '@/lib/hooks/usePages'
11+
import { AlertTriangle, Home, RefreshCw, Search } from 'lucide-react'
812
import Link from 'next/link'
9-
import { useParams } from 'next/navigation'
13+
import { useParams, useRouter } from 'next/navigation'
14+
import { useEffect, useState } from 'react'
1015

1116
export default function PageViewPage() {
1217
const params = useParams()
18+
const router = useRouter()
1319
const slug = params.slug as string
20+
const [retryCount, setRetryCount] = useState(0)
1421

15-
const { data: page, isLoading, isError } = usePageBySlug(slug)
22+
const {
23+
data: page,
24+
isLoading,
25+
isError,
26+
error,
27+
refetch
28+
} = usePageBySlug(slug)
1629

17-
if (isLoading) return <Loader />
18-
if (isError) return <Error />
30+
// Handle retry logic
31+
const handleRetry = () => {
32+
setRetryCount(prev => prev + 1)
33+
refetch()
34+
}
1935

20-
if (!page) {
36+
// Reset retry count when slug changes
37+
useEffect(() => {
38+
setRetryCount(0)
39+
}, [slug])
40+
41+
// Loading state with better UX
42+
if (isLoading) {
2143
return (
22-
<div className="container mx-auto p-4">
23-
<div className="text-center py-8">
24-
<h1 className="text-2xl font-bold mb-4">Page Not Found</h1>
25-
<p className="text-muted-foreground mb-4">
26-
The page with slug &quot;{slug}&quot; could not be found.
27-
</p>
28-
<div className="flex gap-2 justify-center">
29-
<Link href="/">
30-
<Button variant="outline">Back to Home</Button>
31-
</Link>
32-
</div>
44+
<div className="min-h-screen bg-background flex items-center justify-center">
45+
<div className="text-center space-y-4">
46+
<Loader />
47+
<p className="text-muted-foreground">Loading page...</p>
48+
</div>
49+
</div>
50+
)
51+
}
52+
53+
// Handle different types of errors gracefully
54+
if (isError) {
55+
const errorMessage = error && typeof error === 'object' && 'message' in error
56+
? String(error.message)
57+
: 'An unexpected error occurred'
58+
59+
// Network or server errors
60+
if (errorMessage.includes('fetch') || errorMessage.includes('network') || errorMessage.includes('timeout')) {
61+
return (
62+
<div className="min-h-screen bg-background flex items-center justify-center p-4">
63+
<Card className="w-full max-w-md">
64+
<CardHeader className="text-center">
65+
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-orange-100">
66+
<AlertTriangle className="h-6 w-6 text-orange-600" />
67+
</div>
68+
<CardTitle>Connection Error</CardTitle>
69+
<CardDescription>
70+
We're having trouble connecting to our servers. This might be a temporary issue.
71+
</CardDescription>
72+
</CardHeader>
73+
<CardContent className="space-y-4">
74+
<Alert>
75+
<AlertTriangle className="h-4 w-4" />
76+
<AlertDescription>
77+
{retryCount > 0
78+
? `Attempt ${retryCount + 1} failed. Please try again.`
79+
: 'Please check your internet connection and try again.'
80+
}
81+
</AlertDescription>
82+
</Alert>
83+
<div className="flex gap-2">
84+
<Button onClick={handleRetry} className="flex-1">
85+
<RefreshCw className="mr-2 h-4 w-4" />
86+
Try Again
87+
</Button>
88+
<Button variant="outline" onClick={() => router.push('/')}>
89+
<Home className="mr-2 h-4 w-4" />
90+
Go Home
91+
</Button>
92+
</div>
93+
</CardContent>
94+
</Card>
95+
</div>
96+
)
97+
}
98+
99+
// 404 or page not found errors
100+
if (errorMessage.includes('not found') || errorMessage.includes('404')) {
101+
return (
102+
<div className="min-h-screen bg-background flex items-center justify-center p-4">
103+
<Card className="w-full max-w-md">
104+
<CardHeader className="text-center">
105+
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-blue-100">
106+
<Search className="h-6 w-6 text-blue-600" />
107+
</div>
108+
<CardTitle>Page Not Found</CardTitle>
109+
<CardDescription>
110+
The page you're looking for doesn't exist or may have been moved.
111+
</CardDescription>
112+
</CardHeader>
113+
<CardContent className="space-y-4">
114+
<div className="text-sm text-muted-foreground">
115+
<p>Slug: <code className="bg-muted px-1 rounded">{slug}</code></p>
116+
</div>
117+
<div className="flex gap-2">
118+
<Button asChild className="flex-1">
119+
<Link href="/">
120+
<Home className="mr-2 h-4 w-4" />
121+
Go Home
122+
</Link>
123+
</Button>
124+
<Button variant="outline" onClick={() => router.back()}>
125+
Go Back
126+
</Button>
127+
</div>
128+
</CardContent>
129+
</Card>
33130
</div>
131+
)
132+
}
133+
134+
// Generic error fallback
135+
return (
136+
<div className="min-h-screen bg-background flex items-center justify-center p-4">
137+
<Card className="w-full max-w-md">
138+
<CardHeader className="text-center">
139+
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
140+
<AlertTriangle className="h-6 w-6 text-red-600" />
141+
</div>
142+
<CardTitle>Something Went Wrong</CardTitle>
143+
<CardDescription>
144+
We encountered an unexpected error while loading this page.
145+
</CardDescription>
146+
</CardHeader>
147+
<CardContent className="space-y-4">
148+
<Alert>
149+
<AlertTriangle className="h-4 w-4" />
150+
<AlertDescription>
151+
{errorMessage}
152+
</AlertDescription>
153+
</Alert>
154+
<div className="flex gap-2">
155+
<Button onClick={handleRetry} className="flex-1">
156+
<RefreshCw className="mr-2 h-4 w-4" />
157+
Try Again
158+
</Button>
159+
<Button variant="outline" asChild>
160+
<Link href="/">
161+
<Home className="mr-2 h-4 w-4" />
162+
Go Home
163+
</Link>
164+
</Button>
165+
</div>
166+
</CardContent>
167+
</Card>
34168
</div>
35169
)
36170
}
37171

38-
return <PageView page={page as VoloCmsKitContentsPageDto} />
172+
// Handle case where page data is null/undefined
173+
if (!page) {
174+
return (
175+
<div className="min-h-screen bg-background flex items-center justify-center p-4">
176+
<Card className="w-full max-w-md">
177+
<CardHeader className="text-center">
178+
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
179+
<Search className="h-6 w-6 text-gray-600" />
180+
</div>
181+
<CardTitle>Page Not Available</CardTitle>
182+
<CardDescription>
183+
This page exists but is currently not available for viewing.
184+
</CardDescription>
185+
</CardHeader>
186+
<CardContent className="space-y-4">
187+
<div className="flex gap-2">
188+
<Button asChild className="flex-1">
189+
<Link href="/">
190+
<Home className="mr-2 h-4 w-4" />
191+
Go Home
192+
</Link>
193+
</Button>
194+
<Button variant="outline" onClick={() => router.back()}>
195+
Go Back
196+
</Button>
197+
</div>
198+
</CardContent>
199+
</Card>
200+
</div>
201+
)
202+
}
203+
204+
// Render the page with error boundary
205+
return (
206+
<ErrorBoundary fallback={<Error />}>
207+
<PageView page={page as VoloCmsKitContentsPageDto} />
208+
</ErrorBoundary>
209+
)
210+
}
211+
212+
// Error Boundary Component
213+
class ErrorBoundary extends React.Component<
214+
{ children: React.ReactNode; fallback: React.ReactNode },
215+
{ hasError: boolean; error?: Error }
216+
> {
217+
constructor(props: { children: React.ReactNode; fallback: React.ReactNode }) {
218+
super(props)
219+
this.state = { hasError: false }
220+
}
221+
222+
static getDerivedStateFromError(error: unknown) {
223+
const errorObj = error && typeof error === 'object' && 'message' in error
224+
? error as Error
225+
: { message: String(error), name: 'Error' } as Error
226+
return { hasError: true, error: errorObj }
227+
}
228+
229+
componentDidCatch(error: unknown, errorInfo: React.ErrorInfo) {
230+
console.error('PageView Error Boundary caught an error:', error, errorInfo)
231+
}
232+
233+
render() {
234+
if (this.state.hasError) {
235+
return this.props.fallback
236+
}
237+
238+
return this.props.children
239+
}
39240
}

0 commit comments

Comments
 (0)