import { useState, useCallback, useEffect } from 'react' import { api } from '../api/client' import type { UserOut, AbsenceTypeOut, AbsenceOut, AbsenceListResponse, UserListItem, VacationBalanceOut, OvertimeBalanceOut, } from '../types/absence' import { MANAGER_ROLES } from '../utils/calendar' export function useAbsences(year: number, statusFilter: string) { const [user, setUser] = useState(null) const [types, setTypes] = useState([]) const [absences, setAbsences] = useState([]) const [total, setTotal] = useState(0) const [balance, setBalance] = useState(null) const [overtimeBalance, setOvertimeBalance] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [colleagues, setColleagues] = useState([]) const colleagueMap = Object.fromEntries(colleagues.map(c => [c.id, c.full_name])) const load = useCallback(async () => { setLoading(true) try { const params = statusFilter ? `?status=${statusFilter}&year=${year}` : `?year=${year}` const [me, typeList, absList, bal, otBal] = await Promise.all([ api.get('/auth/me'), api.get('/absence-types/'), api.get(`/absences/${params}`), api.get(`/absences/balance?year=${year}`), api.get('/absences/overtime-balance'), ]) setUser(me) setTypes(typeList.filter(t => t.is_active)) setAbsences(absList.items) setTotal(absList.total) setBalance(bal) setOvertimeBalance(otBal) if (MANAGER_ROLES.includes(me.role) && colleagues.length === 0) { try { const res = await api.get<{ items: UserListItem[] }>('/users/?limit=500') setColleagues(res.items) } catch { /* ignore */ } } } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { setLoading(false) } }, [statusFilter, year]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { load() }, [load]) const createAbsence = async ( form: { type_id: string; start_date: string; end_date: string; half_day_start: boolean; half_day_end: boolean; note: string; for_user_id: string }, onSuccess: () => void, setSubmitting: (v: boolean) => void, ) => { if (!form.type_id || !form.start_date || !form.end_date) { setError('Bitte alle Pflichtfelder ausfüllen') return } setSubmitting(true) setError('') try { await api.post('/absences/', { type_id: form.type_id, start_date: form.start_date, end_date: form.end_date, half_day_start: form.half_day_start, half_day_end: form.half_day_end, note: form.note || null, for_user_id: form.for_user_id || null, }) onSuccess() await load() } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler beim Erstellen') } finally { setSubmitting(false) } } const approve = async (id: string) => { setError('') try { await api.post(`/absences/${id}/approve`, {}); await load() } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler') } } const reject = async (id: string, rejectReason: string, onSuccess: () => void) => { if (!rejectReason.trim()) return setError('') try { await api.post(`/absences/${id}/reject`, { rejection_reason: rejectReason }) onSuccess() await load() } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler') } } const saveEdit = async ( editAbsence: AbsenceOut, editForm: { type_id: string; start_date: string; end_date: string; half_day_start: boolean; half_day_end: boolean; note: string; correction_note: string }, isManager: boolean, onSuccess: () => void, setSubmitting: (v: boolean) => void, ) => { if (!editForm.type_id || !editForm.start_date || !editForm.end_date) { setError('Bitte alle Pflichtfelder ausfüllen') return } if (editAbsence.status === 'approved' && !isManager && !editForm.correction_note.trim()) { setError('Änderungsgrund ist Pflicht bei genehmigten Anträgen.') return } setSubmitting(true) setError('') try { await api.patch(`/absences/${editAbsence.id}`, { type_id: editForm.type_id, start_date: editForm.start_date, end_date: editForm.end_date, half_day_start: editForm.half_day_start, half_day_end: editForm.half_day_end, note: editForm.note || null, correction_note: editForm.correction_note.trim() || null, }) onSuccess() await load() } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler beim Speichern') } finally { setSubmitting(false) } } const cancel = async (id: string) => { setError('') try { await api.del(`/absences/${id}`); await load() } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler') } } const loadColleaguesIfNeeded = async () => { if (colleagues.length === 0) { try { const res = await api.get<{ items: UserListItem[] }>('/users/?limit=500') setColleagues(res.items) } catch { /* ignore */ } } } const typeName = (typeId: string) => types.find(t => t.id === typeId)?.name ?? typeId const typeColor = (typeId: string) => types.find(t => t.id === typeId)?.color ?? '#6B7280' const updateBalance = (updated: VacationBalanceOut) => setBalance(updated) return { user, types, absences, total, balance, overtimeBalance, loading, error, setError, colleagues, colleagueMap, load, createAbsence, approve, reject, saveEdit, cancel, loadColleaguesIfNeeded, typeName, typeColor, updateBalance, } }