import { useCallback, useEffect, useMemo, useState } from 'react'; import { ActivityIndicator, Pressable, RefreshControl, ScrollView, StyleSheet, Text, View } from 'react-native'; import { useLocalSearchParams } from 'expo-router'; import * as WebBrowser from 'expo-web-browser'; import { HistorySection } from '@/components/history-section'; import { CalendarEvent, fetchEventById } from '@/src/lib/api'; import { useAuth } from '@/src/providers/auth-provider'; const PRIMARY = '#69c350'; function formatDateTime(value: unknown): string { if (!value) return '-'; const date = new Date(String(value)); if (Number.isNaN(date.getTime())) return String(value); return date.toLocaleString('de-DE', { weekday: 'short', day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }); } function relationName(value: unknown): string { if (!value) return '-'; if (typeof value === 'object') { const relation = value as { id?: number | string; name?: string }; return String(relation.name || relation.id || '-'); } return String(value); } export default function EventDetailScreen() { const params = useLocalSearchParams<{ id?: string }>(); const eventId = Number(params.id); const { token } = useAuth(); const [event, setEvent] = useState(null); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const validId = useMemo(() => Number.isFinite(eventId) && eventId > 0, [eventId]); const load = useCallback(async (showSpinner = true) => { if (!token || !validId) return; if (showSpinner) setLoading(true); setError(null); try { setEvent(await fetchEventById(token, eventId)); } catch (err) { setError(err instanceof Error ? err.message : 'Der Termin konnte nicht geladen werden.'); } finally { setLoading(false); setRefreshing(false); } }, [eventId, token, validId]); useEffect(() => { void load(true); }, [load]); async function onRefresh() { setRefreshing(true); await load(false); } async function openLink() { if (!event?.link) return; const raw = String(event.link).trim(); const url = /^https?:\/\//i.test(raw) ? raw : `https://${raw}`; await WebBrowser.openBrowserAsync(url, { controlsColor: PRIMARY, showTitle: true }); } const rows = event ? [ { label: 'Beginn', value: formatDateTime(event.startDate) }, { label: 'Ende', value: formatDateTime(event.endDate) }, { label: 'Projekt', value: relationName(event.project) }, { label: 'Kunde', value: relationName(event.customer) }, { label: 'Status', value: String(event.state || '-') }, { label: 'Wiederholung', value: String(event.repeatInterval || '-') }, ] : []; return ( }> {error ? {error} : null} {loading ? ( Termin wird geladen... ) : null} {!loading && event ? ( <> {event.name} {rows.map((row) => ( {row.label} {row.value} ))} {event.notes ? Notizen{event.notes} : null} {event.link ? Link öffnen : null} ) : null} ); } const styles = StyleSheet.create({ container: { padding: 16, gap: 12, backgroundColor: '#f9fafb' }, card: { backgroundColor: '#ffffff', borderRadius: 12, borderWidth: 1, borderColor: '#e5e7eb', padding: 12, gap: 10 }, headingRow: { flexDirection: 'row', alignItems: 'center', gap: 9 }, colorMark: { width: 6, height: 28, borderRadius: 3 }, title: { flex: 1, color: '#111827', fontSize: 19, fontWeight: '700' }, table: { borderWidth: 1, borderColor: '#e5e7eb', borderRadius: 10, overflow: 'hidden' }, row: { borderBottomWidth: 1, borderBottomColor: '#e5e7eb', paddingHorizontal: 10, paddingVertical: 8, gap: 2 }, label: { color: '#6b7280', fontSize: 12, textTransform: 'uppercase', fontWeight: '600' }, value: { color: '#111827', fontSize: 14, fontWeight: '500' }, notesBox: { borderWidth: 1, borderColor: '#e5e7eb', borderRadius: 10, padding: 10, backgroundColor: '#fafafa', gap: 4 }, notesLabel: { color: '#6b7280', fontSize: 12, fontWeight: '600', textTransform: 'uppercase' }, notes: { color: '#374151', fontSize: 14 }, linkButton: { backgroundColor: PRIMARY, borderRadius: 9, minHeight: 40, alignItems: 'center', justifyContent: 'center' }, linkButtonText: { color: '#ffffff', fontWeight: '700' }, loadingBox: { paddingVertical: 24, alignItems: 'center', gap: 8 }, loadingText: { color: '#6b7280' }, error: { color: '#dc2626', fontSize: 13 }, });