AI Review Center
Commit Review Workspace ?
Select a commit on the left to inspect quality, security, business value, findings, and suggested code changes.
Project AI Score
?
71%
Quality Avg
?
72%
Security Avg
?
74%
Reviews
?
123
Review Result ?
solutionbowl/website · f8b88153
This commit adds UI enhancements and navigation logic for multi-race and country selection in a racing app, including color opacity utilities and state management. The code generally follows good conventions but lacks some comments and error handling which could affect robustness and maintainability.
Quality
?
85%
Security
?
60%
Business Value
?
70%
Maintainability
?
80%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Missing Validation
Where
src/components/layout/RacingNavMenu.tsx:12
Issue / Evidence
Lack of validation for color string format
Suggested Fix
add validation or sanitize inputs to avoid runtime errors
Possible Null Or Empty String Handling Wit...
Where
src/components/layout/RacingNavMenu.tsx:53-56
Issue / Evidence
Possible null or empty string handling with locationState and URL search params
Suggested Fix
add fallback handling and input validation to prevent errors
Long Function
Where
src/components/layout/RacingNavMenu.tsx:78-97
Issue / Evidence
Complex logic for setting initialCountryId lacks comments
Suggested Fix
add comments to improve readability and maintainability
Missing Checks If Countries Array Is Empty...
Where
src/components/layout/RacingNavMenu.tsx:118-125
Issue / Evidence
Missing checks if countries array is empty before accessing it
Suggested Fix
add guards to prevent potential runtime errors
Missing Validation
Where
src/components/layout/SelectedMultiRaceSidebarMenu.tsx:12
Issue / Evidence
Similar color function lacks input validation
Suggested Fix
add validation to maintain consistency and prevent potential bugs
Non Descriptive Commit Message
Where
commit message
Issue / Evidence
Non-descriptive commit message
Suggested Fix
improve commit message to clearly describe the changes and their purpose for better project history clarity
Code Change Preview · src/components/layout/Header.tsx
?
Removed / Before Commit
- diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx - index f354ac9..51e7303 100644 - return location.pathname === "/"; - } - - return location.pathname === path || location.pathname.startsWith(`${path}/`); - };
Added / After Commit
+ diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx + index f354ac9..51e7303 100644 + return location.pathname === "/"; + } + + if (path === "/horse-racing" && location.pathname === "/multi-race") { + return true; + } + + return location.pathname === path || location.pathname.startsWith(`${path}/`); + };
Removed / Before Commit
- diff --git a/src/components/layout/RacingNavMenu.tsx b/src/components/layout/RacingNavMenu.tsx - index b5da9a1..94691c1 100644 - const COUNTRY_FLAG_BASE_URL = - "https://whitelable-dev-bucket.s3.ap-south-1.amazonaws.com/countries/"; - - type RacingNavMenuVariant = "sidebar" | "header"; - - interface RacingNavMenuProps { - open: boolean; - variant: RacingNavMenuVariant; - }: RacingNavMenuProps) { - const colors = useThemeColors(); - const location = useLocation(); - const [countries, setCountries] = useState<Country[]>([]); - const [activeCountryId, setActiveCountryId] = useState(""); - const [raceEvents, setRaceEvents] = useState<RaceEvent[]>([]); - if (isCurrent) { - const safeCountries = Array.isArray(data) ? data : [];
Added / After Commit
+ diff --git a/src/components/layout/RacingNavMenu.tsx b/src/components/layout/RacingNavMenu.tsx + index b5da9a1..94691c1 100644 + const COUNTRY_FLAG_BASE_URL = + "https://whitelable-dev-bucket.s3.ap-south-1.amazonaws.com/countries/"; + + const withOpacity = (color: string, opacity: number) => { + if (!color.startsWith("#")) return color; + + const hex = color.slice(1); + const normalizedHex = + hex.length === 3 + ? hex + .split("") + .map((char) => `${char}${char}`) + .join("") + : hex; + + if (normalizedHex.length !== 6) return color;
Removed / Before Commit
- diff --git a/src/components/layout/SelectedMultiRaceSidebarMenu.tsx b/src/components/layout/SelectedMultiRaceSidebarMenu.tsx - new file mode 100644 - index 0000000..644e8af
Added / After Commit
+ diff --git a/src/components/layout/SelectedMultiRaceSidebarMenu.tsx b/src/components/layout/SelectedMultiRaceSidebarMenu.tsx + new file mode 100644 + index 0000000..644e8af + import { useEffect, useMemo, useState } from "react"; + import { Link, useLocation, useSearchParams } from "react-router-dom"; + import { getCountries, getRaceEvents } from "../../services/racing"; + import type { Country, RaceEvent } from "../../types/racing"; + import { formatRaceDateTime } from "../../utils/dateFormat"; + import { useThemeColors } from "../../hooks/useThemeColors"; + + const COUNTRY_FLAG_BASE_URL = + "https://whitelable-dev-bucket.s3.ap-south-1.amazonaws.com/countries/"; + + const withOpacity = (color: string, opacity: number) => { + if (!color.startsWith("#")) return color; + + const hex = color.slice(1); + const normalizedHex =
Removed / Before Commit
- diff --git a/src/components/layout/SelectedRaceSidebarMenu.tsx b/src/components/layout/SelectedRaceSidebarMenu.tsx - index 4ecf775..69367c8 100644 - const COUNTRY_FLAG_BASE_URL = - "https://whitelable-dev-bucket.s3.ap-south-1.amazonaws.com/countries/"; - - interface SelectedRaceSidebarMenuProps { - raceId: string; - onRaceClick?: () => void; - } - - return ( - <div className="space-y-[12px] pt-[8px]"> - {/* Country Header */} - <div - className="flex items-center gap-[12px] px-[12px] py-[8px] rounded-[6px]" - style={{ - backgroundColor: 'rgba(255, 255, 255, 0.05)', - borderLeft: `3px solid ${colors.primary}`
Added / After Commit
+ diff --git a/src/components/layout/SelectedRaceSidebarMenu.tsx b/src/components/layout/SelectedRaceSidebarMenu.tsx + index 4ecf775..69367c8 100644 + const COUNTRY_FLAG_BASE_URL = + "https://whitelable-dev-bucket.s3.ap-south-1.amazonaws.com/countries/"; + + const withOpacity = (color: string, opacity: number) => { + if (!color.startsWith("#")) return color; + + const hex = color.slice(1); + const normalizedHex = + hex.length === 3 + ? hex + .split("") + .map((char) => `${char}${char}`) + .join("") + : hex; + + if (normalizedHex.length !== 6) return color;
Removed / Before Commit
- diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx - index 71943ea..f74d745 100644 - import { useEffect, useMemo, useState } from "react"; - import RacingNavMenu from "./RacingNavMenu"; - import SelectedRaceSidebarMenu from "./SelectedRaceSidebarMenu"; - - const racingMenuItems = [ - { - name: "MultiRace", - icon: "/images/horses.png", - path: "/multi-race", - sportId: 3, - }, - { - name: "Horse Racing", - icon: "/images/horses.png", - location.pathname === "/multi-race" || - location.pathname.startsWith("/horse-racing");
Added / After Commit
+ diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx + index 71943ea..f74d745 100644 + import { useEffect, useMemo, useState } from "react"; + import RacingNavMenu from "./RacingNavMenu"; + import SelectedRaceSidebarMenu from "./SelectedRaceSidebarMenu"; + import SelectedMultiRaceSidebarMenu from "./SelectedMultiRaceSidebarMenu"; + + const racingMenuItems = [ + { + name: "Horse Racing", + icon: "/images/horses.png", + location.pathname === "/multi-race" || + location.pathname.startsWith("/horse-racing"); + const selectedRaceId = location.pathname.match(/^\/horse-racing\/([^/]+)/)?.[1] ?? null; + const isMultiRacePage = location.pathname === "/multi-race"; + const [isRacingMenuOpen, setIsRacingMenuOpen] = useState(isRacingRoute); + + useEffect(() => {
Removed / Before Commit
- diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx - index b3f5b36..552293d 100644 - </div> - <p style={{ color: colors.textPrimary }}>({matches.length})</p> - </div> - - <div className="flex gap-2 overflow-x-auto no-scrollbar mb-4"> - {allMatchesTabs.map((tab) => (
Added / After Commit
+ diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx + index b3f5b36..552293d 100644 + </div> + <p style={{ color: colors.textPrimary }}>({matches.length})</p> + </div> + + + <div className="flex gap-2 overflow-x-auto no-scrollbar mb-4"> + {allMatchesTabs.map((tab) => (
Removed / Before Commit
- diff --git a/src/pages/HorseRacing.tsx b/src/pages/HorseRacing.tsx - index 78d5aad..73ed066 100644 - </> - ) : ( - /* Multibet View */ - <MultiRaceDetail /> - )} - </div> - </div>
Added / After Commit
+ diff --git a/src/pages/HorseRacing.tsx b/src/pages/HorseRacing.tsx + index 78d5aad..73ed066 100644 + </> + ) : ( + /* Multibet View */ + <MultiRaceDetail countryId={activeCountry} /> + )} + </div> + </div>
Removed / Before Commit
- diff --git a/src/pages/HorseRacingDetails.tsx b/src/pages/HorseRacingDetails.tsx - index a38491f..2502968 100644 - ? minutes - : DEFAULT_BET_START_BEFORE_IN_MIN - } - - const filterMarketsBySettleFlags = (marketsData: Market[], raceData: Race | null) => { - if (!raceData) return marketsData
Added / After Commit
+ diff --git a/src/pages/HorseRacingDetails.tsx b/src/pages/HorseRacingDetails.tsx + index a38491f..2502968 100644 + ? minutes + : DEFAULT_BET_START_BEFORE_IN_MIN + } + const filterMarketsBySettleFlags = (marketsData: Market[], raceData: Race | null) => { + if (!raceData) return marketsData
Removed / Before Commit
- diff --git a/src/pages/MultiRaceDetail.tsx b/src/pages/MultiRaceDetail.tsx - index f4491b1..ddb5978 100644 - import { useCallback, useEffect, useMemo, useState } from "react" - import { - getMultiBetRaces, - placeMultiBet, - type MultiBetRace, - type PlaceMultiBetRequest, - } from "../services/racing" - // import { betService } from "../services/betService" - import { useThemeColors } from "../hooks/useThemeColors" - back_static_volume: number | null - silkColor: string - jersey?: string - } - - type Race = { - return first.race.id.localeCompare(second.race.id)
Added / After Commit
+ diff --git a/src/pages/MultiRaceDetail.tsx b/src/pages/MultiRaceDetail.tsx + index f4491b1..ddb5978 100644 + import { useCallback, useEffect, useMemo, useState } from "react" + import { useSearchParams, useLocation } from "react-router-dom" + import { + getMultiBetRaces, + getRaceExposure, + placeMultiBet, + type MultiBetRace, + type PlaceMultiBetRequest, + type ExposureData, + } from "../services/racing" + // import { betService } from "../services/betService" + import { useThemeColors } from "../hooks/useThemeColors" + back_static_volume: number | null + silkColor: string + jersey?: string + exposure?: number
Removed / Before Commit
- diff --git a/src/services/racing.ts b/src/services/racing.ts - index b52e12f..2e0e311 100644 - data?: unknown - } - - export const getMultiBetRaces = async (): Promise<MultiBetRacesResponse> => { - const response = await fetch(API_ENDPOINTS.racing.getMultiBetRaces, { - method: "GET", - headers: getApiHeaders(), - })
Added / After Commit
+ diff --git a/src/services/racing.ts b/src/services/racing.ts + index b52e12f..2e0e311 100644 + data?: unknown + } + + export const getMultiBetRaces = async (countryId?: string): Promise<MultiBetRacesResponse> => { + const countryQuery = countryId + ? `?country_id=${encodeURIComponent(countryId)}` + : "" + + const response = await fetch(`${API_ENDPOINTS.racing.getMultiBetRaces}${countryQuery}`, { + method: "GET", + headers: getApiHeaders(), + })