Files
Philip e045354892 feat: Initialize License Tracker Pro v1.2 project
Adds initial project structure, dependencies, and basic configuration for the License Tracker Pro v1.2 application. This includes setting up Vite for the build process, defining core types, and incorporating essential UI components like icons and a timeline. The project is now ready for development.
2026-01-26 18:55:43 -08:00

84 lines
3.5 KiB
TypeScript

import React, { ErrorInfo, ReactNode } from 'react';
interface ErrorBoundaryProps {
children?: ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
/**
* Global Error Boundary to catch UI crashes and display a fallback screen.
*/
// Use React.Component explicitly to ensure proper inheritance and property access for props and state
export default class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
// Explicitly define properties for TypeScript to recognize them on the class instance
public state: ErrorBoundaryState;
public props: ErrorBoundaryProps;
constructor(props: ErrorBoundaryProps) {
super(props);
// Initialize state in constructor to follow standard React patterns and avoid property conflicts
this.state = {
hasError: false,
error: null
};
this.props = props;
}
public static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("Uncaught license-tracker error:", error, errorInfo);
}
public render(): ReactNode {
// Destructuring state and props from this. Inheritance from Component ensures they exist.
// Explicit usage of this.state and this.props helps avoid shadowing or scoping issues.
const { hasError, error } = this.state;
const { children } = this.props;
if (hasError) {
return (
<div className="min-h-screen bg-slate-900 flex items-center justify-center p-4 text-gray-200">
<div className="bg-slate-800 border border-red-500/50 p-6 rounded-lg max-w-2xl shadow-2xl w-full">
<div className="flex items-center gap-3 mb-4">
<div className="bg-red-500/20 p-2 rounded-full">
<svg className="w-6 h-6 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>
<h1 className="text-2xl font-bold text-red-400">Application Failure</h1>
</div>
<p className="mb-4 text-gray-300">The interface encountered an unexpected error during rendering.</p>
<div className="bg-black/40 p-4 rounded text-xs font-mono text-red-300 overflow-auto max-h-64 mb-6 border border-slate-700 whitespace-pre-wrap">
{error?.stack || error?.toString()}
</div>
<div className="flex gap-4">
<button
onClick={() => window.location.reload()}
className="flex-1 px-6 py-3 bg-cyan-600 hover:bg-cyan-500 text-white font-bold rounded-xl transition-all shadow-lg active:scale-95"
>
Reload Interface
</button>
<button
onClick={() => { localStorage.clear(); window.location.reload(); }}
className="px-6 py-3 bg-slate-700 hover:bg-slate-600 text-slate-300 font-bold rounded-xl transition-all"
>
Clear Cache & Reset
</button>
</div>
</div>
</div>
);
}
return children || null;
}
}