Frontend
πŸ‘οΈ Portal (Client View)

Portal - Sportsbook Client View

URL: portal.altsportsleagues.ai Purpose: External read-only interface for sportsbook operators to view published odds and league data.

Overview

Portal is the client-facing platform where sportsbook operators consume AltSportsData's published odds, browse events, and integrate data into their systems. Unlike PRTL, Portal is read-only - clients can view but not modify odds.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Portal Architecture                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                   β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚   β”‚   League    β”‚                    β”‚                     β”‚    β”‚
β”‚   β”‚   Sidebar   β”‚                    β”‚   Event Detail      β”‚    β”‚
β”‚   β”‚             β”‚                    β”‚   (Tabs: Overview,  β”‚    β”‚
β”‚   β”‚  β–Ό MMA      β”‚                    β”‚    Fights, Odds)    β”‚    β”‚
β”‚   β”‚    UFC ●    β”‚                    β”‚                     β”‚    β”‚
β”‚   β”‚    BKB      β”‚                    β”‚                     β”‚    β”‚
β”‚   β”‚  β–Ό F1       β”‚                    β”‚                     β”‚    β”‚
β”‚   β”‚    Monaco ● β”‚                    β”‚                     β”‚    β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                   β”‚
β”‚   ● = Live Event                                                 β”‚
β”‚                                                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Differences from PRTL

FeaturePRTL (Internal)Portal (External)
AccessInternal staff onlySportsbook operators
Odds EditingFull edit capabilitiesRead-only view
Market ControlsSuspend/resume/settleView status only
Data SourceAll markets (draft β†’ settled)Published markets only
AuthenticationSSO + 2FAAPI Key + OAuth

Key Features

1. League Sidebar Navigation

Collapsible sidebar with league hierarchy and live event indicators:

<LeagueSidebar className="h-full" />

Features:

  • Sport grouping (MMA, Motorsports, etc.)
  • League expansion/collapse
  • Live event count badges
  • Active event highlighting
  • Collapsible to icon-only view

Visual structure:

β–Ό MMA
  ● UFC (3 live)
  β—‹ BKB Extreme Fighting (2)
β–Ό Motorsports
  ● Formula 1 (2 live)
β–Ό Other
  β—‹ Jai Alai Miami (5)
  β—‹ World Drone Racing (2)

2. Event Detail Page

Tabbed interface for event information:

// Tab structure
<Tabs defaultValue="overview">
  <TabsList>
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="fights">Fights (8)</TabsTrigger>
    <TabsTrigger value="odds">Odds</TabsTrigger>
  </TabsList>
 
  <TabsContent value="overview">
    <EventOverview event={event} />
  </TabsContent>
 
  <TabsContent value="fights">
    <FightsList fights={event.fights} />
  </TabsContent>
 
  <TabsContent value="odds">
    <OddsDisplay markets={event.markets} />
  </TabsContent>
</Tabs>

3. Status Badges (Read-Only)

Display-only status indicators:

<StatusBadge status="live" />        // Green pulsing dot
<StatusBadge status="upcoming" />    // Blue static dot
<StatusBadge status="completed" />   // Gray dot
<StatusBadge status="suspended" />   // Yellow warning

Status types supported:

  • live - Event/market currently active
  • upcoming - Scheduled future event
  • scheduled - Same as upcoming
  • completed - Event finished
  • cancelled - Event cancelled
  • suspended - Market temporarily unavailable
  • open - Market accepting bets
  • closed - Market no longer accepting bets

4. Fight Cards (View-Only)

Read-only fight card display:

<FightCard fight={fight} />
 
// Compact version for lists
<FightCardCompact fight={fight} onClick={() => navigate(`/fights/${fight.id}`)} />

Elements displayed:

  • Fight number and weight class
  • Blue corner fighter (name, nickname, record)
  • Red corner fighter (name, nickname, record)
  • Scheduled rounds
  • Status badge
  • No edit controls (read-only)

5. Odds Display Components

Multiple components for odds visualization:

OddsMarketCard

Full market card with selections:

<OddsMarketCard market={market} />

Displays:

  • Market name and type
  • Open/Suspended/Closed status
  • All selections with odds
  • Movement indicators (↑ ↓)
  • Last updated timestamp

OddsDisplay

Grid layout for multiple markets:

<OddsDisplay markets={event.markets} fightId={selectedFightId} />

OddsRow

Compact blue vs red odds for tables:

<OddsRow
  blueCornerName="Max Holloway"
  redCornerName="Alexander Volkanovski"
  blueOdds={-150}
  redOdds={130}
  blueMovement="up"
  redMovement="down"
/>

OddsSelectionCard

Individual selection display:

<OddsSelectionCard
  selection={selection}
  isLocked={market.status === 'suspended'}
/>

Component Reference

Layout Components

ComponentLocationPurpose
LeagueSidebarcomponents/layout/league-sidebar.tsxCollapsible league navigation

UI Components

