Fix: Gewichtsberechnung Zusatztaschen, UI-Konsistenz bei Editieren, Icons
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 23s

This commit is contained in:
Gemini Agent
2025-12-07 07:52:03 +00:00
parent 967bae965a
commit 70eef4cd82

View File

@@ -12,7 +12,7 @@ if (!isset($_SESSION['user_id'])) {
require_once 'db_connect.php';
require_once 'household_actions.php';
require_once 'backpack_utils.php'; // Fix: Include utils
require_once 'backpack_utils.php';
require_once 'header.php';
$current_user_id = $_SESSION['user_id'];
@@ -91,55 +91,59 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
$packing_list['name'] = $name;
$packing_list['description'] = $description;
// Handle Backpack Assignments
if (isset($_POST['backpacks'])) {
foreach ($_POST['backpacks'] as $uid => $bid) {
$uid = intval($uid);
$bid = intval($bid);
// 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;
// Update Carrier Table
// Check if exists
$old_backpack_id = 0;
$stmt_chk = $conn->prepare("SELECT id, backpack_id FROM packing_list_carriers WHERE packing_list_id = ? AND user_id = ?");
$stmt_chk->bind_param("ii", $packing_list_id, $uid);
$stmt_chk->execute();
$res_chk = $stmt_chk->get_result();
if ($row_chk = $res_chk->fetch_assoc()) {
$old_backpack_id = $row_chk['backpack_id'];
$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();
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();
}
// CLEANUP LOGIC: If backpack changed or removed
if ($old_backpack_id != $bid) {
// 1. Unparent all items that are inside the old containers (so they don't get deleted)
// Find all container items for this user
$stmt_find_containers = $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_find_containers->bind_param("ii", $packing_list_id, $uid);
$stmt_find_containers->execute();
$res_cont = $stmt_find_containers->get_result();
$container_ids = [];
while ($r = $res_cont->fetch_assoc()) $container_ids[] = $r['id'];
if (!empty($container_ids)) {
$ids_str = implode(',', $container_ids);
// 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 = $packing_list_id AND parent_packing_list_item_id IN ($ids_str)");
// 2. Delete the containers
$conn->query("DELETE FROM packing_list_items WHERE id IN ($ids_str)");
if ($bid) {
sync_backpack_items($conn, $packing_list_id, $uid, $bid);
}
}
// SYNC LOGIC (Only if new backpack assigned)
if ($bid && $old_backpack_id != $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");
}
}
}
@@ -154,6 +158,26 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
}
}
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)");
}
}
?>
<div class="card">
@@ -165,7 +189,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
<?php echo $message; ?>
<?php if ($packing_list): ?>
<form method="post">
<form method="post" id="editListForm">
<div class="row">
<div class="col-md-8">
<h5 class="mb-3">Basisdaten</h5>
@@ -180,35 +204,41 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
</div>
<div class="col-md-4">
<h5 class="mb-3">Rucksack-Zuweisung</h5>
<h5 class="mb-3">Teilnehmer & Rucksäcke</h5>
<div class="card bg-light border-0">
<div class="card-body">
<p class="small text-muted">Wähle hier, wer welchen Rucksack trägt. Bereits vergebene Rucksäcke werden ausgeblendet.</p>
<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
// Calculate used backpacks
$all_assigned_backpack_ids = array_values($current_assignments);
// Prepare data for JS (still needed for the render helper)
$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;
// Store for JS
$user_backpacks_json[$user['id']] = [
'current_id' => $my_current_bp_id,
'backpacks' => $user_backpacks
];
// Use helper to render the widget
echo '<div class="mb-4 border-bottom pb-3">';
echo '<label class="form-label fw-bold mb-2">' . htmlspecialchars($user['username']) . '</label>';
echo render_backpack_card_selector($user, $my_current_bp_id, $user_backpacks);
echo '</div>';
endforeach;
?>
<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>
@@ -218,7 +248,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
<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"><i class="fas fa-save me-2"></i>Speichern & Synchronisieren</button>
<button type="submit" class="btn btn-primary" id="submitBtn"><i class="fas fa-save me-2"></i>Speichern & Synchronisieren</button>
</div>
</form>
<?php endif; ?>
@@ -228,4 +258,63 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
<!-- 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'; ?>