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
?
72%
Quality Avg
?
77%
Security Avg
?
64%
Reviews
?
91
Review Result ?
solutionbowl/super-admin · 41b3563d
This commit adds a new Excel export feature for bets with detailed type definitions and UI integration, improving business value by enabling users to export data easily. The implementation is mostly clean and user-friendly. Dynamic import of the xlsx library is appropriate to reduce initial load. The risk of bugs is low because there is defensive handling of empty datasets. However, security improvements could be made regarding the handling of potentially sensitive data (like IP addresses) and sanitizing data before export. Minor improvements on error handling and clearer commit message would help overall quality and maintainability.
Quality
?
85%
Security
?
30%
Business Value
?
90%
Maintainability
?
88%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Poor Detail
Where
commit message
Issue / Evidence
poor detail
Suggested Fix
write a more descriptive commit message explaining the purpose and key changes
Error Message Is Generic
Where
src/components/common/BetsExcelExportButton.tsx:63
Issue / Evidence
error message is generic
Suggested Fix
consider providing more user context or guidance
Dynamic Import Usage
Where
src/components/common/BetsExcelExportButton.tsx:69
Issue / Evidence
dynamic import usage
Suggested Fix
ensure proper error handling in case the import fails
Includes Ip Addresses In Export
Where
src/components/common/BetsExcelExportButton.tsx:134
Issue / Evidence
includes IP addresses in export
Suggested Fix
consider anonymizing or omitting sensitive data to improve security
Tocelltext Does Minimal Sanitization
Where
src/components/common/BetsExcelExportButton.tsx:186
Issue / Evidence
toCellText does minimal sanitization
Suggested Fix
add sanitization or escaping to avoid injection in excel files
Displaying Username Or User Info
Where
src/routes/bet-list.tsx:674
Issue / Evidence
displaying username or user info
Suggested Fix
ensure no PII is leaked unintentionally in exported data or UI
Code Change Preview · package.json
?
Removed / Before Commit
- diff --git a/package.json b/package.json - index 4aa3e60..f7a01c0 100644 - "input-otp": "^1.4.2", - "lucide-react": "^0.575.0", - "motion": "^12.38.0", - "react": "^19.2.0", - "react-day-picker": "^9.14.0", - "react-dom": "^19.2.0", - "tw-animate-css": "^1.3.4", - "vaul": "^1.1.2", - "vite-tsconfig-paths": "^6.0.2", - "zod": "^3.24.2" - }, - "devDependencies": {
Added / After Commit
+ diff --git a/package.json b/package.json + index 4aa3e60..f7a01c0 100644 + "input-otp": "^1.4.2", + "lucide-react": "^0.575.0", + "motion": "^12.38.0", + "number-to-words": "^1.2.4", + "react": "^19.2.0", + "react-day-picker": "^9.14.0", + "react-dom": "^19.2.0", + "tw-animate-css": "^1.3.4", + "vaul": "^1.1.2", + "vite-tsconfig-paths": "^6.0.2", + "xlsx": "^0.18.5", + "zod": "^3.24.2" + }, + "devDependencies": {
Removed / Before Commit
- diff --git a/src/components/common/BetsExcelExportButton.tsx b/src/components/common/BetsExcelExportButton.tsx - new file mode 100644 - index 0000000..38fb882
Added / After Commit
+ diff --git a/src/components/common/BetsExcelExportButton.tsx b/src/components/common/BetsExcelExportButton.tsx + new file mode 100644 + index 0000000..38fb882 + import { useState, type ComponentProps, type ReactNode } from "react"; + import { Download } from "lucide-react"; + import { toast } from "sonner"; + import { Button } from "@/components/ui/button"; + + type CellValue = string | number | boolean | null | undefined; + type XlsxModule = typeof import("xlsx"); + + export type BetsExcelLeg = { + raceId?: CellValue; + market?: CellValue; + marketId?: CellValue; + runnerId?: CellValue; + selectionNo?: CellValue; + runnerName?: CellValue;
Removed / Before Commit
- diff --git a/src/routes/bet-list.tsx b/src/routes/bet-list.tsx - index c6d13a2..9f3be0b 100644 - import type { DateRange } from "react-day-picker"; - import { Button } from "@/components/ui/button"; - import { Input } from "@/components/ui/input"; - import CsvExportButton from "@/components/common/CsvExportButton"; - import { - Select, - SelectContent, - } from "@/components/ui/select"; - import { internalServices } from "@/services/api/internalServices"; - import type { Bet, MultiBetLeg } from "@/services/api/betTypes"; - import type { CsvColumn } from "@/utils/csv/types"; - import { cn } from "@/lib/utils"; - - export const Route = createFileRoute("/bet-list")({ - const activeIsLoading = isAgentMode ? agentBetsQuery.isLoading : isLoading; - const activeIsFetching = isAgentMode ? agentBetsQuery.isFetching : isFetching;
Added / After Commit
+ diff --git a/src/routes/bet-list.tsx b/src/routes/bet-list.tsx + index c6d13a2..9f3be0b 100644 + import type { DateRange } from "react-day-picker"; + import { Button } from "@/components/ui/button"; + import { Input } from "@/components/ui/input"; + import BetsExcelExportButton from "@/components/common/BetsExcelExportButton"; + import { + Select, + SelectContent, + } from "@/components/ui/select"; + import { internalServices } from "@/services/api/internalServices"; + import type { Bet, MultiBetLeg } from "@/services/api/betTypes"; + import { cn } from "@/lib/utils"; + + export const Route = createFileRoute("/bet-list")({ + const activeIsLoading = isAgentMode ? agentBetsQuery.isLoading : isLoading; + const activeIsFetching = isAgentMode ? agentBetsQuery.isFetching : isFetching; + const activeError = isAgentMode ? agentBetsQuery.error : error;
Removed / Before Commit
- diff --git a/src/routes/bet-ticket.tsx b/src/routes/bet-ticket.tsx - index cacc2ea..8bee2a3 100644 - import { cn } from "@/lib/utils"; - import { format } from "date-fns"; - import { useAutoRefresh } from "@/hooks/useAutoRefresh"; - import CsvExportButton from "@/components/common/CsvExportButton"; - import type { CsvColumn } from "@/utils/csv/types"; - - export const Route = createFileRoute("/bet-ticket")({ - component: BetTicketPage, - const total = data?.total ?? 0; - const totalItems = data?.total ?? 0; - const totalPages = data?.totalPages ?? 1; - const csvColumns = useMemo( - () => - [ - { header: "Legs", accessor: (bet) => bet.totalLegs ?? bet.legs?.length ?? "" }, - { header: "User", accessor: (bet) => bet.username || "-" },
Added / After Commit
+ diff --git a/src/routes/bet-ticket.tsx b/src/routes/bet-ticket.tsx + index cacc2ea..8bee2a3 100644 + import { cn } from "@/lib/utils"; + import { format } from "date-fns"; + import { useAutoRefresh } from "@/hooks/useAutoRefresh"; + import BetsExcelExportButton from "@/components/common/BetsExcelExportButton"; + + export const Route = createFileRoute("/bet-ticket")({ + component: BetTicketPage, + const total = data?.total ?? 0; + const totalItems = data?.total ?? 0; + const totalPages = data?.totalPages ?? 1; + + const [currentPage, setCurrentPage] = useState(1); + // const PAGE_SIZE = 20; + <RefreshCw className={cn("mr-2 h-4 w-4", isFetching && "animate-spin")} /> + Refresh {countdown}s + </Button>
Removed / Before Commit
- diff --git a/src/routes/transfer.tsx b/src/routes/transfer.tsx - index 1c5baa2..d1e0c96 100644 - import { createFileRoute } from "@tanstack/react-router"; - import { useEffect, useMemo, useState, type ReactNode } from "react"; - import { useMutation, useQuery } from "@tanstack/react-query"; - import { motion } from "motion/react"; - import { toast } from "sonner"; - - type TransferTabValue = "all" | CreatableRole; - type TransferTab = { value: TransferTabValue; label: string }; - - function StatCell({ - label, - const [selectedRows, setSelectedRows] = useState<string[]>([]); - const [transferTarget, setTransferTarget] = useState<TransferRow | null>(null); - const [transferAmount, setTransferAmount] = useState(""); - const pageSize = 20; -
Added / After Commit
+ diff --git a/src/routes/transfer.tsx b/src/routes/transfer.tsx + index 1c5baa2..d1e0c96 100644 + import { createFileRoute } from "@tanstack/react-router"; + import { useEffect, useMemo, useRef, useState, type ReactNode } from "react"; + import { useMutation, useQuery } from "@tanstack/react-query"; + import { motion } from "motion/react"; + import { toast } from "sonner"; + + type TransferTabValue = "all" | CreatableRole; + type TransferTab = { value: TransferTabValue; label: string }; + type BulkTransferRow = { + key: string; + childUserId: string; + loginName: string; + action: TransferAction; + amount: string; + }; +
Removed / Before Commit
- diff --git a/src/routes/user-details.$userId.tsx b/src/routes/user-details.$userId.tsx - index 8e90c94..f659b5c 100644 - import { setExposureParams } from "@/lib/nav-params"; - import type { MultiBetLeg } from "@/services/api/betTypes"; - import CsvExportButton from "@/components/common/CsvExportButton"; - import type { CsvColumn } from "@/utils/csv/types"; - - export const Route = createFileRoute("/user-details/$userId")({ - () => bets.slice((currentPage - 1) * pageSize, currentPage * pageSize), - [bets, currentPage], - ); - const csvColumns = useMemo( - () => - [ - { header: "Legs", accessor: (bet) => getUserBetTotalLegs(bet) }, - { header: "Bet ID", accessor: (bet) => bet.bet_id ?? "" }, - { header: "Market", accessor: (bet) => bet.market_name ?? "" }, - { header: "Selection", accessor: (bet) => bet.selection ?? "" },
Added / After Commit
+ diff --git a/src/routes/user-details.$userId.tsx b/src/routes/user-details.$userId.tsx + index 8e90c94..f659b5c 100644 + import { setExposureParams } from "@/lib/nav-params"; + import type { MultiBetLeg } from "@/services/api/betTypes"; + import CsvExportButton from "@/components/common/CsvExportButton"; + import BetsExcelExportButton from "@/components/common/BetsExcelExportButton"; + import type { CsvColumn } from "@/utils/csv/types"; + + export const Route = createFileRoute("/user-details/$userId")({ + () => bets.slice((currentPage - 1) * pageSize, currentPage * pageSize), + [bets, currentPage], + ); + return ( + <Card className="overflow-hidden rounded-2xl border-border/60 bg-card shadow-elegant"> + {/* Filters */} + {f} + </Button> + ))}
Removed / Before Commit
- diff --git a/src/routes/user-exposure-bet.tsx b/src/routes/user-exposure-bet.tsx - new file mode 100644 - index 0000000..87ea24c
Added / After Commit
+ diff --git a/src/routes/user-exposure-bet.tsx b/src/routes/user-exposure-bet.tsx + new file mode 100644 + index 0000000..87ea24c + import { createFileRoute } from '@tanstack/react-router' + + export const Route = createFileRoute('/user-exposure-bet')({ + component: RouteComponent, + }) + + function RouteComponent() { + return <div>Hello "/user-exposure-bet"!</div> + }
Removed / Before Commit
- diff --git a/src/routes/user-listing.tsx b/src/routes/user-listing.tsx - index 472568d..e3e0b1d 100644 - const [editCreditRefUser, setEditCreditRefUser] = useState<DownlineUser | null>(null); - const [newCreditRefValue, setNewCreditRefValue] = useState(""); - const [creditRefError, setCreditRefError] = useState(""); - - useEffect(() => { - setPageInput(String(currentPage)); - <div className="flex flex-wrap items-center divide-x divide-black/10 "> - <StatCell - label="Credit Limit" - value={<div style={{ marginTop: "20px" }}>{fmt(creditSummary.creditLimit)} </div>} - /> - <StatCell - label="Distributed to downline" - </span> - )} - </div>
Added / After Commit
+ diff --git a/src/routes/user-listing.tsx b/src/routes/user-listing.tsx + index 472568d..e3e0b1d 100644 + const [editCreditRefUser, setEditCreditRefUser] = useState<DownlineUser | null>(null); + const [newCreditRefValue, setNewCreditRefValue] = useState(""); + const [creditRefError, setCreditRefError] = useState(""); + const createCreditLimitWords = formatRupeesInWords(formData.creditLimit); + + useEffect(() => { + setPageInput(String(currentPage)); + <div className="flex flex-wrap items-center divide-x divide-black/10 "> + <StatCell + label="Credit Limit" + value={ + <div className="mt-5"> + <div>{fmt(creditSummary.creditLimit)}</div> + + <div className="mt-1 text-xs font-semibold text-green-600"> + {creditSummary.creditLimit
Removed / Before Commit
- diff --git a/src/services/api/internalServices.ts b/src/services/api/internalServices.ts - index 9d5d297..5a0fc1f 100644 - CreatePanelUserRequest, - CreditTransferRequest, - CreditTransferResult, - TransferSubmitRequest, - TransferListResponse, - DownlineUser, - const root = asRecord(payload); - return asRecord(root.data ?? payload) as TransferListResponse; - }, - async submitTransfer(payload: TransferSubmitRequest) { - return authApiClient.post<unknown>(authConfig.panelAuthEndpoints.transferList, payload); - }, - async balance() {
Added / After Commit
+ diff --git a/src/services/api/internalServices.ts b/src/services/api/internalServices.ts + index 9d5d297..5a0fc1f 100644 + CreatePanelUserRequest, + CreditTransferRequest, + CreditTransferResult, + BulkTransferSubmitRequest, + TransferSubmitRequest, + TransferListResponse, + DownlineUser, + const root = asRecord(payload); + return asRecord(root.data ?? payload) as TransferListResponse; + }, + async submitTransfer(payload: TransferSubmitRequest | BulkTransferSubmitRequest) { + return authApiClient.post<unknown>(authConfig.panelAuthEndpoints.transferList, payload); + }, + async balance() {
Removed / Before Commit
- diff --git a/src/services/api/internalTypes.ts b/src/services/api/internalTypes.ts - index f9031fc..93e3c52 100644 - action: TransferAction; - } - - export interface TransferListProfile { - id?: string; - username?: string; - id?: string; - username?: string; - role?: string; - isBetBlocked: boolean, - isTransferBlocked: boolean, - }; - credit?: { - creditLimit?: number; - redirect_link?: string; - publish_time?: string;
Added / After Commit
+ diff --git a/src/services/api/internalTypes.ts b/src/services/api/internalTypes.ts + index f9031fc..93e3c52 100644 + action: TransferAction; + } + + export interface BulkTransferSubmitRequest { + data: Array<{ + childUserId: string; + action: TransferAction; + amount: number; + }>; + } + + export interface TransferListProfile { + id?: string; + username?: string; + id?: string; + username?: string;