import {
View, Text, ScrollView, TouchableOpacity, Linking, ActivityIndicator, Alert, Share, StyleSheet, Platform,
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useLocalSearchParams, useRouter, Stack } from 'expo-router'
import { Ionicons } from '@expo/vector-icons'
import { useTerminDetail, useToggleAnmeldung } from '@/hooks/useTermine'
import { AnmeldeButton } from '@/components/termine/AnmeldeButton'
import { Badge } from '@/components/ui/Badge'
import { TERMIN_TYP_LABELS } from '@innungsapp/shared/types'
import { format } from 'date-fns'
import { de } from 'date-fns/locale'
import * as Calendar from 'expo-calendar'
export default function TerminDetailScreen() {
const { id } = useLocalSearchParams<{ id: string }>()
const router = useRouter()
const { data: termin, isLoading } = useTerminDetail(id)
const { mutate, isPending } = useToggleAnmeldung()
if (isLoading) {
return (
)
}
if (!termin) return null
const datum = new Date(termin.datum)
const isPast = datum < new Date()
const handleAddToCalendar = async () => {
try {
const { status } = await Calendar.requestCalendarPermissionsAsync()
if (status !== 'granted') {
Alert.alert('Fehler', 'Kalender-Berechtigung wurde verweigert.')
return
}
const startDate = new Date(termin.datum)
let endDate = new Date(termin.datum)
if (termin.uhrzeit) {
const [hours, minutes] = termin.uhrzeit.split(':').map(Number)
startDate.setHours(hours || 0, minutes || 0)
if (termin.endeUhrzeit) {
const [endHours, endMinutes] = termin.endeUhrzeit.split(':').map(Number)
endDate.setHours(endHours || 0, endMinutes || 0)
} else {
endDate.setHours((hours || 0) + 1, minutes || 0)
}
} else {
endDate.setDate(startDate.getDate() + 1)
}
let calendarId
if (Platform.OS === 'ios') {
const defaultCalendar = await Calendar.getDefaultCalendarAsync()
calendarId = defaultCalendar.id
} else {
const calendars = await Calendar.getCalendarsAsync(Calendar.EntityTypes.EVENT)
// Try to prefer primary or typical default calendar
const primary = calendars.find(c => c.isPrimary) || calendars.find(c => c.accessLevel === 'owner') || calendars[0]
calendarId = primary?.id
}
if (!calendarId) {
Alert.alert('Fehler', 'Kein beschreibbarer Kalender gefunden.')
return
}
await Calendar.createEventAsync(calendarId, {
title: termin.titel,
startDate,
endDate,
allDay: !termin.uhrzeit,
location: [termin.ort, termin.adresse].filter(Boolean).join(', '),
notes: termin.beschreibung || undefined,
})
Alert.alert('Erfolg', 'Der Termin wurde in den Kalender eingetragen.')
} catch (e) {
console.error(e)
Alert.alert('Fehler', 'Der Termin konnte nicht eingetragen werden.')
}
}
return (
<>
{/* Header */}
router.back()} style={styles.backButton}>
{
const lines: string[] = []
lines.push(`đ
${termin.titel}`)
lines.push(format(datum, 'EEEE, d. MMMM yyyy', { locale: de }))
if (termin.uhrzeit) {
lines.push(`đ ${termin.uhrzeit}${termin.endeUhrzeit ? ` â ${termin.endeUhrzeit}` : ''} Uhr`)
}
if (termin.ort) lines.push(`đ ${termin.ort}`)
if (termin.adresse) lines.push(` ${termin.adresse}`)
if (termin.beschreibung) lines.push(`\n${termin.beschreibung}`)
Share.share({ message: lines.join('\n') })
}}
>
{/* Date Badge */}
{format(datum, 'EEEE, d. MMMM yyyy', { locale: de })}
{termin.titel}
{termin.isAngemeldet && (
Angemeldet
)}
{/* Info Card */}
{/* Time */}
{termin.uhrzeit && (
Uhrzeit
{termin.uhrzeit}
{termin.endeUhrzeit ? ` â ${termin.endeUhrzeit}` : ''} Uhr
)}
{termin.uhrzeit && termin.ort && }
{/* Location */}
{termin.ort && (
termin.adresse &&
Linking.openURL(`https://maps.google.com/?q=${encodeURIComponent(termin.adresse)}`)
}
activeOpacity={termin.adresse ? 0.7 : 1}
>
Ort
{termin.ort}
{termin.adresse && (
{termin.adresse}
)}
{termin.adresse && (
)}
)}
{(termin.uhrzeit || termin.ort) && (termin.teilnehmerAnzahl !== undefined) && }
{/* Participants */}
Teilnehmer
{termin.teilnehmerAnzahl} Anmeldungen
{termin.maxTeilnehmer && (
{termin.maxTeilnehmer} PlĂ€tze verfĂŒgbar
)}
{/* Description */}
{termin.beschreibung && (
Beschreibung
{termin.beschreibung}
)}
{/* Bottom Action Bar â only for upcoming events */}
{isPast ? (
Vergangener Termin â keine Anmeldung möglich
) : (
mutate({ terminId: id })}
isLoading={isPending}
maxTeilnehmer={termin.maxTeilnehmer}
teilnehmerAnzahl={termin.teilnehmerAnzahl}
/>
)}
>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F8FAFC',
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
header: {
paddingHorizontal: 16,
paddingVertical: 12,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#F8FAFC',
},
backButton: {
padding: 8,
borderRadius: 12,
backgroundColor: '#FFFFFF',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 2,
elevation: 1,
},
headerSpacer: {
flex: 1,
},
shareButton: {
padding: 8,
},
scrollContent: {
padding: 24,
paddingBottom: 100,
},
dateline: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
gap: 8,
},
calendarIcon: {
width: 32,
height: 32,
borderRadius: 8,
backgroundColor: '#EFF6FF',
justifyContent: 'center',
alignItems: 'center',
},
dateText: {
fontSize: 15,
fontWeight: '600',
color: '#003B7E',
},
title: {
fontSize: 28,
fontWeight: '800',
color: '#0F172A',
lineHeight: 34,
marginBottom: 16,
letterSpacing: -0.5,
},
badgesRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
marginBottom: 32,
},
registeredBadge: {
flexDirection: 'row',
alignItems: 'center',
gap: 6,
paddingHorizontal: 10,
paddingVertical: 4,
backgroundColor: '#ECFDF5',
borderRadius: 6,
borderWidth: 1,
borderColor: '#A7F3D0',
},
registeredText: {
fontSize: 12,
fontWeight: '600',
color: '#047857',
},
card: {
backgroundColor: '#FFFFFF',
borderRadius: 20,
padding: 20,
shadowColor: '#64748B',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.04,
shadowRadius: 12,
elevation: 2,
marginBottom: 32,
},
infoRow: {
flexDirection: 'row',
alignItems: 'flex-start',
gap: 16,
},
iconBox: {
width: 40,
height: 40,
borderRadius: 10,
backgroundColor: '#F1F5F9',
justifyContent: 'center',
alignItems: 'center',
},
infoContent: {
flex: 1,
paddingTop: 2,
},
infoLabel: {
fontSize: 12,
fontWeight: '600',
color: '#94A3B8',
marginBottom: 2,
textTransform: 'uppercase',
letterSpacing: 0.5,
},
infoValue: {
fontSize: 16,
fontWeight: '600',
color: '#0F172A',
lineHeight: 22,
},
infoSub: {
fontSize: 14,
color: '#64748B',
marginTop: 2,
lineHeight: 20,
},
divider: {
height: 1,
backgroundColor: '#F1F5F9',
marginVertical: 16,
marginLeft: 56,
},
section: {
marginBottom: 24,
},
sectionTitle: {
fontSize: 18,
fontWeight: '700',
color: '#0F172A',
marginBottom: 12,
},
description: {
fontSize: 16,
lineHeight: 26,
color: '#334155',
},
actionBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: '#FFFFFF',
paddingHorizontal: 20,
paddingVertical: 16,
paddingBottom: Platform.OS === 'ios' ? 32 : 16,
flexDirection: 'row',
gap: 12,
borderTopWidth: 1,
borderTopColor: '#F1F5F9',
shadowColor: '#000',
shadowOffset: { width: 0, height: -4 },
shadowOpacity: 0.02,
shadowRadius: 8,
elevation: 4,
},
pastBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: '#F8FAFC',
paddingHorizontal: 20,
paddingVertical: 14,
paddingBottom: Platform.OS === 'ios' ? 28 : 14,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
borderTopWidth: 1,
borderTopColor: '#E2E8F0',
},
pastBarText: {
fontSize: 13,
color: '#94A3B8',
fontWeight: '500',
},
actionButtonContainer: {
flex: 1,
},
calendarButton: {
width: 52,
height: 52,
borderRadius: 14,
backgroundColor: '#F1F5F9',
justifyContent: 'center',
alignItems: 'center',
},
})