diff --git a/backend/src/controllers/shiftTemplateController.ts b/backend/src/controllers/shiftTemplateController.ts index 3c1e573..611add9 100644 --- a/backend/src/controllers/shiftTemplateController.ts +++ b/backend/src/controllers/shiftTemplateController.ts @@ -86,6 +86,57 @@ export const getTemplate = async (req: Request, res: Response): Promise => } }; +export const createDefaultTemplate = async (userId: string): Promise => { + try { + const templateId = uuidv4(); + + await db.run('BEGIN TRANSACTION'); + + try { + // Erstelle die Standard-Vorlage + await db.run( + `INSERT INTO shift_templates (id, name, description, is_default, created_by) + VALUES (?, ?, ?, ?, ?)`, + [templateId, 'Standardwoche', 'Mo-Do: 2 Schichten, Fr: 1 Schicht', true, userId] + ); + + // Vormittagsschicht Mo-Do + for (let day = 1; day <= 4; day++) { + await db.run( + `INSERT INTO template_shifts (id, template_id, day_of_week, name, start_time, end_time, required_employees) + VALUES (?, ?, ?, ?, ?, ?, ?)`, + [uuidv4(), templateId, day, 'Vormittagsschicht', '08:00', '12:00', 1] + ); + } + + // Nachmittagsschicht Mo-Do + for (let day = 1; day <= 4; day++) { + await db.run( + `INSERT INTO template_shifts (id, template_id, day_of_week, name, start_time, end_time, required_employees) + VALUES (?, ?, ?, ?, ?, ?, ?)`, + [uuidv4(), templateId, day, 'Nachmittagsschicht', '11:30', '15:30', 1] + ); + } + + // Freitag nur Vormittagsschicht + await db.run( + `INSERT INTO template_shifts (id, template_id, day_of_week, name, start_time, end_time, required_employees) + VALUES (?, ?, ?, ?, ?, ?, ?)`, + [uuidv4(), templateId, 5, 'Vormittagsschicht', '08:00', '12:00', 1] + ); + + await db.run('COMMIT'); + return templateId; + } catch (error) { + await db.run('ROLLBACK'); + throw error; + } + } catch (error) { + console.error('Error creating default template:', error); + throw error; + } +}; + export const createTemplate = async (req: Request, res: Response): Promise => { try { const { name, description, isDefault, shifts }: CreateShiftTemplateRequest = req.body; @@ -96,6 +147,12 @@ export const createTemplate = async (req: Request, res: Response): Promise return; } + // Wenn diese Vorlage als Standard markiert werden soll, + // zuerst alle anderen Vorlagen auf nicht-Standard setzen + if (isDefault) { + await db.run('UPDATE shift_templates SET is_default = 0'); + } + const templateId = uuidv4(); // Start transaction @@ -182,6 +239,12 @@ export const updateTemplate = async (req: Request, res: Response): Promise await db.run('BEGIN TRANSACTION'); try { + // Wenn diese Vorlage als Standard markiert werden soll, + // zuerst alle anderen Vorlagen auf nicht-Standard setzen + if (isDefault) { + await db.run('UPDATE shift_templates SET is_default = 0'); + } + // Update template if (name !== undefined || description !== undefined || isDefault !== undefined) { await db.run( diff --git a/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.module.css b/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.module.css new file mode 100644 index 0000000..cf20b31 --- /dev/null +++ b/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.module.css @@ -0,0 +1,97 @@ +.editorContainer { + padding: 20px; +} + +.header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30px; +} + +.title { + font-size: 24px; + color: #2c3e50; + margin: 0; +} + +.buttons { + display: flex; + gap: 10px; +} + +.previewButton { + padding: 8px 16px; + background-color: #3498db; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} + +.previewButton:hover { + background-color: #2980b9; +} + +.saveButton { + padding: 8px 16px; + background-color: #2ecc71; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} + +.saveButton:hover { + background-color: #27ae60; +} + +.formGroup { + margin-bottom: 20px; +} + +.formGroup label { + display: block; + margin-bottom: 8px; + color: #34495e; + font-weight: 500; +} + +.formGroup input[type="text"], +.formGroup textarea { + width: 100%; + padding: 8px 12px; + border: 1px solid #bdc3c7; + border-radius: 4px; + font-size: 14px; +} + +.formGroup textarea { + min-height: 100px; + resize: vertical; +} + +.defaultCheckbox { + margin-top: 15px; + display: flex; + align-items: center; + gap: 8px; +} + +.defaultCheckbox input[type="checkbox"] { + width: 16px; + height: 16px; +} + +.defaultCheckbox label { + margin: 0; + font-size: 14px; +} + +.previewContainer { + margin-top: 30px; + border-top: 1px solid #ddd; + padding-top: 20px; +} \ No newline at end of file diff --git a/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.tsx b/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.tsx index b319866..1c49f94 100644 --- a/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.tsx +++ b/frontend/src/pages/ShiftTemplates/ShiftTemplateEditor.tsx @@ -4,8 +4,15 @@ import { useParams, useNavigate } from 'react-router-dom'; import { ShiftTemplate, TemplateShift, DEFAULT_DAYS } from '../../types/shiftTemplate'; import { shiftTemplateService } from '../../services/shiftTemplateService'; import ShiftDayEditor from './components/ShiftDayEditor'; +import DefaultTemplateView from './components/DefaultTemplateView'; +import styles from './ShiftTemplateEditor.module.css'; -const defaultShift: Omit = { +interface ExtendedTemplateShift extends Omit { + id?: string; + isPreview?: boolean; +} + +const defaultShift: ExtendedTemplateShift = { dayOfWeek: 1, // Montag name: '', startTime: '08:00', @@ -27,6 +34,7 @@ const ShiftTemplateEditor: React.FC = () => { }); const [loading, setLoading] = useState(isEditing); const [saving, setSaving] = useState(false); + const [showPreview, setShowPreview] = useState(false); useEffect(() => { if (isEditing) { @@ -104,84 +112,93 @@ const ShiftTemplateEditor: React.FC = () => { })); }; + // Preview-Daten für die DefaultTemplateView vorbereiten + const previewTemplate: ShiftTemplate = { + id: 'preview', + name: template.name || 'Vorschau', + description: template.description, + shifts: template.shifts.map(shift => ({ + ...shift, + id: shift.id || 'preview-' + Date.now() + })), + createdBy: 'preview', + createdAt: new Date().toISOString(), + isDefault: template.isDefault + }; + if (loading) return
Lade Vorlage...
; return ( -
-
-

{isEditing ? 'Vorlage bearbeiten' : 'Neue Vorlage erstellen'}

-
+
+
+

{isEditing ? 'Vorlage bearbeiten' : 'Neue Vorlage erstellen'}

+
- {/* Template Meta Information */} -
-
- - setTemplate(prev => ({ ...prev, name: e.target.value }))} - style={{ width: '100%', padding: '8px', border: '1px solid #ccc', borderRadius: '4px' }} - placeholder="z.B. Standard Woche, Teilzeit Modell, etc." - /> -
+ {showPreview ? ( + + ) : ( + <> +
+ + setTemplate(prev => ({ ...prev, name: e.target.value }))} + placeholder="z.B. Standard Woche, Teilzeit Modell, etc." + /> +
-
- -