feat: KöPi - marktguru.de als Quelle, echte Angebote mit Flaschengröße
This commit is contained in:
@@ -7,160 +7,103 @@ function getMyRole() {
|
||||
try { return JSON.parse(atob(localStorage.getItem('sk_token').split('.')[1])).role; } catch { return null; }
|
||||
}
|
||||
|
||||
function publisherColor(name) {
|
||||
if (!name) return '#555';
|
||||
const n = name.toLowerCase();
|
||||
if (n.includes('rewe')) return '#e2001a';
|
||||
if (n.includes('edeka') || n.includes('e center')) return '#e8a800';
|
||||
if (n.includes('netto')) return '#0057a8';
|
||||
if (n.includes('trinkgut')) return '#e87722';
|
||||
if (n.includes('penny')) return '#e2001a';
|
||||
if (n.includes('kaufland')) return '#e2001a';
|
||||
return '#888';
|
||||
}
|
||||
|
||||
function fmtDate(str) {
|
||||
if (!str) return null;
|
||||
try { return new Date(str).toLocaleDateString('de-DE', { day:'2-digit', month:'2-digit', year:'numeric' }); }
|
||||
catch { return str; }
|
||||
}
|
||||
|
||||
function publisherColor(name) {
|
||||
if (!name) return '#555';
|
||||
const n = name.toLowerCase();
|
||||
if (n.includes('rewe')) return '#e2001a';
|
||||
if (n.includes('edeka')) return '#e8a800';
|
||||
if (n.includes('e center')) return '#e8a800';
|
||||
if (n.includes('netto')) return '#0057a8';
|
||||
if (n.includes('trinkgut')) return '#e87722';
|
||||
if (n.includes('penny')) return '#e2001a';
|
||||
if (n.includes('aldi')) return '#00538f';
|
||||
if (n.includes('lidl')) return '#f5c900';
|
||||
if (n.includes('hit')) return '#e2001a';
|
||||
if (n.includes('alldrink')) return '#2ecc71';
|
||||
if (n.includes('getränke')) return '#3498db';
|
||||
return '#666';
|
||||
}
|
||||
|
||||
// ── Prospekt-Angebot Karte ────────────────────────────────────────────────────
|
||||
function BrochureOfferCard({ offer }) {
|
||||
const color = publisherColor(offer.store);
|
||||
const Wrapper = offer.url
|
||||
? ({children}) => <a href={offer.url} target="_blank" rel="noopener noreferrer" style={{textDecoration:'none'}}>{children}</a>
|
||||
: ({children}) => <div>{children}</div>;
|
||||
return (
|
||||
<Wrapper>
|
||||
<div style={{
|
||||
...S.card, padding:0, overflow:'hidden', cursor: offer.url ? 'pointer' : 'default',
|
||||
border:'1px solid rgba(255,255,255,0.08)',
|
||||
display:'flex', flexDirection:'column',
|
||||
}}>
|
||||
{/* Prospektseite als Bild */}
|
||||
{offer.productImage && (
|
||||
<div style={{ position:'relative', height:160, overflow:'hidden', flexShrink:0 }}>
|
||||
<img src={`/api/tools/koepi/img?url=${encodeURIComponent(offer.productImage)}`}
|
||||
alt={`König Pilsener bei ${offer.store}`}
|
||||
style={{ width:'100%', height:'100%', objectFit:'cover', display:'block' }}
|
||||
onError={e => { e.target.style.display='none'; }}
|
||||
/>
|
||||
{offer.isNew && (
|
||||
<span style={{ position:'absolute', top:8, left:8,
|
||||
background:'#4ecdc4', color:'#000', borderRadius:4,
|
||||
padding:'2px 7px', fontSize:9, fontFamily:'monospace', fontWeight:700 }}>
|
||||
NEU
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding:'10px 12px', flex:1 }}>
|
||||
{/* Händler + Logo */}
|
||||
<div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:8 }}>
|
||||
{offer.publisherLogo && (
|
||||
<img src={offer.publisherLogo} alt={offer.store}
|
||||
style={{ height:20, width:'auto', objectFit:'contain', flexShrink:0 }}
|
||||
onError={e => { e.target.style.display='none'; }}
|
||||
/>
|
||||
)}
|
||||
<span style={{
|
||||
background:`${color}22`, border:`1px solid ${color}44`,
|
||||
borderRadius:4, padding:'2px 8px',
|
||||
color, fontFamily:'monospace', fontSize:10, fontWeight:700,
|
||||
}}>
|
||||
{offer.store}
|
||||
</span>
|
||||
</div>
|
||||
{/* Prospekttitel + Seite */}
|
||||
{offer.title && (
|
||||
<div style={{ color:'rgba(255,255,255,0.6)', fontFamily:'monospace', fontSize:11, marginBottom:4 }}>
|
||||
📄 „{offer.title}"
|
||||
{offer.page && <span style={{ color:'rgba(255,255,255,0.35)', marginLeft:4 }}>Seite {offer.page}</span>}
|
||||
</div>
|
||||
)}
|
||||
{/* Gültigkeit */}
|
||||
{offer.dateRange && (
|
||||
<div style={{ color:'rgba(255,255,255,0.5)', fontFamily:'monospace', fontSize:10, marginTop:4 }}>
|
||||
📅 {offer.dateRange}
|
||||
</div>
|
||||
)}
|
||||
{offer.validity && (
|
||||
<div style={{ color: offer.validity.includes('Noch') ? '#f59e0b' : '#4ecdc4',
|
||||
fontFamily:'monospace', fontSize:10, marginTop:2 }}>
|
||||
⏰ {offer.validity}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Grid-Angebot Karte (mit Preis) ────────────────────────────────────────────
|
||||
function GridOfferCard({ offer }) {
|
||||
const color = publisherColor(offer.store);
|
||||
// ── Angebots-Karte (marktguru) ────────────────────────────────────────────────
|
||||
function OfferCard({ offer }) {
|
||||
const color = publisherColor(offer.retailer);
|
||||
return (
|
||||
<div style={{
|
||||
...S.card, padding:0, overflow:'hidden',
|
||||
border:'1px solid rgba(255,255,255,0.08)',
|
||||
border:'1px solid rgba(255,255,255,0.1)',
|
||||
display:'flex', flexDirection:'column',
|
||||
background:'rgba(255,255,255,0.03)',
|
||||
}}>
|
||||
{offer.image && (
|
||||
<div style={{ height:130, overflow:'hidden', flexShrink:0, background:'#fff', display:'flex', alignItems:'center', justifyContent:'center' }}>
|
||||
<img src={`/api/tools/koepi/img?url=${encodeURIComponent(offer.image)}`}
|
||||
alt={offer.name}
|
||||
style={{ width:'auto', height:'100%', maxWidth:'100%', objectFit:'contain', display:'block' }}
|
||||
onError={e => { e.target.parentElement.style.display='none'; }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding:'10px 12px', flex:1 }}>
|
||||
{offer.brand && (
|
||||
<div style={{ color:'rgba(255,255,255,0.4)', fontFamily:'monospace', fontSize:10, marginBottom:2 }}>
|
||||
{offer.brand}
|
||||
</div>
|
||||
)}
|
||||
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:12, fontWeight:600, marginBottom:6, lineHeight:1.3 }}>
|
||||
{/* Produktbild */}
|
||||
<div style={{ height:150, background:'#fff', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0, overflow:'hidden' }}>
|
||||
{offer.image
|
||||
? <img src={`/api/tools/koepi/img?url=${encodeURIComponent(offer.image)}`}
|
||||
alt={offer.name} style={{ maxHeight:'100%', maxWidth:'100%', objectFit:'contain' }}
|
||||
onError={e => { e.target.parentElement.innerHTML = '<div style="color:#555;font-size:40px">🍺</div>'; }}
|
||||
/>
|
||||
: <div style={{ fontSize:40 }}>🍺</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div style={{ padding:'12px 14px', flex:1, display:'flex', flexDirection:'column', gap:6 }}>
|
||||
{/* Händler Badge */}
|
||||
<div style={{
|
||||
display:'inline-block', alignSelf:'flex-start',
|
||||
background:`${color}22`, border:`1px solid ${color}55`,
|
||||
borderRadius:4, padding:'2px 8px',
|
||||
color, fontFamily:'monospace', fontSize:10, fontWeight:700,
|
||||
}}>{offer.retailer}</div>
|
||||
|
||||
{/* Name */}
|
||||
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:600, lineHeight:1.3 }}>
|
||||
{offer.name}
|
||||
{offer.brand && offer.brand !== offer.name && (
|
||||
<span style={{ color:'rgba(255,255,255,0.4)', fontSize:10, marginLeft:6 }}>{offer.brand}</span>
|
||||
)}
|
||||
</div>
|
||||
{offer.price && (
|
||||
<div style={{ color:GOLD, fontFamily:'Space Mono,monospace', fontSize:18, fontWeight:700, marginBottom:2 }}>
|
||||
|
||||
{/* Beschreibung/Flaschengröße */}
|
||||
{offer.description && (
|
||||
<div style={{ color:'rgba(255,255,255,0.5)', fontFamily:'monospace', fontSize:10, lineHeight:1.4 }}>
|
||||
{offer.description}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Preis */}
|
||||
<div style={{ display:'flex', alignItems:'baseline', gap:8, marginTop:4 }}>
|
||||
<span style={{ color:GOLD, fontFamily:'Space Mono,monospace', fontSize:20, fontWeight:700 }}>
|
||||
{offer.price}
|
||||
</div>
|
||||
)}
|
||||
{(offer.size || offer.baseUnit) && (
|
||||
<div style={{ color:'rgba(255,255,255,0.35)', fontFamily:'monospace', fontSize:10, marginTop:2 }}>
|
||||
{offer.size && <span>{offer.size} · </span>}
|
||||
{offer.baseUnit}
|
||||
</div>
|
||||
)}
|
||||
{offer.store && (
|
||||
<div style={{
|
||||
marginTop:8, display:'inline-block',
|
||||
background:`${color}22`, border:`1px solid ${color}44`,
|
||||
borderRadius:4, padding:'2px 7px',
|
||||
color, fontFamily:'monospace', fontSize:10, fontWeight:700,
|
||||
}}>
|
||||
{offer.store}
|
||||
</div>
|
||||
)}
|
||||
</span>
|
||||
{offer.oldPrice && (
|
||||
<span style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:12, textDecoration:'line-through' }}>
|
||||
{offer.oldPrice}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Gültigkeit */}
|
||||
<div style={{ marginTop:'auto', paddingTop:6, borderTop:'1px solid rgba(255,255,255,0.06)' }}>
|
||||
{offer.validity && (
|
||||
<div style={{ color: offer.validity.includes('Neu') ? '#4ecdc4' : '#f59e0b', fontFamily:'monospace', fontSize:10 }}>
|
||||
⏰ {offer.validity}
|
||||
</div>
|
||||
)}
|
||||
{offer.dateRange && (
|
||||
<div style={{ color:'rgba(255,255,255,0.35)', fontFamily:'monospace', fontSize:10, marginTop:2 }}>
|
||||
📅 {offer.dateRange}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Prospekt-Karte (shelf) ────────────────────────────────────────────────────
|
||||
// ── Prospekt-Karte (kaufda) ───────────────────────────────────────────────────
|
||||
function ProspektCard({ b }) {
|
||||
const color = publisherColor(b.publisher);
|
||||
const isNew = b.badges?.includes('new');
|
||||
const expiring = b.badges?.includes('expiring_soon');
|
||||
const fresh = b.badges?.includes('new');
|
||||
return (
|
||||
<a href={b.url} target="_blank" rel="noopener noreferrer" style={{ textDecoration:'none' }}>
|
||||
<div style={{
|
||||
@@ -169,30 +112,28 @@ function ProspektCard({ b }) {
|
||||
}}>
|
||||
<div style={{ position:'relative' }}>
|
||||
{b.image && (
|
||||
<img src={b.image} alt={b.title}
|
||||
style={{ width:'100%', height:110, objectFit:'cover', display:'block' }}
|
||||
<img src={`/api/tools/koepi/img?url=${encodeURIComponent(b.image)}`}
|
||||
alt={b.title} style={{ width:'100%', height:110, objectFit:'cover', display:'block' }}
|
||||
onError={e => { e.target.style.display='none'; }}
|
||||
/>
|
||||
)}
|
||||
<div style={{ position:'absolute', top:6, left:6, display:'flex', gap:4 }}>
|
||||
{fresh && <span style={{ background:'#4ecdc4', color:'#000', borderRadius:4, padding:'2px 6px', fontSize:9, fontFamily:'monospace', fontWeight:700 }}>NEU</span>}
|
||||
{expiring && <span style={{ background:'#ef4444', color:'#fff', borderRadius:4, padding:'2px 6px', fontSize:9, fontFamily:'monospace', fontWeight:700 }}>ENDET BALD</span>}
|
||||
{isNew && <span style={{ background:'#4ecdc4', color:'#000', borderRadius:4, padding:'2px 6px', fontSize:9, fontFamily:'monospace', fontWeight:700 }}>NEU</span>}
|
||||
{expiring && <span style={{ background:'#ef4444', color:'#fff', borderRadius:4, padding:'2px 6px', fontSize:9, fontFamily:'monospace', fontWeight:700 }}>ENDET BALD</span>}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding:'10px 12px' }}>
|
||||
<div style={{ display:'inline-block', background:`${color}22`, border:`1px solid ${color}44`,
|
||||
borderRadius:4, padding:'2px 8px', marginBottom:6,
|
||||
color, fontFamily:'monospace', fontSize:10, fontWeight:700 }}>
|
||||
{b.storeLabel || b.publisher}
|
||||
borderRadius:4, padding:'2px 8px', marginBottom:6, color, fontFamily:'monospace', fontSize:10, fontWeight:700 }}>
|
||||
{b.publisher}
|
||||
</div>
|
||||
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:11, marginBottom:3, lineHeight:1.4 }}>{b.title}</div>
|
||||
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:11, marginBottom:3 }}>{b.title}</div>
|
||||
<div style={{ color:'rgba(255,255,255,0.4)', fontFamily:'monospace', fontSize:10, marginBottom:2 }}>
|
||||
📍 {b.street || b.store}{b.city ? ` · ${b.city}` : ''}
|
||||
📍 {b.street || b.store}
|
||||
</div>
|
||||
{b.street && <div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9 }}>{b.street}</div>}
|
||||
{(b.validFrom || b.validTo) && (
|
||||
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, marginTop:4 }}>
|
||||
{b.validFrom && `Ab ${fmtDate(b.validFrom)}`}{b.validFrom && b.validTo && ' · '}{b.validTo && `Bis ${fmtDate(b.validTo)}`}
|
||||
{b.validFrom && `Ab ${fmtDate(b.validFrom)}`}{b.validFrom&&b.validTo&&' · '}{b.validTo&&`Bis ${fmtDate(b.validTo)}`}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -210,19 +151,19 @@ export default function Koepi({ toast }) {
|
||||
const [showAll, setShowAll] = useState(false);
|
||||
const isAdmin = getMyRole() === 'admin';
|
||||
|
||||
const loadOffers = async () => {
|
||||
if (offers) return;
|
||||
const loadOffers = async (force=false) => {
|
||||
if (offers && !force) return;
|
||||
setLoading(true);
|
||||
try { setOffers(await api('/tools/koepi/offers')); }
|
||||
catch(e) { toast?.(e.message || 'Fehler', 'error'); }
|
||||
catch(e) { toast?.(e.message||'Fehler','error'); }
|
||||
finally { setLoading(false); }
|
||||
};
|
||||
|
||||
const loadProspekte = async () => {
|
||||
if (prospekte) return;
|
||||
const loadProspekte = async (force=false) => {
|
||||
if (prospekte && !force) return;
|
||||
setLoading(true);
|
||||
try { setProspekte(await api('/tools/koepi/prospekte')); }
|
||||
catch(e) { toast?.(e.message || 'Fehler', 'error'); }
|
||||
catch(e) { toast?.(e.message||'Fehler','error'); }
|
||||
finally { setLoading(false); }
|
||||
};
|
||||
|
||||
@@ -236,101 +177,86 @@ export default function Koepi({ toast }) {
|
||||
await api('/tools/koepi/clear-cache', { body:{} });
|
||||
setOffers(null); setProspekte(null);
|
||||
toast('Cache geleert');
|
||||
if (tab === 'angebote') { setLoading(true); setOffers(await api('/tools/koepi/offers')); setLoading(false); }
|
||||
else { setLoading(true); setProspekte(await api('/tools/koepi/prospekte')); setLoading(false); }
|
||||
} catch(e) { toast?.(e.message, 'error'); }
|
||||
setTimeout(() => { if (tab==='angebote') loadOffers(true); else loadProspekte(true); }, 100);
|
||||
} catch(e) { toast?.(e.message,'error'); }
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth:700, margin:'0 auto' }}>
|
||||
<div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:20, flexWrap:'wrap' }}>
|
||||
{/* 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 }}>
|
||||
🍺 KÖPI — König Pilsener Angebote
|
||||
🍺 KÖPI — König Pilsener
|
||||
</h2>
|
||||
<div style={{ flex:1 }}/>
|
||||
{isAdmin && (
|
||||
<button onClick={clearCache} style={{ ...S.btn('#666666', true), fontSize:10 }}>🗑 Cache</button>
|
||||
<button onClick={clearCache} style={{ ...S.btn('#666666',true), fontSize:10 }}>🗑 Cache leeren</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:10, marginBottom:14 }}>
|
||||
Raum Duisburg/Essen/Düsseldorf · Quelle: kaufDA.de · Cache 1h
|
||||
Raum Duisburg 47259 · EDEKA · REWE · Netto · Kaufland · Penny · Trinkgut · Cache 1h
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div style={{ display:'flex', gap:8, marginBottom:20 }}>
|
||||
{[['angebote','🍺 Angebote'],['prospekte','📋 Alle Prospekte']].map(([t, label]) => (
|
||||
<button key={t} onClick={() => setTab(t)} style={{
|
||||
...S.btn(tab===t ? GOLD : '#444444', true), fontSize:12, padding:'6px 14px',
|
||||
}}>{label}</button>
|
||||
{[['angebote','🍺 Angebote'],['prospekte','📋 Prospekte']].map(([t,l]) => (
|
||||
<button key={t} onClick={()=>setTab(t)} style={{ ...S.btn(tab===t?GOLD:'#444444',true), fontSize:12, padding:'6px 16px' }}>{l}</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Laden */}
|
||||
{loading && (
|
||||
<div style={{ color:'rgba(255,255,255,0.4)', fontFamily:'monospace', fontSize:13, textAlign:'center', padding:'40px 0' }}>
|
||||
⏳ Lade Angebote… (kann bis zu 15 Sekunden dauern)
|
||||
⏳ Lade… (kann bis zu 20 Sekunden dauern)
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Angebote Tab */}
|
||||
{!loading && tab === 'angebote' && offers && (
|
||||
{/* Angebote */}
|
||||
{!loading && tab==='angebote' && offers && (
|
||||
<div>
|
||||
{/* Grid-Angebote mit Preisen */}
|
||||
{offers.gridOffers?.length > 0 && (
|
||||
{offers.offers?.length > 0 ? (
|
||||
<>
|
||||
<div style={{ ...S.head, marginBottom:10 }}>AKTUELLE ANGEBOTE MIT PREIS ({offers.gridOffers.length})</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(160px,1fr))', gap:12, marginBottom:24 }}>
|
||||
{offers.gridOffers.map((o, i) => <GridOfferCard key={i} offer={o} />)}
|
||||
<div style={{ ...S.head, marginBottom:12 }}>
|
||||
{offers.offers.length} AKTUELLE ANGEBOTE · Quelle: marktguru.de
|
||||
</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(180px,1fr))', gap:14 }}>
|
||||
{offers.offers.map((o,i) => <OfferCard key={i} offer={o}/>)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* BrochureBox: Prospektseiten mit KöPi */}
|
||||
{offers.brochureOffers?.length > 0 && (
|
||||
<>
|
||||
<div style={{ ...S.head, marginBottom:10 }}>
|
||||
KÖNIG PILSENER IN DIESEN PROSPEKTEN ({offers.brochureOffers.length})
|
||||
</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(180px,1fr))', gap:12 }}>
|
||||
{offers.brochureOffers.map((o, i) => <BrochureOfferCard key={i} offer={o} />)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{!offers.gridOffers?.length && !offers.brochureOffers?.length && (
|
||||
) : (
|
||||
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:13, textAlign:'center', padding:'40px 0' }}>
|
||||
Aktuell keine König Pilsener Angebote gefunden.
|
||||
Aktuell keine König Pilsener Angebote bei deinen Märkten gefunden.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop:20, textAlign:'center' }}>
|
||||
<a href="https://www.kaufda.de/Angebote/Koenig-Pilsener" target="_blank" rel="noopener noreferrer"
|
||||
style={{ color:GOLD, fontFamily:'monospace', fontSize:11 }}>
|
||||
→ Alle Angebote auf kaufDA.de
|
||||
<a href="https://www.marktguru.de/search/k%C3%B6nig%20pilsener?zipCode=47259" target="_blank" rel="noopener noreferrer"
|
||||
style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:10 }}>
|
||||
→ Alle Angebote auf marktguru.de
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Prospekte Tab */}
|
||||
{!loading && tab === 'prospekte' && prospekte && (
|
||||
{/* Prospekte */}
|
||||
{!loading && tab==='prospekte' && prospekte && (
|
||||
<div>
|
||||
{prospekte.targeted?.length > 0 && (
|
||||
<>
|
||||
<div style={{ ...S.head, marginBottom:10 }}>REWE · EDEKA · NETTO · TRINKGUT & mehr ({prospekte.targeted.length})</div>
|
||||
<div style={{ ...S.head, marginBottom:12 }}>DEINE MÄRKTE ({prospekte.targeted.length})</div>
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(180px,1fr))', gap:12, marginBottom:16 }}>
|
||||
{prospekte.targeted.map(b => <ProspektCard key={b.id} b={b} />)}
|
||||
{prospekte.targeted.map(b=><ProspektCard key={b.id} b={b}/>)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{prospekte.others?.length > 0 && (
|
||||
<>
|
||||
<button onClick={() => setShowAll(v => !v)} style={{ ...S.btn('#444444',true), marginBottom:10, fontSize:11 }}>
|
||||
<button onClick={()=>setShowAll(v=>!v)} style={{ ...S.btn('#444444',true), marginBottom:10, fontSize:11 }}>
|
||||
{showAll ? '▾ Weniger' : `▸ Weitere Prospekte (${prospekte.others.length})`}
|
||||
</button>
|
||||
{showAll && (
|
||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(180px,1fr))', gap:12 }}>
|
||||
{prospekte.others.map(b => <ProspektCard key={b.id} b={b} />)}
|
||||
{prospekte.others.map(b=><ProspektCard key={b.id} b={b}/>)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user