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
?
73%
Quality Avg
?
74%
Security Avg
?
74%
Reviews
?
130
Review Result ?
solutionbowl/crm-dashbaord · 862a23da
The commit merges a feature branch adding a ToteRacepage lazy-loaded route and extensive updates to market odds management with filtering and state propagation for betting markets. The added typing improves code quality, and UI toggles enhance functionality. However, there is some legacy code (commented import) and minor code style inconsistencies. Testing and validation for the new propagation logic are unclear, which may increase bug risk. The changes have high business value in expanding race and betting functionality but limited direct security implications. The commit message is generic and could be improved for clarity.
Quality
?
75%
Security
?
60%
Business Value
?
80%
Maintainability
?
68%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Commented Import
Where
src/main.tsx:17
Issue / Evidence
commented import
Suggested Fix
remove or clarify if necessary to avoid confusion and improve code cleanliness
Early Return When !Sourcemarket Or !Source...
Where
src/modules/horse/pages/Race/AdminRacepage.tsx:679
Issue / Evidence
early return when !sourceMarket or !sourceRunnerRow
Suggested Fix
add logging or error handling to improve observability and reduce silent failures
Propagation Condition For Withdrawn Status
Where
src/modules/horse/pages/Race/AdminRacepage.tsx:681
Issue / Evidence
propagation condition for withdrawn status
Suggested Fix
add unit tests to verify correctness and avoid bugs in betting logic
Use More Descriptive Commit Messages
Where
commit message
Issue / Evidence
use more descriptive commit messages
Suggested Fix
include summary of feature and key changes to improve traceability and business value understanding
Large Type Definitions And Imports
Where
src/modules/horse/pages/Race/ToteRacepage.tsx:1-65
Issue / Evidence
large type definitions and imports
Suggested Fix
consider splitting this file if it grows to improve maintainability
Code Change Preview · src/main.tsx
?
Removed / Before Commit
- diff --git a/src/main.tsx b/src/main.tsx - index 99c6728..45ff543 100644 - import AgentReport from './modules/horse/pages/Report/AgentReport.tsx'; - import BetButton from './modules/horse/pages/Report/BetButton.tsx'; - import BetButtonMarket from "./modules/horse/pages/Report/BetButtonMarket.tsx" - authService.initializeAuth(); - - const Loader = lazy(() => import('./components/loader/loader.tsx')); - const HorseAllPlatforms = lazy(() => import('./modules/horse/pages/Platform/AllPlatforms.tsx')); - const UpdateCountry = lazy(() => import('./modules/horse/pages/Platform/UpdateCountry.tsx')); - const AdminRacePage = lazy(() => import('./modules/horse/pages/Race/AdminRacepage.tsx')); - - createRoot(document.getElementById('root')!).render( - <Fragment> - <Route path="races/edit/:id" element={<CreateRace />} /> - <Route path="races/detail/:id" element={<RaceDetail />} /> - <Route path="races/admin/:raceId" element={<AdminRacePage />} /> - <Route path="races/stats/:id" element={<RaceStats />} />
Added / After Commit
+ diff --git a/src/main.tsx b/src/main.tsx + index 99c6728..45ff543 100644 + import AgentReport from './modules/horse/pages/Report/AgentReport.tsx'; + import BetButton from './modules/horse/pages/Report/BetButton.tsx'; + import BetButtonMarket from "./modules/horse/pages/Report/BetButtonMarket.tsx" + // import ToteRacePage from './modules/horse/pages/Race/ToteRacepage.tsx'; + authService.initializeAuth(); + + const Loader = lazy(() => import('./components/loader/loader.tsx')); + const HorseAllPlatforms = lazy(() => import('./modules/horse/pages/Platform/AllPlatforms.tsx')); + const UpdateCountry = lazy(() => import('./modules/horse/pages/Platform/UpdateCountry.tsx')); + const AdminRacePage = lazy(() => import('./modules/horse/pages/Race/AdminRacepage.tsx')); + const ToteRacepage = lazy(()=> import('./modules/horse/pages/Race/ToteRacepage.tsx')) + + createRoot(document.getElementById('root')!).render( + <Fragment> + <Route path="races/edit/:id" element={<CreateRace />} /> + <Route path="races/detail/:id" element={<RaceDetail />} />
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/AdminRacepage.tsx b/src/modules/horse/pages/Race/AdminRacepage.tsx - index 8429d30..3978f6a 100644 - import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; - - /* ── Types ───────────────────────────────────────────────────── */ - type OddsRow = { - runnerId?: string; - name?: string; - exposure?: number | null; - exposureProfit?: number | null; - back_percent?: number | null; - lay_percent?: number | null; - runner:{ - back_volume: number | null; - lay_volume: number | null; - odds: Array<OddsRow & { - exposure?: number | null; - exposureProfit?: number | null;
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/AdminRacepage.tsx b/src/modules/horse/pages/Race/AdminRacepage.tsx + index 8429d30..3978f6a 100644 + import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; + + /* ── Types ───────────────────────────────────────────────────── */ + + type OddsRow = { + runnerId?: string; + name?: string; + back_percent?: number | null; + lay_percent?: number | null; + runner:{ + back_volume: number | null; + lay_volume: number | null; + odds: Array<OddsRow & { + back_percent?: number | null; + lay_percent?: number | null; + }>;
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/AllRaces.tsx b/src/modules/horse/pages/Race/AllRaces.tsx - index 43c722e..56cd83e 100644 - const [searchTerm, setSearchTerm] = useState<string>(""); - const [events, setEvents] = useState<{ [key: string]: string }>({}); - - // Load events for mapping - const fetchEvents = async () => { - try { - const response = await eventService.getAllEvents(1, 100, ""); - setEvents(eventMap); - } - } catch (error) { - // Silently fail - events are optional for display - } - }; - - // Fetch races data from API - const fetchRaces = async () => {
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/AllRaces.tsx b/src/modules/horse/pages/Race/AllRaces.tsx + index 43c722e..56cd83e 100644 + const [searchTerm, setSearchTerm] = useState<string>(""); + const [events, setEvents] = useState<{ [key: string]: string }>({}); + + const fetchEvents = async () => { + try { + const response = await eventService.getAllEvents(1, 100, ""); + setEvents(eventMap); + } + } catch (error) { + + } + }; + + const fetchRaces = async () => { + try { + setLoading(true);
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/CreateRaces.tsx b/src/modules/horse/pages/Race/CreateRaces.tsx - index e04ff98..6aa88a0 100644 - race_name: string; - distance: string; - start_time: string; - status: boolean; - liveUrl: string; - } - race_name: "", - distance: "", - start_time: "", - status: true, - liveUrl: "" - }); - race_name: race.race_name, - distance: race.distance, - start_time: formattedStartTime, - status: race.status,
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/CreateRaces.tsx b/src/modules/horse/pages/Race/CreateRaces.tsx + index e04ff98..6aa88a0 100644 + race_name: string; + distance: string; + start_time: string; + raceType: string; + status: boolean; + liveUrl: string; + } + race_name: "", + distance: "", + start_time: "", + raceType: "", + status: true, + liveUrl: "" + }); + race_name: race.race_name, + distance: race.distance,
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/RaceDetail.tsx b/src/modules/horse/pages/Race/RaceDetail.tsx - index 4caeff5..f4e0d7f 100644 - interface RaceDetailData { - race: { - _id: string; - race_no: number; - race_name: string; - distance: string;
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/RaceDetail.tsx b/src/modules/horse/pages/Race/RaceDetail.tsx + index 4caeff5..f4e0d7f 100644 + interface RaceDetailData { + race: { + _id: string; + + race_no: number; + race_name: string; + distance: string;
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/stats.tsx b/src/modules/horse/pages/Race/stats.tsx - index 2a5b056..b4f9464 100644 - type OddsRow = { - runnerId?: string; - runner: Runner; - exposure: number; - exposureProfit: number; - back_static_volume: number | null; - lay_static_volume: number | null; - back_volume: number | null; - odds: OddsRow[]; - }; - - const toNullableNumber = (value: string | number | null | undefined): number | null => { - if (value === "" || value === null || value === undefined) return null; - const parsed = typeof value === "number" ? value : Number(value); - - const getRunnerGateNo = (runner?: Runner) =>
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/stats.tsx b/src/modules/horse/pages/Race/stats.tsx + index 2a5b056..b4f9464 100644 + type OddsRow = { + runnerId?: string; + runner: Runner; + exposure?: number; + exposureProfit?: number; + back_static_volume: number | null; + lay_static_volume: number | null; + back_volume: number | null; + odds: OddsRow[]; + }; + + type ExposureRow = { + marketId?: string | number; + market_id?: string | number; + runnerId?: string | number; + runner_id?: string | number;
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/ToteRacepage.tsx b/src/modules/horse/pages/Race/ToteRacepage.tsx - new file mode 100644 - index 0000000..86f44bc
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/ToteRacepage.tsx b/src/modules/horse/pages/Race/ToteRacepage.tsx + new file mode 100644 + index 0000000..86f44bc + import React, { useState, useEffect, Fragment, useCallback, useMemo } from "react"; + import { toast } from "react-toastify"; + import { useParams } from "react-router-dom"; + import Pageheader from "../../components/pageheader/pageheader"; + + import { tenantServiceInstance as axiosInstance } from "../../../../services/api/axiosConfig"; + import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; + + + /* ── Types ───────────────────────────────────────────────────── */ + type OddsRow = { + runnerId?: string; + name?: string; + back_percent?: number | null; + lay_percent?: number | null;
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Report/BetButton.tsx b/src/modules/horse/pages/Report/BetButton.tsx - index 5e17cb9..952e4a9 100644 - import { Fragment, useState, useEffect } from "react"; - import { Card, Col, Row } from "react-bootstrap"; - import { useSearchParams, useNavigate } from "react-router-dom"; - import Pageheader from "../../components/pageheader/pageheader"; - const [loading, setLoading] = useState(false); - const [error, setError] = useState<string | null>(null); - const [currentPage, setCurrentPage] = useState(1); - - useEffect(() => { - if (raceId && tenantId) { - } else { - setError("Race ID or Tenant ID is missing"); - } - }, [raceId, tenantId, currentPage]); - - const fetchBets = async () => {
Added / After Commit
+ diff --git a/src/modules/horse/pages/Report/BetButton.tsx b/src/modules/horse/pages/Report/BetButton.tsx + index 5e17cb9..952e4a9 100644 + import { Fragment, useState, useEffect, type ChangeEvent } from "react"; + import { Card, Col, Row } from "react-bootstrap"; + import { useSearchParams, useNavigate } from "react-router-dom"; + import Pageheader from "../../components/pageheader/pageheader"; + const [loading, setLoading] = useState(false); + const [error, setError] = useState<string | null>(null); + const [currentPage, setCurrentPage] = useState(1); + const [rowsPerPage, setRowsPerPage] = useState(10); + + useEffect(() => { + if (raceId && tenantId) { + } else { + setError("Race ID or Tenant ID is missing"); + } + }, [raceId, tenantId, currentPage, rowsPerPage]); +
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Report/BetButtonMarket.tsx b/src/modules/horse/pages/Report/BetButtonMarket.tsx - index 5715c12..dc0ebae 100644 - import { Fragment, useState, useEffect } from "react"; - import { Card, Col, Row } from "react-bootstrap"; - import { useSearchParams, useNavigate } from "react-router-dom"; - import Pageheader from "../../components/pageheader/pageheader"; - const [loading, setLoading] = useState(false); - const [error, setError] = useState<string | null>(null); - const [currentPage, setCurrentPage] = useState(1); - - useEffect(() => { - if (raceId && marketId) { - } else { - setError("Race ID or market ID is missing"); - } - }, [raceId, marketId, currentPage]); - - const fetchBets = async () => {
Added / After Commit
+ diff --git a/src/modules/horse/pages/Report/BetButtonMarket.tsx b/src/modules/horse/pages/Report/BetButtonMarket.tsx + index 5715c12..dc0ebae 100644 + import { Fragment, useState, useEffect, type ChangeEvent } from "react"; + import { Card, Col, Row } from "react-bootstrap"; + import { useSearchParams, useNavigate } from "react-router-dom"; + import Pageheader from "../../components/pageheader/pageheader"; + const [loading, setLoading] = useState(false); + const [error, setError] = useState<string | null>(null); + const [currentPage, setCurrentPage] = useState(1); + const [rowsPerPage, setRowsPerPage] = useState(10); + + useEffect(() => { + if (raceId && marketId) { + } else { + setError("Race ID or market ID is missing"); + } + }, [raceId, marketId, currentPage, rowsPerPage]); +
Removed / Before Commit
- diff --git a/src/modules/horse/styles/horsespages.css b/src/modules/horse/styles/horsespages.css - index d296dd4..4e35458 100644 - font-weight: 700; - } - - @media (max-width: 1199.98px) { - .horse-report-table { - overflow-x: auto; - width: 100%; - flex-direction: column; - } - }
Added / After Commit
+ diff --git a/src/modules/horse/styles/horsespages.css b/src/modules/horse/styles/horsespages.css + index d296dd4..4e35458 100644 + font-weight: 700; + } + + .horse-report-pagination { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 1.5rem; + margin-top: 1.25rem; + color: #6b7280; + font-size: 0.85rem; + flex-wrap: wrap; + } + + .horse-report-pagination__rows, + .horse-report-pagination__actions {
Removed / Before Commit
- diff --git a/src/pages/Platforms/AdminMarketPage.tsx b/src/pages/Platforms/AdminMarketPage.tsx - index b380df5..ab0b2d2 100644 - type OddsRow = { - runnerId?: string; - name?: string; - exposure?: number | null; - exposureProfit?: number | null; - back_percent?: number | null; - lay_percent?: number | null; - runner:{ - back_volume: number | null; - lay_volume: number | null; - odds: Array<OddsRow & { - exposure?: number | null; - exposureProfit?: number | null; - back_percent?: number | null; - lay_percent?: number | null; - }>;
Added / After Commit
+ diff --git a/src/pages/Platforms/AdminMarketPage.tsx b/src/pages/Platforms/AdminMarketPage.tsx + index b380df5..ab0b2d2 100644 + type OddsRow = { + runnerId?: string; + name?: string; + back_percent?: number | null; + lay_percent?: number | null; + runner:{ + back_volume: number | null; + lay_volume: number | null; + odds: Array<OddsRow & { + back_percent?: number | null; + lay_percent?: number | null; + }>; + const buildGlobalStateMap = (marketList: Market[]) => { + const next: Record<string, GlobalState> = {}; + marketList.forEach((market) => { + const nonWithdrawnOdds = market.odds.filter((oddsRow) => !oddsRow.withdrawn);
Removed / Before Commit
- diff --git a/src/pages/Races/stats.tsx b/src/pages/Races/stats.tsx - index 8540f94..3d3f4f2 100644 - type OddsRow = { - runnerId?: string; - runner: Runner; - exposure: number; - exposureProfit: number; - back_static_volume: number | null; - lay_static_volume: number | null; - back_volume: number | null; - odds: OddsRow[]; - }; - - type BetApiRow = { - _id?: string; - username?: string; - ...oddsRow, - runnerId: String(oddsRow?.runnerId ?? oddsRow?.runner?.runnerId ?? oddsRow?.selection?.runnerId ?? "") || undefined,
Added / After Commit
+ diff --git a/src/pages/Races/stats.tsx b/src/pages/Races/stats.tsx + index 8540f94..3d3f4f2 100644 + type OddsRow = { + runnerId?: string; + runner: Runner; + exposure?: number; + exposureProfit?: number; + back_static_volume: number | null; + lay_static_volume: number | null; + back_volume: number | null; + odds: OddsRow[]; + }; + + type ExposureRow = { + marketId?: string | number; + market_id?: string | number; + runnerId?: string | number; + runner_id?: string | number;
Removed / Before Commit
- diff --git a/src/services/api/raceService.ts b/src/services/api/raceService.ts - index 2df6a4e..0fbecef 100644 - race_name: string; - distance: string; - start_time: string; - status: boolean; - liveUrl?: string; - createdAt: string; - race_name: string; - distance: string; - start_time: string; - status: boolean; - liveUrl?: string; - }): Promise<RaceResponse> { - race_name: string; - distance: string; - start_time: string; - status: boolean;
Added / After Commit
+ diff --git a/src/services/api/raceService.ts b/src/services/api/raceService.ts + index 2df6a4e..0fbecef 100644 + race_name: string; + distance: string; + start_time: string; + raceType?: string; + status: boolean; + liveUrl?: string; + createdAt: string; + race_name: string; + distance: string; + start_time: string; + raceType?: string; + status: boolean; + liveUrl?: string; + }): Promise<RaceResponse> { + race_name: string; + distance: string;