refactor: dashboard cards with clickable status counts + tab bar restored

- Dashboard cards show all 4 statuses inline: new (gold), contacted (blue),
  confirmed (green), declined (red) — big numbers with consistent status colors
- Each number+label is clickable to filter the tab by that status
- Tab bar restored below dashboard
- Removed filter chips from SearchBar (dashboard handles filtering)
- Open Day card uses cyan border (distinct from blue contacted status)
This commit is contained in:
2026-03-24 18:56:39 +03:00
parent 745d72f36d
commit 67d8f6330c
2 changed files with 113 additions and 114 deletions
+15 -45
View File
@@ -1,18 +1,14 @@
"use client";
import { useState, useRef } from "react";
import { Search, X, Filter } from "lucide-react";
import { Search, X } from "lucide-react";
import { adminFetch } from "@/lib/csrf";
import { type BookingFilter, type SearchResult, BOOKING_STATUSES } from "./types";
import type { SearchResult } from "./types";
export function SearchBar({
filter,
onFilterChange,
onResults,
onClear,
}: {
filter: BookingFilter;
onFilterChange: (f: BookingFilter) => void;
onResults: (results: SearchResult[]) => void;
onClear: () => void;
}) {
@@ -40,45 +36,19 @@ export function SearchBar({
}
return (
<div className="space-y-2">
<div className="relative">
<Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-neutral-500" />
<input
type="text"
value={query}
onChange={(e) => handleChange(e.target.value)}
placeholder="Поиск по имени или телефону..."
className="w-full rounded-lg border border-white/[0.08] bg-white/[0.04] py-2 pl-9 pr-8 text-sm text-white placeholder-neutral-500 outline-none focus:border-gold/40"
/>
{query && (
<button onClick={clear} className="absolute right-2 top-1/2 -translate-y-1/2 text-neutral-500 hover:text-white">
<X size={14} />
</button>
)}
</div>
{(
<div className="flex items-center gap-1.5">
<Filter size={12} className="text-neutral-600 shrink-0" />
<button
onClick={() => onFilterChange("all")}
className={`rounded-full px-2.5 py-1 text-[11px] font-medium transition-all ${
filter === "all" ? "bg-gold/20 text-gold border border-gold/40" : "text-neutral-500 hover:text-neutral-300"
}`}
>
Все
</button>
{BOOKING_STATUSES.map((s) => (
<button
key={s.key}
onClick={() => onFilterChange(filter === s.key ? "all" : s.key)}
className={`rounded-full px-2.5 py-1 text-[11px] font-medium transition-all ${
filter === s.key ? `${s.bg} ${s.color} border ${s.border}` : "text-neutral-500 hover:text-neutral-300"
}`}
>
{s.label}
</button>
))}
</div>
<div className="relative">
<Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-neutral-500" />
<input
type="text"
value={query}
onChange={(e) => handleChange(e.target.value)}
placeholder="Поиск по имени или телефону..."
className="w-full rounded-lg border border-white/[0.08] bg-white/[0.04] py-2 pl-9 pr-8 text-sm text-white placeholder-neutral-500 outline-none focus:border-gold/40"
/>
{query && (
<button onClick={clear} className="absolute right-2 top-1/2 -translate-y-1/2 text-neutral-500 hover:text-white">
<X size={14} />
</button>
)}
</div>
);