From f6e19bc1ed3217335669342de04afe1d5642125a Mon Sep 17 00:00:00 2001 From: donpat1to Date: Wed, 5 Nov 2025 14:18:18 +0100 Subject: [PATCH] added dropdown menu --- .../src/pages/ShiftPlans/ShiftPlanCreate.tsx | 42 +- .../src/pages/ShiftPlans/ShiftPlanView.tsx | 905 +++++++++++++++--- 2 files changed, 790 insertions(+), 157 deletions(-) diff --git a/frontend/src/pages/ShiftPlans/ShiftPlanCreate.tsx b/frontend/src/pages/ShiftPlans/ShiftPlanCreate.tsx index 9b05399..3297fd5 100644 --- a/frontend/src/pages/ShiftPlans/ShiftPlanCreate.tsx +++ b/frontend/src/pages/ShiftPlans/ShiftPlanCreate.tsx @@ -18,7 +18,7 @@ const ShiftPlanCreate: React.FC = () => { const [searchParams] = useSearchParams(); const { showNotification } = useNotification(); const { executeWithValidation, isSubmitting } = useBackendValidation(); - + const [planName, setPlanName] = useState(''); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); @@ -35,9 +35,9 @@ const ShiftPlanCreate: React.FC = () => { console.log('🔄 Lade verfügbare Vorlagen-Presets...'); const data = await shiftPlanService.getTemplatePresets(); console.log('✅ Presets geladen:', data); - + setPresets(data); - + // Setze das erste Preset als Standard, falls vorhanden if (data.length > 0) { setSelectedPreset(data[0].name); @@ -75,7 +75,7 @@ const ShiftPlanCreate: React.FC = () => { if (!endDate) { showNotification({ type: 'error', - title: 'Fehlende Angaben', + title: 'Fehlende Angaben', message: 'Bitte wählen Sie ein Enddatum' }); return; @@ -115,14 +115,14 @@ const ShiftPlanCreate: React.FC = () => { }); console.log('✅ Plan erstellt:', createdPlan); - + // Erfolgsmeldung und Weiterleitung showNotification({ type: 'success', title: 'Erfolg', message: 'Schichtplan erfolgreich erstellt!' }); - + setTimeout(() => { navigate(`/shift-plans/${createdPlan.id}`); }, 1500); @@ -146,20 +146,20 @@ const ShiftPlanCreate: React.FC = () => {

Neuen Schichtplan erstellen

-
- +
- setPlanName(e.target.value)} placeholder="z.B. KW 42 2025" @@ -171,8 +171,8 @@ const ShiftPlanCreate: React.FC = () => {
- setStartDate(e.target.value)} className={styles.input} @@ -182,8 +182,8 @@ const ShiftPlanCreate: React.FC = () => {
- setEndDate(e.target.value)} className={styles.input} @@ -194,8 +194,8 @@ const ShiftPlanCreate: React.FC = () => {
- - + {selectedPreset && (
{getSelectedPresetDescription()} @@ -222,9 +222,9 @@ const ShiftPlanCreate: React.FC = () => {
-
- - {/* Export Dropdown - Only show when plan is published */} - {shiftPlan?.status === 'published' && ( -
-
- {/* Export Dropdown - Always visible but moves when option selected */} -
- -
- - {/* Export Button - Only shows when an export type is selected */} - {selectedExportType && ( -
- - -
- )} -
-
- )}
); }; - // ... (rest of the component remains the same, including all the other functions) - if (loading) return
Lade Schichtplan...
; if (!shiftPlan) return
Schichtplan nicht gefunden
; @@ -841,7 +1142,280 @@ const ShiftPlanView: React.FC = () => {
- {/* ... (rest of the JSX remains the same) */} + {/* Availability Status - only show for drafts */} + {shiftPlan.status === 'draft' && ( +
+

Veröffentlichungsvoraussetzungen

+
+
+
+ Verfügbarkeitseinträge: +
+
+ {availabilityStatus.completed} / {availabilityStatus.total} Mitarbeiter +
+
+
+
+
+ + {hasRole(['admin', 'maintenance']) && ( +
+ + + {!canPublish() && ( +
+ {availabilityStatus.percentage === 100 + ? 'Bereit zur Berechnung' + : `${availabilityStatus.total - availabilityStatus.completed} Mitarbeiter müssen noch Verfügbarkeit eintragen`} +
+ )} +
+ )} +
+ + {/* Plan Structure Info */} +
+ Plan-Struktur: {allTimeSlots.length} Schichttypen an {days.length} Tagen +
+
+ )} + + {/* Assignment Preview Modal */} + {(showAssignmentPreview || assignmentResult) && ( +
+
+

Wochenmuster-Zuordnung

+ + {/* Detaillierter Reparatur-Bericht anzeigen */} + {assignmentResult?.resolutionReport && ( +
+

+ 📋 Detaillierter Reparatur-Bericht +

+
+ {assignmentResult.resolutionReport.map((line, index) => { + let color = '#2c3e50'; + let fontWeight = 'normal'; + + if (line.includes('✅') || line.includes('ALLES KRITISCHEN PROBLEME BEHOBEN')) { + color = '#2ecc71'; + fontWeight = 'bold'; + } else if (line.includes('❌') || line.includes('KRITISCHEN PROBLEME')) { + color = '#e74c3c'; + fontWeight = 'bold'; + } else if (line.includes('⚠️')) { + color = '#f39c12'; + } else if (line.includes('📊') || line.includes('🔧') || line.includes('📅') || line.includes('🚨') || line.includes('🛠️') || line.includes('💡') || line.includes('🎯')) { + color = '#3498db'; + fontWeight = 'bold'; + } else if (line.startsWith(' •') || line.startsWith(' -')) { + color = '#7f8c8d'; + } + + return ( +
+ {line} +
+ ); + })} +
+
+ )} + + {/* ZUSAMMENFASSUNG */} + {assignmentResult && ( +
+

Zusammenfassung:

+ + {/* Entscheidung basierend auf tatsächlichen kritischen Problemen */} + {(assignmentResult.violations.length === 0) || assignmentResult.success == true ? ( +
+
✅ Bereit zur Veröffentlichung
+

+ Alle kritischen Probleme wurden behoben. Der Schichtplan kann veröffentlicht werden. +

+
+ ) : ( +
+
❌ Kritische Probleme
+

+ Folgende kritische Probleme müssen behoben werden, bevor der Plan veröffentlicht werden kann: +

+
    + {assignmentResult.violations + .filter(v => v.includes('ERROR:') || v.includes('❌ KRITISCH:')) + .map((violation, index) => ( +
  • + {violation.replace('ERROR: ', '').replace('❌ KRITISCH: ', '')} +
  • + ))} +
+
+ )} + + {/* Warnungen separat anzeigen - NUR wenn welche vorhanden sind */} + {assignmentResult.violations.some(v => v.includes('WARNING:') || v.includes('⚠️')) && ( +
+
+ ⚠️ Hinweise & Warnungen +
+
    + {assignmentResult.violations + .filter(v => v.includes('WARNING:') || v.includes('⚠️')) + .map((warning, index) => ( +
  • + {warning.replace('WARNING: ', '').replace('⚠️ WARNHINWEIS: ', '')} +
  • + ))} +
+
+ )} +
+ )} + +
+ + + {/* BUTTON zum publishen */} + +
+
+
+ )} {/* Timetable */}
{ {renderTimetable()} + {shiftPlan.status === 'published' && hasRole(['admin', 'maintenance']) && ( +
+ {/* Export Dropdown */} +
+ +
+ + {/* Export Button */} + {exportType && ( + + )} +
+ )} + {/* Summary */} {days.length > 0 && (