Fix: Verstecke ToDo-Auswahl bei Packlistenvorlagen in den Einstellungen
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 38s

This commit is contained in:
Gemini
2026-05-13 20:10:50 +00:00
parent 0ba5399c86
commit c001ea6f62

View File

@@ -1,365 +0,0 @@
<?php
// edit_packing_list_details.php - Bearbeiten von Details und Rucksack-Zuweisung
$page_title = "Packliste Details bearbeiten";
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 'household_actions.php';
require_once 'backpack_utils.php';
require_once 'header.php';
$current_user_id = $_SESSION['user_id'];
$packing_list_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$message = '';
$packing_list = null;
$can_edit = false;
// --- 1. Permissions & Basic Data ---
if ($packing_list_id > 0) {
$stmt_household_check = $conn->prepare("SELECT household_id FROM users WHERE id = ?");
$stmt_household_check->bind_param("i", $current_user_id);
$stmt_household_check->execute();
$current_user_household_id = $stmt_household_check->get_result()->fetch_assoc()['household_id'];
$stmt_household_check->close();
$stmt_list_check = $conn->prepare("SELECT id, name, description, user_id, household_id, is_template, todo_list_id FROM packing_lists WHERE id = ?");
$stmt_list_check->bind_param("i", $packing_list_id);
$stmt_list_check->execute();
$result = $stmt_list_check->get_result();
if ($result->num_rows == 1) {
$packing_list = $result->fetch_assoc();
$is_owner = ($packing_list['user_id'] == $current_user_id);
$is_household_list = !empty($packing_list['household_id']);
$is_in_same_household = ($is_household_list && $packing_list['household_id'] == $current_user_household_id);
if ($is_owner || $is_in_same_household) {
$can_edit = true;
} else {
$message = '<div class="alert alert-danger">Keine Berechtigung.</div>';
$packing_list = null;
}
} else {
$message = '<div class="alert alert-warning">Packliste nicht gefunden.</div>';
}
} else {
$message = '<div class="alert alert-danger">Keine ID.</div>';
}
// --- 2. Fetch Data for Dropdowns ---
$available_users = [];
$available_todo_lists = [];
if ($can_edit) {
// Owners: Creator + Household Members (if shared)
if ($packing_list['household_id']) {
$stmt = $conn->prepare("SELECT id, COALESCE(NULLIF(display_name, ''), username) AS username FROM users WHERE household_id = ?");
$stmt->bind_param("i", $packing_list['household_id']);
} else {
$stmt = $conn->prepare("SELECT id, COALESCE(NULLIF(display_name, ''), username) AS username FROM users WHERE id = ?");
$stmt->bind_param("i", $packing_list['user_id']);
}
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$available_users[] = $row;
}
// Fetch Todo Lists
$stmt_tl = $conn->prepare("SELECT id, name FROM todo_lists WHERE user_id = ? OR (household_id IS NOT NULL AND household_id = ?)");
$stmt_tl->bind_param("ii", $current_user_id, $current_user_household_id);
$stmt_tl->execute();
$res_tl = $stmt_tl->get_result();
while ($row = $res_tl->fetch_assoc()) {
$available_todo_lists[] = $row;
}
$stmt_tl->close();
// Current Assignments
$current_assignments = [];
$stmt_ca = $conn->prepare("SELECT user_id, backpack_id FROM packing_list_carriers WHERE packing_list_id = ?");
$stmt_ca->bind_param("i", $packing_list_id);
$stmt_ca->execute();
$res_ca = $stmt_ca->get_result();
while ($row = $res_ca->fetch_assoc()) {
$current_assignments[$row['user_id']] = $row['backpack_id'];
}
}
// --- 3. Handle Form Submission ---
if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
// Update Basic Details
$name = trim($_POST['name']);
$description = trim($_POST['description']);
// Household sharing logic
$new_household_id = NULL;
if (isset($_POST['is_household_list']) && $_POST['is_household_list'] == '1' && $current_user_household_id) {
$new_household_id = $current_user_household_id;
}
$todo_list_id = !empty($_POST['todo_list_id']) ? intval($_POST['todo_list_id']) : NULL;
$stmt_update = $conn->prepare("UPDATE packing_lists SET name = ?, description = ?, household_id = ?, todo_list_id = ? WHERE id = ?");
$stmt_update->bind_param("sssii", $name, $description, $new_household_id, $todo_list_id, $packing_list_id);
$stmt_update->execute();
$packing_list['name'] = $name;
$packing_list['description'] = $description;
$packing_list['household_id'] = $new_household_id;
$packing_list['todo_list_id'] = $todo_list_id;
// Handle Participation & Backpacks
// Get all potential users to check if they were unchecked
$participate_map = $_POST['participate'] ?? []; // Array of UserID => "1" if checked
foreach ($available_users as $user) {
$uid = $user['id'];
$is_checked = isset($participate_map[$uid]);
$was_participating = array_key_exists($uid, $current_assignments);
if ($is_checked) {
// User participates -> Update/Insert Backpack
$bid = isset($_POST['backpacks'][$uid]) ? intval($_POST['backpacks'][$uid]) : 0;
$bid = ($bid > 0) ? $bid : NULL;
if ($was_participating) {
$old_bid = $current_assignments[$uid];
// Update if changed
if ($old_bid != $bid) {
$stmt_up = $conn->prepare("UPDATE packing_list_carriers SET backpack_id = ? WHERE packing_list_id = ? AND user_id = ?");
$stmt_up->bind_param("iii", $bid, $packing_list_id, $uid);
$stmt_up->execute();
// Cleanup Old Containers
cleanup_old_backpack_containers($conn, $packing_list_id, $uid);
// Sync New
if ($bid) {
sync_backpack_items($conn, $packing_list_id, $uid, $bid);
}
}
} else {
// New Participant
$stmt_in = $conn->prepare("INSERT INTO packing_list_carriers (packing_list_id, user_id, backpack_id) VALUES (?, ?, ?)");
$stmt_in->bind_param("iii", $packing_list_id, $uid, $bid);
$stmt_in->execute();
if ($bid) {
sync_backpack_items($conn, $packing_list_id, $uid, $bid);
}
}
} else {
// User NOT checked -> Remove if existed
if ($was_participating) {
$conn->query("DELETE FROM packing_list_carriers WHERE packing_list_id = $packing_list_id AND user_id = $uid");
// Cleanup Items: Delete all items carried by this user?
// Or move to unassigned? Let's move to unassigned (NULL) to be safe against data loss.
// But Containers (Backpacks) should be deleted.
// 1. Delete Containers
cleanup_old_backpack_containers($conn, $packing_list_id, $uid);
// 2. Move remaining items (loose items) to unassigned?
$conn->query("UPDATE packing_list_items SET carrier_user_id = NULL WHERE packing_list_id = $packing_list_id AND carrier_user_id = $uid");
}
}
}
$message = '<div class="alert alert-success">Änderungen gespeichert!</div>';
// Refresh assignments
$stmt_ca->execute();
$res_ca = $stmt_ca->get_result();
$current_assignments = [];
while ($row = $res_ca->fetch_assoc()) {
$current_assignments[$row['user_id']] = $row['backpack_id'];
}
}
function cleanup_old_backpack_containers($conn, $list_id, $user_id) {
// Find all container items for this user (backpacks or compartments)
$stmt = $conn->prepare("SELECT id FROM packing_list_items WHERE packing_list_id = ? AND carrier_user_id = ? AND (backpack_id IS NOT NULL OR backpack_compartment_id IS NOT NULL)");
$stmt->bind_param("ii", $list_id, $user_id);
$stmt->execute();
$res = $stmt->get_result();
$container_ids = [];
while ($r = $res->fetch_assoc()) $container_ids[] = $r['id'];
if (!empty($container_ids)) {
$ids_str = implode(',', $container_ids);
// Unparent children so they don't get deleted (or keep them and they get deleted? No, save content)
// Set parent to NULL for children of these containers
$conn->query("UPDATE packing_list_items SET parent_packing_list_item_id = NULL WHERE packing_list_id = $list_id AND parent_packing_list_item_id IN ($ids_str)");
// Delete containers
$conn->query("DELETE FROM packing_list_items WHERE id IN ($ids_str)");
}
}
$back_link = 'packing_lists.php' . (!empty($packing_list['is_template']) ? '?view=templates' : '');
$page_headline = !empty($packing_list['is_template']) ? 'Vorlage bearbeiten' : 'Details bearbeiten';
?>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h2 class="h4 mb-0"><?php echo $page_headline; ?>: <?php echo htmlspecialchars($packing_list['name'] ?? ''); ?></h2>
<a href="<?php echo $back_link; ?>" class="btn btn-sm btn-outline-light"><i class="fas fa-arrow-left me-2"></i>Zurück</a>
</div>
<div class="card-body p-4">
<?php echo $message; ?>
<?php if ($packing_list): ?>
<form method="post" id="editListForm">
<div class="row">
<div class="col-md-8">
<h5 class="mb-3">Basisdaten</h5>
<div class="mb-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" name="name" value="<?php echo htmlspecialchars($packing_list['name']); ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Beschreibung</label>
<textarea class="form-control" name="description" rows="3"><?php echo htmlspecialchars($packing_list['description'] ?: ''); ?></textarea>
</div>
<div class="mb-4">
<label for="todo_list_id" class="form-label fw-bold">ToDo-Liste (optional)</label>
<select class="form-select" id="todo_list_id" name="todo_list_id">
<option value="">-- Keine ToDo-Liste --</option>
<?php foreach ($available_todo_lists as $tl): ?>
<option value="<?php echo $tl['id']; ?>" <?php if (($packing_list['todo_list_id'] ?? null) == $tl['id']) echo 'selected'; ?>>
<?php echo htmlspecialchars($tl['name']); ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text">Verknüpfe eine ToDo-Liste mit dieser Packliste.</div>
</div>
<?php if ($current_user_household_id): ?>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="is_household_list" name="is_household_list" value="1" <?php echo !empty($packing_list['household_id']) ? 'checked' : ''; ?>>
<label class="form-check-label" for="is_household_list">Für den gesamten Haushalt freigeben</label>
</div>
<?php endif; ?>
</div>
<div class="col-md-4">
<h5 class="mb-3">Teilnehmer & Rucksäcke <?php if(!empty($packing_list['is_template'])): ?><small class="text-muted">(Standard)</small><?php endif; ?></h5>
<div class="card bg-light border-0">
<div class="card-body">
<p class="small text-muted">Wähle hier, wer mitkommt und welchen Rucksack er trägt.</p>
<div id="backpack-warning" class="alert alert-warning d-none small p-2 mb-2">
<i class="fas fa-exclamation-triangle me-1"></i> Ein Rucksack wurde mehrfach ausgewählt!
</div>
<?php
$all_assigned_backpack_ids = array_values($current_assignments);
$user_backpacks_json = [];
foreach ($available_users as $user):
$user_backpacks = get_available_backpacks_for_user($conn, $user['id'], $packing_list['household_id']);
$is_participating = array_key_exists($user['id'], $current_assignments);
$my_current_bp_id = $current_assignments[$user['id']] ?? 0;
$user_backpacks_json[$user['id']] = [
'current_id' => $my_current_bp_id,
'backpacks' => $user_backpacks
];
?>
<div class="mb-4 border-bottom pb-3">
<div class="form-check mb-2">
<input class="form-check-input participation-check" type="checkbox" name="participate[<?php echo $user['id']; ?>]" value="1" <?php echo $is_participating ? 'checked' : ''; ?> id="part_<?php echo $user['id']; ?>">
<label class="form-check-label fw-bold" for="part_<?php echo $user['id']; ?>">
<?php echo htmlspecialchars($user['username']); ?>
</label>
</div>
<div class="ms-4 backpack-selector-wrapper" style="<?php echo $is_participating ? '' : 'opacity: 0.5; pointer-events: none;'; ?>">
<?php echo render_backpack_card_selector($user, $my_current_bp_id, $user_backpacks); ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
<hr class="my-4">
<div class="d-flex justify-content-between">
<a href="manage_packing_list_items.php?id=<?php echo $packing_list_id; ?>" class="btn btn-info text-white"><i class="fas fa-boxes me-2"></i>Inhalt bearbeiten</a>
<button type="submit" class="btn btn-primary" id="submitBtn"><i class="fas fa-save me-2"></i>Speichern & Synchronisieren</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
<!-- Render Modal JS -->
<?php echo render_backpack_modal_script($user_backpacks_json, $all_assigned_backpack_ids); ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
const submitBtn = document.getElementById('submitBtn');
const warning = document.getElementById('backpack-warning');
// Toggle Opacity logic
document.querySelectorAll('.participation-check').forEach(chk => {
chk.addEventListener('change', function() {
const wrapper = this.closest('.mb-4').querySelector('.backpack-selector-wrapper');
if (this.checked) {
wrapper.style.opacity = '1';
wrapper.style.pointerEvents = 'auto';
} else {
wrapper.style.opacity = '0.5';
wrapper.style.pointerEvents = 'none';
}
validateBackpacks();
});
});
// Validation Logic (Copied from add_packing_list.php)
function validateBackpacks() {
const selected = [];
let hasDuplicate = false;
const inputs = document.querySelectorAll('input[name^="backpacks["]');
inputs.forEach(input => {
const userIdMatch = input.name.match(/backpacks\[(\d+)\]/);
if (userIdMatch) {
const userId = userIdMatch[1];
const partCheck = document.getElementById('part_' + userId);
if (partCheck && partCheck.checked) {
const val = parseInt(input.value);
if (val > 0) {
if (selected.includes(val)) {
hasDuplicate = true;
}
selected.push(val);
}
}
}
});
if (hasDuplicate) {
warning.classList.remove('d-none');
submitBtn.disabled = true;
} else {
warning.classList.add('d-none');
submitBtn.disabled = false;
}
}
document.body.addEventListener('hidden.bs.modal', validateBackpacks);
validateBackpacks();
});
</script>
<?php require_once 'footer.php'; ?>