mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-12-01 06:55:45 +01:00
creating plan possible
This commit is contained in:
@@ -681,33 +681,53 @@ async function generateScheduledShifts(planId: string, startDate: string, endDat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*export const getTemplates = async (req: Request, res: Response): Promise<void> => {
|
export const revertToDraft = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
console.log('🔍 Lade Vorlagen...');
|
const { id } = req.params;
|
||||||
|
const userId = (req as AuthRequest).user?.userId;
|
||||||
|
|
||||||
const templates = await db.all<any>(`
|
if (!userId) {
|
||||||
SELECT sp.*, e.name as created_by_name
|
res.status(401).json({ error: 'Unauthorized' });
|
||||||
FROM shift_plans sp
|
return;
|
||||||
LEFT JOIN employees e ON sp.created_by = e.id
|
}
|
||||||
WHERE sp.is_template = 1
|
|
||||||
ORDER BY sp.created_at DESC
|
|
||||||
`);
|
|
||||||
|
|
||||||
console.log(`✅ ${templates.length} Vorlagen gefunden:`, templates.map(t => t.name));
|
// Check if plan exists
|
||||||
|
const existingPlan = await getShiftPlanById(id);
|
||||||
|
//const existingPlan: ShiftPlan = await db.get('SELECT * FROM shift_plans WHERE id = ?', [id]);
|
||||||
|
if (!existingPlan) {
|
||||||
|
res.status(404).json({ error: 'Shift plan not found' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const templatesWithDetails = await Promise.all(
|
// Only allow reverting from published to draft
|
||||||
templates.map(async (template) => {
|
if (existingPlan.status !== 'published') {
|
||||||
const details = await getPlanWithDetails(template.id);
|
res.status(400).json({ error: 'Can only revert published plans to draft' });
|
||||||
return details ? { ...details.plan, timeSlots: details.timeSlots, shifts: details.shifts } : null;
|
return;
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// Update plan status to draft
|
||||||
|
await db.run(
|
||||||
|
'UPDATE shift_plans SET status = ? WHERE id = ?',
|
||||||
|
['draft', id]
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json(templatesWithDetails.filter(Boolean));
|
// Clear all assigned employees from scheduled shifts
|
||||||
|
await db.run(
|
||||||
|
'UPDATE scheduled_shifts SET assigned_employees = ? WHERE plan_id = ?',
|
||||||
|
[JSON.stringify([]), id]
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`✅ Plan ${id} reverted to draft status`);
|
||||||
|
|
||||||
|
// Return updated plan
|
||||||
|
const updatedPlan = await getShiftPlanById(id);
|
||||||
|
res.json(updatedPlan);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching templates:', error);
|
console.error('Error reverting plan to draft:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
};*/
|
};
|
||||||
|
|
||||||
// Neue Funktion: Create from Template
|
// Neue Funktion: Create from Template
|
||||||
/*export const createFromTemplate = async (req: Request, res: Response): Promise<void> => {
|
/*export const createFromTemplate = async (req: Request, res: Response): Promise<void> => {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import {
|
|||||||
deleteShiftPlan,
|
deleteShiftPlan,
|
||||||
//getTemplates,
|
//getTemplates,
|
||||||
//createFromTemplate,
|
//createFromTemplate,
|
||||||
createFromPreset
|
createFromPreset,
|
||||||
|
revertToDraft
|
||||||
} from '../controllers/shiftPlanController.js';
|
} from '../controllers/shiftPlanController.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@@ -42,4 +43,7 @@ router.put('/:id', requireRole(['admin', 'instandhalter']), updateShiftPlan);
|
|||||||
// DELETE shift plan or template
|
// DELETE shift plan or template
|
||||||
router.delete('/:id', requireRole(['admin', 'instandhalter']), deleteShiftPlan);
|
router.delete('/:id', requireRole(['admin', 'instandhalter']), deleteShiftPlan);
|
||||||
|
|
||||||
|
// PUT revert published plan to draft
|
||||||
|
router.put('/:id/revert-to-draft', requireRole(['admin', 'instandhalter']), revertToDraft);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
@@ -32,6 +32,7 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
const [assignmentResult, setAssignmentResult] = useState<AssignmentResult | null>(null);
|
const [assignmentResult, setAssignmentResult] = useState<AssignmentResult | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [publishing, setPublishing] = useState(false);
|
const [publishing, setPublishing] = useState(false);
|
||||||
|
const [reverting, setReverting] = useState(false);
|
||||||
const [showAssignmentPreview, setShowAssignmentPreview] = useState(false);
|
const [showAssignmentPreview, setShowAssignmentPreview] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -166,8 +167,13 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
message: 'Schichtplan wurde erfolgreich veröffentlicht!'
|
message: 'Schichtplan wurde erfolgreich veröffentlicht!'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reload the plan to reflect changes
|
// Lade den Plan neu, um die aktuellen Daten zu erhalten
|
||||||
loadShiftPlanData();
|
const updatedPlan = await shiftPlanService.getShiftPlan(shiftPlan.id);
|
||||||
|
setShiftPlan(updatedPlan);
|
||||||
|
|
||||||
|
// Behalte die assignmentResult für die Anzeige bei
|
||||||
|
// Die Tabelle wird nun automatisch die tatsächlichen Mitarbeiternamen anzeigen
|
||||||
|
|
||||||
setShowAssignmentPreview(false);
|
setShowAssignmentPreview(false);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -202,6 +208,62 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
return employeesWithoutAvailabilities.length === 0;
|
return employeesWithoutAvailabilities.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRevertToDraft = async () => {
|
||||||
|
if (!shiftPlan || !id) return;
|
||||||
|
|
||||||
|
if (!window.confirm('Möchten Sie diesen Schichtplan wirklich zurück in den Entwurfsstatus setzen? Alle Zuweisungen werden entfernt.')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setReverting(true);
|
||||||
|
|
||||||
|
const updatedPlan = await shiftPlanService.revertToDraft(id);
|
||||||
|
setShiftPlan(updatedPlan);
|
||||||
|
setAssignmentResult(null);
|
||||||
|
|
||||||
|
showNotification({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Erfolg',
|
||||||
|
message: 'Schichtplan wurde erfolgreich zurück in den Entwurfsstatus gesetzt.'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verfügbarkeiten neu laden
|
||||||
|
loadAvailabilities();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error reverting plan to draft:', error);
|
||||||
|
showNotification({
|
||||||
|
type: 'error',
|
||||||
|
title: 'Fehler',
|
||||||
|
message: 'Schichtplan konnte nicht zurückgesetzt werden.'
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setReverting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadAvailabilities = async () => {
|
||||||
|
if (!employees.length) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const availabilityPromises = employees
|
||||||
|
.filter(emp => emp.isActive)
|
||||||
|
.map(emp => employeeService.getAvailabilities(emp.id));
|
||||||
|
|
||||||
|
const allAvailabilities = await Promise.all(availabilityPromises);
|
||||||
|
const flattenedAvailabilities = allAvailabilities.flat();
|
||||||
|
|
||||||
|
const planAvailabilities = flattenedAvailabilities.filter(
|
||||||
|
availability => availability.planId === id
|
||||||
|
);
|
||||||
|
|
||||||
|
setAvailabilities(planAvailabilities);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading availabilities:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getAvailabilityStatus = () => {
|
const getAvailabilityStatus = () => {
|
||||||
const totalEmployees = employees.length;
|
const totalEmployees = employees.length;
|
||||||
const employeesWithAvailabilities = new Set(
|
const employeesWithAvailabilities = new Set(
|
||||||
@@ -219,9 +281,10 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
const getTimetableData = () => {
|
const getTimetableData = () => {
|
||||||
if (!shiftPlan) return { shifts: [], weekdays: [] };
|
if (!shiftPlan) return { shifts: [], weekdays: [] };
|
||||||
|
|
||||||
// Use timeSlots directly since shifts reference them
|
const hasAssignments = shiftPlan.status === 'published' || (assignmentResult && Object.keys(assignmentResult.assignments).length > 0);
|
||||||
|
|
||||||
const timetableShifts = shiftPlan.timeSlots.map(timeSlot => {
|
const timetableShifts = shiftPlan.timeSlots.map(timeSlot => {
|
||||||
const weekdayData: Record<number, string> = {};
|
const weekdayData: Record<number, { employees: string[], display: string }> = {};
|
||||||
|
|
||||||
weekdays.forEach(weekday => {
|
weekdays.forEach(weekday => {
|
||||||
const shiftsOnDay = shiftPlan.shifts.filter(shift =>
|
const shiftsOnDay = shiftPlan.shifts.filter(shift =>
|
||||||
@@ -230,12 +293,47 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (shiftsOnDay.length === 0) {
|
if (shiftsOnDay.length === 0) {
|
||||||
weekdayData[weekday.id] = '';
|
weekdayData[weekday.id] = { employees: [], display: '' };
|
||||||
} else {
|
} else {
|
||||||
const totalRequired = shiftsOnDay.reduce((sum, shift) =>
|
const totalRequired = shiftsOnDay.reduce((sum, shift) =>
|
||||||
sum + shift.requiredEmployees, 0);
|
sum + shift.requiredEmployees, 0);
|
||||||
// For now, show required count since we don't have assigned employees in Shift
|
|
||||||
weekdayData[weekday.id] = `0/${totalRequired}`;
|
let assignedEmployees: string[] = [];
|
||||||
|
|
||||||
|
if (hasAssignments && shiftPlan.scheduledShifts) {
|
||||||
|
const scheduledShift = shiftPlan.scheduledShifts.find(scheduled => {
|
||||||
|
const scheduledDayOfWeek = getDayOfWeek(scheduled.date);
|
||||||
|
return scheduledDayOfWeek === weekday.id &&
|
||||||
|
scheduled.timeSlotId === timeSlot.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (scheduledShift) {
|
||||||
|
if (shiftPlan.status === 'published') {
|
||||||
|
// Verwende tatsächliche Zuweisungen aus der Datenbank
|
||||||
|
assignedEmployees = scheduledShift.assignedEmployees
|
||||||
|
.map(empId => {
|
||||||
|
const employee = employees.find(emp => emp.id === empId);
|
||||||
|
return employee ? employee.name : 'Unbekannt';
|
||||||
|
});
|
||||||
|
} else if (assignmentResult && assignmentResult.assignments[scheduledShift.id]) {
|
||||||
|
// Verwende Preview-Zuweisungen
|
||||||
|
assignedEmployees = assignmentResult.assignments[scheduledShift.id]
|
||||||
|
.map(empId => {
|
||||||
|
const employee = employees.find(emp => emp.id === empId);
|
||||||
|
return employee ? employee.name : 'Unbekannt';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayText = hasAssignments
|
||||||
|
? assignedEmployees.join(', ') || `0/${totalRequired}`
|
||||||
|
: `0/${totalRequired}`;
|
||||||
|
|
||||||
|
weekdayData[weekday.id] = {
|
||||||
|
employees: assignedEmployees,
|
||||||
|
display: displayText
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -249,17 +347,83 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
return { shifts: timetableShifts, weekdays };
|
return { shifts: timetableShifts, weekdays };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDayOfWeek = (dateString: string): number => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.getDay() === 0 ? 7 : date.getDay();
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) return <div>Lade Schichtplan...</div>;
|
if (loading) return <div>Lade Schichtplan...</div>;
|
||||||
if (!shiftPlan) return <div>Schichtplan nicht gefunden</div>;
|
if (!shiftPlan) return <div>Schichtplan nicht gefunden</div>;
|
||||||
|
|
||||||
const timetableData = getTimetableData();
|
const timetableData = getTimetableData();
|
||||||
|
const availabilityStatus = getAvailabilityStatus();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '20px' }}>
|
<div style={{ padding: '20px' }}>
|
||||||
{/* Existing header code... */}
|
{/* Header mit Plan-Informationen und Aktionen */}
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
marginBottom: '20px'
|
||||||
|
}}>
|
||||||
|
<div>
|
||||||
|
<h1>{shiftPlan.name}</h1>
|
||||||
|
<p style={{ color: '#666', margin: 0 }}>
|
||||||
|
{shiftPlan.startDate && shiftPlan.endDate &&
|
||||||
|
`Zeitraum: ${formatDate(shiftPlan.startDate)} - ${formatDate(shiftPlan.endDate)}`
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<div style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
padding: '4px 12px',
|
||||||
|
backgroundColor: shiftPlan.status === 'published' ? '#2ecc71' : '#f1c40f',
|
||||||
|
color: 'white',
|
||||||
|
borderRadius: '20px',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginTop: '5px'
|
||||||
|
}}>
|
||||||
|
{shiftPlan.status === 'published' ? 'Veröffentlicht' : 'Entwurf'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
|
||||||
|
{shiftPlan.status === 'published' && hasRole(['admin', 'instandhalter']) && (
|
||||||
|
<button
|
||||||
|
onClick={handleRevertToDraft}
|
||||||
|
disabled={reverting}
|
||||||
|
style={{
|
||||||
|
padding: '10px 20px',
|
||||||
|
backgroundColor: '#e74c3c',
|
||||||
|
color: 'white',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '4px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{reverting ? 'Zurücksetzen...' : 'Zu Entwurf zurücksetzen'}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => navigate('/shift-plans')}
|
||||||
|
style={{
|
||||||
|
padding: '10px 20px',
|
||||||
|
backgroundColor: '#95a5a6',
|
||||||
|
color: 'white',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '4px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Zurück zur Übersicht
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Availability Status */}
|
{/* Availability Status - nur für Entwürfe anzeigen */}
|
||||||
{shiftPlan?.status === 'draft' && (
|
{shiftPlan.status === 'draft' && (
|
||||||
<div style={{
|
<div style={{
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
@@ -274,7 +438,7 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
Verfügbarkeitseinträge:
|
Verfügbarkeitseinträge:
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: '18px', fontWeight: 'bold' }}>
|
<div style={{ fontSize: '18px', fontWeight: 'bold' }}>
|
||||||
{getAvailabilityStatus().completed} / {getAvailabilityStatus().total} Mitarbeiter
|
{availabilityStatus.completed} / {availabilityStatus.total} Mitarbeiter
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
width: '200px',
|
width: '200px',
|
||||||
@@ -286,9 +450,9 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
}}>
|
}}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: `${getAvailabilityStatus().percentage}%`,
|
width: `${availabilityStatus.percentage}%`,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
backgroundColor: getAvailabilityStatus().percentage === 100 ? '#2ecc71' : '#f1c40f',
|
backgroundColor: availabilityStatus.percentage === 100 ? '#2ecc71' : '#f1c40f',
|
||||||
transition: 'all 0.3s ease'
|
transition: 'all 0.3s ease'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -315,9 +479,9 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
|
|
||||||
{!canPublish() && (
|
{!canPublish() && (
|
||||||
<div style={{ fontSize: '12px', color: '#666', marginTop: '5px' }}>
|
<div style={{ fontSize: '12px', color: '#666', marginTop: '5px' }}>
|
||||||
{getAvailabilityStatus().percentage === 100
|
{availabilityStatus.percentage === 100
|
||||||
? 'Bereit zur Veröffentlichung'
|
? 'Bereit zur Veröffentlichung'
|
||||||
: `${getAvailabilityStatus().total - getAvailabilityStatus().completed} Mitarbeiter müssen noch Verfügbarkeit eintragen`}
|
: `${availabilityStatus.total - availabilityStatus.completed} Mitarbeiter müssen noch Verfügbarkeit eintragen`}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -441,9 +605,12 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
padding: '20px',
|
padding: '20px',
|
||||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
||||||
}}>
|
}}>
|
||||||
{/* Timetable */}
|
|
||||||
<div style={{ marginTop: '30px' }}>
|
<div style={{ marginTop: '30px' }}>
|
||||||
<h3>Schichtplan</h3>
|
<h3>
|
||||||
|
Schichtplan
|
||||||
|
{shiftPlan.status === 'published' && ' (Aktuelle Zuweisungen)'}
|
||||||
|
{assignmentResult && shiftPlan.status === 'draft' && ' (Exemplarische Woche)'}
|
||||||
|
</h3>
|
||||||
|
|
||||||
{timetableData.shifts.length === 0 ? (
|
{timetableData.shifts.length === 0 ? (
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -481,7 +648,7 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
border: '1px solid #dee2e6',
|
border: '1px solid #dee2e6',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
minWidth: '80px'
|
minWidth: '120px'
|
||||||
}}>
|
}}>
|
||||||
{weekday.name}
|
{weekday.name}
|
||||||
</th>
|
</th>
|
||||||
@@ -505,9 +672,10 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
border: '1px solid #dee2e6',
|
border: '1px solid #dee2e6',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: shift.weekdayData[weekday.id] ? '#2c3e50' : '#bdc3c7'
|
color: shift.weekdayData[weekday.id].display ? '#2c3e50' : '#bdc3c7',
|
||||||
|
fontSize: shift.weekdayData[weekday.id].employees.length > 0 ? '14px' : 'inherit'
|
||||||
}}>
|
}}>
|
||||||
{shift.weekdayData[weekday.id] || '–'}
|
{shift.weekdayData[weekday.id].display || '–'}
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -523,12 +691,18 @@ const ShiftPlanView: React.FC = () => {
|
|||||||
<div style={{
|
<div style={{
|
||||||
marginTop: '20px',
|
marginTop: '20px',
|
||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
backgroundColor: '#e8f4fd',
|
backgroundColor: shiftPlan.status === 'published' ? '#d4edda' : '#e8f4fd',
|
||||||
borderRadius: '4px',
|
borderRadius: '4px',
|
||||||
border: '1px solid #b8d4f0',
|
border: shiftPlan.status === 'published' ? '1px solid #c3e6cb' : '1px solid #b8d4f0',
|
||||||
fontSize: '14px'
|
fontSize: '14px'
|
||||||
}}>
|
}}>
|
||||||
<strong>Legende:</strong> Angezeigt wird "zugewiesene/benötigte Mitarbeiter" pro Schicht und Wochentag
|
<strong>Legende:</strong> {
|
||||||
|
shiftPlan.status === 'published'
|
||||||
|
? 'Angezeigt werden die aktuell zugewiesenen Mitarbeiter'
|
||||||
|
: assignmentResult
|
||||||
|
? 'Angezeigt werden die vorgeschlagenen Mitarbeiter für eine exemplarische Woche'
|
||||||
|
: 'Angezeigt wird "zugewiesene/benötigte Mitarbeiter" pro Schicht und Wochentag'
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -122,12 +122,25 @@ export const shiftPlanService = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/*getTemplates: async (): Promise<ShiftPlan[]> => {
|
async revertToDraft(id: string): Promise<ShiftPlan> {
|
||||||
const response = await fetch(`${API_BASE}/templates`, {
|
const response = await fetch(`${API_BASE}/${id}/revert-to-draft`, {
|
||||||
headers: getAuthHeaders()
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...authService.getAuthHeaders()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return handleResponse(response);
|
|
||||||
},*/
|
if (!response.ok) {
|
||||||
|
if (response.status === 401) {
|
||||||
|
authService.logout();
|
||||||
|
throw new Error('Nicht authorisiert - bitte erneut anmelden');
|
||||||
|
}
|
||||||
|
throw new Error('Fehler beim Zurücksetzen des Schichtplans');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
// Get specific template or plan
|
// Get specific template or plan
|
||||||
getTemplate: async (id: string): Promise<ShiftPlan> => {
|
getTemplate: async (id: string): Promise<ShiftPlan> => {
|
||||||
|
|||||||
Reference in New Issue
Block a user