feat(buchhaltung): add audit trail UI to konto detail transaction table

This commit is contained in:
Matthias Hochmeister
2026-03-30 16:03:58 +02:00
parent d833b3c224
commit 2eb59e9ff1

View File

@@ -1,15 +1,17 @@
import { useParams, useNavigate } from 'react-router-dom';
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import {
Box, Typography, Button, Grid, Card, CardContent,
Table, TableHead, TableBody, TableRow, TableCell,
LinearProgress, Chip, Alert, Skeleton, TableContainer, Paper,
IconButton, CircularProgress,
} from '@mui/material';
import { ArrowBack } from '@mui/icons-material';
import { ArrowBack, KeyboardArrowDown, KeyboardArrowUp } from '@mui/icons-material';
import DashboardLayout from '../components/dashboard/DashboardLayout';
import { buchhaltungApi } from '../services/buchhaltung';
import { AUSGABEN_TYP_LABELS } from '../types/buchhaltung.types';
import type { AusgabenTyp } from '../types/buchhaltung.types';
import type { AusgabenTyp, BuchhaltungAudit } from '../types/buchhaltung.types';
const fmtEur = (n: number) => new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(n);
@@ -37,10 +39,77 @@ function BudgetCard({ label, budget, spent }: { label: string; budget: number; s
);
}
const AKTION_LABELS: Record<string, string> = {
erstellt: 'Erstellt',
aktualisiert: 'Aktualisiert',
gebucht: 'Gebucht',
storniert: 'Storniert',
erstellt_wiederkehrend: 'Erstellt (wiederkehrend)',
freigabe_beantragt: 'Freigabe beantragt',
freigabe_genehmigt: 'Freigabe genehmigt',
freigabe_abgelehnt: 'Freigabe abgelehnt',
};
function AuditRows({ transaktionId }: { transaktionId: number }) {
const { data, isLoading } = useQuery<BuchhaltungAudit[]>({
queryKey: ['buchhaltung-audit', transaktionId],
queryFn: () => buchhaltungApi.getAudit(transaktionId),
});
if (isLoading) {
return (
<TableRow>
<TableCell colSpan={7} sx={{ py: 1, bgcolor: 'action.hover' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, px: 2 }}>
<CircularProgress size={14} />
<Typography variant="caption" color="text.secondary">Lade Verlauf</Typography>
</Box>
</TableCell>
</TableRow>
);
}
if (!data || data.length === 0) {
return (
<TableRow>
<TableCell colSpan={7} sx={{ py: 1, bgcolor: 'action.hover' }}>
<Typography variant="caption" color="text.secondary" sx={{ px: 2 }}>Kein Verlauf vorhanden</Typography>
</TableCell>
</TableRow>
);
}
return (
<>
{data.map(entry => (
<TableRow key={entry.id} sx={{ bgcolor: 'action.hover' }}>
<TableCell />
<TableCell>
<Typography variant="caption" color="text.secondary">
{new Date(entry.erstellt_am).toLocaleString('de-DE')}
</Typography>
</TableCell>
<TableCell colSpan={3}>
<Typography variant="caption">
{AKTION_LABELS[entry.aktion] ?? entry.aktion}
</Typography>
</TableCell>
<TableCell colSpan={2}>
<Typography variant="caption" color="text.secondary">
{entry.erstellt_von ?? '—'}
</Typography>
</TableCell>
</TableRow>
))}
</>
);
}
export default function BuchhaltungKontoDetail() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const kontoId = Number(id);
const [expandedId, setExpandedId] = useState<number | null>(null);
const { data, isLoading, isError } = useQuery({
queryKey: ['kontoDetail', kontoId],
@@ -163,6 +232,7 @@ export default function BuchhaltungKontoDetail() {
<Table size="small">
<TableHead>
<TableRow>
<TableCell padding="checkbox" />
<TableCell>Datum</TableCell>
<TableCell>Beschreibung</TableCell>
<TableCell>Typ</TableCell>
@@ -173,10 +243,17 @@ export default function BuchhaltungKontoDetail() {
</TableHead>
<TableBody>
{transaktionen.length === 0 && (
<TableRow><TableCell colSpan={6} align="center">Keine Transaktionen</TableCell></TableRow>
<TableRow><TableCell colSpan={7} align="center">Keine Transaktionen</TableCell></TableRow>
)}
{transaktionen.map(t => (
<TableRow key={t.id}>
<>
<TableRow key={t.id} hover sx={{ cursor: 'pointer' }}
onClick={() => setExpandedId(expandedId === t.id ? null : t.id)}>
<TableCell padding="checkbox">
<IconButton size="small">
{expandedId === t.id ? <KeyboardArrowUp fontSize="small" /> : <KeyboardArrowDown fontSize="small" />}
</IconButton>
</TableCell>
<TableCell>{new Date(t.datum).toLocaleDateString('de-DE')}</TableCell>
<TableCell>{t.beschreibung}</TableCell>
<TableCell>
@@ -190,6 +267,8 @@ export default function BuchhaltungKontoDetail() {
</TableCell>
<TableCell>{t.status}</TableCell>
</TableRow>
{expandedId === t.id && <AuditRows transaktionId={t.id} />}
</>
))}
</TableBody>
</Table>