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 · 773393a4
This commit integrates settle and position APIs into the horse race detail page and navigation components. It adds role-based menu items for the OWNER role, protects OwnerRoute based on user roles, and implements detailed position handling functions for race horses. It facilitates position normalization, validation, and selection with proper UI feedback like spinners and toasts.
Quality
?
85%
Security
?
80%
Business Value
?
90%
Maintainability
?
83%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Getpositionlabel Returns Position As A Str...
Where
src/modules/horse/pages/Race/RaceDetail.tsx:56
Issue / Evidence
getPositionLabel returns position as a string without ordinal suffixes (e.g., '1st', '2nd')
Suggested Fix
add proper ordinal suffixes to improve UX and clarity
Normalizepositiondisplay Uses Many Positio...
Where
src/modules/horse/pages/Race/RaceDetail.tsx:86
Issue / Evidence
normalizePositionDisplay uses many position property variants, which can lead to inconsistent data
Suggested Fix
unify backend data shape to reduce complexity and prevent bugs
Getsettlementcandidate Returns The First S...
Where
src/modules/horse/pages/Race/RaceDetail.tsx:131
Issue / Evidence
getSettlementCandidate returns the first sorted candidate by position, but does not handle ties or invalid positions explicitly
Suggested Fix
add explicit error handling and manage tie cases to reduce potential bugs
Missing Validation
Where
src/modules/horse/pages/Race/RaceDetail.tsx:486
Issue / Evidence
handlePositionSelect does not sanitize or validate input beyond numeric check
Suggested Fix
add robust input sanitization to mitigate injection or UI bugs
Ownerroute Only Checks Userrole === 'Owner...
Where
src/components/OwnerRoute.tsx:26
Issue / Evidence
OwnerRoute only checks userRole === 'OWNER'
Suggested Fix
consider supporting multiple roles or more granular permission checks to enhance flexibility and security
Message Is Brief And Not Descriptive
Where
commit message
Issue / Evidence
message is brief and not descriptive
Suggested Fix
improve commit message to describe specific integrations and changes for better traceability
Code Change Preview · src/components/OwnerRoute.tsx
?
Removed / Before Commit
- diff --git a/src/components/OwnerRoute.tsx b/src/components/OwnerRoute.tsx - new file mode 100644 - index 0000000..dc8c7a2
Added / After Commit
+ diff --git a/src/components/OwnerRoute.tsx b/src/components/OwnerRoute.tsx + new file mode 100644 + index 0000000..dc8c7a2 + import React from "react"; + import { Navigate } from "react-router-dom"; + import { useAuth } from "../hooks/useAuth"; + + interface OwnerRouteProps { + children: React.ReactNode; + redirectTo?: string; + } + + const OwnerRoute: React.FC<OwnerRouteProps> = ({ + children, + redirectTo = "/dashboard", + }) => { + const { userRole, loading } = useAuth(); +
Removed / Before Commit
- diff --git a/src/components/sidebar/nav.tsx b/src/components/sidebar/nav.tsx - index 332243b..ffc6a15 100644 - - const Usersicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="128" cy="96" r="64" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><path d="M30.989,215.99064a112.03731,112.03731,0,0,1,194.02311.002" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/></svg> - - const Bannersicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="32" y="48" width="192" height="160" rx="8" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><line x1="32" y1="112" x2="224" y2="112" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><circle cx="68" cy="80" r="12"/><circle cx="108" cy="80" r="12"/></svg> - - const Racesicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M48 184h160" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><path d="M72 184V88l56-32 56 32v96" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><path d="M100 184v-40h56v40" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/></svg> - - const Punchingicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="32" y="48" width="192" height="160" rx="8" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><line x1="96" y1="48" x2="96" y2="208" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><line x1="32" y1="128" x2="96" y2="128" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/></svg> - - const link = (path: string, title: string) => ({ - path: `${import.meta.env.BASE_URL}${path}`, - - const punchingItem = linkIcon("punching", "Punching", Punchingicon); - - export const getMenuItemsByRole = (userRole: string | null, permissions: string[] = []): any[] => { -
Added / After Commit
+ diff --git a/src/components/sidebar/nav.tsx b/src/components/sidebar/nav.tsx + index 332243b..ffc6a15 100644 + + const Usersicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="128" cy="96" r="64" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><path d="M30.989,215.99064a112.03731,112.03731,0,0,1,194.02311.002" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/></svg> + + const Bannersicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="32" y="48" width="192" height="160" rx="8" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><line x1="32" y1="112" x2="224" y2="112" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><circle cx="68" cy="80" r="12"/><circle cx="108" cy="80" r="12"/></svg> + + const Racesicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M48 184h160" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><path d="M72 184V88l56-32 56 32v96" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><path d="M100 184v-40h56v40" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/></svg> + + const Punchingicon = <svg xmlns="http://www.w3.org/2000/svg" className="side-menu__icon" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="32" y="48" width="192" height="160" rx="8" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><line x1="96" y1="48" x2="96" y2="208" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/><line x1="32" y1="128" x2="96" y2="128" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="16"/></svg> + + const link = (path: string, title: string) => ({ + path: `${import.meta.env.BASE_URL}${path}`, + + const punchingItem = linkIcon("punching", "Punching", Punchingicon); + + export const getMenuItemsByRole = (userRole: string | null, permissions: string[] = []): any[] => { +
Removed / Before Commit
- diff --git a/src/main.tsx b/src/main.tsx - index 15d3268..1eecd60 100644 - const CreateUser = lazy(() => import('./pages/Users/CreateUser.tsx')); - const Userdetail = lazy(() => import('./pages/Users/Userdetail.tsx')); - const AllBanners = lazy(() => import('./pages/Banners/AllBanners.tsx')); - - const CreateBanner = lazy(() => import('./pages/Banners/CreateBanner.tsx')); - const MainAllRaces = lazy(() => import('./pages/Races/AllRaces.tsx')); - <Route path={`${import.meta.env.BASE_URL}users/create`} element={<CreateUser />} /> - <Route path={`${import.meta.env.BASE_URL}users/detail/:id`} element={<Userdetail />} /> - <Route path={`${import.meta.env.BASE_URL}banners`} element={<AllBanners />} /> - <Route path={`${import.meta.env.BASE_URL}banners/create`} element={<CreateBanner />} /> - <Route path={`${import.meta.env.BASE_URL}banners/edit/:id`} element={<CreateBanner />} /> - <Route path={`${import.meta.env.BASE_URL}races`} element={<MainAllRaces />} /> - <Route path={`${import.meta.env.BASE_URL}races/stats/:id`} element={<MainRaceStats />} /> - <Route path={`${import.meta.env.BASE_URL}platform-users`} element={<AllPlatformUsers />} /> - <Route path={`${import.meta.env.BASE_URL}platform-users/create`} element={<CreatePlatformUser />} />
Added / After Commit
+ diff --git a/src/main.tsx b/src/main.tsx + index 15d3268..1eecd60 100644 + const CreateUser = lazy(() => import('./pages/Users/CreateUser.tsx')); + const Userdetail = lazy(() => import('./pages/Users/Userdetail.tsx')); + const AllBanners = lazy(() => import('./pages/Banners/AllBanners.tsx')); + const AllSport = lazy(() => import('./pages/Sports/AllSport.tsx')); + + const CreateBanner = lazy(() => import('./pages/Banners/CreateBanner.tsx')); + const MainAllRaces = lazy(() => import('./pages/Races/AllRaces.tsx')); + <Route path={`${import.meta.env.BASE_URL}users/create`} element={<CreateUser />} /> + <Route path={`${import.meta.env.BASE_URL}users/detail/:id`} element={<Userdetail />} /> + <Route path={`${import.meta.env.BASE_URL}banners`} element={<AllBanners />} /> + + <Route path={`${import.meta.env.BASE_URL}banners/create`} element={<CreateBanner />} /> + <Route path={`${import.meta.env.BASE_URL}banners/edit/:id`} element={<CreateBanner />} /> + <Route path={`${import.meta.env.BASE_URL}races`} element={<MainAllRaces />} /> + <Route path={`${import.meta.env.BASE_URL}sports`} element={<AllSport />} /> + <Route path={`${import.meta.env.BASE_URL}races/stats/:id`} element={<MainRaceStats />} />
Removed / Before Commit
- diff --git a/src/modules/horse/pages/Race/RaceDetail.tsx b/src/modules/horse/pages/Race/RaceDetail.tsx - index 55c59a7..a12abef 100644 - import React, { Fragment, useState, useEffect } from "react"; - import { Card, Col, Row, Spinner, Badge, Modal, Form, Button } from "react-bootstrap"; - import Pageheader from "../../components/pageheader/pageheader"; - import { useNavigate, useParams, useLocation } from "react-router-dom"; - import { toast } from "react-toastify"; - jockey: string; - trainer: string; - status: boolean; - odds: { - back_odds: number; - lay_odds: number; - }>; - } - - const runnerTableHeadCell: React.CSSProperties = { - textAlign: "center",
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/RaceDetail.tsx b/src/modules/horse/pages/Race/RaceDetail.tsx + index 55c59a7..a12abef 100644 + import React, { Fragment, useState, useEffect } from "react"; + import { Card, Col, Row, Spinner, Badge, Modal, Form, Button, Dropdown } from "react-bootstrap"; + import Pageheader from "../../components/pageheader/pageheader"; + import { useNavigate, useParams, useLocation } from "react-router-dom"; + import { toast } from "react-toastify"; + jockey: string; + trainer: string; + status: boolean; + position?: string; + position_value?: string | number; + saved_position?: string | number; + horse_position?: string | number; + finishing_position?: string | number; + finishingPosition?: string | number; + finish_position?: string | number; + result_position?: string | number;
Removed / Before Commit
- diff --git a/src/pages/Sports/AllSport.tsx b/src/pages/Sports/AllSport.tsx - new file mode 100644 - index 0000000..d60329a
Added / After Commit
+ diff --git a/src/pages/Sports/AllSport.tsx b/src/pages/Sports/AllSport.tsx + new file mode 100644 + index 0000000..d60329a + import { Fragment, useState } from "react"; + import { Card, Col, Row, Badge, Spinner, Button, Form, Modal } from "react-bootstrap"; + import Pageheader from "../../components/pageheader/pageheader"; + import DataTable from "react-data-table-component"; + + type Sport = { + sportsId: number; + sportsName: string; + eventName: string; + status: string; + createdAt: string; + }; + + const data: Sport[] = [ + { sportsId: 1, sportsName: "Cricket", eventName: "IPL 2026", status: "ACTIVE", createdAt: "2026-04-01" },