ErrorBoundary.tsx raw

   1  import { Button } from '@/components/ui/button'
   2  import { RotateCw } from 'lucide-react'
   3  import React, { Component, ReactNode } from 'react'
   4  
   5  interface ErrorBoundaryProps {
   6    children: ReactNode
   7  }
   8  
   9  interface ErrorBoundaryState {
  10    hasError: boolean
  11    error?: Error
  12  }
  13  
  14  export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
  15    constructor(props: ErrorBoundaryProps) {
  16      super(props)
  17      this.state = { hasError: false }
  18    }
  19  
  20    static getDerivedStateFromError(error: Error) {
  21      return { hasError: true, error }
  22    }
  23  
  24    componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
  25      console.error('ErrorBoundary caught an error:', error, errorInfo)
  26    }
  27  
  28    render() {
  29      if (this.state.hasError) {
  30        return (
  31          <div className="w-screen h-screen flex flex-col items-center justify-center p-4 gap-4">
  32            <h1 className="text-2xl font-bold">Oops, something went wrong.</h1>
  33            <p className="text-lg text-center max-w-md">
  34              Sorry for the inconvenience. If you don't mind helping, you can{' '}
  35              <a
  36                href="https://git.mleku.dev/mleku/smesh/issues/new"
  37                target="_blank"
  38                rel="noopener noreferrer"
  39                className="text-primary underline"
  40              >
  41                submit an issue
  42              </a>{' '}
  43              with the error details, or{' '}
  44              <a
  45                href="https://smesh.mleku.dev/npub1syjmjy0dp62dhccq3g97fr87tngvpvzey08llyt6ul58m2zqpzps9wf6wl"
  46                target="_blank"
  47                rel="noopener noreferrer"
  48                className="text-primary underline"
  49              >
  50                mention me
  51              </a>
  52              . Thank you for your support!
  53            </p>
  54            {this.state.error?.message && (
  55              <>
  56                <Button
  57                  onClick={() => {
  58                    navigator.clipboard.writeText(this.state.error!.message)
  59                  }}
  60                  variant="secondary"
  61                >
  62                  Copy Error Message
  63                </Button>
  64                <pre className="bg-destructive/10 text-destructive p-2 rounded text-wrap break-words whitespace-pre-wrap">
  65                  Error: {this.state.error.message}
  66                </pre>
  67              </>
  68            )}
  69            <Button onClick={() => window.location.reload()} className="mt-2">
  70              <RotateCw />
  71              Reload Page
  72            </Button>
  73          </div>
  74        )
  75      }
  76      return this.props.children
  77    }
  78  }
  79