rework from modal to page

This commit is contained in:
Matthias Hochmeister
2026-03-25 10:23:28 +01:00
parent 4ad260ce66
commit feb39d234f
14 changed files with 698 additions and 280 deletions

View File

@@ -7,7 +7,7 @@ import {
import {
ArrowBack, Delete as DeleteIcon,
BugReport, FiberNew, HelpOutline, Send as SendIcon,
Circle as CircleIcon, Refresh as RefreshIcon,
Circle as CircleIcon, Refresh as RefreshIcon, History,
} from '@mui/icons-material';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useParams, useNavigate } from 'react-router-dom';
@@ -16,7 +16,7 @@ import { useNotification } from '../contexts/NotificationContext';
import { usePermissionContext } from '../contexts/PermissionContext';
import { useAuth } from '../contexts/AuthContext';
import { issuesApi } from '../services/issues';
import type { Issue, IssueComment, UpdateIssuePayload, AssignableMember, IssueStatusDef, IssuePriorityDef } from '../types/issue.types';
import type { Issue, IssueComment, UpdateIssuePayload, AssignableMember, IssueStatusDef, IssuePriorityDef, IssueHistorie } from '../types/issue.types';
// ── Helpers (copied from Issues.tsx) ──
@@ -117,6 +117,12 @@ export default function IssueDetail() {
enabled: hasEdit,
});
const { data: historie = [] } = useQuery<IssueHistorie[]>({
queryKey: ['issues', issueId, 'history'],
queryFn: () => issuesApi.getHistory(issueId),
enabled: !isNaN(issueId),
});
// ── Permissions ──
const isOwner = issue?.erstellt_von === userId;
const isAssignee = issue?.zugewiesen_an === userId;
@@ -144,6 +150,7 @@ export default function IssueDetail() {
mutationFn: (data: UpdateIssuePayload) => issuesApi.updateIssue(issueId, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['issues'] });
queryClient.invalidateQueries({ queryKey: ['issues', issueId, 'history'] });
showSuccess('Issue aktualisiert');
},
onError: () => showError('Fehler beim Aktualisieren'),
@@ -393,6 +400,35 @@ export default function IssueDetail() {
</IconButton>
</Box>
)}
{/* History section */}
<Divider sx={{ my: 2 }} />
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
<History fontSize="small" />
<Typography variant="subtitle2">Historie</Typography>
</Box>
{historie.length === 0 ? (
<Typography variant="body2" color="text.secondary">Keine Einträge</Typography>
) : (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
{historie.map((h) => (
<Box key={h.id} sx={{ display: 'flex', gap: 1 }}>
<Box sx={{ width: 6, minHeight: '100%', borderRadius: 3, bgcolor: 'divider', flexShrink: 0 }} />
<Box>
<Typography variant="body2">{h.aktion}</Typography>
<Typography variant="caption" color="text.secondary">
{h.erstellt_von_name || 'System'} &middot; {formatDate(h.erstellt_am)}
</Typography>
{h.details && (
<Typography variant="caption" display="block" color="text.secondary">
{Object.entries(h.details).map(([k, v]) => `${k}: ${v}`).join(', ')}
</Typography>
)}
</Box>
</Box>
))}
</Box>
)}
</Box>
{/* Reopen Dialog */}