20260317d: Auto-dismiss move modal after 15s with progress bar countdown
This commit is contained in:
@@ -751,6 +751,12 @@ body {
|
|||||||
border: 2px solid var(--border);
|
border: 2px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.move-countdown-btn {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-accent {
|
.btn-accent {
|
||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
+39
-6
@@ -3570,27 +3570,58 @@ function closeLowStockPrompt() {
|
|||||||
if (cb) cb();
|
if (cb) cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _moveModalTimer = null;
|
||||||
|
let _moveModalRAF = null;
|
||||||
|
|
||||||
|
function clearMoveModalTimer() {
|
||||||
|
if (_moveModalTimer) { clearTimeout(_moveModalTimer); _moveModalTimer = null; }
|
||||||
|
if (_moveModalRAF) { cancelAnimationFrame(_moveModalRAF); _moveModalRAF = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function startMoveModalCountdown(btnId, onExpire) {
|
||||||
|
clearMoveModalTimer();
|
||||||
|
const duration = 15000;
|
||||||
|
const start = performance.now();
|
||||||
|
const btn = document.getElementById(btnId);
|
||||||
|
if (!btn) return;
|
||||||
|
function tick() {
|
||||||
|
const elapsed = performance.now() - start;
|
||||||
|
const pct = Math.max(0, 100 - (elapsed / duration) * 100);
|
||||||
|
btn.style.background = `linear-gradient(to right, var(--bg-tertiary) ${pct}%, transparent ${pct}%)`;
|
||||||
|
if (elapsed < duration) {
|
||||||
|
_moveModalRAF = requestAnimationFrame(tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_moveModalRAF = requestAnimationFrame(tick);
|
||||||
|
_moveModalTimer = setTimeout(() => {
|
||||||
|
clearMoveModalTimer();
|
||||||
|
onExpire();
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
|
||||||
function showMoveAfterUseModal(product, fromLoc, remaining, openedId) {
|
function showMoveAfterUseModal(product, fromLoc, remaining, openedId) {
|
||||||
const otherLocs = Object.entries(LOCATIONS).filter(([k]) => k !== fromLoc);
|
const otherLocs = Object.entries(LOCATIONS).filter(([k]) => k !== fromLoc);
|
||||||
const locButtons = otherLocs.map(([k, v]) =>
|
const locButtons = otherLocs.map(([k, v]) =>
|
||||||
`<button type="button" class="loc-btn" onclick="confirmMoveAfterUse(${product.id}, '${fromLoc}', '${k}', ${openedId || 0})">${v.icon} ${v.label}</button>`
|
`<button type="button" class="loc-btn" onclick="clearMoveModalTimer();confirmMoveAfterUse(${product.id}, '${fromLoc}', '${k}', ${openedId || 0})">${v.icon} ${v.label}</button>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
document.getElementById('modal-content').innerHTML = `
|
document.getElementById('modal-content').innerHTML = `
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3>📦 Spostare il resto?</h3>
|
<h3>📦 Spostare il resto?</h3>
|
||||||
<button class="modal-close" onclick="closeModal();showPage('dashboard')">✕</button>
|
<button class="modal-close" onclick="clearMoveModalTimer();closeModal();showPage('dashboard')">✕</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0 16px 16px">
|
<div style="padding:0 16px 16px">
|
||||||
<p style="margin-bottom:12px">Vuoi spostare ${openedId ? 'la confezione aperta' : 'il resto'} di <strong>${escapeHtml(product.name)}</strong> in un'altra posizione?</p>
|
<p style="margin-bottom:12px">Vuoi spostare ${openedId ? 'la confezione aperta' : 'il resto'} di <strong>${escapeHtml(product.name)}</strong> in un'altra posizione?</p>
|
||||||
<div class="location-selector">${locButtons}</div>
|
<div class="location-selector">${locButtons}</div>
|
||||||
<button type="button" class="btn btn-secondary full-width" style="margin-top:12px" onclick="closeModal();showPage('dashboard')">No, resta in ${LOCATIONS[fromLoc]?.label || fromLoc}</button>
|
<button type="button" id="btn-move-stay" class="btn btn-secondary full-width move-countdown-btn" style="margin-top:12px" onclick="clearMoveModalTimer();closeModal();showPage('dashboard')">No, resta in ${LOCATIONS[fromLoc]?.label || fromLoc}</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
document.getElementById('modal-overlay').style.display = 'flex';
|
document.getElementById('modal-overlay').style.display = 'flex';
|
||||||
|
startMoveModalCountdown('btn-move-stay', () => { closeModal(); showPage('dashboard'); });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmMoveAfterUse(productId, fromLoc, toLoc, openedId) {
|
async function confirmMoveAfterUse(productId, fromLoc, toLoc, openedId) {
|
||||||
|
clearMoveModalTimer();
|
||||||
closeModal();
|
closeModal();
|
||||||
showLoading(true);
|
showLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -5260,24 +5291,26 @@ async function submitRecipeUse(useAll) {
|
|||||||
function showRecipeMoveModal(productId, fromLoc, remaining, openedId) {
|
function showRecipeMoveModal(productId, fromLoc, remaining, openedId) {
|
||||||
const otherLocs = Object.entries(LOCATIONS).filter(([k]) => k !== fromLoc);
|
const otherLocs = Object.entries(LOCATIONS).filter(([k]) => k !== fromLoc);
|
||||||
const locButtons = otherLocs.map(([k, v]) =>
|
const locButtons = otherLocs.map(([k, v]) =>
|
||||||
`<button type="button" class="loc-btn" onclick="confirmRecipeMove(${productId}, '${fromLoc}', '${k}', ${openedId || 0})">${v.icon} ${v.label}</button>`
|
`<button type="button" class="loc-btn" onclick="clearMoveModalTimer();confirmRecipeMove(${productId}, '${fromLoc}', '${k}', ${openedId || 0})">${v.icon} ${v.label}</button>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
document.getElementById('modal-content').innerHTML = `
|
document.getElementById('modal-content').innerHTML = `
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3>📦 Spostare il resto?</h3>
|
<h3>📦 Spostare il resto?</h3>
|
||||||
<button class="modal-close" onclick="closeModal()">✕</button>
|
<button class="modal-close" onclick="clearMoveModalTimer();closeModal()">✕</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0 16px 16px">
|
<div style="padding:0 16px 16px">
|
||||||
<p style="margin-bottom:12px">Vuoi spostare ${openedId ? 'la confezione aperta' : 'il resto'} in un'altra posizione?</p>
|
<p style="margin-bottom:12px">Vuoi spostare ${openedId ? 'la confezione aperta' : 'il resto'} in un'altra posizione?</p>
|
||||||
<div class="location-selector">${locButtons}</div>
|
<div class="location-selector">${locButtons}</div>
|
||||||
<button type="button" class="btn btn-secondary full-width" style="margin-top:12px" onclick="closeModal()">No, resta in ${LOCATIONS[fromLoc]?.label || fromLoc}</button>
|
<button type="button" id="btn-move-stay" class="btn btn-secondary full-width move-countdown-btn" style="margin-top:12px" onclick="clearMoveModalTimer();closeModal()">No, resta in ${LOCATIONS[fromLoc]?.label || fromLoc}</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
document.getElementById('modal-overlay').style.display = 'flex';
|
document.getElementById('modal-overlay').style.display = 'flex';
|
||||||
|
startMoveModalCountdown('btn-move-stay', () => { closeModal(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmRecipeMove(productId, fromLoc, toLoc, openedId) {
|
async function confirmRecipeMove(productId, fromLoc, toLoc, openedId) {
|
||||||
|
clearMoveModalTimer();
|
||||||
closeModal();
|
closeModal();
|
||||||
try {
|
try {
|
||||||
if (openedId) {
|
if (openedId) {
|
||||||
|
|||||||
Binary file not shown.
+2
-2
@@ -9,7 +9,7 @@
|
|||||||
<title>Dispensa Manager</title>
|
<title>Dispensa Manager</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
|
||||||
<link rel="stylesheet" href="assets/css/style.css?v=20260317c">
|
<link rel="stylesheet" href="assets/css/style.css?v=20260317d">
|
||||||
<!-- QuaggaJS for barcode scanning -->
|
<!-- QuaggaJS for barcode scanning -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -911,6 +911,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="assets/js/app.js?v=20260317c"></script>
|
<script src="assets/js/app.js?v=20260317d"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user