Files
tickte-system/src/components/CreateTicketModal.jsx
Basilosaurusrex 0e19df6895 woms 3.0
2025-12-29 22:28:43 +01:00

405 lines
14 KiB
JavaScript

import { useState, useEffect } from 'react'
import { FaTimes } from 'react-icons/fa'
import { useAdminConfig } from '../hooks/useAdminConfig'
import { useEmployees } from '../hooks/useEmployees'
// Fallback-Werte falls Config nicht geladen werden kann
const DEFAULT_TICKET_TYPES = [
'Home Office', 'Holidays', 'Trip', 'Supportrequest', 'Change Request',
'Maintenance', 'Project', 'Controlling', 'Development', 'Documentation',
'Meeting/Conference', 'IT Management', 'IT Security', 'Procurement',
'Rollout', 'Emergency Call', 'Other Services'
]
const DEFAULT_SYSTEMS = [
'Account View', 'Client', 'Cofano', 'Credentials', 'Diamant', 'Docuware',
'EDI', 'eMail', 'Employee', 'Invoice', 'LBase', 'Medical Office', 'Network',
'O365', 'PDF Viewer', 'Printer', 'Reports', 'Server', 'Time Tracking',
'TK', 'TOS', 'Vivendi NG', 'VGM', '(W)LAN', '(W)WAN', 'WOMS', 'n/a'
]
const DEFAULT_RESPONSE_LEVELS = [
'USER', 'KEY USER', 'Helpdesk', 'Support', 'Admin', 'FS/FE', '24/7',
'TECH MGMT', 'Backoffice', 'BUSI MGMT', 'n/a'
]
const DEFAULT_SERVICE_TYPES = ['Remote', 'On Site', 'Off Site']
const DEFAULT_PRIORITIES = [
{ value: 0, label: 'None' },
{ value: 1, label: 'Low' },
{ value: 2, label: 'Medium' },
{ value: 3, label: 'High' },
{ value: 4, label: 'Critical' }
]
const today = new Date().toLocaleDateString('de-DE')
export default function CreateTicketModal({ isOpen, onClose, onCreate, customers = [] }) {
const { config } = useAdminConfig()
const { employees } = useEmployees()
// Verwende Config-Werte oder Fallbacks
const TICKET_TYPES = config?.ticketTypes || DEFAULT_TICKET_TYPES
const SYSTEMS = config?.systems || DEFAULT_SYSTEMS
const RESPONSE_LEVELS = config?.responseLevels || DEFAULT_RESPONSE_LEVELS
const SERVICE_TYPES = config?.serviceTypes || DEFAULT_SERVICE_TYPES
const PRIORITIES = config?.priorities || DEFAULT_PRIORITIES
const [formData, setFormData] = useState({
customerId: '',
type: '',
systemType: '',
responseLevel: '',
serviceType: '',
priority: 1,
topic: '',
requestedBy: '',
requestedFor: '',
assignedTo: '', // Zugewiesener Mitarbeiter (User ID)
status: 'Open', // Status wird automatisch gesetzt basierend auf assignedTo
startDate: today,
startTime: '',
deadline: today,
endTime: '',
estimate: '30',
mailCopyTo: '',
sendNotification: false,
details: ''
})
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
// Setze Default-Werte wenn Config geladen ist oder Modal geöffnet wird
useEffect(() => {
if (isOpen && (TICKET_TYPES.length > 0 || SERVICE_TYPES.length > 0)) {
setFormData(prev => ({
...prev,
type: prev.type || TICKET_TYPES[0] || 'Supportrequest',
serviceType: prev.serviceType || SERVICE_TYPES[0] || 'Remote',
priority: prev.priority || (PRIORITIES.find(p => p.value === 1)?.value || 1)
}))
}
// Reset error when modal opens
if (isOpen) {
setError('')
}
}, [isOpen, TICKET_TYPES, SERVICE_TYPES, PRIORITIES])
const handleChange = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }))
// Clear error when user makes changes
if (error) setError('')
}
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
setError('')
try {
const result = await onCreate(formData)
if (result.success) {
onClose()
setFormData({
customerId: '',
type: TICKET_TYPES[0] || 'Supportrequest',
systemType: '',
responseLevel: '',
serviceType: SERVICE_TYPES[0] || 'Remote',
priority: PRIORITIES.find(p => p.value === 1)?.value || 1,
topic: '',
requestedBy: '',
requestedFor: '',
startDate: today,
startTime: '',
deadline: today,
endTime: '',
estimate: '30',
mailCopyTo: '',
sendNotification: false,
details: ''
})
} else {
setError(result.error || 'Fehler beim Erstellen des Tickets')
}
} catch (error) {
console.error('Error creating ticket:', error)
setError(error.message || 'Ein unerwarteter Fehler ist aufgetreten')
} finally {
setLoading(false)
}
}
if (!isOpen) return null
return (
<div className="overlay">
<span className="overlay-close" onClick={onClose}>
<FaTimes />
</span>
<div className="overlay-content">
<h2 className="mb-2">Create New Ticket</h2>
{error && (
<div className="bg-red text-white p-2 mb-2" style={{ borderRadius: '4px' }}>
{error}
</div>
)}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col col-6">
<div className="form-group">
<label className="form-label">Customer ID</label>
<select
className="form-control"
value={formData.customerId}
onChange={(e) => handleChange('customerId', e.target.value)}
required
>
<option value="">Affected Customer</option>
{customers.map(c => (
<option key={c.$id} value={c.$id}>({c.code || ''}) {c.name || 'Unnamed'}</option>
))}
</select>
</div>
<div className="form-group">
<label className="form-label">Work Order Type</label>
<select
className="form-control"
value={formData.type}
onChange={(e) => handleChange('type', e.target.value)}
>
{TICKET_TYPES.map(type => (
<option key={type} value={type}>{type}</option>
))}
</select>
</div>
<div className="form-group">
<label className="form-label">Affected System</label>
<select
className="form-control"
value={formData.systemType}
onChange={(e) => handleChange('systemType', e.target.value)}
required
>
<option value="">Affected System</option>
{SYSTEMS.map(sys => (
<option key={sys} value={sys}>{sys}</option>
))}
</select>
</div>
<div className="form-group">
<label className="form-label">Response Level</label>
<select
className="form-control"
value={formData.responseLevel}
onChange={(e) => handleChange('responseLevel', e.target.value)}
>
<option value="">Response Level</option>
{RESPONSE_LEVELS.map(level => (
<option key={level} value={level}>{level}</option>
))}
</select>
</div>
<div className="form-group">
<label className="form-label">Service Type</label>
<select
className="form-control"
value={formData.serviceType}
onChange={(e) => handleChange('serviceType', e.target.value)}
>
{SERVICE_TYPES.map(type => (
<option key={type} value={type}>{type}</option>
))}
</select>
</div>
<div className="form-group">
<label className="form-label">Priority</label>
<select
className="form-control"
value={formData.priority}
onChange={(e) => handleChange('priority', parseInt(e.target.value))}
required
>
<option value="">Priority Level</option>
{PRIORITIES.map(p => (
<option key={p.value} value={p.value}>{p.label}</option>
))}
</select>
</div>
<div className="form-group">
<label className="form-label">Assigned To</label>
<select
className="form-control"
value={formData.assignedTo}
onChange={(e) => {
const userId = e.target.value
handleChange('assignedTo', userId)
// Status-Automatik: Wenn Mitarbeiter zugewiesen → Status = "Assigned"
// Wenn kein Mitarbeiter → Status = "Open"
if (userId) {
handleChange('status', 'Assigned')
} else {
handleChange('status', 'Open')
}
}}
>
<option value="">Unassigned</option>
{employees.map(emp => (
<option key={emp.$id} value={emp.userId}>
{emp.displayName}{emp.shortcode ? ` (${emp.shortcode})` : ''}
</option>
))}
</select>
</div>
</div>
<div className="col col-6">
<div className="form-group">
<label className="form-label">Topic</label>
<input
type="text"
className="form-control"
placeholder="Topic"
value={formData.topic}
onChange={(e) => handleChange('topic', e.target.value)}
required
/>
</div>
<div className="form-group">
<label className="form-label">Requested by</label>
<input
type="text"
className="form-control"
placeholder="Name"
value={formData.requestedBy}
onChange={(e) => handleChange('requestedBy', e.target.value)}
required
/>
</div>
<div className="form-group">
<label className="form-label">Requested for</label>
<input
type="text"
className="form-control"
placeholder="Name"
value={formData.requestedFor}
onChange={(e) => handleChange('requestedFor', e.target.value)}
/>
</div>
<div className="form-group">
<label className="form-label">Start Date & Time</label>
<div style={{ display: 'flex', gap: '8px' }}>
<input
type="text"
className="form-control"
placeholder="dd.mm.yyyy"
value={formData.startDate}
onChange={(e) => handleChange('startDate', e.target.value)}
style={{ flex: 1 }}
/>
<input
type="text"
className="form-control"
placeholder="hhmm"
value={formData.startTime}
onChange={(e) => handleChange('startTime', e.target.value)}
style={{ flex: 1 }}
/>
</div>
</div>
<div className="form-group">
<label className="form-label">End Date & Time (Deadline)</label>
<div style={{ display: 'flex', gap: '8px' }}>
<input
type="text"
className="form-control"
placeholder="dd.mm.yyyy"
value={formData.deadline}
onChange={(e) => handleChange('deadline', e.target.value)}
style={{ flex: 1 }}
/>
<input
type="text"
className="form-control"
placeholder="hhmm"
value={formData.endTime}
onChange={(e) => handleChange('endTime', e.target.value)}
style={{ flex: 1 }}
/>
</div>
</div>
<div className="form-group">
<label className="form-label">Workload Estimate</label>
<input
type="text"
className="form-control"
placeholder="xx minutes"
value={formData.estimate}
onChange={(e) => handleChange('estimate', e.target.value)}
/>
</div>
<div className="form-group">
<label className="form-label">Notification Recipient(s)</label>
<input
type="text"
className="form-control"
placeholder="name@domain.xx"
value={formData.mailCopyTo}
onChange={(e) => handleChange('mailCopyTo', e.target.value)}
/>
</div>
<div className="form-group">
<label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<input
type="checkbox"
checked={formData.sendNotification}
onChange={(e) => handleChange('sendNotification', e.target.checked)}
/>
Send Notification?
</label>
</div>
</div>
</div>
<div className="form-group">
<label className="form-label">Details</label>
<textarea
className="form-control"
rows={5}
placeholder="Details"
value={formData.details}
onChange={(e) => handleChange('details', e.target.value)}
/>
</div>
<div className="text-center mt-2">
<button
type="submit"
className="btn btn-dark"
disabled={loading}
>
{loading ? 'Creating...' : 'CREATE NOW'}
</button>
</div>
</form>
</div>
</div>
)
}