- Implemented HeroBanner component for image carousel with navigation arrows and indicators. - Created LiveEventsList component to display live events with odds and match details. - Added SportsNav component for sport category navigation with icons. - Introduced TopMatches component to showcase highlighted matches with odds. - Updated InPlayHeader and QuickFilterBar for improved UI and functionality. - Enhanced ReloadTicket and SearchEvent components for better user experience. - Refactored SportsSidebar to include popular leagues and quick filter options. - Added new sport-home layout to integrate various betting components.
196 lines
9.1 KiB
TypeScript
196 lines
9.1 KiB
TypeScript
"use client"
|
||
|
||
import { useBetslipStore } from "@/lib/store/betslip-store"
|
||
import { mockEvents, type Event } from "@/lib/mock-data"
|
||
import { cn } from "@/lib/utils"
|
||
import { BarChart2, TrendingUp, Monitor, Tv } from "lucide-react"
|
||
|
||
|
||
function LiveEventRow({ event, isNoOdds }: { event: Event, isNoOdds?: boolean }) {
|
||
const { bets, addBet } = useBetslipStore()
|
||
|
||
// Dummy data for demonstration
|
||
const score = event.homeScore !== undefined ? `${event.homeScore} - ${event.awayScore}` : "0 - 0"
|
||
const time = event.liveMinute ? `${event.liveMinute}:00` : "83:10"
|
||
const period = "H2"
|
||
|
||
return (
|
||
<div className="bg-[#121212] border-b border-white/5 hover:bg-white/5 transition-colors h-[50px] flex items-center group">
|
||
{/* Match Info Column (Time & Score) */}
|
||
<div className="flex items-center gap-3 px-3 w-[360px] shrink-0 h-full border-r border-white/5">
|
||
<div className="flex flex-col text-[10px] font-black leading-tight italic w-[55px] shrink-0 tabular-nums">
|
||
<span className="text-[#ff9800]">{time}</span>
|
||
<span className="text-white/40">{period}</span>
|
||
</div>
|
||
<div className="flex items-center min-w-0 flex-1 gap-2">
|
||
<span className="text-[11.5px] font-black text-white truncate italic uppercase">
|
||
{event.homeTeam} <span className="text-[#ff9800] mx-1 tabular-nums">{score}</span> {event.awayTeam}
|
||
</span>
|
||
</div>
|
||
<div className="flex items-center gap-2 shrink-0 px-1 opacity-20 group-hover:opacity-100 transition-opacity">
|
||
<BarChart2 className="size-3.5 text-white" />
|
||
<Monitor className="size-3.5 text-white" />
|
||
</div>
|
||
</div>
|
||
|
||
{/* Odds Grid or Placeholder */}
|
||
<div className="flex-1 h-full flex items-center">
|
||
{isNoOdds ? (
|
||
<div className="flex-1 h-full bg-[#161616] flex items-center justify-center text-[10.5px] font-black text-white/20 uppercase italic tracking-tight">
|
||
Sorry, no odds for this match
|
||
</div>
|
||
) : (
|
||
<div className="flex-1 grid grid-cols-3 h-full">
|
||
{event.markets.slice(0, 3).map((m, idx) => {
|
||
const labels = ["Home", "Draw", "Away"]
|
||
return (
|
||
<button
|
||
key={m.id}
|
||
onClick={() => addBet({
|
||
id: `${event.id}-${m.id}`,
|
||
event: `${event.homeTeam} vs ${event.awayTeam}`,
|
||
league: event.league,
|
||
market: "1X2",
|
||
selection: `${m.label}`,
|
||
odds: m.odds,
|
||
})}
|
||
className="bg-[#1a1a1a] hover:bg-[#2a2a2a] flex items-center justify-between px-4 h-full border-r border-white/5 transition-colors group/btn"
|
||
>
|
||
<span className="text-[10px] font-black text-white/40 group-hover/btn:text-white uppercase">{labels[idx]}</span>
|
||
<span className="text-[11px] font-black text-[#ff9800] tabular-nums">{m.odds.toFixed(2)}</span>
|
||
</button>
|
||
)
|
||
})}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Right Indicator */}
|
||
<div className="w-[4px] bg-[#ff9800] h-full" />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
const liveSports = [
|
||
{ id: "soccer", label: "Soccer", icon: "⚽", count: 25, active: true },
|
||
{ id: "basketball", label: "Basketball", icon: "🏀", count: 39 },
|
||
{ id: "ice-hockey", label: "Ice Hockey", icon: "🏒", count: 3 },
|
||
{ id: "tennis", label: "Tennis", icon: "🎾", count: 4 },
|
||
{ id: "handball", label: "Handball", icon: "🤾", count: 10 },
|
||
{ id: "rugby", label: "Rugby", icon: "🏉", count: 2 },
|
||
{ id: "table-tennis", label: "Table Tennis", icon: "🏓", count: 8 },
|
||
{ id: "volleyball", label: "Volleyball", icon: "🏐", count: 7 },
|
||
{ id: "futsal", label: "Futsal", icon: "⚽", count: 2 },
|
||
{ id: "esport-counter-strike", label: "ESport Cou...", icon: "🎮", count: 2 },
|
||
{ id: "esport-league-of-legends", label: "ESport Lea...", icon: "🎮", count: 1 },
|
||
{ id: "esport-dota-2", label: "ESport Dota", icon: "🎮", count: 1 },
|
||
{ id: "efootball", label: "eFootball", icon: "⚽", count: 4 },
|
||
{ id: "ebasketball", label: "eBasketball", icon: "🏀", count: 1 },
|
||
]
|
||
|
||
export function LiveEventsList() {
|
||
// Enhanced mock data local to live view to match screenshot exactly
|
||
const liveMatches = [
|
||
{
|
||
league: "Algeria - Ligue 1",
|
||
flag: "https://flagcdn.com/w20/dz.png",
|
||
matches: [
|
||
{ ...mockEvents[0], id: "l1", homeTeam: "Paradou AC", awayTeam: "Ben Aknoun", homeScore: 3, awayScore: 5, liveMinute: 91, noOdds: true }
|
||
]
|
||
},
|
||
{
|
||
league: "Australia - U23 Victoria NPL",
|
||
flag: "https://flagcdn.com/w20/au.png",
|
||
matches: [
|
||
{ ...mockEvents[1], id: "l2", homeTeam: "Oakleigh Cannons FC", awayTeam: "Altona Magic SC", homeScore: 5, awayScore: 1, liveMinute: 87, noOdds: true }
|
||
]
|
||
},
|
||
{
|
||
league: "Australia - U23 Victoria Premier League 1",
|
||
flag: "https://flagcdn.com/w20/au.png",
|
||
matches: [
|
||
{ ...mockEvents[2], id: "l3", homeTeam: "Northcote City FC", awayTeam: "Western United FC", homeScore: 4, awayScore: 0, liveMinute: 83, noOdds: false },
|
||
{ ...mockEvents[3], id: "l4", homeTeam: "Melbourne Knights FC", awayTeam: "Melbourne Victory FC", homeScore: 0, awayScore: 3, liveMinute: 81, noOdds: true }
|
||
]
|
||
},
|
||
{
|
||
league: "Australia - Victoria NPL, Women",
|
||
flag: "https://flagcdn.com/w20/au.png",
|
||
matches: [
|
||
{ ...mockEvents[4], id: "l5", homeTeam: "Preston Lions FC", awayTeam: "South Melbourne FC", homeScore: 1, awayScore: 1, liveMinute: 52, noOdds: true },
|
||
{ ...mockEvents[0], id: "l6", homeTeam: "Bentleigh Greens SC", awayTeam: "Box Hill United", homeScore: 0, awayScore: 6, liveMinute: 83, noOdds: true }
|
||
]
|
||
}
|
||
]
|
||
|
||
return (
|
||
<div className="flex flex-col min-h-screen bg-[#111]">
|
||
{/* Sport Navigation Carousel */}
|
||
<div className="bg-[#1a1a1a] border-b border-border/20 px-2 flex items-center h-[54px] overflow-x-auto scrollbar-hide">
|
||
<div className="flex items-center gap-0 h-full">
|
||
{/* Favourites & Prematch */}
|
||
<button className="flex flex-col items-center justify-center px-4 h-full border-r border-white/5 min-w-[70px]">
|
||
<span className="text-[14px]">⭐</span>
|
||
<span className="text-[9px] font-bold text-white/40 uppercase mt-0.5">Favourites</span>
|
||
</button>
|
||
<button className="flex flex-col items-center justify-center px-4 h-full border-r border-white/5 min-w-[70px]">
|
||
<span className="text-[14px]">⏱️</span>
|
||
<span className="text-[9px] font-bold text-white/40 uppercase mt-0.5">Prematch</span>
|
||
</button>
|
||
|
||
{/* Live Sports */}
|
||
{liveSports.map((sport) => (
|
||
<button
|
||
key={sport.id}
|
||
className={cn(
|
||
"flex flex-col items-center justify-center px-3 h-full border-r border-white/5 min-w-[75px] relative transition-colors",
|
||
sport.active ? "bg-black/20" : "hover:bg-white/5"
|
||
)}
|
||
>
|
||
<span className="absolute top-1 right-2 text-[8.5px] font-black text-white/40">{sport.count}</span>
|
||
<span className="text-[16px]">{sport.icon}</span>
|
||
<span className={cn(
|
||
"text-[9px] font-bold uppercase mt-1 tracking-tighter whitespace-nowrap",
|
||
sport.active ? "text-[#ff9800]" : "text-white/40"
|
||
)}>
|
||
{sport.label}
|
||
</span>
|
||
{sport.active && (
|
||
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-[#ff9800]" />
|
||
)}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Category Header (Soccer) */}
|
||
<div className="bg-[#009688] px-3 py-1.5 flex items-center gap-2 border-l-[4px] border-[#ff9800]">
|
||
<span className="text-[16px]">⚽</span>
|
||
<h2 className="text-[14px] font-black text-white uppercase tracking-tight">Soccer</h2>
|
||
</div>
|
||
|
||
{/* Grouped Live Matches */}
|
||
<div className="flex flex-col mb-10">
|
||
{liveMatches.map((group, gIdx) => (
|
||
<div key={gIdx} className="flex flex-col">
|
||
{/* League Header */}
|
||
<div className="bg-[#1a1a1a] px-3 py-1 border-b border-border/10 flex items-center gap-2">
|
||
<img src={group.flag} width="14" alt={group.league} className="rounded-sm opacity-60" />
|
||
<span className="text-[9.5px] font-black text-white/60 uppercase tracking-widest leading-none">
|
||
{group.league}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Matches in this league */}
|
||
<div className="flex flex-col">
|
||
{group.matches.map((match, mIdx) => (
|
||
<LiveEventRow key={match.id} event={match as any} isNoOdds={match.noOdds} />
|
||
))}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|