@@ -216,6 +245,7 @@ document.addEventListener('DOMContentLoaded', function () {
const filterManufacturer = document.getElementById('filter-manufacturer');
const collapsedCategories = new Set();
+ let currentView = 'list';
// Initialize collapsed state based on user setting
if (collapseDefault) {
@@ -226,6 +256,23 @@ document.addEventListener('DOMContentLoaded', function () {
uniqueCategories.forEach(c => collapsedCategories.add(c));
}
+ document.getElementById('btn-view-list').addEventListener('click', function() {
+ currentView = 'list';
+ this.classList.add('active');
+ document.getElementById('btn-view-grid').classList.remove('active');
+ document.getElementById('view-container-list').style.display = '';
+ document.getElementById('view-container-grid').style.display = 'none';
+ renderTable();
+ });
+ document.getElementById('btn-view-grid').addEventListener('click', function() {
+ currentView = 'grid';
+ this.classList.add('active');
+ document.getElementById('btn-view-list').classList.remove('active');
+ document.getElementById('view-container-list').style.display = 'none';
+ document.getElementById('view-container-grid').style.display = '';
+ renderTable();
+ });
+
function renderTable() {
const textValue = filterText.value.toLowerCase();
const categoryValue = filterCategory.value;
@@ -247,6 +294,16 @@ document.addEventListener('DOMContentLoaded', function () {
return false;
});
+ // Update Export Modal
+ const exportIds = filteredList.flatMap(a => {
+ const ids = [a.id];
+ if (a.children) {
+ a.children.forEach(c => ids.push(c.id));
+ }
+ return ids;
+ });
+ document.getElementById('export_ids_input').value = exportIds.join(',');
+
const groupedArticles = {};
filteredList.forEach(article => {
const catName = article.category_name || 'Ohne Kategorie';
@@ -261,9 +318,11 @@ document.addEventListener('DOMContentLoaded', function () {
});
let tableHTML = '';
+ let gridHTML = '';
if (sortedCategories.length === 0) {
tableHTML = '
| Keine Artikel gefunden. |
';
+ gridHTML = '
Keine Artikel gefunden.
';
} else {
sortedCategories.forEach(catName => {
const items = groupedArticles[catName];
@@ -281,15 +340,70 @@ document.addEventListener('DOMContentLoaded', function () {
if (!isCollapsed) {
items.forEach(article => {
tableHTML += generateRowHTML(article);
+ gridHTML += generateCardHTML(article);
+ if (article.children.length > 0) {
+ article.children.forEach(child => {
+ gridHTML += generateCardHTML(child);
+ });
+ }
});
}
});
}
tableBody.innerHTML = tableHTML;
+ document.getElementById('articlesGridBody').innerHTML = gridHTML;
initializeInteractivity();
}
+ function generateCardHTML(article) {
+ const imagePath = article.image_url ? article.image_url : 'assets/images/keinbild.png';
+ const productLink = article.product_url ? `
` : '';
+ const householdBadge = article.household_id ? `
` : `
`;
+ const consumableIcon = article.consumable == 1 ? `
` : '';
+ const quantityBadge = article.consumable == 1 ? `
∞` : `
${article.quantity_owned} x`;
+
+ let actionButtons = '';
+ const isOwner = (article.user_id == currentUserId);
+ const isHouseholdArticle = (article.household_id && article.household_id == currentUserHouseholdId);
+
+ if (isOwner || isHouseholdArticle) {
+ actionButtons = `
+
`;
+ actionButtons += `
`;
+ actionButtons += `
`;
+ }
+
+ return `
+
+
+

+
+ ${householdBadge} ${consumableIcon}
+
+
+
${article.name}
+
+ ${new Intl.NumberFormat('de-DE').format(article.weight_grams)} g
+ ${quantityBadge}
+
+
+ ${article.category_name || 'Ohne Kat.'}
+
+
+ ${article.manufacturer_name ? `Hersteller: ${article.manufacturer_name}
` : ''}
+ ${article.product_designation ? `Modell: ${article.product_designation}` : ''}
+
+
+
+
+
+ `;
+ }
+
function generateRowHTML(article, level = 0) {
let html = '';
const imagePath = article.image_url ? article.image_url : 'assets/images/keinbild.png';
diff --git a/src/export_articles.php b/src/export_articles.php
index 8c58da8..b0924f6 100644
--- a/src/export_articles.php
+++ b/src/export_articles.php
@@ -37,6 +37,21 @@ if ($current_user_household_id) {
$placeholders = implode(',', array_fill(0, count($household_member_ids), '?'));
$types = str_repeat('i', count($household_member_ids));
+$where_clause = "(a.user_id IN ($placeholders) OR a.household_id = ?)";
+$all_params = array_merge($household_member_ids, [$current_user_household_id]);
+$all_types = $types . 'i';
+
+if (isset($_POST['export_type']) && $_POST['export_type'] == 'filtered' && !empty($_POST['export_ids'])) {
+ $ids = explode(',', $_POST['export_ids']);
+ $valid_ids = array_map('intval', $ids);
+ if (count($valid_ids) > 0) {
+ $id_placeholders = implode(',', array_fill(0, count($valid_ids), '?'));
+ $where_clause .= " AND a.id IN ($id_placeholders)";
+ $all_params = array_merge($all_params, $valid_ids);
+ $all_types .= str_repeat('i', count($valid_ids));
+ }
+}
+
$sql = "SELECT
a.name AS 'Artikelname',
a.product_designation AS 'Produktbezeichnung',
@@ -55,7 +70,7 @@ $sql = "SELECT
LEFT JOIN manufacturers m ON a.manufacturer_id = m.id
LEFT JOIN storage_locations l2 ON a.storage_location_id = l2.id
LEFT JOIN storage_locations l1 ON l2.parent_id = l1.id
- WHERE a.user_id IN ($placeholders) OR a.household_id = ?
+ WHERE $where_clause
ORDER BY c.name ASC, a.name ASC";
$stmt = $conn->prepare($sql);
@@ -63,8 +78,6 @@ if ($stmt === false) {
die("Datenbankfehler.");
}
-$all_params = array_merge($household_member_ids, [$current_user_household_id]);
-$all_types = $types . 'i';
$stmt->bind_param($all_types, ...$all_params);
$stmt->execute();
$result = $stmt->get_result();
diff --git a/src/household.php b/src/household.php
index b8055f5..6a8f25f 100644
--- a/src/household.php
+++ b/src/household.php
@@ -46,12 +46,12 @@ if ($household_id) {
// Mitglieder und deren Statistiken laden
$stmt_members = $conn->prepare("
SELECT
- u.id, u.username,
+ u.id, COALESCE(NULLIF(u.display_name, ''), u.username) AS username,
(SELECT COUNT(*) FROM articles WHERE user_id = u.id) as article_count,
(SELECT COUNT(*) FROM packing_lists WHERE user_id = u.id) as list_count
FROM users u
WHERE u.household_id = ?
- ORDER BY u.username
+ ORDER BY username
");
$stmt_members->bind_param("i", $household_id);
$stmt_members->execute();
@@ -59,7 +59,7 @@ if ($household_id) {
$stmt_members->close();
// Eingeladene Mitglieder laden
- $stmt_pending = $conn->prepare("SELECT u.username FROM household_invitations hi JOIN users u ON hi.invited_user_id = u.id WHERE hi.household_id = ? AND hi.status = 'pending'");
+ $stmt_pending = $conn->prepare("SELECT COALESCE(NULLIF(u.display_name, ''), u.username) AS username FROM household_invitations hi JOIN users u ON hi.invited_user_id = u.id WHERE hi.household_id = ? AND hi.status = 'pending'");
$stmt_pending->bind_param("i", $household_id);
$stmt_pending->execute();
$pending_invitations = $stmt_pending->get_result()->fetch_all(MYSQLI_ASSOC);
diff --git a/src/todo_lists.php b/src/todo_lists.php
index eed1aab..a706a57 100644
--- a/src/todo_lists.php
+++ b/src/todo_lists.php
@@ -58,6 +58,24 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
$stmt->bind_param("i", $item_id);
$stmt->execute();
$stmt->close();
+ } elseif (isset($_POST['edit_list'])) {
+ $list_id = intval($_POST['list_id']);
+ $name = trim($_POST['list_name']);
+ if (!empty($name)) {
+ $stmt = $conn->prepare("UPDATE todo_lists SET name = ? WHERE id = ? AND (user_id = ? OR household_id = ?)");
+ $stmt->bind_param("siii", $name, $list_id, $current_user_id, $current_user_household_id);
+ $stmt->execute();
+ $stmt->close();
+ }
+ } elseif (isset($_POST['edit_item'])) {
+ $item_id = intval($_POST['item_id']);
+ $title = trim($_POST['item_title']);
+ if (!empty($title)) {
+ $stmt = $conn->prepare("UPDATE todo_items SET title = ? WHERE id = ?");
+ $stmt->bind_param("si", $title, $item_id);
+ $stmt->execute();
+ $stmt->close();
+ }
} elseif (isset($_POST['toggle_item'])) {
$item_id = intval($_POST['item_id']);
$status = isset($_POST['status']) ? intval($_POST['status']) : 0;
@@ -131,28 +149,57 @@ $active_list_id = isset($_GET['list_id']) ? intval($_GET['list_id']) : (!empty($
foreach ($todo_lists as $l) if ($l['id'] == $active_list_id) $active_list_name = $l['name'];
?>
-