Files
padelnomics/scratch/supplier-dashboard.jsx
Deeman bc7fbcd595 chore: commit pending changes — logo, base template, scratch designs, changelog
- favicon.svg: pending logo tweaks
- base.html: pending template changes
- CHANGELOG.md: add waitlist mode and logo redesign entries missed in prior commits
- scratch/: add design prototype HTML/JSX files, remove old markdown notes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 23:45:42 +01:00

856 lines
31 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from "react";
const COLORS = {
bg: "#0A0F1C",
surface: "#111827",
surfaceLight: "#1A2236",
surfaceHover: "#1F2A40",
border: "#2A3550",
borderLight: "#354263",
accent: "#22D3A7",
accentDim: "rgba(34,211,167,0.12)",
accentGlow: "rgba(34,211,167,0.25)",
warning: "#F59E0B",
warningDim: "rgba(245,158,11,0.12)",
hot: "#EF4444",
hotDim: "rgba(239,68,68,0.12)",
blue: "#3B82F6",
blueDim: "rgba(59,130,246,0.12)",
purple: "#A78BFA",
purpleDim: "rgba(167,139,250,0.12)",
text: "#F1F5F9",
textMuted: "#94A3B8",
textDim: "#64748B",
};
const tabs = [
{ id: "dashboard", label: "Dashboard", icon: "◐" },
{ id: "leads", label: "Lead Feed", icon: "◉" },
{ id: "listing", label: "My Listing", icon: "◧" },
{ id: "boost", label: "Boost & Upsells", icon: "△" },
];
const mockLeads = [
{
id: 1,
type: "Indoor Padel Center",
courts: 6,
region: "Lower Saxony, Germany",
budget: "€400K €600K",
timeline: "Q3 2026",
specs: ["Indoor steel hall", "LED lighting", "Panoramic glass walls", "Pro-grade turf"],
posted: "2 hours ago",
heat: "hot",
credits: 25,
unlocked: false,
bidders: 1,
},
{
id: 2,
type: "Outdoor Padel Courts",
courts: 4,
region: "Bavaria, Germany",
budget: "€180K €280K",
timeline: "Q2 2026",
specs: ["Outdoor installation", "Drainage system", "Windbreak fencing", "Night lighting"],
posted: "5 hours ago",
heat: "warm",
credits: 15,
unlocked: false,
bidders: 3,
},
{
id: 3,
type: "Indoor Padel & Fitness Complex",
courts: 10,
region: "North Rhine-Westphalia, Germany",
budget: "€800K €1.2M",
timeline: "Q1 2027",
specs: ["Mixed-use facility", "Padel + gym + café", "Climate control", "Spectator area"],
posted: "1 day ago",
heat: "hot",
credits: 40,
unlocked: false,
bidders: 0,
},
{
id: 4,
type: "Padel Court Addition",
courts: 2,
region: "Hesse, Germany",
budget: "€80K €140K",
timeline: "Q4 2026",
specs: ["Tennis club conversion", "2 courts", "Basic lighting", "Standard glass"],
posted: "2 days ago",
heat: "cool",
credits: 8,
unlocked: true,
bidders: 5,
contact: { name: "Thomas M.", org: "TC Wiesbaden e.V.", email: "t.m***@tc-wiesbaden.de", phone: "+49 611 ***" },
},
{
id: 5,
type: "Commercial Padel Venue",
courts: 8,
region: "Hamburg, Germany",
budget: "€500K €750K",
timeline: "Q2 2026",
specs: ["Standalone commercial", "Bar/lounge area", "Premium courts", "Booking system integration"],
posted: "3 days ago",
heat: "warm",
credits: 30,
unlocked: false,
bidders: 2,
},
];
const upsells = [
{
id: "logo",
label: "Show Company Logo",
desc: "Display your logo next to your listing name",
price: 29,
period: "/mo",
boost: "+40% more clicks",
preselected: true,
active: true,
},
{
id: "highlight",
label: "Highlight Listing",
desc: "Yellow background to stand out in search results",
price: 39,
period: "/mo",
boost: "+65% more views",
preselected: true,
active: true,
},
{
id: "brandcolor",
label: "Custom Brand Color",
desc: "Use your brand color instead of yellow",
price: 59,
period: "/mo",
boost: "+80% brand recognition",
preselected: false,
active: false,
},
{
id: "verified",
label: "Verified Badge ✓",
desc: "Trusted supplier badge on your profile",
price: 49,
period: "/mo",
boost: "+55% more inquiries",
preselected: true,
active: true,
},
{
id: "sticky_week",
label: "Sticky Top 1 Week",
desc: "Pinned to the top of your category for 7 days",
price: 79,
period: "one-time",
boost: "2× more views",
preselected: false,
active: false,
},
{
id: "sticky_month",
label: "Sticky Top 1 Month",
desc: "Pinned to the top of your category for 30 days",
price: 199,
period: "one-time",
boost: "6× more views",
preselected: false,
active: false,
},
{
id: "newsletter",
label: "Featured in Newsletter",
desc: "Included in weekly email to 2,400+ project planners",
price: 99,
period: "/mo",
boost: "+120 targeted impressions/week",
preselected: false,
active: false,
},
{
id: "leadaccess",
label: "Lead Feed Access",
desc: "Browse & unlock leads in your categories",
price: 199,
period: "/mo",
boost: "Direct customer contact",
preselected: true,
active: true,
},
];
function HeatBadge({ heat }) {
const conf = {
hot: { bg: COLORS.hotDim, color: COLORS.hot, label: "🔥 Hot", border: "rgba(239,68,68,0.3)" },
warm: { bg: COLORS.warningDim, color: COLORS.warning, label: "◐ Warm", border: "rgba(245,158,11,0.3)" },
cool: { bg: COLORS.blueDim, color: COLORS.blue, label: "○ Cool", border: "rgba(59,130,246,0.3)" },
}[heat];
return (
<span style={{
background: conf.bg,
color: conf.color,
border: `1px solid ${conf.border}`,
padding: "3px 10px",
borderRadius: 20,
fontSize: 12,
fontWeight: 600,
letterSpacing: 0.3,
}}>{conf.label}</span>
);
}
function StatCard({ label, value, sub, color }) {
return (
<div style={{
background: COLORS.surface,
border: `1px solid ${COLORS.border}`,
borderRadius: 12,
padding: "20px 22px",
flex: 1,
minWidth: 160,
}}>
<div style={{ fontSize: 12, color: COLORS.textDim, textTransform: "uppercase", letterSpacing: 1.2, marginBottom: 8, fontWeight: 600 }}>{label}</div>
<div style={{ fontSize: 28, fontWeight: 700, color: color || COLORS.text, lineHeight: 1.1 }}>{value}</div>
{sub && <div style={{ fontSize: 12, color: COLORS.textMuted, marginTop: 6 }}>{sub}</div>}
</div>
);
}
function DashboardView() {
return (
<div>
<div style={{ marginBottom: 28 }}>
<h2 style={{ fontSize: 22, fontWeight: 700, color: COLORS.text, margin: 0 }}>Welcome back, PadelBau GmbH</h2>
<p style={{ color: COLORS.textMuted, margin: "6px 0 0", fontSize: 14 }}>Your supplier dashboard February 2026</p>
</div>
<div style={{ display: "flex", gap: 14, flexWrap: "wrap", marginBottom: 28 }}>
<StatCard label="Profile Views" value="1,247" sub="↑ 23% vs last month" color={COLORS.accent} />
<StatCard label="Leads Unlocked" value="14" sub="This month" color={COLORS.blue} />
<StatCard label="Credits Balance" value="85" sub="~3 premium leads" color={COLORS.warning} />
<StatCard label="Directory Rank" value="#3" sub="Padel Courts category" color={COLORS.purple} />
</div>
<div style={{
background: `linear-gradient(135deg, ${COLORS.accentDim}, ${COLORS.purpleDim})`,
border: `1px solid ${COLORS.border}`,
borderRadius: 12,
padding: "22px 26px",
marginBottom: 28,
}}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 12 }}>
<div>
<div style={{ fontSize: 15, fontWeight: 600, color: COLORS.text, marginBottom: 4 }}>🔥 3 new leads match your profile</div>
<div style={{ fontSize: 13, color: COLORS.textMuted }}>Indoor facilities in Lower Saxony, NRW, and Hamburg total project value 1.7M+</div>
</div>
<button style={{
background: COLORS.accent,
color: COLORS.bg,
border: "none",
borderRadius: 8,
padding: "10px 20px",
fontWeight: 700,
fontSize: 13,
cursor: "pointer",
whiteSpace: "nowrap",
}}>View Lead Feed </button>
</div>
</div>
<h3 style={{ fontSize: 15, fontWeight: 600, color: COLORS.text, marginBottom: 14 }}>Recent Activity</h3>
{[
{ time: "2h ago", text: "New lead posted: 6-court indoor center in Lower Saxony (€400K€600K)", dot: COLORS.hot },
{ time: "1d ago", text: "Your listing was viewed 47 times today — 12 from the Padel Courts category", dot: COLORS.accent },
{ time: "2d ago", text: "Lead unlocked: TC Wiesbaden — 2-court addition project. Contact details available.", dot: COLORS.blue },
{ time: "3d ago", text: "Your 'Sticky Top' placement in Padel Courts expired. Renew to stay on top.", dot: COLORS.warning },
{ time: "5d ago", text: "Newsletter sent to 2,400 subscribers — your company was featured", dot: COLORS.purple },
].map((item, i) => (
<div key={i} style={{
display: "flex",
gap: 14,
padding: "12px 0",
borderBottom: i < 4 ? `1px solid ${COLORS.border}` : "none",
alignItems: "flex-start",
}}>
<div style={{ width: 8, height: 8, borderRadius: 4, background: item.dot, marginTop: 6, flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<div style={{ fontSize: 13, color: COLORS.text, lineHeight: 1.5 }}>{item.text}</div>
</div>
<div style={{ fontSize: 12, color: COLORS.textDim, whiteSpace: "nowrap", flexShrink: 0 }}>{item.time}</div>
</div>
))}
</div>
);
}
function LeadFeedView() {
const [leads, setLeads] = useState(mockLeads);
const [filter, setFilter] = useState("all");
const unlock = (id) => {
setLeads(leads.map(l => l.id === id ? {
...l,
unlocked: true,
contact: { name: "Max S.", org: "Padel Invest Nord GmbH", email: "m.s***@padel-invest.de", phone: "+49 40 ***" }
} : l));
};
const filtered = filter === "all" ? leads : leads.filter(l => l.heat === filter);
return (
<div>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 24, flexWrap: "wrap", gap: 12 }}>
<div>
<h2 style={{ fontSize: 22, fontWeight: 700, color: COLORS.text, margin: 0 }}>Lead Feed</h2>
<p style={{ color: COLORS.textMuted, margin: "6px 0 0", fontSize: 14 }}>Browse anonymized project briefs · Spend credits to unlock contact details</p>
</div>
<div style={{
background: COLORS.surface,
border: `1px solid ${COLORS.border}`,
borderRadius: 8,
padding: "8px 14px",
display: "flex",
alignItems: "center",
gap: 8,
}}>
<span style={{ fontSize: 12, color: COLORS.textDim }}>Balance:</span>
<span style={{ fontSize: 16, fontWeight: 700, color: COLORS.warning }}>85 credits</span>
<button style={{
background: COLORS.warningDim,
color: COLORS.warning,
border: `1px solid rgba(245,158,11,0.3)`,
borderRadius: 6,
padding: "4px 10px",
fontSize: 11,
fontWeight: 600,
cursor: "pointer",
marginLeft: 4,
}}>Buy More</button>
</div>
</div>
<div style={{ display: "flex", gap: 8, marginBottom: 20 }}>
{[
{ id: "all", label: "All Leads" },
{ id: "hot", label: "🔥 Hot" },
{ id: "warm", label: "◐ Warm" },
{ id: "cool", label: "○ Cool" },
].map(f => (
<button key={f.id} onClick={() => setFilter(f.id)} style={{
background: filter === f.id ? COLORS.accentDim : "transparent",
color: filter === f.id ? COLORS.accent : COLORS.textMuted,
border: `1px solid ${filter === f.id ? "rgba(34,211,167,0.3)" : COLORS.border}`,
borderRadius: 20,
padding: "6px 16px",
fontSize: 12,
fontWeight: 600,
cursor: "pointer",
}}>{f.label}</button>
))}
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
{filtered.map(lead => (
<div key={lead.id} style={{
background: lead.unlocked ? COLORS.surface : COLORS.surfaceLight,
border: `1px solid ${lead.heat === "hot" ? "rgba(239,68,68,0.2)" : COLORS.border}`,
borderRadius: 12,
padding: "20px 22px",
position: "relative",
overflow: "hidden",
}}>
{lead.heat === "hot" && !lead.unlocked && (
<div style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
height: 2,
background: `linear-gradient(90deg, ${COLORS.hot}, ${COLORS.warning})`,
}} />
)}
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 12, flexWrap: "wrap", gap: 8 }}>
<div>
<div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
<span style={{ fontSize: 16, fontWeight: 700, color: COLORS.text }}>{lead.type}</span>
<HeatBadge heat={lead.heat} />
</div>
<div style={{ display: "flex", gap: 16, flexWrap: "wrap" }}>
<span style={{ fontSize: 13, color: COLORS.textMuted }}>📍 {lead.region}</span>
<span style={{ fontSize: 13, color: COLORS.textMuted }}>🏟 {lead.courts} courts</span>
<span style={{ fontSize: 13, color: COLORS.textMuted }}>💰 {lead.budget}</span>
<span style={{ fontSize: 13, color: COLORS.textMuted }}>📅 {lead.timeline}</span>
</div>
</div>
<div style={{ fontSize: 12, color: COLORS.textDim }}>{lead.posted}</div>
</div>
<div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 14 }}>
{lead.specs.map((s, i) => (
<span key={i} style={{
background: COLORS.bg,
color: COLORS.textMuted,
border: `1px solid ${COLORS.border}`,
borderRadius: 6,
padding: "3px 10px",
fontSize: 11,
fontWeight: 500,
}}>{s}</span>
))}
</div>
{lead.unlocked ? (
<div style={{
background: COLORS.accentDim,
border: `1px solid rgba(34,211,167,0.2)`,
borderRadius: 8,
padding: "14px 18px",
}}>
<div style={{ fontSize: 12, color: COLORS.accent, fontWeight: 600, marginBottom: 8, textTransform: "uppercase", letterSpacing: 0.8 }}> Contact Unlocked</div>
<div style={{ display: "flex", gap: 24, flexWrap: "wrap" }}>
<div>
<div style={{ fontSize: 11, color: COLORS.textDim }}>Contact</div>
<div style={{ fontSize: 13, color: COLORS.text, fontWeight: 600 }}>{lead.contact.name}</div>
</div>
<div>
<div style={{ fontSize: 11, color: COLORS.textDim }}>Organization</div>
<div style={{ fontSize: 13, color: COLORS.text, fontWeight: 600 }}>{lead.contact.org}</div>
</div>
<div>
<div style={{ fontSize: 11, color: COLORS.textDim }}>Email</div>
<div style={{ fontSize: 13, color: COLORS.text, fontWeight: 600 }}>{lead.contact.email}</div>
</div>
<div>
<div style={{ fontSize: 11, color: COLORS.textDim }}>Phone</div>
<div style={{ fontSize: 13, color: COLORS.text, fontWeight: 600 }}>{lead.contact.phone}</div>
</div>
</div>
</div>
) : (
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 10 }}>
<div style={{ fontSize: 12, color: COLORS.textDim }}>
{lead.bidders === 0 ? (
<span style={{ color: COLORS.accent, fontWeight: 600 }}> No other suppliers yet be first!</span>
) : (
<span>{lead.bidders} supplier{lead.bidders > 1 ? "s" : ""} already unlocked this lead</span>
)}
</div>
<button onClick={() => unlock(lead.id)} style={{
background: `linear-gradient(135deg, ${COLORS.accent}, #1AAB8A)`,
color: COLORS.bg,
border: "none",
borderRadius: 8,
padding: "10px 20px",
fontWeight: 700,
fontSize: 13,
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: 8,
}}>
<span>Unlock Contact</span>
<span style={{
background: "rgba(0,0,0,0.2)",
borderRadius: 4,
padding: "2px 8px",
fontSize: 12,
}}>{lead.credits} credits</span>
</button>
</div>
)}
</div>
))}
</div>
</div>
);
}
function ListingView() {
return (
<div>
<h2 style={{ fontSize: 22, fontWeight: 700, color: COLORS.text, margin: "0 0 6px" }}>Your Listing Preview</h2>
<p style={{ color: COLORS.textMuted, margin: "0 0 24px", fontSize: 14 }}>This is how your company appears in the directory</p>
{/* Listing card preview */}
<div style={{
background: "linear-gradient(135deg, rgba(245,158,11,0.06), rgba(245,158,11,0.02))",
border: `1px solid rgba(245,158,11,0.25)`,
borderRadius: 14,
padding: "24px 26px",
marginBottom: 28,
position: "relative",
}}>
<div style={{
position: "absolute",
top: 12,
right: 14,
background: COLORS.warningDim,
color: COLORS.warning,
border: `1px solid rgba(245,158,11,0.3)`,
padding: "3px 10px",
borderRadius: 20,
fontSize: 11,
fontWeight: 700,
letterSpacing: 0.5,
}}> PROMOTED</div>
<div style={{ display: "flex", gap: 18, alignItems: "flex-start", marginBottom: 16 }}>
<div style={{
width: 56,
height: 56,
borderRadius: 10,
background: `linear-gradient(135deg, ${COLORS.accent}, ${COLORS.blue})`,
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: 22,
fontWeight: 800,
color: COLORS.bg,
flexShrink: 0,
}}>PB</div>
<div>
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
<span style={{ fontSize: 18, fontWeight: 700, color: COLORS.text }}>PadelBau GmbH</span>
<span style={{
background: COLORS.accentDim,
color: COLORS.accent,
border: `1px solid rgba(34,211,167,0.3)`,
padding: "2px 8px",
borderRadius: 4,
fontSize: 10,
fontWeight: 700,
}}> VERIFIED</span>
</div>
<div style={{ fontSize: 13, color: COLORS.textMuted, marginBottom: 8 }}>Premium padel court manufacturer & installer. 150+ courts built across DACH region. Full-service from planning to turnkey delivery.</div>
<div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
<span style={{ fontSize: 12, color: COLORS.textDim }}>📍 Cologne, Germany</span>
<span style={{ fontSize: 12, color: COLORS.textDim }}>🏟 150+ courts installed</span>
<span style={{ fontSize: 12, color: COLORS.textDim }}> 4.8/5 (23 reviews)</span>
</div>
</div>
</div>
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
{["Padel Courts", "Court Construction", "LED Lighting", "Artificial Turf", "Planning & Design"].map((tag, i) => (
<span key={i} style={{
background: COLORS.bg,
color: COLORS.textMuted,
border: `1px solid ${COLORS.border}`,
borderRadius: 6,
padding: "4px 10px",
fontSize: 11,
fontWeight: 500,
}}>{tag}</span>
))}
</div>
</div>
<h3 style={{ fontSize: 15, fontWeight: 600, color: COLORS.text, marginBottom: 14 }}>Active Boosts on Your Listing</h3>
<div style={{ display: "flex", gap: 10, flexWrap: "wrap", marginBottom: 28 }}>
{[
{ label: "Logo Visible", color: COLORS.accent },
{ label: "Yellow Highlight", color: COLORS.warning },
{ label: "Verified Badge", color: COLORS.accent },
{ label: "Lead Feed Access", color: COLORS.blue },
].map((b, i) => (
<span key={i} style={{
background: `${b.color}15`,
color: b.color,
border: `1px solid ${b.color}30`,
padding: "6px 14px",
borderRadius: 8,
fontSize: 12,
fontWeight: 600,
}}> {b.label}</span>
))}
</div>
<h3 style={{ fontSize: 15, fontWeight: 600, color: COLORS.text, marginBottom: 14 }}>Listing Performance (Last 30 Days)</h3>
<div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
<StatCard label="Views" value="1,247" sub="From directory search" color={COLORS.accent} />
<StatCard label="Profile Clicks" value="183" sub="14.7% click rate" color={COLORS.blue} />
<StatCard label="Website Clicks" value="67" sub="From your listing" color={COLORS.purple} />
<StatCard label="Contact Requests" value="12" sub="Direct inquiries" color={COLORS.warning} />
</div>
</div>
);
}
function BoostView() {
const [selected, setSelected] = useState(
Object.fromEntries(upsells.map(u => [u.id, u.preselected]))
);
const toggle = (id) => setSelected({ ...selected, [id]: !selected[id] });
const total = upsells.reduce((sum, u) => {
if (!selected[u.id]) return sum;
return sum + u.price;
}, 0);
const monthlyTotal = upsells.reduce((sum, u) => {
if (!selected[u.id] || u.period !== "/mo") return sum;
return sum + u.price;
}, 0);
const viewMultiplier = upsells.reduce((mult, u) => {
if (!selected[u.id]) return mult;
const m = parseFloat(u.boost.match(/[\d.]+/)?.[0] || 0);
if (u.boost.includes("×")) return mult * m;
if (u.boost.includes("%")) return mult * (1 + m / 100);
return mult;
}, 1);
return (
<div>
<h2 style={{ fontSize: 22, fontWeight: 700, color: COLORS.text, margin: "0 0 6px" }}>Boost Your Visibility</h2>
<p style={{ color: COLORS.textMuted, margin: "0 0 24px", fontSize: 14 }}>Select upgrades to stand out · Pre-selected options are our recommendation</p>
<div style={{ display: "flex", gap: 20, flexWrap: "wrap" }}>
{/* Upsell list */}
<div style={{ flex: "1 1 400px", display: "flex", flexDirection: "column", gap: 10 }}>
{upsells.map(u => {
const isOn = selected[u.id];
return (
<div key={u.id} onClick={() => toggle(u.id)} style={{
background: isOn ? COLORS.surfaceLight : COLORS.surface,
border: `1px solid ${isOn ? COLORS.accent + "40" : COLORS.border}`,
borderRadius: 10,
padding: "16px 18px",
cursor: "pointer",
transition: "all 0.15s",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
gap: 14,
}}>
<div style={{ display: "flex", gap: 14, alignItems: "center", flex: 1 }}>
<div style={{
width: 22,
height: 22,
borderRadius: 6,
border: `2px solid ${isOn ? COLORS.accent : COLORS.textDim}`,
background: isOn ? COLORS.accent : "transparent",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: 13,
color: COLORS.bg,
fontWeight: 800,
flexShrink: 0,
}}>{isOn ? "✓" : ""}</div>
<div>
<div style={{ fontSize: 14, fontWeight: 600, color: COLORS.text, marginBottom: 2 }}>{u.label}</div>
<div style={{ fontSize: 12, color: COLORS.textDim }}>{u.desc}</div>
</div>
</div>
<div style={{ textAlign: "right", flexShrink: 0 }}>
<div style={{ fontSize: 16, fontWeight: 700, color: isOn ? COLORS.accent : COLORS.textMuted }}>{u.price}<span style={{ fontSize: 11, fontWeight: 400, color: COLORS.textDim }}>{u.period}</span></div>
<div style={{
fontSize: 11,
color: COLORS.accent,
background: COLORS.accentDim,
borderRadius: 4,
padding: "2px 8px",
marginTop: 4,
display: "inline-block",
fontWeight: 600,
}}>{u.boost}</div>
</div>
</div>
);
})}
</div>
{/* Summary sidebar */}
<div style={{
flex: "0 0 260px",
position: "sticky",
top: 20,
alignSelf: "flex-start",
}}>
<div style={{
background: COLORS.surface,
border: `1px solid ${COLORS.border}`,
borderRadius: 12,
padding: "22px 20px",
}}>
<div style={{ fontSize: 13, color: COLORS.textDim, textTransform: "uppercase", letterSpacing: 1, marginBottom: 16, fontWeight: 600 }}>Your Plan</div>
{upsells.filter(u => selected[u.id]).map(u => (
<div key={u.id} style={{
display: "flex",
justifyContent: "space-between",
fontSize: 13,
color: COLORS.text,
marginBottom: 8,
}}>
<span>{u.label}</span>
<span style={{ color: COLORS.textMuted }}>{u.price}</span>
</div>
))}
<div style={{
borderTop: `1px solid ${COLORS.border}`,
marginTop: 14,
paddingTop: 14,
}}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
<span style={{ fontSize: 14, fontWeight: 700, color: COLORS.text }}>Monthly</span>
<span style={{ fontSize: 18, fontWeight: 700, color: COLORS.accent }}>{monthlyTotal}/mo</span>
</div>
</div>
<div style={{
background: COLORS.accentDim,
borderRadius: 8,
padding: "12px 14px",
marginTop: 16,
textAlign: "center",
}}>
<div style={{ fontSize: 12, color: COLORS.textMuted, marginBottom: 2 }}>Estimated view boost</div>
<div style={{ fontSize: 22, fontWeight: 800, color: COLORS.accent }}>{viewMultiplier.toFixed(1)}×</div>
<div style={{ fontSize: 11, color: COLORS.textDim }}>more visibility vs basic listing</div>
</div>
<button style={{
width: "100%",
background: `linear-gradient(135deg, ${COLORS.accent}, #1AAB8A)`,
color: COLORS.bg,
border: "none",
borderRadius: 8,
padding: "12px 0",
fontWeight: 700,
fontSize: 14,
cursor: "pointer",
marginTop: 16,
}}>Update Plan </button>
<div style={{ fontSize: 11, color: COLORS.textDim, textAlign: "center", marginTop: 10 }}>
Cancel anytime · No lock-in contracts
</div>
</div>
</div>
</div>
</div>
);
}
export default function SupplierDashboard() {
const [activeTab, setActiveTab] = useState("dashboard");
return (
<div style={{
fontFamily: "'DM Sans', 'Manrope', system-ui, sans-serif",
background: COLORS.bg,
color: COLORS.text,
minHeight: "100vh",
display: "flex",
}}>
{/* Sidebar */}
<div style={{
width: 220,
background: COLORS.surface,
borderRight: `1px solid ${COLORS.border}`,
padding: "20px 0",
display: "flex",
flexDirection: "column",
flexShrink: 0,
}}>
<div style={{
padding: "0 20px 20px",
borderBottom: `1px solid ${COLORS.border}`,
marginBottom: 14,
}}>
<div style={{
fontSize: 17,
fontWeight: 800,
color: COLORS.accent,
letterSpacing: -0.5,
}}> PadelConnect</div>
<div style={{ fontSize: 11, color: COLORS.textDim, marginTop: 2 }}>Supplier Portal</div>
</div>
<div style={{ flex: 1 }}>
{tabs.map(tab => (
<button key={tab.id} onClick={() => setActiveTab(tab.id)} style={{
width: "100%",
display: "flex",
alignItems: "center",
gap: 10,
padding: "10px 20px",
border: "none",
background: activeTab === tab.id ? COLORS.accentDim : "transparent",
color: activeTab === tab.id ? COLORS.accent : COLORS.textMuted,
fontSize: 13,
fontWeight: activeTab === tab.id ? 600 : 400,
cursor: "pointer",
textAlign: "left",
borderRight: activeTab === tab.id ? `2px solid ${COLORS.accent}` : "2px solid transparent",
}}>
<span style={{ fontSize: 16 }}>{tab.icon}</span>
{tab.label}
{tab.id === "leads" && (
<span style={{
marginLeft: "auto",
background: COLORS.hotDim,
color: COLORS.hot,
borderRadius: 10,
padding: "1px 7px",
fontSize: 11,
fontWeight: 700,
}}>3</span>
)}
</button>
))}
</div>
<div style={{
padding: "14px 20px",
borderTop: `1px solid ${COLORS.border}`,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{
width: 32,
height: 32,
borderRadius: 8,
background: `linear-gradient(135deg, ${COLORS.accent}, ${COLORS.blue})`,
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: 13,
fontWeight: 700,
color: COLORS.bg,
}}>PB</div>
<div>
<div style={{ fontSize: 12, fontWeight: 600, color: COLORS.text }}>PadelBau GmbH</div>
<div style={{ fontSize: 11, color: COLORS.textDim }}>Premium Plan</div>
</div>
</div>
</div>
</div>
{/* Main content */}
<div style={{
flex: 1,
padding: "28px 32px",
overflowY: "auto",
maxHeight: "100vh",
}}>
{activeTab === "dashboard" && <DashboardView />}
{activeTab === "leads" && <LeadFeedView />}
{activeTab === "listing" && <ListingView />}
{activeTab === "boost" && <BoostView />}
</div>
</div>
);
}