276 lines
12 KiB
PHP
276 lines
12 KiB
PHP
<?php
|
||
use PDO;
|
||
|
||
if (!isset($_SESSION['user_id'])) {
|
||
redirect('/login');
|
||
}
|
||
|
||
$app = app();
|
||
$pdo = $app->pdo();
|
||
$flash = $app->flash()->get();
|
||
$userId = (int)$_SESSION['user_id'];
|
||
$error = '';
|
||
$info = '';
|
||
|
||
// POST Aktionen
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$action = $_POST['action'] ?? '';
|
||
try {
|
||
if ($action === 'profile') {
|
||
$stmt = $pdo->prepare('UPDATE user_profiles SET display_name=:name, zip=:zip, city=:city, profession=:prof, languages=:langs, about=:about, updated_at=NOW() WHERE user_id=:id');
|
||
$stmt->execute([
|
||
'name' => trim((string)$_POST['display_name']),
|
||
'zip' => trim((string)$_POST['zip']),
|
||
'city' => trim((string)$_POST['city']),
|
||
'prof' => trim((string)$_POST['profession']),
|
||
'langs' => trim((string)$_POST['languages']),
|
||
'about' => trim((string)$_POST['about']),
|
||
'id' => $userId,
|
||
]);
|
||
$info = 'Profil gespeichert.';
|
||
} elseif ($action === 'child_add') {
|
||
$stmt = $pdo->prepare('INSERT INTO children (user_id, gender, birthdate, age_years, encrypted_first_name, note, created_at, updated_at) VALUES (:uid, :gender, :birthdate, :age, :name, :note, NOW(), NOW())');
|
||
$stmt->execute([
|
||
'uid' => $userId,
|
||
'gender' => $_POST['gender'] ?? 'unknown',
|
||
'birthdate' => $_POST['birthdate'] ?: null,
|
||
'age' => $_POST['age_years'] ?: null,
|
||
'name' => trim((string)$_POST['first_name']),
|
||
'note' => trim((string)$_POST['note']),
|
||
]);
|
||
$info = 'Kind hinzugefügt.';
|
||
} elseif ($action === 'event_add') {
|
||
$stmt = $pdo->prepare('INSERT INTO events (created_by, title, teaser_public, description, location_label, zip, city, region, lat, lng, starts_at, allow_kids, visibility, status, created_at, updated_at) VALUES (:uid, :title, :teaser, :descr, :loc, :zip, :city, :region, NULL, NULL, :start, :allow, :vis, :status, NOW(), NOW())');
|
||
$stmt->execute([
|
||
'uid' => $userId,
|
||
'title' => trim((string)$_POST['title']),
|
||
'teaser' => trim((string)$_POST['teaser']),
|
||
'descr' => trim((string)$_POST['description']),
|
||
'loc' => trim((string)$_POST['location_label']),
|
||
'zip' => trim((string)$_POST['zip']),
|
||
'city' => trim((string)$_POST['city']),
|
||
'region' => trim((string)$_POST['region']),
|
||
'start' => $_POST['starts_at'] ?? null,
|
||
'allow' => isset($_POST['allow_kids']) ? 1 : 0,
|
||
'vis' => $_POST['visibility'] ?? 'public',
|
||
'status' => 'published',
|
||
]);
|
||
$info = 'Event gespeichert.';
|
||
}
|
||
} catch (Throwable $e) {
|
||
$error = $e->getMessage();
|
||
}
|
||
}
|
||
|
||
// Daten laden
|
||
$profile = [
|
||
'display_name' => '',
|
||
'zip' => '',
|
||
'city' => '',
|
||
'profession' => '',
|
||
'languages' => '',
|
||
'about' => '',
|
||
];
|
||
$stmt = $pdo->prepare('SELECT u.email, u.status, p.display_name, p.zip, p.city, p.profession, p.languages, p.about FROM users u LEFT JOIN user_profiles p ON p.user_id = u.id WHERE u.id = :id LIMIT 1');
|
||
$stmt->execute(['id' => $userId]);
|
||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
if ($row) {
|
||
$profile = array_merge($profile, array_filter($row, fn($v) => $v !== null));
|
||
}
|
||
|
||
$children = [];
|
||
$stmt = $pdo->prepare('SELECT id, encrypted_first_name AS first_name, gender, birthdate, age_years FROM children WHERE user_id = :id ORDER BY id DESC');
|
||
$stmt->execute(['id' => $userId]);
|
||
$children = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||
|
||
$events = [];
|
||
$stmt = $pdo->prepare('SELECT id, title, teaser_public, starts_at, city, visibility FROM events WHERE created_by = :id ORDER BY starts_at DESC');
|
||
$stmt->execute(['id' => $userId]);
|
||
$events = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||
?>
|
||
<main class="section">
|
||
<div class="container" style="display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px;">
|
||
<div>
|
||
<p class="eyebrow">Mitgliederbereich</p>
|
||
<h1>Hallo, <span style="color: var(--color-primary);"><?= htmlspecialchars($profile['display_name'] ?: 'Papa', ENT_QUOTES) ?></span>!</h1>
|
||
<p class="muted">Verwalte dein Profil, Kinder, Events und Teilnahmen.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container dash-section">
|
||
<?php if ($flash): ?>
|
||
<div class="toast-bar"><?= htmlspecialchars($flash['message'], ENT_QUOTES) ?></div>
|
||
<?php endif; ?>
|
||
<?php if ($info): ?>
|
||
<div class="toast-bar" style="margin-top:10px;"><?= htmlspecialchars($info, ENT_QUOTES) ?></div>
|
||
<?php endif; ?>
|
||
<?php if ($error): ?>
|
||
<div class="toast-bar" style="margin-top:10px; border-color:#f87171; color:#991b1b;">Fehler: <?= htmlspecialchars($error, ENT_QUOTES) ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<div class="container dash-section">
|
||
<div class="dash-grid-2">
|
||
<div class="card dash-card">
|
||
<div class="badge">Profil</div>
|
||
<h3>Deine Angaben</h3>
|
||
<form method="post" class="stack gap-12">
|
||
<input type="hidden" name="action" value="profile">
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="pName">Anzeigename</label>
|
||
<input id="pName" name="display_name" class="input" value="<?= htmlspecialchars($profile['display_name'], ENT_QUOTES) ?>">
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="pCity">Ort</label>
|
||
<input id="pCity" name="city" class="input" value="<?= htmlspecialchars($profile['city'], ENT_QUOTES) ?>">
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="pZip">PLZ</label>
|
||
<input id="pZip" name="zip" class="input" value="<?= htmlspecialchars($profile['zip'], ENT_QUOTES) ?>">
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="pProf">Beruf</label>
|
||
<input id="pProf" name="profession" class="input" value="<?= htmlspecialchars($profile['profession'], ENT_QUOTES) ?>">
|
||
</div>
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="pLang">Sprachen</label>
|
||
<input id="pLang" name="languages" class="input" value="<?= htmlspecialchars($profile['languages'], ENT_QUOTES) ?>">
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="pAbout">Kurzvorstellung</label>
|
||
<textarea id="pAbout" name="about" class="textarea" rows="3"><?= htmlspecialchars($profile['about'], ENT_QUOTES) ?></textarea>
|
||
</div>
|
||
<button class="btn" type="submit">Speichern</button>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card dash-card">
|
||
<div class="badge">Kinder</div>
|
||
<h3>Deine Kids</h3>
|
||
<?php if (!$children): ?>
|
||
<p class="muted small">Noch keine Kinder eingetragen.</p>
|
||
<?php else: ?>
|
||
<ul class="dash-list">
|
||
<?php foreach ($children as $c): ?>
|
||
<li><?= htmlspecialchars($c['first_name'], ENT_QUOTES) ?>, <?= htmlspecialchars($c['gender'], ENT_QUOTES) ?> <?= $c['age_years'] ? '(' . (int)$c['age_years'] . ' Jahre)' : '' ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
<form method="post" class="stack gap-12" style="margin-top:12px;">
|
||
<input type="hidden" name="action" value="child_add">
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="cName">Vorname</label>
|
||
<input id="cName" name="first_name" class="input" required>
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="cGender">Geschlecht</label>
|
||
<select id="cGender" name="gender" class="select">
|
||
<option value="male">Männlich</option>
|
||
<option value="female">Weiblich</option>
|
||
<option value="diverse">Divers</option>
|
||
<option value="unknown">Unbekannt</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="cBirth">Geburtsdatum</label>
|
||
<input id="cBirth" name="birthdate" class="input" type="date">
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="cAge">Alter (Jahre)</label>
|
||
<input id="cAge" name="age_years" class="input" type="number" min="0" max="18">
|
||
</div>
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="cNote">Notiz</label>
|
||
<input id="cNote" name="note" class="input">
|
||
</div>
|
||
<button class="btn" type="submit">Kind hinzufügen</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container dash-section">
|
||
<div class="card dash-card">
|
||
<div class="badge">Deine Events</div>
|
||
<?php if (!$events): ?>
|
||
<p class="muted small">Noch keine Events angelegt.</p>
|
||
<?php else: ?>
|
||
<ul class="dash-list">
|
||
<?php foreach ($events as $e): ?>
|
||
<li><?= htmlspecialchars($e['title'], ENT_QUOTES) ?> – <?= htmlspecialchars($e['city'], ENT_QUOTES) ?>, <?= htmlspecialchars($e['starts_at'], ENT_QUOTES) ?> (<?= htmlspecialchars($e['visibility'], ENT_QUOTES) ?>)</li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container dash-section" id="events">
|
||
<div class="card dash-card">
|
||
<div class="badge">Eigenes Event</div>
|
||
<h3>Neuen Termin erstellen</h3>
|
||
<form class="stack gap-12" style="margin-top: 10px;" method="post" action="/dashboard#events">
|
||
<input type="hidden" name="action" value="event_add">
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evTitle">Titel</label>
|
||
<input id="evTitle" name="title" class="input" placeholder="z. B. Väter-Kaffee im Park" required>
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evTeaser">Kurzbeschreibung</label>
|
||
<input id="evTeaser" name="teaser" class="input" placeholder="Kurztext für Gäste" required>
|
||
</div>
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evDesc">Beschreibung (voll)</label>
|
||
<textarea id="evDesc" name="description" class="textarea" rows="3" placeholder="Was soll passieren, was mitbringen?" required></textarea>
|
||
</div>
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evDate">Datum & Uhrzeit</label>
|
||
<input id="evDate" name="starts_at" class="input" type="datetime-local" required>
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evLoc">Ort/Label</label>
|
||
<input id="evLoc" name="location_label" class="input" placeholder="Park / Café">
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evZip">PLZ</label>
|
||
<input id="evZip" name="zip" class="input" maxlength="5">
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evCity">Stadt</label>
|
||
<input id="evCity" name="city" class="input">
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evRegion">Region/Bezirk</label>
|
||
<input id="evRegion" name="region" class="input">
|
||
</div>
|
||
<div class="stack gap-6">
|
||
<label class="label" for="evVis">Sichtbarkeit</label>
|
||
<select id="evVis" name="visibility" class="select">
|
||
<option value="public">Öffentlich</option>
|
||
<option value="members">Nur Mitglieder</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<label class="label" style="display:flex; align-items:center; gap:8px;">
|
||
<input type="checkbox" name="allow_kids" checked> Kinder erlaubt
|
||
</label>
|
||
<button class="btn" type="submit">Event anlegen</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</main>
|