22be68ee27
- MobileAbsencesScreen.tsx: - Urlaubskonto-Karte (verbleibende Tage + Fortschrittsbalken) - Liste eigener Abwesenheiten (aktuell/geplant + vergangen) - Farbpunkt pro Abwesenheitstyp, Status-Badge - Bottom-Sheet Modal: Antrag stellen oder Krank melden - Start-/Enddatum-Picker, Typ-Auswahl, optionale Notiz - SICK-Typ → quick-sick Endpoint, sonst POST /absences/ - MobileBottomNav: 4. Tab 'Urlaub' (war 3 Tabs) - MobilePage: Screen 'absences' eingebunden Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
type Screen = 'stamp' | 'today' | 'absences' | 'profile'
|
|
|
|
interface Props {
|
|
active: Screen
|
|
onChange: (s: Screen) => void
|
|
}
|
|
|
|
export function MobileBottomNav({ active, onChange }: Props) {
|
|
const items: { id: Screen; label: string; icon: React.ReactNode }[] = [
|
|
{
|
|
id: 'stamp',
|
|
label: 'Stempeln',
|
|
icon: (
|
|
<svg className='w-6 h-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' strokeWidth={1.75}>
|
|
<circle cx='12' cy='12' r='9' />
|
|
<polyline points='12 7 12 12 15 15' />
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
id: 'today',
|
|
label: 'Heute',
|
|
icon: (
|
|
<svg className='w-6 h-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' strokeWidth={1.75}>
|
|
<rect x='3' y='4' width='18' height='18' rx='2' ry='2' />
|
|
<line x1='16' y1='2' x2='16' y2='6' />
|
|
<line x1='8' y1='2' x2='8' y2='6' />
|
|
<line x1='3' y1='10' x2='21' y2='10' />
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
id: 'absences',
|
|
label: 'Urlaub',
|
|
icon: (
|
|
<svg className='w-6 h-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' strokeWidth={1.75}>
|
|
<path strokeLinecap='round' strokeLinejoin='round' d='M3 17l4-8 4 4 4-6 4 10' />
|
|
<path strokeLinecap='round' strokeLinejoin='round' d='M3 20h18' />
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
id: 'profile',
|
|
label: 'Profil',
|
|
icon: (
|
|
<svg className='w-6 h-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' strokeWidth={1.75}>
|
|
<path strokeLinecap='round' strokeLinejoin='round' d='M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2' />
|
|
<circle cx='12' cy='7' r='4' />
|
|
</svg>
|
|
),
|
|
},
|
|
]
|
|
|
|
return (
|
|
<nav
|
|
className='fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 z-20'
|
|
style={{ paddingBottom: 'env(safe-area-inset-bottom)' }}
|
|
>
|
|
<div className='flex'>
|
|
{items.map(item => (
|
|
<button
|
|
key={item.id}
|
|
onClick={() => onChange(item.id)}
|
|
className={`flex-1 flex flex-col items-center justify-center gap-1 min-h-[56px] py-2 transition-colors ${
|
|
active === item.id ? 'text-blue-600' : 'text-gray-400'
|
|
}`}
|
|
>
|
|
{item.icon}
|
|
<span className={`text-[11px] font-medium leading-none ${active === item.id ? 'text-blue-600' : 'text-gray-400'}`}>
|
|
{item.label}
|
|
</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</nav>
|
|
)
|
|
}
|