147 lines
4.6 KiB
TypeScript
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>
|
|
);
|
|
}
|