diff --git a/src/components/CreateTicketModal.jsx b/src/components/CreateTicketModal.jsx
index 11d3a31..573e268 100644
--- a/src/components/CreateTicketModal.jsx
+++ b/src/components/CreateTicketModal.jsx
@@ -1,30 +1,30 @@
-import { useState, useEffect } from 'react'
+import { useState, useEffect, useMemo } from 'react'
import { FaTimes } from 'react-icons/fa'
import { useAdminConfig } from '../hooks/useAdminConfig'
import { useEmployees } from '../hooks/useEmployees'
+import { databases, DATABASE_ID, COLLECTIONS, Query, isDemoMode } from '../lib/appwrite'
+import {
+ todayIso,
+ isoToGermanDate,
+ timeToWoms,
+ buildRequesterSuggestions,
+ rankSuggestions,
+} from '../lib/ticketForm'
+import { AutocompleteInput } from './ui'
-// Fallback-Werte falls Config nicht geladen werden kann
-const DEFAULT_TICKET_TYPES = [
- 'Akquise', 'Home Office', 'Holidays', 'Trip', 'Supportrequest', 'Change Request',
- 'Maintenance', 'Project', 'Webpage', 'Controlling', 'Development', 'Documentation',
- 'Meeting/Conference', 'IT Management', 'IT Security', 'Procurement',
- 'Rollout', 'Emergency Call', 'Other Services'
+// Neue Tickets gibt es aktuell nur fuer diese Arten; alte Tickets behalten ihre Art.
+// Migration = ein Kunde, den wir von einem anderen Anbieter uebernehmen.
+const TICKET_TYPES = [
+ { value: 'Webpage', label: 'Webpage' },
+ { value: 'Migration', label: 'Migration (Übernahme von anderem Anbieter)' },
]
-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'
+// Gespeichert werden die bisherigen Werte, angezeigt wird Deutsch
+const SERVICE_TYPES = [
+ { value: 'Remote', label: 'Fernwartung (remote)' },
+ { value: 'On Site', label: 'Vor Ort beim Kunden' },
]
-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' },
@@ -33,56 +33,68 @@ const DEFAULT_PRIORITIES = [
{ value: 4, label: 'Critical' }
]
-const today = new Date().toLocaleDateString('de-DE')
+// Datum als "yyyy-mm-dd", Uhrzeit als "hh:mm" (Werte der Kalender-Felder)
+const emptyForm = () => ({
+ customerId: '',
+ type: TICKET_TYPES[0].value,
+ serviceType: SERVICE_TYPES[0].value,
+ priority: 1,
+ topic: '',
+ requestedBy: '',
+ requestedFor: '',
+ startDate: todayIso(),
+ startTime: '',
+ deadline: todayIso(),
+ endTime: '',
+ estimate: '30',
+ details: ''
+})
+
+// Klick irgendwo ins Datumsfeld oeffnet den Kalender, nicht nur das kleine Symbol
+const openCalendar = (e) => {
+ try {
+ e.currentTarget.showPicker?.()
+ } catch {
+ // aeltere Browser: Kalender bleibt ueber das Symbol erreichbar
+ }
+}
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: '',
- startDate: today,
- startTime: '',
- deadline: today,
- endTime: '',
- estimate: '30',
- mailCopyTo: '',
- sendNotification: false,
- details: ''
- })
+ const [formData, setFormData] = useState(emptyForm)
+ const [recentTickets, setRecentTickets] = useState([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
- // Setze Default-Werte wenn Config geladen ist oder Modal geöffnet wird
+ // Reset error when modal opens
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)
- }))
+ if (isOpen) setError('')
+ }, [isOpen])
+
+ // Namen aus den letzten Tickets fuer die Autovervollstaendigung
+ useEffect(() => {
+ if (!isOpen || isDemoMode) return
+ let cancelled = false
+ databases
+ .listDocuments(DATABASE_ID, COLLECTIONS.WORKORDERS, [Query.orderDesc('$createdAt'), Query.limit(200)])
+ .then((response) => {
+ if (!cancelled) setRecentTickets(response.documents || [])
+ })
+ .catch((err) => console.warn('Vorschläge aus früheren Tickets nicht geladen:', err))
+ return () => {
+ cancelled = true
}
- // Reset error when modal opens
- if (isOpen) {
- setError('')
- }
- }, [isOpen, TICKET_TYPES, SERVICE_TYPES, PRIORITIES])
+ }, [isOpen])
+
+ const suggestions = useMemo(
+ () => buildRequesterSuggestions({ customers, employees, tickets: recentTickets }),
+ [customers, employees, recentTickets]
+ )
+ const getSuggestions = (text) => rankSuggestions(suggestions, text, { customerId: formData.customerId })
const handleChange = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }))
@@ -90,34 +102,35 @@ export default function CreateTicketModal({ isOpen, onClose, onCreate, customers
if (error) setError('')
}
+ // Das Ende darf nicht vor dem Start liegen, deshalb rueckt es mit
+ const handleStartDateChange = (value) => {
+ setFormData(prev => ({
+ ...prev,
+ startDate: value,
+ deadline: value && prev.deadline && prev.deadline < value ? value : prev.deadline
+ }))
+ if (error) setError('')
+ }
+
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
setError('')
-
+
+ const customer = customers.find(c => c.$id === formData.customerId)
try {
- const result = await onCreate(formData)
+ const result = await onCreate({
+ ...formData,
+ customerName: customer?.name || '',
+ customerLocation: customer?.location || '',
+ startDate: isoToGermanDate(formData.startDate),
+ startTime: timeToWoms(formData.startTime),
+ deadline: isoToGermanDate(formData.deadline),
+ endTime: timeToWoms(formData.endTime)
+ })
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: ''
- })
+ setFormData(emptyForm())
} else {
setError(result.error || 'Fehler beim Erstellen des Tickets')
}
@@ -138,13 +151,13 @@ export default function CreateTicketModal({ isOpen, onClose, onCreate, customers
Create New Ticket
-
+
{error && (
{error}
)}
-
+
-
-
Requested by
+
handleChange('requestedBy', e.target.value)}
+ onChange={(value) => handleChange('requestedBy', value)}
+ getSuggestions={getSuggestions}
required
/>
-
-
Requested for
+
handleChange('requestedFor', e.target.value)}
+ onChange={(value) => handleChange('requestedFor', value)}
+ getSuggestions={getSuggestions}
/>
-
-
-
-
@@ -333,28 +316,6 @@ export default function CreateTicketModal({ isOpen, onClose, onCreate, customers
onChange={(e) => handleChange('estimate', e.target.value)}
/>
-
-
-
- handleChange('mailCopyTo', e.target.value)}
- />
-
-
-
-
-
@@ -370,8 +331,8 @@ export default function CreateTicketModal({ isOpen, onClose, onCreate, customers
-