270 lines
9.5 KiB
TypeScript
270 lines
9.5 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import Link from "next/link"
|
|
import { useBetslipStore } from "@/lib/store/betslip-store"
|
|
import {
|
|
getEventDetailMarkets,
|
|
getCardsBookingsMarkets,
|
|
type Event,
|
|
type DetailMarketSection,
|
|
} from "@/lib/mock-data"
|
|
import { cn } from "@/lib/utils"
|
|
import { ChevronDown, ChevronUp } from "lucide-react"
|
|
|
|
const MARKET_CATEGORIES = [
|
|
"Betbuilder",
|
|
"All",
|
|
"Main",
|
|
"Goals",
|
|
"Handicap",
|
|
"1st Half",
|
|
"2nd Half",
|
|
"Combo",
|
|
"Chance Mix",
|
|
"Home",
|
|
"Half Time / Full Time",
|
|
"Away",
|
|
"Correct Score",
|
|
"Asian Markets",
|
|
"Corners",
|
|
"Minutes",
|
|
"Cards/Bookings",
|
|
"Points Handicap",
|
|
"Total Points",
|
|
"Team 1",
|
|
"Team 2",
|
|
"Other",
|
|
"Handicap Goals",
|
|
"Total Goals",
|
|
"Combo",
|
|
"Specials",
|
|
]
|
|
|
|
function MarketSectionBlock({
|
|
section,
|
|
event,
|
|
marketName,
|
|
isExpanded,
|
|
onToggle,
|
|
}: {
|
|
section: DetailMarketSection
|
|
event: Event
|
|
marketName: string
|
|
isExpanded: boolean
|
|
onToggle: () => void
|
|
}) {
|
|
const { bets, addBet } = useBetslipStore()
|
|
const hasOutcomes = section.outcomes.length > 0
|
|
|
|
return (
|
|
<div className="bg-brand-surface-light border-b border-white/5">
|
|
<button
|
|
type="button"
|
|
onClick={onToggle}
|
|
className="w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/5 transition-colors"
|
|
>
|
|
<span className="text-[11px] font-bold text-white uppercase">
|
|
{section.title}
|
|
</span>
|
|
{isExpanded ? (
|
|
<ChevronUp className="size-4 text-white/60" />
|
|
) : (
|
|
<ChevronDown className="size-4 text-white/60" />
|
|
)}
|
|
</button>
|
|
{isExpanded && hasOutcomes && (
|
|
<div className="px-3 pb-3 space-y-1.5">
|
|
{section.outcomes.length > 2 && section.outcomes.length % 2 === 0 ? (
|
|
<div className="grid grid-cols-2 gap-x-4 gap-y-1.5">
|
|
{section.outcomes.map((outcome) => {
|
|
const betId = `${event.id}-${section.id}-${outcome.label.replace(/\s/g, "-").toLowerCase()}`
|
|
const isSelected = bets.some((b) => b.id === betId)
|
|
return (
|
|
<div key={outcome.label} className="flex items-center justify-between gap-2">
|
|
<span className="text-[11px] text-white/90 truncate">{outcome.label}</span>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
addBet({
|
|
id: betId,
|
|
event: `${event.homeTeam} - ${event.awayTeam}`,
|
|
league: `${event.sport} - ${event.country} - ${event.league}`,
|
|
market: marketName,
|
|
selection: outcome.label,
|
|
odds: outcome.odds,
|
|
})
|
|
}
|
|
className={cn(
|
|
"min-w-[52px] px-2 py-1 rounded text-[11px] font-bold tabular-nums text-center transition-all shrink-0",
|
|
isSelected ? "bg-brand-primary text-black" : "text-brand-primary hover:bg-white/5"
|
|
)}
|
|
>
|
|
{outcome.odds.toFixed(2)}
|
|
</button>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
) : (
|
|
section.outcomes.map((outcome) => {
|
|
const betId = `${event.id}-${section.id}-${outcome.label.replace(/\s/g, "-").toLowerCase()}`
|
|
const isSelected = bets.some((b) => b.id === betId)
|
|
return (
|
|
<div
|
|
key={outcome.label}
|
|
className="flex items-center justify-between gap-3 py-1"
|
|
>
|
|
<span className="text-[11px] text-white/90">{outcome.label}</span>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
addBet({
|
|
id: betId,
|
|
event: `${event.homeTeam} - ${event.awayTeam}`,
|
|
league: `${event.sport} - ${event.country} - ${event.league}`,
|
|
market: marketName,
|
|
selection: outcome.label,
|
|
odds: outcome.odds,
|
|
})
|
|
}
|
|
className={cn(
|
|
"min-w-[52px] px-2 py-1 rounded text-[11px] font-bold tabular-nums text-center transition-all shrink-0",
|
|
isSelected ? "bg-brand-primary text-black" : "text-brand-primary hover:bg-white/5"
|
|
)}
|
|
>
|
|
{outcome.odds.toFixed(2)}
|
|
</button>
|
|
</div>
|
|
)
|
|
})
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function MatchDetailView({ event }: { event: Event }) {
|
|
const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({
|
|
"bookings-1x2": true,
|
|
"sending-off": true,
|
|
"1st-booking": true,
|
|
"1st-half-bookings-1x2": true,
|
|
"booking-points-ou": true,
|
|
"1st-half-1st-booking": true,
|
|
})
|
|
const [activeCategory, setActiveCategory] = useState("Cards/Bookings")
|
|
|
|
const detailMarkets = getEventDetailMarkets(event.id)
|
|
const cardsBookings = getCardsBookingsMarkets(event.id)
|
|
|
|
const toggleSection = (id: string) => {
|
|
setExpandedSections((prev) => ({ ...prev, [id]: !prev[id] }))
|
|
}
|
|
|
|
const breadcrumbLeague =
|
|
event.league === "Premier League"
|
|
? "England - Premier League"
|
|
: `${event.country} - ${event.league}`
|
|
|
|
const isCardsBookings = activeCategory === "Cards/Bookings"
|
|
const leftSections = isCardsBookings ? cardsBookings.left : detailMarkets
|
|
const rightSections = isCardsBookings ? cardsBookings.right : []
|
|
|
|
return (
|
|
<div className="flex flex-col bg-brand-bg rounded overflow-hidden">
|
|
{/* Breadcrumb: back arrow, ellipsis, path */}
|
|
<div className="bg-brand-surface px-3 py-2 border-b border-border/20">
|
|
<Link
|
|
href="/"
|
|
className="flex items-center gap-2 text-[11px] font-bold text-white/70 hover:text-brand-primary transition-colors"
|
|
>
|
|
<span className="text-white/80"><</span>
|
|
<span>...</span>
|
|
<span>Football {breadcrumbLeague} / {event.homeTeam} vs. {event.awayTeam}</span>
|
|
</Link>
|
|
<h1 className="text-[15px] font-bold text-white mt-2">
|
|
{breadcrumbLeague}
|
|
</h1>
|
|
</div>
|
|
|
|
{/* Match header */}
|
|
<div className="bg-brand-surface px-4 py-5 border-b border-border/20">
|
|
<div className="flex items-center justify-center gap-10">
|
|
<div className="flex flex-col items-center gap-2">
|
|
<div className="w-16 h-20 rounded-md bg-brand-bg border border-white/10 flex items-center justify-center">
|
|
<span className="text-[10px] font-black text-white/60 uppercase">
|
|
{event.homeTeam.slice(0, 2)}
|
|
</span>
|
|
</div>
|
|
<span className="text-[13px] font-bold text-white">{event.homeTeam}</span>
|
|
</div>
|
|
<span className="text-[12px] font-black text-white/50 uppercase">VS</span>
|
|
<div className="flex flex-col items-center gap-2">
|
|
<div className="w-16 h-20 rounded-md bg-brand-bg border border-white/10 flex items-center justify-center">
|
|
<span className="text-[10px] font-black text-white/60 uppercase">
|
|
{event.awayTeam.slice(0, 2)}
|
|
</span>
|
|
</div>
|
|
<span className="text-[13px] font-bold text-white">{event.awayTeam}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Category tabs: horizontal scroll, selected = darker grey */}
|
|
<div className="flex overflow-x-auto gap-1 p-2 bg-brand-bg border-b border-border/20 scrollbar-hide">
|
|
{MARKET_CATEGORIES.map((label) => (
|
|
<button
|
|
key={label}
|
|
type="button"
|
|
onClick={() => setActiveCategory(label)}
|
|
className={cn(
|
|
"px-3 py-1.5 text-[10px] font-bold uppercase whitespace-nowrap rounded transition-colors shrink-0",
|
|
activeCategory === label
|
|
? "bg-brand-surface-light text-white border border-white/10"
|
|
: "text-white/60 hover:text-white hover:bg-white/5"
|
|
)}
|
|
>
|
|
{label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Two-column grid of market sections */}
|
|
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-0 bg-brand-surface-light">
|
|
{/* Left column */}
|
|
<div className="border-r border-white/5">
|
|
{leftSections.map((section) => (
|
|
<MarketSectionBlock
|
|
key={section.id}
|
|
section={section}
|
|
event={event}
|
|
marketName={section.title}
|
|
isExpanded={expandedSections[section.id] ?? false}
|
|
onToggle={() => toggleSection(section.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
{/* Right column (Cards/Bookings only) */}
|
|
{rightSections.length > 0 && (
|
|
<div>
|
|
{rightSections.map((section) => (
|
|
<MarketSectionBlock
|
|
key={section.id}
|
|
section={section}
|
|
event={event}
|
|
marketName={section.title}
|
|
isExpanded={expandedSections[section.id] ?? false}
|
|
onToggle={() => toggleSection(section.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|