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 · c0d3d11f
This commit adds a withdraw runner from race API integration and implements the corresponding UI updates in three components. The implementation issues API calls correctly and handles basic error feedback via toast notifications. Code reuse is improved with a helper function to get runner ID. However, error handling could be more thorough; the security of the API endpoint URL and token management is unclear. The commit message is not descriptive enough, decreasing confidence, and there's some code duplication across three similar components.
Quality
?
85%
Security
?
60%
Business Value
?
80%
Maintainability
?
83%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Vague Message
Where
commit message
Issue / Evidence
vague message
Suggested Fix
improve commit message describing the feature and changes made
Large Function
Where
src/modules/horse/pages/Race/AdminRacepage.tsx:676
Issue / Evidence
large function
Suggested Fix
refactor updateRunnerToggle for better readability and single responsibility
Duplicate Logic
Where
src/modules/horse/pages/Race/ToteRacepage.tsx:674
Issue / Evidence
duplicated logic
Suggested Fix
extract shared withdrawal handling into a common hook or utility to reduce duplication
Duplicate Logic
Where
src/pages/Platforms/AdminMarketPage.tsx:713
Issue / Evidence
duplicated logic
Suggested Fix
same as above for AdminMarketPage.tsx
Hardcoded Endpoint Url
Where
src/services/api/runnerWithdrawalService.ts:3
Issue / Evidence
hardcoded endpoint URL
Suggested Fix
move endpoint URL to environment variables or config to improve security and flexibility
No Error Handling On Api Call
Where
src/services/api/runnerWithdrawalService.ts:10
Issue / Evidence
no error handling on API call
Suggested Fix
consider wrapping API call to handle network errors and return consistent error info
Code Change Preview · src/modules/horse/pages/Race/AdminRacepage.tsx
?
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/AdminRacepage.tsx b/src/modules/horse/pages/Race/AdminRacepage.tsx - index 3978f6a..9cb6a44 100644 - import Pageheader from "../../components/pageheader/pageheader"; - - import { tenantServiceInstance as axiosInstance } from "../../../../services/api/axiosConfig"; - import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; - - /* ── Types ───────────────────────────────────────────────────── */ - }; - - const getRaceMarketsOddsEndpoint = (raceId: string) => `horse-racing/races/${raceId}/markets/odds`; - const hasOwn = <T extends object>(obj: T, key: PropertyKey): key is keyof T => Object.prototype.hasOwnProperty.call(obj, key); - - const buildGlobalStateMap = (marketList: Market[]) => { - runner?.gateNo ?? - null; - - const normalizeMarketType = (marketType?: string) => String(marketType ?? "").trim().toUpperCase();
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/AdminRacepage.tsx b/src/modules/horse/pages/Race/AdminRacepage.tsx + index 3978f6a..9cb6a44 100644 + import Pageheader from "../../components/pageheader/pageheader"; + + import { tenantServiceInstance as axiosInstance } from "../../../../services/api/axiosConfig"; + import { withdrawRunnerFromRace } from "../../../../services/api/runnerWithdrawalService"; + import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; + + /* ── Types ───────────────────────────────────────────────────── */ + }; + + const getRaceMarketsOddsEndpoint = (raceId: string) => `horse-racing/races/${raceId}/markets/odds`; + + const hasOwn = <T extends object>(obj: T, key: PropertyKey): key is keyof T => Object.prototype.hasOwnProperty.call(obj, key); + + const buildGlobalStateMap = (marketList: Market[]) => { + runner?.gateNo ?? + null;
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/ToteRacepage.tsx b/src/modules/horse/pages/Race/ToteRacepage.tsx - index 86f44bc..5dc7143 100644 - import Pageheader from "../../components/pageheader/pageheader"; - - import { tenantServiceInstance as axiosInstance } from "../../../../services/api/axiosConfig"; - import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; - - - runner?.gateNo ?? - null; - - const normalizeMarketType = (marketType?: string) => String(marketType ?? "").trim().toUpperCase(); - const isWinnerMarketType = (marketType?: string, marketName?: string) => { - const normalizedType = normalizeMarketType(marketType); - marketId: string; runnerKey: string; runnerName: string; - } | null>(null); - - const updateRunnerToggle = useCallback(async ( marketId: string,
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/ToteRacepage.tsx b/src/modules/horse/pages/Race/ToteRacepage.tsx + index 86f44bc..5dc7143 100644 + import Pageheader from "../../components/pageheader/pageheader"; + + import { tenantServiceInstance as axiosInstance } from "../../../../services/api/axiosConfig"; + import { withdrawRunnerFromRace } from "../../../../services/api/runnerWithdrawalService"; + import useRaceOddsSocket from "../../hooks/useRaceOddsSocket"; + + + runner?.gateNo ?? + null; + + const getOddsRowRunnerId = (oddsRow?: OddsRow) => + String(oddsRow?.runnerId ?? oddsRow?.runner?.runnerId ?? "").trim(); + + const normalizeMarketType = (marketType?: string) => String(marketType ?? "").trim().toUpperCase(); + const isWinnerMarketType = (marketType?: string, marketName?: string) => { + const normalizedType = normalizeMarketType(marketType);
Removed / Before Commit
- diff --git a/src/pages/Platforms/AdminMarketPage.tsx b/src/pages/Platforms/AdminMarketPage.tsx - index ab0b2d2..1e4097f 100644 - import { useParams } from "react-router-dom"; - import Pageheader from "../../modules/horse/components/pageheader/pageheader"; - import { tenantServiceInstance as axiosInstance } from "../../services/api/axiosConfig"; - import useRaceOddsSocket from "../../modules/horse/hooks/useRaceOddsSocket"; - - /* ── Types ───────────────────────────────────────────────────── */ - runner?.gateNo ?? - null; - - const normalizeMarketType = (marketType?: string) => String(marketType ?? "").trim().toUpperCase(); - const isWinnerMarketType = (marketType?: string, marketName?: string) => { - const normalizedType = normalizeMarketType(marketType); - marketId: string; runnerKey: string; runnerName: string; - } | null>(null); - - const updateRunnerToggle = useCallback(async ( marketId: string,
Added / After Commit
+ diff --git a/src/pages/Platforms/AdminMarketPage.tsx b/src/pages/Platforms/AdminMarketPage.tsx + index ab0b2d2..1e4097f 100644 + import { useParams } from "react-router-dom"; + import Pageheader from "../../modules/horse/components/pageheader/pageheader"; + import { tenantServiceInstance as axiosInstance } from "../../services/api/axiosConfig"; + import { withdrawRunnerFromRace } from "../../services/api/runnerWithdrawalService"; + import useRaceOddsSocket from "../../modules/horse/hooks/useRaceOddsSocket"; + + /* ── Types ───────────────────────────────────────────────────── */ + runner?.gateNo ?? + null; + + const getOddsRowRunnerId = (oddsRow?: OddsRow) => + String(oddsRow?.runnerId ?? oddsRow?.runner?.runnerId ?? "").trim(); + + const normalizeMarketType = (marketType?: string) => String(marketType ?? "").trim().toUpperCase(); + const isWinnerMarketType = (marketType?: string, marketName?: string) => { + const normalizedType = normalizeMarketType(marketType);
Removed / Before Commit
- diff --git a/src/services/api/runnerWithdrawalService.ts b/src/services/api/runnerWithdrawalService.ts - new file mode 100644 - index 0000000..8540043
Added / After Commit
+ diff --git a/src/services/api/runnerWithdrawalService.ts b/src/services/api/runnerWithdrawalService.ts + new file mode 100644 + index 0000000..8540043 + import { tenantServiceInstance as axiosInstance } from "./axiosConfig"; + + const RUNNER_WITHDRAWAL_ENDPOINT = "https://api.digitalbowls.com/tenant/api/test/runnerWithdrawal"; + + export type RunnerWithdrawalPayload = { + race_id: string; + runner_id: string; + }; + + export const withdrawRunnerFromRace = (payload: RunnerWithdrawalPayload) => + axiosInstance.post(RUNNER_WITHDRAWAL_ENDPOINT, payload);