diff --git a/docker-compose.yml b/docker-compose.yml index a4dec37..c554f24 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: - .env # Lädt Umgebungsvariablen aus der .env-Datei restart: unless-stopped volumes: - - ./config:/app/config # Für persistente Konfiguration + - /opt/docker/foodsharing/config:/app/config # Für persistente Konfiguration networks: - nginx-proxy-manager_default labels: diff --git a/server.js b/server.js index 38afb89..dec8d6a 100644 --- a/server.js +++ b/server.js @@ -59,13 +59,14 @@ function mergeStoresIntoConfig(config = [], stores = []) { } const id = String(store.id); if (!map.has(id)) { + const hideByDefault = store.hasPickupSlots === false; map.set(id, { id, label: store.name || `Store ${id}`, active: false, checkProfileId: true, onlyNotify: false, - hidden: false + hidden: hideByDefault }); changed = true; return; diff --git a/services/foodsharingClient.js b/services/foodsharingClient.js index 4db2a44..bf2615a 100644 --- a/services/foodsharingClient.js +++ b/services/foodsharingClient.js @@ -124,11 +124,8 @@ async function fetchStores(cookieHeader, profileId) { headers: buildHeaders(cookieHeader), params: { activeStores: 1 } }); - const stores = response.data || []; - if (!Array.isArray(stores)) { - return []; - } - return stores.map((store) => ({ + const stores = Array.isArray(response.data) ? response.data : []; + const normalized = stores.map((store) => ({ id: String(store.id), name: store.name || `Store ${store.id}`, pickupStatus: store.pickupStatus, @@ -138,12 +135,45 @@ async function fetchStores(cookieHeader, profileId) { street: store.street || '', zip: store.zip || '' })); + + return annotateStoresWithPickupSlots(normalized, cookieHeader); } catch (error) { console.warn('Stores konnten nicht geladen werden:', error.message); return []; } } +async function annotateStoresWithPickupSlots(stores, cookieHeader, concurrency = 5) { + if (!Array.isArray(stores) || stores.length === 0) { + return []; + } + + const cappedConcurrency = Math.max(1, Math.min(concurrency, stores.length)); + const results = new Array(stores.length); + let pointer = 0; + + async function worker() { + while (true) { + const currentIndex = pointer++; + if (currentIndex >= stores.length) { + return; + } + const store = stores[currentIndex]; + let hasPickupSlots = null; + try { + const pickups = await fetchPickups(store.id, cookieHeader); + hasPickupSlots = Array.isArray(pickups) && pickups.length > 0; + } catch (error) { + console.warn(`Pickups für Store ${store.id} konnten nicht geprüft werden:`, error.message); + } + results[currentIndex] = { ...store, hasPickupSlots }; + } + } + + await Promise.all(Array.from({ length: cappedConcurrency }, () => worker())); + return results; +} + async function fetchPickups(storeId, cookieHeader) { const response = await client.get(`/api/stores/${storeId}/pickups`, { headers: buildHeaders(cookieHeader) diff --git a/src/App.js b/src/App.js index 09e3fce..0a42ab4 100644 --- a/src/App.js +++ b/src/App.js @@ -713,12 +713,19 @@ function App() { const entry = configMap.get(storeId); const isVisible = entry && !entry.hidden; const needsRestore = entry && entry.hidden; + const blockedByNoPickups = store.hasPickupSlots === false; let statusLabel = 'Hinzufügen'; + let statusClass = 'text-blue-600'; if (isVisible) { statusLabel = 'Bereits in Konfiguration'; + statusClass = 'text-gray-500'; } else if (needsRestore) { statusLabel = 'Ausgeblendet – erneut hinzufügen'; } + if (blockedByNoPickups) { + statusLabel = 'Keine Pickups – automatisch verborgen'; + statusClass = 'text-amber-600'; + } return ( ); })}