added cache system
This commit is contained in:
@@ -48,7 +48,7 @@ function populateTimeSelects() {
|
||||
}
|
||||
|
||||
async function loadOffices() {
|
||||
const response = await api.get('/api/offices');
|
||||
const response = await api.getCached('/api/offices', 60);
|
||||
if (response && response.ok) {
|
||||
offices = await response.json();
|
||||
renderOffices();
|
||||
@@ -115,6 +115,7 @@ async function deleteOffice(officeId) {
|
||||
const response = await api.delete(`/api/offices/${officeId}`);
|
||||
if (response && response.ok) {
|
||||
utils.showMessage('Ufficio eliminato', 'success');
|
||||
api.invalidateCache('/api/offices'); // Clear cache
|
||||
await loadOffices();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
@@ -177,6 +178,7 @@ async function handleOfficeSubmit(e) {
|
||||
if (response && response.ok) {
|
||||
closeModal();
|
||||
utils.showMessage(officeId ? 'Ufficio aggiornato' : 'Ufficio creato', 'success');
|
||||
api.invalidateCache('/api/offices'); // Clear cache
|
||||
await loadOffices();
|
||||
} else {
|
||||
let errorMessage = 'Errore operazione';
|
||||
|
||||
@@ -23,14 +23,16 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
});
|
||||
|
||||
async function loadOffices() {
|
||||
const response = await api.get('/api/offices');
|
||||
// Cache offices for dropdown (60 min)
|
||||
const response = await api.getCached('/api/offices', 60);
|
||||
if (response && response.ok) {
|
||||
offices = await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
async function loadUsers() {
|
||||
const response = await api.get('/api/users');
|
||||
// Cache users list (15 min)
|
||||
const response = await api.getCached('/api/users', 15);
|
||||
if (response && response.ok) {
|
||||
users = await response.json();
|
||||
renderUsers();
|
||||
@@ -166,6 +168,8 @@ async function deleteUser(userId) {
|
||||
const response = await api.delete(`/api/users/${userId}`);
|
||||
if (response && response.ok) {
|
||||
utils.showMessage('Utente eliminato', 'success');
|
||||
api.invalidateCache('/api/users');
|
||||
api.invalidateCache('/api/offices'); // Invalidate office counts
|
||||
await loadUsers();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
@@ -210,6 +214,8 @@ function setupEventListeners() {
|
||||
if (response && response.ok) {
|
||||
document.getElementById('userModal').style.display = 'none';
|
||||
utils.showMessage('Utente aggiornato', 'success');
|
||||
api.invalidateCache('/api/users');
|
||||
api.invalidateCache('/api/offices'); // Invalidate office counts
|
||||
await loadUsers();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
|
||||
@@ -23,6 +23,80 @@ const api = {
|
||||
*/
|
||||
clearToken() {
|
||||
localStorage.removeItem('access_token');
|
||||
this.clearCache();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get data with caching - Returns Response obj or Mock Response
|
||||
* @param {string} url - API endpoint
|
||||
* @param {number} ttlMinutes - Time to live in minutes (default 60)
|
||||
*/
|
||||
async getCached(url, ttlMinutes = 60) {
|
||||
const cacheKey = 'cache_' + url;
|
||||
const cachedItem = localStorage.getItem(cacheKey);
|
||||
|
||||
if (cachedItem) {
|
||||
try {
|
||||
const { data, timestamp } = JSON.parse(cachedItem);
|
||||
const age = (Date.now() - timestamp) / 1000 / 60;
|
||||
|
||||
if (age < ttlMinutes) {
|
||||
console.log(`[Cache] Hit for ${url}`);
|
||||
// Return a mock response-like object
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => data
|
||||
};
|
||||
} else {
|
||||
console.log(`[Cache] Expired for ${url}`);
|
||||
localStorage.removeItem(cacheKey);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Cache] Error parsing cache', e);
|
||||
localStorage.removeItem(cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[Cache] Miss for ${url}`);
|
||||
const response = await this.get(url);
|
||||
|
||||
if (response && response.ok) {
|
||||
try {
|
||||
// Clone response to read body and still return it to caller
|
||||
const clone = response.clone();
|
||||
const data = await clone.json();
|
||||
|
||||
localStorage.setItem(cacheKey, JSON.stringify({
|
||||
data: data,
|
||||
timestamp: Date.now()
|
||||
}));
|
||||
} catch (e) {
|
||||
console.warn('[Cache] failed to save to localStorage', e);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Invalidate specific cache key
|
||||
*/
|
||||
invalidateCache(url) {
|
||||
localStorage.removeItem('cache_' + url);
|
||||
console.log(`[Cache] Invalidated ${url}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all API cache
|
||||
*/
|
||||
clearCache() {
|
||||
Object.keys(localStorage).forEach(key => {
|
||||
if (key.startsWith('cache_')) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
console.log('[Cache] Cleared all cache');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -37,14 +111,36 @@ const api = {
|
||||
* Call this on page load to verify auth status
|
||||
*/
|
||||
async checkAuth() {
|
||||
// Try to get current user - works with Authelia headers or JWT
|
||||
const response = await fetch('/api/auth/me', {
|
||||
const url = '/api/auth/me';
|
||||
// 1. Try Cache (Short TTL: 5 min)
|
||||
const cacheKey = 'cache_' + url;
|
||||
const cachedItem = localStorage.getItem(cacheKey);
|
||||
if (cachedItem) {
|
||||
try {
|
||||
const { data, timestamp } = JSON.parse(cachedItem);
|
||||
if ((Date.now() - timestamp) / 1000 / 60 < 5) {
|
||||
this._autheliaAuth = true;
|
||||
return data;
|
||||
}
|
||||
} catch (e) { localStorage.removeItem(cacheKey); }
|
||||
}
|
||||
|
||||
// 2. Fetch from Network
|
||||
const response = await fetch(url, {
|
||||
headers: this.getToken() ? { 'Authorization': `Bearer ${this.getToken()}` } : {}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
this._autheliaAuth = true;
|
||||
return await response.json();
|
||||
const data = await response.json();
|
||||
|
||||
// Save to Cache
|
||||
localStorage.setItem(cacheKey, JSON.stringify({
|
||||
data: data,
|
||||
timestamp: Date.now()
|
||||
}));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
this._autheliaAuth = false;
|
||||
|
||||
@@ -82,15 +82,14 @@ async function loadOffices() {
|
||||
if (currentUser.role === 'employee') return;
|
||||
}
|
||||
|
||||
const response = await api.get('/api/offices');
|
||||
// Cache offices list
|
||||
const response = await api.getCached('/api/offices', 60);
|
||||
if (response && response.ok) {
|
||||
offices = await response.json();
|
||||
|
||||
let filteredOffices = offices;
|
||||
if (currentUser.role === 'manager') {
|
||||
// Manager only sees their own office in the filter?
|
||||
// Actually managers might want to filter if they (hypothetically) managed multiple,
|
||||
// but currently User has 1 office.
|
||||
if (currentUser.office_id) {
|
||||
filteredOffices = offices.filter(o => o.id === currentUser.office_id);
|
||||
} else {
|
||||
@@ -254,8 +253,8 @@ async function loadClosingData() {
|
||||
const promises = officeIdsToLoad.map(async (oid) => {
|
||||
try {
|
||||
const [weeklyRes, specificRes] = await Promise.all([
|
||||
api.get(`/api/offices/${oid}/weekly-closing-days`),
|
||||
api.get(`/api/offices/${oid}/closing-days`)
|
||||
api.getCached(`/api/offices/${oid}/weekly-closing-days`, 60),
|
||||
api.getCached(`/api/offices/${oid}/closing-days`, 60)
|
||||
]);
|
||||
|
||||
officeClosingRules[oid] = { weekly: [], specific: [] };
|
||||
|
||||
Reference in New Issue
Block a user