refactor: migrate ReportsPage to TanStack Query

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
CCS Admin 2026-02-26 18:31:59 +00:00
parent 29b54e58a2
commit 150be9183c
2 changed files with 54 additions and 43 deletions

View file

@ -0,0 +1,38 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import api from '@/services/api'
import type { ReportMeta } from '@/types'
interface ReportsListResponse {
items: ReportMeta[]
total: number
}
export function useReports() {
return useQuery({
queryKey: ['reports'],
queryFn: () =>
api.get<ReportsListResponse>('/reports/list').then(r => r.data),
})
}
export function useGenerateReport() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (params: { jahr: number; kw: number }) =>
api.post<ReportMeta>('/reports/generate', null, { params }).then(r => r.data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reports'] })
},
})
}
export function useDeleteReports() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (ids: number[]) =>
api.delete('/reports/delete', { data: ids }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['reports'] })
},
})
}

View file

@ -1,8 +1,8 @@
import { useState, useEffect } from 'react'
import { useState } from 'react'
import { Download, FileSpreadsheet, Loader2, Plus, Trash2 } from 'lucide-react'
import api from '@/services/api'
import type { ReportMeta } from '@/types'
import { useAuth } from '@/context/AuthContext'
import { useReports, useGenerateReport, useDeleteReports } from '@/hooks/useReports'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Checkbox } from '@/components/ui/checkbox'
@ -19,54 +19,31 @@ export function ReportsPage() {
const currentYear = new Date().getFullYear()
const currentKw = getISOWeek(new Date())
const [reports, setReports] = useState<ReportMeta[]>([])
const [totalReports, setTotalReports] = useState(0)
const [loading, setLoading] = useState(true)
// TanStack Query hooks
const { data, isLoading: loading } = useReports()
const reports = data?.items ?? []
const totalReports = data?.total ?? 0
const generateMutation = useGenerateReport()
const deleteMutation = useDeleteReports()
// Report generation state
const [genJahr, setGenJahr] = useState(currentYear)
const [genKw, setGenKw] = useState(currentKw)
const [generating, setGenerating] = useState(false)
const [genError, setGenError] = useState('')
const [genSuccess, setGenSuccess] = useState('')
// Selection state for deletion
const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set())
const [deleting, setDeleting] = useState(false)
// Fetch reports list
const fetchReports = () => {
setLoading(true)
api.get<{ items: ReportMeta[]; total: number }>('/reports/list')
.then((res) => {
setReports(res.data.items)
setTotalReports(res.data.total)
})
.catch(() => {
setReports([])
setTotalReports(0)
})
.finally(() => setLoading(false))
}
useEffect(() => {
fetchReports()
}, [])
const generateReport = async () => {
setGenerating(true)
setGenError('')
setGenSuccess('')
try {
const res = await api.post<ReportMeta>('/reports/generate', null, {
params: { jahr: genJahr, kw: genKw },
})
setGenSuccess(`Bericht für KW ${res.data.kw}/${res.data.jahr} wurde generiert.`)
fetchReports()
const result = await generateMutation.mutateAsync({ jahr: genJahr, kw: genKw })
setGenSuccess(`Bericht für KW ${result.kw}/${result.jahr} wurde generiert.`)
} catch {
setGenError('Fehler beim Generieren des Berichts.')
} finally {
setGenerating(false)
}
}
@ -122,15 +99,11 @@ export function ReportsPage() {
const deleteSelected = async () => {
if (selectedIds.size === 0) return
setDeleting(true)
try {
await api.delete('/reports/delete', { data: Array.from(selectedIds) })
await deleteMutation.mutateAsync(Array.from(selectedIds))
setSelectedIds(new Set())
fetchReports()
} catch {
setGenError('Fehler beim Löschen der Berichte.')
} finally {
setDeleting(false)
}
}
@ -173,8 +146,8 @@ export function ReportsPage() {
max={53}
/>
</div>
<Button onClick={generateReport} disabled={generating}>
{generating ? (
<Button onClick={generateReport} disabled={generateMutation.isPending}>
{generateMutation.isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Wird generiert...
@ -213,9 +186,9 @@ export function ReportsPage() {
variant="destructive"
size="sm"
onClick={deleteSelected}
disabled={deleting}
disabled={deleteMutation.isPending}
>
{deleting ? (
{deleteMutation.isPending ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<Trash2 className="mr-2 h-4 w-4" />