1import { aj as createLucideIcon, u as useDealership, r as reactExports, t as trpc, e as toast, j as jsxRuntimeExports, O as Shield, f as Badge, B as Button, R as RefreshCw, a6 as FileText, o as TriangleAlert, m as Clock, C as ChartColumn, X, g as Search, S as Select, a as SelectTrigger, b as SelectValue, c as SelectContent, d as SelectItem, T as TrendingUp, x as ChevronRight, D as Dialog, y as DialogContent, z as DialogHeader, E as DialogTitle, a$ as DialogFooter, aC as TooltipProvider, s as Tooltip, v as TooltipTrigger, w as TooltipContent, bE as __vitePreload } from "./index-DZUVA1tZ.js"; 2import { C as Card, a as CardHeader, b as CardTitle, c as CardContent } from "./card-C2_jI6O8.js"; 3import { I as Input } from "./input-BsBhHtex.js"; 4import { L as Label } from "./label-DkWcE3Xf.js"; 5import { S as Slider } from "./slider-DQ-4XWUN.js"; 6import { C as Checkbox } from "./checkbox-B90zIwk_.js"; 7import { C as ChartContainer, a as ChartTooltip, b as ChartTooltipContent } from "./chart-DqrXm1Bo.js"; 8import { T as Textarea } from "./textarea-B194Jwaz.js"; 9import { U as Upload } from "./upload-BV_VYj_j.js"; 10import { D as Download } from "./download-2Lv-z89u.js"; 11import { P as Plus } from "./plus-BbqdyZv7.js"; 12import { C as CircleX } from "./circle-x-Bl7mXUyr.js"; 13import { C as CircleCheck } from "./circle-check-RQpKy75X.js"; 14import { D as DollarSign } from "./dollar-sign-DMAmZp43.js"; 15import { B as BarChart } from "./BarChart-nELobgLf.js"; 16import { C as CartesianGrid } from "./CartesianGrid-Dju2DZc9.js"; 17import { X as XAxis, Y as YAxis } from "./YAxis-vcBlqPnO.js"; 18import { B as Bar, C as Cell } from "./generateCategoricalChart-DS6b7n0z.js"; 19import { E as ExternalLink } from "./external-link-DqNhAofM.js"; 20import { E as Eye } from "./eye-C3v9vgKf.js"; 21import { P as Percent } from "./percent-CyWz1J0J.js"; 22import { C as ChevronsLeft, a as ChevronsRight } from "./chevrons-right-eb_GFtZL.js"; 23import { C as ChevronLeft } from "./chevron-left-BUMmw3WR.js"; 24import { H as History } from "./history-SGguF2VL.js"; 25import { C as CalendarDays } from "./calendar-days-kCkFTmM5.js"; 26import { U as User } from "./user-C-t3XOxU.js"; 27import { I as Info } from "./info-DYimJ5vB.js"; 28import "./useComposition-Bo7q6aoH.js"; 29import "./string-Cl2mTqJp.js"; 30import "./band-CR10Xg6M.js"; 31import "./init-CTO7spbL.js"; 32import "./ordinal-B3yiDjK9.js"; 33import "./linear-CiVNRwv0.js"; 34import "./defaultLocale-DVr69WTU.js"; 35import "./time-ByDv7dtv.js"; 36/** 37 * @license lucide-react v0.453.0 - ISC 38 * 39 * This source code is licensed under the ISC license. 40 * See the LICENSE file in the root directory of this source tree. 41 */ 42const SlidersHorizontal = createLucideIcon("SlidersHorizontal", [ 43 ["line", { x1: "21", x2: "14", y1: "4", y2: "4", key: "obuewd" }], 44 ["line", { x1: "10", x2: "3", y1: "4", y2: "4", key: "1q6298" }], 45 ["line", { x1: "21", x2: "12", y1: "12", y2: "12", key: "1iu8h1" }], 46 ["line", { x1: "8", x2: "3", y1: "12", y2: "12", key: "ntss68" }], 47 ["line", { x1: "21", x2: "16", y1: "20", y2: "20", key: "14d8ph" }], 48 ["line", { x1: "12", x2: "3", y1: "20", y2: "20", key: "m0wm8r" }], 49 ["line", { x1: "14", x2: "14", y1: "2", y2: "6", key: "14e1ph" }], 50 ["line", { x1: "8", x2: "8", y1: "10", y2: "14", key: "1i6ji0" }], 51 ["line", { x1: "16", x2: "16", y1: "18", y2: "22", key: "1lctlv" }] 52]); 53function statusColor(s) { 54 switch (s) { 55 case "RATE_OVER_MAX": 56 return "text-red-500 bg-red-500/10 border-red-500/30"; 57 case "DEAL_PACK_MISMATCH": 58 return "text-amber-500 bg-amber-500/10 border-amber-500/30"; 59 case "INCOMPLETE": 60 return "text-gray-400 bg-gray-500/10 border-gray-500/30"; 61 case "OK": 62 return "text-emerald-500 bg-emerald-500/10 border-emerald-500/30"; 63 } 64} 65function statusIcon(s) { 66 switch (s) { 67 case "RATE_OVER_MAX": 68 return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "w-4 h-4 text-red-500" }); 69 case "DEAL_PACK_MISMATCH": 70 return /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-amber-500" }); 71 case "INCOMPLETE": 72 return /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-4 h-4 text-gray-400" }); 73 case "OK": 74 return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-emerald-500" }); 75 } 76} 77function statusLabel(s) { 78 switch (s) { 79 case "RATE_OVER_MAX": 80 return "RATE OVER MAX"; 81 case "DEAL_PACK_MISMATCH": 82 return "DEAL PACK MISMATCH"; 83 case "INCOMPLETE": 84 return "INCOMPLETE"; 85 case "OK": 86 return "OK"; 87 } 88} 89function fmt(n) { 90 if (n == null) return "â";
91 return n.toLocaleString("en-US", { style: "currency", currency: "USD" }); 92} 93function fmtPct(n) { 94 if (n == null) return "â"; 95 return n.toFixed(3) + "%"; 96} 97function MaxRateAudit() { 98 const { selectedDealerId } = useDealership(); 99 const dealerId = selectedDealerId; 100 const [statusFilter, setStatusFilter] = reactExports.useState("ALL"); 101 const [searchQuery, setSearchQuery] = reactExports.useState(""); 102 const [selectedAuditId, setSelectedAuditId] = reactExports.useState(null); 103 const [lienHolderFilter, setLienHolderFilter] = reactExports.useState("ALL"); 104 const [sortField, setSortField] = reactExports.useState("dealDate"); 105 const [sortDir, setSortDir] = reactExports.useState("desc"); 106 const [showAddDeal, setShowAddDeal] = reactExports.useState(false); 107 const [showImport, setShowImport] = reactExports.useState(false); 108 const [showResolve, setShowResolve] = reactExports.useState(false); 109 const [resolveNotes, setResolveNotes] = reactExports.useState(""); 110 const [currentPage, setCurrentPage] = reactExports.useState(1); 111 const [pageSize, setPageSize] = reactExports.useState(25); 112 const [selectedIds, setSelectedIds] = reactExports.useState(/* @__PURE__ */ new Set()); 113 const [resolvedFilter, setResolvedFilter] = reactExports.useState("ALL"); 114 const [vehicleTypeFilter, setVehicleTypeFilter] = reactExports.useState("ALL"); 115 const [minAmountOver, setMinAmountOver] = reactExports.useState(""); 116 const [dateFrom, setDateFrom] = reactExports.useState(""); 117 const [dateTo, setDateTo] = reactExports.useState(""); 118 const [termRange, setTermRange] = reactExports.useState([1, 300]); 119 const [showAdvancedFilters, setShowAdvancedFilters] = reactExports.useState(false); 120 const metrics = trpc.maxrate.metrics.useQuery( 121 { dealerId }, 122 { enabled: !!dealerId } 123 ); 124 const audits = trpc.maxrate.list.useQuery( 125 { dealerId, status: statusFilter === "ALL" ? "ALL" : statusFilter }, 126 { enabled: !!dealerId } 127 ); 128 const detail = trpc.maxrate.detail.useQuery( 129 { dealerId, auditId: selectedAuditId }, 130 { enabled: !!dealerId && selectedAuditId != null } 131 ); 132 const autoPopulate = trpc.maxrate.autoPopulate.useMutation({ 133 onSuccess: (data) => { 134 toast.success(data.message); 135 audits.refetch(); 136 metrics.refetch(); 137 }, 138 onError: (e) => toast.error(e.message) 139 }); 140 const resolve = trpc.maxrate.resolve.useMutation({ 141 onSuccess: () => { 142 toast.success("Audit marked as resolved"); 143 setShowResolve(false); 144 setResolveNotes(""); 145 audits.refetch(); 146 metrics.refetch(); 147 if (selectedAuditId) detail.refetch(); 148 } 149 }); 150 const deleteMut = trpc.maxrate.delete.useMutation({ 151 onSuccess: () => { 152 toast.success("Deleted"); 153 setSelectedAuditId(null); 154 audits.refetch(); 155 metrics.refetch(); 156 } 157 }); 158 const updateInline = trpc.maxrate.updateInline.useMutation({ 159 onSuccess: () => { 160 toast.success("Updated"); 161 audits.refetch(); 162 metrics.refetch(); 163 if (selectedAuditId) detail.refetch(); 164 setEditingCell(null); 165 }, 166 onError: (e) => toast.error(e.message) 167 }); 168 const [editingCell, setEditingCell] = reactExports.useState(null); 169 const [editValue, setEditValue] = reactExports.useState(""); 170 const filteredAudits = reactExports.useMemo(() => { 171 if (!audits.data) return []; 172 let result = [...audits.data]; 173 if (searchQuery.trim()) { 174 const q = searchQuery.toLowerCase(); 175 result = result.filter( 176 (a) => a.customerName?.toLowerCase().includes(q) || a.externalDealNumber?.toLowerCase().includes(q) || a.vin?.toLowerCase().includes(q) || a.tekionDealId?.toLowerCase().includes(q) || a.vehicleMake?.toLowerCase().includes(q) || a.vehicleModel?.toLowerCase().includes(q) || a.vehicleTrim?.toLowerCase().includes(q) || a.vehicleStockId?.toLowerCase().includes(q) || a.lenderName?.toLowerCase().includes(q) 177 ); 178 } 179 if (lienHolderFilter === "AFFINITY") { 180 result = result.filter((a) => a.lenderName?.toUpperCase().includes("AFFINITY")); 181 } else if (lienHolderFilter === "NON_AFFINITY") { 182 result = result.filter((a) => a.lenderName && !a.lenderName.toUpperCase().includes("AFFINITY")); 183 } else if (lienHolderFilter === "MISSING") { 184 result = result.filter((a) => !a.lenderName); 185 } 186 if (resolvedFilter === "RESOLVED") { 187 result = result.filter((a) => a.resolved); 188 } else if (resolvedFilter === "UNRESOLVED") { 189 result = result.filter((a) => !a.resolved); 190 } 191 if (vehicleTypeFilter === "NEW") { 192 result = result.filter((a) => a.tekIsNewCar === true || a.vehicleStockType === "NEW"); 193 } else if (vehicleTypeFilter === "USED") { 194 result = result.filter((a) => a.tekIsNewCar === false || a.vehicleStockType === "USED"); 195 } 196 const minOver = parseFloat(minAmountOver); 197 if (!isNaN(minOver) && minOver > 0) { 198 result = result.filter((a) => { 199 const over = a.tekFinanceCharge && a.maxFinanceCharge ? parseFloat(String(a.tekFinanceCharge)) - parseFloat(String(a.maxFinanceCharge)) : 0; 200 return over >= minOver; 201 }); 202 } 203 if (dateFrom) { 204 const fromDate = new Date(dateFrom).getTime(); 205 result = result.filter((a) => a.dealDate && new Date(a.dealDate).getTime() >= fromDate); 206 } 207 if (dateTo) { 208 const toDate = (/* @__PURE__ */ new Date(dateTo + "T23:59:59")).getTime(); 209 result = result.filter((a) => a.dealDate && new Date(a.dealDate).getTime() <= toDate); 210 } 211 if (termRange[0] > 1 || termRange[1] < 300) { 212 result = result.filter((a) => { 213 if (!a.tekTerm) return false;
214 return a.tekTerm >= termRange[0] && a.tekTerm <= termRange[1]; 215 }); 216 } 217 if (sortField) { 218 result.sort((a, b) => { 219 let valA, valB; 220 switch (sortField) { 221 case "dealDate": 222 valA = a.dealDate ? new Date(a.dealDate).getTime() : 0; 223 valB = b.dealDate ? new Date(b.dealDate).getTime() : 0; 224 break; 225 case "lienHolder": 226 valA = (a.lenderName || "").toLowerCase(); 227 valB = (b.lenderName || "").toLowerCase(); 228 break; 229 case "amtFinanced": 230 valA = a.tekAmountFinanced ? Number(a.tekAmountFinanced) : 0; 231 valB = b.tekAmountFinanced ? Number(b.tekAmountFinanced) : 0; 232 break; 233 case "term": 234 valA = a.tekTerm ?? 0; 235 valB = b.tekTerm ?? 0; 236 break; 237 case "apr": 238 valA = a.tekApr ? a.tekApr ?? 0 : 0; 239 valB = b.tekApr ? b.tekApr ?? 0 : 0; 240 break; 241 case "financeChg": 242 valA = a.tekFinanceCharge ? Number(a.tekFinanceCharge) : 0; 243 valB = b.tekFinanceCharge ? Number(b.tekFinanceCharge) : 0; 244 break; 245 case "overUnder": 246 valA = a.tekFinanceCharge && a.maxFinanceCharge ? parseFloat(String(a.tekFinanceCharge)) - parseFloat(String(a.maxFinanceCharge)) : 0; 247 valB = b.tekFinanceCharge && b.maxFinanceCharge ? parseFloat(String(b.tekFinanceCharge)) - parseFloat(String(b.maxFinanceCharge)) : 0; 248 break; 249 default: 250 return 0; 251 } 252 if (valA < valB) return sortDir === "asc" ? -1 : 1; 253 if (valA > valB) return sortDir === "asc" ? 1 : -1; 254 return 0; 255 }); 256 } 257 return result; 258 }, [audits.data, searchQuery, lienHolderFilter, resolvedFilter, vehicleTypeFilter, minAmountOver, dateFrom, dateTo, termRange, sortField, sortDir]); 259 reactExports.useEffect(() => { 260 setCurrentPage(1); 261 }, [searchQuery, statusFilter, lienHolderFilter, resolvedFilter, vehicleTypeFilter, minAmountOver, dateFrom, dateTo, termRange, sortField, sortDir]); 262 const totalPages = Math.max(1, Math.ceil(filteredAudits.length / pageSize)); 263 const safeCurrentPage = Math.min(currentPage, totalPages); 264 const startIndex = (safeCurrentPage - 1) * pageSize; 265 const endIndex = Math.min(startIndex + pageSize, filteredAudits.length); 266 const paginatedAudits = filteredAudits.slice(startIndex, endIndex); 267 const analytics = reactExports.useMemo(() => { 268 if (!filteredAudits.length) return { totalFinanced: 0, totalFinanceChg: 0, totalOver: 0, avgApr: 0, riskBreakdown: { critical: 0, high: 0, medium: 0, low: 0 }, overByDay: [] }; 269 let totalFinanced = 0, totalFinanceChg = 0, totalOver = 0, aprSum = 0, aprCount = 0; 270 let critical = 0, high = 0, medium = 0, low = 0; 271 const dayMap = /* @__PURE__ */ new Map(); 272 for (const a of filteredAudits) { 273 totalFinanced += a.tekAmountFinanced ? Number(a.tekAmountFinanced) : 0; 274 totalFinanceChg += a.tekFinanceCharge ? Number(a.tekFinanceCharge) : 0; 275 const over = (a.amountOver ?? 0) > 0 ? Number(a.amountOver) : 0; 276 totalOver += over; 277 if (a.tekApr) { 278 aprSum += a.tekApr ?? 0; 279 aprCount++; 280 } 281 if (over > 500) critical++; 282 else if (over > 200) high++; 283 else if (over > 0) medium++; 284 else low++; 285 if (a.dealDate) { 286 const d = new Date(a.dealDate).toLocaleDateString("en-US", { month: "short", day: "
286numeric" }); 287 const existing = dayMap.get(d) || { over: 0, count: 0 }; 288 existing.over += over; 289 existing.count++; 290 dayMap.set(d, existing); 291 } 292 } 293 const overByDay = Array.from(dayMap.entries()).map(([date, v]) => ({ date, ...v })).slice(-14); 294 return { totalFinanced, totalFinanceChg, totalOver, avgApr: aprCount ? aprSum / aprCount : 0, riskBreakdown: { critical, high, medium, low }, overByDay }; 295 }, [filteredAudits]); 296 const allPageSelected = paginatedAudits.length > 0 && paginatedAudits.every((a) => selectedIds.has(a.id)); 297 const somePageSelected = paginatedAudits.some((a) => selectedIds.has(a.id)); 298 const toggleSelectAll = () => { 299 setSelectedIds((prev) => { 300 const next = new Set(prev); 301 if (allPageSelected) { 302 paginatedAudits.forEach((a) => next.delete(a.id)); 303 } else { 304 paginatedAudits.forEach((a) => next.add(a.id)); 305 } 306 return next; 307 }); 308 }; 309 const toggleSelectOne = (id) => { 310 setSelectedIds((prev) => { 311 const next = new Set(prev); 312 if (next.has(id)) next.delete(id); 313 else next.add(id); 314 return next; 315 }); 316 }; 317 const bulkResolve = trpc.maxrate.bulkResolve.useMutation({ 318 onSuccess: (data) => { 319 toast.success(`Resolved ${data.count} deal(s)`); 320 setSelectedIds(/* @__PURE__ */ new Set()); 321 audits.refetch(); 322 metrics.refetch(); 323 }, 324 onError: (e) => toast.error(e.message) 325 }); 326 const exportCSV = reactExports.useCallback(() => { 327 const headers = ["Status", "Deal #", "Customer", "VIN", "Vehicle", "Stock #", "Type", "Amt Financed", "Term", "Frequency", "APR", "Finance Charge", "Max Allowed", "Over/Under", "Lien Holder", "Deal Date", "Resolved"]; 328 const rows = filteredAudits.map((a) => [ 329 a.auditStatus || "", 330 a.externalDealNumber || "", 331 a.customerName || "", 332 a.vin || "", 333 [a.tekVehicleYear, a.vehicleMake, a.vehicleModel].filter(Boolean).join(" "), 334 a.vehicleStockId || "", 335 a.vehicleStockType || "", 336 a.tekAmountFinanced || "", 337 a.tekTerm || "", 338 a.tekFrequency || "", 339 a.tekApr || "", 340 a.tekFinanceCharge || "", 341 a.maxFinanceCharge || "", 342 a.amountOver || "", 343 a.lenderName || "", 344 a.dealDate ? new Date(a.dealDate).toLocaleDateString() : "", 345 a.resolved ? "Yes" : "No" 346 ]); 347 const csv = [headers.join(","), ...rows.map((r) => r.map((c) => `"${String(c).replace(/"/g, '""')}"`).join(","))].join("\n"); 348 const blob = new Blob([csv], { type: "text/csv" }); 349 const url = URL.createObjectURL(blob); 350 const link = document.createElement("a"); 351 link.href = url; 352 link.download = `maxrate-audit-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.csv`; 353 link.click(); 354 URL.revokeObjectURL(url); 355 toast.success(`Exported ${filteredAudits.length} records to CSV`); 356 }, [filteredAudits]); 357 reactExports.useEffect(() => { 358 const handler = (e) => { 359 if (e.key === "Escape" && selectedIds.size > 0 && !selectedAuditId) { 360 setSelectedIds(/* @__PURE__ */ new Set()); 361 return; 362 } 363 if (e.key === "Escape" && selectedAuditId) { 364 setSelectedAuditId(null); 365 return; 366 } 367 }; 368 window.addEventListener("keydown", handler); 369 return () => window.removeEventListener("keydown", handler); 370 }, [selectedIds, selectedAuditId]); 371 reactExports.useEffect(() => { 372 if (selectedAuditId == null) return; 373 const handler = (e) => { 374 const idx = filteredAudits.findIndex((a) => a.id === selectedAuditId); 375 if (e.key === "ArrowLeft" && idx > 0) { 376 e.preventDefault(); 377 setSelectedAuditId(filteredAudits[idx - 1].id); 378 } else if (e.key === "ArrowRight" && idx < filteredAudits.length - 1) { 379 e.preventDefault(); 380 setSelectedAuditId(filteredAudits[idx + 1].id); 381 } 382 }; 383 window.addEventListener("keydown", handler); 384 return () => window.removeEventListener("keydown", handler); 385 }, [selectedAuditId, filteredAudits]); 386 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
387 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 388 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 389 /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-2xl font-bold flex items-center gap-2", children: [ 390 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-6 h-6 text-indigo-400" }), 391 "MaxRate Deal Audit", 392 /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-xs font-normal border-indigo-500/40 text-indigo-400 ml-1", children: "Affinity Financial" }) 393 ] }), 394 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Dealer-financed deals through Affinity Financial · Finance charge vs. legal ceiling · Tekion vs. Deal Pack reconciliation" }) 395 ] }), 396 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 397 /* @__PURE__ */ jsxRuntimeExports.jsxs( 398 Button, 399 { 400 variant: "outline", 401 size: "sm", 402 onClick: () => autoPopulate.mutate({ dealerId }), 403 disabled: autoPopulate.isPending || !dealerId, 404 children: [
405 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-4 h-4 mr-1 ${autoPopulate.isPending ? "animate-spin" : ""}` }), 406 "Auto-Populate from Tekion" 407 ] 408 } 409 ), 410 /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { variant: "outline", size: "sm", onClick: () => setShowImport(true), children: [ 411 /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { className: "w-4 h-4 mr-1" }), 412 "Import Deal Pack" 413 ] }), 414 /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { variant: "outline", size: "sm", onClick: exportCSV, children: [ 415 /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "w-4 h-4 mr-1" }), 416 "Export CSV" 417 ] }), 418 /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { size: "sm", onClick: () => setShowAddDeal(true), children: [ 419 /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "w-4 h-4 mr-1" }), 420 "Add Deal" 421 ] }) 422 ] }) 423 ] }), 424 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-3", children: [
425 /* @__PURE__ */ jsxRuntimeExports.jsx( 426 KpiCard, 427 { 428 label: "Total Deals", 429 value: metrics.data?.total ?? 0, 430 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "w-4 h-4" }), 431 onClick: () => setStatusFilter("ALL"), 432 active: statusFilter === "ALL" 433 } 434 ), 435 /* @__PURE__ */ jsxRuntimeExports.jsx( 436 KpiCard, 437 { 438 label: "Rate Over Max", 439 value: metrics.data?.overMax ?? 0, 440 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "w-4 h-4 text-red-500" }), 441 className: "border-red-500/30", 442 valueColor: "text-red-500", 443 onClick: () => setStatusFilter("RATE_OVER_MAX"), 444 active: statusFilter === "RATE_OVER_MAX", 445 tooltip: "Triggered when the actual finance charge exceeds the Affinity Financial legal ceiling. Computed using the 365/360 day-count formula with Newton's method, based on amount financed, term, payment frequency, and vehicle year class rate (Class 1: 10%, Class 2: 11%, Class 3: 15%, Class 4: 17%)." 446 } 447 ),
448 /* @__PURE__ */ jsxRuntimeExports.jsx( 449 KpiCard, 450 { 451 label: "Mismatch", 452 value: metrics.data?.mismatch ?? 0, 453 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-amber-500" }), 454 className: "border-amber-500/30", 455 valueColor: "text-amber-500", 456 onClick: () => setStatusFilter("DEAL_PACK_MISMATCH"), 457 active: statusFilter === "DEAL_PACK_MISMATCH", 458 tooltip: "Triggered when Deal Pack fields don't match Tekion (source of truth) for Affinity Financial deals. Compares: Amount Financed, Down Payment, Term, Payment Frequency, Payment Amount, APR, Vehicle Year, and Finance Charge. Any variance flags the deal for review." 459 } 460 ), 461 /* @__PURE__ */ jsxRuntimeExports.jsx( 462 KpiCard, 463 { 464 label: "Incomplete", 465 value: metrics.data?.incomplete ?? 0, 466 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-4 h-4 text-gray-400" }), 467 onClick: () => setStatusFilter("INCOMPLETE"), 468 active: statusFilter === "INCOMPLETE", 469 tooltip: "Deals missing required Tekion data (Amount Financed, Term, or Vehicle Year) needed to compute the max rate ceiling. Also shows deals without Deal Pack data entered yet." 470 } 471 ),
472 /* @__PURE__ */ jsxRuntimeExports.jsx( 473 KpiCard, 474 { 475 label: "OK", 476 value: metrics.data?.ok ?? 0, 477 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-emerald-500" }), 478 className: "border-emerald-500/30", 479 valueColor: "text-emerald-500", 480 onClick: () => setStatusFilter("OK"), 481 active: statusFilter === "OK", 482 tooltip: "Finance charge is within the legal maximum AND all Deal Pack fields match Tekion. These deals are fully compliant with no data discrepancies." 483 } 484 ), 485 /* @__PURE__ */ jsxRuntimeExports.jsx( 486 KpiCard, 487 { 488 label: "Resolved", 489 value: metrics.data?.resolved ?? 0, 490 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-blue-400" }), 491 valueColor: "text-blue-400" 492 } 493 ), 494 /* @__PURE__ */ jsxRuntimeExports.jsx( 495 KpiCard, 496 { 497 label: "Total Overcharge", 498 value: fmt(metrics.data?.totalOvercharge ?? 0), 499 icon: /* @__PURE__ */ jsxRuntimeExports.jsx(DollarSign, { className: "w-4 h-4 text-red-500" }), 500 className: "border-red-500/20", 501 valueColor: "text-red-500", 502 isAmount: true 503 } 504 ) 505 ] }), 506 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-4", children: [
507 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "border-border/40", children: [ 508 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2", children: [ 509 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-4 h-4 text-indigo-400" }), 510 "Risk Severity" 511 ] }) }), 512 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "pb-4", children: [ 513 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ 514 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 515 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 text-[10px] font-medium text-red-500", children: "CRITICAL" }), 516 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 h-5 bg-muted/30 rounded-full overflow-hidden relative", children: [
517 /* @__PURE__ */ jsxRuntimeExports.jsx( 518 "div", 519 { 520 className: "h-full bg-gradient-to-r from-red-600 to-red-500 rounded-full transition-all duration-500", 521 style: { width: `${filteredAudits.length ? analytics.riskBreakdown.critical / filteredAudits.length * 100 : 0}%` } 522 } 523 ), 524 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] font-bold", children: analytics.riskBreakdown.critical > 0 ? `${analytics.riskBreakdown.critical} ($500+)` : "" }) 525 ] }) 526 ] }), 527 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 528 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 text-[10px] font-medium text-orange-500", children: "HIGH" }), 529 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 h-5 bg-muted/30 rounded-full overflow-hidden relative", children: [
530 /* @__PURE__ */ jsxRuntimeExports.jsx( 531 "div", 532 { 533 className: "h-full bg-gradient-to-r from-orange-600 to-orange-500 rounded-full transition-all duration-500", 534 style: { width: `${filteredAudits.length ? analytics.riskBreakdown.high / filteredAudits.length * 100 : 0}%` } 535 } 536 ), 537 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] font-bold", children: analytics.riskBreakdown.high > 0 ? `${analytics.riskBreakdown.high} ($200-500)` : "" }) 538 ] }) 539 ] }), 540 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 541 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 text-[10px] font-medium text-amber-500", children: "MEDIUM" }), 542 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 h-5 bg-muted/30 rounded-full overflow-hidden relative", children: [
543 /* @__PURE__ */ jsxRuntimeExports.jsx( 544 "div", 545 { 546 className: "h-full bg-gradient-to-r from-amber-600 to-amber-500 rounded-full transition-all duration-500", 547 style: { width: `${filteredAudits.length ? analytics.riskBreakdown.medium / filteredAudits.length * 100 : 0}%` } 548 } 549 ), 550 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] font-bold", children: analytics.riskBreakdown.medium > 0 ? `${analytics.riskBreakdown.medium} ($1-200)` : "" }) 551 ] }) 552 ] }), 553 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 554 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 text-[10px] font-medium text-emerald-500", children: "LOW" }), 555 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 h-5 bg-muted/30 rounded-full overflow-hidden relative", children: [
556 /* @__PURE__ */ jsxRuntimeExports.jsx( 557 "div", 558 { 559 className: "h-full bg-gradient-to-r from-emerald-600 to-emerald-500 rounded-full transition-all duration-500", 560 style: { width: `${filteredAudits.length ? analytics.riskBreakdown.low / filteredAudits.length * 100 : 0}%` } 561 } 562 ), 563 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] font-bold", children: analytics.riskBreakdown.low > 0 ? `${analytics.riskBreakdown.low} (compliant)` : "" }) 564 ] }) 565 ] }) 566 ] }), 567 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 pt-3 border-t border-border/30 grid grid-cols-2 gap-2 text-center", children: [ 568 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 569 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground", children: "Avg APR" }),
570 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold", children: [ 571 analytics.avgApr.toFixed(2), 572 "%" 573 ] }) 574 ] }), 575 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 576 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground", children: "Total Financed" }), 577 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold", children: [ 578 (analytics.totalFinanced / 1e6).toFixed(1), 579 "M" 580 ] }) 581 ] }) 582 ] }) 583 ] }) 584 ] }), 585 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "border-border/40 lg:col-span-2", children: [ 586 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2", children: [
587 /* @__PURE__ */ jsxRuntimeExports.jsx(ChartColumn, { className: "w-4 h-4 text-red-400" }), 588 "Overcharge by Deal Date", 589 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-auto text-[10px] font-normal text-muted-foreground", children: "Last 14 deal dates" }) 590 ] }) }), 591 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { children: analytics.overByDay.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx( 592 ChartContainer, 593 { 594 config: { 595 over: { label: "Overcharge", color: "#ef4444" }, 596 count: { label: "Deals", color: "#6366f1" } 597 }, 598 className: "h-[180px] w-full", 599 children: /* @__PURE__ */ jsxRuntimeExports.jsxs(BarChart, { data: analytics.overByDay, margin: { top: 4, right: 4, left: 0, bottom: 0 }, children: [ 600 /* @__PURE__ */ jsxRuntimeExports.jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "hsl(var(--border))", opacity: 0.3 }), 601 /* @__PURE__ */ jsxRuntimeExports.jsx(XAxis, { dataKey: "date", tick: { fontSize: 10 }, stroke: "hsl(var(--muted-foreground))" }),
602 /* @__PURE__ */ jsxRuntimeExports.jsx(YAxis, { tick: { fontSize: 10 }, stroke: "hsl(var(--muted-foreground))", tickFormatter: (v) => `$${v > 999 ? (v / 1e3).toFixed(0) + "k" : v}` }), 603 /* @__PURE__ */ jsxRuntimeExports.jsx(ChartTooltip, { content: /* @__PURE__ */ jsxRuntimeExports.jsx(ChartTooltipContent, {}) }), 604 /* @__PURE__ */ jsxRuntimeExports.jsx(Bar, { dataKey: "over", radius: [4, 4, 0, 0], name: "Overcharge", children: analytics.overByDay.map((entry, idx) => /* @__PURE__ */ jsxRuntimeExports.jsx(Cell, { fill: entry.over > 500 ? "#dc2626" : entry.over > 200 ? "#f97316" : entry.over > 0 ? "#eab308" : "#22c55e" }, idx)) }) 605 ] }) 606 } 607 ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-[180px] flex items-center justify-center text-muted-foreground text-sm", children: "No overcharge data to display" }) }) 608 ] }) 609 ] }), 610 selectedIds.size > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "border-indigo-500/40 bg-indigo-500/5 animate-in slide-in-from-top-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
611 /* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "secondary", className: "bg-indigo-500/20 text-indigo-300", children: [ 612 selectedIds.size, 613 " selected" 614 ] }), 615 /* @__PURE__ */ jsxRuntimeExports.jsxs( 616 Button, 617 { 618 variant: "outline", 619 size: "sm", 620 className: "gap-1.5 border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10", 621 onClick: () => bulkResolve.mutate({ dealerId, auditIds: Array.from(selectedIds), notes: "Bulk resolved" }), 622 disabled: bulkResolve.isPending, 623 children: [ 624 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-3.5 h-3.5" }), 625 "Resolve Selected" 626 ] 627 } 628 ), 629 /* @__PURE__ */ jsxRuntimeExports.jsxs( 630 Button, 631 { 632 variant: "outline", 633 size: "sm", 634 className: "gap-1.5", 635 onClick: () => { 636 const selectedAudits = filteredAudits.filter((a) => selectedIds.has(a.id)); 637 const headers = ["Status", "Deal #", "Customer", "VIN", "Vehicle", "Amt Financed", "Finance Charge", "Max Allowed", "Over/Under", "Lien Holder"]; 638 const rows = selectedAudits.map((a) => [ 639 a.auditStatus || "", 640 a.externalDealNumber || "", 641 a.customerName || "", 642 a.vin || "", 643 [a.tekVehicleYear, a.vehicleMake, a.vehicleModel].filter(Boolean).join(" "), 644 a.tekAmountFinanced || "", 645 a.tekFinanceCharge || "", 646 a.maxFinanceCharge || "", 647 a.amountOver || "", 648 a.lenderName || "" 649 ]); 650 const csv = [headers.join(","), ...rows.map((r) => r.map((c) => `"${String(c).replace(/"/g, '""')}"`).join(","))].join("\n"); 651 const blob = new Blob([csv], { type: "text/csv" }); 652 const url = URL.createObjectURL(blob); 653 const link = document.createElement("a"); 654 link.href = url; 655 link.download = `maxrate-selected-${selectedIds.size}-deals.csv`; 656 link.click(); 657 URL.revokeObjectURL(url); 658 toast.success(`Exported ${selectedIds.size} selected records`); 659 }, 660 children: [
661 /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "w-3.5 h-3.5" }), 662 "Export Selected" 663 ] 664 } 665 ), 666 /* @__PURE__ */ jsxRuntimeExports.jsxs( 667 Button, 668 { 669 variant: "ghost", 670 size: "sm", 671 className: "ml-auto text-muted-foreground", 672 onClick: () => setSelectedIds(/* @__PURE__ */ new Set()), 673 children: [ 674 /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-3.5 h-3.5 mr-1" }), 675 "Clear Selection" 676 ] 677 } 678 ) 679 ] }) }) }), 680 /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "border-border/40", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-3", children: [ 681 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [ 682 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex-1 min-w-[200px] max-w-sm", children: [ 683 /* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" }),
684 /* @__PURE__ */ jsxRuntimeExports.jsx( 685 Input, 686 { 687 placeholder: "Search customer, deal #, VIN, make/model...", 688 value: searchQuery, 689 onChange: (e) => setSearchQuery(e.target.value), 690 className: "pl-9" 691 } 692 ) 693 ] }), 694 /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: statusFilter, onValueChange: (v) => setStatusFilter(v), children: [ 695 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[200px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Filter by status" }) }), 696 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [ 697 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectItem, { value: "ALL", children: [ 698 "All Statuses (", 699 metrics.data?.total ?? 0, 700 ")" 701 ] }), 702 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectItem, { value: "RATE_OVER_MAX", children: [ 703 "Rate Over Max (", 704 metrics.data?.overMax ?? 0, 705 ")" 706 ] }),
707 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectItem, { value: "DEAL_PACK_MISMATCH", children: [ 708 "Deal Pack Mismatch (", 709 metrics.data?.mismatch ?? 0, 710 ")" 711 ] }), 712 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectItem, { value: "INCOMPLETE", children: [ 713 "Incomplete (", 714 metrics.data?.incomplete ?? 0, 715 ")" 716 ] }), 717 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectItem, { value: "OK", children: [ 718 "OK (", 719 metrics.data?.ok ?? 0, 720 ")" 721 ] }) 722 ] }) 723 ] }), 724 /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: lienHolderFilter, onValueChange: (v) => setLienHolderFilter(v), children: [ 725 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[200px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Filter by lien holder" }) }), 726 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
727 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "ALL", children: "All Lien Holders" }), 728 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "AFFINITY", children: "Affinity Financial Only" }), 729 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "NON_AFFINITY", children: "Non-Affinity (Flagged)" }), 730 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "MISSING", children: "Missing Lien Holder" }) 731 ] }) 732 ] }), 733 /* @__PURE__ */ jsxRuntimeExports.jsxs( 734 Button, 735 { 736 variant: showAdvancedFilters ? "secondary" : "outline", 737 size: "sm", 738 className: "gap-1.5", 739 onClick: () => setShowAdvancedFilters(!showAdvancedFilters), 740 children: [ 741 /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersHorizontal, { className: "w-3.5 h-3.5" }), 742 "Filters", 743 (resolvedFilter !== "ALL" || vehicleTypeFilter !== "ALL" || minAmountOver || dateFrom || dateTo || termRange[0] > 1 || termRange[1] < 300) && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "secondary", className: "text-[9px] px-1 py-0 ml-1 bg-indigo-500/20 text-indigo-300", children: [resolvedFilter !== "ALL", vehicleTypeFilter !== "ALL", !!minAmountOver, !!dateFrom || !!dateTo, termRange[0] > 1 || termRange[1] < 300].filter(Boolean).length }) 744 ] 745 } 746 ),
747 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground ml-auto", children: [ 748 "Showing ", 749 filteredAudits.length, 750 " of ", 751 audits.data?.length ?? 0, 752 " deals" 753 ] }) 754 ] }), 755 showAdvancedFilters && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 pt-3 border-t border-border/30 space-y-3", children: [ 756 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [ 757 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [ 758 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-[10px] text-muted-foreground uppercase", children: "Resolution" }), 759 /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: resolvedFilter, onValueChange: (v) => setResolvedFilter(v), children: [ 760 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[150px] h-8 text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, {}) }),
761 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [ 762 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "ALL", children: "All" }), 763 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "UNRESOLVED", children: "Unresolved" }), 764 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "RESOLVED", children: "Resolved" }) 765 ] }) 766 ] }) 767 ] }), 768 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [ 769 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-[10px] text-muted-foreground uppercase", children: "Vehicle Type" }), 770 /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: vehicleTypeFilter, onValueChange: (v) => setVehicleTypeFilter(v), children: [ 771 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[130px] h-8 text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, {}) }),
772 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [ 773 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "ALL", children: "All" }), 774 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "NEW", children: "New" }), 775 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "USED", children: "Used" }) 776 ] }) 777 ] }) 778 ] }), 779 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [ 780 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-[10px] text-muted-foreground uppercase", children: "Min $ Over Max" }), 781 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [ 782 /* @__PURE__ */ jsxRuntimeExports.jsx(DollarSign, { className: "absolute left-2 top-1/2 -translate-y-1/2 w-3 h-3 text-muted-foreground" }), 783 /* @__PURE__ */ jsxRuntimeExports.jsx( 784 Input, 785 { 786 type: "number", 787 min: 0, 788 placeholder: "0", 789 value: minAmountOver, 790 onChange: (e) => setMinAmountOver(e.target.value), 791 className: "w-[100px] h-8 text-xs pl-6" 792 } 793 ) 794 ] }) 795 ] }),
796 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [ 797 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-[10px] text-muted-foreground uppercase", children: "Deal Date From" }), 798 /* @__PURE__ */ jsxRuntimeExports.jsx( 799 Input, 800 { 801 type: "date", 802 value: dateFrom, 803 onChange: (e) => setDateFrom(e.target.value), 804 className: "w-[140px] h-8 text-xs" 805 } 806 ) 807 ] }), 808 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [ 809 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-[10px] text-muted-foreground uppercase", children: "Deal Date To" }), 810 /* @__PURE__ */ jsxRuntimeExports.jsx( 811 Input, 812 { 813 type: "date", 814 value: dateTo, 815 onChange: (e) => setDateTo(e.target.value), 816 className: "w-[140px] h-8 text-xs" 817 } 818 ) 819 ] }), 820 (resolvedFilter !== "ALL" || vehicleTypeFilter !== "ALL" || minAmountOver || dateFrom || dateTo || termRange[0] > 1 || termRange[1] < 300) && /* @__PURE__ */ jsxRuntimeExports.jsxs( 821 Button, 822 { 823 variant: "ghost", 824 size: "sm", 825 className: "h-8 text-xs text-muted-foreground hover:text-foreground gap-1 mt-auto", 826 onClick: () => { 827 setResolvedFilter("ALL"); 828 setVehicleTypeFilter("ALL"); 829 setMinAmountOver(""); 830 setDateFrom(""); 831 setDateTo(""); 832 setTermRange([1, 300]); 833 }, 834 children: [
835 /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-3 h-3" }), 836 " Clear All" 837 ] 838 } 839 ) 840 ] }), 841 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [ 842 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 843 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-[10px] text-muted-foreground uppercase", children: "Term Range (months)" }), 844 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-muted-foreground", children: [ 845 termRange[0], 846 " \\u2013 ", 847 termRange[1], 848 " ", 849 termRange[1] > 95 ? "(incl. biweekly)" : "(monthly)" 850 ] }) 851 ] }), 852 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 853 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground w-6", children: "1" }),
854 /* @__PURE__ */ jsxRuntimeExports.jsx( 855 Slider, 856 { 857 value: termRange, 858 onValueChange: (v) => setTermRange(v), 859 min: 1, 860 max: 300, 861 step: 1, 862 className: "flex-1" 863 } 864 ), 865 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground w-8", children: "300" }) 866 ] }), 867 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4 text-[10px] text-muted-foreground", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Monthly: 1\\u201395 | Biweekly: 1\\u2013300" }) }) 868 ] }) 869 ] }) 870 ] }) }), 871 /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-0", children: [ 872 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-sm", children: [
873 /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { className: "sticky top-0 z-10 bg-card shadow-[0_1px_3px_rgba(0,0,0,0.15)]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border/50 bg-muted/40", children: [ 874 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "w-10 px-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 875 Checkbox, 876 { 877 checked: allPageSelected ? true : somePageSelected ? "indeterminate" : false, 878 onCheckedChange: toggleSelectAll, 879 "aria-label": "Select all on this page" 880 } 881 ) }), 882 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-3 font-medium whitespace-nowrap", children: "Status" }), 883 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-3 font-medium whitespace-nowrap", children: "Deal #" }), 884 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-3 font-medium whitespace-nowrap", children: "Customer" }),
885 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-3 font-medium whitespace-nowrap", children: "Vehicle" }), 886 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-3 font-medium whitespace-nowrap", children: "Mileage" }), 887 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-right p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 888 if (sortField === "amtFinanced") { 889 setSortDir((d) => d === "asc" ? "desc" : "asc"); 890 } else { 891 setSortField("amtFinanced"); 892 setSortDir("desc"); 893 } 894 }, children: [ 895 "Amt Financed ", 896 sortField === "amtFinanced" && (sortDir === "asc" ? "â" : "â") 897 ] }), 898 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-center p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 899 if (sortField === "term") { 900 setSortDir((d) => d === "asc" ? "desc" : "asc"); 901 } else { 902 setSortField("term"); 903 setSortDir("desc"); 904 } 905 }, children: [ 906 "Term ", 907 sortField === "term" && (sortDir === "asc" ? "â" : "â") 908 ] }),
909 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-right p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 910 if (sortField === "apr") { 911 setSortDir((d) => d === "asc" ? "desc" : "asc"); 912 } else { 913 setSortField("apr"); 914 setSortDir("desc"); 915 } 916 }, children: [ 917 "APR ", 918 sortField === "apr" && (sortDir === "asc" ? "â" : "â") 919 ] }), 920 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-right p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 921 if (sortField === "financeChg") { 922 setSortDir((d) => d === "asc" ? "desc" : "asc"); 923 } else { 924 setSortField("financeChg"); 925 setSortDir("desc"); 926 } 927 }, children: [ 928 "Finance Chg ", 929 sortField === "financeChg" && (sortDir === "asc" ? "â" : "â") 930 ] }),
931 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-3 font-medium whitespace-nowrap", children: "Max Allowed" }), 932 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-right p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 933 if (sortField === "overUnder") { 934 setSortDir((d) => d === "asc" ? "desc" : "asc"); 935 } else { 936 setSortField("overUnder"); 937 setSortDir("desc"); 938 } 939 }, children: [ 940 "Over/Under ", 941 sortField === "overUnder" && (sortDir === "asc" ? "â" : "â") 942 ] }), 943 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-left p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 944 if (sortField === "lienHolder") { 945 setSortDir((d) => d === "asc" ? "desc" : "asc"); 946 } else { 947 setSortField("lienHolder"); 948 setSortDir("asc"); 949 } 950 }, children: [ 951 "Lien Holder ", 952 sortField === "lienHolder" && (sortDir === "asc" ? "â" : "â") 953 ] }),
954 /* @__PURE__ */ jsxRuntimeExports.jsxs("th", { className: "text-left p-3 font-medium whitespace-nowrap cursor-pointer hover:text-foreground transition-colors", onClick: () => { 955 if (sortField === "dealDate") { 956 setSortDir((d) => d === "asc" ? "desc" : "asc"); 957 } else { 958 setSortField("dealDate"); 959 setSortDir("desc"); 960 } 961 }, children: [ 962 "Deal Date ", 963 sortField === "dealDate" && (sortDir === "asc" ? "â" : "â") 964 ] }), 965 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-center p-3 font-medium whitespace-nowrap", children: "View" }) 966 ] }) }), 967 /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: paginatedAudits.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("tr", { children: /* @__PURE__ */ jsxRuntimeExports.jsx("td", { colSpan: 15, className: "text-center py-12 text-muted-foreground", children: audits.isLoading ? "Loading..." : "No Affinity Financial deals found. Click 'Auto-Populate from Tekion' to pull deals with Affinity Financial as lien holder." }) }) : paginatedAudits.map((audit) => { 968 const vehicle = [audit.tekVehicleYear, audit.vehicleMake, audit.vehicleModel].filter(Boolean).join(" "); 969 const mileage = audit.vehicleOdometer ? audit.vehicleOdometer.toLocaleString() : null; 970 const apr = audit.tekApr ? audit.tekApr ?? 0 : null; 971 const dealDate = audit.dealDate ? new Date(audit.dealDate).toLocaleDateString("en-US", { month: "short", day: "
971numeric", year: "2-digit" }) : null; 972 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 973 "tr", 974 { 975 className: `border-b border-border/30 cursor-pointer transition-all duration-150 group hover:bg-muted/40 hover:shadow-[inset_0_0_0_1px_rgba(99,102,241,0.15)] ${audit.auditStatus === "RATE_OVER_MAX" ? "bg-red-500/10 border-l-2 border-l-red-500 hover:bg-red-500/15" : audit.auditStatus === "DEAL_PACK_MISMATCH" ? "bg-amber-500/8 border-l-2 border-l-amber-500 hover:bg-amber-500/12" : "hover:bg-muted/40"} ${selectedIds.has(audit.id) ? "bg-indigo-500/10 hover:bg-indigo-500/15" : ""}`, 976 onClick: () => setSelectedAuditId(audit.id), 977 children: [ 978 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-3", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsx( 979 Checkbox, 980 { 981 checked: selectedIds.has(audit.id), 982 onCheckedChange: () => toggleSelectOne(audit.id), 983 "aria-label": `Select ${audit.customerName || "deal"}` 984 } 985 ) }),
986 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [ 987 statusIcon(audit.auditStatus), 988 /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: `text-[10px] px-1.5 py-0 ${statusColor(audit.auditStatus)}`, children: audit.auditStatus === "RATE_OVER_MAX" ? "OVER" : audit.auditStatus === "DEAL_PACK_MISMATCH" ? "MISMATCH" : audit.auditStatus === "INCOMPLETE" ? "INC" : "OK" }) 989 ] }) }), 990 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3", children: audit.externalDealNumber ? /* @__PURE__ */ jsxRuntimeExports.jsxs( 991 "a", 992 { 993 href: `https://app.tekioncloud.com/sales/deals/details/${audit.tekionDealId}`, 994 target: "_blank", 995 rel: "noopener noreferrer", 996 className: "text-indigo-400 hover:underline font-mono text-xs", 997 onClick: (e) => e.stopPropagation(), 998 children: [ 999 audit.externalDealNumber,
1000 /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "w-3 h-3 inline ml-0.5" }) 1001 ] 1002 } 1003 ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground text-xs", children: "â" }) }), 1004 /* @__PURE__ */ jsxRuntimeExports.jsxs("td", { className: "p-3", children: [ 1005 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium text-xs", children: audit.customerName || "â" }), 1006 audit.vin && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground font-mono", children: audit.vin }) 1007 ] }), 1008 /* @__PURE__ */ jsxRuntimeExports.jsxs("td", { className: "p-3", children: [ 1009 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium", children: vehicle || "â" }), 1010 audit.vehicleTrim && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground", children: audit.vehicleTrim }), 1011 audit.vehicleStockId && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] text-muted-foreground", children: [ 1012 "Stk# ", 1013 audit.vehicleStockId, 1014 audit.vehicleStockType && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-[9px] px-1 py-0 ml-1 border-border/50", children: audit.vehicleStockType === "NEW" ? "N" : "U" }) 1015 ] }) 1016 ] }),
1017 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-right font-mono text-xs", children: mileage ? `${mileage} mi` : "â" }), 1018 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-right font-mono text-xs", children: editingCell?.id === audit.id && editingCell?.field === "tekAmountFinanced" ? /* @__PURE__ */ jsxRuntimeExports.jsx("input", { autoFocus: true, type: "number", className: "w-20 bg-background border border-indigo-500 rounded px-1 py-0.5 text-xs font-mono text-right", value: editValue, onChange: (e) => setEditValue(e.target.value), onBlur: () => { 1019 const v = parseFloat(editValue); 1020 if (!isNaN(v) && v !== audit.tekAmountFinanced) { 1021 updateInline.mutate({ dealerId, auditId: audit.id, tekAmountFinanced: Math.round(v) }); 1022 } else { 1023 setEditingCell(null); 1024 } 1025 }, onKeyDown: (e) => { 1026 if (e.key === "Enter") e.target.blur(); 1027 if (e.key === "Escape") setEditingCell(null); 1028 }, onClick: (e) => e.stopPropagation() }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "cursor-text hover:bg-muted/40 rounded px-1 py-0.5 -mx-1 transition-colors", onDoubleClick: (e) => { 1029 e.stopPropagation(); 1030 setEditingCell({ id: audit.id, field: "tekAmountFinanced" }); 1031 setEditValue(audit.tekAmountFinanced?.toString() || ""); 1032 }, title: "Double-click to edit", children: fmt(audit.tekAmountFinanced) }) }),
1033 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-center font-mono text-xs", children: editingCell?.id === audit.id && editingCell?.field === "tekTerm" ? /* @__PURE__ */ jsxRuntimeExports.jsx("input", { autoFocus: true, type: "number", className: "w-12 bg-background border border-indigo-500 rounded px-1 py-0.5 text-xs font-mono text-center", value: editValue, onChange: (e) => setEditValue(e.target.value), onBlur: () => { 1034 const v = parseInt(editValue); 1035 if (!isNaN(v) && v !== audit.tekTerm) { 1036 updateInline.mutate({ dealerId, auditId: audit.id, tekTerm: v }); 1037 } else { 1038 setEditingCell(null); 1039 } 1040 }, onKeyDown: (e) => { 1041 if (e.key === "Enter") e.target.blur(); 1042 if (e.key === "Escape") setEditingCell(null); 1043 }, onClick: (e) => e.stopPropagation() }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "cursor-text hover:bg-muted/40 rounded px-1 py-0.5 -mx-1 transition-colors", onDoubleClick: (e) => { 1044 e.stopPropagation(); 1045 setEditingCell({ id: audit.id, field: "tekTerm" }); 1046 setEditValue(audit.tekTerm?.toString() || ""); 1047 }, title: "Double-click to edit", children: audit.tekTerm ? `${audit.tekTerm}mo` : "â" }) }),
1048 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-right font-mono text-xs", children: editingCell?.id === audit.id && editingCell?.field === "tekApr" ? /* @__PURE__ */ jsxRuntimeExports.jsx("input", { autoFocus: true, type: "number", step: "0.01", className: "w-14 bg-background border border-indigo-500 rounded px-1 py-0.5 text-xs font-mono text-right", value: editValue, onChange: (e) => setEditValue(e.target.value), onBlur: () => { 1049 const v = parseFloat(editValue); 1050 if (!isNaN(v) && v !== apr) { 1051 updateInline.mutate({ dealerId, auditId: audit.id, tekApr: v }); 1052 } else { 1053 setEditingCell(null); 1054 } 1055 }, onKeyDown: (e) => { 1056 if (e.key === "Enter") e.target.blur(); 1057 if (e.key === "Escape") setEditingCell(null); 1058 }, onClick: (e) => e.stopPropagation() }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "cursor-text hover:bg-muted/40 rounded px-1 py-0.5 -mx-1 transition-colors", onDoubleClick: (e) => { 1059 e.stopPropagation(); 1060 setEditingCell({ id: audit.id, field: "tekApr" }); 1061 setEditValue(apr?.toString() || ""); 1062 }, title: "Double-click to edit", children: apr != null ? `${apr.toFixed(2)}%` : "â" }) }),
1063 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: `p-3 text-right font-mono text-xs ${audit.auditStatus === "RATE_OVER_MAX" ? "text-red-500 font-bold" : ""}`, children: editingCell?.id === audit.id && editingCell?.field === "tekFinanceCharge" ? /* @__PURE__ */ jsxRuntimeExports.jsx("input", { autoFocus: true, type: "number", className: "w-20 bg-background border border-indigo-500 rounded px-1 py-0.5 text-xs font-mono text-right", value: editValue, onChange: (e) => setEditValue(e.target.value), onBlur: () => { 1064 const v = parseFloat(editValue); 1065 if (!isNaN(v) && v !== audit.tekFinanceCharge) { 1066 updateInline.mutate({ dealerId, auditId: audit.id, tekFinanceCharge: Math.round(v) }); 1067 } else { 1068 setEditingCell(null); 1069 } 1070 }, onKeyDown: (e) => { 1071 if (e.key === "Enter") e.target.blur(); 1072 if (e.key === "Escape") setEditingCell(null); 1073 }, onClick: (e) => e.stopPropagation() }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "cursor-text hover:bg-muted/40 rounded px-1 py-0.5 -mx-1 transition-colors", onDoubleClick: (e) => { 1074 e.stopPropagation(); 1075 setEditingCell({ id: audit.id, field: "tekFinanceCharge" }); 1076 setEditValue(audit.tekFinanceCharge?.toString() || ""); 1077 }, title: "Double-click to edit", children: fmt(audit.tekFinanceCharge) }) }),
1078 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-right font-mono text-xs", children: fmt(audit.maxFinanceCharge) }), 1079 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: `p-3 text-right font-mono text-xs font-bold ${(audit.amountOver ?? 0) > 0 ? "text-red-500" : "text-emerald-500"}`, children: (audit.amountOver ?? 0) > 0 ? `+${fmt(audit.amountOver)}` : audit.maxFinanceCharge ? "â" : "â" }), 1080 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-xs whitespace-nowrap", children: editingCell?.id === audit.id && editingCell?.field === "lenderName" ? /* @__PURE__ */ jsxRuntimeExports.jsx( 1081 "input", 1082 { 1083 autoFocus: true, 1084 className: "w-24 bg-background border border-indigo-500 rounded px-1 py-0.5 text-xs font-mono", 1085 value: editValue, 1086 onChange: (e) => setEditValue(e.target.value), 1087 onBlur: () => { 1088 if (editValue !== (audit.lenderName || "")) { 1089 updateInline.mutate({ dealerId, auditId: audit.id, lenderName: editValue }); 1090 } else { 1091 setEditingCell(null); 1092 } 1093 }, 1094 onKeyDown: (e) => { 1095 if (e.key === "Enter") e.target.blur(); 1096 if (e.key === "Escape") setEditingCell(null); 1097 }, 1098 onClick: (e) => e.stopPropagation() 1099 } 1100 ) : /* @__PURE__ */ jsxRuntimeExports.jsx( 1101 "span", 1102 { 1103 className: `cursor-text hover:bg-muted/40 rounded px-1 py-0.5 -mx-1 transition-colors inline-flex items-center gap-1 ${!audit.lenderName ? "text-muted-foreground" : audit.lenderName.toUpperCase().includes("AFFINITY") ? "text-emerald-400" : "text-red-400 font-semibold"}`, 1104 onDoubleClick: (e) => { 1105 e.stopPropagation(); 1106 setEditingCell({ id: audit.id, field: "lenderName" }); 1107 setEditValue(audit.lenderName || ""); 1108 }, 1109 title: "Double-click to edit", 1110 children: !audit.lenderName ? "â" : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 1111 !audit.lenderName.toUpperCase().includes("AFFINITY") && /* @__P
1111URE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-3 h-3 text-red-400 shrink-0" }), 1112 audit.lenderName 1113 ] }) 1114 } 1115 ) }), 1116 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-xs text-muted-foreground whitespace-nowrap", children: dealDate || "â" }), 1117 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "ghost", size: "sm", className: "h-7 w-7 p-0", onClick: (e) => { 1118 e.stopPropagation(); 1119 setSelectedAuditId(audit.id); 1120 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "w-3.5 h-3.5" }) }) }) 1121 ] 1122 }, 1123 audit.id 1124 ); 1125 }) }) 1126 ] }) }), 1127 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-6 px-4 py-2 border-t border-border/30 bg-muted/5", children: [
1128 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [ 1129 /* @__PURE__ */ jsxRuntimeExports.jsx(DollarSign, { className: "w-3.5 h-3.5 text-muted-foreground" }), 1130 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Total Financed:" }), 1131 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold", children: fmt(analytics.totalFinanced) }) 1132 ] }), 1133 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [ 1134 /* @__PURE__ */ jsxRuntimeExports.jsx(Percent, { className: "w-3.5 h-3.5 text-muted-foreground" }), 1135 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Total Finance Chg:" }), 1136 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold", children: fmt(analytics.totalFinanceChg) }) 1137 ] }), 1138 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
1139 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { className: "w-3.5 h-3.5 text-red-400" }), 1140 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Total Overcharge:" }), 1141 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-red-500", children: fmt(analytics.totalOver) }) 1142 ] }), 1143 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 ml-auto", children: [ 1144 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Avg APR:" }), 1145 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold", children: [ 1146 analytics.avgApr.toFixed(2), 1147 "%" 1148 ] }) 1149 ] }) 1150 ] }), 1151 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-t border-border/30 bg-muted/10", children: [ 1152 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1153 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground", children: "Rows per page" }), 1154 /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: String(pageSize), onValueChange: (v) => { 1155 setPageSize(Number(v)); 1156 setCurrentPage(1); 1157 }, children: [ 1158 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "h-8 w-[70px] text-xs bg-background border-border/50", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, {}) }), 1159 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [ 1160 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "25", children: "25" }), 1161 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "50", children: "50" }), 1162 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "100", children: "100" }) 1163 ] }) 1164 ] }) 1165 ] }), 1166 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
1167 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground mr-2", children: filteredAudits.length === 0 ? "0 of 0" : `${startIndex + 1}â${endIndex} of ${filteredAudits.length}` }), 1168 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", size: "icon", className: "size-8 border-border/50", onClick: () => setCurrentPage(1), disabled: safeCurrentPage <= 1, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsLeft, { className: "size-4" }) }), 1169 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", size: "icon", className: "size-8 border-border/50", onClick: () => setCurrentPage((p) => Math.max(1, p - 1)), disabled: safeCurrentPage <= 1, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "size-4" }) }), 1170 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-medium px-2", children: [ 1171 "Page ", 1172 safeCurrentPage, 1173 " of ", 1174 totalPages 1175 ] }),
1176 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", size: "icon", className: "size-8 border-border/50", onClick: () => setCurrentPage((p) => Math.min(totalPages, p + 1)), disabled: safeCurrentPage >= totalPages, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4" }) }), 1177 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", size: "icon", className: "size-8 border-border/50", onClick: () => setCurrentPage(totalPages), disabled: safeCurrentPage >= totalPages, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsRight, { className: "size-4" }) }) 1178 ] }) 1179 ] }) 1180 ] }) }), 1181 /* @__PURE__ */ jsxRuntimeExports.jsx( 1182 AddDealDialog, 1183 { 1184 open: showAddDeal, 1185 onOpenChange: setShowAddDeal, 1186 dealerId, 1187 onSuccess: () => { 1188 audits.refetch(); 1189 metrics.refetch(); 1190 } 1191 } 1192 ), 1193 /* @__PURE__ */ jsxRuntimeExports.jsx( 1194 ImportDealPackDialog, 1195 { 1196 open: showImport, 1197 onOpenChange: setShowImport, 1198 dealerId, 1199 onSuccess: () => { 1200 audits.refetch(); 1201 metrics.refetch(); 1202 } 1203 } 1204 ), 1205 /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open: selectedAuditId != null, onOpenChange: (open) => { 1206 if (!open) setSelectedAuditId(null); 1207 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogContent, { className: "max-w-4xl max-h-[90vh] overflow-y-auto", children: detail.isLoading || !detail.data ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-12 text-muted-foreground", children: "Loading deal breakdown..." }) : (() => { 1208 const d = detail.data; 1209 const ar = d.auditResult; 1210 const vehicle = [d.tekVehicleYear, d.vehicleMake, d.vehicleModel, d.vehicleTrim].filter(Boolean).join(" "); 1211 const currentIdx = filteredAudits.findIndex((a) => a.id === selectedAuditId); 1212 const hasPrev = currentIdx > 0; 1213 const hasNext = currentIdx < filteredAudits.length - 1; 1214 const goToPrev = () => { 1215 if (hasPrev) setSelectedAuditId(filteredAudits[currentIdx - 1].id); 1216 }; 1217 const goToNext = () => { 1218 if (hasNext) setSelectedAuditId(filteredAudits[currentIdx + 1].id); 1219 }; 1220 return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1221 /* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 1222 /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogTitle, { className: "flex items-center gap-3", children: [ 1223 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-5 h-5 text-indigo-400" }), 1224 "Deal Breakdown: ", 1225 d.externalDealNumber || d.tekionDealId || `#${d.id}`, 1226 /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: `text-xs px-2 py-0.5 ${statusColor(ar.status)}`, children: ar.status === "RATE_OVER_MAX" ? "RATE OVER MAX" : ar.status === "DEAL_PACK_MISMATCH" ? "MISMATCH" : ar.status === "INCOMPLETE" ? "INCOMPLETE" : "OK" }) 1227 ] }), 1228 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 mr-8", children: [ 1229 /* @__PURE__ */ jsxRuntimeExports.jsx( 1230 Button, 1231 { 1232 variant: "outline", 1233 size: "sm", 1234 className: "h-8 w-8 p-0", 1235 disabled: !hasPrev, 1236 onClick: goToPrev, 1237 title: "Previous deal (\\u2190)", 1238 children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "w-4 h-4" }) 1239 } 1240 ),
1241 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-muted-foreground px-2 whitespace-nowrap", children: [ 1242 currentIdx + 1, 1243 " of ", 1244 filteredAudits.length 1245 ] }), 1246 /* @__PURE__ */ jsxRuntimeExports.jsx( 1247 Button, 1248 { 1249 variant: "outline", 1250 size: "sm", 1251 className: "h-8 w-8 p-0", 1252 disabled: !hasNext, 1253 onClick: goToNext, 1254 title: "Next deal (\\u2192)", 1255 children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-4 h-4" }) 1256 } 1257 ) 1258 ] }) 1259 ] }) }), 1260 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 mt-4", children: [ 1261 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-border/50 p-4 space-y-3", children: [ 1262 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide", children: "Customer & Vehicle" }),
1263 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [ 1264 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1265 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Customer" }), 1266 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: d.customerName || "â" }) 1267 ] }), 1268 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1269 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Vehicle" }), 1270 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: vehicle || "â" }) 1271 ] }), 1272 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1273 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "VIN" }),
1274 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-mono", children: d.vin || "â" }) 1275 ] }), 1276 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1277 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Mileage" }), 1278 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: d.vehicleOdometer ? `${d.vehicleOdometer.toLocaleString()} mi` : "â" }) 1279 ] }), 1280 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1281 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Stock #" }), 1282 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm font-medium", children: [ 1283 d.vehicleStockId || "â", 1284 " ", 1285 d.vehicleStockType && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-[9px] px-1 py-0 ml-1", children: d.vehicleStockType === "NEW" ? "New" : "Used" }) 1286 ] }) 1287 ] }),
1288 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1289 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Lien Holder" }), 1290 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-indigo-400", children: d.lenderName || "â" }) 1291 ] }), 1292 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1293 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Deal Date" }), 1294 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: d.dealDate ? new Date(d.dealDate).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : "â" }) 1295 ] }), 1296 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1297 /* @__P
1297URE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Deal Status" }), 1298 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: d.dealStatus || "â" }) 1299 ] }) 1300 ] }) 1301 ] }), 1302 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-border/50 p-4 space-y-3", children: [ 1303 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide", children: "Financial Details" }), 1304 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [ 1305 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1306 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Amount Financed" }), 1307 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold", children: fmt(d.tekAmountFinanced) }) 1308 ] }),
1309 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1310 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Down Payment" }), 1311 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: fmt(d.tekDownPayment) }) 1312 ] }), 1313 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1314 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Term" }), 1315 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold", children: d.tekTerm ? `${d.tekTerm} months` : "â" }) 1316 ] }), 1317 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1318 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Payment Frequency" }),
1319 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold capitalize text-indigo-400", children: d.tekFrequency || "monthly" }) 1320 ] }), 1321 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1322 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "Payment Amount" }), 1323 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: fmt(d.tekPaymentAmount) }) 1324 ] }), 1325 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1326 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground", children: "APR" }), 1327 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold", children: d.tekApr ? `${parseFloat(String(d.tekApr)).toFixed(2)}%` : "â" }) 1328 ] }), 1329 /* @__P
1329URE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between border-t border-border/30 pt-2 mt-2", children: [ 1330 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground font-semibold", children: "Finance Charge" }), 1331 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-sm font-bold ${ar.status === "RATE_OVER_MAX" ? "text-red-500" : "text-emerald-500"}`, children: fmt(d.tekFinanceCharge) }) 1332 ] }) 1333 ] }) 1334 ] }) 1335 ] }), 1336 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `rounded-lg border p-4 mt-4 ${ar.status === "RATE_OVER_MAX" ? "border-red-500/50 bg-red-500/5" : "border-border/50"}`, children: [ 1337 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3", children: "Max Rate Compliance" }), 1338 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [
1339 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1340 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground", children: "Vehicle Class" }), 1341 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold", children: [ 1342 "Class ", 1343 ar.maxRateDetails.vehicleClassLabel 1344 ] }), 1345 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground", children: [ 1346 "Rate: ", 1347 (ar.maxRateDetails.vehicleYearRate * 100).toFixed(0), 1348 "%" 1349 ] }) 1350 ] }), 1351 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1352 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground", children: "Term" }), 1353 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold", children: [ 1354 ar.maxRateDetails.termInMonths, 1355 " months" 1356 ] }),
1357 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground", children: [ 1358 ar.maxRateDetails.termInYears.toFixed(1), 1359 " years" 1360 ] }) 1361 ] }), 1362 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1363 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground", children: "Max Finance Charge" }), 1364 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-indigo-400", children: fmt(ar.maxFinanceCharge) }) 1365 ] }), 1366 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1367 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground", children: "Over / Under" }), 1368 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `font-bold ${ar.amountOver > 0 ? "text-red-500" : "text-emerald-500"}`, children: ar.amountOver > 0 ? `+${fmt(ar.amountOver)} OVER` : ar.maxFinanceCharge ? "â Within Limit" : "â" }) 1369 ] }) 1370 ] }) 1371 ] }), 1372 ar.fieldComparisons.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-border/50 p-4 mt-4", children: [
1373 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3", children: "Tekion vs Deal Pack Comparison" }), 1374 /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-sm", children: [ 1375 /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border/50", children: [ 1376 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-2 font-medium text-xs", children: "Field" }), 1377 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-2 font-medium text-xs", children: "Tekion" }), 1378 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-2 font-medium text-xs", children: "Deal Pack" }), 1379 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-2 font-medium text-xs", children: "Variance" }), 1380 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-center p-2 font-medium text-xs", children: "Match" }) 1381 ] }) }),
1382 /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: ar.fieldComparisons.map((fc) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: `border-b border-border/20 ${!fc.matches ? "bg-red-500/5" : ""}`, children: [ 1383 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 font-medium text-xs", children: fc.field }), 1384 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-right font-mono text-xs", children: typeof fc.tekionValue === "number" ? fc.field.includes("APR") ? fmtPct(fc.tekionValue) : fc.field.includes("Year") || fc.field === "Term" ? fc.tekionValue : fmt(fc.tekionValue) : fc.tekionValue ?? "â" }), 1385 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-right font-mono text-xs", children: typeof fc.dealPackValue === "number" ? fc.field.includes("APR") ? fmtPct(fc.dealPackValue) : fc.field.includes("Year") || fc.field === "Term" ? fc.dealPackValue : fmt(fc.dealPackValue) : fc.dealPackValue ?? "â" }), 1386 /* @__P
1386URE__ */ jsxRuntimeExports.jsx("td", { className: `p-2 text-right font-mono text-xs ${!fc.matches ? "text-red-500 font-bold" : ""}`, children: fc.variance != null ? typeof fc.variance === "number" ? fc.field.includes("APR") ? (fc.variance > 0 ? "+" : "") + fc.variance.toFixed(3) : fc.field.includes("Year") || fc.field === "Term" ? (fc.variance > 0 ? "+" : "") + fc.variance : (fc.variance > 0 ? "+" : "") + fmt(fc.variance) : fc.variance : "â" }), 1387 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-center", children: fc.matches ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-emerald-500 mx-auto" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "w-4 h-4 text-red-500 mx-auto" }) }) 1388 ] }, fc.field)) }) 1389 ] }) 1390 ] }), 1391 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-border/50 p-4 mt-4", children: [ 1392 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3 flex items-center gap-2", children: [
1393 /* @__PURE__ */ jsxRuntimeExports.jsx(History, { className: "w-4 h-4" }), 1394 "Audit History & Context" 1395 ] }), 1396 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ 1397 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative pl-6 space-y-3", children: [ 1398 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-[9px] top-1 bottom-1 w-px bg-border/60" }), 1399 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex items-start gap-3", children: [ 1400 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-[-15px] top-1 w-3 h-3 rounded-full bg-indigo-500 border-2 border-background z-10" }), 1401 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [ 1402 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium", children: "Record Created" }), 1403 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
1404 /* @__PURE__ */ jsxRuntimeExports.jsx(CalendarDays, { className: "w-3 h-3" }), 1405 d.createdAt ? new Date(d.createdAt).toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit" }) : "â" 1406 ] }), 1407 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: "Auto-populated from Tekion API sync" }) 1408 ] }) 1409 ] }), 1410 d.updatedAt && d.createdAt && new Date(d.updatedAt).getTime() - new Date(d.createdAt).getTime() > 6e4 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex items-start gap-3", children: [ 1411 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-[-15px] top-1 w-3 h-3 rounded-full bg-amber-500 border-2 border-background z-10" }), 1412 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [ 1413 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium", children: "Last Updated" }),
1414 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [ 1415 /* @__PURE__ */ jsxRuntimeExports.jsx(CalendarDays, { className: "w-3 h-3" }), 1416 new Date(d.updatedAt).toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit" }) 1417 ] }), 1418 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: "Fields modified via inline edit or re-sync" }) 1419 ] }) 1420 ] }), 1421 d.resolved && d.resolvedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex items-start gap-3", children: [ 1422 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-[-15px] top-1 w-3 h-3 rounded-full bg-emerald-500 border-2 border-background z-10" }), 1423 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
1424 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium text-emerald-400", children: "Resolved" }), 1425 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [ 1426 /* @__PURE__ */ jsxRuntimeExports.jsx(CalendarDays, { className: "w-3 h-3" }), 1427 new Date(d.resolvedAt).toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit" }) 1428 ] }), 1429 d.notes && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1.5 p-2 rounded bg-emerald-500/5 border border-emerald-500/20", children: [ 1430 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-1 mb-1", children: [ 1431 /* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "w-3 h-3" }), 1432 " Resolution Notes" 1433 ] }),
1434 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: d.notes }) 1435 ] }) 1436 ] }) 1437 ] }) 1438 ] }), 1439 d.mismatchedFields && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 pt-3 border-t border-border/30", children: [ 1440 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs font-medium text-amber-400 mb-1.5 flex items-center gap-1", children: [ 1441 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-3 h-3" }), 1442 "Flagged Fields" 1443 ] }), 1444 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1.5", children: d.mismatchedFields.split(",").map((field) => /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-[10px] px-1.5 py-0 border-amber-500/30 text-amber-400", children: field.trim() }, field.trim())) }) 1445 ] }), 1446 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 pt-3 border-t border-border/30 grid grid-cols-2 md:grid-cols-4 gap-3", children: [
1447 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1448 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground uppercase", children: "Audit ID" }), 1449 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs font-mono", children: [ 1450 "#", 1451 d.id 1452 ] }) 1453 ] }), 1454 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1455 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground uppercase", children: "Tekion Deal ID" }), 1456 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-mono", children: d.tekionDealId || "â" }) 1457 ] }), 1458 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1459 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground uppercase", children: "Vehicle Class" }), 1460 /* @__P
1460URE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs font-medium", children: [ 1461 "Class ", 1462 d.vehicleClass != null ? d.vehicleClass + 1 : "â", 1463 " (", 1464 d.vehicleYearRate ? `${(d.vehicleYearRate * 100).toFixed(0)}%` : "â", 1465 ")" 1466 ] }) 1467 ] }), 1468 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1469 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-muted-foreground uppercase", children: "Status" }), 1470 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [ 1471 d.auditStatus && statusIcon(d.auditStatus), 1472 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium", children: d.auditStatus ? statusLabel(d.auditStatus) : "â" }) 1473 ] }) 1474 ] }) 1475 ] }) 1476 ] }) 1477 ] }), 1478 /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogFooter, { className: "mt-4 flex items-center gap-2", children: [ 1479 d.tekionDealId && /* @__PURE__ */ jsxRuntimeExports.jsxs( 1480 "a", 1481 { 1482 href: `https://app.tekioncloud.com/sales/deals/details/${d.tekionDealId}`, 1483 target: "_blank", 1484 rel: "noopener noreferrer", 1485 className: "text-xs text-indigo-400 hover:underline flex items-center gap-1 mr-auto", 1486 children: [
1487 /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "w-3 h-3" }), 1488 " View in Tekion" 1489 ] 1490 } 1491 ), 1492 !d.resolved && /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", variant: "outline", onClick: () => setShowResolve(true), children: "Mark Resolved" }), 1493 d.resolved && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-blue-400 border-blue-400/30 bg-blue-400/10", children: "Resolved" }), 1494 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", variant: "destructive", onClick: () => { 1495 if (confirm("Delete this audit entry?")) { 1496 deleteMut.mutate({ dealerId, auditId: selectedAuditId }); 1497 } 1498 }, children: "Delete" }) 1499 ] }) 1500 ] }); 1501 })() }) }), 1502 /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open: showResolve, onOpenChange: setShowResolve, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { children: [
1503 /* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Resolve Audit Issue" }) }), 1504 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1505 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Resolution Notes" }), 1506 /* @__PURE__ */ jsxRuntimeExports.jsx( 1507 Textarea, 1508 { 1509 value: resolveNotes, 1510 onChange: (e) => setResolveNotes(e.target.value), 1511 placeholder: "Describe how this was resolved...", 1512 rows: 4 1513 } 1514 ) 1515 ] }) }), 1516 /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogFooter, { children: [ 1517 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", onClick: () => setShowResolve(false), children: "Cancel" }), 1518 /* @__PURE__ */ jsxRuntimeExports.jsx( 1519 Button, 1520 { 1521 onClick: () => { 1522 if (selectedAuditId) resolve.mutate({ dealerId, auditId: selectedAuditId, notes: resolveNotes }); 1523 }, 1524 disabled: resolve.isPending, 1525 children: "Mark Resolved" 1526 } 1527 ) 1528 ] }) 1529 ] }) }) 1530 ] }); 1531} 1532function KpiCard({ label, value, icon, className, valueColor, onClick, active, isAmount, tooltip }) { 1533 const card = /* @__PURE__ */ jsxRuntimeExports.jsx( 1534 Card, 1535 { 1536 className: `cursor-pointer transition-all hover:scale-[1.02] ${active ? "ring-2 ring-indigo-500" : ""} ${className || ""}`, 1537 onClick, 1538 children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-3", children: [
1539 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [ 1540 icon, 1541 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground", children: label }), 1542 tooltip && /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { className: "w-3 h-3 text-muted-foreground/40 transition-all duration-200 hover:text-indigo-400 hover:opacity-100 hover:scale-110 cursor-help" }) 1543 ] }), 1544 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `text-xl font-bold ${valueColor || ""} ${isAmount ? "text-base" : ""}`, children: value }) 1545 ] }) 1546 } 1547 ); 1548 if (!tooltip) return card; 1549 return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [ 1550 /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: card }), 1551 /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { side: "bottom", className: "max-w-xs text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: tooltip }) }) 1552 ] }) }); 1553} 1554function AddDealDialog({ open, onOpenChange, dealerId, onSuccess }) { 1555 const [form, setForm] = reactExports.useState({ 1556 externalDealNumber: "", 1557 customerName: "", 1558 vin: "", 1559 tekAmountFinanced: "", 1560 tekDownPayment: "", 1561 tekTerm: "", 1562 tekFrequency: "monthly", 1563 tekPaymentAmount: "", 1564 tekApr: "", 1565 tekVehicleYear: "", 1566 tekFinanceCharge: "", 1567 tekIsNewCar: false 1568 }); 1569 const create = trpc.maxrate.create.useMutation({ 1570 onSuccess: (data) => { 1571 toast.success(`Deal Added â Status: ${data.status}`); 1572 onOpenChange(false); 1573 onSuccess(); 1574 }, 1575 onError: (e) => toast.error(e.message) 1576 }); 1577 const handleSubmit = () => { 1578 create.mutate({ 1579 dealerId, 1580 externalDealNumber: form.externalDealNumber || void 0, 1581 customerName: form.customerName || void 0, 1582 vin: form.vin || void 0, 1583 tekAmountFinanced: form.tekAmountFinanced ? parseFloat(form.tekAmountFinanced) : void 0, 1584 tekDownPayment: form.tekDownPayment ? parseFloat(form.tekDownPayment) : void 0, 1585 tekTerm: form.tekTerm ? parseInt(form.tekTerm) : void 0, 1586 tekFrequency: form.tekFrequency, 1587 tekPaymentAmount: form.tekPaymentAmount ? parseFloat(form.tekPaymentAmount) : void 0, 1588 tekApr: form.tekApr ? parseFloat(form.tekApr) : void 0, 1589 tekVehicleYear: form.tekVehicleYear ? parseInt(form.tekVehicleYear) : void 0, 1590 tekFinanceCharge: form.tekFinanceCharge ? parseFloat(form.tekFinanceCharge) : void 0, 1591 tekIsNewCar: form.tekIsNewCar 1592 }); 1593 }; 1594 return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "max-w-lg", children: [ 1595 /* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Add Deal for Audit" }) }), 1596 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3 max-h-[60vh] overflow-y-auto pr-2", children: [
1597 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [ 1598 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Deal Number" }), 1599 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { value: form.externalDealNumber, onChange: (e) => setForm((f) => ({ ...f, externalDealNumber: e.target.value })), placeholder: "e.g. 12345" }) 1600 ] }), 1601 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1602 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Customer Name" }), 1603 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { value: form.customerName, onChange: (e) => setForm((f) => ({ ...f, customerName: e.target.value })) }) 1604 ] }), 1605 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1606 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "VIN" }), 1607 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { value: form.vin, onChange: (e) => setForm((f) => ({ ...f, vin: e.target.value })) }) 1608 ] }), 1609 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1610 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Amount Financed ($)" }), 1611 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", value: form.tekAmountFinanced, onChange: (e) => setForm((f) => ({ ...f, tekAmountFinanced: e.target.value })) }) 1612 ] }), 1613 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1614 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Down Payment ($)" }), 1615 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", value: form.tekDownPayment, onChange: (e) => setForm((f) => ({ ...f, tekDownPayment: e.target.value })) }) 1616 ] }), 1617 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1618 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Term" }), 1619 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", value: form.tekTerm, onChange: (e) => setForm((f) => ({ ...f, tekTerm: e.target.value })), placeholder: form.tekFrequency === "biweekly" ? "periods" : "months" }) 1620 ] }), 1621 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1622 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Frequency" }), 1623 /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: form.tekFrequency, onValueChange: (v) => setForm((f) => ({ ...f, tekFrequency: v })), children: [ 1624 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, {}) }), 1625 /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [ 1626 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "monthly", children: "Monthly" }), 1627 /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "biweekly", children: "Bi-Weekly" }) 1628 ] }) 1629 ] }) 1630 ] }), 1631 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1632 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Payment Amount ($)" }), 1633 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", value: form.tekPaymentAmount, onChange: (e) => setForm((f) => ({ ...f, tekPaymentAmount: e.target.value })) }) 1634 ] }),
1635 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1636 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "APR (%)" }), 1637 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", step: "0.001", value: form.tekApr, onChange: (e) => setForm((f) => ({ ...f, tekApr: e.target.value })) }) 1638 ] }), 1639 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1640 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Vehicle Year" }), 1641 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", value: form.tekVehicleYear, onChange: (e) => setForm((f) => ({ ...f, tekVehicleYear: e.target.value })), placeholder: "e.g. 2022" }) 1642 ] }), 1643 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1644 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { children: "Finance Charge ($)" }), 1645 /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { type: "number", value: form.tekFinanceCharge, onChange: (e) => setForm((f) => ({ ...f, tekFinanceCharge: e.target.value })) }) 1646 ] }),
1647 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 col-span-2", children: [ 1648 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: form.tekIsNewCar, onChange: (e) => setForm((f) => ({ ...f, tekIsNewCar: e.target.checked })), id: "newcar" }), 1649 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { htmlFor: "newcar", children: "New Car (factory fresh)" }) 1650 ] }) 1651 ] }), 1652 /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogFooter, { children: [ 1653 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Cancel" }), 1654 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { onClick: handleSubmit, disabled: create.isPending, children: create.isPending ? "Adding..." : "Add & Audit" }) 1655 ] }) 1656 ] }) }); 1657} 1658function ImportDealPackDialog({ open, onOpenChange, dealerId, onSuccess }) { 1659 const [csvText, setCsvText] = reactExports.useState(""); 1660 const [preview, setPreview] = reactExports.useState([]); 1661 const [importSource, setImportSource] = reactExports.useState("dealpack"); 1662 const [fileName, setFileName] = reactExports.useState(""); 1663 const [parsing, setParsing] = reactExports.useState(false); 1664 const [dragOver, setDragOver] = reactExports.useState(false); 1665 const fileInputRef = reactExports.useRef(null); 1666 const importMut = trpc.maxrate.importDealPack.useMutation({ 1667 onSuccess: (data) => { 1668 toast.success(`Import Complete â Matched: ${data.matched}, Unmatched: ${data.unmatched} of ${data.total} rows`); 1669 onOpenChange(false); 1670 setCsvText(""); 1671 setPreview([]); 1672 setFileName(""); 1673 onSuccess(); 1674 }, 1675 onError: (e) => toast.error(e.message) 1676 }); 1677 const parseCSVText = reactExports.useCallback((text) => { 1678 const lines = text.trim().split("\n"); 1679 if (lines.length < 2) return []; 1680 const headers = lines[0].split(/[,\t]/).map((h) => h.trim().toLowerCase().replace(/["']/g, "")); 1681 return lines.slice(1).map((line) => { 1682 const vals = line.split(/[,\t]/).map((v) => v.trim().replace(/["']/g, "")); 1683 const obj = {}; 1684 headers.forEach((h, i) => { 1685 const v = vals[i] || ""; 1686 if (h.includes("deal") && (h.includes("num") || h.includes("#") || h.includes("no"))) obj.dealNumber = v; 1687 else if (h === "vin" || h.includes("vin")) obj.vin = v.length >= 10 ? v : void 0; 1688 else if (h.includes("amount") && h.includes("fin") || h === "amountfinanced" || h === "amt financed") obj.amountFinanced = parseFloat(v.replace(/[$,]/g, "")) || void 0; 1689 else if (h.includes("down") && h.includes("pay")) obj.downPayment = parseFloat(v.replace(/[$,]/g, "")) || void 0; 1690 else if (h === "term" || h.includes("term") || h.includes("months") || h.includes("# payments")) obj.term = parseInt(v) || void 0; 1691 else if (h.includes("freq")) obj.frequency = v.toLowerCase().includes("bi") ? "biweekly" : v.toLowerCase().includes("week") ? "weekly" : "monthly"; 1692 else if ((h.includes("payment") || h.includes("pmt")) && !h.includes("down") && !h.includes("freq") && !h.includes("#")) obj.paymentAmount = parseFloat(v.replace(/[$,]/g, "")) || void 0; 1693 else if (h === "apr" || h.includes("rate") || h.includes("apr") || h.includes("interest")) obj.apr = parseFloat(v.replace(/%/g, "")) || void 0; 1694 else if (h.includes("year") && !h.includes("rate")) obj.vehicleYear = parseInt(v) || void 0; 1695 else if (h.includes("finance") && h.includes("charge")) obj.financeCharge = parseFloat(v.replace(/[$,]/g, "")) || void 0; 1696 else if (h.includes("customer") || h.includes("name") || h.includes("buyer")) obj.customerName = v; 1697 else if (h.includes("make")) obj.make = v; 1698 else if (h.includes("model")) obj.model = v; 1699 else if (h.includes("lien") || h.includes("lender") || h.includes("bank")) obj.lender = v; 1700 }); 1701 return obj; 1702 }).filter((r) => r.dealNumber || r.vin); 1703 }, []); 1704 const handleFile = reactExports.useCallback(async (file) => { 1705 setFileName(file.name); 1706 setParsing(true); 1707 try { 1708 const ext = file.name.toLowerCase().split(".").pop(); 1709 if (ext === "csv" || ext === "tsv" || ext === "txt") { 1710 const text = await file.text(); 1711 setCsvText(text); 1712 const rows = parseCSVText(text); 1713 setPreview(rows); 1714 if (rows.length > 0) toast.success(`Parsed ${rows.length} deals from ${file.name}`); 1715 else toast.error("No deal rows found. Check file format."); 1716 } else if (ext === "xls" || ext === "xlsx") { 1717 const XLSX = await __vitePreload(() => import("./xlsx-BSWhk5a4.js"), true ? [] : void 0); 1718 const buffer = await file.arrayBuffer(); 1719 const wb = XLSX.read(buffer, { type: "array" }); 1720 const ws = wb.Sheets[wb.SheetNames[0]]; 1721 const csvOutput = XLSX.utils.sheet_to_csv(ws); 1722 setCsvText(csvOutput); 1723 const rows = parseCSVText(csvOutput); 1724 setPreview(rows); 1725 if (rows.length > 0) toast.success(`Parsed ${rows.length} deals from ${file.name}`); 1726 else toast.error("No deal rows found. Check file format."); 1727 } else if (ext === "pdf") { 1728 const buffer = await file.arrayBuffer(); 1729 const bytes = new Uint8Array(buffer); 1730 let binary = ""; 1731 for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]); 1732 const base64 = btoa(binary); 1733 const resp = await fetch("/api/trpc/maxrate.parsePdf", { 1734 method: "POST", 1735 headers: { "Content-Type": "application/json" }, 1736 body: JSON.stringify({ json: { dealerId, pdfBase64: base64, source: importSource } }) 1737 }); 1738 const result = await resp.json(); 1739 if (result?.result?.data?.json?.rows) { 1740 const rows = result.result.data.json.rows; 1741 setPreview(rows); 1742 setCsvText(rows.map((r) => `${r.dealNumber || ""},${r.vin || ""},${r.amountFinanced || ""},${r.term || ""},${r.apr || ""},${r.financeCharge || ""}`).join("\n")); 1743 if (rows.length > 0) toast.success(`Parsed ${rows.length} deals from PDF`); 1744 else toast.error("Could not extract deal data from PDF. Try XLS export instead."); 1745 } else { 1746 toast.error("Could not parse PDF. Try exporting as XLS/CSV
1746instead."); 1747 } 1748 } else { 1749 toast.error(`Unsupported file type: .${ext}. Use CSV, XLS, XLSX, or PDF.`); 1750 } 1751 } catch (err) { 1752 toast.error(`Parse error: ${err.message}`); 1753 } finally { 1754 setParsing(false); 1755 } 1756 }, [dealerId, importSource, parseCSVText]); 1757 return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "max-w-3xl max-h-[90vh] overflow-y-auto", children: [ 1758 /* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogTitle, { className: "flex items-center gap-2", children: [ 1759 /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { className: "w-5 h-5 text-indigo-400" }), 1760 "Import Deal Data" 1761 ] }) }), 1762 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 1763 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [ 1764 /* @__PURE__ */ jsxRuntimeExports.jsx( 1765 Button, 1766 { 1767 variant: importSource === "tekion" ? "default" : "outline", 1768 size: "sm", 1769 onClick: () => setImportSource("tekion"), 1770 className: importSource === "tekion" ? "bg-indigo-600 hover:bg-indigo-700" : "", 1771 children: "From Tekion Export" 1772 } 1773 ),
1774 /* @__PURE__ */ jsxRuntimeExports.jsx( 1775 Button, 1776 { 1777 variant: importSource === "dealpack" ? "default" : "outline", 1778 size: "sm", 1779 onClick: () => setImportSource("dealpack"), 1780 className: importSource === "dealpack" ? "bg-indigo-600 hover:bg-indigo-700" : "", 1781 children: "From Deal Pack Export" 1782 } 1783 ) 1784 ] }), 1785 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1786 "div", 1787 { 1788 className: `border-2 border-dashed rounded-lg p-6 text-center transition-all cursor-pointer ${dragOver ? "border-indigo-500 bg-indigo-500/10" : "border-border/50 hover:border-indigo-500/50"}`, 1789 onDragOver: (e) => { 1790 e.preventDefault(); 1791 setDragOver(true); 1792 }, 1793 onDragLeave: () => setDragOver(false), 1794 onDrop: (e) => { 1795 e.preventDefault(); 1796 setDragOver(false); 1797 const file = e.dataTransfer.files[0]; 1798 if (file) handleFile(file); 1799 }, 1800 onClick: () => fileInputRef.current?.click(), 1801 children: [
1802 /* @__PURE__ */ jsxRuntimeExports.jsx( 1803 "input", 1804 { 1805 ref: fileInputRef, 1806 type: "file", 1807 accept: ".csv,.tsv,.txt,.xls,.xlsx,.pdf", 1808 className: "hidden", 1809 onChange: (e) => { 1810 const file = e.target.files?.[0]; 1811 if (file) handleFile(file); 1812 } 1813 } 1814 ), 1815 parsing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center gap-2", children: [ 1816 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-5 h-5 animate-spin text-indigo-400" }), 1817 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm", children: [ 1818 "Parsing ", 1819 fileName, 1820 "..." 1821 ] }) 1822 ] }) : fileName ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1823 /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "w-8 h-8 mx-auto text-indigo-400 mb-2" }),
1824 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: fileName }), 1825 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: [ 1826 preview.length, 1827 " deals parsed â click to replace" 1828 ] }) 1829 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1830 /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { className: "w-8 h-8 mx-auto text-muted-foreground mb-2" }), 1831 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: "Drop a file here or click to browse" }), 1832 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "Supports: PDF, XLS, XLSX, CSV" }), 1833 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground", children: [ 1834 "Export from ", 1835 importSource === "tekion" ? "Tekion" : "Deal Pack", 1836 " and upload directly" 1837 ] }) 1838 ] }) 1839 ] 1840 } 1841 ),
1842 /* @__PURE__ */ jsxRuntimeExports.jsxs("details", { className: "text-sm", children: [ 1843 /* @__PURE__ */ jsxRuntimeExports.jsx("summary", { className: "cursor-pointer text-muted-foreground hover:text-foreground", children: "Or paste CSV/tab-separated text manually" }), 1844 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 space-y-2", children: [ 1845 /* @__PURE__ */ jsxRuntimeExports.jsx( 1846 Textarea, 1847 { 1848 value: csvText, 1849 onChange: (e) => setCsvText(e.target.value), 1850 placeholder: "Deal Number,VIN,Amount Financed,Down Payment,Term,Frequency,Payment Amount,APR,Vehicle Year,Finance Charge", 1851 rows: 4, 1852 className: "text-xs font-mono" 1853 } 1854 ), 1855 /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { variant: "outline", size: "sm", onClick: () => { 1856 const rows = parseCSVText(csvText); 1857 setPreview(rows); 1858 if (rows.length > 0) toast.success(`Parsed ${rows.length} deals`); 1859 }, children: [ 1860 "Parse Text (", 1861 preview.length, 1862 " rows)" 1863 ] }) 1864 ] }) 1865 ] }), 1866 preview.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border rounded-lg overflow-hidden", children: [
1867 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-muted/30 px-3 py-2 text-xs font-medium flex items-center justify-between", children: [ 1868 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1869 preview.length, 1870 " deals ready to import" 1871 ] }), 1872 /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-[10px]", children: importSource === "tekion" ? "Tekion Source" : "Deal Pack Source" }) 1873 ] }), 1874 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-h-48 overflow-y-auto", children: [ 1875 /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-xs", children: [ 1876 /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border/50 bg-muted/20", children: [ 1877 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-2", children: "Deal #" }), 1878 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left p-2", children: "VIN" }),
1879 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-2", children: "Amt Fin" }), 1880 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-center p-2", children: "Term" }), 1881 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-2", children: "APR" }), 1882 /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right p-2", children: "Fin Chg" }) 1883 ] }) }), 1884 /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: preview.map((r, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border/20", children: [ 1885 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 font-mono", children: r.dealNumber || "â" }), 1886 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 font-mono", children: r.vin ? `...${r.vin.slice(-6)}` : "â" }), 1887 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-right", children: r.amountFinanced ? `$${r.amountFinanced.toLocaleString()}` : "â" }),
1888 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-center", children: r.term || "â" }), 1889 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-right", children: r.apr ? `${r.apr}%` : "â" }), 1890 /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-right", children: r.financeCharge ? `$${r.financeCharge.toLocaleString()}` : "â" }) 1891 ] }, i)) }) 1892 ] }), 1893 preview.length > 10 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground text-center py-2", children: [ 1894 "...and ", 1895 preview.length - 10, 1896 " more" 1897 ] }) 1898 ] }) 1899 ] }) 1900 ] }), 1901 /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogFooter, { children: [ 1902 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", onClick: () => { 1903 onOpenChange(false); 1904 setPreview([]); 1905 setCsvText(""); 1906 setFileName(""); 1907 }, children: "Cancel" }),
1908 /* @__PURE__ */ jsxRuntimeExports.jsx( 1909 Button, 1910 { 1911 onClick: () => importMut.mutate({ dealerId, rows: preview }), 1912 disabled: importMut.isPending || preview.length === 0, 1913 className: "bg-indigo-600 hover:bg-indigo-700", 1914 children: importMut.isPending ? "Importing..." : `Import ${preview.length} Deals` 1915 } 1916 ) 1917 ] }) 1918 ] }) }); 1919} 1920export { 1921 MaxRateAudit as default 1922};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.