Rucksack-Feature finalisiert: Management, Zuweisung und Anzeige implementiert

This commit is contained in:
Gemini Agent
2025-12-04 19:55:38 +00:00
parent 17fb54193f
commit eab7de42a4
224 changed files with 1609 additions and 679 deletions

223
index.php
View File

@@ -1,223 +0,0 @@
<?php
// index.php - Startseite der Trekking Packlisten Anwendung
// KORREKTUR: Farbpalette für die Diagramme für bessere Lesbarkeit überarbeitet.
$page_title = "Dashboard";
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit;
}
require_once 'db_connect.php';
require_once 'header.php';
$current_user_id = $_SESSION['user_id'];
$current_username = $_SESSION['username'];
// --- Lade Haushalts-Informationen ---
$stmt_household = $conn->prepare("SELECT household_id FROM users WHERE id = ?");
$stmt_household->bind_param("i", $current_user_id);
$stmt_household->execute();
$current_user_household_id = $stmt_household->get_result()->fetch_assoc()['household_id'];
$stmt_household->close();
$household_member_ids = [$current_user_id];
if ($current_user_household_id) {
$stmt_members = $conn->prepare("SELECT id FROM users WHERE household_id = ?");
$stmt_members->bind_param("i", $current_user_household_id);
$stmt_members->execute();
$result_members = $stmt_members->get_result();
while ($row = $result_members->fetch_assoc()) {
if (!in_array($row['id'], $household_member_ids)) {
$household_member_ids[] = $row['id'];
}
}
$stmt_members->close();
}
$placeholders = implode(',', array_fill(0, count($household_member_ids), '?'));
$types = str_repeat('i', count($household_member_ids));
// --- Daten für die Statistik-Boxen laden ---
$articles_by_category = [];
$sql_articles_by_category = "SELECT c.name AS category_name, COUNT(a.id) AS article_count FROM articles a LEFT JOIN categories c ON a.category_id = c.id WHERE a.user_id IN ($placeholders) OR a.household_id = ? GROUP BY c.name ORDER BY article_count DESC";
$stmt_articles_by_category = $conn->prepare($sql_articles_by_category);
if ($stmt_articles_by_category) {
$all_params = array_merge($household_member_ids, [$current_user_household_id]);
$all_types = $types . 'i';
$stmt_articles_by_category->bind_param($all_types, ...$all_params);
$stmt_articles_by_category->execute();
$result_articles_by_category = $stmt_articles_by_category->get_result();
while ($row = $result_articles_by_category->fetch_assoc()) {
$articles_by_category[] = [
'category_name' => $row['category_name'] ?: 'Ohne Kategorie',
'article_count' => $row['article_count']
];
}
$stmt_articles_by_category->close();
}
$packing_lists_stats = [];
$sql_lists = "SELECT pl.id, pl.name, SUM(pli.quantity * a.weight_grams) AS total_weight FROM packing_lists pl LEFT JOIN packing_list_items pli ON pl.id = pli.packing_list_id LEFT JOIN articles a ON pli.article_id = a.id WHERE pl.user_id IN ($placeholders) OR pl.household_id = ? GROUP BY pl.id, pl.name ORDER BY total_weight DESC";
$stmt_lists = $conn->prepare($sql_lists);
if ($stmt_lists) {
$all_params = array_merge($household_member_ids, [$current_user_household_id]);
$all_types = $types . 'i';
$stmt_lists->bind_param($all_types, ...$all_params);
$stmt_lists->execute();
$result_lists = $stmt_lists->get_result();
while ($row = $result_lists->fetch_assoc()) {
$packing_lists_stats[] = [
'packing_list_id' => $row['id'],
'packing_list_name' => htmlspecialchars($row['name']),
'total_weight_grams' => $row['total_weight'] ?: 0
];
}
$stmt_lists->close();
}
$conn->close();
// Daten für die Diagramme vorbereiten
$category_chart_labels = json_encode(array_column($articles_by_category, 'category_name'));
$category_chart_data = json_encode(array_column($articles_by_category, 'article_count'));
$list_chart_labels = json_encode(array_column($packing_lists_stats, 'packing_list_name'));
$list_chart_data = json_encode(array_column($packing_lists_stats, 'total_weight_grams'));
$quotes = ["Nur wo du zu Fuß warst, bist du auch wirklich gewesen.", "Der Weg ist das Ziel.", "Abenteuer beginnen, wo Pläne enden."];
$random_quote = $quotes[array_rand($quotes)];
?>
<div class="card p-4 border-0 shadow-sm">
<div class="welcome-section">
<h1>Willkommen zurück, <strong><?php echo htmlspecialchars($current_username); ?></strong>!</h1>
<p class="lead">Organisiere deine Ausrüstung und bereite dich optimal auf dein nächstes Abenteuer vor.</p>
<div class="welcome-image-container">
<div class="animated-bg"></div>
</div>
<p class="text-muted fst-italic mt-4">"<?php echo $random_quote; ?>"</p>
</div>
<hr class="my-5" style="opacity: 0.1;">
<div class="row g-4">
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header"><h3 class="h5 mb-0"><i class="fas fa-chart-pie me-2"></i>Artikelverteilung im Haushalt</h3></div>
<div class="card-body d-flex align-items-center justify-content-center">
<?php if (empty($articles_by_category)): ?>
<p class="text-center text-muted p-4">Füge Artikel hinzu, um hier eine Übersicht zu sehen.</p>
<?php else: ?>
<div class="chart-container w-100">
<canvas id="categoryChart"></canvas>
</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header"><h3 class="h5 mb-0"><i class="fas fa-chart-bar me-2"></i>Gewicht pro Packliste im Haushalt (g)</h3></div>
<div class="card-body d-flex align-items-center justify-content-center">
<?php if (empty($packing_lists_stats)): ?>
<p class="text-center text-muted p-4">Erstelle eine Packliste, um hier eine Analyse zu sehen.</p>
<?php else: ?>
<div class="chart-container w-100">
<canvas id="listWeightChart"></canvas>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
// KORREKTUR: Neue, kontrastreichere Farbpalette
const chartColors = [
'#4CAF50', '#2196F3', '#FFC107', '#E91E63', '#9C27B0',
'#00BCD4', '#FF5722', '#795548', '#607D8B', '#F44336'
];
const categoryCtx = document.getElementById('categoryChart');
if (categoryCtx && <?php echo $category_chart_data; ?>.length > 0) {
new Chart(categoryCtx, {
type: 'doughnut',
data: {
labels: <?php echo $category_chart_labels; ?>,
datasets: [{
label: 'Anzahl Artikel',
data: <?php echo $category_chart_data; ?>,
backgroundColor: chartColors,
hoverOffset: 4,
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
usePointStyle: true,
padding: 20
}
}
},
cutout: '70%'
}
});
}
const listWeightCtx = document.getElementById('listWeightChart');
if (listWeightCtx && <?php echo $list_chart_data; ?>.length > 0) {
new Chart(listWeightCtx, {
type: 'bar',
data: {
labels: <?php echo $list_chart_labels; ?>,
datasets: [{
label: 'Gesamtgewicht in Gramm',
data: <?php echo $list_chart_data; ?>,
backgroundColor: 'rgba(107, 142, 35, 0.8)', // Using primary light color
borderColor: 'rgba(59, 74, 35, 1)',
borderWidth: 1,
borderRadius: 4
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
beginAtZero: true,
grid: {
display: false
}
},
y: {
grid: {
color: 'rgba(0,0,0,0.05)'
}
}
},
plugins: {
legend: {
display: false
}
}
}
});
}
});
</script>
<?php require_once 'footer.php'; ?>