Showing AI reviews for super-admin
Project AI Score ?
72%
Quality Avg ?
77%
Security Avg ?
64%
Reviews ?
91

Review Result ?

solutionbowl/super-admin · 2618eddb
The commit introduces a well-structured export feature for bets to Excel with support for multiple layouts and detailed bet leg breakdowns. The code is modular with multiple helper functions improving maintainability and readability. It adds useful features likely increasing business value by enabling better reporting and data export. There is a minor bug risk if the mapping functions (getBet, etc.) are flawed or if the XLSX library usage is incorrect, but overall risk is low. Security could be improved via validation or sanitization of input data before exporting. The commit message could be more descriptive regarding the layout parameter and specific features.
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
Missing Validation
Where src/components/common/BetsExcelExportButton.tsx:124
Issue / Evidence Potential missing validation of bet data before export
Suggested Fix Add input data validation to avoid corrupt or malicious data in generated Excel files
Direct Manipulation Of Excel Sheet Cells W...
Where src/components/common/BetsExcelExportButton.tsx:125
Issue / Evidence Direct manipulation of Excel sheet cells without error handling
Suggested Fix Add try-catch blocks or checks when accessing sheet cells to prevent runtime errors
External Function Getbet Usage Without Sho...
Where src/components/common/BetsExcelExportButton.tsx:73
Issue / Evidence External function getBet usage without shown definition
Suggested Fix Verify and document getBet mapping to ensure correct row data transformation
Lack Of Detail And Clarity
Where commit message
Issue / Evidence Lack of detail and clarity
Suggested Fix Expand commit message to better explain added features and parameters, e.g. role of layout options
Default Layout Assignment Could Be More Ex...
Where src/components/common/BetsExcelExportButton.tsx:54
Issue / Evidence Default layout assignment could be more explicit
Suggested Fix Ensure default parameter use is clear to avoid bugs with unspecified layouts
Code Change Preview · src/components/common/BetsExcelExportButton.tsx ?
Removed / Before Commit
- diff --git a/src/components/common/BetsExcelExportButton.tsx b/src/components/common/BetsExcelExportButton.tsx
- index 38fb882..07aac68 100644
- filename: string;
- rows: TRow[];
- getBet: (row: TRow) => BetsExcelBet;
- onExport?: (rows: number) => void;
- children?: ReactNode;
- };
- filename,
- rows,
- getBet,
- children = "Download XLSX",
- disabled,
- className,
- setIsExporting(true);
- const XLSX = await import("xlsx");
- 
-       exportBetsExcel(XLSX, rows.map(getBet), filename);
Added / After Commit
+ diff --git a/src/components/common/BetsExcelExportButton.tsx b/src/components/common/BetsExcelExportButton.tsx
+ index 38fb882..07aac68 100644
+ filename: string;
+ rows: TRow[];
+ getBet: (row: TRow) => BetsExcelBet;
+   layout?: "default" | "bet-ticket" | "bet-list";
+ onExport?: (rows: number) => void;
+ children?: ReactNode;
+ };
+ filename,
+ rows,
+ getBet,
+   layout = "default",
+ children = "Download XLSX",
+ disabled,
+ className,
+ setIsExporting(true);
+ const XLSX = await import("xlsx");
Removed / Before Commit
- diff --git a/src/components/common/NetExposureExcelExportButton.tsx b/src/components/common/NetExposureExcelExportButton.tsx
- new file mode 100644
- index 0000000..ad81f10
Added / After Commit
+ diff --git a/src/components/common/NetExposureExcelExportButton.tsx b/src/components/common/NetExposureExcelExportButton.tsx
+ new file mode 100644
+ index 0000000..ad81f10
+ import { useState } from "react";
+ import { Download } from "lucide-react";
+ import { toast } from "sonner";
+ import { Button } from "@/components/ui/button";
+ import { tenantApiClient } from "@/services/api/apiClient";
+ 
+ type ExposureMarket = {
+   marketId: string;
+   marketName: string;
+   totalStake: number;
+   worstBook: number;
+   bestBook: number;
+ };
+ 
+ type ExposureRace = {
Removed / Before Commit
- diff --git a/src/components/common/ProfitLossExcelExportButton.tsx b/src/components/common/ProfitLossExcelExportButton.tsx
- new file mode 100644
- index 0000000..c5726d3
Added / After Commit
+ diff --git a/src/components/common/ProfitLossExcelExportButton.tsx b/src/components/common/ProfitLossExcelExportButton.tsx
+ new file mode 100644
+ index 0000000..c5726d3
+ import { useState } from "react";
+ import { Download } from "lucide-react";
+ import { toast } from "sonner";
+ import { Button } from "@/components/ui/button";
+ 
+ type CellValue = string | number | boolean | null | undefined;
+ 
+ export type ProfitLossExcelDetail = {
+   rowIndex: number;
+   sheetName: string;
+   loadBets: () => Promise<unknown>;
+ };
+ 
+ export default function ProfitLossExcelExportButton({
+   filename,
Removed / Before Commit
- diff --git a/src/components/common/XlsxExportButton.tsx b/src/components/common/XlsxExportButton.tsx
- new file mode 100644
- index 0000000..49f7eb5
Added / After Commit
+ diff --git a/src/components/common/XlsxExportButton.tsx b/src/components/common/XlsxExportButton.tsx
+ new file mode 100644
+ index 0000000..49f7eb5
+ import { useState, type ComponentProps, type ReactNode } from "react";
+ import { Download } from "lucide-react";
+ import { Button } from "@/components/ui/button";
+ import type { CsvColumn } from "@/utils/csv/types";
+ 
+ export default function XlsxExportButton<TRow>({
+   filename,
+   rows,
+   columns,
+   children = "Download XLSX",
+   disabled,
+   ...buttonProps
+ }: Omit<ComponentProps<typeof Button>, "onClick"> & {
+   filename: string;
+   rows: TRow[];
Removed / Before Commit
- diff --git a/src/routes/bet-list.tsx b/src/routes/bet-list.tsx
- index 48696cb..f363642 100644
- filename={`bets-list-${formatApiDate(new Date())}.xlsx`}
- rows={bets}
- getBet={getBetExcelRow}
- disabled={activeIsLoading || Boolean(activeError)}
- className="ml-auto h-9 rounded-md bg-emerald-600 px-4 text-white hover:bg-emerald-700"
- />
Added / After Commit
+ diff --git a/src/routes/bet-list.tsx b/src/routes/bet-list.tsx
+ index 48696cb..f363642 100644
+ filename={`bets-list-${formatApiDate(new Date())}.xlsx`}
+ rows={bets}
+ getBet={getBetExcelRow}
+             layout="bet-list"
+ disabled={activeIsLoading || Boolean(activeError)}
+ className="ml-auto h-9 rounded-md bg-emerald-600 px-4 text-white hover:bg-emerald-700"
+ />
Removed / Before Commit
- diff --git a/src/routes/bet-ticket.tsx b/src/routes/bet-ticket.tsx
- index 9c39012..2c7b934 100644
- filename={`bet-ticket-${new Date().toISOString().slice(0, 10)}.xlsx`}
- rows={bets}
- getBet={getBetTickerExcelRow}
- disabled={isLoading}
- className="h-9 rounded-lg bg-emerald-600 px-4 text-white hover:bg-emerald-700"
- />
- <table className="w-full min-w-[780px] border-collapse text-left text-xs">
- <thead className="bg-background">
- <tr>
-               {["Leg", "Race", "Market", "Market ID", "Runner", "Selection", "Status"].map((h) => (
- <th key={h} className="whitespace-nowrap px-3 py-2 font-bold text-muted-foreground">
- {h}
- </th>
Added / After Commit
+ diff --git a/src/routes/bet-ticket.tsx b/src/routes/bet-ticket.tsx
+ index 9c39012..2c7b934 100644
+ filename={`bet-ticket-${new Date().toISOString().slice(0, 10)}.xlsx`}
+ rows={bets}
+ getBet={getBetTickerExcelRow}
+               layout="bet-ticket"
+ disabled={isLoading}
+ className="h-9 rounded-lg bg-emerald-600 px-4 text-white hover:bg-emerald-700"
+ />
+ <table className="w-full min-w-[780px] border-collapse text-left text-xs">
+ <thead className="bg-background">
+ <tr>
+               {["Leg", "Race", "Market", "Market ID", "Runner", "Odds","Selection", "Status"].map((h) => (
+ <th key={h} className="whitespace-nowrap px-3 py-2 font-bold text-muted-foreground">
+ {h}
+ </th>
Removed / Before Commit
- diff --git a/src/routes/net-exposure.tsx b/src/routes/net-exposure.tsx
- index 63d4d39..b09ed7b 100644
- import { internalServices } from "@/services/api/internalServices";
- import { setExposureParams } from "@/lib/nav-params";
- import { useRefreshToggle } from "@/hooks/useRefreshToggle";
- 
- export const Route = createFileRoute("/net-exposure")({
- component: NetExposurePage,
- "Greyhound Racing",
- ];
- 
-   const { data: rawData, isLoading, error, refetch, isFetching } = useQuery({
- queryKey: ["net-exposure"],
- queryFn: fetchNetExposure,
- refetchOnMount: "always",
- {/* Title + Refresh */}
- <div className="flex flex-col gap-4 border-b border-border/60 p-5 lg:flex-row lg:items-center lg:justify-between">
- <h2 className="text-xl font-bold tracking-tight">Net Exposure</h2>
Added / After Commit
+ diff --git a/src/routes/net-exposure.tsx b/src/routes/net-exposure.tsx
+ index 63d4d39..b09ed7b 100644
+ import { internalServices } from "@/services/api/internalServices";
+ import { setExposureParams } from "@/lib/nav-params";
+ import { useRefreshToggle } from "@/hooks/useRefreshToggle";
+ import NetExposureExcelExportButton from "@/components/common/NetExposureExcelExportButton";
+ 
+ export const Route = createFileRoute("/net-exposure")({
+ component: NetExposurePage,
+ "Greyhound Racing",
+ ];
+ 
+   const {
+     data: rawData,
+     isLoading,
+     error,
+     refetch,
+     isFetching,
Removed / Before Commit
- diff --git a/src/routes/pl-by-agent.tsx b/src/routes/pl-by-agent.tsx
- index 940a3d9..1cc2e50 100644
- import { Card } from "@/components/ui/card";
- import { Button } from "@/components/ui/button";
- import DateRangePicker from "@/components/common/DateRangePicker";
- import CsvExportButton from "@/components/common/CsvExportButton";
- import {
- Table,
- TableBody,
- agent: string;
- market: string;
- totals: ProfitLossTotals;
- };
- 
- const defaultFilters = {
- Race: row.race,
- Agent: row.agent,
- Market: row.market,
Added / After Commit
+ diff --git a/src/routes/pl-by-agent.tsx b/src/routes/pl-by-agent.tsx
+ index 940a3d9..1cc2e50 100644
+ import { Card } from "@/components/ui/card";
+ import { Button } from "@/components/ui/button";
+ import DateRangePicker from "@/components/common/DateRangePicker";
+ import ProfitLossExcelExportButton from "@/components/common/ProfitLossExcelExportButton";
+ import {
+ Table,
+ TableBody,
+ agent: string;
+ market: string;
+ totals: ProfitLossTotals;
+   raceId: string;
+   agentId: string;
+ };
+ 
+ const defaultFilters = {
+ Race: row.race,
Removed / Before Commit
- diff --git a/src/routes/pl-by-market.tsx b/src/routes/pl-by-market.tsx
- index 63f4500..d7b7ff2 100644
- import { Card } from "@/components/ui/card";
- import { Button } from "@/components/ui/button";
- import DateRangePicker from "@/components/common/DateRangePicker";
- import CsvExportButton from "@/components/common/CsvExportButton";
- import {
- Table,
- TableBody,
- date: string;
- race: string;
- market: string;
- totals: ProfitLossTotals;
- };
- 
- 
- useReportSocket({ onProfitLoss: refreshFromSocket });
- 
Added / After Commit
+ diff --git a/src/routes/pl-by-market.tsx b/src/routes/pl-by-market.tsx
+ index 63f4500..d7b7ff2 100644
+ import { Card } from "@/components/ui/card";
+ import { Button } from "@/components/ui/button";
+ import DateRangePicker from "@/components/common/DateRangePicker";
+ import ProfitLossExcelExportButton from "@/components/common/ProfitLossExcelExportButton";
+ import {
+ Table,
+ TableBody,
+ date: string;
+ race: string;
+ market: string;
+   marketId: string;
+ totals: ProfitLossTotals;
+ };
+ 
+ 
+ useReportSocket({ onProfitLoss: refreshFromSocket });
Removed / Before Commit
- diff --git a/src/routes/transfer.tsx b/src/routes/transfer.tsx
- index dd93b4f..e7bd987 100644
- loginName: string;
- action: TransferAction;
- amount: string;
- };
- 
- function StatCell({
- loginName: row.loginName,
- action: getTransferAction(row) as TransferAction,
- amount: getTransferAmount(row),
- })),
- );
- };
- };
- 
- const focusBulkTransferAmount = (rowKey: string) => {
-     bulkAmountInputRefs.current[rowKey]?.focus();
Added / After Commit
+ diff --git a/src/routes/transfer.tsx b/src/routes/transfer.tsx
+ index dd93b4f..e7bd987 100644
+ loginName: string;
+ action: TransferAction;
+ amount: string;
+   isEditing: boolean;
+ };
+ 
+ function StatCell({
+ loginName: row.loginName,
+ action: getTransferAction(row) as TransferAction,
+ amount: getTransferAmount(row),
+         isEditing: false,
+ })),
+ );
+ };
+ };
+ 
Removed / Before Commit
- diff --git a/src/routes/user-details.$userId.tsx b/src/routes/user-details.$userId.tsx
- index 1985931..8dcabf0 100644
- import { format } from "date-fns";
- 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")({
- component: UserDetailsPage,
- 
- return (
- <Card className="overflow-hidden rounded-2xl border-border/60 bg-card shadow-elegant">
- <div className="overflow-x-auto">
- <Table>
- <TableHeader>
- 
Added / After Commit
+ diff --git a/src/routes/user-details.$userId.tsx b/src/routes/user-details.$userId.tsx
+ index 1985931..8dcabf0 100644
+ import { format } from "date-fns";
+ import { setExposureParams } from "@/lib/nav-params";
+ import type { MultiBetLeg } from "@/services/api/betTypes";
+ import BetsExcelExportButton from "@/components/common/BetsExcelExportButton";
+ import XlsxExportButton from "@/components/common/XlsxExportButton";
+ import type { CsvColumn } from "@/utils/csv/types";
+ import NetExposureExcelExportButton from "@/components/common/NetExposureExcelExportButton";
+ 
+ export const Route = createFileRoute("/user-details/$userId")({
+ component: UserDetailsPage,
+ 
+ return (
+ <Card className="overflow-hidden rounded-2xl border-border/60 bg-card shadow-elegant">
+       <div className="flex justify-end border-b border-border/60 p-4">
+         <XlsxExportButton
+           filename={`user-activity-${new Date().toISOString().slice(0, 10)}.xlsx`}
Removed / Before Commit
- diff --git a/src/routes/user-exposure-detail.tsx b/src/routes/user-exposure-detail.tsx
- index 1e82173..7aa0a9d 100644
- return (Array.isArray(data) ? data : []) as OddsMarket[];
- }
- 
- async function fetchHierarchy(
- raceId: string,
- marketId: string,
Added / After Commit
+ diff --git a/src/routes/user-exposure-detail.tsx b/src/routes/user-exposure-detail.tsx
+ index 1e82173..7aa0a9d 100644
+ return (Array.isArray(data) ? data : []) as OddsMarket[];
+ }
+ 
+ 
+ 
+ async function fetchHierarchy(
+ raceId: string,
+ marketId: string,
Removed / Before Commit
- diff --git a/src/routes/user-listing.tsx b/src/routes/user-listing.tsx
- index 2b8a7d1..8bf8c22 100644
- Pencil,
- Plus,
- RefreshCw,
- Unlock,
- } from "lucide-react";
- import {
- DownlineUser,
- UserBlockStatusResult,
- } from "@/services/api/internalTypes";
- import CsvExportButton from "@/components/common/CsvExportButton";
- import type { CsvColumn } from "@/utils/csv/types";
- import { cn } from "@/lib/utils";
- 
- const statusFilterValues = ["ACTIVE", "INACTIVE", "CLOSED"] as const;
- const [selectedDownlineTab, setSelectedDownlineTab] = useState<DownlineTab>("all");
- const [drillDownlineUserId, setDrillDownlineUserId] = useState<string | null>(null);
Added / After Commit
+ diff --git a/src/routes/user-listing.tsx b/src/routes/user-listing.tsx
+ index 2b8a7d1..8bf8c22 100644
+ Pencil,
+ Plus,
+ RefreshCw,
+   Download,
+ Unlock,
+ } from "lucide-react";
+ import {
+ DownlineUser,
+ UserBlockStatusResult,
+ } from "@/services/api/internalTypes";
+ import type { CsvCellValue, CsvColumn } from "@/utils/csv/types";
+ import { cn } from "@/lib/utils";
+ 
+ const statusFilterValues = ["ACTIVE", "INACTIVE", "CLOSED"] as const;
+ const [selectedDownlineTab, setSelectedDownlineTab] = useState<DownlineTab>("all");
+ const [drillDownlineUserId, setDrillDownlineUserId] = useState<string | null>(null);
Removed / Before Commit
- diff --git a/src/services/api/internalServices.ts b/src/services/api/internalServices.ts
- index 5a0fc1f..13a7a72 100644
- return unwrapData<DownlineUser[]>(
- await authApiClient.get<unknown>(
- `${authConfig.panelAuthEndpoints.downlineUsers}${queryString}`,
- ),
- );
- },
Added / After Commit
+ diff --git a/src/services/api/internalServices.ts b/src/services/api/internalServices.ts
+ index 5a0fc1f..13a7a72 100644
+ return unwrapData<DownlineUser[]>(
+ await authApiClient.get<unknown>(
+ `${authConfig.panelAuthEndpoints.downlineUsers}${queryString}`,
+           { cache: "no-store" },
+ ),
+ );
+ },