Fixed change management rendering error

This commit is contained in:
2026-09-27 13:43:14 +02:00
parent c1c5641d1e
commit 8afceda1cd
6 changed files with 137 additions and 10 deletions
@@ -23,6 +23,7 @@ import {
import { useAuth } from '../../auth/AuthProvider';
import { BrandLogo } from '../ui/BrandLogo';
import { HelpTooltip } from '../ui/HelpTooltip';
import { ErrorBoundary } from '../ui/ErrorBoundary';
import { useQuery } from '@tanstack/react-query';
import { getUsers } from '../../services/api';
import { getUserEmail, registerUserEmail } from '../../lib/formatters';
@@ -395,7 +396,9 @@ export const AppLayout: React.FC = () => {
<div className="absolute top-1/2 -right-24 w-80 h-80 bg-indigo-600/10 rounded-full blur-3xl pointer-events-none" />
<div className="relative z-10">
<Outlet />
<ErrorBoundary>
<Outlet />
</ErrorBoundary>
</div>
</main>
@@ -0,0 +1,76 @@
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
interface Props {
children: ReactNode;
fallbackTitle?: string;
}
interface State {
hasError: boolean;
error: Error | null;
}
export class ErrorBoundary extends React.Component<Props, State> {
declare props: Props;
declare state: State;
constructor(props: Props) {
super(props);
this.state = {
hasError: false,
error: null,
};
}
public static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('[PFM Error Boundary Caught]', error, errorInfo);
}
public handleReset = () => {
(this as any).setState({ hasError: false, error: null });
};
public render() {
if (this.state.hasError) {
return (
<div className="min-h-[400px] flex items-center justify-center p-6">
<div className="max-w-md w-full bg-[#0f1523]/90 backdrop-blur-md rounded-2xl border border-rose-500/30 p-6 text-center shadow-2xl">
<div className="w-12 h-12 rounded-2xl bg-rose-500/10 border border-rose-500/20 text-rose-400 flex items-center justify-center mx-auto mb-4">
<AlertTriangle className="w-6 h-6" />
</div>
<h3 className="text-base font-bold text-white mb-2">
{this.props.fallbackTitle || 'Display Module Encountered an Issue'}
</h3>
<p className="text-xs text-slate-400 mb-6 leading-relaxed">
An unexpected display error occurred while rendering this view. You can reload the view or return to the executive dashboard.
</p>
<div className="flex items-center justify-center gap-3">
<button
type="button"
onClick={this.handleReset}
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl text-xs font-semibold bg-slate-800 hover:bg-slate-700 text-white border border-slate-700 transition cursor-pointer"
>
<RefreshCw className="w-3.5 h-3.5 text-blue-400" />
<span>Reload View</span>
</button>
<a
href="/dashboard"
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl text-xs font-semibold bg-blue-600 hover:bg-blue-500 text-white transition cursor-pointer shadow-md shadow-blue-500/20"
>
<Home className="w-3.5 h-3.5" />
<span>Dashboard</span>
</a>
</div>
</div>
</div>
);
}
return this.props.children;
}
}
@@ -0,0 +1,31 @@
import React from 'react';
import { ApprovalStatus, Priority, ActivityStatus } from '../../types';
import { getApprovalStatusBadge, getPriorityBadge, getActivityStatusBadge } from '../../lib/formatters';
export const ApprovalStatusBadge: React.FC<{ status: ApprovalStatus | number | null | undefined }> = ({ status }) => {
const badge = getApprovalStatusBadge(status ?? ApprovalStatus.Pending);
return (
<span className={`inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[11px] font-semibold border whitespace-nowrap ${badge.className}`}>
{badge.dot && <span className={`w-1.5 h-1.5 rounded-full ${badge.dot}`} />}
<span>{badge.label}</span>
</span>
);
};
export const PriorityBadge: React.FC<{ priority: Priority | number | null | undefined }> = ({ priority }) => {
const badge = getPriorityBadge(priority ?? Priority.Medium);
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-[11px] font-semibold border whitespace-nowrap ${badge.className}`}>
<span>{badge.label}</span>
</span>
);
};
export const ActivityStatusBadge: React.FC<{ status: ActivityStatus | number | string | boolean | null | undefined }> = ({ status }) => {
const badge = getActivityStatusBadge(status);
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-[11px] font-semibold border whitespace-nowrap ${badge.className}`}>
<span>{badge.label}</span>
</span>
);
};