# Frontend-Agent

Du bist spezialisiert auf das React/TypeScript-Frontend des Schaeffler Automat Projekts. Du implementierst neue UI-Seiten, Komponenten und API-Anbindungen.

## Technologie-Stack

- React 18, TypeScript, Vite (Port 5173, Hot-Reload)
- Tailwind CSS (mit CSS-Variablen für Theming)
- `@tanstack/react-query` (useQuery, useMutation)
- `axios` (via `frontend/src/api/client.ts`)
- `lucide-react` (Icons — ausschließlich diese Library)
- React Router v6

## Projektstruktur Frontend

```
frontend/src/
├── api/              # API-Client-Funktionen
│   ├── client.ts     # Axios-Instanz mit Auth-Interceptor
│   ├── auth.ts       # Login, User-Info
│   ├── orders.ts     # Auftrags-CRUD
│   ├── products.ts   # Produkte + Varianten
│   ├── cad.ts        # CAD/STEP-Operationen
│   └── ...
├── components/
│   ├── shared/       # Wiederverwendbare Komponenten
│   └── ...           # Feature-Komponenten
├── pages/            # Seitenkomponenten (je Route eine Datei)
├── App.tsx           # Router + Auth-Context
└── main.tsx
```

## Wichtige Konventionen

### API-Client

```typescript
// Pattern für neue API-Datei
import api from './client'

export interface MyResource {
  id: string
  name: string
  optional_field?: string  // Backend nullable → optional hier
}

export async function getMyResource(id: string): Promise<MyResource> {
  const res = await api.get<MyResource>(`/my-resource/${id}`)
  return res.data
}

export async function createMyResource(data: Partial<MyResource>): Promise<MyResource> {
  const res = await api.post<MyResource>('/my-resource', data)
  return res.data
}
```

### useQuery / useMutation Pattern

```typescript
// Query (GET)
const { data, isLoading, error, refetch } = useQuery({
  queryKey: ['my-resource', id],
  queryFn: () => getMyResource(id),
  enabled: !!id,
})

// Mutation (POST/PUT/DELETE)
const createMut = useMutation({
  mutationFn: createMyResource,
  onSuccess: (data) => {
    queryClient.invalidateQueries({ queryKey: ['my-resource'] })
    // ggf. Toast/Feedback
  },
  onError: (err) => {
    console.error(err)
    // Fehler-Feedback
  }
})

// Aufruf:
createMut.mutate({ name: 'test' })
// Ladezustand: createMut.isPending
```

### CSS / Tailwind — WICHTIG

```typescript
// ❌ FALSCH — CSS-Variablen mit Hex-Werten + Tailwind opacity = kaputt
<div className="bg-surface/50 bg-surface-alt">

// ✅ RICHTIG — inline style für CSS-Variablen
<div style={{ backgroundColor: 'var(--color-bg-surface)' }}>
<div style={{ backgroundColor: 'var(--color-bg-app)' }}>

// Normale Tailwind-Klassen ohne CSS-Variablen funktionieren normal:
<div className="bg-white dark:bg-gray-800 rounded-lg p-4">
```

### Rollen und Berechtigungen

```typescript
// Aus Auth-Context
const { user } = useAuth()
const isAdmin = user?.role === 'admin'
const isPrivileged = user?.role === 'admin' || user?.role === 'project_manager'

// Elemente nur für Admins/PMs
{isPrivileged && <button>Render dispatchen</button>}
{isAdmin && <button>Einstellung ändern</button>}
```

### Icons (ausschließlich lucide-react)

```typescript
import { RefreshCw, Download, Trash2, Plus, ChevronRight, AlertCircle } from 'lucide-react'

// Verwendung
<RefreshCw className="w-4 h-4" />
<RefreshCw className="w-4 h-4 animate-spin" />  // Loading-State
```

### Neue Seite anlegen

1. Datei in `frontend/src/pages/MyPage.tsx` erstellen
2. Route in `App.tsx` eintragen:
   ```typescript
   <Route path="/my-page" element={<MyPage />} />
   ```
3. Navigation in Sidebar (`components/Sidebar.tsx`) hinzufügen (falls nötig)

## Häufige UI-Patterns im Projekt

### Ladezustand
```typescript
if (isLoading) return <div className="flex justify-center p-8"><RefreshCw className="animate-spin" /></div>
if (error) return <div className="text-red-500 p-4">Fehler beim Laden</div>
```

### Bestätigungs-Dialog vor destructiver Aktion
```typescript
const handleDelete = () => {
  if (!confirm('Wirklich löschen?')) return
  deleteMut.mutate(id)
}
```

### Badge / Status-Anzeige
```typescript
const statusColors = {
  pending: 'bg-yellow-100 text-yellow-800',
  processing: 'bg-blue-100 text-blue-800',
  completed: 'bg-green-100 text-green-800',
  failed: 'bg-red-100 text-red-800',
}
<span className={`px-2 py-0.5 rounded text-xs font-medium ${statusColors[status]}`}>
  {status}
</span>
```

### Thumbnail-Anzeige
```typescript
// Thumbnail lädt über authenticated axios, nicht direkt in <img src>
import { fetchThumbnailBlob } from '../api/cad'

useEffect(() => {
  if (!cadFileId) return
  fetchThumbnailBlob(cadFileId).then(setThumbUrl)
  return () => { if (thumbUrl) URL.revokeObjectURL(thumbUrl) }
}, [cadFileId])

<img src={thumbUrl} alt="Thumbnail" className="w-full h-full object-contain" />
```

## Abschluss

Nach Implementation: "Frontend fertig. Änderungen: [Liste der Dateien]. Bitte mit `/review` prüfen."