ComponentLocationPurpose
StatusBadgecomponents/ui/status-badge.tsxRead-only status indicators
FightCardcomponents/ui/fight-card.tsxFull fight card (view-only)
FightCardCompactcomponents/ui/fight-card.tsxCompact fight row
OddsMarketCardcomponents/ui/odds-card.tsxFull market display
OddsDisplaycomponents/ui/odds-card.tsxMulti-market grid
OddsRowcomponents/ui/odds-card.tsxCompact odds row
OddsSelectionCardcomponents/ui/odds-card.tsxSingle selection

Types

// src/types/event.ts
 
type Sport = 'mma' | 'jai_alai' | 'f1' | 'esports' | 'drone_racing' | 'arm_wrestling' | 'combat';
 
type EventStatus = 'live' | 'upcoming' | 'scheduled' | 'completed' | 'cancelled';
 
interface Fighter {
  id: string;
  name: string;
  nickname?: string;
  record?: string;
  country?: string;
}
 
interface Fight {
  id: string;
  event_id: string;
  fight_number: number;
  weight_class: WeightClass;
  scheduled_rounds: number;
  status: FightStatus;
  blue_corner?: Fighter;
  red_corner?: Fighter;
  result?: FightResult;
}
 
interface OddsMarket {
  id: string;
  type: string;           // 'moneyline', 'method_of_victory', etc.
  name: string;           // "Winner", "Method of Victory"
  status: 'open' | 'suspended' | 'closed';
  selections: OddsSelection[];
  last_updated: string;   // ISO timestamp
}
 
interface OddsSelection {
  id: string;
  name: string;           // "Max Holloway", "KO/TKO", "Over 2.5"
  odds: number;           // American odds: -150, +200
  implied_probability: number;
  movement?: 'up' | 'down' | 'none';
}
 
interface EventDetail {
  id: string;
  league_id: string;
  league_name: string;
  sport: Sport;
  name: string;
  venue?: string;
  location?: string;
  date: string;
  start_time?: string;
  status: EventStatus;
  broadcast?: string;
  fights: Fight[];
  markets?: OddsMarket[];
}

Design Patterns

Read-Only Visual Cues

Portal components are visually distinct from PRTL:

  1. No edit buttons - Fight cards don't show edit icons
  2. No toggle switches - Markets show status but can't be changed
  3. No input fields - Odds displayed as text, not inputs
  4. Locked indicators - Suspended markets show lock icon
// Locked market display
{market.status === 'suspended' && (
  <Lock className="h-4 w-4 text-muted-foreground" />
)}

Movement Indicators

Show odds changes without allowing edits:

function MovementIndicator({ movement }: { movement?: 'up' | 'down' | 'none' }) {
  if (!movement || movement === 'none') return null;
 
  if (movement === 'up') {
    return <TrendingUp className="h-3.5 w-3.5 text-green-500" />;
  }
  return <TrendingDown className="h-3.5 w-3.5 text-red-500" />;
}

Odds Formatting

American odds display utility:

function formatOdds(odds: number): string {
  if (odds >= 0) return `+${odds}`;
  return odds.toString();
}
 
// Colors
<span className={odds >= 0 ? 'text-green-600' : 'text-foreground'}>
  {formatOdds(odds)}
</span>

Status Color Scheme

StatusBackgroundTextDot
livebg-green-500/10text-green-600bg-green-500 animate-pulse
upcomingbg-blue-500/10text-blue-600bg-blue-500
completedbg-gray-500/10text-gray-500bg-gray-400
suspendedbg-yellow-500/10text-yellow-600bg-yellow-500
cancelledbg-red-500/10text-red-500bg-red-400

API Integration

Portal connects to read-only API endpoints:

// Read-only endpoints
GET /v1/portal/odds                    // List published odds
GET /v1/portal/odds/{marketId}         // Get market odds
GET /v1/portal/events                  // List events
GET /v1/portal/sports                  // List sports
GET /v1/portal/leagues                 // List leagues
GET /v1/portal/export/odds             // Export data (JSON/CSV)
 
// Webhook management (write)
POST /v1/portal/webhooks               // Create subscription
PUT  /v1/portal/webhooks/{id}          // Update subscription

Authentication

External clients authenticate via:

  • API Keys - For programmatic access
  • OAuth 2.0 - For third-party integrations
  • Rate limiting - Per client tier
  • IP whitelisting - Optional per-client

Real-Time Updates

Portal receives real-time updates via:

  1. WebSocket feed - Subscribe to topics
  2. Webhook delivery - Push notifications
// WebSocket subscription
ws.send(JSON.stringify({
  action: 'subscribe',
  topics: ['event:123', 'sport:MMA']
}));
 
// Receive updates
ws.onmessage = (event) => {
  const { type, data } = JSON.parse(event.data);
  if (type === 'odds_update') {
    updateOddsDisplay(data);
  }
};

Related Documentation

Platform

Documentation

Community

Support

partnership@altsportsdata.comdev@altsportsleagues.ai

2025 Β© AltSportsLeagues.ai. Powered by AI-driven sports business intelligence.

πŸ€– AI-Enhancedβ€’πŸ“Š Data-Drivenβ€’βš‘ Real-Time