Favorieten toegevoegd aan de navigatiebalk en sidebar.
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
const FavoriteService = require("../services/FavoriteService");
|
||||||
|
|
||||||
|
class FavoriteController {
|
||||||
|
index(req, res) {
|
||||||
|
const favorites = FavoriteService.getFavorites(req.user.id, req.user.household_id);
|
||||||
|
|
||||||
|
res.locals.title = "Favorieten";
|
||||||
|
res.render("favorites/index", {
|
||||||
|
favorites,
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(req, res) {
|
||||||
|
const productId = Number.parseInt(req.params.id, 10);
|
||||||
|
|
||||||
|
if (!Number.isInteger(productId)) {
|
||||||
|
req.flash("error", "Product niet gevonden.");
|
||||||
|
return res.redirect("/products");
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFavorite = FavoriteService.toggleFavorite(req.user.id, productId, req.user.household_id);
|
||||||
|
if (!isFavorite && !FavoriteService.getFavoriteIds(req.user.id, req.user.household_id).has(productId)) {
|
||||||
|
req.flash("error", "Product niet gevonden.");
|
||||||
|
return res.redirect("/products");
|
||||||
|
}
|
||||||
|
|
||||||
|
req.flash("success", isFavorite ? "Product toegevoegd aan favorieten." : "Product verwijderd uit favorieten.");
|
||||||
|
res.redirect("/products");
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(req, res) {
|
||||||
|
const productId = Number.parseInt(req.params.productId, 10);
|
||||||
|
|
||||||
|
if (!Number.isInteger(productId)) {
|
||||||
|
req.flash("error", "Product niet gevonden.");
|
||||||
|
return res.redirect("/favorites");
|
||||||
|
}
|
||||||
|
|
||||||
|
const removed = FavoriteService.removeFavorite(req.user.id, productId, req.user.household_id);
|
||||||
|
if (!removed) {
|
||||||
|
req.flash("error", "Product niet gevonden in favorieten.");
|
||||||
|
return res.redirect("/favorites");
|
||||||
|
}
|
||||||
|
|
||||||
|
req.flash("success", "Product verwijderd uit favorieten.");
|
||||||
|
res.redirect("/favorites");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new FavoriteController();
|
||||||
@@ -2,6 +2,7 @@ const ProductService =
|
|||||||
require("../services/ProductService");
|
require("../services/ProductService");
|
||||||
|
|
||||||
const CategoryService = require("../services/CategoryService");
|
const CategoryService = require("../services/CategoryService");
|
||||||
|
const FavoriteService = require("../services/FavoriteService");
|
||||||
|
|
||||||
const parseCsv = require("../utils/parseCsv");
|
const parseCsv = require("../utils/parseCsv");
|
||||||
|
|
||||||
@@ -10,16 +11,18 @@ class ProductController {
|
|||||||
|
|
||||||
index(req, res) {
|
index(req, res) {
|
||||||
|
|
||||||
const products =
|
const products = ProductService.getProducts(req.user.household_id);
|
||||||
ProductService.getProducts(req.user.household_id);
|
const favoriteIds = FavoriteService.getFavoriteIds(req.user.id, req.user.household_id);
|
||||||
|
|
||||||
const categories = CategoryService.getCategories(req.user.household_id);
|
const categories = CategoryService.getCategories(req.user.household_id);
|
||||||
|
|
||||||
res.render(
|
res.render(
|
||||||
"products/index",
|
"products/index",
|
||||||
{
|
{
|
||||||
title:"Producten",
|
title:"Producten",
|
||||||
products,
|
products: products.map(product => ({
|
||||||
|
...product,
|
||||||
|
is_favorite: favoriteIds.has(product.id)
|
||||||
|
})),
|
||||||
categories
|
categories
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const ProductRepository = require("../repositories/ProductRepository");
|
const ProductRepository = require("../repositories/ProductRepository");
|
||||||
const ShoppingListRepository = require("../repositories/ShoppingListRepository");
|
const ShoppingListRepository = require("../repositories/ShoppingListRepository");
|
||||||
|
const FavoriteService = require("../services/FavoriteService");
|
||||||
|
|
||||||
class ShoppingListController {
|
class ShoppingListController {
|
||||||
index(req, res) {
|
index(req, res) {
|
||||||
@@ -63,6 +64,40 @@ class ShoppingListController {
|
|||||||
res.redirect(`/lists/${list.id}`);
|
res.redirect(`/lists/${list.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearItems(req, res) {
|
||||||
|
const list = ShoppingListRepository.findById(req.params.id, req.user.household_id);
|
||||||
|
if (!list) return res.status(404).render("errors/404");
|
||||||
|
|
||||||
|
ShoppingListRepository.clearItems(list.id);
|
||||||
|
this.broadcastUpdate(req, list.id);
|
||||||
|
req.flash("success", "Alle producten zijn verwijderd uit de lijst.");
|
||||||
|
res.redirect(`/lists/${list.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
addFavoriteProducts(req, res) {
|
||||||
|
const list = ShoppingListRepository.findById(req.params.id, req.user.household_id);
|
||||||
|
if (!list) return res.status(404).render("errors/404");
|
||||||
|
|
||||||
|
const favorites = FavoriteService.getFavorites(req.user.id, req.user.household_id);
|
||||||
|
const items = favorites.map((favorite) => ({
|
||||||
|
list_id: list.id,
|
||||||
|
product_id: favorite.id,
|
||||||
|
amount: 1,
|
||||||
|
checked: 0,
|
||||||
|
sort_order: 0
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (items.length === 0) {
|
||||||
|
req.flash("info", "Je hebt nog geen favorieten om toe te voegen.");
|
||||||
|
return res.redirect(`/lists/${list.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShoppingListRepository.addItems(list.id, items);
|
||||||
|
this.broadcastUpdate(req, list.id);
|
||||||
|
req.flash("success", `${items.length} favoriete producten toegevoegd aan de lijst.`);
|
||||||
|
res.redirect(`/lists/${list.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
deleteItem(req, res) {
|
deleteItem(req, res) {
|
||||||
const list = ShoppingListRepository.findById(req.params.id, req.user.household_id);
|
const list = ShoppingListRepository.findById(req.params.id, req.user.household_id);
|
||||||
if (!list) return res.status(404).json({ error: "Lijst niet gevonden" });
|
if (!list) return res.status(404).json({ error: "Lijst niet gevonden" });
|
||||||
|
|||||||
+31
-4
@@ -163,18 +163,18 @@ CREATE TABLE IF NOT EXISTS product_favorites (
|
|||||||
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
|
||||||
user_id INTEGER NOT NULL,
|
household_id INTEGER NOT NULL,
|
||||||
|
|
||||||
product_id INTEGER NOT NULL,
|
product_id INTEGER NOT NULL,
|
||||||
|
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
|
||||||
UNIQUE(user_id, product_id),
|
UNIQUE(household_id, product_id),
|
||||||
|
|
||||||
|
|
||||||
FOREIGN KEY(user_id)
|
FOREIGN KEY(household_id)
|
||||||
REFERENCES users(id)
|
REFERENCES households(id)
|
||||||
ON DELETE CASCADE,
|
ON DELETE CASCADE,
|
||||||
|
|
||||||
|
|
||||||
@@ -217,8 +217,35 @@ const addColumnIfMissing = (table, column, definition) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const migrateFavoriteTableToHouseholdScope = () => {
|
||||||
|
const columns = db.prepare(`PRAGMA table_info(product_favorites)`).all();
|
||||||
|
const hasHouseholdId = columns.some(column => column.name === "household_id");
|
||||||
|
|
||||||
|
if (!hasHouseholdId) {
|
||||||
|
db.exec(`ALTER TABLE product_favorites ADD COLUMN household_id INTEGER`);
|
||||||
|
db.exec(`UPDATE product_favorites
|
||||||
|
SET household_id = (
|
||||||
|
SELECT products.household_id
|
||||||
|
FROM products
|
||||||
|
WHERE products.id = product_favorites.product_id
|
||||||
|
)
|
||||||
|
WHERE household_id IS NULL`);
|
||||||
|
|
||||||
|
db.exec(`DELETE FROM product_favorites
|
||||||
|
WHERE id NOT IN (
|
||||||
|
SELECT MIN(id)
|
||||||
|
FROM product_favorites
|
||||||
|
GROUP BY household_id, product_id
|
||||||
|
)`);
|
||||||
|
|
||||||
|
db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_product_favorites_household_product
|
||||||
|
ON product_favorites (household_id, product_id)`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
addColumnIfMissing("categories", "household_id", "INTEGER REFERENCES households(id)");
|
addColumnIfMissing("categories", "household_id", "INTEGER REFERENCES households(id)");
|
||||||
addColumnIfMissing("products", "household_id", "INTEGER REFERENCES households(id)");
|
addColumnIfMissing("products", "household_id", "INTEGER REFERENCES households(id)");
|
||||||
|
migrateFavoriteTableToHouseholdScope();
|
||||||
|
|
||||||
const defaultHousehold = db.prepare("SELECT id FROM households ORDER BY id LIMIT 1").get();
|
const defaultHousehold = db.prepare("SELECT id FROM households ORDER BY id LIMIT 1").get();
|
||||||
if (defaultHousehold) {
|
if (defaultHousehold) {
|
||||||
|
|||||||
+6
-5
@@ -1,16 +1,17 @@
|
|||||||
module.exports = function(req, res, next) {
|
module.exports = function(req, res, next) {
|
||||||
|
|
||||||
|
if (!req.session || !req.session.userId || !req.user) {
|
||||||
if (!req.session.userId) {
|
|
||||||
|
|
||||||
if (req.originalUrl.startsWith("/api/")) {
|
if (req.originalUrl.startsWith("/api/")) {
|
||||||
return res.status(401).json({ error: "Je bent niet ingelogd" });
|
return res.status(401).json({ error: "Je bent niet ingelogd" });
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.redirect("/login");
|
if (req.session && req.session.userId) {
|
||||||
|
delete req.session.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.flash("info", "Je sessie is verlopen. Log opnieuw in.");
|
||||||
|
return res.redirect("/login");
|
||||||
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
|
||||||
|
|||||||
+12
-8
@@ -4,17 +4,21 @@ require("../repositories/UserRepository");
|
|||||||
|
|
||||||
module.exports = function userMiddleware(req, res, next) {
|
module.exports = function userMiddleware(req, res, next) {
|
||||||
|
|
||||||
|
req.user = null;
|
||||||
|
|
||||||
if (req.session.userId) {
|
if (!req.session || !req.session.userId) {
|
||||||
|
return next();
|
||||||
req.user =
|
|
||||||
UserRepository.findById(
|
|
||||||
req.session.userId
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.user = UserRepository.findById(req.session.userId);
|
||||||
|
|
||||||
next();
|
if (!req.user) {
|
||||||
|
delete req.session.userId;
|
||||||
|
if (typeof req.session.destroy === "function") {
|
||||||
|
return req.session.destroy(() => next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
const db = require("../config/database");
|
||||||
|
|
||||||
|
class FavoriteRepository {
|
||||||
|
getByHousehold(householdId) {
|
||||||
|
return db.prepare(`
|
||||||
|
SELECT products.id,
|
||||||
|
products.name,
|
||||||
|
products.category_id,
|
||||||
|
products.barcode,
|
||||||
|
categories.name AS category_name,
|
||||||
|
categories.icon AS category_icon
|
||||||
|
FROM product_favorites
|
||||||
|
JOIN products ON products.id = product_favorites.product_id
|
||||||
|
LEFT JOIN categories ON categories.id = products.category_id
|
||||||
|
WHERE product_favorites.household_id = ?
|
||||||
|
AND products.household_id = ?
|
||||||
|
ORDER BY products.name ASC
|
||||||
|
`).all(householdId, householdId);
|
||||||
|
}
|
||||||
|
|
||||||
|
getIdsByHousehold(householdId) {
|
||||||
|
return new Set(
|
||||||
|
db.prepare(`
|
||||||
|
SELECT product_favorites.product_id
|
||||||
|
FROM product_favorites
|
||||||
|
JOIN products ON products.id = product_favorites.product_id
|
||||||
|
WHERE product_favorites.household_id = ?
|
||||||
|
AND products.household_id = ?
|
||||||
|
`).all(householdId, householdId).map(row => row.product_id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
find(householdId, productId) {
|
||||||
|
return db.prepare(`
|
||||||
|
SELECT * FROM product_favorites
|
||||||
|
WHERE household_id = ? AND product_id = ?
|
||||||
|
`).get(householdId, productId);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(householdId, productId) {
|
||||||
|
return db.prepare(`
|
||||||
|
INSERT OR IGNORE INTO product_favorites (household_id, product_id)
|
||||||
|
VALUES (?, ?)
|
||||||
|
`).run(householdId, productId);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(householdId, productId) {
|
||||||
|
return db.prepare(`
|
||||||
|
DELETE FROM product_favorites
|
||||||
|
WHERE household_id = ? AND product_id = ?
|
||||||
|
`).run(householdId, productId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new FavoriteRepository();
|
||||||
@@ -72,6 +72,37 @@ class ShoppingListRepository {
|
|||||||
`).run(listId);
|
`).run(listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearItems(listId) {
|
||||||
|
return db.prepare(`
|
||||||
|
DELETE FROM shopping_list_items
|
||||||
|
WHERE list_id = ?
|
||||||
|
`).run(listId);
|
||||||
|
}
|
||||||
|
|
||||||
|
addItems(listId, items) {
|
||||||
|
if (!items.length) return 0;
|
||||||
|
|
||||||
|
const insert = db.prepare(`
|
||||||
|
INSERT INTO shopping_list_items (list_id, product_id, amount, checked, sort_order)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
|
||||||
|
const transaction = db.transaction(() => {
|
||||||
|
for (const item of items) {
|
||||||
|
insert.run(
|
||||||
|
listId,
|
||||||
|
item.product_id,
|
||||||
|
item.amount ?? 1,
|
||||||
|
item.checked ?? 0,
|
||||||
|
item.sort_order ?? 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction();
|
||||||
|
return items.length;
|
||||||
|
}
|
||||||
|
|
||||||
deleteItem(listId, itemId) {
|
deleteItem(listId, itemId) {
|
||||||
return db.prepare(`
|
return db.prepare(`
|
||||||
DELETE FROM shopping_list_items WHERE id = ? AND list_id = ?
|
DELETE FROM shopping_list_items WHERE id = ? AND list_id = ?
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ require("../controllers/CategoryController");
|
|||||||
const ShoppingListController =
|
const ShoppingListController =
|
||||||
require("../controllers/ShoppingListController");
|
require("../controllers/ShoppingListController");
|
||||||
|
|
||||||
|
const FavoriteController = require("../controllers/FavoriteController");
|
||||||
|
|
||||||
const MenuController =
|
const MenuController =
|
||||||
require("../controllers/MenuController");
|
require("../controllers/MenuController");
|
||||||
|
|
||||||
@@ -119,6 +121,24 @@ router.post(
|
|||||||
ProductController.remove.bind(ProductController)
|
ProductController.remove.bind(ProductController)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/products/:id/favorite",
|
||||||
|
auth,
|
||||||
|
FavoriteController.toggle.bind(FavoriteController)
|
||||||
|
);
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/favorites",
|
||||||
|
auth,
|
||||||
|
FavoriteController.index.bind(FavoriteController)
|
||||||
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/favorites/:productId/delete",
|
||||||
|
auth,
|
||||||
|
FavoriteController.remove.bind(FavoriteController)
|
||||||
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/lists",
|
"/lists",
|
||||||
auth,
|
auth,
|
||||||
@@ -149,6 +169,18 @@ router.post(
|
|||||||
ShoppingListController.create.bind(ShoppingListController)
|
ShoppingListController.create.bind(ShoppingListController)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/lists/:id/favorites/add",
|
||||||
|
auth,
|
||||||
|
ShoppingListController.addFavoriteProducts.bind(ShoppingListController)
|
||||||
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/lists/:id/items/clear",
|
||||||
|
auth,
|
||||||
|
ShoppingListController.clearItems.bind(ShoppingListController)
|
||||||
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/lists/:id",
|
"/lists/:id",
|
||||||
auth,
|
auth,
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
const FavoriteRepository = require("../repositories/FavoriteRepository");
|
||||||
|
const ProductRepository = require("../repositories/ProductRepository");
|
||||||
|
|
||||||
|
class FavoriteService {
|
||||||
|
getFavorites(userId, householdId) {
|
||||||
|
return FavoriteRepository.getByHousehold(householdId);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFavoriteIds(userId, householdId) {
|
||||||
|
return FavoriteRepository.getIdsByHousehold(householdId);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleFavorite(userId, productId, householdId) {
|
||||||
|
const product = ProductRepository.findById(productId, householdId);
|
||||||
|
if (!product) return false;
|
||||||
|
|
||||||
|
const current = FavoriteRepository.find(householdId, productId);
|
||||||
|
if (current) {
|
||||||
|
FavoriteRepository.remove(householdId, productId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FavoriteRepository.add(householdId, productId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFavorite(userId, productId, householdId) {
|
||||||
|
const product = ProductRepository.findById(productId, householdId);
|
||||||
|
if (!product) return false;
|
||||||
|
|
||||||
|
return FavoriteRepository.remove(householdId, productId).changes > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new FavoriteService();
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,26 @@
|
|||||||
|
<div class="page-header mb-4">
|
||||||
|
<h1>💙 Favorieten</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<% if (favorites.length === 0) { %>
|
||||||
|
<p class="text-secondary">Je hebt nog geen favoriete producten.</p>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="list-group">
|
||||||
|
<% favorites.forEach(product => { %>
|
||||||
|
<div class="list-group-item d-flex justify-content-between align-items-center gap-3">
|
||||||
|
<div>
|
||||||
|
<strong><%= product.category_icon || "" %> <%= product.name %></strong>
|
||||||
|
<div class="text-secondary"><%= product.category_name || "Geen categorie" %></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" action="/favorites/<%= product.id %>/delete">
|
||||||
|
<button class="btn btn-sm btn-outline-danger" type="submit">Verwijder</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<% }); %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -2,10 +2,20 @@
|
|||||||
<a href="/lists" class="btn btn-outline-secondary mb-3">← Terug naar lijsten</a>
|
<a href="/lists" class="btn btn-outline-secondary mb-3">← Terug naar lijsten</a>
|
||||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
<h1 class="mb-0"><%= list.name %></h1>
|
<h1 class="mb-0"><%= list.name %></h1>
|
||||||
|
<div class="d-flex flex-wrap gap-2">
|
||||||
|
<form method="post" action="/lists/<%= list.id %>/favorites/add"
|
||||||
|
onsubmit="return confirm('Alle favorieten toevoegen aan deze lijst?');">
|
||||||
|
<button class="btn btn-outline-primary" type="submit">Alle favorieten toevoegen</button>
|
||||||
|
</form>
|
||||||
<form method="post" action="/lists/<%= list.id %>/items/reset"
|
<form method="post" action="/lists/<%= list.id %>/items/reset"
|
||||||
onsubmit="return confirm('Alle producten weer openzetten?');">
|
onsubmit="return confirm('Alle producten weer openzetten?');">
|
||||||
<button class="btn btn-outline-primary" type="submit">Alles weer openzetten</button>
|
<button class="btn btn-outline-primary" type="submit">Alles weer openzetten</button>
|
||||||
</form>
|
</form>
|
||||||
|
<form method="post" action="/lists/<%= list.id %>/items/clear"
|
||||||
|
onsubmit="return confirm('Weet je zeker dat je alle producten uit deze lijst wilt verwijderen?');">
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Alles verwijderen</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
<a class="nav-link" href="/">Dashboard</a>
|
<a class="nav-link" href="/">Dashboard</a>
|
||||||
<a class="nav-link" href="/lists">Lijsten</a>
|
<a class="nav-link" href="/lists">Lijsten</a>
|
||||||
<a class="nav-link" href="/products">Producten</a>
|
<a class="nav-link" href="/products">Producten</a>
|
||||||
|
<a class="nav-link" href="/favorites">Favorieten</a>
|
||||||
<a class="nav-link" href="/categories">Categorieën</a>
|
<a class="nav-link" href="/categories">Categorieën</a>
|
||||||
<a class="nav-link" href="/household">Huishouden</a>
|
<a class="nav-link" href="/household">Huishouden</a>
|
||||||
<a class="nav-link text-danger" href="/logout">Uitloggen</a>
|
<a class="nav-link text-danger" href="/logout">Uitloggen</a>
|
||||||
|
|||||||
@@ -26,6 +26,12 @@
|
|||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<a class="nav-link" href="/favorites">
|
||||||
|
|
||||||
|
💙 Favorieten
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
<a class="nav-link" href="/household">
|
<a class="nav-link" href="/household">
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<button class="btn btn-primary" type="submit" form="product-edit-<%= product.id %>">Wijzigingen opslaan</button>
|
<button class="btn btn-primary" type="submit" form="product-edit-<%= product.id %>">Wijzigingen opslaan</button>
|
||||||
<form method="post" action="/products/<%= product.id %>/delete"
|
<form method="post" action="/products/<%= product.id %>/delete"
|
||||||
onsubmit="return confirm('Weet je zeker dat je dit product wilt verwijderen?');">
|
onsubmit="return confirm('Weet je zeker dat je dit product wilt verwijderen?');">
|
||||||
<button class="btn btn-outline-danger" type="submit">Product verwijderen</button>
|
<button class="btn btn-light border text-danger" type="submit">Product verwijderen</button>
|
||||||
</form>
|
</form>
|
||||||
<a class="btn btn-link" href="/products">Annuleren</a>
|
<a class="btn btn-link" href="/products">Annuleren</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,11 +23,20 @@
|
|||||||
<strong><%= product.category_icon || "" %> <%= product.name %></strong>
|
<strong><%= product.category_icon || "" %> <%= product.name %></strong>
|
||||||
<div class="text-secondary"><%= product.category_name || "Geen categorie" %></div>
|
<div class="text-secondary"><%= product.category_name || "Geen categorie" %></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<form method="post" action="/products/<%= product.id %>/favorite">
|
||||||
|
<button class="btn btn-sm <%= product.is_favorite ? 'btn-danger' : 'btn-outline-secondary' %>"
|
||||||
|
type="submit"
|
||||||
|
aria-label="<%= product.is_favorite ? 'Verwijder uit favorieten' : 'Toevoegen aan favorieten' %>">
|
||||||
|
<%= product.is_favorite ? '♥' : '♡' %>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
<a class="btn btn-sm btn-outline-primary" href="/products/<%= product.id %>/edit">
|
<a class="btn btn-sm btn-outline-primary" href="/products/<%= product.id %>/edit">
|
||||||
Wijzigen
|
Wijzigen
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|||||||
Reference in New Issue
Block a user