a ticket must be assigned to someone when creating

This commit is contained in:
Yinyin Liu 2026-04-14 13:35:53 +02:00
parent b8d67f7926
commit 52c9a42e42
6 changed files with 71 additions and 7 deletions

View File

@ -19,7 +19,7 @@ import {
Typography Typography
} from '@mui/material'; } from '@mui/material';
import AttachFileIcon from '@mui/icons-material/AttachFile'; import AttachFileIcon from '@mui/icons-material/AttachFile';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
import axiosConfig from 'src/Resources/axiosConfig'; import axiosConfig from 'src/Resources/axiosConfig';
import { import {
TicketPriority, TicketPriority,
@ -28,7 +28,8 @@ import {
subCategoryLabels, subCategoryLabels,
subCategoriesByCategory, subCategoriesByCategory,
categoryLabels, categoryLabels,
otherSubCategoryValues otherSubCategoryValues,
AdminUser
} from 'src/interfaces/TicketTypes'; } from 'src/interfaces/TicketTypes';
type Installation = { type Installation = {
@ -65,6 +66,7 @@ interface Props {
} }
function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }: Props) { function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }: Props) {
const intl = useIntl();
const [subject, setSubject] = useState(''); const [subject, setSubject] = useState('');
const [selectedProduct, setSelectedProduct] = useState<number | ''>(''); const [selectedProduct, setSelectedProduct] = useState<number | ''>('');
const [selectedDevice, setSelectedDevice] = useState<number | ''>(''); const [selectedDevice, setSelectedDevice] = useState<number | ''>('');
@ -73,6 +75,8 @@ function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }:
useState<Installation | null>(null); useState<Installation | null>(null);
const [loadingInstallations, setLoadingInstallations] = useState(false); const [loadingInstallations, setLoadingInstallations] = useState(false);
const [priority, setPriority] = useState<number>(TicketPriority.Medium); const [priority, setPriority] = useState<number>(TicketPriority.Medium);
const [assigneeId, setAssigneeId] = useState<number | ''>('');
const [adminUsers, setAdminUsers] = useState<AdminUser[]>([]);
const [category, setCategory] = useState<number>(TicketCategory.Hardware); const [category, setCategory] = useState<number>(TicketCategory.Hardware);
const [subCategory, setSubCategory] = useState<number>( const [subCategory, setSubCategory] = useState<number>(
TicketSubCategory.Battery TicketSubCategory.Battery
@ -189,6 +193,16 @@ function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }:
.finally(() => setLoadingInstallations(false)); .finally(() => setLoadingInstallations(false));
}, [selectedProduct]); }, [selectedProduct]);
useEffect(() => {
if (!open) return;
axiosConfig
.get('/GetAdminUsers')
.then((res) => {
if (Array.isArray(res.data)) setAdminUsers(res.data);
})
.catch(() => setAdminUsers([]));
}, [open]);
useEffect(() => { useEffect(() => {
if (defaultInstallationId == null || !open) return; if (defaultInstallationId == null || !open) return;
axiosConfig axiosConfig
@ -233,6 +247,7 @@ function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }:
setAllInstallations([]); setAllInstallations([]);
setSelectedInstallation(null); setSelectedInstallation(null);
setPriority(TicketPriority.Medium); setPriority(TicketPriority.Medium);
setAssigneeId('');
setCategory(TicketCategory.Hardware); setCategory(TicketCategory.Hardware);
setSubCategory(TicketSubCategory.Battery); setSubCategory(TicketSubCategory.Battery);
setDescription(''); setDescription('');
@ -244,6 +259,15 @@ function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }:
const handleSubmit = async () => { const handleSubmit = async () => {
if (!subject.trim()) return; if (!subject.trim()) return;
if (assigneeId === '') {
setError(
intl.formatMessage({
id: 'assigneeRequired',
defaultMessage: 'Please assign this ticket to someone before creating it.'
})
);
return;
}
setSubmitting(true); setSubmitting(true);
setError(''); setError('');
@ -253,6 +277,7 @@ function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }:
description, description,
installationId: selectedInstallation?.id ?? null, installationId: selectedInstallation?.id ?? null,
priority, priority,
assigneeId,
category, category,
subCategory: isOtherCategory ? 0 : subCategory, subCategory: isOtherCategory ? 0 : subCategory,
customSubCategory: (isOtherSubCategory || isOtherCategory) ? customSubCategory || null : null, customSubCategory: (isOtherSubCategory || isOtherCategory) ? customSubCategory || null : null,
@ -390,6 +415,33 @@ function CreateTicketModal({ open, onClose, onCreated, defaultInstallationId }:
)} )}
/> />
<FormControl fullWidth margin="dense" required error={assigneeId === ''}>
<InputLabel>
<FormattedMessage id="assignee" defaultMessage="Assignee" />
</InputLabel>
<Select
value={assigneeId}
label="Assignee"
onChange={(e) =>
setAssigneeId(e.target.value === '' ? '' : Number(e.target.value))
}
>
{adminUsers
.filter((u) => {
const name = (u.name ?? '').toLowerCase();
return (
!name.includes('inesco energy master admin') &&
!name.includes('paal myhre')
);
})
.map((u) => (
<MenuItem key={u.id} value={u.id}>
{u.name}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl fullWidth margin="dense"> <FormControl fullWidth margin="dense">
<InputLabel> <InputLabel>
<FormattedMessage id="priority" defaultMessage="Priority" /> <FormattedMessage id="priority" defaultMessage="Priority" />

View File

@ -591,7 +591,15 @@ function TicketDetailPage() {
/> />
</em> </em>
</MenuItem> </MenuItem>
{adminUsers.map((u) => ( {adminUsers
.filter((u) => {
const name = (u.name ?? '').toLowerCase();
return (
!name.includes('inesco energy master admin') &&
!name.includes('paal myhre')
);
})
.map((u) => (
<MenuItem key={u.id} value={u.id}> <MenuItem key={u.id} value={u.id}>
{u.name} {u.name}
</MenuItem> </MenuItem>

View File

@ -574,6 +574,7 @@
"resolvedAt": "Gelöst", "resolvedAt": "Gelöst",
"noDescription": "Keine Beschreibung vorhanden.", "noDescription": "Keine Beschreibung vorhanden.",
"assignee": "Zuständig", "assignee": "Zuständig",
"assigneeRequired": "Bitte weisen Sie dieses Ticket jemandem zu, bevor Sie es erstellen.",
"unassigned": "Nicht zugewiesen", "unassigned": "Nicht zugewiesen",
"deleteTicket": "Löschen", "deleteTicket": "Löschen",
"confirmDeleteTicket": "Ticket löschen?", "confirmDeleteTicket": "Ticket löschen?",

View File

@ -322,6 +322,7 @@
"resolvedAt": "Resolved", "resolvedAt": "Resolved",
"noDescription": "No description provided.", "noDescription": "No description provided.",
"assignee": "Assignee", "assignee": "Assignee",
"assigneeRequired": "Please assign this ticket to someone before creating it.",
"unassigned": "Unassigned", "unassigned": "Unassigned",
"deleteTicket": "Delete", "deleteTicket": "Delete",
"confirmDeleteTicket": "Delete Ticket?", "confirmDeleteTicket": "Delete Ticket?",

View File

@ -574,6 +574,7 @@
"resolvedAt": "Résolu", "resolvedAt": "Résolu",
"noDescription": "Aucune description fournie.", "noDescription": "Aucune description fournie.",
"assignee": "Responsable", "assignee": "Responsable",
"assigneeRequired": "Veuillez assigner ce ticket à quelqu'un avant de le créer.",
"unassigned": "Non assigné", "unassigned": "Non assigné",
"deleteTicket": "Supprimer", "deleteTicket": "Supprimer",
"confirmDeleteTicket": "Supprimer le ticket ?", "confirmDeleteTicket": "Supprimer le ticket ?",

View File

@ -574,6 +574,7 @@
"resolvedAt": "Risolto", "resolvedAt": "Risolto",
"noDescription": "Nessuna descrizione fornita.", "noDescription": "Nessuna descrizione fornita.",
"assignee": "Assegnatario", "assignee": "Assegnatario",
"assigneeRequired": "Assegna questo ticket a qualcuno prima di crearlo.",
"unassigned": "Non assegnato", "unassigned": "Non assegnato",
"deleteTicket": "Elimina", "deleteTicket": "Elimina",
"confirmDeleteTicket": "Eliminare il ticket?", "confirmDeleteTicket": "Eliminare il ticket?",