# Pattern: Settings Page

A structured settings page with categorized sections, form fields, and save/cancel actions. Suitable for user preferences, application configuration, and account management.

---

## When to Use

Use the Settings pattern when:

- Users need to configure personal preferences (theme, language, notifications)
- Administrators need to manage application-level configuration
- Account management (profile, password, API keys) is required
- Settings are grouped into logical categories (General, Security, Notifications, etc.)

---

## Components Used

- [`PageHeader`](../components/page-header.md) — page title and breadcrumb
- [`Card`](../components/card.md) — settings section container
- [`Tabs`](../components/tabs.md) — category navigation (sidebar or top tabs)
- [`Form`](../components/form.md) + form elements — settings fields
- [`Switch`](../components/switch.md) — boolean toggles
- [`Select`](../components/select.md) — option dropdowns
- [`Input`](../components/input.md) — text settings
- [`Button`](../components/button.md) — Save and Cancel actions
- [`Separator`](../components/separator.md) — section dividers
- [`Sonner`](../components/sonner.md) — success/error toast after save

---

## Basic Structure

```tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
  Button,
  Input,
  Label,
  Switch,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
  Separator,
} from 'xertica-ui/ui';
import { PageHeader, PageHeaderHeading, PageHeaderDescription } from 'xertica-ui/ui';
import { toast } from 'sonner';

export function SettingsPage() {
  return (
    <div className="flex flex-col h-full overflow-hidden">
      <PageHeader>
        <div>
          <PageHeaderHeading>Configurações</PageHeaderHeading>
          <PageHeaderDescription>
            Gerencie suas preferências e configurações da conta.
          </PageHeaderDescription>
        </div>
      </PageHeader>

      <div className="flex-1 overflow-y-auto p-6">
        <Tabs defaultValue="general" className="space-y-6">
          <TabsList>
            <TabsTrigger value="general">Geral</TabsTrigger>
            <TabsTrigger value="security">Segurança</TabsTrigger>
            <TabsTrigger value="notifications">Notificações</TabsTrigger>
            <TabsTrigger value="api">API Keys</TabsTrigger>
          </TabsList>

          <TabsContent value="general">
            <GeneralSettings />
          </TabsContent>

          <TabsContent value="security">
            <SecuritySettings />
          </TabsContent>

          <TabsContent value="notifications">
            <NotificationSettings />
          </TabsContent>

          <TabsContent value="api">
            <ApiKeySettings />
          </TabsContent>
        </Tabs>
      </div>
    </div>
  );
}
```

---

## General Settings Section

```tsx
function GeneralSettings() {
  const [name, setName] = useState('João Silva');
  const [language, setLanguage] = useState('pt-BR');
  const [theme, setTheme] = useState('system');

  const handleSave = () => {
    // persist settings
    toast.success('Configurações salvas com sucesso.');
  };

  return (
    <div className="space-y-6 max-w-2xl">
      {/* Profile */}
      <Card>
        <CardHeader>
          <CardTitle>Perfil</CardTitle>
          <CardDescription>Informações básicas da sua conta.</CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="space-y-2">
            <Label htmlFor="name">Nome completo</Label>
            <Input id="name" value={name} onChange={e => setName(e.target.value)} />
          </div>
        </CardContent>
      </Card>

      {/* Preferences */}
      <Card>
        <CardHeader>
          <CardTitle>Preferências</CardTitle>
          <CardDescription>Idioma e aparência da interface.</CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="space-y-2">
            <Label>Idioma</Label>
            <Select value={language} onValueChange={setLanguage}>
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="pt-BR">Português (Brasil)</SelectItem>
                <SelectItem value="en">English</SelectItem>
                <SelectItem value="es">Español</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div className="space-y-2">
            <Label>Tema</Label>
            <Select value={theme} onValueChange={setTheme}>
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="light">Claro</SelectItem>
                <SelectItem value="dark">Escuro</SelectItem>
                <SelectItem value="system">Sistema</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </CardContent>
        <CardFooter className="flex justify-end gap-2">
          <Button variant="outline">Cancelar</Button>
          <Button onClick={handleSave}>Salvar alterações</Button>
        </CardFooter>
      </Card>
    </div>
  );
}
```

---

## Notification Settings Section

