11"use client" ;
22
3+ import { Logo } from "@/components/logo" ;
4+ import { Badge } from "@/components/ui/badge" ;
35import { Button } from "@/components/ui/button" ;
46import { Card , CardContent , CardDescription , CardFooter , CardHeader , CardTitle } from "@/components/ui/card" ;
5- import { Badge } from "@/components/ui/badge" ;
6- import {
7- ERROR_NOT_FOUND ,
8- ERROR_UNAUTHORIZED ,
9- ERROR_USER_VERIFIED ,
10- ERROR_NOT_IMPLEMENTED
11- } from "@/lib/apollo" ;
7+ import { ERROR_NOT_FOUND , ERROR_NOT_IMPLEMENTED , ERROR_UNAUTHORIZED , ERROR_USER_VERIFIED } from "@/lib/apollo" ;
128import { ApolloError } from "@apollo/client" ;
13- import {
14- AlertCircle ,
15- RefreshCw ,
16- Home ,
17- Lock ,
18- Search ,
19- WifiOff ,
20- Code ,
21- Shield
22- } from "lucide-react" ;
9+ import { AlertCircle , Code , Home , Lock , RefreshCw , Search , Shield , WifiOff } from "lucide-react" ;
2310import Link from "next/link" ;
24- import { Logo } from "@/components/logo" ;
2511import { useEffect } from "react" ;
2612
2713interface GlobalErrorProps {
@@ -33,32 +19,32 @@ function getErrorInfo(error: Error | ApolloError) {
3319 // Check if it's an ApolloError
3420 if ( error instanceof ApolloError ) {
3521 // Network errors
36- if ( error . networkError && ' statusCode' in error . networkError ) {
22+ if ( error . networkError && " statusCode" in error . networkError ) {
3723 switch ( error . networkError . statusCode ) {
3824 case 401 :
3925 return {
4026 title : "未經授權" ,
4127 description : "您的登入狀態已過期,請重新登入。" ,
4228 icon : Lock ,
43- actionHref : "/login"
29+ actionHref : "/login" ,
4430 } ;
4531 case 403 :
4632 return {
47- title : "權限不足" ,
33+ title : "權限不足" ,
4834 description : "您沒有權限執行此操作。" ,
49- icon : Shield
35+ icon : Shield ,
5036 } ;
5137 case 404 :
5238 return {
5339 title : "找不到資源" ,
54- description : "請求的資源不存在或已被移除。" ,
55- icon : Search
40+ description : "請求的資源不存在或已被移除。" ,
41+ icon : Search ,
5642 } ;
5743 case 500 :
5844 return {
5945 title : "伺服器錯誤" ,
6046 description : "伺服器發生內部錯誤,請稍後再試。" ,
61- icon : AlertCircle
47+ icon : AlertCircle ,
6248 } ;
6349 }
6450 }
@@ -67,7 +53,7 @@ function getErrorInfo(error: Error | ApolloError) {
6753 return {
6854 title : "網路連線錯誤" ,
6955 description : "無法連接到伺服器,請檢查網路連線。" ,
70- icon : WifiOff
56+ icon : WifiOff ,
7157 } ;
7258 }
7359
@@ -81,33 +67,33 @@ function getErrorInfo(error: Error | ApolloError) {
8167 return {
8268 title : "找不到資料" ,
8369 description : "請求的資料不存在或已被刪除。" ,
84- icon : Search
70+ icon : Search ,
8571 } ;
8672 case ERROR_UNAUTHORIZED :
8773 return {
88- title : "未經授權" ,
74+ title : "未經授權" ,
8975 description : "請登入後再試,或您的權限不足。" ,
9076 icon : Lock ,
91- actionHref : "/login"
77+ actionHref : "/login" ,
9278 } ;
9379 case ERROR_USER_VERIFIED :
9480 return {
9581 title : "帳號已驗證" ,
9682 description : "此帳號已經完成驗證程序。" ,
97- icon : Shield
83+ icon : Shield ,
9884 } ;
9985 case ERROR_NOT_IMPLEMENTED :
10086 return {
10187 title : "功能未實作" ,
10288 description : "此功能目前尚未實作,請稍後再試。" ,
103- icon : Code
89+ icon : Code ,
10490 } ;
10591 }
10692
10793 return {
10894 title : "GraphQL 查詢錯誤" ,
10995 description : firstError . message || "GraphQL 查詢發生錯誤。" ,
110- icon : AlertCircle
96+ icon : AlertCircle ,
11197 } ;
11298 }
11399 }
@@ -116,7 +102,7 @@ function getErrorInfo(error: Error | ApolloError) {
116102 return {
117103 title : "應用程式發生錯誤" ,
118104 description : error . message || "應用程式遇到預期外的錯誤。" ,
119- icon : AlertCircle
105+ icon : AlertCircle ,
120106 } ;
121107}
122108
@@ -152,91 +138,141 @@ export default function GlobalError({ error, reset }: GlobalErrorProps) {
152138 </ div >
153139 Database Playground
154140 </ Link >
155-
156- < Card className = "min-w-md max-w-2xl" >
157- < CardHeader className = "flex w-full flex-col items-center text-center" >
141+
142+ < Card className = "max-w-2xl min-w-md" >
143+ < CardHeader
144+ className = { `flex w-full flex-col items-center text-center` }
145+ >
158146 < errorInfo . icon className = "mb-2 size-7 text-red-500" />
159147 < CardTitle className = "text-xl" > { errorInfo . title } </ CardTitle >
160148 < CardDescription >
161149 { errorInfo . description }
162150 </ CardDescription >
163151 </ CardHeader >
164-
152+
165153 < CardContent className = "flex flex-col items-center gap-4" >
166- < div className = "w-full rounded-md bg-red-50 p-4 text-left" >
167- < details className = "text-sm" >
168- < summary className = "cursor-pointer font-medium text-red-800" >
169- 錯誤詳細資訊
170- </ summary >
171- < div className = "text-red-700 space-y-2 mt-2" >
172- < p className = "font-medium" > { error . name } : { error . message } </ p >
173-
174- { error . stack && (
175- < pre className = "whitespace-pre-wrap text-xs bg-red-100 p-2 rounded overflow-x-auto" >
154+ < div className = "w-full rounded-md bg-red-50 p-4 text-left" >
155+ < details className = "text-sm" >
156+ < summary className = "cursor-pointer font-medium text-red-800" >
157+ 錯誤詳細資訊
158+ </ summary >
159+ < div className = "mt-2 space-y-2 text-red-700" >
160+ < p className = "font-medium" > { error . name } : { error . message } </ p >
161+
162+ { error . stack && (
163+ < pre
164+ className = { `
165+ overflow-x-auto rounded bg-red-100 p-2 text-xs
166+ whitespace-pre-wrap
167+ ` }
168+ >
176169 { error . stack }
177- </ pre >
178- ) }
179-
180- { error instanceof ApolloError && (
181- < div className = "space-y-2" >
182- { error . networkError && (
183- < div >
184- < Badge variant = "destructive" className = "text-xs mb-1" > Network Error</ Badge >
185- < pre className = "whitespace-pre-wrap text-xs bg-red-100 p-2 rounded" >
170+ </ pre >
171+ ) }
172+
173+ { error instanceof ApolloError && (
174+ < div className = "space-y-2" >
175+ { error . networkError && (
176+ < div >
177+ < Badge
178+ variant = "destructive"
179+ className = { `mb-1 text-xs` }
180+ >
181+ Network Error
182+ </ Badge >
183+ < pre
184+ className = { `
185+ rounded bg-red-100 p-2 text-xs
186+ whitespace-pre-wrap
187+ ` }
188+ >
186189 { JSON . stringify ( error . networkError , null , 2 ) }
187- </ pre >
188- </ div >
189- ) }
190-
191- { error . graphQLErrors && error . graphQLErrors . length > 0 && (
192- < div >
193- < Badge variant = "destructive" className = "text-xs mb-1" >
194- GraphQL Errors ({ error . graphQLErrors . length } )
195- </ Badge >
196- < pre className = "whitespace-pre-wrap text-xs bg-red-100 p-2 rounded" >
190+ </ pre >
191+ </ div >
192+ ) }
193+
194+ { error . graphQLErrors && error . graphQLErrors . length > 0 && (
195+ < div >
196+ < Badge
197+ variant = "destructive"
198+ className = { `mb-1 text-xs` }
199+ >
200+ GraphQL Errors ({ error . graphQLErrors . length } )
201+ </ Badge >
202+ < pre
203+ className = { `
204+ rounded bg-red-100 p-2 text-xs
205+ whitespace-pre-wrap
206+ ` }
207+ >
197208 { JSON . stringify ( error . graphQLErrors , null , 2 ) }
198- </ pre >
199- </ div >
200- ) }
201- </ div >
202- ) }
203- </ div >
204- </ details >
205- </ div >
206-
207- < div className = "flex flex-col sm:flex-row gap-3" >
208- < Button onClick = { reset } variant = "default" className = "flex items-center gap-2" >
209+ </ pre >
210+ </ div >
211+ ) }
212+ </ div >
213+ ) }
214+ </ div >
215+ </ details >
216+ </ div >
217+
218+ < div
219+ className = { `
220+ flex flex-col gap-3
221+ sm:flex-row
222+ ` }
223+ >
224+ < Button
225+ onClick = { reset }
226+ variant = "default"
227+ className = { `flex items-center gap-2` }
228+ >
209229 < RefreshCw className = "size-4" />
210230 重試
211231 </ Button >
212-
213- { errorInfo . actionHref ? (
214- < Button asChild variant = "outline" className = "flex items-center gap-2" >
215- < Link href = { errorInfo . actionHref } >
216- 前往處理
217- </ Link >
218- </ Button >
219- ) : (
220- < Button asChild variant = "outline" className = "flex items-center gap-2" >
221- < Link href = "/" >
222- < Home className = "size-4" />
223- 回到首頁
224- </ Link >
225- </ Button >
226- ) }
232+
233+ { errorInfo . actionHref
234+ ? (
235+ < Button
236+ asChild
237+ variant = "outline"
238+ className = { `flex items-center gap-2` }
239+ >
240+ < Link href = { errorInfo . actionHref } >
241+ 前往處理
242+ </ Link >
243+ </ Button >
244+ )
245+ : (
246+ < Button
247+ asChild
248+ variant = "outline"
249+ className = { `flex items-center gap-2` }
250+ >
251+ < Link href = "/" >
252+ < Home className = "size-4" />
253+ 回到首頁
254+ </ Link >
255+ </ Button >
256+ ) }
227257 </ div >
228258 </ CardContent >
229-
259+
230260 < CardFooter
231- className = { `justify-center text-center text-xs text-muted-foreground` }
261+ className = { `
262+ justify-center text-center text-xs text-muted-foreground
263+ ` }
232264 >
233265 < section className = "flex flex-col items-center gap-1" >
234266 < p > 如果問題持續發生,請聯絡開發者進行處理。</ p >
235267 < p className = "text-red-600" >
236- 錯誤時間:{ new Date ( ) . toLocaleString ( ' zh-TW' , { timeZone : ' Asia/Taipei' } ) }
268+ 錯誤時間:{ new Date ( ) . toLocaleString ( " zh-TW" , { timeZone : " Asia/Taipei" } ) }
237269 </ p >
238- { 'digest' in error && error . digest && (
239- < p className = "text-red-600" > 錯誤 ID:{ error . digest } </ p >
270+ { "digest" in error && error . digest && (
271+ < p
272+ className = { `text-red-600` }
273+ >
274+ 錯誤 ID:{ error . digest }
275+ </ p >
240276 ) }
241277 </ section >
242278 </ CardFooter >
0 commit comments