HotTRDealsFrontend/src/components/Sidebar/HotDealsSidebar.tsx

158 lines
5.4 KiB
TypeScript
Raw 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 { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { fetchTopDeals, type TopRange } from "../../api/deal/getTopDeals";
import { scoreToHeat } from "../../utils/heat";
const LIMIT = 6;
const TABS: { key: TopRange; label: string }[] = [
{ key: "day", label: "Günlük" },
{ key: "week", label: "Haftalık" },
{ key: "month", label: "Aylık" },
];
export default function HotDealsSidebar() {
const navigate = useNavigate();
const [range, setRange] = useState<TopRange>("day");
const [items, setItems] = useState<any[]>([]); // Initialize with the correct type
const [loading, setLoading] = useState(false);
const [err, setErr] = useState<string | null>(null);
useEffect(() => {
let canceled = false;
const load = async () => {
setLoading(true);
setErr(null);
try {
const data = await fetchTopDeals(range, LIMIT);
if (canceled) return;
setItems(Array.isArray(data) ? data.slice(0, LIMIT) : []);
} catch (e: any) {
if (canceled) return;
setErr(e?.message ?? "Bir hata oluştu");
setItems([]);
} finally {
if (!canceled) setLoading(false);
}
};
load();
return () => {
canceled = true;
};
}, [range]);
return (
<div className="rounded shadow-lg bg-surface p-4">
{/* Title and Tabs */}
<div className="text-center">
<div className="text-sm font-semibold text-grey">En İyi İlanlar</div>
<div className="mt-3 flex justify-center">
<div className="relative inline-flex items-center rounded-full bg-background shadow-md p-1">
{/* Sliding indicator */}
<div
className="absolute top-1 bottom-1 rounded-full transition-all bg-background/50 border border-white/10 shadow-sm duration-200"
style={{}}
/>
{TABS.map((t) => {
const isActive = t.key === range;
return (
<button
key={t.key}
type="button"
onClick={() => setRange(t.key)}
className={[
"relative z-10 px-3 py-1.5 rounded-full text-xs font-semibold transition-colors cursor-pointer",
isActive ? "text-primary" : "text-text-muted hover:text-text",
].join(" ")}
>
{t.label}
</button>
);
})}
</div>
</div>
</div>
{err && (
<div className="mt-3 rounded-xl shadow-md bg-[linear-gradient(90deg,var(--color-notice-danger-soft),var(--color-surface))] px-3 py-2 text-xs text-text">
{err}
</div>
)}
{/* Items - Vertical Layout (1 item per row) */}
<div className="mt-4 flex flex-col gap-4">
{loading && items.length === 0
? Array.from({ length: LIMIT }).map((_, i) => (
<div key={i} className="h-[200px] rounded-2xl shadow-md bg-background/40 animate-pulse" />
))
: items.map((d) => {
const img = d.imageUrl || "/placeholder.png";
const price = d.price ? `${d.price}` : "";
const title = d.title || "Ürün adı";
const { degree, color } = scoreToHeat(d.score ?? 0);
return (
<button
key={d.id}
type="button"
onClick={() => navigate(`/deal/${d.id}`)}
className="group text-left w-full hover:bg-background/20 transition-all"
>
<div className="flex items-center space-x-4">
{/* Left: Image */}
<div className="w-1/3">
<img
src={img}
alt={title}
className="w-full h-full object-cover rounded-lg"
loading="lazy"
/>
</div>
{/* Right: Details */}
<div className="w-2/3">
<div className="text-xs font-semibold text-text line-clamp-2 group-hover:text-primary transition">
{title}
</div>
<div className="mt-2 text-sm font-bold text-primary">{price}</div>
</div>
</div>
{/* Heat Indicator */}
<div
className="absolute top-2 right-2 px-2 py-1 text-[12px] font-bold text-white rounded-full"
style={{ backgroundColor: color }}
>
{degree}°
</div>
</button>
);
})}
{/* No items or error */}
{!loading && items.length === 0 && !err && (
<div className="rounded-2xl shadow-md bg-background/40 p-4 text-center">
<div className="text-sm font-semibold text-text">Gösterilecek fırsat yok</div>
<div className="text-xs text-text-muted mt-1">Daha sonra tekrar dene.</div>
</div>
)}
</div>
{/* View All Button */}
<div className="text-center mt-4">
<button
onClick={() => navigate(`/deals/${range}`)}
className="btn btn-primary w-full py-2 rounded-md text-white"
>
Hepsini Gör
</button>
</div>
</div>
);
}