```tsx
function NotificationSettings() {
  const [notifications, setNotifications] = useState({
    email: true,
    push: false,
    weeklyReport: true,
    securityAlerts: true,
  });

  const toggle = (key: keyof typeof notifications) => {
    setNotifications(prev => ({ ...prev, [key]: !prev[key] }));
  };

  const items = [
    {
      key: 'email',
      label: 'Notificações por e-mail',
      description: 'Receba atualizações no seu e-mail',
    },
    { key: 'push', label: 'Notificações push', description: 'Notificações no navegador' },
    {
      key: 'weeklyReport',
      label: 'Relatório semanal',
      description: 'Resumo de atividades toda segunda-feira',
    },
    {
      key: 'securityAlerts',
      label: 'Alertas de segurança',
      description: 'Notificações sobre acessos suspeitos',
    },
  ];

  return (
    <Card className="max-w-2xl">
      <CardHeader>
        <CardTitle>Notificações</CardTitle>
        <CardDescription>Escolha quais notificações deseja receber.</CardDescription>
      </CardHeader>
      <CardContent className="space-y-0">
        {items.map(({ key, label, description }, index) => (
          <div key={key}>
            <div className="flex items-center justify-between py-4">
              <div className="space-y-0.5">
                <Label className="text-base">{label}</Label>
                <p className="text-sm text-muted-foreground">{description}</p>
              </div>
              <Switch
                checked={notifications[key as keyof typeof notifications]}
                onCheckedChange={() => toggle(key as keyof typeof notifications)}
              />
            </div>
            {index < items.length - 1 && <Separator />}
          </div>
        ))}
      </CardContent>
      <CardFooter className="flex justify-end">
        <Button onClick={() => toast.success('Preferências de notificação salvas.')}>Salvar</Button>
      </CardFooter>
    </Card>
  );
}
```

---

## Security Settings Section

```tsx
function SecuritySettings() {
  const [currentPassword, setCurrentPassword] = useState('');
  const [newPassword, setNewPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');

  const handleChangePassword = () => {
    if (newPassword !== confirmPassword) {
      toast.error('As senhas não coincidem.');
      return;
    }
    // call API
    toast.success('Senha alterada com sucesso.');
    setCurrentPassword('');
    setNewPassword('');
    setConfirmPassword('');
  };

  return (
    <Card className="max-w-2xl">
      <CardHeader>
        <CardTitle>Alterar Senha</CardTitle>
        <CardDescription>Use uma senha forte com pelo menos 8 caracteres.</CardDescription>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="space-y-2">
          <Label htmlFor="current-password">Senha atual</Label>
          <Input
            id="current-password"
            type="password"
            value={currentPassword}
            onChange={e => setCurrentPassword(e.target.value)}
          />
        </div>
        <div className="space-y-2">
          <Label htmlFor="new-password">Nova senha</Label>
          <Input
            id="new-password"
            type="password"
            value={newPassword}
            onChange={e => setNewPassword(e.target.value)}
          />
        </div>
        <div className="space-y-2">
          <Label htmlFor="confirm-password">Confirmar nova senha</Label>
          <Input
            id="confirm-password"
            type="password"
            value={confirmPassword}
            onChange={e => setConfirmPassword(e.target.value)}
          />
        </div>
      </CardContent>
      <CardFooter className="flex justify-end">
        <Button onClick={handleChangePassword}>Alterar senha</Button>
      </CardFooter>
    </Card>
  );
}
```

---

## API Key Settings Section

```tsx
import { useApiKey } from 'xertica-ui/hooks';

function ApiKeySettings() {
  const { geminiApiKey, setGeminiApiKey } = useApiKey();
  const [localKey, setLocalKey] = useState(geminiApiKey);

  const handleSave = () => {
    setGeminiApiKey(localKey);
    toast.success('API key salva com sucesso.');
  };

  return (
    <Card className="max-w-2xl">
      <CardHeader>
        <CardTitle>Chaves de API</CardTitle>
        <CardDescription>Configure as chaves de API para os serviços integrados.</CardDescription>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="space-y-2">
          <Label htmlFor="gemini-key">Google Gemini API Key</Label>
          <Input
            id="gemini-key"
            type="password"
            value={localKey}
            onChange={e => setLocalKey(e.target.value)}
            placeholder="AIza..."
          />
          <p className="text-xs text-muted-foreground">
            Necessária para o assistente de IA em modo real.
          </p>
        </div>
      </CardContent>
      <CardFooter className="flex justify-end">
        <Button onClick={handleSave}>Salvar chave</Button>
      </CardFooter>
    </Card>
  );
}
```

---

## AI Rules

> [!IMPORTANT]
>
> - **One `Card` per settings group**: Group related settings into a single `Card` with a `CardHeader` (title + description), `CardContent` (fields), and `CardFooter` (Save/Cancel buttons).
> - **Use `Switch` for boolean settings**: Never use `Checkbox` for on/off toggles in settings. `Switch` is the correct component for this context.
> - **Always show a toast after save**: Use `toast.success()` from `sonner` to confirm that settings were saved. Use `toast.error()` for validation failures.
> - **`Tabs` for categories**: When there are more than 2 settings categories, use `Tabs` to organize them. Do not use a custom sidebar navigation.
> - **Password fields use `type="password"`**: Never render password inputs as plain text. Always use `<Input type="password">`.
> - **API keys via `useApiKey`**: Use the `useApiKey()` hook from `xertica-ui/hooks` to read and write API keys. Do not store them in component state or `localStorage` directly.
