import * as Calendar from "expo-calendar"; import * as SQLite from "expo-sqlite"; import React, { useEffect, useState } from "react"; import { FlatList, SafeAreaView, StyleSheet, Text, TouchableOpacity, View, } from "react-native"; export interface EventItem { id: string; title: string; startDate: string; endDate: string; } const db = SQLite.openDatabaseSync("events.db"); export default function CalendarTab() { const [source, setSource] = useState<"sqlite" | "iphone">("sqlite"); const [events, setEvents] = useState([]); const [loading, setLoading] = useState(false); const [selectedYear, setSelectedYear] = useState( new Date().getFullYear() ); const [permissionError, setPermissionError] = useState(null); const [calendarType, setCalendarType] = useState<"calendar" | "reminder">( "calendar" ); useEffect(() => { if (source === "sqlite") { loadEventsFromDB(); } else { loadEventsFromDevice(); } }, [source, selectedYear, calendarType]); const loadEventsFromDB = async () => { setLoading(true); try { const stmt = await db.prepareAsync("SELECT * FROM events;"); const loadedEvents: EventItem[] = []; const result = await stmt.executeAsync([]); for await (const row of result) { loadedEvents.push(row as EventItem); } setEvents(loadedEvents); await stmt.finalizeAsync(); } catch (e) { setEvents([]); } finally { setLoading(false); } }; const loadEventsFromDevice = async () => { setLoading(true); setPermissionError(null); try { let perm; if (calendarType === "reminder") { perm = await Calendar.requestRemindersPermissionsAsync(); } else { perm = await Calendar.requestCalendarPermissionsAsync(); } if (!perm.granted) { setEvents([]); setPermissionError( `Keine Berechtigung für ${ calendarType === "reminder" ? "Erinnerungen" : "Kalender" }-Zugriff. Bitte in den iOS-Einstellungen aktivieren.` ); return; } let calendars = await Calendar.getCalendarsAsync(); console.log( "Gefundene Kalender:", calendars.map((c) => ({ id: c.id, title: c.title, type: c.type })) ); if (calendarType === "calendar") { calendars = calendars.filter((c) => String(c.type) === "calendar"); } else { calendars = calendars.filter((c) => String(c.type) === "reminder"); } const start = new Date(selectedYear, 0, 1); const end = new Date(selectedYear, 11, 31, 23, 59, 59); let allEvents: EventItem[] = []; for (const cal of calendars) { const calEvents = await Calendar.getEventsAsync([cal.id], start, end); console.log( `Events für Kalender ${cal.title}:`, calEvents.map((e) => ({ id: e.id, title: e.title, start: e.startDate, end: e.endDate, })) ); allEvents = allEvents.concat( calEvents.map((e) => ({ id: e.id, title: e.title || "(Kein Titel)", startDate: typeof e.startDate === "string" ? e.startDate : new Date(e.startDate).toISOString(), endDate: typeof e.endDate === "string" ? e.endDate : new Date(e.endDate).toISOString(), })) ); } setEvents(allEvents); } catch (e: any) { setEvents([]); setPermissionError( "Fehler beim Zugriff auf " + (calendarType === "reminder" ? "Erinnerungen" : "Kalender") + ": " + (e?.message || JSON.stringify(e)) ); } finally { setLoading(false); } }; const renderItem = ({ item }: { item: EventItem }) => ( {item.title} {new Date(item.startDate).toLocaleString()} -{" "} {new Date(item.endDate).toLocaleString()} ); return ( setSource("sqlite")} > SQLite setSource("iphone")} > iPhone ({calendarType === "calendar" ? "Kalender" : "Erinnerungen"}) {source === "iphone" && ( setCalendarType("calendar")} > Kalender setCalendarType("reminder")} > Erinnerungen )} Kalender Events ({selectedYear}) item.id} renderItem={renderItem} ListEmptyComponent={ permissionError ? ( {permissionError} ) : ( Keine Events gefunden. ) } refreshing={loading} onRefresh={ source === "sqlite" ? loadEventsFromDB : loadEventsFromDevice } /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", padding: 10 }, header: { fontSize: 20, fontWeight: "bold", marginBottom: 16, textAlign: "center", }, item: { marginBottom: 12, padding: 12, borderRadius: 8, backgroundColor: "#f2f2f2", }, title: { fontSize: 16, fontWeight: "600" }, time: { fontSize: 14, color: "#555" }, switchRow: { flexDirection: "row", justifyContent: "center", marginBottom: 16, }, switchButton: { padding: 10, borderRadius: 8, backgroundColor: "#eee", marginHorizontal: 8, }, activeButton: { backgroundColor: "#007AFF" }, switchText: { color: "#333", fontWeight: "bold" }, });