Invalid or missing list hash.

'); } // Resolve hash → activity IDs $stmt = $pdo->prepare("SELECT activity_ids FROM selection_hashes WHERE hash = ?"); $stmt->execute([$hash]); $row = $stmt->fetch(); if (!$row) { http_response_code(404); die('

List not found. It may have expired or the link is wrong.

'); } $activityIds = array_map('intval', explode(',', $row['activity_ids'])); if (empty($activityIds)) { die('

No activities stored for this hash.

'); } // Fetch the selected activity names for display $ph = implode(',', array_fill(0, count($activityIds), '?')); $stmt = $pdo->prepare(" SELECT a.activityName FROM activities a WHERE a.activityID IN ($ph) ORDER BY a.activityName "); $stmt->execute($activityIds); $activityNames = $stmt->fetchAll(PDO::FETCH_COLUMN); // Get all items for these activities, deduplicated, grouped by item_group $stmt = $pdo->prepare(" SELECT DISTINCT ig.groupID, ig.groupName, ig.sortOrder AS groupSort, i.itemID, i.itemName, i.sortOrder AS itemSort FROM activity_item_map aim JOIN items i ON i.itemID = aim.itemID JOIN item_groups ig ON ig.groupID = i.groupID WHERE aim.activityID IN ($ph) ORDER BY ig.sortOrder, ig.groupID, i.sortOrder, i.itemID "); $stmt->execute($activityIds); $allItems = $stmt->fetchAll(); // Group items by item_group $grouped = []; foreach ($allItems as $item) { $gid = $item['groupID']; if (!isset($grouped[$gid])) { $grouped[$gid] = ['name' => $item['groupName'], 'items' => []]; } $grouped[$gid]['items'][] = ['id' => $item['itemID'], 'name' => $item['itemName']]; } $pageUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; $totalItems = count($allItems); ?> PackIt – Your Packing List
items  ·  activities
← New list
Copied!
0 / packed
$group): ?>