# Pattern: Detail Page

A full-page view for displaying the details of a single entity (user, project, order, etc.) with a header, metadata section, tabbed content, and action buttons.

---

## When to Use

Use the Detail Page pattern when:

- A user clicks on a row in a data table and needs to see the full record
- An entity has multiple related sections (overview, history, settings, documents)
- Actions like Edit, Delete, or Export are available for the entity
- The page needs a breadcrumb trail back to the list view

---

## Components Used

- [`PageHeader`](../components/page-header.md) — breadcrumb + title
- [`Card`](../components/card.md) — metadata and content sections
- [`Tabs`](../components/tabs.md) — multiple content sections
- [`Badge`](../components/badge.md) — status indicators
- [`Button`](../components/button.md) — primary and secondary actions
- [`Table`](../components/table.md) — related records list
- [`Separator`](../components/separator.md) — visual dividers
- [`Avatar`](../components/avatar.md) — entity image/icon
- [`Skeleton`](../components/skeleton.md) — loading state

---

## Basic Structure

```tsx
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
  Badge,
  Button,
  Avatar,
  AvatarFallback,
  AvatarImage,
  Separator,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from 'xertica-ui/ui';
import { PageHeader, PageHeaderHeading } from 'xertica-ui/ui';
import { Edit, Trash2, Download } from 'lucide-react';

interface EntityDetailPageProps {
  entity: {
    id: string;
    name: string;
    email: string;
    status: 'active' | 'inactive' | 'pending';
    createdAt: string;
    avatar?: string;
  };
  onEdit: () => void;
  onDelete: () => void;
}

export function EntityDetailPage({ entity, onEdit, onDelete }: EntityDetailPageProps) {
  return (
    <div className="flex flex-col h-full overflow-hidden">
      {/* Page Header */}
      <PageHeader>
        <PageHeaderHeading>{entity.name}</PageHeaderHeading>
        <div className="flex items-center gap-2 ml-auto">
          <Button variant="outline" size="sm" onClick={onEdit}>
            <Edit className="w-4 h-4 mr-2" />
            Editar
          </Button>
          <Button variant="destructive" size="sm" onClick={onDelete}>
            <Trash2 className="w-4 h-4 mr-2" />
            Excluir
          </Button>
        </div>
      </PageHeader>

      {/* Scrollable Content */}
      <div className="flex-1 overflow-y-auto p-6 space-y-6">
        {/* Entity Summary Card */}
        <Card>
          <CardContent className="pt-6">
            <div className="flex items-start gap-4">
              <Avatar className="w-16 h-16">
                <AvatarImage src={entity.avatar} />
                <AvatarFallback>{entity.name.slice(0, 2).toUpperCase()}</AvatarFallback>
              </Avatar>
              <div className="flex-1 space-y-1">
                <div className="flex items-center gap-2">
                  <h2 className="text-xl font-semibold">{entity.name}</h2>
                  <Badge variant={entity.status === 'active' ? 'default' : 'secondary'}>
                    {entity.status}
                  </Badge>
                </div>
                <p className="text-muted-foreground">{entity.email}</p>
                <p className="text-sm text-muted-foreground">
                  Criado em {new Date(entity.createdAt).toLocaleDateString('pt-BR')}
                </p>
              </div>
            </div>
          </CardContent>
        </Card>

        {/* Tabbed Content */}
        <Tabs defaultValue="overview">
          <TabsList>
            <TabsTrigger value="overview">Visão Geral</TabsTrigger>
            <TabsTrigger value="history">Histórico</TabsTrigger>
            <TabsTrigger value="documents">Documentos</TabsTrigger>
          </TabsList>

          <TabsContent value="overview" className="mt-4">
            <OverviewTab entity={entity} />
          </TabsContent>

          <TabsContent value="history" className="mt-4">
            <HistoryTab entityId={entity.id} />
          </TabsContent>

          <TabsContent value="documents" className="mt-4">
            <DocumentsTab entityId={entity.id} />
          </TabsContent>
        </Tabs>
      </div>
    </div>
  );
}
```

