# ErrorBoundary — Xertica UI

React Error Boundaries catch JavaScript errors in the component tree, log them, and render a fallback UI instead of crashing the application. Xertica UI ships a single reusable `ErrorBoundary` class with **three pre-configured wrapper variants** covering every granularity of protection.

---

## Import

```tsx
// Pre-configured wrappers (recommended)
import {
  AppErrorBoundary,
  PageErrorBoundary,
  SectionErrorBoundary,
} from '@/components/shared/error-boundary';

// Base class (for custom fallbacks)
import { ErrorBoundary } from '@/components/shared/error-boundary';
import type { FallbackProps } from '@/components/shared/error-boundary';
```

---

## The Three Variants

| Variant                | Fallback UI                  | Placement                                           | Purpose                                                                         |
| ---------------------- | ---------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------- |
| `AppErrorBoundary`     | Full-screen, inline-styled   | Outside `QueryClientProvider`, wraps entire `App`   | Catches provider/context crashes; works even if Tailwind/CSS fails              |
| `PageErrorBoundary`    | Half-height, Tailwind-styled | Wraps `<Routes>` / `<AuthGuard>` inside the router  | Catches lazy-chunk load failures and page render errors; app chrome stays alive |
| `SectionErrorBoundary` | Compact inline badge         | Wraps individual sections (table, chart, assistant) | Catches isolated data-rendering errors; page layout stays intact                |

---

## Provider Stack Placement

```tsx
<AppErrorBoundary>
  {' '}
  {/* ← catches: provider init, context crashes */}
  <QueryClientProvider client={queryClient}>
    <XerticaProvider>
      <Router>
        <AuthProvider>
          <PageErrorBoundary>
            {' '}
            {/* ← catches: lazy chunk failures, route renders */}
            <Suspense fallback={null}>
              <Routes>
                <Route
                  path="/home"
                  element={
                    <ProtectedRoute>
                      <HomePage /> {/* ← page internals */}
                    </ProtectedRoute>
                  }
                />
              </Routes>
            </Suspense>
          </PageErrorBoundary>
        </AuthProvider>
      </Router>
    </XerticaProvider>
  </QueryClientProvider>
</AppErrorBoundary>
```

---

## Props

### `AppErrorBoundary` / `PageErrorBoundary` / `SectionErrorBoundary`

| Prop        | Type                                            | Default | Description                                                                                                       |
| ----------- | ----------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| `children`  | `ReactNode`                                     | —       | **Required.** Content to protect                                                                                  |
| `onError`   | `(error: Error, info: React.ErrorInfo) => void` | —       | Called when an error is caught. Wire to Sentry, Datadog, etc.                                                     |
| `resetKeys` | `unknown[]`                                     | —       | When any value in this array changes, the boundary auto-resets. Pass `[location.pathname]` to reset on navigation |

### Base `ErrorBoundary`

Same props plus:

| Prop       | Type                                 | Description                                                   |
| ---------- | ------------------------------------ | ------------------------------------------------------------- |
| `fallback` | `React.ComponentType<FallbackProps>` | **Required.** The component to render when an error is caught |

### `FallbackProps` interface

```ts
interface FallbackProps {
  error: Error; // The caught error
  reset: () => void; // Call to clear the error and re-render children
}
```

---

## Usage Examples

### Protecting a data table section

```tsx
import { SectionErrorBoundary } from '@/components/shared/error-boundary';

function TeamSection() {
  return (
    <SectionErrorBoundary>
      <TeamDataTable />
    </SectionErrorBoundary>
  );
}
```

### Resetting on route change

```tsx
import { PageErrorBoundary } from '@/components/shared/error-boundary';
import { useLocation } from 'react-router-dom';

function AppRoutes() {
  const location = useLocation();
  return (
    <PageErrorBoundary resetKeys={[location.pathname]}>
      <Suspense fallback={null}>
        <Routes>{/* ... */}</Routes>
      </Suspense>
    </PageErrorBoundary>
  );
}
```

### Logging to an error monitoring service

```tsx
import { AppErrorBoundary } from '@/components/shared/error-boundary';
import * as Sentry from '@sentry/react';

<AppErrorBoundary onError={(error, info) => Sentry.captureException(error, { extra: info })}>
  <App />
</AppErrorBoundary>;
```

### Custom fallback with base `ErrorBoundary`

```tsx
import { ErrorBoundary } from '@/components/shared/error-boundary';
import type { FallbackProps } from '@/components/shared/error-boundary';

function MyFallback({ error, reset }: FallbackProps) {
  return (
    <div role="alert">
      <p>Erro: {error.message}</p>
      <button onClick={reset}>Tentar novamente</button>
    </div>
  );
}

<ErrorBoundary fallback={MyFallback}>
  <MyComponent />
</ErrorBoundary>;
```

---

## Fallback UIs

### `AppErrorFallback`

- Full-screen centered layout using **inline styles** (no Tailwind dependency)
- Shows a destructive info icon, error title, and message
- Two buttons: "Tentar novamente" (calls `reset()`) and "Ir para o início" (`window.location.assign('/')`)
- In `DEV` mode: displays the full error stack trace in a `<pre>` block

### `PageErrorFallback`

- Uses Tailwind / xertica-ui token classes
- Centered within the page content area (sidebar and header remain visible)
- Triangle warning icon + descriptive message
- Same two action buttons

### `SectionErrorFallback`

- Compact `rounded-lg` card with `destructive/30` border
- Circle info icon + short message
- Single "Tentar novamente" button
- In `DEV` mode: shows `error.message` in a mono paragraph

---

## AI Rules

> [!IMPORTANT]
>
> - **ALWAYS** place `<AppErrorBoundary>` as the **outermost** element in `App.tsx`, before `QueryClientProvider`. If the query client itself crashes, the app must still show something.
> - **ALWAYS** place `<PageErrorBoundary>` around `<Routes>` / `<AuthGuard>`. This is the primary protection against lazy-chunk load failures (network errors, chunk not found).
> - **USE** `<SectionErrorBoundary>` around any section that fetches data or renders complex content (tables, charts, the assistant panel, embedded maps). An error in one section must not crash the page.
> - **DO NOT** place `<AppErrorBoundary>` inside `<Router>` — it must be outside the router so `AppErrorFallback` can use `window.location.assign` (not `useNavigate`).
> - **DO NOT** use `try/catch` as a substitute for `ErrorBoundary` — try/catch does not catch render-time errors in React component trees. Both are needed for different error classes.
> - **Pass `onError`** to the `AppErrorBoundary` in production to send errors to Sentry, Datadog, or another observability service.
> - **Pass `resetKeys={[location.pathname]}`** to `PageErrorBoundary` if you want errors to auto-clear when the user navigates to a different route.
> - Error boundaries do **not** catch: errors in event handlers (use try/catch there), async errors outside render (use React Query's `onError`), errors in server-side rendering, and errors thrown in the boundary itself.
