improved caching to handle multi-tabs and save some requests

This commit is contained in:
Luca Haid
2025-09-11 10:33:50 +00:00
parent e989cbfc28
commit 865992c6a0

View File

@@ -39,9 +39,11 @@ document.body.insertAdjacentHTML('beforeend', `
class VodiaIdentitySwitcher {
API_BASE_URL = window.baseurl || '/';
POLLING_INTERVAL_MS = 30000;
CACHE_DURATION_MS = 30000;
CACHE_KEY = 'vodiaIdentityCache'; // Key for localStorage
POLLING_INTERVAL_MS = 60000;
CACHE_DURATION_MS = 60000;
CACHE_KEY = 'vodiaIdentityCache';
LOADING_CACHE_KEY = 'vodiaIdentityCache_loading';
LOADING_TIMEOUT_MS = 2000;
TEXT = {
checking: "Prüfe...",
@@ -49,10 +51,8 @@ class VodiaIdentitySwitcher {
dropdownTitle: "Ausgehende Identität wählen:",
ownExtension: "Eigene Nummer",
customIdentity: "Andere Nummer",
// ## START: ADDED TEXT ##
noActiveCall: "Kein aktiver Anruf gefunden.",
lookupError: "Fehler bei der Anrufabfrage."
// ## END: ADDED TEXT ##
};
pollingTimer = null;
@@ -74,24 +74,23 @@ class VodiaIdentitySwitcher {
this.getVodiaIdentity();
}
_getCache() {
const cachedString = localStorage.getItem(this.CACHE_KEY);
_getCache(key) {
const cachedString = localStorage.getItem(key);
if (!cachedString) return null;
try {
return JSON.parse(cachedString);
} catch (e) {
console.error("Vodia Cache Error: Could not parse cached data.", e);
localStorage.removeItem(this.CACHE_KEY);
localStorage.removeItem(key);
return null;
}
}
_setCache(vodiaState) {
const itemToCache = { data: vodiaState, timestamp: Date.now() };
_setCache(key, data) {
const itemToCache = { data, timestamp: Date.now() };
try {
localStorage.setItem(this.CACHE_KEY, JSON.stringify(itemToCache));
localStorage.setItem(key, JSON.stringify(itemToCache));
} catch (e) {
console.error("Vodia Cache Error: Could not write to localStorage.", e);
console.error(`Vodia Cache Error (${key}): Could not write to localStorage.`, e);
}
}
@@ -140,12 +139,12 @@ class VodiaIdentitySwitcher {
const { callLookupButton, callLookupIconStack, callLookupSpinner } = this.elements;
if (isLoading) {
callLookupButton.setAttribute('disabled', 'true');
callLookupIconStack.classList.add('d-none'); // Hide the icon stack
callLookupSpinner.classList.remove('d-none'); // Show the spinner
callLookupIconStack.classList.add('d-none');
callLookupSpinner.classList.remove('d-none');
} else {
callLookupButton.removeAttribute('disabled');
callLookupIconStack.classList.remove('d-none'); // Show the icon stack
callLookupSpinner.classList.add('d-none'); // Hide the spinner
callLookupIconStack.classList.remove('d-none');
callLookupSpinner.classList.add('d-none');
}
}
@@ -158,7 +157,7 @@ class VodiaIdentitySwitcher {
const data = await response.json();
if (data.status === 'OK' && data.result.number && data.result.number.length >= 5) {
const url = `${this.API_BASE_URL}Address/Index?filter[pfm]=${data.result.number}`;
window.open(url, '_blank'); // Open address book in a new tab
window.open(url, '_blank');
} else {
if (window.notify) window.notify('info', this.TEXT.noActiveCall);
}
@@ -169,7 +168,6 @@ class VodiaIdentitySwitcher {
this._setLookupButtonLoadingState(false);
}
}
// ## END: ADDED METHOD TO HANDLE CALL LOOKUP ##
_setLoadingState(isLoading, message = '') {
const { phoneIcon, currentName, currentNumber } = this.elements;
@@ -184,39 +182,49 @@ class VodiaIdentitySwitcher {
}
}
_updateFromState(vodiaState) {
if (vodiaState?.enabled) {
this.elements.container.style.display = 'flex';
this._updateUI(vodiaState);
this._setLoadingState(false);
} else {
this.elements.container.style.display = 'none';
}
}
async getVodiaIdentity() {
clearTimeout(this.pollingTimer);
const cachedData = this._getCache(this.CACHE_KEY);
if (cachedData && (Date.now() - cachedData.timestamp < this.CACHE_DURATION_MS)) {
this._updateFromState(cachedData.data);
this.pollingTimer = setTimeout(() => this.getVodiaIdentity(), this.POLLING_INTERVAL_MS);
return;
}
const loadingLock = this._getCache(this.LOADING_CACHE_KEY);
if (loadingLock && (Date.now() - loadingLock.timestamp < this.LOADING_TIMEOUT_MS)) {
setTimeout(() => this.getVodiaIdentity(), 500);
return;
}
this._setLoadingState(true, this.TEXT.checking);
this._setCache(this.LOADING_CACHE_KEY, true);
try {
const cachedItem = this._getCache();
let vodiaState;
const response = await fetch(`${this.API_BASE_URL}User/Api/do=getVodiaIdentity`);
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
if (data.status !== "OK") throw new Error(data.message || 'API returned an error');
if (cachedItem && (Date.now() - cachedItem.timestamp < this.CACHE_DURATION_MS)) {
vodiaState = cachedItem.data;
} else {
this._setLoadingState(true, this.TEXT.checking);
const response = await fetch(`${this.API_BASE_URL}User/Api/do=getVodiaIdentity`);
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
if (data.status !== "OK") throw new Error(data.message || 'API returned an error');
vodiaState = data.result;
this._setCache(vodiaState);
}
if (vodiaState?.enabled) {
this.elements.container.style.display = 'flex'; // Use flex to align items
this._updateUI(vodiaState);
this._setLoadingState(false);
} else {
this.elements.container.style.display = 'none';
}
this._setCache(this.CACHE_KEY, data.result);
this._updateFromState(data.result);
} catch (error) {
console.error("Vodia Fetch Error:", error.message);
this.elements.phoneIcon.className = 'phone-icon fas fa-phone text-danger';
this.elements.currentName.textContent = 'Fehler';
} finally {
localStorage.removeItem(this.LOADING_CACHE_KEY);
this.pollingTimer = setTimeout(() => this.getVodiaIdentity(), this.POLLING_INTERVAL_MS);
}
}
@@ -237,7 +245,8 @@ class VodiaIdentitySwitcher {
const data = await response.json();
if (data.status !== "OK") throw new Error(data.message || 'API returned an error.');
localStorage.removeItem(this.CACHE_KEY)
localStorage.removeItem(this.CACHE_KEY);
localStorage.removeItem(this.LOADING_CACHE_KEY);
} catch (error) {
console.error("Vodia Set Error:", error.message);
if (window.notify) window.notify.error("Fehler beim Ändern der ID!");
@@ -318,4 +327,4 @@ class VodiaIdentitySwitcher {
document.addEventListener('DOMContentLoaded', () => {
const topbar = document.querySelector("#topbar");
if (topbar) new VodiaIdentitySwitcher(topbar);
});
});