Files
dashboard/frontend/src/pages/IssueNeu.tsx

147 lines
4.6 KiB
TypeScript

import { useState } from 'react';
import {
Button, TextField, MenuItem, Select, FormControl,
InputLabel, Grid, Collapse,
} from '@mui/material';
import { Add as AddIcon } from '@mui/icons-material';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import DashboardLayout from '../components/dashboard/DashboardLayout';
import { PageHeader, FormLayout } from '../components/templates';
import { useNotification } from '../contexts/NotificationContext';
import { issuesApi } from '../services/issues';
import type { CreateIssuePayload } from '../types/issue.types';
export default function IssueNeu() {
const navigate = useNavigate();
const queryClient = useQueryClient();
const { showSuccess, showError } = useNotification();
const [form, setForm] = useState<CreateIssuePayload>({ titel: '', prioritaet: '' });
const [showDescription, setShowDescription] = useState(false);
const { data: types = [] } = useQuery({
queryKey: ['issue-types'],
queryFn: issuesApi.getTypes,
});
const { data: priorities = [] } = useQuery({
queryKey: ['issue-priorities'],
queryFn: issuesApi.getPriorities,
});
const defaultTypId = types.find(t => t.aktiv)?.id;
const defaultPriority = priorities.find(p => p.aktiv)?.schluessel ?? 'mittel';
const createMut = useMutation({
mutationFn: (data: CreateIssuePayload) => issuesApi.createIssue(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['issues'] });
showSuccess('Issue erstellt');
navigate('/issues');
},
onError: () => showError('Fehler beim Erstellen'),
});
const handleSubmit = () => {
createMut.mutate({
...form,
typ_id: form.typ_id ?? defaultTypId,
prioritaet: form.prioritaet || defaultPriority,
});
};
return (
<DashboardLayout>
<PageHeader
title="Neues Issue"
backTo="/issues"
/>
<FormLayout
actions={<>
<Button onClick={() => navigate('/issues')}>Abbrechen</Button>
<Button
variant="contained"
disabled={!form.titel.trim() || createMut.isPending}
onClick={handleSubmit}
>
Erstellen
</Button>
</>}
>
<TextField
label="Titel"
required
fullWidth
value={form.titel}
onChange={(e) => setForm({ ...form, titel: e.target.value })}
autoFocus
/>
<Collapse in={showDescription} unmountOnExit>
<TextField
label="Beschreibung"
multiline
rows={4}
fullWidth
value={form.beschreibung || ''}
onChange={(e) => setForm({ ...form, beschreibung: e.target.value })}
/>
</Collapse>
{!showDescription && (
<Button
size="small"
startIcon={<AddIcon />}
onClick={() => setShowDescription(true)}
sx={{ alignSelf: 'flex-start' }}
>
Beschreibung hinzufuegen
</Button>
)}
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<FormControl fullWidth>
<InputLabel>Typ</InputLabel>
<Select
value={form.typ_id ?? defaultTypId ?? ''}
label="Typ"
onChange={(e) => setForm({ ...form, typ_id: Number(e.target.value) })}
>
{types.filter(t => t.aktiv).map(t => (
<MenuItem key={t.id} value={t.id}>{t.name}</MenuItem>
))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl fullWidth>
<InputLabel>Prioritaet</InputLabel>
<Select
value={form.prioritaet || defaultPriority}
label="Prioritaet"
onChange={(e) => setForm({ ...form, prioritaet: e.target.value })}
>
{priorities.filter(p => p.aktiv).map(p => (
<MenuItem key={p.schluessel} value={p.schluessel}>{p.bezeichnung}</MenuItem>
))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
label="Fällig am"
type="date"
fullWidth
value={form.faellig_am || ''}
onChange={(e) => setForm({ ...form, faellig_am: e.target.value || null })}
InputLabelProps={{ shrink: true }}
/>
</Grid>
</Grid>
</FormLayout>
</DashboardLayout>
);
}