function createToastContainer() { const container = document.createElement('div'); container.id = 'toastContainer'; container.className = 'toast-container position-fixed bottom-0 end-0 p-3'; document.body.appendChild(container); return container; } // Simple toast helper function showToast(message, type) { const toastContainer = document.getElementById('toastContainer') || createToastContainer(); const toast = document.createElement('div'); toast.className = `toast align-items-center text-white bg-${type} border-0`; toast.role = 'alert'; toast.innerHTML = `
${message}
`; toastContainer.appendChild(toast); const bsToast = new bootstrap.Toast(toast, { delay: 3000 }); bsToast.show(); toast.addEventListener('hidden.bs.toast', () => toast.remove()); } function downloadBarcode(svgId, filename = "barcode.png") { const svg = document.getElementById(svgId); const serializer = new XMLSerializer(); const svgString = serializer.serializeToString(svg); const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); // Optionally set canvas size const bbox = svg.getBBox(); canvas.width = bbox.width + 20; // padding canvas.height = bbox.height + 20; const img = new Image(); const svgBlob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" }); const url = URL.createObjectURL(svgBlob); img.onload = () => { ctx.drawImage(img, 0, 0); URL.revokeObjectURL(url); const pngUrl = canvas.toDataURL("image/png"); const a = document.createElement("a"); a.href = pngUrl; a.download = filename; a.click(); }; img.src = url; } function printBarcode(svgId) { const svg = document.getElementById(svgId); if (!svg) return; // Serialize the SVG const serializer = new XMLSerializer(); const svgString = serializer.serializeToString(svg); // Open a new window for printing const printWindow = window.open('', '_blank'); printWindow.document.write(` Print Barcode ${svgString} `); printWindow.document.close(); printWindow.focus(); printWindow.print(); printWindow.close(); } function getBarcodeValue(BARCODE_TYPE, assetId) { if (!assetId) return ""; const type = BARCODE_TYPE.toUpperCase(); if (type === "EAN13") { let numeric = assetId.replace(/\D/g, ""); if (numeric.length < 12) { numeric = numeric.padStart(12, "0"); } else if (numeric.length > 12) { numeric = numeric.slice(0, 12); } return numeric; } else if (type === "EAN8") { let numeric = assetId.replace(/\D/g, ""); if (numeric.length < 7) { numeric = numeric.padStart(7, "0"); } else if (numeric.length > 7) { numeric = numeric.slice(0, 7); } return numeric; } else if (type === "UPC") { let numeric = assetId.replace(/\D/g, ""); if (numeric.length < 11) { numeric = numeric.padStart(11, "0"); } else if (numeric.length > 11) { numeric = numeric.slice(0, 11); } return numeric; } else if (type === "ITF14") { let numeric = assetId.replace(/\D/g, ""); if (numeric.length < 13) { numeric = numeric.padStart(13, "0"); } else if (numeric.length > 13) { numeric = numeric.slice(0, 13); } return numeric; } else if (type === "PHARMACODE") { let numeric = assetId.replace(/\D/g, ""); if (numeric.length < 2) { numeric = numeric.padStart(6, "0"); } else if (numeric.length > 6) { numeric = numeric.slice(0, 6); } return numeric; } return assetId.toString().padStart(12, "0"); } // Table filter document.addEventListener('DOMContentLoaded', () => { const filters = document.querySelectorAll('.column-filter'); const table = document.querySelector('table'); if (table == null) { return; } const tbody = table.querySelector('tbody'); filters.forEach(filter => { filter.addEventListener('input', () => { const rows = tbody.querySelectorAll('tr'); const filterValues = Array.from(filters).map(f => f.value.toLowerCase().trim()); rows.forEach(row => { const cells = row.querySelectorAll('td'); let visible = true; filterValues.forEach((val, i) => { if (val && !cells[i].textContent.toLowerCase().includes(val)) { visible = false; } }); row.style.display = visible ? '' : 'none'; }); }); }); }); async function loadLocationsIntoSelect(selectElement, selectedValue = null) { try { const response = await fetch('/Locations/GetAll'); const data = await response.json(); const locations = data.locations; const ts = selectElement.tomselect; if (!ts) { selectElement.innerHTML = ``; locations.forEach(loc => { const option = document.createElement('option'); option.value = loc.location; option.textContent = loc.location; if (selectedValue && selectedValue === loc.location) { option.selected = true; } selectElement.appendChild(option); }); return; } ts.clearOptions(); ts.addOption(locations.map(loc => ({ value: loc.location, text: loc.location }))); ts.refreshOptions(false); if (selectedValue) { ts.setValue(selectedValue); } else { ts.clear(true); } } catch (err) { console.error('Error loading locations:', err); showToast(appTranslations.errorLoadingLocations, 'danger'); } } async function loadUsersIntoSelect(selectElement, selectedValue = null) { try { const response = await fetch('/Users/GetAll?Cn=false&Sn=false&Title=false&Description=false&JpegPhoto=false&UserPassword=false'); const users = await response.json(); const ts = selectElement.tomselect; if (!ts) { selectElement.innerHTML = ``; users.forEach(u => { const opt = document.createElement('option'); opt.value = u.uid; opt.textContent = u.uid; selectElement.appendChild(opt); }); return; } ts.clearOptions(); ts.addOption(users.map(u => ({ value: u.uid, text: u.uid }))); ts.refreshOptions(false); if (selectedValue) ts.setValue(selectedValue); } catch (err) { console.error('Error loading users:', err); showToast(appTranslations.errorLoadingUsers, 'danger'); } } function validatePassword(password) { // Regex: min 8 chars, one uppercase, one lowercase, one number, one special char const strongPasswordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_\-+=\[{\]};:'",<.>/?\\|`~]).{8,}$/; return strongPasswordRegex.test(password); } function unflatten(obj) { const result = {}; for (const [key, value] of Object.entries(obj)) { const parts = key.split("."); let current = result; for (let i = 0; i < parts.length; i++) { const part = parts[i]; if (i === parts.length - 1) { if (typeof value === "string" && /^[\[{]/.test(value.trim())) { try { current[part] = JSON.parse(value); } catch { current[part] = value; } } else { current[part] = value; } } else { current[part] = current[part] || {}; current = current[part]; } } } return result; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function loadPresetsIntoSelect(selectElement, selectedValue = null) { try { const response = await fetch('/Settings/Presets'); const responseJson = await response.json(); var presets = []; for (var key in responseJson) { presets.push(key); } console.log(presets); const ts = selectElement.tomselect; if (!ts) { selectElement.innerHTML = ``; presets.forEach(u => { const opt = document.createElement('option'); opt.value = u; opt.textContent = u; selectElement.appendChild(opt); }); return; } ts.clearOptions(); ts.addOption(presets.map(u => ({ value: u, text: u }))); ts.refreshOptions(false); if (selectedValue) ts.setValue(selectedValue); } catch (err) { console.error('Error loading presets:', err); showToast(appTranslations.errorLoadingPresets, 'danger'); } }