Hinzufügen einer Option zum Berechnen von Pfand

This commit is contained in:
Dennis Heinrich 2025-04-09 14:47:51 +02:00
parent f93fc66af3
commit 97e3971f6f
7 changed files with 91 additions and 12 deletions

View file

@ -3,60 +3,70 @@
"id": 75086086956949000,
"name": "Wasser",
"price": "0.5",
"deposit": null,
"image": "./assets/example/images/wasser.webp"
},
{
"id": 403980494034923100,
"name": "Cola",
"price": "1",
"deposit": "0.25",
"image": "./assets/example/images/cola.webp"
},
{
"id": 174111295271372860,
"name": "Fanta",
"price": "1",
"deposit": "0.25",
"image": "./assets/example/images/fanta.webp"
},
{
"id": 13086165444583086,
"name": "Bier",
"price": "1.5",
"deposit": "0.07",
"image": "./assets/example/images/bier.webp"
},
{
"id": 227920082494117630,
"name": "Helles Bier",
"price": "1.2",
"deposit": null,
"image": "./assets/example/images/bier_helles.webp"
},
{
"id": 27617349687000040,
"name": "Apfelsaft",
"price": "1.2",
"deposit": null,
"image": "./assets/example/images/apfelsaft.webp"
},
{
"id": 191783545996520450,
"name": "Eistee",
"price": "1.5",
"deposit": null,
"image": "./assets/example/images/eistee.webp"
},
{
"id": 203321763516746460,
"name": "Cider",
"price": "1.8",
"deposit": null,
"image": "./assets/example/images/cider.webp"
},
{
"id": 615216202376277900,
"name": "Zitronenlimonade",
"price": "1",
"deposit": null,
"image": "./assets/example/images/limonade.webp"
},
{
"id": 363150314621734500,
"name": "Wodka Lemon",
"price": "3",
"deposit": null,
"image": "./assets/example/images/wodka_lemon.webp"
}
]

View file

@ -3,60 +3,70 @@
"id": 75086086956949000,
"name": "Wasser",
"price": "0.5",
"deposit": null,
"image": "https://placehold.co/250x250?text=1"
},
{
"id": 403980494034923100,
"name": "Cola",
"price": "1",
"deposit": "0.25",
"image": "https://placehold.co/250x250?text=2"
},
{
"id": 174111295271372860,
"name": "Fanta",
"price": "1",
"deposit": "0.25",
"image": "https://placehold.co/250x250?text=3"
},
{
"id": 13086165444583086,
"name": "Bier",
"price": "1.5",
"deposit": "0.07",
"image": "https://placehold.co/250x250?text=4"
},
{
"id": 227920082494117630,
"name": "Helles Bier",
"price": "1.2",
"deposit": null,
"image": "https://placehold.co/250x250?text=5"
},
{
"id": 27617349687000040,
"name": "Apfelsaft",
"price": "1.2",
"deposit": null,
"image": "https://placehold.co/250x250?text=6"
},
{
"id": 191783545996520450,
"name": "Eistee",
"price": "1.5",
"deposit": null,
"image": "https://placehold.co/250x250?text=7"
},
{
"id": 203321763516746460,
"name": "Cider",
"price": "1.8",
"deposit": null,
"image": "https://placehold.co/250x250?text=8"
},
{
"id": 615216202376277900,
"name": "Zitronenlimonade",
"price": "1",
"deposit": null,
"image": "https://placehold.co/250x250?text=9"
},
{
"id": 363150314621734500,
"name": "Wodka Lemon",
"price": "3",
"deposit": null,
"image": "https://placehold.co/250x250?text=10"
}
]

View file

