diff --git a/DEVLOG.md b/DEVLOG.md index c97d8fc..fcb49be 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -1470,3 +1470,24 @@ Keine Commits in dieser Session. - frontend/src/pages/CompanySettingsPage.tsx | 88 +++++++++++++++++++++++++++++- --- +## 2026-05-25 22:17 – 22:18 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** timemaster + +### Commits +- a63b0e8 feat: Stunden-Auszahlung Feature (/hr/payouts) + +### Geänderte Dateien +- DEVLOG.md | 136 ++++++ +- backend/app/main.py | 2 + +- backend/app/models/__init__.py | 2 + +- backend/app/models/hours_payout.py | 45 ++ +- backend/app/routers/hours_payouts.py | 189 +++++++++ +- backend/app/schemas/hours_payout.py | 33 ++ +- backend/migrations/versions/0030_hours_payouts.py | 36 ++ +- frontend/src/App.tsx | 2 + +- frontend/src/components/Layout.tsx | 1 + +- frontend/src/pages/HoursPayoutPage.tsx | 484 ++++++++++++++++++++++ +- frontend/src/types/hoursPayout.ts | 26 ++ + +--- diff --git a/frontend/src/pages/mobile/MobileProfileScreen.tsx b/frontend/src/pages/mobile/MobileProfileScreen.tsx index 0477cd5..27adb89 100644 --- a/frontend/src/pages/mobile/MobileProfileScreen.tsx +++ b/frontend/src/pages/mobile/MobileProfileScreen.tsx @@ -11,6 +11,30 @@ interface UserOut { personnel_number: string | null } +interface OvertimeBalance { + total_hours: number + taken_hours: number + available_hours: number +} + +interface HoursPayoutOut { + id: string + hours: number + period_year: number | null + period_month: number | null + note: string | null + created_by_name: string + created_at: string +} + +interface HoursPayoutListResponse { + payouts: HoursPayoutOut[] + total_count: number +} + +const MONTH_NAMES = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', + 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'] + const ROLE_LABELS: Record = { SUPER_ADMIN: 'Super Admin', COMPANY_ADMIN: 'Administrator', @@ -21,15 +45,24 @@ const ROLE_LABELS: Record = { export function MobileProfileScreen() { const { logout } = useAuth() - const [user, setUser] = useState(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) + const [user, setUser] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [overtime, setOvertime] = useState(null) + const [payouts, setPayouts] = useState([]) const load = useCallback(async () => { setError(null) try { const me = await api.get('/auth/me') setUser(me) + // Überstunden-Saldo + eigene Auszahlungen parallel laden + const [bal, payoutData] = await Promise.all([ + api.get(`/absences/overtime-balance?user_id=${me.id}`).catch(() => null), + api.get(`/hr/payouts?user_id=${me.id}`).catch(() => null), + ]) + if (bal) setOvertime(bal) + if (payoutData) setPayouts(payoutData.payouts.slice(0, 5)) // letzte 5 } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { @@ -96,6 +129,54 @@ export function MobileProfileScreen() { )} + {/* Überstunden-Saldo */} + {overtime !== null && ( +
+

Überstunden-Konto

+
+
+

{overtime.total_hours.toFixed(1)}

+

Gesamt

+
+
+

{overtime.taken_hours.toFixed(1)}

+

Entnommen

+
+
+

= 0 ? 'text-green-600' : 'text-red-600'}`}> + {overtime.available_hours.toFixed(1)} +

+

Verfügbar

+
+
+
+ )} + + {/* Stunden-Auszahlungen */} + {payouts.length > 0 && ( +
+

+ 💸 Stunden-Auszahlungen +

+
+ {payouts.map(p => ( +
+
+

{p.hours.toFixed(2)} h

+

+ {p.period_year && p.period_month + ? `${MONTH_NAMES[p.period_month - 1]} ${p.period_year}` + : new Date(p.created_at).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })} +

+ {p.note &&

{p.note}

} +
+

{p.created_by_name}

+
+ ))} +
+
+ )} + {/* Desktop-Version Link */}