+ {/* Gesamtübersicht */}
+
+
+
+ Gesamtübersicht
+
+
+
-
-
-
- Gesamtübersicht
-
-
-
- Worksheets:
- {worksheets.length}
-
-
- Arbeitszeit:
- {formatTime(totalMinutes)}
-
-
- Kommentare:
- {worksheets.filter(ws => ws.isComment).length}
-
-
- Ø pro Worksheet:
-
- {formatTime(Math.round(totalMinutes / (worksheets.filter(ws => !ws.isComment).length || 1)))}
-
-
-
-
+
Worksheets:
+
{worksheets.length}
-
-
- {/* Nach Mitarbeiter */}
-
-
-
-
-
- Nach Mitarbeiter
-
-
- {Object.values(byEmployee).map((emp, idx) => (
-
-
-
- {emp.name}
- {emp.short && (
- {emp.short}
- )}
-
-
-
{formatTime(emp.time)}
-
{emp.count} WS
-
-
-
- ))}
-
-
+
Arbeitszeit:
+
{formatTime(totalMinutes)}
-
-
- {/* Service Type Verteilung */}
-
-
-
-
-
- Service Types
-
-
- {Object.entries(byServiceType).map(([type, count], idx) => (
-
- {type}
- {count}
-
- ))}
-
-
+
Kommentare:
+
{worksheets.filter(ws => ws.isComment).length}
+
+
+ Ø pro WS:
+
+ {formatTime(Math.round(totalMinutes / (worksheets.filter(ws => !ws.isComment).length || 1)))}
+
- {/* Status-Historie */}
- {statusHistory.length > 0 && (
-
+
-
-
-
- Status-Historie
-
-
-
-
-
- | Datum |
- Zeit |
- Von |
- |
- Nach |
- Mitarbeiter |
-
-
-
- {statusHistory.reverse().map((change, idx) => (
-
- | {change.date} |
- {formatTimeShort(change.time)} |
-
- {change.from}
- |
- → |
-
- {change.to}
- |
- {change.employee} |
-
- ))}
-
-
-
+
+ Mitarbeiter-Statistiken
+
+
+ {Object.keys(byEmployee).length === 0 ? (
+
+ Keine Mitarbeiter-Daten verfügbar
+ ) : (
+
+ {(() => {
+ const employeeArray = Object.values(byEmployee).sort((a, b) => b.time - a.time)
+ const maxTime = Math.max(...employeeArray.map(e => e.time), 1)
+
+ return employeeArray.map((emp, idx) => {
+ const percentage = maxTime > 0 ? (emp.time / maxTime) * 100 : 0
+ return (
+
+
+
+ {emp.short && (
+ {emp.short}
+ )}
+
+ {emp.name}
+
+
+
+
+ {/* WS Anzahl am Anfang */}
+
+ WS
+ {emp.count}
+
+
+ {/* Balken mit Zeit */}
+
+ {/* Zeit am Ende des Balkens */}
+
+ {formatTime(emp.time)}
+
+
+
+ {/* Zeit außerhalb des Balkens (falls Balken zu kurz) */}
+ {percentage < 30 && (
+
+ {formatTime(emp.time)}
+
+ )}
+
+
+ )
+ })
+ })()}
+
+ )}
+
+
+ {/* Service Type Verteilung */}
+
+
+
+ Service Types
+
+
+ {Object.entries(byServiceType).map(([type, count]) => (
+
+ {type}
+ {count}
+
+ ))}
- )}
+
)
}
diff --git a/src/hooks/useWorkorders.js b/src/hooks/useWorkorders.js
index 3b31a5b..7e443fc 100644
--- a/src/hooks/useWorkorders.js
+++ b/src/hooks/useWorkorders.js
@@ -4,8 +4,61 @@ import { databases, DATABASE_ID, COLLECTIONS, Query, ID } from '../lib/appwrite'
const DEMO_MODE = !import.meta.env.VITE_APPWRITE_PROJECT_ID
// Demo data for testing without Appwrite
+const lastWeek = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
+
const DEMO_WORKORDERS = [
- { $id: '1', woid: '10001', title: 'Server Wartung', description: 'Monatliche Wartung', status: 'Open', priority: 2, type: 'Maintenance', customerName: 'Kunde A', assignedName: 'Max M.', response: 'Onsite', $createdAt: new Date().toISOString() },
+ {
+ $id: 'dummy-10001',
+ woid: '10001',
+ topic: 'Kompletter Systemausfall - Server & Netzwerk',
+ status: 'Assigned',
+ priority: 4,
+ type: 'Emergency Call',
+ systemType: 'Server',
+ responseLevel: 'Backoffice',
+ serviceType: 'On Site',
+ customerName: 'Kunde A',
+ customerLocation: 'Hauptstraße 123, 12345 Musterstadt',
+ assignedTo: 'user-max-id',
+ assignedName: 'Max Mustermann',
+ requestedBy: 'Dr. Anna Schmidt',
+ requestedFor: 'IT-Abteilung Kunde A',
+ startDate: '30.12.2025',
+ startTime: '0800',
+ deadline: '31.12.2025',
+ endTime: '1800',
+ estimate: '480',
+ mailCopyTo: 'admin@kunde-a.de, it@kunde-a.de',
+ sendNotification: true,
+ details: `KRITISCHER SYSTEMAUSFALL - SOFORTIGE BEARBEITUNG ERFORDERLICH
+
+Problembeschreibung:
+- Kompletter Serverausfall im Rechenzentrum
+- Alle Server sind offline (keine Verbindung möglich)
+- Netzwerk-Infrastruktur betroffen
+- Keine Backup-Systeme verfügbar
+
+Betroffene Systeme:
+- Hauptserver (Windows Server 2022)
+- Datenbankserver (SQL Server 2019)
+- Fileserver
+- Exchange Server
+- Netzwerk-Switches
+
+Auswirkungen:
+- Keine E-Mail-Kommunikation möglich
+- Alle Anwendungen offline
+- Kein Zugriff auf Datenbanken
+- Produktion steht still
+
+Dringlichkeit: KRITISCH - Produktionsausfall
+
+Erwartete Bearbeitungszeit: 8 Stunden
+Benötigte Ressourcen: 2 Techniker, Hardware-Ersatzteile`,
+ approvalStatus: 'approved',
+ $createdAt: lastWeek.toISOString(),
+ createdAt: lastWeek.toISOString()
+ },
{ $id: '2', woid: '10002', title: 'Netzwerk Problem', description: 'WLAN funktioniert nicht', status: 'Occupied', priority: 3, type: 'Support', customerName: 'Kunde B', assignedName: 'Lisa S.', response: 'Remote', $createdAt: new Date().toISOString() },
{ $id: '3', woid: '10003', title: 'Software Installation', description: 'Office 365 Setup', status: 'Assigned', priority: 1, type: 'Installation', customerName: 'Kunde C', assignedName: 'Tom K.', response: 'Onsite', $createdAt: new Date().toISOString() },
{ $id: '4', woid: '10004', title: 'Drucker defekt', description: 'Papierstau', status: 'Awaiting', priority: 2, type: 'Hardware', customerName: 'Kunde D', assignedName: '', response: 'Pickup', $createdAt: new Date().toISOString() },
diff --git a/src/hooks/useWorksheets.js b/src/hooks/useWorksheets.js
index 4d1ba59..6fa06e7 100644
--- a/src/hooks/useWorksheets.js
+++ b/src/hooks/useWorksheets.js
@@ -3,28 +3,144 @@ import { databases, DATABASE_ID, COLLECTIONS, Query, ID } from '../lib/appwrite'
const DEMO_MODE = !import.meta.env.VITE_APPWRITE_PROJECT_ID
-// Demo data für Testing
+// Demo data für Testing - Vollständiges Dummy-Ticket 10001 mit allen Worksheets
+const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000)
+const twoDaysAgo = new Date(Date.now() - 48 * 60 * 60 * 1000)
+const threeDaysAgo = new Date(Date.now() - 72 * 60 * 60 * 1000)
+
const DEMO_WORKSHEETS = [
{
- $id: '1',
+ $id: 'ws-10001-001',
wsid: '100001',
woid: '10001',
- workorderId: '1',
- employeeId: 'emp1',
- employeeName: 'Max Müller',
- employeeShort: 'MAMU',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-max-id',
+ employeeName: 'Max Mustermann',
+ employeeShort: 'MM',
serviceType: 'Remote',
oldStatus: 'Open',
newStatus: 'Occupied',
+ oldResponseLevel: '',
+ newResponseLevel: '24/7',
totalTime: 30,
- startDate: '29.12.2025',
- startTime: '1000',
- endDate: '29.12.2025',
- endTime: '1030',
- details: 'Router neu gestartet',
+ startDate: '23.12.2025',
+ startTime: '0800',
+ endDate: '23.12.2025',
+ endTime: '0830',
+ details: 'Erste Analyse durchgeführt. Server komplett offline. Keine Remote-Verbindung möglich. Vor-Ort-Einsatz erforderlich.',
isComment: false,
- $createdAt: new Date().toISOString()
+ $createdAt: threeDaysAgo.toISOString()
},
+ {
+ $id: 'ws-10001-002',
+ wsid: '100002',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-lisa-id',
+ employeeName: 'Lisa Schneider',
+ employeeShort: 'LS',
+ serviceType: 'On Site',
+ oldStatus: 'Occupied',
+ newStatus: 'Assigned',
+ oldResponseLevel: '24/7',
+ newResponseLevel: '24/7',
+ totalTime: 120,
+ startDate: '23.12.2025',
+ startTime: '1000',
+ endDate: '23.12.2025',
+ endTime: '1200',
+ details: 'Vor-Ort-Einsatz: Hardware-Check durchgeführt. Netzteil des Hauptservers defekt. Ersatzteil bestellt. Notfall-Backup-Server gestartet.',
+ isComment: false,
+ $createdAt: threeDaysAgo.toISOString()
+ },
+ {
+ $id: 'ws-10001-003',
+ wsid: '100003',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-tom-id',
+ employeeName: 'Tom Klein',
+ employeeShort: 'TK',
+ serviceType: 'On Site',
+ oldStatus: 'Assigned',
+ newStatus: 'Assigned',
+ oldResponseLevel: '24/7',
+ newResponseLevel: '24/7',
+ totalTime: 0,
+ startDate: '24.12.2025',
+ startTime: '1400',
+ endDate: '24.12.2025',
+ endTime: '1400',
+ details: 'Warte auf Ersatzteil-Lieferung. Kunde informiert. Backup-System läuft stabil.',
+ isComment: true,
+ $createdAt: twoDaysAgo.toISOString()
+ },
+ {
+ $id: 'ws-10001-004',
+ wsid: '100004',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-max-id',
+ employeeName: 'Max Mustermann',
+ employeeShort: 'MM',
+ serviceType: 'On Site',
+ oldStatus: 'Assigned',
+ newStatus: 'In Test',
+ oldResponseLevel: '24/7',
+ newResponseLevel: '24/7',
+ totalTime: 180,
+ startDate: '25.12.2025',
+ startTime: '0900',
+ endDate: '25.12.2025',
+ endTime: '1200',
+ details: 'Ersatzteil eingebaut. Server gestartet. Alle Dienste wiederhergestellt. System-Tests durchgeführt. Datenbank-Verbindungen geprüft.',
+ isComment: false,
+ $createdAt: twoDaysAgo.toISOString()
+ },
+ {
+ $id: 'ws-10001-005',
+ wsid: '100005',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-lisa-id',
+ employeeName: 'Lisa Schneider',
+ employeeShort: 'LS',
+ serviceType: 'Remote',
+ oldStatus: 'In Test',
+ newStatus: 'Awaiting',
+ oldResponseLevel: '24/7',
+ newResponseLevel: 'Support',
+ totalTime: 45,
+ startDate: '26.12.2025',
+ startTime: '1000',
+ endDate: '26.12.2025',
+ endTime: '1045',
+ details: 'Remote-Monitoring eingerichtet. Warte auf Kunden-Feedback nach 24h Testphase. Alle Systeme laufen stabil.',
+ isComment: false,
+ $createdAt: yesterday.toISOString()
+ },
+ {
+ $id: 'ws-10001-006',
+ wsid: '100006',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-tom-id',
+ employeeName: 'Tom Klein',
+ employeeShort: 'TK',
+ serviceType: 'COMMENT',
+ oldStatus: 'Awaiting',
+ newStatus: 'Closed',
+ oldResponseLevel: 'Support',
+ newResponseLevel: 'Backoffice',
+ totalTime: 0,
+ startDate: '30.12.2025',
+ startTime: '0900',
+ endDate: '30.12.2025',
+ endTime: '0900',
+ details: 'Kunde bestätigt: Alle Systeme funktionieren einwandfrei. Problem vollständig behoben. Ticket kann geschlossen werden.',
+ isComment: true,
+ $createdAt: new Date().toISOString()
+ }
]
export function useWorksheets(woid = null) {
diff --git a/src/utils/createDummyTicket.js b/src/utils/createDummyTicket.js
new file mode 100644
index 0000000..073271c
--- /dev/null
+++ b/src/utils/createDummyTicket.js
@@ -0,0 +1,231 @@
+/**
+ * Erstellt ein vollständiges Dummy-Ticket mit WOID 10001
+ * Zeigt alle möglichen Funktionen, Felder und Kombinationen
+ */
+
+export function createDummyTicket10001() {
+ const now = new Date()
+ const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000)
+ const lastWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
+
+ // Haupt-Ticket mit allen Feldern ausgefüllt
+ const dummyTicket = {
+ $id: 'dummy-10001',
+ woid: '10001',
+ topic: 'Kompletter Systemausfall - Server & Netzwerk',
+ status: 'Assigned',
+ priority: 4, // Critical
+ type: 'Emergency Call',
+ systemType: 'Server',
+ responseLevel: '24/7',
+ serviceType: 'On Site',
+ customerId: 'customer-a-id',
+ customerName: 'Kunde A',
+ customerLocation: 'Hauptstraße 123, 12345 Musterstadt',
+ assignedTo: 'user-max-id', // Max Mustermann
+ requestedBy: 'Dr. Anna Schmidt',
+ requestedFor: 'IT-Abteilung Kunde A',
+ startDate: '30.12.2025',
+ startTime: '0800',
+ deadline: '31.12.2025',
+ endTime: '1800',
+ estimate: '480',
+ mailCopyTo: 'admin@kunde-a.de, it@kunde-a.de',
+ sendNotification: true,
+ details: `KRITISCHER SYSTEMAUSFALL - SOFORTIGE BEARBEITUNG ERFORDERLICH
+
+Problembeschreibung:
+- Kompletter Serverausfall im Rechenzentrum
+- Alle Server sind offline (keine Verbindung möglich)
+- Netzwerk-Infrastruktur betroffen
+- Keine Backup-Systeme verfügbar
+
+Betroffene Systeme:
+- Hauptserver (Windows Server 2022)
+- Datenbankserver (SQL Server 2019)
+- Fileserver
+- Exchange Server
+- Netzwerk-Switches
+
+Auswirkungen:
+- Keine E-Mail-Kommunikation möglich
+- Alle Anwendungen offline
+- Kein Zugriff auf Datenbanken
+- Produktion steht still
+
+Dringlichkeit: KRITISCH - Produktionsausfall
+
+Erwartete Bearbeitungszeit: 8 Stunden
+Benötigte Ressourcen: 2 Techniker, Hardware-Ersatzteile`,
+ approvalStatus: 'approved',
+ createdAt: lastWeek.toISOString(),
+ $createdAt: lastWeek.toISOString()
+ }
+
+ // Mehrere Worksheets mit verschiedenen Status-Änderungen und Benutzern
+ const dummyWorksheets = [
+ {
+ $id: 'ws-10001-001',
+ wsid: '100001',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-max-id',
+ employeeName: 'Max Mustermann',
+ employeeShort: 'MM',
+ serviceType: 'Remote',
+ oldStatus: 'Open',
+ newStatus: 'Occupied',
+ oldResponseLevel: '',
+ newResponseLevel: '24/7',
+ totalTime: 30,
+ startDate: '23.12.2025',
+ startTime: '0800',
+ endDate: '23.12.2025',
+ endTime: '0830',
+ details: 'Erste Analyse durchgeführt. Server komplett offline. Keine Remote-Verbindung möglich. Vor-Ort-Einsatz erforderlich.',
+ isComment: false,
+ createdAt: yesterday.toISOString(),
+ $createdAt: yesterday.toISOString()
+ },
+ {
+ $id: 'ws-10001-002',
+ wsid: '100002',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-lisa-id',
+ employeeName: 'Lisa Schneider',
+ employeeShort: 'LS',
+ serviceType: 'On Site',
+ oldStatus: 'Occupied',
+ newStatus: 'Assigned',
+ oldResponseLevel: '24/7',
+ newResponseLevel: '24/7',
+ totalTime: 120,
+ startDate: '23.12.2025',
+ startTime: '1000',
+ endDate: '23.12.2025',
+ endTime: '1200',
+ details: 'Vor-Ort-Einsatz: Hardware-Check durchgeführt. Netzteil des Hauptservers defekt. Ersatzteil bestellt. Notfall-Backup-Server gestartet.',
+ isComment: false,
+ createdAt: yesterday.toISOString(),
+ $createdAt: yesterday.toISOString()
+ },
+ {
+ $id: 'ws-10001-003',
+ wsid: '100003',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-tom-id',
+ employeeName: 'Tom Klein',
+ employeeShort: 'TK',
+ serviceType: 'On Site',
+ oldStatus: 'Assigned',
+ newStatus: 'Assigned',
+ oldResponseLevel: '24/7',
+ newResponseLevel: '24/7',
+ totalTime: 0,
+ startDate: '24.12.2025',
+ startTime: '1400',
+ endDate: '24.12.2025',
+ endTime: '1400',
+ details: 'Warte auf Ersatzteil-Lieferung. Kunde informiert. Backup-System läuft stabil.',
+ isComment: true,
+ createdAt: new Date(yesterday.getTime() - 12 * 60 * 60 * 1000).toISOString(),
+ $createdAt: new Date(yesterday.getTime() - 12 * 60 * 60 * 1000).toISOString()
+ },
+ {
+ $id: 'ws-10001-004',
+ wsid: '100004',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-max-id',
+ employeeName: 'Max Mustermann',
+ employeeShort: 'MM',
+ serviceType: 'On Site',
+ oldStatus: 'Assigned',
+ newStatus: 'In Test',
+ oldResponseLevel: '24/7',
+ newResponseLevel: '24/7',
+ totalTime: 180,
+ startDate: '25.12.2025',
+ startTime: '0900',
+ endDate: '25.12.2025',
+ endTime: '1200',
+ details: 'Ersatzteil eingebaut. Server gestartet. Alle Dienste wiederhergestellt. System-Tests durchgeführt. Datenbank-Verbindungen geprüft.',
+ isComment: false,
+ createdAt: new Date(yesterday.getTime() - 24 * 60 * 60 * 1000).toISOString(),
+ $createdAt: new Date(yesterday.getTime() - 24 * 60 * 60 * 1000).toISOString()
+ },
+ {
+ $id: 'ws-10001-005',
+ wsid: '100005',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-lisa-id',
+ employeeName: 'Lisa Schneider',
+ employeeShort: 'LS',
+ serviceType: 'Remote',
+ oldStatus: 'In Test',
+ newStatus: 'Awaiting',
+ oldResponseLevel: '24/7',
+ newResponseLevel: 'Support',
+ totalTime: 45,
+ startDate: '26.12.2025',
+ startTime: '1000',
+ endDate: '26.12.2025',
+ endTime: '1045',
+ details: 'Remote-Monitoring eingerichtet. Warte auf Kunden-Feedback nach 24h Testphase. Alle Systeme laufen stabil.',
+ isComment: false,
+ createdAt: new Date(yesterday.getTime() - 48 * 60 * 60 * 1000).toISOString(),
+ $createdAt: new Date(yesterday.getTime() - 48 * 60 * 60 * 1000).toISOString()
+ },
+ {
+ $id: 'ws-10001-006',
+ wsid: '100006',
+ woid: '10001',
+ workorderId: 'dummy-10001',
+ employeeId: 'user-tom-id',
+ employeeName: 'Tom Klein',
+ employeeShort: 'TK',
+ serviceType: 'COMMENT',
+ oldStatus: 'Awaiting',
+ newStatus: 'Closed',
+ oldResponseLevel: 'Support',
+ newResponseLevel: 'Backoffice',
+ totalTime: 0,
+ startDate: '30.12.2025',
+ startTime: '0900',
+ endDate: '30.12.2025',
+ endTime: '0900',
+ details: 'Kunde bestätigt: Alle Systeme funktionieren einwandfrei. Problem vollständig behoben. Ticket kann geschlossen werden.',
+ isComment: true,
+ createdAt: now.toISOString(),
+ $createdAt: now.toISOString()
+ }
+ ]
+
+ return {
+ ticket: dummyTicket,
+ worksheets: dummyWorksheets
+ }
+}
+
+/**
+ * Fügt das Dummy-Ticket zu den Demo-Daten hinzu
+ */
+export function addDummyTicketToDemo(workorders, worksheets) {
+ const { ticket, worksheets: ticketWorksheets } = createDummyTicket10001()
+
+ // Prüfe ob Ticket bereits existiert
+ const exists = workorders.some(wo => wo.woid === '10001')
+ if (exists) {
+ console.log('Dummy-Ticket 10001 existiert bereits')
+ return { workorders, worksheets }
+ }
+
+ return {
+ workorders: [ticket, ...workorders],
+ worksheets: [...ticketWorksheets, ...worksheets]
+ }
+}
+