diff --git a/.gitignore b/.gitignore index 391c439..55d728a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,5 @@ node_modules/ - .env - database.sqlite - -storage/logs/* -storage/backups/* - -public/uploads/* - -.vscode - -.idea \ No newline at end of file +*.sqlite-shm +*.sqlite-wal diff --git a/app.js b/app.js index 3c51a4c..54842e9 100644 --- a/app.js +++ b/app.js @@ -10,6 +10,11 @@ const socketHandlers = require("./sockets/handlers"); const app = createApp(); const server = http.createServer(app); +const io = new Server(server); + +io.use((socket, next) => session(socket.request, {}, next)); +socketHandlers(io); +app.locals.io = io; const io = new Server(server, { cors: { diff --git a/config/express.js b/config/express.js index e0267d9..99e2fe5 100644 --- a/config/express.js +++ b/config/express.js @@ -57,24 +57,29 @@ module.exports = () => { app.use(session); - app.use(flash()); +app.use(flash()); - app.use(userMiddleware); +app.use(userMiddleware); - app.use((req, res, next) => { - - res.locals.user = req.user || null; - - res.locals.success = req.flash("success"); - res.locals.error = req.flash("error"); - res.locals.info = req.flash("info"); - res.locals.warning = req.flash("warning"); - - res.locals.title = res.locals.title || "PantryHub"; - - next(); +app.use((req, res, next) => { + res.set("X-PantryHub-Worktree", __dirname); + res.locals.user = req.user || null; + res.locals.success = req.flash("success"); + res.locals.error = req.flash("error"); + res.locals.info = req.flash("info"); + res.locals.warning = req.flash("warning"); + res.locals.title = "PantryHub"; + next(); +}); +app.get("/__version", (req, res) => { + res.set("Cache-Control", "no-store"); + res.json({ + app: "PantryHub", + root: path.join(__dirname, ".."), + pid: process.pid }); +}); app.use( @@ -84,13 +89,11 @@ module.exports = () => { ); - // API Routes app.use( "/api", require("../routes/api") ); - // Web Routes app.use( "/", require("../routes/auth") diff --git a/config/session.js b/config/session.js index ad93068..70d1a3f 100644 --- a/config/session.js +++ b/config/session.js @@ -1,8 +1,9 @@ const session = require("express-session"); const BetterSqlite3Store = require("better-sqlite3-session-store")(session); const Database = require("better-sqlite3"); +const path = require("path"); -const db = new Database("sessions.sqlite"); +const db = new Database(path.join(__dirname, "..", "sessions.sqlite")); module.exports = session({ diff --git a/controllers/ProductController.js b/controllers/ProductController.js index 2e39d0f..c359175 100644 --- a/controllers/ProductController.js +++ b/controllers/ProductController.js @@ -3,51 +3,54 @@ require("../services/ProductService"); const db = require("../config/database"); - class ProductController { + index(req, res) { const products = ProductService.getProducts(); - const categories = db.prepare(` - SELECT * FROM categories ORDER BY name - `).all(); - - res.locals.title = "Producten"; + const categories = db.prepare( + "SELECT * FROM categories ORDER BY name" + ).all(); res.render( "products/index", { + title:"Producten", products, - categories, - user: req.user + categories } + ); } create(req, res) { + const name = (req.body.name || "").trim(); + const categoryId = req.body.category_id + ? Number.parseInt(req.body.category_id, 10) + : null; - const { name, category_id } = req.body; - - if (!name || name.trim().length === 0) { - req.flash("error", "Geef een productnaam op"); + if (!name || (categoryId !== null && !Number.isInteger(categoryId))) { + req.flash("error", "Geef een geldige productnaam en categorie op."); return res.redirect("/products"); } ProductService.createProduct({ - name: name.trim(), - category_id: category_id || null + name, + category_id: categoryId }); - req.flash("success", "Product toegevoegd"); + req.flash("success", "Product toegevoegd."); res.redirect("/products"); - } + + } + module.exports = new ProductController(); \ No newline at end of file diff --git a/controllers/ShoppingListController.js b/controllers/ShoppingListController.js index 6b23544..eff516d 100644 --- a/controllers/ShoppingListController.js +++ b/controllers/ShoppingListController.js @@ -1,179 +1,71 @@ -const ShoppingListRepository = require("../repositories/ShoppingListRepository"); const ProductRepository = require("../repositories/ProductRepository"); +const ShoppingListRepository = require("../repositories/ShoppingListRepository"); class ShoppingListController { - index(req, res) { - - const lists = ShoppingListRepository.getByHousehold( - req.user.household_id - ); - + const lists = ShoppingListRepository.getByHousehold(req.user.household_id); res.locals.title = "Boodschappenlijsten"; - - res.render("lists/index", { - lists, - user: req.user - }); - + res.render("lists/index", { lists, user: req.user }); } create(req, res) { - - const { name } = req.body; - - if (!name || name.trim().length === 0) { - req.flash("error", "Geef een naam op"); + const name = (req.body.name || "").trim(); + if (!name) { + req.flash("error", "Geef een lijstnaam op"); return res.redirect("/lists"); } - - // Check if user has a household - if (!req.user || !req.user.household_id) { - req.flash("error", "Je bent niet aan een huishouden gekoppeld"); - return res.redirect("/lists"); - } - - ShoppingListRepository.create({ - household_id: req.user.household_id, - name: name.trim() - }); - + ShoppingListRepository.create(req.user.household_id, name); req.flash("success", "Boodschappenlijst aangemaakt"); res.redirect("/lists"); - } show(req, res) { - - const { id } = req.params; - - const list = ShoppingListRepository.getById(id); - - if (!list) { - return res.status(404).render("errors/404"); - } - - if (list.household_id !== req.user.household_id) { - return res.status(403).render("errors/404"); - } - - const items = ShoppingListRepository.getItems(id); - + const list = ShoppingListRepository.findById(req.params.id, req.user.household_id); + if (!list) return res.status(404).render("errors/404"); res.locals.title = list.name; - res.render("lists/show", { list, - items, + items: ShoppingListRepository.getItems(list.id), + products: ProductRepository.getAll(), user: req.user }); - } addItem(req, res) { - - const { id } = req.params; - const { product_id, amount } = req.body; - - const list = ShoppingListRepository.getById(id); - - if (!list) { - return res.status(404).json({ error: "Lijst niet gevonden" }); + const list = ShoppingListRepository.findById(req.params.id, req.user.household_id); + const productId = Number.parseInt(req.body.product_id, 10); + const amount = Number.parseFloat(req.body.amount || "1"); + const product = Number.isInteger(productId) ? ProductRepository.findById(productId) : null; + if (!list || !product || !Number.isFinite(amount) || amount <= 0) { + req.flash("error", "Ongeldig product of ongeldige hoeveelheid"); + return res.redirect(`/lists/${req.params.id}`); } - - if (list.household_id !== req.user.household_id) { - return res.status(403).json({ error: "Niet gemachtigd" }); - } - - const product = ProductRepository.findById(product_id); - - if (!product) { - return res.status(404).json({ error: "Product niet gevonden" }); - } - - const quantity = Number(amount); - if (!Number.isFinite(quantity) || quantity <= 0 || quantity > 999) { - req.flash("error", "Vul een geldige hoeveelheid in"); - return res.redirect(`/lists/${id}`); - } - - const item = ShoppingListRepository.addItem({ - list_id: id, - product_id, - amount: quantity - }); - - req.app.locals.io.to(`household:${req.user.household_id}`).emit("item:added", { - listId: Number(id) - }); - - req.flash("success", "Product toegevoegd"); - - if (req.xhr || req.headers.accept?.includes("application/json")) { - return res.json({ success: true, item }); - } - - res.redirect(`/lists/${id}`); - + ShoppingListRepository.addItem(list.id, product.id, amount); + res.redirect(`/lists/${list.id}`); } toggleItem(req, res) { - - const { id, itemId } = req.params; - - const list = ShoppingListRepository.getById(id); - - if (!list || list.household_id !== req.user.household_id) { - return res.status(403).json({ error: "Niet gemachtigd" }); - } - - if (!ShoppingListRepository.findItem(id, itemId)) { - return res.status(404).json({ error: "Item niet gevonden" }); - } - - ShoppingListRepository.toggleItem(itemId); - - req.app.locals.io.to(`household:${req.user.household_id}`).emit("item:toggled", { - listId: Number(id), itemId: Number(itemId) - }); - - if (req.xhr || req.headers.accept?.includes("application/json")) { - return res.json({ success: true }); - } - - res.redirect(`/lists/${id}`); - + const list = ShoppingListRepository.findById(req.params.id, req.user.household_id); + if (!list) return res.status(404).render("errors/404"); + ShoppingListRepository.toggleItem(list.id, req.params.itemId); + this.broadcastUpdate(req, list.id); + res.redirect(`/lists/${list.id}`); } deleteItem(req, res) { - - const { id, itemId } = req.params; - - const list = ShoppingListRepository.getById(id); - - if (!list || list.household_id !== req.user.household_id) { - return res.status(403).json({ error: "Niet gemachtigd" }); - } - - if (!ShoppingListRepository.findItem(id, itemId)) { - return res.status(404).json({ error: "Item niet gevonden" }); - } - - ShoppingListRepository.deleteItem(itemId); - - req.app.locals.io.to(`household:${req.user.household_id}`).emit("item:removed", { - listId: Number(id), itemId: Number(itemId) - }); - - req.flash("success", "Product verwijderd"); - - if (req.method === "DELETE" || req.xhr || req.headers.accept?.includes("application/json")) { - return res.json({ success: true }); - } - - res.redirect(`/lists/${id}`); - + const list = ShoppingListRepository.findById(req.params.id, req.user.household_id); + if (!list) return res.status(404).json({ error: "Lijst niet gevonden" }); + const result = ShoppingListRepository.deleteItem(list.id, req.params.itemId); + if (result.changes === 0) return res.status(404).json({ error: "Product niet gevonden" }); + this.broadcastUpdate(req, list.id); + res.json({ success: true }); } + broadcastUpdate(req, listId) { + if (req.app.locals.io) { + req.app.locals.io.to(`list:${listId}`).emit("list:updated", { listId }); + } + } } module.exports = new ShoppingListController(); diff --git a/database/seed.js b/database/seed.js index 91c1f4d..bc1115b 100644 --- a/database/seed.js +++ b/database/seed.js @@ -2,96 +2,42 @@ require("dotenv").config(); const db = require("../config/database"); - const categories = [ - ["Groente", "๐ฅฌ"], - ["Fruit", "๐"], - ["Zuivel", "๐ฅ"], - ["Brood", "๐"], - ["Dranken", "๐ฅค"], - ["Huishouden", "๐งป"] - ]; const products = [ - - [ - "Melk", - 3 - ], - - [ - "Bananen", - 2 - ], - - [ - "Brood", - 4 - ], - - [ - "Koffie", - 5 - ], - - [ - "WC papier", - 6 - ] - + ["Melk", "Zuivel"], + ["Bananen", "Fruit"], + ["Brood", "Brood"], + ["Koffie", "Dranken"], + ["WC papier", "Huishouden"] ]; - const insertCategory = db.prepare(` - -INSERT INTO categories (name, icon) -SELECT ?, ? -WHERE NOT EXISTS (SELECT 1 FROM categories WHERE name = ?) - + INSERT OR IGNORE INTO categories (name, icon) VALUES (?, ?) `); -const seedCategories = db.transaction(() => { - - for (const category of categories) { - insertCategory.run(category[0], category[1], category[0]); - } - -}); - -seedCategories(); - const insertProduct = db.prepare(` - -INSERT INTO products (name, category_id) -SELECT ?, ? -WHERE NOT EXISTS (SELECT 1 FROM products WHERE name = ?) - + INSERT OR IGNORE INTO products (name, category_id) VALUES (?, ?) `); - - - -const seedProducts = db.transaction(() => { - - - for(const product of products){ - - insertProduct.run(product[0], product[1], product[0]); - +db.transaction(() => { + for (const category of categories) { + insertCategory.run(category); } - -}); - - -seedProducts(); - + for (const [name, categoryName] of products) { + const category = db.prepare( + "SELECT id FROM categories WHERE name = ?" + ).get(categoryName); + insertProduct.run(name, category.id); + } +})(); console.log("Seed voltooid."); diff --git a/public/js/app.js b/public/js/app.js index 71b89d7..9d68a52 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -1,48 +1,11 @@ -// Socket.IO Client -const socket = typeof io === 'function' ? io() : null; +(() => { + const socket = window.io && window.io(); + if (!socket) return; -// Join household room if available -const householdId = document.querySelector('[data-household-id]')?.dataset.householdId; -if (socket && householdId) { - socket.emit('join:household', householdId); -} + const listMatch = window.location.pathname.match(/^\/lists\/(\d+)$/); + if (listMatch) socket.emit("list:join", listMatch[1]); -// Real-time list updates -socket?.on('list:updated', (data) => { - console.log('๐ Lijst bijgewerkt:', data); - window.location.reload(); -}); - -socket?.on('item:added', (data) => { - console.log('โ Item toegevoegd:', data); - window.location.reload(); -}); - -socket?.on('item:toggled', (data) => { - console.log('โ Item afgevinkt:', data); - window.location.reload(); -}); - -socket?.on('item:removed', (data) => { - console.log('โ Item verwijderd:', data); - window.location.reload(); -}); - -// Auto-remove alerts -document.addEventListener("DOMContentLoaded", () => { - - setTimeout(() => { - - document - .querySelectorAll(".alert") - .forEach(alert => { - - alert.remove(); - - }); - - }, 4000); - -}); - -console.log('โ PantryHub app geladen'); + socket.on("list:updated", ({ listId }) => { + if (window.location.pathname === `/lists/${listId}`) window.location.reload(); + }); +})(); diff --git a/public/service-worker.js b/public/service-worker.js index 7e1d1d7..e7aadf2 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,98 +1,43 @@ -const CACHE_NAME = 'pantryhub-v2'; -const urlsToCache = [ - '/', - '/css/style.css', - '/js/app.js', - '/manifest.json', - '/icons/icon.svg' -]; +const CACHE_NAME = "pantryhub-static-v3"; -// Install event -self.addEventListener('install', (event) => { +self.addEventListener("install", () => { + self.skipWaiting(); +}); + +self.addEventListener("activate", (event) => { event.waitUntil( - caches.open(CACHE_NAME).then((cache) => { - return cache.addAll(urlsToCache).catch(err => { - console.log('Cache addAll error:', err); + caches.keys().then((keys) => + Promise.all( + keys + .filter((key) => key !== CACHE_NAME) + .map((key) => caches.delete(key)) + ) + ).then(() => self.clients.claim()) + ); +}); + +self.addEventListener("fetch", (event) => { + if (event.request.method !== "GET") return; + + const url = new URL(event.request.url); + if (url.origin !== self.location.origin) return; + + // Authenticated HTML and API responses must never be served from stale cache. + if (event.request.mode === "navigate" || url.pathname.startsWith("/api/")) { + event.respondWith(fetch(event.request)); + return; + } + + event.respondWith( + caches.match(event.request).then((cached) => { + if (cached) return cached; + return fetch(event.request).then((response) => { + if (response.ok && response.type === "basic") { + const copy = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(event.request, copy)); + } + return response; }); }) ); }); - -// Activate event -self.addEventListener('activate', (event) => { - event.waitUntil( - caches.keys().then((cacheNames) => { - return Promise.all( - cacheNames.map((cacheName) => { - if (cacheName !== CACHE_NAME) { - return caches.delete(cacheName); - } - }) - ); - }) - ); -}); - -// Fetch event -self.addEventListener('fetch', (event) => { - // Skip non-GET requests - if (event.request.method !== 'GET') { - return; - } - - // Browser extensions and third-party resources cannot be stored by Cache API. - // Only handle same-origin HTTP(S) requests belonging to PantryHub. - const url = new URL(event.request.url); - if (!['http:', 'https:'].includes(url.protocol) || url.origin !== self.location.origin) { - return; - } - - // For API calls, use network-first strategy - if (event.request.url.includes('/api/')) { - event.respondWith( - fetch(event.request) - .then(response => { - const responseClone = response.clone(); - caches.open(CACHE_NAME).then(cache => { - cache.put(event.request, responseClone); - }); - return response; - }) - .catch(() => { - return caches.match(event.request); - }) - ); - return; - } - - // For other requests, use cache-first strategy - event.respondWith( - caches.match(event.request) - .then(response => { - if (response) { - return response; - } - return fetch(event.request).then(response => { - if (!response || response.status !== 200 || response.type !== 'basic') { - return response; - } - const responseClone = response.clone(); - caches.open(CACHE_NAME) - .then(cache => { - cache.put(event.request, responseClone); - }); - return response; - }); - }) - .catch(() => { - // Return offline page or empty response - return new Response('Offline - pagina niet beschikbaar', { - status: 503, - statusText: 'Service Unavailable', - headers: new Headers({ - 'Content-Type': 'text/plain' - }) - }); - }) - ); -}); diff --git a/repositories/ShoppingListRepository.js b/repositories/ShoppingListRepository.js index f58f80f..0220924 100644 --- a/repositories/ShoppingListRepository.js +++ b/repositories/ShoppingListRepository.js @@ -1,108 +1,71 @@ const db = require("../config/database"); class ShoppingListRepository { - getByHousehold(householdId) { - return db.prepare(` - SELECT - shopping_lists.*, - COUNT(shopping_list_items.id) as item_count, - SUM(CASE WHEN shopping_list_items.checked = 1 THEN 1 ELSE 0 END) as checked_count + SELECT shopping_lists.*, + COUNT(shopping_list_items.id) AS item_count, + COALESCE(SUM(shopping_list_items.checked), 0) AS checked_count FROM shopping_lists - LEFT JOIN shopping_list_items - ON shopping_lists.id = shopping_list_items.list_id - WHERE shopping_lists.household_id = ? - AND shopping_lists.archived = 0 + LEFT JOIN shopping_list_items + ON shopping_list_items.list_id = shopping_lists.id + WHERE shopping_lists.household_id = ? AND shopping_lists.archived = 0 GROUP BY shopping_lists.id - ORDER BY shopping_lists.created_at DESC + ORDER BY shopping_lists.created_at DESC, shopping_lists.id DESC `).all(householdId); - } - getById(id) { - + findById(id, householdId) { return db.prepare(` - SELECT * FROM shopping_lists WHERE id = ? - `).get(id); - - } - - create(data) { - - return db.prepare(` - INSERT INTO shopping_lists - (household_id, name) - VALUES (?, ?) - `).run(data.household_id, data.name); - + SELECT * FROM shopping_lists + WHERE id = ? AND household_id = ? + `).get(id, householdId); } getItems(listId) { - return db.prepare(` - SELECT - shopping_list_items.*, - products.name as product_name, - categories.name as category_name, - categories.icon as category_icon + SELECT shopping_list_items.*, products.name AS product_name, + categories.name AS category_name, categories.icon AS category_icon FROM shopping_list_items JOIN products ON products.id = shopping_list_items.product_id LEFT JOIN categories ON categories.id = products.category_id WHERE shopping_list_items.list_id = ? - ORDER BY shopping_list_items.checked ASC, shopping_list_items.sort_order ASC + ORDER BY shopping_list_items.checked ASC, + shopping_list_items.sort_order ASC, + shopping_list_items.created_at ASC `).all(listId); - } - addItem(data) { - + create(householdId, name) { return db.prepare(` - INSERT INTO shopping_list_items - (list_id, product_id, amount) - VALUES (?, ?, ?) - `).run(data.list_id, data.product_id, data.amount); - + INSERT INTO shopping_lists (household_id, name) VALUES (?, ?) + `).run(householdId, name); } - findItem(listId, itemId) { - + addItem(listId, productId, amount) { + const nextSortOrder = db.prepare(` + SELECT COALESCE(MAX(sort_order), -1) + 1 AS value + FROM shopping_list_items WHERE list_id = ? + `).get(listId).value; return db.prepare(` - SELECT id FROM shopping_list_items - WHERE id = ? AND list_id = ? - `).get(itemId, listId); - + INSERT INTO shopping_list_items (list_id, product_id, amount, sort_order) + VALUES (?, ?, ?, ?) + `).run(listId, productId, amount, nextSortOrder); } - toggleItem(itemId) { - + toggleItem(listId, itemId) { return db.prepare(` UPDATE shopping_list_items - SET checked = CASE WHEN checked = 1 THEN 0 ELSE 1 END - WHERE id = ? - `).run(itemId); - + SET checked = CASE checked WHEN 0 THEN 1 ELSE 0 END + WHERE id = ? AND list_id = ? + `).run(itemId, listId); } - deleteItem(itemId) { - + deleteItem(listId, itemId) { return db.prepare(` - DELETE FROM shopping_list_items - WHERE id = ? - `).run(itemId); - + DELETE FROM shopping_list_items WHERE id = ? AND list_id = ? + `).run(itemId, listId); } - - archiveList(listId) { - - return db.prepare(` - UPDATE shopping_lists - SET archived = 1 - WHERE id = ? - `).run(listId); - - } - } module.exports = new ShoppingListRepository(); diff --git a/routes/api.js b/routes/api.js index ae7f8f3..718c462 100644 --- a/routes/api.js +++ b/routes/api.js @@ -1,43 +1,8 @@ const router = require("express").Router(); - const auth = require("../middleware/auth"); - const ProductRepository = require("../repositories/ProductRepository"); -const ShoppingListRepository = require("../repositories/ShoppingListRepository"); -// Get all products -router.get("/products", auth, (req, res) => { - - const products = ProductRepository.getAll(); - - res.json(products); - -}); - -// Get shopping lists for household -router.get("/lists", auth, (req, res) => { - - const lists = ShoppingListRepository.getByHousehold( - req.user.household_id - ); - - res.json(lists); - -}); - -// Get shopping list items -router.get("/lists/:id/items", auth, (req, res) => { - - const list = ShoppingListRepository.getById(req.params.id); - - if (!list || list.household_id !== req.user.household_id) { - return res.status(403).json({ error: "Not authorized" }); - } - - const items = ShoppingListRepository.getItems(req.params.id); - - res.json(items); - -}); +router.use(auth); +router.get("/products", (req, res) => res.json(ProductRepository.getAll())); module.exports = router; diff --git a/routes/web.js b/routes/web.js index 0702f36..94ae778 100644 --- a/routes/web.js +++ b/routes/web.js @@ -20,6 +20,27 @@ router.get( DashboardController.index ); +router.get( + "/household", + auth, + HouseholdController.index.bind(HouseholdController) +); + +router.get( + "/products", + + auth, + + ProductController.index.bind(ProductController) + +); + +router.post( + "/products", + auth, + ProductController.create.bind(ProductController) +); + router.get( "/lists", auth, @@ -56,22 +77,4 @@ router.delete( ShoppingListController.deleteItem.bind(ShoppingListController) ); -router.get( - "/household", - auth, - HouseholdController.index.bind(HouseholdController) -); - -router.get( - "/products", - auth, - ProductController.index.bind(ProductController) -); - -router.post( - "/products", - auth, - ProductController.create.bind(ProductController) -); - module.exports = router; \ No newline at end of file diff --git a/sockets/handlers.js b/sockets/handlers.js index b269d7a..d623208 100644 --- a/sockets/handlers.js +++ b/sockets/handlers.js @@ -1,55 +1,12 @@ const UserRepository = require("../repositories/UserRepository"); -module.exports = function(io) { - +module.exports = function registerSocketHandlers(io) { io.on("connection", (socket) => { - - const userId = socket.request.session?.userId; + const userId = socket.request.session && socket.request.session.userId; const user = userId && UserRepository.findById(userId); - - if (!user || !user.household_id) { - socket.disconnect(true); - return; - } + if (!user || !user.household_id) return socket.disconnect(true); socket.join(`household:${user.household_id}`); - - console.log("๐ Gebruiker verbonden:", socket.id); - - socket.on("join:household", () => { - // The room is derived from the authenticated session above. - }); - - socket.on("list:updated", (data) => { - - io.to(`household:${data.householdId}`).emit("list:updated", data); - - }); - - socket.on("item:added", (data) => { - - io.to(`household:${data.householdId}`).emit("item:added", data); - - }); - - socket.on("item:toggled", (data) => { - - io.to(`household:${data.householdId}`).emit("item:toggled", data); - - }); - - socket.on("item:removed", (data) => { - - io.to(`household:${data.householdId}`).emit("item:removed", data); - - }); - - socket.on("disconnect", () => { - - console.log("โ Gebruiker verbroken:", socket.id); - - }); - + socket.on("list:join", (listId) => socket.join(`list:${listId}`)); }); - }; diff --git a/views/auth/login.ejs b/views/auth/login.ejs index ed12ea3..caf6377 100644 --- a/views/auth/login.ejs +++ b/views/auth/login.ejs @@ -78,6 +78,10 @@ +
+ Nog geen account? Registreren +
+ diff --git a/views/layouts/main.ejs b/views/layouts/main.ejs index 8c6ec7c..26b928d 100644 --- a/views/layouts/main.ejs +++ b/views/layouts/main.ejs @@ -1,5 +1,5 @@ - - + + @@ -7,26 +7,39 @@ + + +Je hebt nog geen boodschappenlijsten. Maak er een aan!
- + <% if (lists.length === 0) { %> +Je hebt nog geen boodschappenlijsten.
<% } else { %> -Nog geen producten op de lijst.
- <% } else { %> -Nog geen producten.
- <% } else { %> -