---

## Overview Tab

```tsx
function OverviewTab({ entity }) {
  const fields = [
    { label: 'ID', value: entity.id },
    { label: 'E-mail', value: entity.email },
    { label: 'Status', value: entity.status },
    { label: 'Data de criação', value: new Date(entity.createdAt).toLocaleDateString('pt-BR') },
  ];

  return (
    <Card>
      <CardHeader>
        <CardTitle>Informações</CardTitle>
      </CardHeader>
      <CardContent>
        <dl className="space-y-3">
          {fields.map(({ label, value }) => (
            <div
              key={label}
              className="flex justify-between py-2 border-b border-border last:border-0"
            >
              <dt className="text-muted-foreground text-sm">{label}</dt>
              <dd className="font-medium text-sm">{value}</dd>
            </div>
          ))}
        </dl>
      </CardContent>
    </Card>
  );
}
```

---

## History Tab

```tsx
function HistoryTab({ entityId }) {
  const events = [
    { date: '2026-05-01', action: 'Criado', user: 'Admin' },
    { date: '2026-05-10', action: 'Atualizado', user: 'João Silva' },
    { date: '2026-05-15', action: 'Status alterado para ativo', user: 'Sistema' },
  ];

  return (
    <Card>
      <CardHeader>
        <CardTitle>Histórico de Alterações</CardTitle>
      </CardHeader>
      <CardContent>
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead>Data</TableHead>
              <TableHead>Ação</TableHead>
              <TableHead>Usuário</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {events.map((event, i) => (
              <TableRow key={i}>
                <TableCell className="text-muted-foreground">
                  {new Date(event.date).toLocaleDateString('pt-BR')}
                </TableCell>
                <TableCell>{event.action}</TableCell>
                <TableCell>{event.user}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </CardContent>
    </Card>
  );
}
```

---

## Loading State

Use `Skeleton` while the entity data is being fetched:

```tsx
function EntityDetailSkeleton() {
  return (
    <div className="p-6 space-y-6">
      <Card>
        <CardContent className="pt-6">
          <div className="flex items-start gap-4">
            <Skeleton className="w-16 h-16 rounded-full" />
            <div className="flex-1 space-y-2">
              <Skeleton className="h-6 w-48" />
              <Skeleton className="h-4 w-64" />
              <Skeleton className="h-4 w-32" />
            </div>
          </div>
        </CardContent>
      </Card>
      <Skeleton className="h-10 w-full" />
      <Skeleton className="h-64 w-full" />
    </div>
  );
}
```

---

## Routing Integration

```tsx
import { useParams, useNavigate } from 'react-router-dom';

function EntityDetailRoute() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const [entity, setEntity] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchEntity(id).then(data => {
      setEntity(data);
      setLoading(false);
    });
  }, [id]);

  if (loading) return <EntityDetailSkeleton />;

  return (
    <EntityDetailPage
      entity={entity}
      onEdit={() => navigate(`/entities/${id}/edit`)}
      onDelete={() => {
        deleteEntity(id).then(() => navigate('/entities'));
      }}
    />
  );
}
```

---

## AI Rules

> [!IMPORTANT]
>
> - **Use `Tabs` for multiple content sections**: Never stack all content vertically without tabs when there are more than 2 logical sections. Use `Tabs` to keep the page scannable.
> - **Status with `Badge`**: Always use `<Badge>` for entity status indicators. Never use raw colored `<span>` elements.
> - **`PageHeader` for breadcrumbs and actions**: Place the entity name in `<PageHeaderHeading>` and action buttons (Edit, Delete) in the right side of `<PageHeader>`. Do not put action buttons inside the content area.
> - **`Skeleton` for loading**: Always show a skeleton layout while data is loading. Never show an empty page or a spinner alone.
> - **Destructive actions need confirmation**: Wrap Delete actions in an `<AlertDialog>` to confirm before executing. Never delete on a single click.
