feat: immediate api refresh on flag, fix timestamp fallback (v1.4.14)
This commit is contained in:
2
dist/bookmarklet-payload.js
vendored
2
dist/bookmarklet-payload.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bookmarklet.txt
vendored
2
dist/bookmarklet.txt
vendored
File diff suppressed because one or more lines are too long
18
dist/install.html
vendored
18
dist/install.html
vendored
File diff suppressed because one or more lines are too long
98
dist/kantine-standalone.html
vendored
98
dist/kantine-standalone.html
vendored
@@ -2021,7 +2021,7 @@ body {
|
||||
<div class="brand">
|
||||
<span class="material-icons-round logo-icon">restaurant_menu</span>
|
||||
<div class="header-left">
|
||||
<h1>Kantinen Übersicht <small class="version-tag" style="font-size: 0.6em; opacity: 0.7; font-weight: 400; cursor: pointer;" title="Klick für Versionsmenü">v1.4.13</small></h1>
|
||||
<h1>Kantinen Übersicht <small class="version-tag" style="font-size: 0.6em; opacity: 0.7; font-weight: 400; cursor: pointer;" title="Klick für Versionsmenü">v1.4.14</small></h1>
|
||||
<div id="last-updated-subtitle" class="subtitle"></div>
|
||||
</div>
|
||||
<div class="nav-group" style="margin-left: 1rem;">
|
||||
@@ -2163,7 +2163,7 @@ body {
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<strong>Aktuell:</strong> <span id="version-current">v1.4.13</span>
|
||||
<strong>Aktuell:</strong> <span id="version-current">v1.4.14</span>
|
||||
</div>
|
||||
<div class="dev-toggle">
|
||||
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;">
|
||||
@@ -2889,6 +2889,67 @@ body {
|
||||
localStorage.setItem('kantine_flags', JSON.stringify([...userFlags]));
|
||||
}
|
||||
|
||||
async function refreshFlaggedItems() {
|
||||
if (userFlags.size === 0) return;
|
||||
const token = authToken || GUEST_TOKEN;
|
||||
const datesToFetch = new Set();
|
||||
|
||||
for (const flagId of userFlags) {
|
||||
const [dateStr] = flagId.split('_');
|
||||
datesToFetch.add(dateStr);
|
||||
}
|
||||
|
||||
let updated = false;
|
||||
for (const dateStr of datesToFetch) {
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE}/venues/${VENUE_ID}/menu/${MENU_ID}/${dateStr}/`, {
|
||||
headers: apiHeaders(token)
|
||||
});
|
||||
if (!resp.ok) continue;
|
||||
const data = await resp.json();
|
||||
const menuGroups = data.results || [];
|
||||
let dayItems = [];
|
||||
for (const group of menuGroups) {
|
||||
if (group.items && Array.isArray(group.items)) {
|
||||
dayItems = dayItems.concat(group.items);
|
||||
}
|
||||
}
|
||||
|
||||
// Update allWeeks in memory
|
||||
for (let week of allWeeks) {
|
||||
if (!week.days) continue;
|
||||
let dayObj = week.days.find(d => d.date === dateStr);
|
||||
if (dayObj) {
|
||||
dayObj.items = dayItems.map(item => {
|
||||
const isUnlimited = item.amount_tracking === false;
|
||||
const hasStock = parseInt(item.available_amount) > 0;
|
||||
return {
|
||||
id: `${dateStr}_${item.id}`,
|
||||
articleId: item.id,
|
||||
name: item.name || 'Unknown',
|
||||
description: item.description || '',
|
||||
price: parseFloat(item.price) || 0,
|
||||
available: isUnlimited || hasStock,
|
||||
availableAmount: parseInt(item.available_amount) || 0,
|
||||
amountTracking: item.amount_tracking !== false
|
||||
};
|
||||
});
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error refreshing flag date', dateStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
saveMenuCache();
|
||||
updateLastUpdatedTime(new Date().toISOString());
|
||||
updateAlarmBell();
|
||||
renderVisibleWeeks();
|
||||
}
|
||||
}
|
||||
|
||||
function updateAlarmBell() {
|
||||
const bellBtn = document.getElementById('alarm-bell');
|
||||
const bellIcon = document.getElementById('alarm-bell-icon');
|
||||
@@ -2896,12 +2957,14 @@ body {
|
||||
|
||||
if (userFlags.size === 0) {
|
||||
bellBtn.classList.add('hidden');
|
||||
bellBtn.style.display = 'none';
|
||||
bellIcon.style.color = 'var(--text-secondary)';
|
||||
bellIcon.style.textShadow = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
bellBtn.classList.remove('hidden');
|
||||
bellBtn.style.display = 'inline-flex';
|
||||
|
||||
// Check if any flagged item is available
|
||||
let anyAvailable = false;
|
||||
@@ -2920,15 +2983,20 @@ body {
|
||||
if (anyAvailable) break;
|
||||
}
|
||||
|
||||
const lastUpdatedStr = localStorage.getItem('kantine_last_updated');
|
||||
let timeStr = 'Unbekannt';
|
||||
if (lastUpdatedStr) {
|
||||
const lastUpdated = new Date(lastUpdatedStr);
|
||||
const diffMs = Date.now() - lastUpdated.getTime();
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
if (diffMins < 60) timeStr = `vor ${diffMins} Min.`;
|
||||
else timeStr = `vor ${Math.floor(diffMins / 60)} Std.`;
|
||||
let lastUpdatedStr = localStorage.getItem('kantine_last_updated');
|
||||
let timeStr = 'gerade eben'; // Fallback instead of Unbekannt
|
||||
if (!lastUpdatedStr) {
|
||||
lastUpdatedStr = new Date().toISOString();
|
||||
localStorage.setItem('kantine_last_updated', lastUpdatedStr);
|
||||
}
|
||||
|
||||
const lastUpdated = new Date(lastUpdatedStr);
|
||||
const diffMs = Date.now() - lastUpdated.getTime();
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
if (diffMins < 1) timeStr = 'gerade eben';
|
||||
else if (diffMins < 60) timeStr = `vor ${diffMins} Min.`;
|
||||
else timeStr = `vor ${Math.floor(diffMins / 60)} Std.`;
|
||||
|
||||
bellBtn.title = `Zuletzt geprüft: ${timeStr}`;
|
||||
|
||||
if (anyAvailable) {
|
||||
@@ -2942,11 +3010,13 @@ body {
|
||||
|
||||
function toggleFlag(date, articleId, name, cutoff) {
|
||||
const id = `${date}_${articleId}`;
|
||||
let flagAdded = false;
|
||||
if (userFlags.has(id)) {
|
||||
userFlags.delete(id);
|
||||
showToast(`Flag entfernt für ${name}`, 'success');
|
||||
} else {
|
||||
userFlags.add(id);
|
||||
flagAdded = true;
|
||||
showToast(`Benachrichtigung aktiviert für ${name}`, 'success');
|
||||
if (Notification.permission === 'default') {
|
||||
Notification.requestPermission();
|
||||
@@ -2955,6 +3025,10 @@ body {
|
||||
saveFlags();
|
||||
updateAlarmBell();
|
||||
renderVisibleWeeks();
|
||||
|
||||
if (flagAdded) {
|
||||
refreshFlaggedItems();
|
||||
}
|
||||
}
|
||||
|
||||
// FR-019: Auto-remove flags whose cutoff has passed
|
||||
@@ -3895,7 +3969,7 @@ body {
|
||||
|
||||
// Periodic update check (runs on init + every hour)
|
||||
async function checkForUpdates() {
|
||||
const currentVersion = 'v1.4.13';
|
||||
const currentVersion = 'v1.4.14';
|
||||
const devMode = localStorage.getItem('kantine_dev_mode') === 'true';
|
||||
|
||||
try {
|
||||
@@ -3936,7 +4010,7 @@ body {
|
||||
const modal = document.getElementById('version-modal');
|
||||
const container = document.getElementById('version-list-container');
|
||||
const devToggle = document.getElementById('dev-mode-toggle');
|
||||
const currentVersion = 'v1.4.13';
|
||||
const currentVersion = 'v1.4.14';
|
||||
|
||||
if (!modal) return;
|
||||
modal.classList.remove('hidden');
|
||||
|
||||
Reference in New Issue
Block a user