Adjusted links.

This commit is contained in:
2026-01-06 17:58:26 -06:00
parent a69d8c0291
commit 725b81494e
9 changed files with 173 additions and 101 deletions

View File

@ -18,6 +18,7 @@ import { Live } from './pages/Live'
import { NewBets } from './pages/NewBets'
import { Watchlist } from './pages/Watchlist'
import { HowItWorks } from './pages/HowItWorks'
import { EventDetail } from './pages/EventDetail'
const queryClient = new QueryClient({
defaultOptions: {
@ -60,6 +61,7 @@ function App() {
<Route path="/new-bets" element={<NewBets />} />
<Route path="/watchlist" element={<Watchlist />} />
<Route path="/how-it-works" element={<HowItWorks />} />
<Route path="/events/:id" element={<EventDetail />} />
<Route
path="/profile"

View File

@ -0,0 +1,96 @@
import { Link, useParams } from 'react-router-dom'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useAuthStore } from '@/store'
import { sportEventsApi } from '@/api/sport-events'
import { SpreadGrid } from '@/components/bets/SpreadGrid'
import { Button } from '@/components/common/Button'
import { Loading } from '@/components/common/Loading'
import { Header } from '@/components/layout/Header'
import { ChevronLeft } from 'lucide-react'
export const EventDetail = () => {
const { id } = useParams<{ id: string }>()
const eventId = parseInt(id || '0', 10)
const { isAuthenticated } = useAuthStore()
const queryClient = useQueryClient()
const { data: event, isLoading, error } = useQuery({
queryKey: ['sport-event', eventId, isAuthenticated],
queryFn: () =>
isAuthenticated
? sportEventsApi.getEventWithGrid(eventId)
: sportEventsApi.getPublicEventWithGrid(eventId),
enabled: eventId > 0,
})
const handleBetCreated = () => {
// Refetch event data to show new bet
queryClient.invalidateQueries({ queryKey: ['sport-event', eventId] })
queryClient.invalidateQueries({ queryKey: ['public-sport-events'] })
}
const handleBetTaken = () => {
// Refetch event data to update bet status
queryClient.invalidateQueries({ queryKey: ['sport-event', eventId] })
queryClient.invalidateQueries({ queryKey: ['public-sport-events'] })
}
if (isLoading) {
return (
<div className="min-h-screen bg-gray-50">
<Header />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Link to="/">
<Button variant="secondary">
<ChevronLeft size={20} className="mr-2" />
Back to Events
</Button>
</Link>
<div className="mt-8">
<Loading />
</div>
</div>
</div>
)
}
if (error || !event) {
return (
<div className="min-h-screen bg-gray-50">
<Header />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Link to="/">
<Button variant="secondary">
<ChevronLeft size={20} className="mr-2" />
Back to Events
</Button>
</Link>
<div className="mt-8 text-center py-12 bg-white rounded-lg shadow">
<p className="text-gray-600">Event not found</p>
</div>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gray-50">
<Header />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Link to="/">
<Button variant="secondary">
<ChevronLeft size={20} className="mr-2" />
Back to Events
</Button>
</Link>
<div className="mt-6">
<SpreadGrid
event={event}
onBetCreated={handleBetCreated}
onBetTaken={handleBetTaken}
/>
</div>
</div>
</div>
)
}

View File

@ -3,16 +3,14 @@ import { Link, useNavigate } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import { useAuthStore } from '@/store'
import { sportEventsApi } from '@/api/sport-events'
import { SpreadGrid } from '@/components/bets/SpreadGrid'
import { Button } from '@/components/common/Button'
import { Loading } from '@/components/common/Loading'
import { Header } from '@/components/layout/Header'
import { ChevronLeft, TrendingUp, Clock, ArrowRight } from 'lucide-react'
import { TrendingUp, Clock, ArrowRight } from 'lucide-react'
export const Home = () => {
const navigate = useNavigate()
const { isAuthenticated } = useAuthStore()
const [selectedEventId, setSelectedEventId] = useState<number | null>(null)
const [email, setEmail] = useState('')
// Use public API for events (works for both authenticated and non-authenticated)
@ -21,24 +19,6 @@ export const Home = () => {
queryFn: () => sportEventsApi.getPublicEvents(),
})
// Use authenticated API for event details if logged in, otherwise public
const { data: selectedEvent, isLoading: isLoadingEvent } = useQuery({
queryKey: ['sport-event', selectedEventId, isAuthenticated],
queryFn: () =>
isAuthenticated
? sportEventsApi.getEventWithGrid(selectedEventId!)
: sportEventsApi.getPublicEventWithGrid(selectedEventId!),
enabled: selectedEventId !== null,
})
const handleEventClick = (eventId: number) => {
setSelectedEventId(eventId)
}
const handleBackToList = () => {
setSelectedEventId(null)
}
const handleSignUp = (e: React.FormEvent) => {
e.preventDefault()
navigate(`/register?email=${encodeURIComponent(email)}`)
@ -56,47 +36,6 @@ export const Home = () => {
)
}
// Selected event view (spread grid)
if (selectedEventId) {
if (isLoadingEvent) {
return (
<div className="min-h-screen bg-gray-50">
<Header />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Button variant="secondary" onClick={handleBackToList}>
<ChevronLeft size={20} className="mr-2" />
Back to Events
</Button>
<div className="mt-8">
<Loading />
</div>
</div>
</div>
)
}
if (selectedEvent) {
return (
<div className="min-h-screen bg-gray-50">
<Header />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Button variant="secondary" onClick={handleBackToList}>
<ChevronLeft size={20} className="mr-2" />
Back to Events
</Button>
<div className="mt-6">
<SpreadGrid
event={selectedEvent}
onBetCreated={() => {}}
onBetTaken={() => {}}
/>
</div>
</div>
</div>
)
}
}
// Calculate total open bets across all events
const totalOpenBets = events?.length || 0
@ -131,11 +70,13 @@ export const Home = () => {
</form>
)}
{isAuthenticated && (
{isAuthenticated && events?.[0] && (
<div className="flex gap-4">
<Button size="lg" onClick={() => events?.[0] && handleEventClick(events[0].id)}>
Start Betting <ArrowRight size={18} className="ml-2" />
</Button>
<Link to={`/events/${events[0].id}`}>
<Button size="lg">
Start Betting <ArrowRight size={18} className="ml-2" />
</Button>
</Link>
</div>
)}
</div>
@ -262,9 +203,9 @@ export const Home = () => {
const isUrgent = hoursUntil >= 0 && hoursUntil < 24
return (
<button
<Link
key={event.id}
onClick={() => handleEventClick(event.id)}
to={`/events/${event.id}`}
className="grid grid-cols-12 gap-4 px-6 py-5 w-full text-left hover:bg-gray-50 transition-colors items-center"
>
<div className="col-span-4">
@ -305,7 +246,7 @@ export const Home = () => {
Spreads: {event.min_spread} to {event.max_spread}
</div>
</div>
</button>
</Link>
)
})}
</div>

View File

@ -12,7 +12,7 @@ export const NewBets = () => {
queryFn: () => sportEventsApi.getPublicEvents(),
})
// Simulate recent bets from events
// Show events with simulated bet activity
const recentBets = events?.slice(0, 10).map((event, index) => ({
id: index,
event,
@ -39,7 +39,7 @@ export const NewBets = () => {
{recentBets?.map((bet) => (
<Link
key={bet.id}
to="/"
to={`/events/${bet.event.id}`}
className="block bg-white rounded-xl shadow-sm hover:shadow-md transition-shadow p-6 border border-gray-100"
>
<div className="flex items-center justify-between">
@ -64,7 +64,7 @@ export const NewBets = () => {
<Clock size={14} />
{bet.timeAgo}
</span>
<Button size="sm">Take Bet</Button>
<Button size="sm">View Event</Button>
</div>
</div>
</Link>

View File

@ -1,18 +1,32 @@
import { Link } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import { Header } from '@/components/layout/Header'
import { Button } from '@/components/common/Button'
import { Loading } from '@/components/common/Loading'
import { sportEventsApi } from '@/api/sport-events'
import { Trophy, ArrowRight } from 'lucide-react'
export const Sports = () => {
const { data: events, isLoading } = useQuery({
queryKey: ['public-sport-events'],
queryFn: () => sportEventsApi.getPublicEvents(),
})
const sports = [
{ name: 'Football', icon: '🏈', leagues: ['NFL', 'NCAA Football'] },
{ name: 'Basketball', icon: '🏀', leagues: ['NBA', 'NCAA Basketball'] },
{ name: 'Hockey', icon: '🏒', leagues: ['NHL'] },
{ name: 'Soccer', icon: '⚽', leagues: ['Premier League', 'La Liga', 'Bundesliga', 'MLS'] },
{ name: 'Baseball', icon: '⚾', leagues: ['MLB'] },
{ name: 'MMA', icon: '🥊', leagues: ['UFC', 'Bellator'] },
{ name: 'Football', icon: '🏈', filter: 'football' },
{ name: 'Basketball', icon: '🏀', filter: 'basketball' },
{ name: 'Hockey', icon: '🏒', filter: 'hockey' },
{ name: 'Soccer', icon: '⚽', filter: 'soccer' },
{ name: 'Baseball', icon: '⚾', filter: 'baseball' },
{ name: 'MMA', icon: '🥊', filter: 'mma' },
]
// Group events by sport
const eventsBySport = sports.map(sport => ({
...sport,
events: events?.filter(e => e.sport.toLowerCase() === sport.filter) || [],
}))
return (
<div className="min-h-screen bg-gray-50">
<Header />
@ -23,30 +37,49 @@ export const Sports = () => {
<p className="text-xl text-gray-600">Choose your sport and start betting</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{sports.map((sport) => (
<Link
key={sport.name}
to="/"
className="bg-white rounded-xl shadow-sm hover:shadow-md transition-shadow p-6 border border-gray-100"
>
<div className="flex items-center gap-4 mb-4">
<span className="text-4xl">{sport.icon}</span>
<h2 className="text-2xl font-bold text-gray-900">{sport.name}</h2>
{isLoading ? (
<Loading />
) : (
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{eventsBySport.map((sport) => (
<div
key={sport.name}
className="bg-white rounded-xl shadow-sm p-6 border border-gray-100"
>
<div className="flex items-center gap-4 mb-4">
<span className="text-4xl">{sport.icon}</span>
<div>
<h2 className="text-2xl font-bold text-gray-900">{sport.name}</h2>
<p className="text-sm text-gray-500">{sport.events.length} events</p>
</div>
</div>
{sport.events.length > 0 ? (
<div className="space-y-2">
{sport.events.slice(0, 3).map((event) => (
<Link
key={event.id}
to={`/events/${event.id}`}
className="block p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"
>
<p className="font-medium text-gray-900 text-sm">
{event.home_team} vs {event.away_team}
</p>
<p className="text-xs text-gray-500">{event.league}</p>
</Link>
))}
{sport.events.length > 3 && (
<p className="text-xs text-gray-400 text-center pt-2">
+{sport.events.length - 3} more events
</p>
)}
</div>
) : (
<p className="text-sm text-gray-400">No upcoming events</p>
)}
</div>
<div className="flex flex-wrap gap-2">
{sport.leagues.map((league) => (
<span
key={league}
className="px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm"
>
{league}
</span>
))}
</div>
</Link>
))}
</div>
))}
</div>
)}
<div className="mt-12 text-center">
<Link to="/">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 242 KiB