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 · bdd8782d
The commit adds a feature to detect if the user is logged in on multiple tabs and triggers a logout modal to prevent concurrent sessions, improving user session integrity. The implementation includes UI components and hooks to manage this condition, and integrates with authentication state. While enhancing session management and user experience, the commit could benefit from clearer commit messages and more defensive error handling.
Quality
?
75%
Security
?
70%
Business Value
?
85%
Maintainability
?
73%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Vague And Not Descriptive
Where
commit message
Issue / Evidence
vague and not descriptive
Suggested Fix
write a more detailed and descriptive commit message explaining the feature and purpose
Useeffect Runs Once On Mount But Lacks Cle...
Where
src/App.tsx:27
Issue / Evidence
useEffect runs once on mount but lacks cleanup or event listener for tab status changes
Suggested Fix
consider adding cleanup or listen for storage events to update modal dynamically
Setting Login State And Localstorage Indep...
Where
src/components/auth/LoginForm.tsx:97
Issue / Evidence
setting login state and localStorage independently
Suggested Fix
abstract into a single function to reduce duplication and risk of inconsistent state
Use Of Window.location.href For Navigation
Where
src/components/auth/LoginForm.tsx:105
Issue / Evidence
use of window.location.href for navigation
Suggested Fix
prefer react router navigation methods to keep SPA behavior consistent
Singletablogout Call Without Error Handlin...
Where
src/contexts/AuthContext.tsx:246
Issue / Evidence
singleTabLogout call without error handling
Suggested Fix
add try-catch or error management to improve robustness
Hardcoded Color Styles Mixed With Theme Co...
Where
src/components/common/SingleTabModal.tsx:14
Issue / Evidence
hardcoded color styles mixed with theme colors
Suggested Fix
unify to use theme colors for better maintainability
Long Function
Where
src/components/common/SingleTabModal.tsx:41
Issue / Evidence
long message text directly in JSX
Suggested Fix
consider moving text to constants or localization files
Use Of Window.location.replace('/') To Log...
Where
src/App.tsx:36
Issue / Evidence
use of window.location.replace('/') to logout
Suggested Fix
validate if this properly clears user state and tokens or if additional cleanup needed for security
Code Change Preview · src/App.tsx
?
Removed / Before Commit
- diff --git a/src/App.tsx b/src/App.tsx - index 99ecb9d..b1baed8 100644 - import SportsDetailPage from "./pages/SportsDetailPage"; - import LiveCasinoPage from "./pages/LiveCasinoPage"; - import TransactionPage from "./pages/Transaction"; - - function App() { - const { isLoading, tenant, isSuspended } = useConfig(); - - if (isLoading) return <GlobalLoader />; - - } - - return ( - <BrowserRouter> - <Routes> - {/* Auth Routes */} - <Route path="/login" element={<Login />} />
Added / After Commit
+ diff --git a/src/App.tsx b/src/App.tsx + index 99ecb9d..b1baed8 100644 + import SportsDetailPage from "./pages/SportsDetailPage"; + import LiveCasinoPage from "./pages/LiveCasinoPage"; + import TransactionPage from "./pages/Transaction"; + import { checkSingleTab} from "./utils/singleTab"; + import { useEffect, useState } from "react"; + import SingleTabModal from "./components/common/SingleTabModal"; + + function App() { + const { isLoading, tenant, isSuspended } = useConfig(); + const [showSingleTabModal, setShowSingleTabModal] = useState(false); + + useEffect(() => { + const result = checkSingleTab(); + if (result.showToast) { + setShowSingleTabModal(true); + }
Removed / Before Commit
- diff --git a/src/components/auth/LoginForm.tsx b/src/components/auth/LoginForm.tsx - index 046394b..63bb259 100644 - import { useIsB2C } from "../../hooks"; - import { markLoginSocketForceLogoutPending } from "../../utils/loginSocketSession"; - import toast from 'react-hot-toast'; - - interface LoginFormProps { - onSwitch: () => void; - const [loading, setLoading] = useState(false); - - const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => { - // Only allow digits - const value = e.target.value.replace(/\D/g, ""); - setPhone(value); - setOtpSent(false); - }); - - if (response.status) {
Added / After Commit
+ diff --git a/src/components/auth/LoginForm.tsx b/src/components/auth/LoginForm.tsx + index 046394b..63bb259 100644 + import { useIsB2C } from "../../hooks"; + import { markLoginSocketForceLogoutPending } from "../../utils/loginSocketSession"; + import toast from 'react-hot-toast'; + import { setLogin } from "../../utils/singleTab"; + + interface LoginFormProps { + onSwitch: () => void; + const [loading, setLoading] = useState(false); + + const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => { + + const value = e.target.value.replace(/\D/g, ""); + setPhone(value); + setOtpSent(false); + }); +
Removed / Before Commit
- diff --git a/src/components/common/SingleTabModal.tsx b/src/components/common/SingleTabModal.tsx - new file mode 100644 - index 0000000..9e7b27c
Added / After Commit
+ diff --git a/src/components/common/SingleTabModal.tsx b/src/components/common/SingleTabModal.tsx + new file mode 100644 + index 0000000..9e7b27c + import { useThemeColors } from "../../hooks/useThemeColors"; + + interface SingleTabModalProps { + onConfirm: () => void; + } + + export default function SingleTabModal({ onConfirm }: SingleTabModalProps) { + const colors = useThemeColors(); + + return ( + <div + className="fixed inset-0 z-[9999] flex items-center justify-center" + style={{ backgroundColor: "rgba(0, 0, 0, 0.75)" }} + > + <div
Removed / Before Commit
- diff --git a/src/components/racing/MarketCard.tsx b/src/components/racing/MarketCard.tsx - index 9de3cf9..35a7346 100644 - {insuranceBetEnabled ? "Insurance Bet" : ""} - {insuranceBetEnabled && <i className="fa-regular fa-circle-question text-[11px]"></i>} - - <div className="absolute left-0 top-[22px] hidden group-hover:block z-50 w-[650px] bg-[#1f2937] text-white text-[11px] leading-[18px] p-3 rounded shadow-lg border border-gray-700 whitespace-pre-line"> - {`An “insurance bet” is a betting market in which the total bet amount placed by the customer is equally divided among all available Win and various Place markets available at the time the bet is placed for the selected horse. - The payout for the insurance bet shall be determined based on the final finishing position of the selected horse: - - If the horse wins, the applicable Win and Place market returns may apply. - - If the horse finishes in a qualifying place position, the payout shall be settled according to the relevant Place market terms. - - If the horse finishes outside the eligible positions, no payout shall be payable. - Accordingly, an insurance bet provides coverage across multiple available betting markets by distributing the stake equally at the time of placement, with settlement based on the horse’s finishing result.`} - </div> - </div> - - <div></div> - - <div className="text-center text-gray-400 text-[12px]">Back</div>
Added / After Commit
+ diff --git a/src/components/racing/MarketCard.tsx b/src/components/racing/MarketCard.tsx + index 9de3cf9..35a7346 100644 + {insuranceBetEnabled ? "Insurance Bet" : ""} + {insuranceBetEnabled && <i className="fa-regular fa-circle-question text-[11px]"></i>} + + {insuranceBetEnabled ? <div className="absolute left-0 top-[22px] hidden group-hover:block z-50 w-[650px] bg-[#1f2937] text-white text-[11px] leading-[18px] p-3 rounded shadow-lg border border-gray-700 whitespace-pre-line"> + {insuranceBetEnabled ?`An “insurance bet” is a betting market in which the total bet amount placed by the customer is equally divided among all available Win and various Place markets available at the time the bet is placed for the selected horse. + The payout for the insurance bet shall be determined based on the final finishing position of the selected horse: + - If the horse wins, the applicable Win and Place market returns may apply. + - If the horse finishes in a qualifying place position, the payout shall be settled according to the relevant Place market terms. + - If the horse finishes outside the eligible positions, no payout shall be payable. + Accordingly, an insurance bet provides coverage across multiple available betting markets by distributing the stake equally at the time of placement, with settlement based on the horse’s finishing result.`:" "} + </div>: ""} + </div> + <div></div> + + <div className="text-center text-gray-400 text-[12px]">Back</div>
Removed / Before Commit
- diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx - index 250c2e5..c9c22e5 100644 - } from "react"; - import { queueSessionExpiredModal } from "../utils/authSessionExpired"; - import { dispatchLogoutEvent } from "../utils/authEvents"; - import { useLoginSocket } from "../hooks/useLoginSoket"; - import { authService } from "../services/authService"; - - - checkTokenSync(); - - // Also check on visibility change (when user switches tabs) - const handleVisibilityChange = () => { - if (!document.hidden) { - console.log('👁️ [TokenSync] Tab became visible, checking token sync'); - true; - - try {
Added / After Commit
+ diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx + index 250c2e5..c9c22e5 100644 + } from "react"; + import { queueSessionExpiredModal } from "../utils/authSessionExpired"; + import { dispatchLogoutEvent } from "../utils/authEvents"; + import { logout as singleTabLogout } from "../utils/singleTab"; + import { useLoginSocket } from "../hooks/useLoginSoket"; + import { authService } from "../services/authService"; + + + checkTokenSync(); + + + const handleVisibilityChange = () => { + if (!document.hidden) { + console.log('👁️ [TokenSync] Tab became visible, checking token sync'); + true; +
Removed / Before Commit
- diff --git a/src/pages/MultiRaceDetail.tsx b/src/pages/MultiRaceDetail.tsx - index 53b882d..2732321 100644 - type MultiBetRace, - type PlaceMultiBetRequest, - } from "../services/racing" - import { useThemeColors } from "../hooks/useThemeColors" - import { formatRaceDateTime } from "../utils/dateFormat" - import { useAuth } from "../contexts/AuthContext" - ? slipSelections.reduce((total, selection) => total * (selection.runner.backOdd || 0), 1) - : 0 - - // Calculate potential payout with compound profit logic - const potentialPayout = useMemo(() => { - if (slipSelections.length === 0 || stakeAmount <= 0) { - return 0 - currentAmount = currentAmount + profit - } -
Added / After Commit
+ diff --git a/src/pages/MultiRaceDetail.tsx b/src/pages/MultiRaceDetail.tsx + index 53b882d..2732321 100644 + type MultiBetRace, + type PlaceMultiBetRequest, + } from "../services/racing" + import { betService } from "../services/betService" + import { useThemeColors } from "../hooks/useThemeColors" + import { formatRaceDateTime } from "../utils/dateFormat" + import { useAuth } from "../contexts/AuthContext" + ? slipSelections.reduce((total, selection) => total * (selection.runner.backOdd || 0), 1) + : 0 + + + const potentialPayout = useMemo(() => { + if (slipSelections.length === 0 || stakeAmount <= 0) { + return 0 + currentAmount = currentAmount + profit + }