Initial Release: Lütte Planer mit Google-Login-Vorbereitung

- Login-System (Mock für Tests, Google OAuth vorbereitet)
- Reisen erstellen mit Emoji, Ziel und Datum
- Ablauf (Timeline), Packliste, Ideen, Notizen, Dokumente
- Team-System: Personen einladen per E-Mail + Einladungslinks
- Berechtigungen: Nur lesen / Bearbeiten / Admin
- E-Mail-Benachrichtigungen beim Einladen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 20:56:30 +02:00
co-authored by Claude Sonnet 4.6
commit bd8a322fc0
21 changed files with 1647 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
<?php
require_once __DIR__ . '/config.php';
$tripId = $_GET['trip'] ?? '';
[$trip, $user] = requireTripAccess($tripId);
$canEdit = userCanEdit($tripId, $user['id']);
$members = getTripMembers($tripId);
global $PACKEN_KATEGORIEN;
// Item hinzufügen
if ($canEdit && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add'])) {
dbInsert('packliste', [
'trip_id' => $tripId,
'name' => trim($_POST['name'] ?? ''),
'menge' => trim($_POST['menge'] ?? ''),
'kat' => $_POST['kat'] ?? 'sonstiges',
'assigned_to' => ($_POST['assigned_to'] ?? '') ?: null,
'created_by' => $user['id'],
]);
header('Location: /Develop/PlanerGoogel/packen.php?trip=' . $tripId); exit;
}
// Packed toggling
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['toggle'])) {
$item = dbOne('SELECT * FROM packliste WHERE id = ? AND trip_id = ?', [(int)$_POST['toggle'], $tripId]);
if ($item) {
dbExec('UPDATE packliste SET packed = ? WHERE id = ?', [$item['packed'] ? 0 : 1, $item['id']]);
}
header('Location: /Develop/PlanerGoogel/packen.php?trip=' . $tripId); exit;
}
// Löschen
if ($canEdit && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete'])) {
dbExec('DELETE FROM packliste WHERE id = ? AND trip_id = ?', [(int)$_POST['delete'], $tripId]);
header('Location: /Develop/PlanerGoogel/packen.php?trip=' . $tripId); exit;
}
// Alle zurücksetzen
if ($canEdit && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['reset_all'])) {
dbExec('UPDATE packliste SET packed = 0 WHERE trip_id = ?', [$tripId]);
header('Location: /Develop/PlanerGoogel/packen.php?trip=' . $tripId); exit;
}
$items = dbAll(
'SELECT p.*, u.name as assigned_name, u.farbe as assigned_farbe FROM packliste p
LEFT JOIN users u ON u.id = p.assigned_to
WHERE p.trip_id = ?
ORDER BY p.kat ASC, p.id ASC',
[$tripId]
);
// Nach Kategorie gruppieren
$grouped = [];
foreach ($items as $item) {
$grouped[$item['kat']][] = $item;
}
$total = count($items);
$packed = count(array_filter($items, fn($i) => $i['packed']));
$pct = $total > 0 ? round($packed / $total * 100) : 0;
$pageTitle = 'Packliste';
$activeTab = 'packen';
include __DIR__ . '/includes/header.php';
?>
<main class="main">
<div class="page-header">
<h1 class="section-head">Packliste</h1>
<div style="display:flex;gap:8px;align-items:center;">
<?php if ($canEdit): ?>
<button class="btn btn-primary" onclick="toggleForm('add-form')">+ Item</button>
<?php endif; ?>
</div>
</div>
<?php if ($total > 0): ?>
<div class="pack-progress">
<div class="pack-progress-bar" style="width:<?= $pct ?>%"></div>
</div>
<div class="stats-bar">
<span class="stat-pill"><strong><?= $packed ?></strong> / <?= $total ?> gepackt</span>
<span class="stat-pill"><strong><?= $pct ?>%</strong></span>
<?php if ($canEdit && $packed > 0): ?>
<form method="POST" style="margin:0;">
<button type="submit" name="reset_all" class="btn-secondary" style="font-size:.73rem;padding:4px 10px;">↺ Zurücksetzen</button>
</form>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if ($canEdit): ?>
<div id="add-form" class="add-form hidden">
<form method="POST" style="display:contents;">
<input type="text" name="name" placeholder="Was packen? *" required style="min-width:180px;">
<input type="text" name="menge" placeholder="Menge (z.B. 2x)" style="max-width:100px;">
<select name="kat">
<?php foreach ($PACKEN_KATEGORIEN as $k => $v): ?>
<option value="<?= $k ?>"><?= $v['icon'] ?> <?= $v['label'] ?></option>
<?php endforeach; ?>
</select>
<select name="assigned_to">
<option value="">Für wen?</option>
<?php foreach ($members as $m): ?>
<option value="<?= $m['id'] ?>"><?= h($m['name']) ?></option>
<?php endforeach; ?>
</select>
<button type="submit" name="add" class="btn btn-primary">Hinzufügen</button>
</form>
</div>
<?php endif; ?>
<?php if (empty($items)): ?>
<div class="empty"><div class="empty-icon">🧳</div><p>Noch nichts auf der Packliste.</p></div>
<?php else: ?>
<?php foreach ($grouped as $kat => $katItems):
$katInfo = $PACKEN_KATEGORIEN[$kat] ?? ['icon' => '📦', 'label' => ucfirst($kat)];
$katPacked = count(array_filter($katItems, fn($i) => $i['packed']));
?>
<div class="pack-group">
<div class="pack-group-header">
<span><?= $katInfo['icon'] ?> <?= $katInfo['label'] ?></span>
<span class="pack-group-count"><?= $katPacked ?>/<?= count($katItems) ?></span>
</div>
<div class="todo-list">
<?php foreach ($katItems as $item): ?>
<div class="todo-item <?= $item['packed'] ? 'done' : '' ?>">
<form method="POST" class="todo-check-form">
<button type="submit" name="toggle" value="<?= $item['id'] ?>" class="todo-check <?= $item['packed'] ? 'checked' : '' ?>"></button>
</form>
<div class="todo-content">
<div class="todo-row1">
<span class="todo-text"><?= h($item['name']) ?></span>
<?php if ($item['menge']): ?>
<span class="badge-menge"><?= h($item['menge']) ?></span>
<?php endif; ?>
<?php if ($item['assigned_name']): ?>
<span class="who-badge" style="background:<?= h($item['assigned_farbe']) ?>22;color:<?= h($item['assigned_farbe']) ?>;border:1.5px solid <?= h($item['assigned_farbe']) ?>55;"><?= h($item['assigned_name']) ?></span>
<?php endif; ?>
</div>
</div>
<?php if ($canEdit): ?>
<form method="POST">
<button type="submit" name="delete" value="<?= $item['id'] ?>" class="btn-delete" onclick="return confirm('Löschen?')">✕</button>
</form>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</main>
<?php include __DIR__ . '/includes/footer.php'; ?>