Files
lead-scraper/components/layout/TopBar.tsx
Timo Uttenweiler 60073b97c9 feat: OnyvaLeads customer UI — Suche + Leadspeicher
- New Topbar: logo, 2-tab pill switcher, live "Neu" badge
- /suche page: SearchCard, LoadingCard, ExamplePills
- /leadspeicher page: full leads table with filters, pagination
- StatusBadge, StatusPopover, LeadSidePanel, BulkActionBar
- POST /api/search: unified search entry point → serp-enrich
- Remove Sidebar + old TopBar from layout
- Title: OnyvaLeads, redirect / → /suche

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:48:05 +01:00

138 lines
3.7 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
function OnyvaLogo() {
return (
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<div
style={{
width: 24,
height: 24,
borderRadius: 6,
background: "linear-gradient(135deg, #3b82f6, #8b5cf6)",
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
}}
>
{/* 5-pointed star SVG */}
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<polygon
points="7,1 8.5,5.5 13,5.5 9.5,8.5 10.8,13 7,10.2 3.2,13 4.5,8.5 1,5.5 5.5,5.5"
fill="white"
/>
</svg>
</div>
<span style={{ fontSize: 15, fontWeight: 500, color: "#ffffff" }}>OnyvaLeads</span>
</div>
);
}
export function Topbar() {
const pathname = usePathname();
const [newLeadsCount, setNewLeadsCount] = useState(0);
useEffect(() => {
function fetchNewLeads() {
fetch("/api/leads/stats")
.then((r) => r.json())
.then((d: { new?: number }) => setNewLeadsCount(d.new ?? 0))
.catch(() => {});
}
fetchNewLeads();
const t = setInterval(fetchNewLeads, 30000);
return () => clearInterval(t);
}, []);
const tabs = [
{ href: "/suche", label: "Suche" },
{ href: "/leadspeicher", label: "Leadspeicher" },
];
return (
<header
style={{
position: "sticky",
top: 0,
zIndex: 50,
height: 52,
background: "#111118",
borderBottom: "1px solid #1e1e2e",
display: "flex",
alignItems: "center",
paddingLeft: 20,
paddingRight: 20,
gap: 16,
flexShrink: 0,
}}
>
{/* Logo */}
<Link href="/suche" style={{ textDecoration: "none" }}>
<OnyvaLogo />
</Link>
{/* Tab switcher */}
<div
style={{
background: "#0a0a0f",
borderRadius: 8,
padding: 3,
display: "flex",
gap: 2,
}}
>
{tabs.map((tab) => {
const isActive = pathname === tab.href || pathname.startsWith(tab.href + "/");
return (
<Link
key={tab.href}
href={tab.href}
style={{
display: "flex",
alignItems: "center",
gap: 6,
padding: "4px 12px",
borderRadius: 6,
fontSize: 13,
fontWeight: isActive ? 500 : 400,
color: isActive ? "#ffffff" : "#9ca3af",
background: isActive ? "#111118" : "transparent",
boxShadow: isActive ? "0 1px 3px rgba(0,0,0,0.2)" : "none",
textDecoration: "none",
transition: "all 0.15s",
whiteSpace: "nowrap",
}}
>
{tab.label}
{tab.href === "/leadspeicher" && newLeadsCount > 0 && (
<span
style={{
background: "#3b82f6",
color: "#ffffff",
fontSize: 10,
fontWeight: 600,
minWidth: 18,
height: 18,
borderRadius: 10,
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "0 4px",
lineHeight: 1,
}}
>
{newLeadsCount > 99 ? "99+" : newLeadsCount}
</span>
)}
</Link>
);
})}
</div>
</header>
);
}