Fix Calendar Loading Problems

This commit is contained in:
2025-12-18 19:00:05 +01:00
parent afadbbc835
commit bbe05bd765
3 changed files with 228 additions and 177 deletions
+105 -96
View File
@@ -2,14 +2,22 @@
$events = collection('termine');
if ($events === null): ?>
<section class="py-24 bg-sf_grau-50">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="text-red-600 bg-white p-6 rounded-lg shadow">Die Termine können gerade nicht geladen werden.</div>
</div>
</section>
<?php return; endif;
// Nur Events mit DTSTART berücksichtigen
$events = array_filter($events, function ($event) {
return isset($event['DTSTART']) && !empty($event['DTSTART']);
return isset($event['DTSTART']) && !empty($event['DTSTART']);
});
// Nach Datum sortieren
usort($events, function ($a, $b) {
return strcmp($a['DTSTART'], $b['DTSTART']);
return strcmp($a['DTSTART'], $b['DTSTART']);
});
// Aktuelles Datum - PHP 8.3 kompatibel
@@ -17,44 +25,44 @@ $today = (new DateTime('now'))->format('Ymd');
// Nur zukünftige Termine anzeigen
$future_events = array_filter($events, function ($event) use ($today) {
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
});
// --- Deutsche Monatsnamen ---
$de_months = [
'01' => 'Januar',
'02' => 'Februar',
'03' => 'März',
'04' => 'April',
'05' => 'Mai',
'06' => 'Juni',
'07' => 'Juli',
'08' => 'August',
'09' => 'September',
'10' => 'Oktober',
'11' => 'November',
'12' => 'Dezember',
'01' => 'Januar',
'02' => 'Februar',
'03' => 'März',
'04' => 'April',
'05' => 'Mai',
'06' => 'Juni',
'07' => 'Juli',
'08' => 'August',
'09' => 'September',
'10' => 'Oktober',
'11' => 'November',
'12' => 'Dezember',
];
// --- Gruppierung aller Termine nach Jahr und Monat für die Sidebar ---
function group_events_by_year_month($events)
{
$grouped = [];
foreach ($events as $event) {
if (!isset($event['DTSTART'])) {
continue;
$grouped = [];
foreach ($events as $event) {
if (!isset($event['DTSTART'])) {
continue;
}
$date = $event['DTSTART'];
$year = substr($date, 0, 4);
$month = substr($date, 4, 2);
$grouped[$year][$month][] = $event;
}
krsort($grouped); // Jahre absteigend
foreach ($grouped as &$months) {
krsort($months); // Monate absteigend
}
$date = $event['DTSTART'];
$year = substr($date, 0, 4);
$month = substr($date, 4, 2);
$grouped[$year][$month][] = $event;
}
krsort($grouped); // Jahre absteigend
foreach ($grouped as &$months) {
krsort($months); // Monate absteigend
}
return $grouped;
return $grouped;
}
$all_events_grouped = group_events_by_year_month($events);
@@ -64,19 +72,19 @@ $filter_jahr = filter_input(INPUT_GET, 'jahr', FILTER_SANITIZE_FULL_SPECIAL_CHAR
$filter_monat = filter_input(INPUT_GET, 'monat', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? null;
if ($filter_jahr && $filter_monat) {
$filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) {
$date = $event['DTSTART'] ?? '';
$filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) {
$date = $event['DTSTART'] ?? '';
return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat;
});
return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat;
});
} elseif ($filter_jahr) {
$filtered_events = array_filter($events, function ($event) use ($filter_jahr) {
$date = $event['DTSTART'] ?? '';
$filtered_events = array_filter($events, function ($event) use ($filter_jahr) {
$date = $event['DTSTART'] ?? '';
return substr($date, 0, 4) === $filter_jahr;
});
return substr($date, 0, 4) === $filter_jahr;
});
} else {
$filtered_events = $future_events;
$filtered_events = $future_events;
}
?>
@@ -90,33 +98,34 @@ if ($filter_jahr && $filter_monat) {
<?php foreach ($all_events_grouped as $year => $months): ?>
<li class="mb-2">
<div class="flex items-center">
<?php
<?php
$safe_year = htmlspecialchars($year, ENT_QUOTES, 'UTF-8');
$is_year_selected = ($filter_jahr === $year && !$filter_monat);
?>
<a href="?jahr=<?= $safe_year ?>"
class="font-bold text-sf_blau-600 focus:outline-none flex items-center group<?= $is_year_selected ? ' underline selected' : '' ?>"
onclick="event.stopPropagation(); openYear('<?= $safe_year ?>')">
class="font-bold text-sf_blau-600 focus:outline-none flex items-center group<?= $is_year_selected ? ' underline selected' : '' ?>"
onclick="event.stopPropagation(); openYear('<?= $safe_year ?>')">
<span><?= $safe_year ?></span>
</a>
<button type="button" class="ml-1 focus:outline-none" onclick="toggleYear('<?= $safe_year ?>')">
<svg class="w-4 h-4 transition-transform" id="arrow-<?= $safe_year ?>" fill="none" stroke="currentColor" stroke-width="2"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
<button type="button" class="ml-1 focus:outline-none"
onclick="toggleYear('<?= $safe_year ?>')">
<svg class="w-4 h-4 transition-transform" id="arrow-<?= $safe_year ?>" fill="none"
stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
<ul class="ml-4 mt-1 hidden" id="months-<?= $safe_year ?>">
<?php foreach ($months as $month => $evts): ?>
<li>
<?php
<?php
$safe_month = htmlspecialchars($month, ENT_QUOTES, 'UTF-8');
$month_name = $de_months[$month] ?? 'Unbekannt';
$is_month_selected = ($filter_jahr === $year && $filter_monat === $month);
$event_count = count($evts);
?>
<a href="?jahr=<?= $safe_year ?>&monat=<?= $safe_month ?>"
class="text-sf_blau-500 hover:underline<?= $is_month_selected ? ' font-bold underline selected' : '' ?>">
<a href="?jahr=<?= $safe_year ?>&monat=<?= $safe_month ?>"
class="text-sf_blau-500 hover:underline<?= $is_month_selected ? ' font-bold underline selected' : '' ?>">
<?= htmlspecialchars($month_name, ENT_QUOTES, 'UTF-8') ?> (<?= $event_count ?>)
</a>
</li>
@@ -157,50 +166,50 @@ if ($filter_jahr && $filter_monat) {
<div class="overflow-x-auto">
<table class="min-w-full border border-gray-200 bg-white rounded-lg shadow">
<thead>
<tr class="bg-gray-100">
<th class="py-2 px-4 border-b text-left">Datum</th>
<th class="py-2 px-4 border-b text-left">Uhrzeit</th>
<th class="py-2 px-4 border-b text-left">Titel</th>
</tr>
<tr class="bg-gray-100">
<th class="py-2 px-4 border-b text-left">Datum</th>
<th class="py-2 px-4 border-b text-left">Uhrzeit</th>
<th class="py-2 px-4 border-b text-left">Titel</th>
</tr>
</thead>
<tbody>
<?php foreach ($filtered_events as $event): ?>
<?php
$start = $event['DTSTART'] ?? '';
$end = $event['DTEND'] ?? '';
$summary = $event['SUMMARY'] ?? '';
$location = $event['LOCATION'] ?? '';
$desc = $event['DESCRIPTION'] ?? '';
$timezone = $event['DTSTART_TZID'] ?? null;
// Sichere Funktionsaufrufe mit Null-Checks
$date_info = function_exists('format_ics_date_with_timezone')
? format_ics_date_with_timezone($start, $timezone)
: ['display' => '', 'has_time' => false, 'iso' => ''];
$date = $date_info['display'] ?? '';
$time = ($date_info['has_time'] ?? false) ? substr($date, 11) : 'ganztägig';
$date = substr($date, 0, 10);
$iso_date = $date_info['iso'] ?? '';
// Sichere HTML-Ausgabe
$safe_date = htmlspecialchars($date, ENT_QUOTES, 'UTF-8');
$safe_time = htmlspecialchars($time, ENT_QUOTES, 'UTF-8');
$safe_iso_date = htmlspecialchars($iso_date, ENT_QUOTES, 'UTF-8');
$safe_summary = htmlspecialchars($summary, ENT_QUOTES, 'UTF-8');
?>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b whitespace-nowrap"><?= $safe_date ?></td>
<td class="py-2 px-4 border-b whitespace-nowrap">
<?php if ($date_info['has_time'] ?? false): ?>
<span class="local-time" data-iso-date="<?= $safe_iso_date ?>"><?= $safe_time ?></span>
<?php else: ?>
ganztägig
<?php endif; ?>
</td>
<td class="py-2 px-4 border-b"><?= $safe_summary ?></td>
</tr>
<?php endforeach; ?>
<?php foreach ($filtered_events as $event): ?>
<?php
$start = $event['DTSTART'] ?? '';
$end = $event['DTEND'] ?? '';
$summary = $event['SUMMARY'] ?? '';
$location = $event['LOCATION'] ?? '';
$desc = $event['DESCRIPTION'] ?? '';
$timezone = $event['DTSTART_TZID'] ?? null;
// Sichere Funktionsaufrufe mit Null-Checks
$date_info = function_exists('format_ics_date_with_timezone')
? format_ics_date_with_timezone($start, $timezone)
: ['display' => '', 'has_time' => false, 'iso' => ''];
$date = $date_info['display'] ?? '';
$time = ($date_info['has_time'] ?? false) ? substr($date, 11) : 'ganztägig';
$date = substr($date, 0, 10);
$iso_date = $date_info['iso'] ?? '';
// Sichere HTML-Ausgabe
$safe_date = htmlspecialchars($date, ENT_QUOTES, 'UTF-8');
$safe_time = htmlspecialchars($time, ENT_QUOTES, 'UTF-8');
$safe_iso_date = htmlspecialchars($iso_date, ENT_QUOTES, 'UTF-8');
$safe_summary = htmlspecialchars($summary, ENT_QUOTES, 'UTF-8');
?>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b whitespace-nowrap"><?= $safe_date ?></td>
<td class="py-2 px-4 border-b whitespace-nowrap">
<?php if ($date_info['has_time'] ?? false): ?>
<span class="local-time" data-iso-date="<?= $safe_iso_date ?>"><?= $safe_time ?></span>
<?php else: ?>
ganztägig
<?php endif; ?>
</td>
<td class="py-2 px-4 border-b"><?= $safe_summary ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
@@ -214,7 +223,7 @@ if ($filter_jahr && $filter_monat) {
font-weight: bold;
}
</style>
<script>
// Zeitzonenkonvertierung für lokale Zeiten
function convertTimesToLocal() {
@@ -226,23 +235,23 @@ if ($filter_jahr && $filter_monat) {
// Erstelle ein Date-Objekt aus der ISO-Date
// JavaScript erkennt automatisch UTC-Zeiten (mit Z oder +00:00)
const date = new Date(isoDate);
// Prüfe ob das Datum gültig ist
if (isNaN(date.getTime())) {
console.warn('Ungültiges Datum:', isoDate);
return;
}
// Formatiere die Zeit in der lokalen Zeitzone des Browsers
const localTime = date.toLocaleTimeString('de-DE', {
hour: '2-digit',
minute: '2-digit',
hour12: false
});
// Aktualisiere den Text
element.textContent = localTime;
// Debug-Information (kann später entfernt werden)
console.log('Konvertiert:', isoDate, '->', localTime, 'in Zeitzone:', Intl.DateTimeFormat().resolvedOptions().timeZone);
} catch (error) {
@@ -253,7 +262,7 @@ if ($filter_jahr && $filter_monat) {
}
// Zeitzonenkonvertierung beim Laden der Seite
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
convertTimesToLocal();
});
</script>