Feat: Enhanced backpack selection UI in add/edit packing list and fixed tree toggle
This commit is contained in:
@@ -59,20 +59,35 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
if ($stmt->execute()) {
|
||||
$new_list_id = $conn->insert_id;
|
||||
|
||||
// Handle Backpacks
|
||||
if (isset($_POST['backpacks'])) {
|
||||
foreach ($_POST['backpacks'] as $uid => $bid) {
|
||||
// Handle Backpacks and Participation
|
||||
if (isset($_POST['participate']) && is_array($_POST['participate'])) {
|
||||
foreach ($_POST['participate'] as $uid => $val) {
|
||||
$uid = intval($uid);
|
||||
$bid = intval($bid);
|
||||
if ($bid > 0) {
|
||||
// Only add if checked (value is usually '1')
|
||||
if ($val) {
|
||||
$bid = isset($_POST['backpacks'][$uid]) ? intval($_POST['backpacks'][$uid]) : 0;
|
||||
|
||||
// Insert Carrier (even if no backpack is assigned, they are a carrier on the list)
|
||||
// But DB schema: packing_list_carriers links user to list. Backpack is optional.
|
||||
// If we want them on the list, we insert.
|
||||
|
||||
// Check if $bid is valid (>0)
|
||||
$bid_to_insert = ($bid > 0) ? $bid : NULL;
|
||||
|
||||
$stmt_in = $conn->prepare("INSERT INTO packing_list_carriers (packing_list_id, user_id, backpack_id) VALUES (?, ?, ?)");
|
||||
$stmt_in->bind_param("iii", $new_list_id, $uid, $bid);
|
||||
$stmt_in->bind_param("iii", $new_list_id, $uid, $bid_to_insert);
|
||||
$stmt_in->execute();
|
||||
$stmt_in->close();
|
||||
|
||||
sync_backpack_items($conn, $new_list_id, $uid, $bid);
|
||||
if ($bid > 0) {
|
||||
sync_backpack_items($conn, $new_list_id, $uid, $bid);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If no array (e.g. single user form without checkboxes?), usually we force current user?
|
||||
// Or assume no one selected. Let's ensure Current User is added if not explicitly unchecked?
|
||||
// Actually, the UI below will default to checked for everyone.
|
||||
}
|
||||
|
||||
if ($household_id_for_user) {
|
||||
@@ -104,7 +119,7 @@ require_once 'header.php';
|
||||
|
||||
<form action="add_packing_list.php" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-7">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label"><i class="fas fa-file-signature me-2 text-muted"></i>Name der Packliste</label>
|
||||
<input type="text" class="form-control" id="name" value="<?php echo htmlspecialchars($name); ?>" name="name" required>
|
||||
@@ -122,71 +137,55 @@ require_once 'header.php';
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3"><i class="fas fa-hiking me-2 text-muted"></i>Rucksack-Zuweisung</h5>
|
||||
<div class="col-md-5">
|
||||
<h5 class="mb-3"><i class="fas fa-users me-2 text-muted"></i>Teilnehmer & Rucksäcke</h5>
|
||||
<div class="card bg-light border-0">
|
||||
<div class="card-body">
|
||||
<p class="small text-muted">Wähle gleich hier, wer welchen Rucksack trägt.</p>
|
||||
<p class="small text-muted">Wähle aus, wer mitkommt und wer welchen Rucksack trägt.</p>
|
||||
|
||||
<?php foreach ($available_users as $user):
|
||||
<?php
|
||||
$user_backpacks_json = [];
|
||||
$all_assigned_backpack_ids = []; // Empty for new list
|
||||
|
||||
foreach ($available_users as $user):
|
||||
$user_backpacks = get_available_backpacks_for_user($conn, $user['id'], $household_id_for_user);
|
||||
// Pre-select: None (0)
|
||||
$current_bp_id = 0;
|
||||
|
||||
// Store for JS
|
||||
$user_backpacks_json[$user['id']] = [
|
||||
'current_id' => $current_bp_id,
|
||||
'backpacks' => $user_backpacks
|
||||
];
|
||||
?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold small"><?php echo htmlspecialchars($user['username']); ?></label>
|
||||
<select class="form-select form-select-sm" name="backpacks[<?php echo $user['id']; ?>]">
|
||||
<option value="0">-- Kein Rucksack --</option>
|
||||
<?php foreach ($user_backpacks as $bp): ?>
|
||||
<option value="<?php echo $bp['id']; ?>">
|
||||
<?php echo htmlspecialchars($bp['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<div class="mb-3 pb-3 border-bottom">
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" name="participate[<?php echo $user['id']; ?>]" value="1" 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">
|
||||
<?php echo render_backpack_card_selector($user, $current_bp_id, $user_backpacks); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-plus-circle me-2"></i>Packliste erstellen</button>
|
||||
<a href="packing_lists.php" class="btn btn-secondary"><i class="fas fa-arrow-left me-2"></i>Abbrechen</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-plus-circle me-2"></i>Packliste erstellen & Artikel hinzufügen</button>
|
||||
<a href="packing_lists.php" class="btn btn-secondary"><i class="fas fa-arrow-left me-2"></i>Abbrechen</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const selects = document.querySelectorAll('select[name^="backpacks"]');
|
||||
|
||||
function updateOptions() {
|
||||
const selectedValues = Array.from(selects)
|
||||
.map(s => s.value)
|
||||
.filter(v => v !== "0");
|
||||
|
||||
selects.forEach(select => {
|
||||
const currentVal = select.value;
|
||||
Array.from(select.options).forEach(option => {
|
||||
if (option.value === "0") return;
|
||||
|
||||
// If this option is selected in another dropdown, hide it
|
||||
// Unless it's the currently selected value of THIS dropdown
|
||||
if (selectedValues.includes(option.value) && option.value !== currentVal) {
|
||||
option.style.display = 'none';
|
||||
option.disabled = true; // For robust blocking
|
||||
} else {
|
||||
option.style.display = '';
|
||||
option.disabled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selects.forEach(s => s.addEventListener('change', updateOptions));
|
||||
updateOptions(); // Init on load
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
|
||||
<!-- Render Modal JS -->
|
||||
<?php echo render_backpack_modal_script($user_backpacks_json, $all_assigned_backpack_ids); ?>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
|
||||
@@ -70,4 +70,171 @@ function get_available_backpacks_for_user($conn, $target_user_id, $household_id)
|
||||
}
|
||||
return $bps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the HTML for the Backpack Selection Card (Small widget per user)
|
||||
*/
|
||||
function render_backpack_card_selector($user, $current_bp_id, $user_backpacks) {
|
||||
// Find current details
|
||||
$current_bp_details = null;
|
||||
foreach ($user_backpacks as $bp) {
|
||||
if ($bp['id'] == $current_bp_id) {
|
||||
$current_bp_details = $bp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<input type="hidden" name="backpacks[<?php echo $user['id']; ?>]" id="input_bp_<?php echo $user['id']; ?>" value="<?php echo $current_bp_id; ?>">
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<!-- Selected Backpack Display -->
|
||||
<div id="display_bp_<?php echo $user['id']; ?>" class="flex-grow-1 p-2 border rounded bg-white d-flex align-items-center" style="min-height: 60px;">
|
||||
<?php if ($current_bp_details): ?>
|
||||
<?php if(!empty($current_bp_details['image_url'])): ?>
|
||||
<img src="<?php echo htmlspecialchars($current_bp_details['image_url']); ?>" style="width: 40px; height: 40px; object-fit: cover; border-radius: 4px;" class="me-2">
|
||||
<?php else: ?>
|
||||
<i class="fas fa-hiking fa-2x text-muted me-2"></i>
|
||||
<?php endif; ?>
|
||||
<div>
|
||||
<div class="fw-bold small"><?php echo htmlspecialchars($current_bp_details['name']); ?></div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<span class="text-muted small fst-italic">Kein Rucksack zugewiesen</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ms-2" onclick="openBackpackModal(<?php echo $user['id']; ?>, '<?php echo htmlspecialchars($user['username']); ?>')">
|
||||
<i class="fas fa-exchange-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Modal HTML and the JS needed to drive it.
|
||||
* Needs $user_backpacks_json and $all_assigned_backpack_ids to be populated.
|
||||
*/
|
||||
function render_backpack_modal_script($user_backpacks_json, $all_assigned_backpack_ids) {
|
||||
ob_start();
|
||||
?>
|
||||
<!-- Generic Modal -->
|
||||
<div class="modal fade" id="genericBpModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="genericBpModalTitle">Rucksack wählen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body bg-light" id="genericBpModalBody">
|
||||
<!-- Content loaded via JS -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const userBackpacksData = <?php echo json_encode($user_backpacks_json); ?>;
|
||||
const allAssignedIds = <?php echo json_encode($all_assigned_backpack_ids); ?>;
|
||||
|
||||
function openBackpackModal(userId, username) {
|
||||
const data = userBackpacksData[userId];
|
||||
if (!data) return; // Should not happen
|
||||
|
||||
const currentBpId = data.current_id;
|
||||
const titleEl = document.getElementById('genericBpModalTitle');
|
||||
const bodyEl = document.getElementById('genericBpModalBody');
|
||||
|
||||
titleEl.textContent = 'Rucksack für ' + username + ' wählen';
|
||||
|
||||
let html = '<div class="row g-3">';
|
||||
|
||||
// Option: None
|
||||
html += `
|
||||
<div class="col-md-4 col-6">
|
||||
<div class="card h-100 text-center p-3 bp-select-card ${currentBpId == 0 ? 'border-primary bg-white' : ''}" onclick="selectBackpack(${userId}, 0)">
|
||||
<div class="card-body">
|
||||
<i class="fas fa-times-circle fa-2x text-muted mb-2"></i>
|
||||
<div class="small fw-bold">Kein Rucksack</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
data.backpacks.forEach(bp => {
|
||||
// Filter logic: Show if NOT assigned OR if assigned to ME
|
||||
const isAssigned = allAssignedIds.some(id => String(id) === String(bp.id));
|
||||
// Display logic: Show if free OR if it is my current one
|
||||
if (isAssigned && String(bp.id) !== String(currentBpId)) return;
|
||||
|
||||
const imgHtml = bp.image_url ? `<img src="${bp.image_url}" class="card-img-top" style="height: 100px; object-fit: contain; padding: 10px;">` : `<div class="text-center py-4"><i class="fas fa-hiking fa-3x text-muted"></i></div>`;
|
||||
const activeClass = (String(bp.id) === String(currentBpId)) ? 'border-primary bg-white' : '';
|
||||
// Escape name for HTML attribute
|
||||
const safeName = bp.name.replace(/"/g, '"');
|
||||
|
||||
html += `
|
||||
<div class="col-md-4 col-6">
|
||||
<div class="card h-100 bp-select-card ${activeClass}" onclick='selectBackpack(${userId}, ${bp.id})'>
|
||||
${imgHtml}
|
||||
<div class="card-body p-2 text-center">
|
||||
<div class="small fw-bold text-truncate">${bp.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
bodyEl.innerHTML = html;
|
||||
|
||||
new bootstrap.Modal(document.getElementById('genericBpModal')).show();
|
||||
}
|
||||
|
||||
function selectBackpack(userId, bpId) {
|
||||
// Update Hidden Input
|
||||
document.getElementById('input_bp_' + userId).value = bpId;
|
||||
|
||||
// Find BP Data for display
|
||||
let bpName = 'Kein Rucksack zugewiesen';
|
||||
let bpImage = null;
|
||||
|
||||
if (bpId > 0 && userBackpacksData[userId]) {
|
||||
const data = userBackpacksData[userId];
|
||||
const bp = data.backpacks.find(b => String(b.id) === String(bpId));
|
||||
if (bp) {
|
||||
bpName = bp.name;
|
||||
bpImage = bp.image_url;
|
||||
}
|
||||
}
|
||||
|
||||
// Update Display
|
||||
const displayDiv = document.getElementById('display_bp_' + userId);
|
||||
let html = '';
|
||||
if (bpId == 0) {
|
||||
html = '<span class="text-muted small fst-italic">Kein Rucksack zugewiesen</span>';
|
||||
} else {
|
||||
if (bpImage) {
|
||||
html += '<img src="' + bpImage + '" style="width: 40px; height: 40px; object-fit: cover; border-radius: 4px;" class="me-2">';
|
||||
} else {
|
||||
html += '<i class="fas fa-hiking fa-2x text-muted me-2"></i>';
|
||||
}
|
||||
html += '<div><div class="fw-bold small">' + bpName + '</div></div>';
|
||||
}
|
||||
displayDiv.innerHTML = html;
|
||||
|
||||
// Close Modal
|
||||
const modalEl = document.getElementById('genericBpModal');
|
||||
const modal = bootstrap.Modal.getInstance(modalEl);
|
||||
modal.hide();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bp-select-card { cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; border: 1px solid rgba(0,0,0,0.1); }
|
||||
.bp-select-card:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0,0,0,0.1); border-color: var(--color-primary); }
|
||||
</style>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
?>
|
||||
@@ -189,7 +189,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
|
||||
// Calculate used backpacks
|
||||
$all_assigned_backpack_ids = array_values($current_assignments);
|
||||
|
||||
// Prepare data for JS
|
||||
// Prepare data for JS (still needed for the render helper)
|
||||
$user_backpacks_json = [];
|
||||
|
||||
foreach ($available_users as $user):
|
||||
@@ -202,42 +202,13 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
|
||||
'backpacks' => $user_backpacks
|
||||
];
|
||||
|
||||
// Find current backpack details for display
|
||||
$current_bp_details = null;
|
||||
foreach ($user_backpacks as $bp) {
|
||||
if ($bp['id'] == $my_current_bp_id) {
|
||||
$current_bp_details = $bp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 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">
|
||||
<label class="form-label fw-bold mb-2"><?php echo htmlspecialchars($user['username']); ?></label>
|
||||
<input type="hidden" name="backpacks[<?php echo $user['id']; ?>]" id="input_bp_<?php echo $user['id']; ?>" value="<?php echo $my_current_bp_id; ?>">
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<!-- Selected Backpack Display -->
|
||||
<div id="display_bp_<?php echo $user['id']; ?>" class="flex-grow-1 p-2 border rounded bg-white d-flex align-items-center" style="min-height: 60px;">
|
||||
<?php if ($current_bp_details): ?>
|
||||
<!-- Image if available -->
|
||||
<?php if(!empty($current_bp_details['image_url'])): ?>
|
||||
<img src="<?php echo htmlspecialchars($current_bp_details['image_url']); ?>" style="width: 40px; height: 40px; object-fit: cover; border-radius: 4px;" class="me-2">
|
||||
<?php else: ?>
|
||||
<i class="fas fa-hiking fa-2x text-muted me-2"></i>
|
||||
<?php endif; ?>
|
||||
<div>
|
||||
<div class="fw-bold small"><?php echo htmlspecialchars($current_bp_details['name']); ?></div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<span class="text-muted small fst-italic">Kein Rucksack zugewiesen</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ms-2" onclick="openBackpackModal(<?php echo $user['id']; ?>, '<?php echo htmlspecialchars($user['username']); ?>')">
|
||||
<i class="fas fa-exchange-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -254,115 +225,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && $can_edit) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generic Modal -->
|
||||
<div class="modal fade" id="genericBpModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="genericBpModalTitle">Rucksack wählen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body bg-light" id="genericBpModalBody">
|
||||
<!-- Content loaded via JS -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const userBackpacksData = <?php echo json_encode($user_backpacks_json); ?>;
|
||||
const allAssignedIds = <?php echo json_encode($all_assigned_backpack_ids); ?>;
|
||||
|
||||
function openBackpackModal(userId, username) {
|
||||
const data = userBackpacksData[userId];
|
||||
const currentBpId = data.current_id;
|
||||
const titleEl = document.getElementById('genericBpModalTitle');
|
||||
const bodyEl = document.getElementById('genericBpModalBody');
|
||||
|
||||
titleEl.textContent = 'Rucksack für ' + username + ' wählen';
|
||||
|
||||
let html = '<div class="row g-3">';
|
||||
|
||||
// Option: None
|
||||
html += `
|
||||
<div class="col-md-4 col-6">
|
||||
<div class="card h-100 text-center p-3 bp-select-card ${currentBpId == 0 ? 'border-primary bg-white' : ''}" onclick="selectBackpack(${userId}, 0)">
|
||||
<div class="card-body">
|
||||
<i class="fas fa-times-circle fa-2x text-muted mb-2"></i>
|
||||
<div class="small fw-bold">Kein Rucksack</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
data.backpacks.forEach(bp => {
|
||||
// Filter logic
|
||||
const isAssigned = allAssignedIds.some(id => String(id) === String(bp.id));
|
||||
if (isAssigned && String(bp.id) !== String(currentBpId)) return;
|
||||
|
||||
const imgHtml = bp.image_url ? `<img src="${bp.image_url}" class="card-img-top" style="height: 100px; object-fit: contain; padding: 10px;">` : `<div class="text-center py-4"><i class="fas fa-hiking fa-3x text-muted"></i></div>`;
|
||||
const activeClass = (String(bp.id) === String(currentBpId)) ? 'border-primary bg-white' : '';
|
||||
|
||||
html += `
|
||||
<div class="col-md-4 col-6">
|
||||
<div class="card h-100 bp-select-card ${activeClass}" onclick='selectBackpack(${userId}, ${bp.id})'>
|
||||
${imgHtml}
|
||||
<div class="card-body p-2 text-center">
|
||||
<div class="small fw-bold text-truncate">${bp.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
bodyEl.innerHTML = html;
|
||||
|
||||
new bootstrap.Modal(document.getElementById('genericBpModal')).show();
|
||||
}
|
||||
|
||||
function selectBackpack(userId, bpId) {
|
||||
// Update Hidden Input
|
||||
document.getElementById('input_bp_' + userId).value = bpId;
|
||||
|
||||
// Find BP Data for display
|
||||
let bpName = 'Kein Rucksack zugewiesen';
|
||||
let bpImage = null;
|
||||
|
||||
if (bpId > 0) {
|
||||
const data = userBackpacksData[userId];
|
||||
const bp = data.backpacks.find(b => String(b.id) === String(bpId));
|
||||
if (bp) {
|
||||
bpName = bp.name;
|
||||
bpImage = bp.image_url;
|
||||
}
|
||||
}
|
||||
|
||||
// Update Display
|
||||
const displayDiv = document.getElementById('display_bp_' + userId);
|
||||
let html = '';
|
||||
if (bpId == 0) {
|
||||
html = '<span class="text-muted small fst-italic">Kein Rucksack zugewiesen</span>';
|
||||
} else {
|
||||
if (bpImage) {
|
||||
html += '<img src="' + bpImage + '" style="width: 40px; height: 40px; object-fit: cover; border-radius: 4px;" class="me-2">';
|
||||
} else {
|
||||
html += '<i class="fas fa-hiking fa-2x text-muted me-2"></i>';
|
||||
}
|
||||
html += '<div><div class="fw-bold small">' + bpName + '</div></div>';
|
||||
}
|
||||
displayDiv.innerHTML = html;
|
||||
|
||||
// Close Modal
|
||||
const modalEl = document.getElementById('genericBpModal');
|
||||
const modal = bootstrap.Modal.getInstance(modalEl);
|
||||
modal.hide();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bp-select-card { cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; border: 1px solid rgba(0,0,0,0.1); }
|
||||
.bp-select-card:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0,0,0,0.1); border-color: var(--color-primary); }
|
||||
</style>
|
||||
<!-- Render Modal JS -->
|
||||
<?php echo render_backpack_modal_script($user_backpacks_json, $all_assigned_backpack_ids); ?>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
@@ -161,6 +161,9 @@ function render_item_row($item, $level, $items_by_parent) {
|
||||
$weight_display = $item['weight_grams'] > 0 ? number_format($item['weight_grams'], 0, ',', '.') . ' g' : '-';
|
||||
$total_weight_display = $item['weight_grams'] > 0 ? number_format($item['weight_grams'] * $item['quantity'], 0, ',', '.') . ' g' : '-';
|
||||
|
||||
// Ensure children rows are initially shown or hidden based on some logic? Default shown.
|
||||
// But the toggle button should reflect state. Default expanded -> chevron-down.
|
||||
|
||||
echo '<tr class="' . $bg_class . '" data-id="' . $item['id'] . '" data-parent-id="' . ($item['parent_packing_list_item_id'] ?: 0) . '">';
|
||||
|
||||
// Name Column with Indentation
|
||||
@@ -169,9 +172,10 @@ function render_item_row($item, $level, $items_by_parent) {
|
||||
|
||||
// Tree Toggle or Spacer
|
||||
if ($has_children) {
|
||||
echo '<button class="btn btn-sm btn-link p-0 me-2 text-decoration-none toggle-tree-btn" data-target-id="' . $item['id'] . '"><i class="fas fa-chevron-down"></i></button>';
|
||||
// Explicitly style the button
|
||||
echo '<button type="button" class="btn btn-sm p-0 me-2 border-0 bg-transparent text-primary toggle-tree-btn" data-target-id="' . $item['id'] . '" style="width:20px; cursor:pointer;"><i class="fas fa-chevron-down"></i></button>';
|
||||
} else {
|
||||
echo '<span style="width: 20px; display: inline-block;"></span>';
|
||||
echo '<span style="width: 20px; display: inline-block; margin-right: 0.5rem;"></span>';
|
||||
}
|
||||
|
||||
echo $icon;
|
||||
|
||||
Reference in New Issue
Block a user