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 · 1fb3f20d
The commit introduces an OwnerRoute component implementing access control based on user roles, enhancing security and user routing. It also adds menu items tailored by user roles and enhances the race-related modules with new UI elements and logic for handling positions and live URLs. The use of React lazy loading and hooks are applied appropriately. There is potential to improve validation on URL input fields and to ensure consistent and meaningful commit messages.
Quality
?
85%
Security
?
80%
Business Value
?
70%
Maintainability
?
88%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Vague And Non Descriptive
Where
commit message
Issue / Evidence
vague and non-descriptive
Suggested Fix
provide a more detailed and descriptive commit message for better traceability
Missing Validation
Where
src/modules/horse/pages/Race/CreateRaces.tsx:370-376
Issue / Evidence
Live URL input lacks validation
Suggested Fix
add thorough validation for the URL field to prevent invalid or malicious URLs
Security Issue
Where
src/components/OwnerRoute.tsx:14-27
Issue / Evidence
no explicit handling for unauthorized users beyond redirect
Suggested Fix
consider adding logging or error messages on authorization failure to aid debugging
Menu Items Hardcoded Without Permission Gr...
Where
src/components/sidebar/nav.tsx:48-67
Issue / Evidence
menu items hardcoded without permission granularity for OWNER
Suggested Fix
enhance permission checks to tailor menu items based on more granular permissions
Getpositionlabel Function Returns Position...
Where
src/modules/horse/pages/Race/RaceDetail.tsx:56-65
Issue / Evidence
getPositionLabel function returns position as string without suffixes
Suggested Fix
implement proper ordinal suffixes to improve user readability
Savingpositions State Usage Is Not Shown
Where
src/modules/horse/pages/Race/RaceDetail.tsx:164
Issue / Evidence
savingPositions state usage is not shown
Suggested Fix
ensure states used are justified and cleaned up if unused
Loading Ui Uses Spinner With Basic Accessi...
Where
src/components/OwnerRoute.tsx:16-23
Issue / Evidence
loading UI uses spinner with basic accessibility
Suggested Fix
improve spinner accessibility by adding ARIA attributes and ensuring screen reader friendliness
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/CreateRaces.tsx b/src/modules/horse/pages/Race/CreateRaces.tsx - index e660540..e04ff98 100644 - distance: string; - start_time: string; - status: boolean; - } - - const CreateRace: React.FC = () => { - race_name: "", - distance: "", - start_time: "", - status: true - }); - - // Load events for dropdown from API - race_name: race.race_name, - distance: race.distance, - start_time: formattedStartTime,
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/CreateRaces.tsx b/src/modules/horse/pages/Race/CreateRaces.tsx + index e660540..e04ff98 100644 + distance: string; + start_time: string; + status: boolean; + liveUrl: string; + } + + const CreateRace: React.FC = () => { + race_name: "", + distance: "", + start_time: "", + status: true, + liveUrl: "" + }); + + // Load events for dropdown from API + race_name: race.race_name,
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/modules/horse/pages/Race/stats.tsx b/src/modules/horse/pages/Race/stats.tsx - index f83e6ce..bd0ae64 100644 - const oddsType = (bet.oddsType || bet.odds_type || bet.betType || '-').toString().toUpperCase(); - return { - id: bet._id || bet.id, - username: bet.username || bet.user?.username || '-', - marketName: bet.marketName || bet.market_name || '-', - oddsType: oddsType, - <Table className={`align-middle ${styles.betsTable}`}> - <thead> - <tr className={styles.summaryHeader}> - <th className="border-0">Name</th> - <th className="border-0 text-center">Market Name</th> - <th className="border-0 text-center">Odds Type</th> - <th className="border-0 text-center">Odds Request</th> - <th className="border-0 text-center">Bet Amount</th> - </tr> - </thead>
Added / After Commit
+ diff --git a/src/modules/horse/pages/Race/stats.tsx b/src/modules/horse/pages/Race/stats.tsx + index f83e6ce..bd0ae64 100644 + const oddsType = (bet.oddsType || bet.odds_type || bet.betType || '-').toString().toUpperCase(); + return { + id: bet._id || bet.id, + tenantName: bet.tenantName || bet.tenant_name || bet.tenant?.name || bet.platformName || '-', + username: bet.username || bet.user?.username || '-', + marketName: bet.marketName || bet.market_name || '-', + oddsType: oddsType, + <Table className={`align-middle ${styles.betsTable}`}> + <thead> + <tr className={styles.summaryHeader}> + <th className="border-0">Tenant</th> + <th className="border-0">Name</th> + <th className="border-0 text-center">Odds Type</th> + <th className="border-0 text-center">Odds Value</th> + <th className="border-0 text-center">Bet Amount</th> + </tr>
Removed / Before Commit
- diff --git a/src/pages/Races/stats.tsx b/src/pages/Races/stats.tsx - index 6023f03..637c606 100644 - import React, { Fragment, useCallback, useEffect, useMemo, useState } from "react"; - import { Alert, Badge, Button, Card, Col, Row, Spinner, Table } from "react-bootstrap"; - import { useParams } from "react-router-dom"; - import { toast } from "react-toastify"; - import Pageheader from "../../components/pageheader/pageheader"; - type BetApiRow = { - _id?: string; - username?: string; - phone?: string | number; - market_name?: string; - bet_status?: string; - - type BetRow = { - id: string; - username: string; - marketName: string;
Added / After Commit
+ diff --git a/src/pages/Races/stats.tsx b/src/pages/Races/stats.tsx + index 6023f03..637c606 100644 + import React, { Fragment, useCallback, useEffect, useMemo, useState } from "react"; + import { Alert, Button, Card, Col, Row, Spinner, Table } from "react-bootstrap"; + import { useParams } from "react-router-dom"; + import { toast } from "react-toastify"; + import Pageheader from "../../components/pageheader/pageheader"; + type BetApiRow = { + _id?: string; + username?: string; + tenant_name?: string; + tenantName?: string; + phone?: string | number; + market_name?: string; + bet_status?: string; + + type BetRow = { + id: string;
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" },
Removed / Before Commit
- diff --git a/src/services/api/raceService.ts b/src/services/api/raceService.ts - index fa2f37c..2df6a4e 100644 - - export interface Race { - _id: string; - event_id: string | { _id: string; event_name: string }; // Can be populated - race_no: number; - race_name: string; - distance: string; - start_time: string; - status: boolean; - createdAt: string; - updatedAt?: string; - __v?: number; - distance: string; - start_time: string; - status: boolean; - }): Promise<RaceResponse> {
Added / After Commit
+ diff --git a/src/services/api/raceService.ts b/src/services/api/raceService.ts + index fa2f37c..2df6a4e 100644 + + export interface Race { + _id: string; + event_id: string | { _id: string; event_name: string }; + race_no: number; + race_name: string; + distance: string; + start_time: string; + status: boolean; + liveUrl?: string; + createdAt: string; + updatedAt?: string; + __v?: number; + distance: string; + start_time: string; + status: boolean;