Spaces:
Sleeping
Sleeping
| 'use client'; | |
| import { Button } from '@/components/ui/button'; | |
| import { AlertTriangle, ChevronLeft, RefreshCw } from 'lucide-react'; | |
| import React, { Component, ReactNode } from 'react'; | |
| interface Props { | |
| children: ReactNode; | |
| fallback?: ReactNode; | |
| showBackButton?: boolean; | |
| backButtonText?: string; | |
| backButtonAction?: () => void; | |
| } | |
| interface State { | |
| hasError: boolean; | |
| error?: Error; | |
| } | |
| export class ErrorBoundary extends Component<Props, State> { | |
| constructor(props: Props) { | |
| super(props); | |
| this.state = { hasError: false }; | |
| } | |
| static getDerivedStateFromError(error: Error): State { | |
| return { hasError: true, error }; | |
| } | |
| componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { | |
| console.error('ErrorBoundary caught an error:', error, errorInfo); | |
| // シリアライゼーションエラーの詳細解析 | |
| if (error.message.includes('Only plain objects')) { | |
| console.error('[SERIALIZATION_ERROR] シリアライゼーションエラーの詳細:'); | |
| console.error('[SERIALIZATION_ERROR] Error message:', error.message); | |
| console.error('[SERIALIZATION_ERROR] Error stack:', error.stack); | |
| console.error('[SERIALIZATION_ERROR] Component stack:', errorInfo.componentStack); | |
| // エラーダイジェストが含まれている場合の解析 | |
| if ('digest' in error) { | |
| console.error('[SERIALIZATION_ERROR] Error digest:', (error as Error & { digest?: string }).digest); | |
| } | |
| } | |
| } | |
| handleReset = () => { | |
| this.setState({ hasError: false, error: undefined }); | |
| }; | |
| render() { | |
| if (this.state.hasError) { | |
| if (this.props.fallback) { | |
| return <>{this.props.fallback}</>; | |
| } | |
| return ( | |
| <div className="flex min-h-[400px] flex-col items-center justify-center p-8"> | |
| <div className="mx-auto max-w-md text-center"> | |
| <AlertTriangle className="mx-auto mb-4 h-16 w-16 text-red-500" /> | |
| <h2 className="mb-2 text-2xl font-semibold text-gray-900">エラーが発生しました</h2> | |
| <p className="mb-6 text-gray-600"> | |
| 申し訳ございません。予期しないエラーが発生しました。 | |
| {this.state.error?.message && <span className="mt-2 block text-sm text-gray-500">{this.state.error.message}</span>} | |
| </p> | |
| <div className="flex justify-center gap-3"> | |
| {this.props.showBackButton && ( | |
| <Button | |
| onClick={this.props.backButtonAction} | |
| className="flex h-10 min-w-[120px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1px] border-[#CCCCCC] bg-white px-6 text-[12px] font-semibold text-[#212121] shadow-none hover:bg-[#EEEEEE] hover:text-[#212121]" | |
| > | |
| <ChevronLeft className="h-4 w-4" /> | |
| {this.props.backButtonText || '戻る'} | |
| </Button> | |
| )} | |
| <Button | |
| onClick={this.handleReset} | |
| className="flex h-10 min-w-[120px] cursor-pointer items-center justify-center gap-2 rounded-full bg-[#212121] px-6 text-[12px] font-semibold text-white shadow-none hover:bg-[#212121E5]" | |
| > | |
| <RefreshCw className="h-4 w-4" /> | |
| 再試行 | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return this.props.children; | |
| } | |
| } | |