fix: KoePi Mobile-Layout, Bilddateiname korrigiert, Haendler-Logos statt Text, 'reisen'-Filter

This commit is contained in:
2026-07-18 02:45:47 +02:00
parent 263610b0bc
commit dadf2525b7
12 changed files with 50 additions and 17 deletions

View File

@@ -396,12 +396,12 @@ function hasQty(desc, count, vol) {
// Bild pro Angebot exakt nach Mengenangabe wählen (siehe Vorgabe):
// 20x0,5 -> kasten_050 | 20x0,33 -> kasten_steini | 24x0,33 -> kasten_033
// 11x0,5 -> kasten_11er | 6x0,33 -> traeger | 24x0,5 -> palette_050
// 20x0,5 UND 24x0,33 gleichzeitig -> kasten_033_055 | sonst -> koepi_platzhalter
// 20x0,5 UND 24x0,33 gleichzeitig -> kasten_033_05 | sonst -> koepi_platzhalter
function pickOfferImage(description) {
const d = (description || '').toLowerCase();
const q2005 = hasQty(d, 20, '0,5');
const q2433 = hasQty(d, 24, '0,33');
if (q2005 && q2433) return '/koepi/kasten_033_055.png';
if (q2005 && q2433) return '/koepi/kasten_033_05.png';
if (hasQty(d, 20, '0,33')) return '/koepi/kasten_steini.png';
if (q2433) return '/koepi/kasten_033.png';
if (hasQty(d, 11, '0,5')) return '/koepi/kasten_11er.png';
@@ -560,7 +560,12 @@ async function scrapeProspekte() {
}
// "Sondermagazin"-Prospekte ausblenden (keine normalen Wochenangebote)
const withoutSondermagazin = all.filter(b => !(b.title || '').toLowerCase().includes('sondermagazin'));
// Unerwünschte Prospekt-Typen ausblenden (Sondermagazine, Reise-Prospekte etc.)
const EXCLUDED_TITLE_KEYWORDS = ['sondermagazin', 'reisen'];
const withoutSondermagazin = all.filter(b => {
const t = (b.title || '').toLowerCase();
return !EXCLUDED_TITLE_KEYWORDS.some(kw => t.includes(kw));
});
const targeted = withoutSondermagazin.filter(b => b.isTarget);
// Chronologisch in "aktuell laufend" und "kommend" trennen

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -19,6 +19,25 @@ function publisherColor(name) {
return '#888';
}
// Logo-Bild je Händler — Reihenfolge wichtig: "Netto Getränke-Discount" muss
// VOR dem generischen "netto"-Check geprüft werden. Kein Eintrag (z.B.
// Kaufland) -> Aufrufer fällt auf den farbigen Text-Badge zurück.
function retailerLogo(name) {
if (!name) return null;
const n = name.toLowerCase();
if (n.includes('netto') && n.includes('getränke')) return '/koepi/netto_getraenkemarkt.png';
if (n.includes('netto')) return '/koepi/netto.png';
if (n.includes('rewe dortmund')) return null;
if (n.includes('rewe')) return '/koepi/rewe.png';
if (n.includes('edeka') || n.includes('e center')) return '/koepi/edeka.png';
if (n.includes('trinkgut')) return '/koepi/trinkgut.png';
if (n.includes('penny')) return '/koepi/penny.png';
if (n.includes('lidl')) return '/koepi/lidl.png';
if (n.includes('aldi')) return '/koepi/aldi.png';
if (n.includes('hornbach')) return '/koepi/hornbach.png';
return null;
}
function fmtDate(str) {
if (!str) return null;
try { return new Date(str).toLocaleDateString('de-DE', { day:'2-digit', month:'2-digit', year:'numeric' }); }
@@ -28,6 +47,7 @@ function fmtDate(str) {
// ── Angebots-Karte (marktguru) ────────────────────────────────────────────────
function OfferCard({ offer }) {
const color = publisherColor(offer.retailer);
const logo = retailerLogo(offer.retailer);
return (
<div style={{
...S.card, padding:'12px 14px',
@@ -45,11 +65,15 @@ function OfferCard({ offer }) {
{/* Händler + Adresse */}
<div style={{ display:'flex', alignItems:'center', gap:6, flexWrap:'wrap' }}>
{logo ? (
<img src={logo} alt={offer.retailer} style={{ height:20, maxWidth:100, objectFit:'contain', borderRadius:3 }}/>
) : (
<span style={{
background:`${color}22`, border:`1px solid ${color}55`,
borderRadius:4, padding:'2px 7px',
color, fontFamily:'monospace', fontSize:10, fontWeight:700,
}}>{offer.retailer}</span>
)}
{offer.oldPrice && <span style={{ background:'#e2001a', color:'#fff', borderRadius:4, padding:'2px 6px', fontSize:9, fontFamily:'monospace', fontWeight:700 }}>-29%</span>}
</div>
{offer.address && (
@@ -97,6 +121,7 @@ function OfferCard({ offer }) {
// ── Prospekt-Karte (marktguru) ────────────────────────────────────────────────
function ProspektCard({ b }) {
const color = publisherColor(b.publisher);
const logo = retailerLogo(b.publisher);
return (
<a href={b.url} target="_blank" rel="noopener noreferrer" style={{ textDecoration:'none' }}>
<div style={{
@@ -111,10 +136,14 @@ function ProspektCard({ b }) {
)}
<div style={{ padding:'10px 12px' }}>
<div style={{ display:'flex', alignItems:'center', gap:6, marginBottom:4, flexWrap:'wrap' }}>
{logo ? (
<img src={logo} alt={b.publisher} style={{ height:20, maxWidth:110, objectFit:'contain', borderRadius:3 }}/>
) : (
<div style={{ background:`${color}22`, border:`1px solid ${color}44`,
borderRadius:4, padding:'2px 8px', color, fontFamily:'monospace', fontSize:10, fontWeight:700 }}>
{b.publisher}
</div>
)}
{b.hasKoenigPilsener && (
<span title="König Pilsener gerade im Angebot" style={{ fontSize:13 }}>🍺</span>
)}
@@ -195,16 +224,15 @@ export default function Koepi({ toast }) {
};
return (
<div style={{ maxWidth:700, margin:'0 auto' }}>
<div style={{ maxWidth:700, margin:'0 auto', padding:'0 14px' }}>
{/* Header */}
<div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:20 }}>
<h2 style={{ margin:0, fontSize:15, fontFamily:'monospace', color:'rgba(255,255,255,0.55)', letterSpacing:2, fontWeight:400, whiteSpace:'nowrap', flexShrink:0 }}>
<div style={{ marginBottom:20 }}>
<h2 style={{ margin:'0 0 10px 0', fontSize:15, fontFamily:'monospace', color:'rgba(255,255,255,0.55)', letterSpacing:2, fontWeight:400 }}>
🍺 KÖPI König Pilsener
</h2>
<div style={{ flex:1 }}/>
{isAdmin && (
<div style={{ display:'flex', gap:8, overflowX:'auto', scrollbarWidth:'none',
WebkitOverflowScrolling:'touch', paddingBottom:2, minWidth:0 }}>
WebkitOverflowScrolling:'touch', paddingBottom:2 }}>
<button onClick={testDailyCheck} disabled={cronRunning} style={{ ...S.btn('#f59e0b',true), fontSize:10, opacity:cronRunning?0.5:1, flexShrink:0, whiteSpace:'nowrap' }}>
{cronRunning ? '⏳ läuft…' : '🔔 Cron testen'}
</button>