fix permissions
This commit is contained in:
148
frontend/src/components/dashboard/IssueQuickAddWidget.tsx
Normal file
148
frontend/src/components/dashboard/IssueQuickAddWidget.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
Typography,
|
||||
Box,
|
||||
TextField,
|
||||
Button,
|
||||
MenuItem,
|
||||
Select,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Skeleton,
|
||||
SelectChangeEvent,
|
||||
} from '@mui/material';
|
||||
import { BugReport } from '@mui/icons-material';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { issuesApi } from '../../services/issues';
|
||||
import { useNotification } from '../../contexts/NotificationContext';
|
||||
|
||||
const PRIO_OPTIONS = [
|
||||
{ value: 'niedrig', label: 'Niedrig' },
|
||||
{ value: 'mittel', label: 'Mittel' },
|
||||
{ value: 'hoch', label: 'Hoch' },
|
||||
];
|
||||
|
||||
const IssueQuickAddWidget: React.FC = () => {
|
||||
const [titel, setTitel] = useState('');
|
||||
const [typId, setTypId] = useState<number | ''>('');
|
||||
const [prioritaet, setPrioritaet] = useState<string>('mittel');
|
||||
const { showSuccess, showError } = useNotification();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: types = [], isLoading: typesLoading } = useQuery({
|
||||
queryKey: ['issue-types'],
|
||||
queryFn: issuesApi.getTypes,
|
||||
staleTime: 10 * 60 * 1000,
|
||||
});
|
||||
|
||||
const activeTypes = types.filter((t) => t.aktiv);
|
||||
const defaultTypId = activeTypes[0]?.id;
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: () =>
|
||||
issuesApi.createIssue({
|
||||
titel: titel.trim(),
|
||||
typ_id: typId !== '' ? (typId as number) : defaultTypId,
|
||||
prioritaet,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
showSuccess('Issue erstellt');
|
||||
setTitel('');
|
||||
setTypId('');
|
||||
setPrioritaet('mittel');
|
||||
queryClient.invalidateQueries({ queryKey: ['issues'] });
|
||||
},
|
||||
onError: () => {
|
||||
showError('Issue konnte nicht erstellt werden');
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!titel.trim()) return;
|
||||
mutation.mutate();
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
sx={{
|
||||
height: '100%',
|
||||
transition: 'all 0.3s ease',
|
||||
'&:hover': { boxShadow: 3 },
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
||||
<BugReport color="primary" />
|
||||
<Typography variant="h6">Issue melden</Typography>
|
||||
</Box>
|
||||
|
||||
{typesLoading ? (
|
||||
<Box>
|
||||
<Skeleton variant="rectangular" height={40} sx={{ mb: 1.5, borderRadius: 1 }} />
|
||||
<Skeleton variant="rectangular" height={40} sx={{ mb: 1.5, borderRadius: 1 }} />
|
||||
<Skeleton variant="rectangular" height={40} sx={{ borderRadius: 1 }} />
|
||||
</Box>
|
||||
) : (
|
||||
<Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
size="small"
|
||||
label="Titel"
|
||||
value={titel}
|
||||
onChange={(e) => setTitel(e.target.value)}
|
||||
inputProps={{ maxLength: 255 }}
|
||||
autoComplete="off"
|
||||
/>
|
||||
|
||||
<FormControl fullWidth size="small">
|
||||
<InputLabel>Typ</InputLabel>
|
||||
<Select
|
||||
value={typId}
|
||||
label="Typ"
|
||||
onChange={(e: SelectChangeEvent<number | ''>) =>
|
||||
setTypId(e.target.value as number | '')
|
||||
}
|
||||
>
|
||||
{activeTypes.map((t) => (
|
||||
<MenuItem key={t.id} value={t.id}>
|
||||
{t.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth size="small">
|
||||
<InputLabel>Priorität</InputLabel>
|
||||
<Select
|
||||
value={prioritaet}
|
||||
label="Priorität"
|
||||
onChange={(e: SelectChangeEvent<string>) => setPrioritaet(e.target.value)}
|
||||
>
|
||||
{PRIO_OPTIONS.map((p) => (
|
||||
<MenuItem key={p.value} value={p.value}>
|
||||
{p.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={!titel.trim() || mutation.isPending}
|
||||
fullWidth
|
||||
>
|
||||
{mutation.isPending ? 'Wird erstellt…' : 'Melden'}
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default IssueQuickAddWidget;
|
||||
@@ -20,3 +20,4 @@ export { default as LinksWidget } from './LinksWidget';
|
||||
export { default as WidgetGroup } from './WidgetGroup';
|
||||
export { default as BestellungenWidget } from './BestellungenWidget';
|
||||
export { default as AusruestungsanfrageWidget } from './AusruestungsanfrageWidget';
|
||||
export { default as IssueQuickAddWidget } from './IssueQuickAddWidget';
|
||||
|
||||
Reference in New Issue
Block a user