@ -77,15 +77,34 @@ class Element {
return document.querySelector('.navbar-brand');
}
/**
* Get the buttons for importing test data
* @returns {Element}
*/
static getButtonsImportTestdata() {
return document.querySelectorAll('[data-action=import-testdata]');
}
/**
* Get the buttons for showing the test data
* @returns {Element}
*/
static getButtonShowTestdata() {
return document.querySelectorAll('[data-action=import-show-testdata]');
}
/**
* Get the button for clearing the test data
* @returns {Element}
*/
static getButtonClearTestdata() {
return document.querySelectorAll('[data-action=import-clear]');
}
/**
* Get the button for accessing the GitHub repository
* @returns {Element}
*/
static getGitHubReferenceLink() {
return document.querySelector('[data-github-ref]');
}
@ -122,6 +141,15 @@ class TemplateElement {
return this.removeTemplate(element);
}
/**
* Get the deposit element template
* @returns {HTMLElement}
*/
static getDepositTemplate() {
const element = document.querySelector('[data-template=product-deposit]').cloneNode(true);
return this.removeTemplate(element);
}
/**
* Remove the template attribute from the element
* @param element {HTMLElement}
@ -143,11 +171,12 @@ class Product {
* @param price {number} Price of the product
* @param image {string} Image of the product (source url or base64)
*/
constructor(name, price, image) {
constructor(name, price, deposit, image) {
this.id = Product.generateId();
this.name = name;
this.price = price;
this.image = image;
this.deposit = deposit;
}
/**
@ -324,7 +353,7 @@ class ProductManager {
* @returns {Promise<void>}
*/
async convertAndSaveProductImages(json) {
const products = json.map(e => new Product(e.name, e.price, e.image));
const products = json.map(e => new Product(e.name, e.price, e.deposit, e.image));
for (const product of products) {
if (!product.image.toString().startsWith('data:image/')) {
product.image = await Base64Image.imageResize(await Base64Image.fromImageUrl(product.image))
@ -349,7 +378,7 @@ class ProductManager {
try {
parse = JSON.parse(json);
} catch (e) {}
this.products = parse.map(e => new Product(e.name, e.price, e.image));
this.products = parse.map(e => new Product(e.name, e.price, e.deposit, e.image));
this.renderProductList();
}
@ -362,6 +391,7 @@ class ProductManager {
const name = document.querySelector('#product-name').value;
const price = document.querySelector('#product-price').value;
const deposit = document.querySelector('#product-deposit').value;
const image = document.querySelector('#product-image').files[0];
// Validate price
@ -374,12 +404,12 @@ class ProductManager {
if (image) {
const imageSrcWithBase64 = Base64Image.fromFile(image);
imageSrcWithBase64.then(async imageSrcWithBase64 => {
productManager.addProduct(new Product(name, price, await Base64Image.imageResize(imageSrcWithBase64)));
productManager.addProduct(new Product(name, price, deposit, await Base64Image.imageResize(imageSrcWithBase64)));
ProductManager.resetProductSettingsForm();
});
} else {
let image1 = await Base64Image.imageResize(await Base64Image.fromImageUrl(`https://placehold.co/250x250?text=${name}`));
productManager.addProduct(new Product(name, price, image1));
let imageDemoBase64 = await Base64Image.imageResize(await Base64Image.fromImageUrl(`https://placehold.co/250x250?text=${name}`));
productManager.addProduct(new Product(name, price, deposit, imageDemoBase64));
ProductManager.resetProductSettingsForm();
}
});
@ -450,7 +480,7 @@ class CartManager {
registerCartResetEvent() {
Element.getCartButton().addEventListener('click', () => {
CartHistoryManager.addToTotal(this.cartLines.reduce((acc, cartLine) => {
return acc + (cartLine.product.price * cartLine.quantity);
return acc + (cartLine.product.price * cartLine.quantity) + (cartLine.product.deposit * cartLine.quantity);
}, 0));
this.cartLines = [];
this.renderCart();
@ -491,10 +521,12 @@ class CartManager {
*/
renderCart() {
// Clear the cart element before rendering except the template
Element.getCartElement().querySelectorAll('[data-id]').forEach(e => {
Element.getCartElement().querySelectorAll('[data-id], .product-deposit').forEach(e => {
if (e.getAttribute('data-template') === null) {
e.remove();
}
console.log(e)
});
if(this.cartLines.length === 0) {
@ -509,6 +541,16 @@ class CartManager {
const cartLineElement = this.getCartLineElement(cartLine);
Element.getCartElement().appendChild(cartLineElement);
});
let depositTotal = 0;
this.cartLines.forEach(cartLine => {
depositTotal += cartLine.product.deposit * cartLine.quantity;
});
if(depositTotal !== 0) {
let depositElement = TemplateElement.getDepositTemplate();
depositElement.querySelector('[data-attr=deposit]').textContent = CartManager.getNumberFormatter().format(depositTotal);
Element.getCartElement().appendChild(depositElement);
}
}
/**
@ -533,7 +575,7 @@ class CartManager {
*/
calculateCartValue() {
let cartValue = this.cartLines.reduce((acc, cartLine) => {
return acc + (cartLine.product.price * cartLine.quantity);
return acc + (cartLine.product.price * cartLine.quantity) + (cartLine.product.deposit * cartLine.quantity);
}, 0);
Element.getCartButton().querySelector('[data-total-value]').textContent = CartManager.getNumberFormatter().format(cartValue);
}

View file

@ -6,9 +6,9 @@ const FILES_TO_CACHE = [
`${BASE_PATH}/`,
`${BASE_PATH}/index.html`,
`${BASE_PATH}/assets/manifest.json`,
`${BASE_PATH}/assets/script/all.js`,
`${BASE_PATH}/assets/script/service-worker.js`,
`${BASE_PATH}/assets/style/stylesheet.css`,
`${BASE_PATH}/assets/script/all.js`,
`${BASE_PATH}/node_modules/bootstrap/dist/css/bootstrap.min.css`,
`${BASE_PATH}/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js`,
`${BASE_PATH}/node_modules/bootstrap-icons/font/bootstrap-icons.min.css`,

View file

@ -48,6 +48,9 @@
font-weight: bold;
}
}
.product-deposit {
cursor: default;
}
}
/**
* Product list contains all available products,

View file

@ -45,7 +45,12 @@
</span>
<i class="bi bi-dash-circle"></i>
</li>
<ul class="list-group cart-items"></ul>
<li class="list-group-item product-deposit" data-template="product-deposit">
Zzgl. <span data-attr="deposit" class="currency-value">0,00</span> Pfand
</li>
<ul class="list-group cart-items">
</ul>
<div class="alert alert-info cart-empty">Keine Produkte ausgewählt</div>
<hr>
<button class="btn btn-secondary btn-lg w-100 cart-value mb-3">
@ -85,6 +90,13 @@
<input type="number" class="form-control" step="0.01" value="" id="product-price" required>
</div>
</div>
<div class="mb-2">
<label for="product-deposit" class="form-label">Pfand</label>
<div class="input-group">
<span class="input-group-text" id="basic-addon2"></span>
<input type="number" class="form-control" step="0.01" value="" id="product-deposit" required>
</div>
</div>
<div class="mb-2">
<label for="product-image" class="form-label">Bild auswählen</label>
<input type="file" class="form-control" placeholder="Tolles Produkt" id="product-image">

View file

@ -1,7 +1,9 @@
{
"name": "durst-rechner",
"version": "1.0.0",
"scripts": {},
"scripts": {
"dev": "npx http-server -o ."
},
"keywords": [
"calculator",
"feuerwehr",