diff --git a/app/liste/page.tsx b/app/liste/page.tsx new file mode 100644 index 0000000..6da26dc --- /dev/null +++ b/app/liste/page.tsx @@ -0,0 +1,45 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import TabLayout from '@/components/TabLayout'; +import AppointmentList from '@/components/AppointmentList'; +import { Appointment } from '@/types/appointment'; + +export default function ListePage() { + const [appointments, setAppointments] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + const fetchAppointments = async () => { + try { + const res = await fetch('/api/appointments', { cache: 'no-store' }); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + const data = await res.json(); + if (data.success) { + setAppointments(data.data); + } + } catch (error) { + console.error('Fehler beim Laden der Termine:', error); + } finally { + setIsLoading(false); + } + }; + + // Termine einmalig beim Mount laden. + useEffect(() => { + // eslint-disable-next-line react-hooks/set-state-in-effect + fetchAppointments(); + }, []); + + return ( + +
+

Alle Termine

+ {isLoading ? ( +
Lade Daten...
+ ) : ( + + )} +
+
+ ); +} diff --git a/components/AppointmentList.tsx b/components/AppointmentList.tsx index 79b963d..c714474 100644 --- a/components/AppointmentList.tsx +++ b/components/AppointmentList.tsx @@ -4,9 +4,9 @@ import { Appointment } from '@/types/appointment'; interface AppointmentListProps { appointments: Appointment[]; - onToggleDone: (id: string) => void; - onEdit: (appointment: Appointment) => void; - onDelete: (id: string) => void; + onToggleDone?: (id: string) => void; + onEdit?: (appointment: Appointment) => void; + onDelete?: (id: string) => void; } const weekdays = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']; @@ -33,17 +33,22 @@ export default function AppointmentList({ onEdit, onDelete, }: AppointmentListProps) { + const hasActions = Boolean(onEdit || onDelete); + if (appointments.length === 0) { return (
- Keine Termine vorhanden. Fügen Sie oben einen neuen Termin hinzu! + Keine Termine vorhanden.
); } - const sorted = [...appointments].sort( - (a, b) => new Date(a.termin).getTime() - new Date(b.termin).getTime() - ); + // Erledigte Einträge hinter die offenen schieben; innerhalb der Gruppen + // aufsteigend nach Termin sortieren. + const sorted = [...appointments].sort((a, b) => { + if (a.erledigt !== b.erledigt) return a.erledigt ? 1 : -1; + return new Date(a.termin).getTime() - new Date(b.termin).getTime(); + }); return (
@@ -57,17 +62,19 @@ export default function AppointmentList({ Tag Zeit Bemerkungen - Aktion + {hasActions && Aktion} {sorted.map((app, index) => ( onEdit(app)} - className={`border-b border-gray-300 hover:bg-gray-100 cursor-pointer ${ + onClick={onEdit ? () => onEdit(app) : undefined} + className={`border-b border-gray-300 hover:bg-gray-100 ${ + onEdit ? 'cursor-pointer' : '' + } ${ app.erledigt - ? 'bg-green-50 text-gray-400 line-through' + ? 'bg-green-50 text-gray-400' : index % 2 === 0 ? 'bg-white' : 'bg-gray-50' @@ -79,9 +86,12 @@ export default function AppointmentList({ > onToggleDone(app.id)} + disabled={!onToggleDone} + onChange={ + onToggleDone ? () => onToggleDone(app.id) : undefined + } /> {app.arztName} @@ -90,25 +100,31 @@ export default function AppointmentList({ {getWeekday(app.termin)} {formatTime(app.termin)} {app.bemerkungen || '-'} - e.stopPropagation()} - > -
- - -
- + {hasActions && ( + e.stopPropagation()} + > +
+ {onEdit && ( + + )} + {onDelete && ( + + )} +
+ + )} ))} diff --git a/components/TabLayout.tsx b/components/TabLayout.tsx index 7d5e035..8bd38dc 100644 --- a/components/TabLayout.tsx +++ b/components/TabLayout.tsx @@ -1,5 +1,7 @@ 'use client'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; import packageJson from '@/package.json'; interface TabLayoutProps { @@ -7,7 +9,13 @@ interface TabLayoutProps { onPrint?: () => void; } +const TABS = [ + { href: '/', label: 'Termine' }, + { href: '/liste', label: 'Liste' }, +]; + export default function TabLayout({ children, onPrint }: TabLayoutProps) { + const pathname = usePathname(); const version = packageJson.version; const buildDate = process.env.NEXT_PUBLIC_BUILD_DATE || @@ -31,29 +39,46 @@ export default function TabLayout({ children, onPrint }: TabLayoutProps) { {/* Tab-Leiste */}
- - Termine - -
-
- + {TABS.map((tab) => { + const isActive = pathname === tab.href; + return ( + + {tab.label} + + ); + })}
+ {onPrint && ( +
+ +
+ )}
{/* Inhaltsbereich */} diff --git a/deploy.sh b/deploy.sh index f836095..54abddb 100755 --- a/deploy.sh +++ b/deploy.sh @@ -40,7 +40,7 @@ echo "" # 3. Docker Image bauen und pushen echo ">>> Baue Multiplatform Docker Image und pushe zu Registry..." docker buildx build \ - --platform linux/amd64,linux/arm64 \ + --platform linux/amd64 \ --build-arg BUILD_DATE="${BUILD_DATE}" \ -t "${FULL_IMAGE}" \ --push \