feat: KoePi bestellmagazin-Filter, KW ohne Klammern erkannt, kommende Prospekte nach Woche unterteilt, Bier-Icon-Prospekte nach oben sortiert
This commit is contained in:
@@ -166,11 +166,15 @@ async function fetchLeafletDetail(leafletId, cache) {
|
||||
}
|
||||
}
|
||||
|
||||
// Extrahiert "(KW29 Do-Sa)"-artige Klammerzusätze aus dem Leaflet-Namen, falls
|
||||
// vorhanden (nicht jede Filiale/jeder Prospekt hat sowas)
|
||||
// Extrahiert eine "(KW29 Do-Sa)"-artige Angabe aus dem Leaflet-Namen. Manche
|
||||
// Ketten (z.B. ALDI) schreiben die KW-Angabe ohne umschließende Klammern
|
||||
// ("... KW32 ...") — die wird dann selbst eingeklammert, damit die Anzeige
|
||||
// überall einheitlich aussieht.
|
||||
function extractWeekInfo(name) {
|
||||
const m = (name || '').match(/\([^)]*KW\s*\d+[^)]*\)/i);
|
||||
return m ? m[0] : '';
|
||||
const bracket = (name || '').match(/\([^)]*KW\s*\d+[^)]*\)/i);
|
||||
if (bracket) return bracket[0];
|
||||
const bare = (name || '').match(/KW\s*\d+(?:\s*[A-Za-zÄÖÜäöüß-]+)?/i);
|
||||
return bare ? `(${bare[0]})` : '';
|
||||
}
|
||||
|
||||
// Löst die feste Liste gewünschter Filialen (LOCAL_STORE_SEED_LEAFLETS) einmalig
|
||||
@@ -561,7 +565,7 @@ async function scrapeProspekte() {
|
||||
|
||||
// "Sondermagazin"-Prospekte ausblenden (keine normalen Wochenangebote)
|
||||
// Unerwünschte Prospekt-Typen ausblenden (Sondermagazine, Reise-Prospekte etc.)
|
||||
const EXCLUDED_TITLE_KEYWORDS = ['sondermagazin', 'reisen'];
|
||||
const EXCLUDED_TITLE_KEYWORDS = ['sondermagazin', 'reisen', 'bestellmagazin'];
|
||||
const withoutSondermagazin = all.filter(b => {
|
||||
const t = (b.title || '').toLowerCase();
|
||||
return !EXCLUDED_TITLE_KEYWORDS.some(kw => t.includes(kw));
|
||||
|
||||
@@ -45,6 +45,39 @@ function fmtDate(str) {
|
||||
catch { return str; }
|
||||
}
|
||||
|
||||
// Prospekte mit Bier-Icon (König Pilsener im Angebot) immer nach oben,
|
||||
// ansonsten Reihenfolge vom Backend (chronologisch) beibehalten
|
||||
function sortBeerFirst(arr) {
|
||||
return [...arr].sort((a, b) => (b.hasKoenigPilsener?1:0) - (a.hasKoenigPilsener?1:0));
|
||||
}
|
||||
|
||||
// ISO-Kalenderwoche aus einem Datum berechnen
|
||||
function getISOWeek(dateStr) {
|
||||
const d = new Date(dateStr);
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
|
||||
const yearStart = new Date(d.getFullYear(), 0, 1);
|
||||
return { week: Math.ceil((((d - yearStart) / 86400000) + 1) / 7), year: d.getFullYear() };
|
||||
}
|
||||
|
||||
// Kommende Prospekte nach Kalenderwoche gruppieren, Gruppen chronologisch sortiert
|
||||
function groupByWeek(arr) {
|
||||
const groups = new Map();
|
||||
for (const b of arr) {
|
||||
if (!b.validFrom) { // kein Datum -> eigene Sammelgruppe ganz unten
|
||||
const key = 'unbekannt';
|
||||
if (!groups.has(key)) groups.set(key, { label: 'Ohne Datum', sortKey: Infinity, items: [] });
|
||||
groups.get(key).items.push(b);
|
||||
continue;
|
||||
}
|
||||
const { week, year } = getISOWeek(b.validFrom);
|
||||
const key = `${year}-${week}`;
|
||||
if (!groups.has(key)) groups.set(key, { label: `KW${week}`, sortKey: year*100+week, items: [] });
|
||||
groups.get(key).items.push(b);
|
||||
}
|
||||
return [...groups.values()].sort((a,b) => a.sortKey - b.sortKey);
|
||||
}
|
||||
|
||||
// ── Angebots-Karte (marktguru) ────────────────────────────────────────────────
|
||||
function OfferCard({ offer }) {
|
||||
const color = publisherColor(offer.retailer);
|
||||
@@ -301,7 +334,7 @@ export default function Koepi({ toast }) {
|
||||
<>
|
||||
<div style={{ ...S.head, marginBottom:12 }}>DEINE MÄRKTE — AKTUELL ({prospekte.current.length})</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(2,1fr)', gap:12, marginBottom:24 }}>
|
||||
{prospekte.current.map(b=><ProspektCard key={b.id} b={b}/>)}
|
||||
{sortBeerFirst(prospekte.current).map(b=><ProspektCard key={b.id} b={b}/>)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -311,9 +344,16 @@ export default function Koepi({ toast }) {
|
||||
color:'rgba(255,255,255,0.35)' }}>
|
||||
KOMMENDE PROSPEKTE ({prospekte.future.length})
|
||||
</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(2,1fr)', gap:12, opacity:0.75 }}>
|
||||
{prospekte.future.map(b=><ProspektCard key={b.id} b={b}/>)}
|
||||
{groupByWeek(prospekte.future).map(group => (
|
||||
<div key={group.label} style={{ marginBottom:20 }}>
|
||||
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:10, letterSpacing:1, marginBottom:8 }}>
|
||||
{group.label}
|
||||
</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(2,1fr)', gap:12, opacity:0.75 }}>
|
||||
{sortBeerFirst(group.items).map(b=><ProspektCard key={b.id} b={b}/>)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{!prospekte.current?.length && !prospekte.future?.length && (
|
||||
|
||||
Reference in New Issue
Block a user