implemented ui functions for managing products, uploading images and editiing users
This commit is contained in:
65
static/pages/admin_products.js
Normal file
65
static/pages/admin_products.js
Normal file
@ -0,0 +1,65 @@
|
||||
let uploadFileInput = document.getElementById('imgUpload');
|
||||
let fileName = document.getElementById('fileName');
|
||||
let imgUploadForm = document.getElementById('imgUploadForm');
|
||||
|
||||
function handleImagePresence(row) {
|
||||
// Check if /api/v1/image?id=row&check returns true
|
||||
// Needs to be sync
|
||||
|
||||
let isThere = false;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', `/api/v1/image?id=${row.id}&check=true`, false);
|
||||
xhr.send();
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
isThere = JSON.parse(xhr.responseText);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
isThere = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let pretty = isThere ? '<i class="bi bi-check"></i>' : '<i class="bi bi-x"></i></a>';
|
||||
const template = `<a href="/api/v1/image?id=${row.id}" target="_blank">${pretty}</a> <i class="bi bi-dot"></i> <button class="btn btn-primary" onclick="uploadImage(${row.id})">Upload</button>`;
|
||||
return template;
|
||||
}
|
||||
|
||||
function uploadImage(id) {
|
||||
// Open a file picker
|
||||
uploadFileInput.click();
|
||||
// // Open a modal to upload an image
|
||||
// // Use a form
|
||||
// const modal = document.getElementById('imageModal');
|
||||
// modal.style.display = 'block';
|
||||
imgUploadForm.action = `/api/v1/image?id=${id}`;
|
||||
}
|
||||
|
||||
function silentFormSubmit() {
|
||||
// Submit the form silently (without reloading the page or redirecting)
|
||||
// Grab the form and do a POST request (dont forget to prevent default)
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', imgUploadForm.action, true);
|
||||
xhr.send(new FormData(imgUploadForm));
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
console.log(xhr.responseText);
|
||||
//location.reload();
|
||||
createTemporaryNotification('Bild hochgeladen', 'is-success');
|
||||
// Close the modal
|
||||
document.getElementById('imageModal').style.display = "none";
|
||||
|
||||
// Empty the input
|
||||
uploadFileInput.value = '';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
uploadFileInput.addEventListener('change', function() {
|
||||
fileName.innerHTML = this.files[0].name;
|
||||
silentFormSubmit();
|
||||
setTimeout(() => {
|
||||
refreshTableByName('products');
|
||||
}, 1000);
|
||||
});
|
2
static/pages/admin_users.js
Normal file
2
static/pages/admin_users.js
Normal file
@ -0,0 +1,2 @@
|
||||
let elm_table_users = document.getElementById('table_users');
|
||||
|
4
static/pages/payup.js
Normal file
4
static/pages/payup.js
Normal file
@ -0,0 +1,4 @@
|
||||
const tableContent = document.querySelector('.table-content');
|
||||
const tableSum = document.querySelector('.table-sum');
|
||||
|
||||
alert("NYI: Endpoint is not yet implemented. This demo ends here.");
|
@ -2,11 +2,35 @@ console.log('product_select.js loaded');
|
||||
|
||||
// Get containers
|
||||
let mainSelectionDiv = document.getElementById('mainSelect');
|
||||
let checkoutTable = document.getElementById('selectedProducts');
|
||||
|
||||
let sumField = document.getElementById('TableSum');
|
||||
|
||||
let toCheckoutButton = document.getElementById('checkout');
|
||||
let confirmCartButton = document.getElementById('confirmCheckout');
|
||||
|
||||
let loadingModal = document.getElementById('loadingModal');
|
||||
|
||||
let scannerField = document.getElementById('scannerField');
|
||||
|
||||
const baseStruct = document.getElementById("baseStruct");
|
||||
|
||||
let globalData;
|
||||
|
||||
let shoppingCart = [];
|
||||
|
||||
toCheckoutButton.addEventListener('click', finalizeTransaction);
|
||||
confirmCartButton.addEventListener('click', confirmedCart);
|
||||
|
||||
// Get user from url (and cookie)
|
||||
let userFCookie = getCookie('user');
|
||||
let userFUrl = new URLSearchParams(window.location.search).get('user');
|
||||
|
||||
if(userFCookie != userFUrl) {
|
||||
createTemporaryNotification('Fehler: User nicht korrekt gesetzt!', 'is-danger');
|
||||
window.location.href = '/user_select';
|
||||
}
|
||||
|
||||
// On load
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
let data = await returnTableDataByTableName('products');
|
||||
@ -17,7 +41,7 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
|
||||
for(let i = 0; i < result.length; i++) {
|
||||
let product = result[i];
|
||||
if(product.visible) {
|
||||
if(product.visible && product.stock > 0) {
|
||||
let newDiv = baseStruct.cloneNode(true);
|
||||
newDiv.id = `product_${product.id}`;
|
||||
newDiv.style.display = 'block';
|
||||
@ -27,9 +51,186 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
|
||||
newDiv.querySelector('.product_price').innerText = price + " €";
|
||||
newDiv.querySelector('.product_ean').innerText = product.gtin;
|
||||
newDiv.querySelector('.product_image').src = product.image || "https://bulma.io/assets/images/placeholders/1280x960.png";
|
||||
newDiv.querySelector('.product_image').src = "/api/v1/image?id=" + product.id;
|
||||
newDiv.querySelector('.product_image').alt = product.name;
|
||||
|
||||
newDiv.addEventListener('click', selectProductEvent);
|
||||
mainSelectionDiv.appendChild(newDiv);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function canIAddProduct(product, shoppingCart) {
|
||||
let stock = product.stock;
|
||||
let count = shoppingCart.filter(p => p.id == product.id).length;
|
||||
return count < stock;
|
||||
}
|
||||
|
||||
function selectProductEvent(e) {
|
||||
console.log('selectProductEvent', e);
|
||||
let id = e.currentTarget.id.split('_')[1];
|
||||
let product = globalData.find(p => p.id == id);
|
||||
if(!canIAddProduct(product, shoppingCart)) {
|
||||
createTemporaryNotification('Nicht genug Lagerbestand mehr vorhanden!', 'is-danger');
|
||||
return;
|
||||
}
|
||||
let price = parseFloat(product.price).toFixed(2);
|
||||
let row = checkoutTable.insertRow();
|
||||
row.id = `product_${product.id}`;
|
||||
let cell1 = row.insertCell(0); // Name
|
||||
let cell2 = row.insertCell(1); // Price
|
||||
let cell3 = row.insertCell(2); // Actions
|
||||
|
||||
shoppingCart.push(product);
|
||||
|
||||
cell1.innerText = product.name;
|
||||
cell2.innerText = price + " €";
|
||||
let deleteButton = document.createElement('button');
|
||||
deleteButton.innerHTML = '<i class="bi bi-trash"></i>';
|
||||
deleteButton.onclick = deleteProductEvent;
|
||||
deleteButton.className = 'button is-danger';
|
||||
deleteButton.style.color = 'white';
|
||||
cell3.appendChild(deleteButton);
|
||||
|
||||
|
||||
sumField.innerText = calculateSum(shoppingCart);
|
||||
}
|
||||
|
||||
function calculateSum(cart) {
|
||||
let sum = 0;
|
||||
for(let i = 0; i < cart.length; i++) {
|
||||
sum += parseFloat(cart[i].price);
|
||||
}
|
||||
return sum.toFixed(2) + " €";
|
||||
}
|
||||
|
||||
function deleteProductEvent(e) {
|
||||
let row = e.target.parentElement.parentElement;
|
||||
// Check if icon was clicked instead of button
|
||||
if(row.tagName != 'TR') {
|
||||
row = e.target.parentElement.parentElement.parentElement;
|
||||
}
|
||||
let id = row.id.split('_')[1];
|
||||
let product = shoppingCart.find(p => p.id == id);
|
||||
let index = shoppingCart.indexOf(product);
|
||||
shoppingCart.splice(index, 1);
|
||||
row.remove();
|
||||
sumField.innerText = calculateSum(shoppingCart);
|
||||
}
|
||||
|
||||
function finalizeTransaction() {
|
||||
if(shoppingCart.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show confirmation dialog (id-> checkoutModal)
|
||||
let modal = document.getElementById('checkoutModal');
|
||||
modal.classList.add('is-active');
|
||||
let modalContent = document.getElementById('modalContent');
|
||||
|
||||
// Grab table in modal
|
||||
let modalTable = document.getElementById('selectedProductsModal');
|
||||
modalTable.innerHTML = "";
|
||||
for(let i = 0; i < shoppingCart.length; i++) {
|
||||
let product = shoppingCart[i];
|
||||
let row = modalTable.insertRow();
|
||||
let cell1 = row.insertCell(0); // Name
|
||||
let cell2 = row.insertCell(1); // Price
|
||||
cell1.innerText = product.name;
|
||||
cell2.innerText = parseFloat(product.price).toFixed(2) + " €";
|
||||
}
|
||||
|
||||
let modalSum = document.getElementById('ModalSum');
|
||||
modalSum.innerText = calculateSum(shoppingCart);
|
||||
}
|
||||
|
||||
function confirmedCart() {
|
||||
// Close modal
|
||||
let modal = document.getElementById('checkoutModal');
|
||||
modal.classList.remove('is-active');
|
||||
|
||||
// Show loading modal
|
||||
loadingModal.classList.add('is-active');
|
||||
|
||||
// Send data to server
|
||||
// alert('NYI: Send data to server. This demo ends here.');
|
||||
|
||||
let listOfIds = shoppingCart.map(p => p.id);
|
||||
let data = {
|
||||
products: listOfIds,
|
||||
user_id: getCookie('user')
|
||||
};
|
||||
|
||||
// Send data to server
|
||||
fetch('/api/v1/transaction', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(async (response) => {
|
||||
let json = await response.json();
|
||||
if(response.ok) {
|
||||
createTemporaryNotification('<i class="bi bi-check-lg"></i> Erfolgreich abgeschlossen', 'is-success');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/user_select';
|
||||
}, 1000);
|
||||
} else {
|
||||
createTemporaryNotification('Fehler: ' + json.error, 'is-danger');
|
||||
}
|
||||
loadingModal.classList.remove('is-active');
|
||||
}).catch((error) => {
|
||||
createTemporaryNotification('Fehler: ' + error, 'is-danger');
|
||||
loadingModal.classList.remove('is-active');
|
||||
});
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
let value = "; " + document.cookie;
|
||||
let parts = value.split("; " + name + "=");
|
||||
if(parts.length == 2) {
|
||||
return parts.pop().split(";").shift();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle barcode scanner
|
||||
// Force the cursor to the scanner field
|
||||
scannerField.focus();
|
||||
// Do so in an interval
|
||||
setInterval(() => {
|
||||
scannerField.focus();
|
||||
}, 1000);
|
||||
|
||||
// Make it tiny
|
||||
scannerField.style.fontSize = '1px';
|
||||
scannerField.style.height = '1px';
|
||||
scannerField.style.width = '1px';
|
||||
scannerField.style.opacity = '0';
|
||||
scannerField.style.position = 'relative';
|
||||
|
||||
// Handle barcode scanner input
|
||||
scannerField.addEventListener('keydown', async function(event) {
|
||||
if(event.key != 'Enter') {
|
||||
return;
|
||||
}
|
||||
let barcode = scannerField.value;
|
||||
console.log('Barcode scanned:', barcode);
|
||||
scannerField.value = "";
|
||||
// createTemporaryNotification(`Barcode ${barcode} gescannt`, 'is-link');
|
||||
|
||||
let product = globalData.find(p => p.gtin == barcode);
|
||||
if(product) {
|
||||
let event = new Event('click');
|
||||
createTemporaryNotification(`<i class="bi bi-upc-scan"></i> Barcode scan: GTIN ${barcode} gefunden`, 'is-success');
|
||||
document.getElementById(`product_${product.id}`).dispatchEvent(event);
|
||||
} else {
|
||||
createTemporaryNotification( `<i class="bi bi-upc-scan"></i> Barcode scan: GTIN ${barcode} nicht gefunden`, 'is-danger');
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure text fields is always centerd vertically
|
||||
window.addEventListener('scroll', function(event) {
|
||||
scannerField.y = document.documentElement.scrollTop + 20;
|
||||
scannerField.style.top = document.documentElement.scrollTop + 20 + "px";
|
||||
});
|
@ -100,12 +100,15 @@ function validatePin() {
|
||||
if(response) {
|
||||
console.log("Pin is correct");
|
||||
pinPadModal.classList.remove('is-active');
|
||||
// Write a cookie
|
||||
document.cookie = `user=${userId}`;
|
||||
document.cookie = `name=${currentUser.name}`;
|
||||
window.location.href = `/product_select?user=${userId}`;
|
||||
} else {
|
||||
console.log("Pin is incorrect");
|
||||
pinValue = "";
|
||||
updatePinFields();
|
||||
pinError.classList.remove('is-hidden');
|
||||
createTemporaryNotification('Fehlerhafte PIN Eingabe!', 'is-danger');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user