1 line
1.9 MiB
1 line
1.9 MiB
[{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/404/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/500/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/actions/logoutAction.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/admin/AdminDashboardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/admin/actions.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/admin/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/admin/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/admin/users/AdminUsersWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/admin/users/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/forgot-password/ForgotPasswordClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/forgot-password/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/login/LoginClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/login/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/reset-password/ResetPasswordClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/reset-password/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/signup/SignupClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/auth/signup/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/dashboard/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/dashboard/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/drivers/DriversPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/drivers/[id]/DriverProfilePageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/drivers/[id]/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/drivers/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/error.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/global-error.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leaderboards/LeaderboardsPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leaderboards/drivers/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leaderboards/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/LeaguesPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/roster/admin/RosterAdminPage.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/roster/admin/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/rulebook/LeagueRulebookPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/rulebook/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/schedule/admin/LeagueAdminSchedulePageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/schedule/admin/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/schedule/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/settings/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/sponsorships/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/standings/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/stewarding/StewardingPageClient.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":50,"column":10,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":50,"endColumn":13,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2242,2245],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2242,2245],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":65,"column":10,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":65,"endColumn":13,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2739,2742],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2739,2742],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":75,"column":12,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":75,"endColumn":15,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3004,3007],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3004,3007],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":90,"column":12,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":90,"endColumn":15,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3358,3361],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3358,3361],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":234,"column":16,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":234,"endColumn":19,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8075,8078],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8075,8078],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { PenaltyFAB } from '@/ui/PenaltyFAB';\nimport { QuickPenaltyModal } from '@/components/leagues/QuickPenaltyModal';\nimport { ReviewProtestModal } from '@/components/leagues/ReviewProtestModal';\nimport { StewardingStats } from '@/components/leagues/StewardingStats';\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { useLeagueStewardingMutations } from \"@/hooks/league/useLeagueStewardingMutations\";\nimport { useMemo, useState } from 'react';\nimport { PendingProtestsList } from '@/components/leagues/PendingProtestsList';\nimport { PenaltyHistoryList } from '@/components/leagues/PenaltyHistoryList';\nimport { Box } from '@/ui/Box';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\nimport { Heading } from '@/ui/Heading';\nimport type { StewardingViewData } from '@/lib/view-data/leagues/StewardingViewData';\nimport { ProtestViewModel } from '@/lib/view-models/ProtestViewModel';\nimport { RaceViewModel } from '@/lib/view-models/RaceViewModel';\nimport { DriverViewModel } from '@/lib/view-models/DriverViewModel';\n\ninterface StewardingTemplateProps {\n data: StewardingViewData;\n leagueId: string;\n currentDriverId: string;\n onRefetch: () => void;\n}\n\nexport function StewardingPageClient({ data, leagueId, currentDriverId, onRefetch }: StewardingTemplateProps) {\n const [activeTab, setActiveTab] = useState<'pending' | 'history'>('pending');\n const [selectedProtest, setSelectedProtest] = useState<ProtestViewModel | null>(null);\n const [showQuickPenaltyModal, setShowQuickPenaltyModal] = useState(false);\n\n // Mutations using domain hook\n const { acceptProtestMutation, rejectProtestMutation } = useLeagueStewardingMutations(onRefetch);\n\n // Flatten protests for the specialized list components\n const allPendingProtests = useMemo(() => {\n return data.races.flatMap(r => r.pendingProtests.map(p => new ProtestViewModel({\n id: p.id,\n protestingDriverId: p.protestingDriverId,\n accusedDriverId: p.accusedDriverId,\n description: p.incident.description,\n submittedAt: p.filedAt,\n status: p.status,\n raceId: r.id,\n incident: p.incident,\n proofVideoUrl: p.proofVideoUrl,\n decisionNotes: p.decisionNotes,\n } as any)));\n }, [data.races]);\n\n const allResolvedProtests = useMemo(() => {\n return data.races.flatMap(r => r.resolvedProtests.map(p => new ProtestViewModel({\n id: p.id,\n protestingDriverId: p.protestingDriverId,\n accusedDriverId: p.accusedDriverId,\n description: p.incident.description,\n submittedAt: p.filedAt,\n status: p.status,\n raceId: r.id,\n incident: p.incident,\n proofVideoUrl: p.proofVideoUrl,\n decisionNotes: p.decisionNotes,\n } as any)));\n }, [data.races]);\n\n const racesMap = useMemo(() => {\n const map: Record<string, RaceViewModel> = {};\n data.races.forEach(r => {\n map[r.id] = new RaceViewModel({\n id: r.id,\n track: r.track,\n date: r.scheduledAt,\n } as any);\n });\n return map;\n }, [data.races]);\n\n const driverMap = useMemo(() => {\n const map: Record<string, DriverViewModel> = {};\n data.drivers.forEach(d => {\n map[d.id] = new DriverViewModel({\n id: d.id,\n name: d.name,\n iracingId: '',\n country: '',\n joinedAt: '',\n avatarUrl: null,\n } as any);\n });\n return map;\n }, [data.drivers]);\n\n const handleAcceptProtest = async (\n protestId: string,\n penaltyType: string,\n penaltyValue: number,\n stewardNotes: string\n ) => {\n // Find the protest to get details for penalty\n let foundProtest: { raceId: string; accusedDriverId: string; incident: { description: string } } | undefined;\n data.races.forEach((raceData) => {\n const p = raceData.pendingProtests.find((pr) => pr.id === protestId) ||\n raceData.resolvedProtests.find((pr) => pr.id === protestId);\n if (p) foundProtest = { \n raceId: raceData.id, \n accusedDriverId: p.accusedDriverId,\n incident: { description: p.incident.description }\n };\n });\n\n if (foundProtest) {\n acceptProtestMutation.mutate({\n protestId,\n penaltyType,\n penaltyValue,\n stewardNotes,\n raceId: foundProtest.raceId,\n accusedDriverId: foundProtest.accusedDriverId,\n reason: foundProtest.incident.description,\n });\n }\n };\n\n const handleRejectProtest = async (protestId: string, stewardNotes: string) => {\n rejectProtestMutation.mutate({\n protestId,\n stewardNotes,\n });\n };\n\n return (\n <Stack gap={6}>\n <Card>\n <Box p={6}>\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"between\" mb={6}>\n <Box>\n <Heading level={2}>Stewarding</Heading>\n <Box mt={1}>\n <Text size=\"sm\" color=\"text-gray-400\">\n Quick overview of protests and penalties across all races\n </Text>\n </Box>\n </Box>\n </Box>\n\n {/* Stats summary */}\n <StewardingStats\n totalPending={data.totalPending}\n totalResolved={data.totalResolved}\n totalPenalties={data.totalPenalties}\n />\n\n {/* Tab navigation */}\n <Box borderBottom borderColor=\"border-charcoal-outline\" mb={6}>\n <Stack direction=\"row\" gap={4}>\n <Box \n borderBottom={activeTab === 'pending'} \n borderColor={activeTab === 'pending' ? 'border-primary-blue' : undefined}\n >\n <Button\n variant=\"ghost\"\n onClick={() => setActiveTab('pending')}\n rounded=\"none\"\n >\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Text weight=\"medium\" color={activeTab === 'pending' ? 'text-primary-blue' : undefined}>Pending Protests</Text>\n {data.totalPending > 0 && (\n <Box px={2} py={0.5} fontSize=\"0.75rem\" bg=\"bg-warning-amber/20\" color=\"text-warning-amber\" rounded=\"full\">\n {data.totalPending}\n </Box>\n )}\n </Stack>\n </Button>\n </Box>\n <Box \n borderBottom={activeTab === 'history'} \n borderColor={activeTab === 'history' ? 'border-primary-blue' : undefined}\n >\n <Button\n variant=\"ghost\"\n onClick={() => setActiveTab('history')}\n rounded=\"none\"\n >\n <Text weight=\"medium\" color={activeTab === 'history' ? 'text-primary-blue' : undefined}>History</Text>\n </Button>\n </Box>\n </Stack>\n </Box>\n\n {/* Content */}\n {activeTab === 'pending' ? (\n <PendingProtestsList \n protests={allPendingProtests}\n races={racesMap}\n drivers={driverMap}\n leagueId={leagueId}\n onReviewProtest={setSelectedProtest}\n onProtestReviewed={onRefetch}\n />\n ) : (\n <PenaltyHistoryList \n protests={allResolvedProtests}\n races={racesMap}\n drivers={driverMap}\n />\n )}\n </Box>\n </Card>\n\n {activeTab === 'history' && (\n <PenaltyFAB onClick={() => setShowQuickPenaltyModal(true)} />\n )}\n\n {selectedProtest && (\n <ReviewProtestModal\n protest={selectedProtest}\n onClose={() => setSelectedProtest(null)}\n onAccept={handleAcceptProtest}\n onReject={handleRejectProtest}\n />\n )}\n\n {showQuickPenaltyModal && (\n <QuickPenaltyModal\n drivers={data.drivers.map(d => new DriverViewModel({\n id: d.id,\n name: d.name,\n iracingId: '',\n country: '',\n joinedAt: '',\n avatarUrl: null,\n } as any))}\n onClose={() => setShowQuickPenaltyModal(false)}\n adminId={currentDriverId || ''}\n races={data.races.map(r => ({ id: r.id, track: r.track, scheduledAt: new Date(r.scheduledAt) }))}\n />\n )}\n </Stack>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/stewarding/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/stewarding/protests/[protestId]/ProtestDetailPageClient.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":52,"column":9,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":52,"endColumn":12,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1511,1514],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1511,1514],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":102,"column":81,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":102,"endColumn":84,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2915,2918],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2915,2918],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":138,"column":37,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":138,"endColumn":40,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4437,4440],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4437,4440],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":153,"column":34,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":153,"endColumn":37,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4796,4799],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4796,4799],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":202,"column":64,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":202,"endColumn":67,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6461,6464],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6461,6464],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":319,"column":13,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":319,"endColumn":16,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[10546,10549],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[10546,10549],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":577,"column":31,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":587,"endColumn":33},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":591,"column":62,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":591,"endColumn":96},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":633,"column":59,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":633,"endColumn":127},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":653,"column":33,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":658,"endColumn":35},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":668,"column":33,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":673,"endColumn":35},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":694,"column":67,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":694,"endColumn":70,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[32661,32664],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[32661,32664],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":705,"column":45,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":710,"endColumn":47},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":716,"column":79,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":716,"endColumn":107},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":735,"column":43,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":744,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":761,"column":33,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":771,"endColumn":35},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":795,"column":57,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":795,"endColumn":92}],"suppressedMessages":[],"errorCount":17,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { useEffectiveDriverId } from \"@/hooks/useEffectiveDriverId\";\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { PROTEST_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { ProtestDecisionCommandModel } from '@/lib/command-models/protests/ProtestDecisionCommandModel';\nimport {\n AlertTriangle,\n ArrowLeft,\n Calendar,\n CheckCircle,\n ChevronDown,\n Clock,\n ExternalLink,\n Flag,\n Gavel,\n Grid3x3,\n MapPin,\n MessageCircle,\n Send,\n Shield,\n ShieldAlert,\n TrendingDown,\n User,\n Video,\n XCircle,\n AlertCircle\n} from 'lucide-react';\nimport { useParams, useRouter } from 'next/navigation';\nimport { useMemo, useState, useEffect } from 'react';\n\n// Shared state components\nimport { StateContainer } from '@/components/shared/state/StateContainer';\nimport { LoadingWrapper } from '@/components/shared/state/LoadingWrapper';\nimport { useLeagueAdminStatus } from \"@/hooks/league/useLeagueAdminStatus\";\nimport { useProtestDetail } from \"@/hooks/league/useProtestDetail\";\nimport { Box } from '@/ui/Box';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\nimport { Heading } from '@/ui/Heading';\nimport { Grid } from '@/ui/Grid';\nimport { GridItem } from '@/ui/GridItem';\nimport { Icon as UIIcon } from '@/ui/Icon';\nimport { Link as UILink } from '@/ui/Link';\nimport { routes } from '@/lib/routing/RouteConfig';\n\ntype PenaltyUiConfig = {\n label: string;\n description: string;\n icon: any;\n color: string;\n defaultValue?: number;\n};\n\nconst PENALTY_UI: Record<string, PenaltyUiConfig> = {\n time_penalty: {\n label: 'Time Penalty',\n description: 'Add seconds to race result',\n icon: Clock,\n color: 'text-blue-400 bg-blue-500/10 border-blue-500/20',\n defaultValue: 5,\n },\n grid_penalty: {\n label: 'Grid Penalty',\n description: 'Grid positions for next race',\n icon: Grid3x3,\n color: 'text-purple-400 bg-purple-500/10 border-purple-500/20',\n defaultValue: 3,\n },\n points_deduction: {\n label: 'Points Deduction',\n description: 'Deduct championship points',\n icon: TrendingDown,\n color: 'text-red-400 bg-red-500/10 border-red-500/20',\n defaultValue: 5,\n },\n disqualification: {\n label: 'Disqualification',\n description: 'Disqualify from race',\n icon: XCircle,\n color: 'text-red-500 bg-red-500/10 border-red-500/20',\n defaultValue: 0,\n },\n warning: {\n label: 'Warning',\n description: 'Official warning only',\n icon: AlertTriangle,\n color: 'text-yellow-400 bg-yellow-500/10 border-yellow-500/20',\n defaultValue: 0,\n },\n license_points: {\n label: 'License Points',\n description: 'Safety rating penalty',\n icon: ShieldAlert,\n color: 'text-orange-400 bg-orange-500/10 border-orange-500/20',\n defaultValue: 2,\n },\n};\n\nexport function ProtestDetailPageClient({ initialViewData }: { initialViewData: any }) {\n const params = useParams();\n const router = useRouter();\n const leagueId = params.id as string;\n const protestId = params.protestId as string;\n const currentDriverId = useEffectiveDriverId();\n const protestService = useInject(PROTEST_SERVICE_TOKEN);\n\n // Decision state\n const [showDecisionPanel, setShowDecisionPanel] = useState(false);\n const [decision, setDecision] = useState<'uphold' | 'dismiss' | null>(null);\n const [penaltyType, setPenaltyType] = useState<string>('time_penalty');\n const [penaltyValue, setPenaltyValue] = useState<number>(5);\n const [stewardNotes, setStewardNotes] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [newComment, setNewComment] = useState('');\n\n // Check admin status using hook\n const { data: isAdmin, isLoading: adminLoading } = useLeagueAdminStatus(leagueId, currentDriverId || '');\n\n // Load protest detail using hook\n const { data: detail, isLoading: detailLoading, error, retry } = useProtestDetail(leagueId, protestId, isAdmin || false);\n\n // Use initial data if available\n const protestDetail = detail || initialViewData;\n\n // Set initial penalty values when data loads\n useEffect(() => {\n if (protestDetail?.initialPenaltyType) {\n setPenaltyType(protestDetail.initialPenaltyType);\n setPenaltyValue(protestDetail.initialPenaltyValue);\n }\n }, [protestDetail]);\n\n const penaltyTypes = useMemo(() => {\n const referenceItems = protestDetail?.penaltyTypes ?? [];\n return referenceItems.map((ref: any) => {\n const ui = PENALTY_UI[ref.type] ?? {\n icon: Gavel,\n color: 'text-gray-400 bg-gray-500/10 border-gray-500/20',\n };\n\n return {\n ...ref,\n icon: ui.icon,\n color: ui.color,\n };\n });\n }, [protestDetail?.penaltyTypes]);\n\n const selectedPenalty = useMemo(() => {\n return penaltyTypes.find((p: any) => p.type === penaltyType);\n }, [penaltyTypes, penaltyType]);\n\n const handleSubmitDecision = async () => {\n if (!decision || !stewardNotes.trim() || !protestDetail || !currentDriverId) return;\n\n setSubmitting(true);\n try {\n const protest = protestDetail.protest || protestDetail;\n\n const defaultUpheldReason = protestDetail.defaultReasons?.upheld;\n const defaultDismissedReason = protestDetail.defaultReasons?.dismissed;\n\n if (decision === 'uphold') {\n const requiresValue = selectedPenalty?.requiresValue ?? true;\n\n const commandModel = new ProtestDecisionCommandModel({\n decision,\n penaltyType,\n penaltyValue,\n stewardNotes,\n });\n\n const options: {\n requiresValue?: boolean;\n defaultUpheldReason?: string;\n defaultDismissedReason?: string;\n } = { requiresValue };\n\n if (defaultUpheldReason) {\n options.defaultUpheldReason = defaultUpheldReason;\n }\n if (defaultDismissedReason) {\n options.defaultDismissedReason = defaultDismissedReason;\n }\n\n const penaltyCommand = commandModel.toApplyPenaltyCommand(\n protest.raceId || protestDetail.race?.id,\n protest.accusedDriverId || protestDetail.accusedDriver?.id,\n currentDriverId,\n protest.id || protestDetail.protestId,\n options,\n );\n\n const result = await protestService.applyPenalty(penaltyCommand);\n if (result.isErr()) {\n throw new Error(result.getError().message);\n }\n } else {\n const warningRef = protestDetail.penaltyTypes.find((p: any) => p.type === 'warning');\n const requiresValue = warningRef?.requiresValue ?? false;\n\n const commandModel = new ProtestDecisionCommandModel({\n decision,\n penaltyType: 'warning',\n penaltyValue: 0,\n stewardNotes,\n });\n\n const options: {\n requiresValue?: boolean;\n defaultUpheldReason?: string;\n defaultDismissedReason?: string;\n } = { requiresValue };\n\n if (defaultUpheldReason) {\n options.defaultUpheldReason = defaultUpheldReason;\n }\n if (defaultDismissedReason) {\n options.defaultDismissedReason = defaultDismissedReason;\n }\n\n const penaltyCommand = commandModel.toApplyPenaltyCommand(\n protest.raceId || protestDetail.race?.id,\n protest.accusedDriverId || protestDetail.accusedDriver?.id,\n currentDriverId,\n protest.id || protestDetail.protestId,\n options,\n );\n\n const result = await protestService.applyPenalty(penaltyCommand);\n if (result.isErr()) {\n throw new Error(result.getError().message);\n }\n }\n\n router.push(routes.league.stewarding(leagueId));\n } catch (err) {\n alert(err instanceof Error ? err.message : 'Failed to submit decision');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleRequestDefense = async () => {\n if (!protestDetail || !currentDriverId) return;\n\n try {\n // Request defense\n const result = await protestService.requestDefense({\n protestId: protestDetail.protest?.id || protestDetail.protestId,\n stewardId: currentDriverId,\n });\n if (result.isErr()) {\n throw new Error(result.getError().message);\n }\n\n // Reload page to show updated status\n window.location.reload();\n } catch (err) {\n alert(err instanceof Error ? err.message : 'Failed to request defense');\n }\n };\n\n const getStatusConfig = (status: string) => {\n switch (status) {\n case 'pending':\n return { label: 'Pending Review', bg: 'bg-warning-amber/20', color: 'text-warning-amber', borderColor: 'border-warning-amber/30', icon: Clock };\n case 'under_review':\n return { label: 'Under Review', bg: 'bg-blue-500/20', color: 'text-blue-400', borderColor: 'border-blue-500/30', icon: Shield };\n case 'awaiting_defense':\n return { label: 'Awaiting Defense', bg: 'bg-purple-500/20', color: 'text-purple-400', borderColor: 'border-purple-500/30', icon: MessageCircle };\n case 'upheld':\n return { label: 'Upheld', bg: 'bg-red-500/20', color: 'text-red-400', borderColor: 'border-red-500/30', icon: CheckCircle };\n case 'dismissed':\n return { label: 'Dismissed', bg: 'bg-gray-500/20', color: 'text-gray-400', borderColor: 'border-gray-500/30', icon: XCircle };\n default:\n return { label: status, bg: 'bg-gray-500/20', color: 'text-gray-400', borderColor: 'border-gray-500/30', icon: AlertCircle };\n }\n };\n\n // Show loading for admin check\n if (adminLoading) {\n return <LoadingWrapper variant=\"full-screen\" message=\"Checking permissions...\" />;\n }\n\n // Show access denied if not admin\n if (!isAdmin) {\n return (\n <Card>\n <Box p={12} textAlign=\"center\">\n <Box w={16} h={16} mx=\"auto\" mb={4} rounded=\"full\" bg=\"bg-iron-gray/50\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\">\n <UIIcon icon={AlertTriangle} size={8} color=\"text-warning-amber\" />\n </Box>\n <Heading level={3}>Admin Access Required</Heading>\n <Box mt={2}>\n <Text size=\"sm\" color=\"text-gray-400\">\n Only league admins can review protests.\n </Text>\n </Box>\n </Box>\n </Card>\n );\n }\n\n return (\n <StateContainer\n data={protestDetail}\n isLoading={detailLoading}\n error={error}\n retry={retry}\n config={{\n loading: { variant: 'spinner', message: 'Loading protest details...' },\n error: { variant: 'full-screen' },\n }}\n >\n {(pd: any) => {\n if (!pd) return null;\n \n const protest = pd.protest || pd;\n const race = pd.race;\n const protestingDriver = pd.protestingDriver;\n const accusedDriver = pd.accusedDriver;\n\n const statusConfig = getStatusConfig(protest.status);\n const StatusIcon = statusConfig.icon;\n const isPending = protest.status === 'pending';\n const submittedAt = protest.submittedAt || pd.submittedAt;\n const daysSinceFiled = Math.floor((Date.now() - new Date(submittedAt).getTime()) / (1000 * 60 * 60 * 24));\n\n return (\n <Box minHeight=\"100vh\">\n {/* Compact Header */}\n <Box mb={6}>\n <Stack direction=\"row\" align=\"center\" gap={3} mb={4}>\n <UILink href={routes.league.stewarding(leagueId)}>\n <UIIcon icon={ArrowLeft} size={5} color=\"text-gray-400\" />\n </UILink>\n <Stack direction=\"row\" align=\"center\" gap={3} flexGrow={1}>\n <Heading level={1}>Protest Review</Heading>\n <Box display=\"flex\" alignItems=\"center\" gap={1.5} px={2.5} py={1} rounded=\"full\" fontSize=\"0.75rem\" weight=\"medium\" border bg={statusConfig.bg} color={statusConfig.color} borderColor={statusConfig.borderColor}>\n <UIIcon icon={StatusIcon} size={3} />\n <Text>{statusConfig.label}</Text>\n </Box>\n {daysSinceFiled > 2 && isPending && (\n <Box display=\"flex\" alignItems=\"center\" gap={1} px={2} py={0.5} fontSize=\"0.75rem\" weight=\"medium\" bg=\"bg-red-500/20\" color=\"text-red-400\" rounded=\"full\">\n <UIIcon icon={AlertTriangle} size={3} />\n <Text>{daysSinceFiled}d old</Text>\n </Box>\n )}\n </Stack>\n </Stack>\n </Box>\n\n {/* Main Layout: Feed + Sidebar */}\n <Grid cols={12} gap={6}>\n {/* Left Sidebar - Incident Info */}\n <GridItem colSpan={12} lgSpan={3}>\n <Stack gap={4}>\n {/* Drivers Involved */}\n <Card>\n <Box p={4}>\n <Heading level={3} fontSize=\"xs\" weight=\"semibold\" color=\"text-gray-500\" mb={3}>Parties Involved</Heading>\n \n <Stack gap={3}>\n {/* Protesting Driver */}\n <UILink href={routes.driver.detail(protestingDriver?.id || '')} block>\n <Box display=\"flex\" alignItems=\"center\" gap={3} p={3} rounded=\"lg\" bg=\"bg-deep-graphite\" border borderColor=\"border-charcoal-outline\" hoverBorderColor=\"border-blue-500/50\" hoverBg=\"bg-blue-500/5\" transition cursor=\"pointer\">\n <Box w={10} h={10} rounded=\"full\" bg=\"bg-blue-500/20\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\" flexShrink={0}>\n <UIIcon icon={User} size={5} color=\"text-blue-400\" />\n </Box>\n <Box flexGrow={1} minWidth={0}>\n <Text size=\"xs\" color=\"text-blue-400\" weight=\"medium\" block>Protesting</Text>\n <Text size=\"sm\" weight=\"semibold\" color=\"text-white\" truncate block>{protestingDriver?.name || 'Unknown'}</Text>\n </Box>\n <UIIcon icon={ExternalLink} size={3} color=\"text-gray-500\" />\n </Box>\n </UILink>\n\n {/* Accused Driver */}\n <UILink href={routes.driver.detail(accusedDriver?.id || '')} block>\n <Box display=\"flex\" alignItems=\"center\" gap={3} p={3} rounded=\"lg\" bg=\"bg-deep-graphite\" border borderColor=\"border-charcoal-outline\" hoverBorderColor=\"border-orange-500/50\" hoverBg=\"bg-orange-500/5\" transition cursor=\"pointer\">\n <Box w={10} h={10} rounded=\"full\" bg=\"bg-orange-500/20\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\" flexShrink={0}>\n <UIIcon icon={User} size={5} color=\"text-orange-400\" />\n </Box>\n <Box flexGrow={1} minWidth={0}>\n <Text size=\"xs\" color=\"text-orange-400\" weight=\"medium\" block>Accused</Text>\n <Text size=\"sm\" weight=\"semibold\" color=\"text-white\" truncate block>{accusedDriver?.name || 'Unknown'}</Text>\n </Box>\n <UIIcon icon={ExternalLink} size={3} color=\"text-gray-500\" />\n </Box>\n </UILink>\n </Stack>\n </Box>\n </Card>\n\n {/* Race Info */}\n <Card>\n <Box p={4}>\n <Heading level={3} fontSize=\"xs\" weight=\"semibold\" color=\"text-gray-500\" mb={3}>Race Details</Heading>\n \n <UILink\n href={routes.race.detail(race?.id || '')}\n block\n mb={3}\n >\n <Box p={3} rounded=\"lg\" bg=\"bg-deep-graphite\" border borderColor=\"border-charcoal-outline\" hoverBorderColor=\"border-primary-blue/50\" hoverBg=\"bg-primary-blue/5\" transition>\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"between\">\n <Text size=\"sm\" weight=\"medium\" color=\"text-white\">{race?.name || 'Unknown Race'}</Text>\n <UIIcon icon={ExternalLink} size={3} color=\"text-gray-500\" />\n </Box>\n </Box>\n </UILink>\n\n <Stack gap={2}>\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n <UIIcon icon={MapPin} size={4} color=\"text-gray-500\" />\n <Text size=\"sm\" color=\"text-gray-300\">{race?.name || 'Unknown Track'}</Text>\n </Box>\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n <UIIcon icon={Calendar} size={4} color=\"text-gray-500\" />\n <Text size=\"sm\" color=\"text-gray-300\">{race?.formattedDate || (race?.scheduledAt ? new Date(race.scheduledAt).toLocaleDateString() : 'Unknown Date')}</Text>\n </Box>\n {protest.incident?.lap && (\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n <UIIcon icon={Flag} size={4} color=\"text-gray-500\" />\n <Text size=\"sm\" color=\"text-gray-300\">Lap {protest.incident.lap}</Text>\n </Box>\n )}\n </Stack>\n </Box>\n </Card>\n\n {protest.proofVideoUrl && (\n <Card>\n <Box p={4}>\n <Heading level={3} fontSize=\"xs\" weight=\"semibold\" color=\"text-gray-500\" mb={3}>Evidence</Heading>\n <UILink\n href={protest.proofVideoUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n block\n >\n <Box display=\"flex\" alignItems=\"center\" gap={2} p={3} rounded=\"lg\" bg=\"bg-primary-blue/10\" border borderColor=\"border-primary-blue/20\" color=\"text-primary-blue\" hoverBg=\"bg-primary-blue/20\" transition>\n <UIIcon icon={Video} size={4} />\n <Text size=\"sm\" weight=\"medium\" flexGrow={1}>Watch Video</Text>\n <UIIcon icon={ExternalLink} size={3} />\n </Box>\n </UILink>\n </Box>\n </Card>\n )}\n\n {/* Quick Stats */}\n <Card>\n <Box p={4}>\n <Heading level={3} fontSize=\"xs\" weight=\"semibold\" color=\"text-gray-500\" mb={3}>Timeline</Heading>\n <Stack gap={2}>\n <Box display=\"flex\" justifyContent=\"between\">\n <Text size=\"sm\" color=\"text-gray-500\">Filed</Text>\n <Text size=\"sm\" color=\"text-gray-300\">{new Date(submittedAt).toLocaleDateString()}</Text>\n </Box>\n <Box display=\"flex\" justifyContent=\"between\">\n <Text size=\"sm\" color=\"text-gray-500\">Age</Text>\n <Text size=\"sm\" color={daysSinceFiled > 2 ? 'text-red-400' : 'text-gray-300'}>{daysSinceFiled} days</Text>\n </Box>\n {protest.reviewedAt && (\n <Box display=\"flex\" justifyContent=\"between\">\n <Text size=\"sm\" color=\"text-gray-500\">Resolved</Text>\n <Text size=\"sm\" color=\"text-gray-300\">{new Date(protest.reviewedAt).toLocaleDateString()}</Text>\n </Box>\n )}\n </Stack>\n </Box>\n </Card>\n </Stack>\n </GridItem>\n\n {/* Center - Discussion Feed */}\n <GridItem colSpan={12} lgSpan={6}>\n <Stack gap={4}>\n {/* Timeline / Feed */}\n <Card>\n <Box borderBottom borderColor=\"border-charcoal-outline\" bg=\"bg-iron-gray/30\" p={4}>\n <Heading level={2}>Discussion</Heading>\n </Box>\n\n <Stack gap={0}>\n {/* Initial Protest Filing */}\n <Box p={4}>\n <Box display=\"flex\" gap={3}>\n <Box w={10} h={10} rounded=\"full\" bg=\"bg-blue-500/20\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\" flexShrink={0}>\n <UIIcon icon={AlertCircle} size={5} color=\"text-blue-400\" />\n </Box>\n <Box flexGrow={1} minWidth={0}>\n <Box display=\"flex\" alignItems=\"center\" gap={2} mb={1}>\n <Text weight=\"semibold\" color=\"text-white\" size=\"sm\">{protestingDriver?.name || 'Unknown'}</Text>\n <Text size=\"xs\" color=\"text-blue-400\" weight=\"medium\">filed protest</Text>\n <Text size=\"xs\" color=\"text-gray-500\">•</Text>\n <Text size=\"xs\" color=\"text-gray-500\">{new Date(submittedAt).toLocaleString()}</Text>\n </Box>\n \n <Box bg=\"bg-deep-graphite\" rounded=\"lg\" p={4} border borderColor=\"border-charcoal-outline\">\n <Text size=\"sm\" color=\"text-gray-300\" block mb={3}>{protest.description || pd.incident?.description}</Text>\n\n {(protest.comment || pd.comment) && (\n <Box mt={3} pt={3} borderTop borderColor=\"border-charcoal-outline/50\">\n <Text size=\"xs\" color=\"text-gray-500\" block mb={1}>Additional details:</Text>\n <Text size=\"sm\" color=\"text-gray-400\">{protest.comment || pd.comment}</Text>\n </Box>\n )}\n </Box>\n </Box>\n </Box>\n </Box>\n\n {/* Defense placeholder */}\n {protest.status === 'awaiting_defense' && (\n <Box p={4} bg=\"bg-purple-500/5\">\n <Box display=\"flex\" gap={3}>\n <Box w={10} h={10} rounded=\"full\" bg=\"bg-purple-500/20\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\" flexShrink={0}>\n <UIIcon icon={MessageCircle} size={5} color=\"text-purple-400\" />\n </Box>\n <Box flexGrow={1}>\n <Text size=\"sm\" color=\"text-purple-400\" weight=\"medium\" block mb={1}>Defense Requested</Text>\n <Text size=\"sm\" color=\"text-gray-400\">Waiting for {accusedDriver?.name || 'the accused driver'} to submit their defense...</Text>\n </Box>\n </Box>\n </Box>\n )}\n\n {/* Decision (if resolved) */}\n {(protest.status === 'upheld' || protest.status === 'dismissed') && protest.decisionNotes && (\n <Box p={4} bg={protest.status === 'upheld' ? 'bg-red-500/5' : 'bg-gray-500/5'}>\n <Box display=\"flex\" gap={3}>\n <Box w={10} h={10} rounded=\"full\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\" flexShrink={0} bg={protest.status === 'upheld' ? 'bg-red-500/20' : 'bg-gray-500/20'}>\n <UIIcon icon={Gavel} size={5} color={protest.status === 'upheld' ? 'text-red-400' : 'text-gray-400'} />\n </Box>\n <Box flexGrow={1} minWidth={0}>\n <Box display=\"flex\" alignItems=\"center\" gap={2} mb={1}>\n <Text weight=\"semibold\" color=\"text-white\" size=\"sm\">Steward Decision</Text>\n <Text size=\"xs\" weight=\"medium\" color={protest.status === 'upheld' ? 'text-red-400' : 'text-gray-400'}>\n {protest.status === 'upheld' ? 'Protest Upheld' : 'Protest Dismissed'}\n </Text>\n {protest.reviewedAt && (\n <>\n <Text size=\"xs\" color=\"text-gray-500\">•</Text>\n <Text size=\"xs\" color=\"text-gray-500\">{new Date(protest.reviewedAt).toLocaleString()}</Text>\n </>\n )}\n </Box>\n \n <Box rounded=\"lg\" p={4} border bg={protest.status === 'upheld' ? 'bg-red-500/10' : 'bg-gray-500/10'} borderColor={protest.status === 'upheld' ? 'border-red-500/20' : 'border-gray-500/20'}>\n <Text size=\"sm\" color=\"text-gray-300\">{protest.decisionNotes}</Text>\n </Box>\n </Box>\n </Box>\n </Box>\n )}\n </Stack>\n\n {/* Add Comment */}\n {isPending && (\n <Box p={4} borderTop borderColor=\"border-charcoal-outline\" bg=\"bg-iron-gray/20\">\n <Box display=\"flex\" gap={3}>\n <Box w={10} h={10} rounded=\"full\" bg=\"bg-iron-gray\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\" flexShrink={0}>\n <UIIcon icon={User} size={5} color=\"text-gray-500\" />\n </Box>\n <Box flexGrow={1}>\n <Box as=\"textarea\"\n value={newComment}\n onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setNewComment(e.target.value)}\n placeholder=\"Add a comment or request more information...\"\n rows={2}\n style={{\n width: '100%',\n padding: '0.75rem 1rem',\n backgroundColor: '#181B1F',\n border: '1px solid #22262A',\n borderRadius: '0.5rem',\n color: 'white',\n fontSize: '0.875rem',\n resize: 'none',\n outline: 'none'\n }}\n />\n <Box display=\"flex\" justifyContent=\"end\" mt={2}>\n <Button variant=\"secondary\" disabled={!newComment.trim()}>\n <UIIcon icon={Send} size={3} style={{ marginRight: '0.25rem' }} />\n Comment\n </Button>\n </Box>\n </Box>\n </Box>\n </Box>\n )}\n </Card>\n </Stack>\n </GridItem>\n\n {/* Right Sidebar - Actions */}\n <GridItem colSpan={12} lgSpan={3}>\n <Stack gap={4}>\n {isPending && (\n <>\n {/* Quick Actions */}\n <Card>\n <Box p={4}>\n <Heading level={3} fontSize=\"xs\" weight=\"semibold\" color=\"text-gray-500\" mb={3}>Actions</Heading>\n \n <Stack gap={2}>\n <Button\n variant=\"secondary\"\n fullWidth\n onClick={handleRequestDefense}\n >\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <UIIcon icon={MessageCircle} size={4} />\n <Text>Request Defense</Text>\n </Stack>\n </Button>\n \n <Button\n variant=\"primary\"\n fullWidth\n onClick={() => setShowDecisionPanel(!showDecisionPanel)}\n >\n <Stack direction=\"row\" align=\"center\" gap={2} fullWidth>\n <UIIcon icon={Gavel} size={4} />\n <Text>Make Decision</Text>\n <Box ml=\"auto\" transition style={{ transform: showDecisionPanel ? 'rotate(180deg)' : 'none' }}>\n <UIIcon icon={ChevronDown} size={4} />\n </Box>\n </Stack>\n </Button>\n </Stack>\n </Box>\n </Card>\n\n {/* Decision Panel */}\n {showDecisionPanel && (\n <Card>\n <Box p={4}>\n <Heading level={3} fontSize=\"xs\" weight=\"semibold\" color=\"text-gray-500\" mb={3}>Stewarding Decision</Heading>\n \n {/* Decision Selection */}\n <Grid cols={2} gap={2} mb={4}>\n <Button\n variant=\"ghost\"\n onClick={() => setDecision('uphold')}\n style={{ \n padding: '0.75rem',\n border: '2px solid',\n borderColor: decision === 'uphold' ? '#EF4444' : '#22262A',\n backgroundColor: decision === 'uphold' ? 'rgba(239, 68, 68, 0.1)' : 'transparent'\n }}\n >\n <Stack align=\"center\" gap={1}>\n <UIIcon icon={CheckCircle} size={5} color={decision === 'uphold' ? 'text-red-400' : 'text-gray-500'} />\n <Text size=\"xs\" weight=\"medium\" color={decision === 'uphold' ? 'text-red-400' : 'text-gray-400'}>Uphold</Text>\n </Stack>\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => setDecision('dismiss')}\n style={{ \n padding: '0.75rem',\n border: '2px solid',\n borderColor: decision === 'dismiss' ? '#4B5563' : '#22262A',\n backgroundColor: decision === 'dismiss' ? 'rgba(75, 85, 99, 0.1)' : 'transparent'\n }}\n >\n <Stack align=\"center\" gap={1}>\n <UIIcon icon={XCircle} size={5} color={decision === 'dismiss' ? 'text-gray-300' : 'text-gray-500'} />\n <Text size=\"xs\" weight=\"medium\" color={decision === 'dismiss' ? 'text-gray-300' : 'text-gray-400'}>Dismiss</Text>\n </Stack>\n </Button>\n </Grid>\n\n {/* Penalty Selection (if upholding) */}\n {decision === 'uphold' && (\n <Box mb={4}>\n <Text as=\"label\" size=\"xs\" weight=\"medium\" color=\"text-gray-400\" block mb={2}>Penalty Type</Text>\n\n {penaltyTypes.length === 0 ? (\n <Text size=\"xs\" color=\"text-gray-500\">\n Loading penalty types...\n </Text>\n ) : (\n <>\n <Grid cols={2} gap={2}>\n {penaltyTypes.map((penalty: any) => {\n const Icon = penalty.icon;\n const isSelected = penaltyType === penalty.type;\n return (\n <Button\n key={penalty.type}\n variant=\"ghost\"\n onClick={() => {\n setPenaltyType(penalty.type);\n setPenaltyValue(penalty.defaultValue);\n }}\n style={{ \n padding: '0.5rem',\n border: '1px solid',\n borderColor: isSelected ? undefined : '#22262A',\n backgroundColor: isSelected ? undefined : 'rgba(24, 27, 31, 0.3)'\n }}\n color={isSelected ? penalty.color : undefined}\n title={penalty.description}\n >\n <Stack align=\"start\" gap={0.5}>\n <UIIcon icon={Icon} size={3.5} color={isSelected ? undefined : 'text-gray-500'} />\n <Text size=\"xs\" weight=\"medium\" style={{ fontSize: '10px' }} color={isSelected ? undefined : 'text-gray-500'}>\n {penalty.label}\n </Text>\n </Stack>\n </Button>\n );\n })}\n </Grid>\n\n {selectedPenalty?.requiresValue && (\n <Box mt={3}>\n <Text as=\"label\" size=\"xs\" weight=\"medium\" color=\"text-gray-400\" block mb={1}>\n Value ({selectedPenalty.valueLabel})\n </Text>\n <Box as=\"input\"\n type=\"number\"\n value={penaltyValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPenaltyValue(Number(e.target.value))}\n min=\"1\"\n style={{\n width: '100%',\n padding: '0.5rem 0.75rem',\n backgroundColor: '#181B1F',\n border: '1px solid #22262A',\n borderRadius: '0.5rem',\n color: 'white',\n fontSize: '0.875rem',\n outline: 'none'\n }}\n />\n </Box>\n )}\n </>\n )}\n </Box>\n )}\n\n {/* Steward Notes */}\n <Box mb={4}>\n <Text as=\"label\" size=\"xs\" weight=\"medium\" color=\"text-gray-400\" block mb={1}>Decision Reasoning *</Text>\n <Box as=\"textarea\"\n value={stewardNotes}\n onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setStewardNotes(e.target.value)}\n placeholder=\"Explain your decision...\"\n rows={4}\n style={{\n width: '100%',\n padding: '0.5rem 0.75rem',\n backgroundColor: '#181B1F',\n border: '1px solid #22262A',\n borderRadius: '0.5rem',\n color: 'white',\n fontSize: '0.875rem',\n resize: 'none',\n outline: 'none'\n }}\n />\n </Box>\n\n {/* Submit */}\n <Button\n variant=\"primary\"\n fullWidth\n onClick={handleSubmitDecision}\n disabled={!decision || !stewardNotes.trim() || submitting}\n >\n {submitting ? 'Submitting...' : 'Submit Decision'}\n </Button>\n </Box>\n </Card>\n )}\n </>\n )}\n\n {/* Already Resolved Info */}\n {!isPending && (\n <Card>\n <Box p={4} textAlign=\"center\">\n <Box py={4} color={protest.status === 'upheld' ? 'text-red-400' : 'text-gray-400'}>\n <UIIcon icon={Gavel} size={8} style={{ margin: '0 auto 0.5rem' }} />\n <Text weight=\"semibold\" block>Case Closed</Text>\n <Text size=\"xs\" color=\"text-gray-500\" block mt={1}>\n {protest.status === 'upheld' ? 'Protest was upheld' : 'Protest was dismissed'}\n </Text>\n </Box>\n </Box>\n </Card>\n )}\n </Stack>\n </GridItem>\n </Grid>\n </Box>\n );\n }}\n </StateContainer>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/stewarding/protests/[protestId]/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/wallet/LeagueWalletPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/[id]/wallet/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/create/CreateLeagueWizard.tsx","messages":[{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueBasicsSection'.","line":31,"column":37,"nodeType":"Literal","endLine":31,"endColumn":60},{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueDropSection'.","line":32,"column":35,"nodeType":"Literal","endLine":32,"endColumn":56},{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueScoringSection'.","line":36,"column":8,"nodeType":"Literal","endLine":36,"endColumn":32},{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueStewardingSection'.","line":37,"column":41,"nodeType":"Literal","endLine":37,"endColumn":68},{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueStructureSection'.","line":38,"column":40,"nodeType":"Literal","endLine":38,"endColumn":66},{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueTimingsSection'.","line":39,"column":38,"nodeType":"Literal","endLine":39,"endColumn":62},{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './LeagueVisibilitySection'.","line":40,"column":41,"nodeType":"Literal","endLine":40,"endColumn":68},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":288,"column":34,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":288,"endColumn":37,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8095,8098],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8095,8098],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":319,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":319,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8985,8988],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8985,8988],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":368,"column":99,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":368,"endColumn":102,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[11470,11473],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[11470,11473],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":412,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":412,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12713,12716],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12713,12716],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'submit' is assigned a value but never used.","line":474,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":474,"endColumn":21},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":590,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":983,"endColumn":12},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":590,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":590,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":590,"column":35,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":590,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":592,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":609,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":592,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":592,"endColumn":29},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":592,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":592,"endColumn":28},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":593,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":608,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":593,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":593,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":593,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":593,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":594,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":596,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":594,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":594,"endColumn":169},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":594,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":594,"endColumn":168},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":595,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":595,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":597,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":597,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":598,"column":32,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":598,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":601,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":603,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":601,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":601,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":601,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":601,"endColumn":49},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":602,"column":17,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[19876,19930],"text":"\n We'll also set up your first season in "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[19876,19930],"text":"\n We‘ll also set up your first season in "},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[19876,19930],"text":"\n We'll also set up your first season in "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[19876,19930],"text":"\n We’ll also set up your first season in "},"desc":"Replace with `’`."}]},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":604,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":606,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":604,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":604,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":604,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":604,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":612,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":677,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":612,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":612,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":612,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":612,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":613,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":676,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":613,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":613,"endColumn":35},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":613,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":613,"endColumn":34},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":615,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":615,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":615,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":615,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":615,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":615,"endColumn":96},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":617,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":620,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":617,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":620,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":618,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":618,"endColumn":150},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":619,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":619,"endColumn":90},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":622,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":675,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":622,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":622,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":622,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":622,"endColumn":57},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":630,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":672,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":630,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":636,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":635,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":635,"endColumn":124},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":637,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":656,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":637,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":650,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":638,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":649,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":652,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":652,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":654,"column":33,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":654,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":657,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":671,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":657,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":657,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":657,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":657,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":658,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":670,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":658,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":668,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":659,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":667,"endColumn":26},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":680,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":713,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":680,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":680,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":680,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":680,"endColumn":38},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":681,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":689,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":681,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":681,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":681,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":681,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":682,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":685,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":682,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":682,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":682,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":682,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":683,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":683,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":684,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":684,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":684,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":684,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":684,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":684,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":686,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":688,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":686,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":686,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":686,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":686,"endColumn":50},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":690,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":695,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":690,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":690,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":690,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":690,"endColumn":80},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":691,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":694,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":691,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":694,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":692,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":692,"endColumn":129},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":693,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":693,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":697,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":712,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":697,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":697,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":697,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":697,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":699,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":710,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":699,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":710,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":701,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":709,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":716,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":716,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":718,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":718,"endColumn":128},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":718,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":718,"endColumn":128},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":718,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":718,"endColumn":125},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":721,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":743,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":721,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":721,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":721,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":721,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":722,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":724,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":722,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":722,"endColumn":144},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":722,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":722,"endColumn":143},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":723,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":723,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":725,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":737,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":725,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":725,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":725,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":725,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":726,"column":32,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":726,"endColumn":88},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":727,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":732,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":727,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":727,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":727,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":727,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":728,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":728,"endColumn":23},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":729,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":731,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":729,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":729,"endColumn":170},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":729,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":729,"endColumn":169},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":734,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":736,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":734,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":734,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":734,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":734,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":738,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":742,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":738,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":738,"endColumn":137},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":738,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":738,"endColumn":136},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":739,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":739,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":739,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":739,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":739,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":739,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":740,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":740,"endColumn":77},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":740,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":740,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":740,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":740,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":741,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":741,"endColumn":76},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":741,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":741,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":741,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":741,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":746,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":746,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":746,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":746,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":746,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":746,"endColumn":105},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":749,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":915,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":749,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":749,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":749,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":749,"endColumn":39},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":751,"column":12,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":787,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":751,"column":12,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":751,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":751,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":751,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":757,"column":14,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":786,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":757,"column":14,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":757,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":757,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":757,"endColumn":92},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":758,"column":16,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":767,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":758,"column":16,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":758,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":758,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":758,"endColumn":77},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":759,"column":18,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":759,"endColumn":23},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":760,"column":20,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":762,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":760,"column":20,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":760,"endColumn":95},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":760,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":760,"endColumn":94},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":763,"column":20,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":765,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":763,"column":20,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":763,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":763,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":763,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":768,"column":16,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":785,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":768,"column":16,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":768,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":768,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":768,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":769,"column":18,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":771,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":769,"column":18,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":769,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":769,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":769,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":782,"column":18,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":784,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":782,"column":18,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":782,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":782,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":782,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":791,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":801,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":791,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":791,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":791,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":791,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":805,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":819,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":805,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":805,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":805,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":805,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":806,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":813,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":806,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":806,"endColumn":37},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":806,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":806,"endColumn":36},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":807,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":809,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":807,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":807,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":807,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":807,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":810,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":812,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":810,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":810,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":810,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":810,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":823,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":837,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":823,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":823,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":823,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":823,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":824,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":831,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":824,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":824,"endColumn":37},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":824,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":824,"endColumn":36},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":825,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":827,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":825,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":825,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":825,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":825,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":828,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":830,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":828,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":828,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":828,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":828,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":841,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":883,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":841,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":841,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":841,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":841,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":842,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":849,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":842,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":842,"endColumn":37},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":842,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":842,"endColumn":36},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":843,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":845,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":843,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":843,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":843,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":843,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":846,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":848,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":846,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":846,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":846,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":846,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":869,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":869,"endColumn":109},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":869,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":869,"endColumn":109},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":869,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":869,"endColumn":106},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":872,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":875,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":872,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":872,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":872,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":872,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":878,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":881,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":878,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":878,"endColumn":123},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":878,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":878,"endColumn":122},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":879,"column":32,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":879,"endColumn":86},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":880,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":880,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":880,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":880,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":880,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":880,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":887,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":901,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":887,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":887,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":887,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":887,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":888,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":895,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":888,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":888,"endColumn":37},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":888,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":888,"endColumn":36},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":889,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":891,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":889,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":889,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":889,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":889,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":892,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":894,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":892,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":892,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":892,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":892,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":905,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":913,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":905,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":905,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":905,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":905,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":908,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":911,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":908,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":908,"endColumn":123},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":908,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":908,"endColumn":122},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":909,"column":32,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":909,"endColumn":86},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":910,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":910,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":910,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":910,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":910,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":910,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":919,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":977,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":919,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":919,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":919,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":919,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":925,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":925,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":927,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":927,"endColumn":43},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":928,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":928,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":928,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":928,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":928,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":928,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":931,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":976,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":931,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":931,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":931,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":931,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":933,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":943,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":933,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":933,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":933,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":933,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":935,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":941,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":935,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":941,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":937,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":940,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":951,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":951,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":953,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":953,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":954,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":954,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":961,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":961,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":965,"column":28,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":965,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":966,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":966,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":970,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":970,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":971,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":971,"endColumn":25},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":980,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":982,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":980,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":980,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":980,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":980,"endColumn":60}],"suppressedMessages":[],"errorCount":263,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { LeagueReviewSummary } from '@/components/leagues/LeagueReviewSummary';\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { Heading } from '@/ui/Heading';\nimport { Input } from '@/ui/Input';\nimport { useAuth } from '@/lib/auth/AuthContext';\nimport {\n AlertCircle,\n Award,\n Calendar,\n Check,\n CheckCircle2,\n ChevronLeft,\n ChevronRight,\n FileText,\n Loader2,\n Scale,\n Sparkles,\n Trophy,\n Users,\n} from 'lucide-react';\nimport { useRouter } from 'next/navigation';\nimport { FormEvent, useCallback, useEffect, useState } from 'react';\n\nimport { LeagueWizardCommandModel } from '@/lib/command-models/leagues/LeagueWizardCommandModel';\n\nimport { useCreateLeagueWizard } from \"@/hooks/useLeagueWizardService\";\nimport { useLeagueScoringPresets } from \"@/hooks/useLeagueScoringPresets\";\nimport { LeagueBasicsSection } from './LeagueBasicsSection';\nimport { LeagueDropSection } from './LeagueDropSection';\nimport {\n ChampionshipsSection,\n ScoringPatternSection\n} from './LeagueScoringSection';\nimport { LeagueStewardingSection } from './LeagueStewardingSection';\nimport { LeagueStructureSection } from './LeagueStructureSection';\nimport { LeagueTimingsSection } from './LeagueTimingsSection';\nimport { LeagueVisibilitySection } from './LeagueVisibilitySection';\nimport type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';\nimport type { LeagueScoringPresetViewModel } from '@/lib/view-models/LeagueScoringPresetViewModel';\nimport type { Weekday } from '@/lib/types/Weekday';\nimport type { WizardErrors } from '@/lib/types/WizardErrors';\n\n// ============================================================================\n// LOCAL STORAGE PERSISTENCE\n// ============================================================================\n\nconst STORAGE_KEY = 'gridpilot_league_wizard_draft';\nconst STORAGE_HIGHEST_STEP_KEY = 'gridpilot_league_wizard_highest_step';\n\n// TODO there is a better place for this\nfunction saveFormToStorage(form: LeagueWizardFormModel): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(form));\n } catch {\n // Ignore storage errors (quota exceeded, etc.)\n }\n}\n\n// TODO there is a better place for this\nfunction loadFormFromStorage(): LeagueWizardFormModel | null {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored) as LeagueWizardFormModel;\n if (!parsed.seasonName) {\n const seasonStartDate = parsed.timings?.seasonStartDate;\n parsed.seasonName = getDefaultSeasonName(seasonStartDate);\n }\n return parsed;\n }\n } catch {\n // Ignore parse errors\n }\n return null;\n}\n\nfunction clearFormStorage(): void {\n try {\n localStorage.removeItem(STORAGE_KEY);\n localStorage.removeItem(STORAGE_HIGHEST_STEP_KEY);\n } catch {\n // Ignore storage errors\n }\n}\n\nfunction saveHighestStep(step: number): void {\n try {\n const current = getHighestStep();\n if (step > current) {\n localStorage.setItem(STORAGE_HIGHEST_STEP_KEY, String(step));\n }\n } catch {\n // Ignore storage errors\n }\n}\n\nfunction getHighestStep(): number {\n try {\n const stored = localStorage.getItem(STORAGE_HIGHEST_STEP_KEY);\n return stored ? parseInt(stored, 10) : 1;\n } catch {\n return 1;\n }\n}\n\ntype Step = 1 | 2 | 3 | 4 | 5 | 6 | 7;\n\ntype StepName = 'basics' | 'visibility' | 'structure' | 'schedule' | 'scoring' | 'stewarding' | 'review';\n\ntype LeagueWizardFormModel = LeagueConfigFormModel & {\n seasonName?: string;\n};\n\ninterface CreateLeagueWizardProps {\n stepName: StepName;\n onStepChange: (stepName: StepName) => void;\n}\n\nfunction stepNameToStep(stepName: StepName): Step {\n switch (stepName) {\n case 'basics':\n return 1;\n case 'visibility':\n return 2;\n case 'structure':\n return 3;\n case 'schedule':\n return 4;\n case 'scoring':\n return 5;\n case 'stewarding':\n return 6;\n case 'review':\n return 7;\n }\n}\n\nfunction stepToStepName(step: Step): StepName {\n switch (step) {\n case 1:\n return 'basics';\n case 2:\n return 'visibility';\n case 3:\n return 'structure';\n case 4:\n return 'schedule';\n case 5:\n return 'scoring';\n case 6:\n return 'stewarding';\n case 7:\n return 'review';\n }\n}\n\nfunction getDefaultSeasonStartDate(): string {\n // Default to next Saturday\n const now = new Date();\n const daysUntilSaturday = (6 - now.getDay() + 7) % 7 || 7;\n const nextSaturday = new Date(now);\n nextSaturday.setDate(now.getDate() + daysUntilSaturday);\n const [datePart] = nextSaturday.toISOString().split('T');\n return datePart ?? '';\n}\n\nfunction getDefaultSeasonName(seasonStartDate?: string): string {\n if (seasonStartDate) {\n const parsed = new Date(seasonStartDate);\n if (!Number.isNaN(parsed.getTime())) {\n const year = parsed.getFullYear();\n return `Season 1 (${year})`;\n }\n }\n const fallbackYear = new Date().getFullYear();\n return `Season 1 (${fallbackYear})`;\n}\n\nfunction createDefaultForm(): LeagueWizardFormModel {\n const defaultPatternId = 'sprint-main-driver';\n const defaultSeasonStartDate = getDefaultSeasonStartDate();\n\n return {\n basics: {\n name: '',\n description: '',\n visibility: 'public',\n gameId: 'iracing',\n },\n structure: {\n mode: 'solo',\n maxDrivers: 24,\n multiClassEnabled: false,\n },\n championships: {\n enableDriverChampionship: true,\n enableTeamChampionship: false,\n enableNationsChampionship: false,\n enableTrophyChampionship: false,\n },\n scoring: {\n patternId: defaultPatternId,\n customScoringEnabled: false,\n },\n dropPolicy: {\n strategy: 'bestNResults',\n n: 6,\n },\n timings: {\n practiceMinutes: 20,\n qualifyingMinutes: 30,\n sprintRaceMinutes: 20,\n mainRaceMinutes: 40,\n sessionCount: 2,\n roundsPlanned: 8,\n // Default to Saturday races, weekly, starting next week\n weekdays: ['Sat'] as Weekday[],\n recurrenceStrategy: 'weekly' as const,\n timezoneId: 'UTC',\n seasonStartDate: defaultSeasonStartDate,\n },\n stewarding: {\n decisionMode: 'admin_only',\n requiredVotes: 2,\n requireDefense: false,\n defenseTimeLimit: 48,\n voteTimeLimit: 72,\n protestDeadlineHours: 48,\n stewardingClosesHours: 168,\n notifyAccusedOnProtest: true,\n notifyOnVoteRequired: true,\n },\n seasonName: getDefaultSeasonName(defaultSeasonStartDate),\n };\n}\n\nexport function CreateLeagueWizard({ stepName, onStepChange }: CreateLeagueWizardProps) {\n const router = useRouter();\n const { session } = useAuth();\n\n const step = stepNameToStep(stepName);\n const [loading, setLoading] = useState(false);\n const [presetsLoading, setPresetsLoading] = useState(true);\n const [presets, setPresets] = useState<LeagueScoringPresetViewModel[]>([]);\n const [errors, setErrors] = useState<WizardErrors>({});\n const [highestCompletedStep, setHighestCompletedStep] = useState(1);\n const [isHydrated, setIsHydrated] = useState(false);\n \n // Initialize form from localStorage or defaults\n const [form, setForm] = useState<LeagueWizardFormModel>(() =>\n createDefaultForm(),\n );\n\n // Hydrate from localStorage on mount\n useEffect(() => {\n const stored = loadFormFromStorage();\n if (stored) {\n setForm(stored);\n }\n setHighestCompletedStep(getHighestStep());\n setIsHydrated(true);\n }, []);\n\n // Save form to localStorage whenever it changes (after hydration)\n useEffect(() => {\n if (isHydrated) {\n saveFormToStorage(form);\n }\n }, [form, isHydrated]);\n\n // Track highest step reached\n useEffect(() => {\n if (isHydrated) {\n saveHighestStep(step);\n setHighestCompletedStep((prev) => Math.max(prev, step));\n }\n }, [step, isHydrated]);\n\n // Use the react-query hook for scoring presets\n const { data: queryPresets, error: presetsError } = useLeagueScoringPresets();\n\n // Sync presets from query to local state\n useEffect(() => {\n if (queryPresets) {\n setPresets(queryPresets as any);\n const firstPreset = queryPresets[0];\n if (firstPreset && !form.scoring?.patternId) {\n setForm((prev) => ({\n ...prev,\n scoring: {\n ...prev.scoring,\n patternId: firstPreset.id,\n customScoringEnabled: false,\n },\n }));\n }\n setPresetsLoading(false);\n }\n }, [queryPresets, form.scoring?.patternId]);\n\n // Handle presets error\n useEffect(() => {\n if (presetsError) {\n setErrors((prev) => ({\n ...prev,\n submit: presetsError instanceof Error ? presetsError.message : 'Failed to load scoring presets',\n }));\n }\n }, [presetsError]);\n\n // Use the create league mutation\n const createLeagueMutation = useCreateLeagueWizard();\n\n const validateStep = (currentStep: Step): boolean => {\n // Convert form to LeagueWizardFormData for validation\n const formData: any = {\n leagueId: form.leagueId || '',\n basics: {\n name: form.basics?.name || '',\n description: form.basics?.description || '',\n visibility: (form.basics?.visibility as 'public' | 'private' | 'unlisted') || 'public',\n gameId: form.basics?.gameId || 'iracing',\n },\n structure: {\n mode: (form.structure?.mode as 'solo' | 'fixedTeams') || 'solo',\n maxDrivers: form.structure?.maxDrivers || 0,\n maxTeams: form.structure?.maxTeams || 0,\n driversPerTeam: form.structure?.driversPerTeam || 0,\n },\n championships: {\n enableDriverChampionship: form.championships?.enableDriverChampionship ?? true,\n enableTeamChampionship: form.championships?.enableTeamChampionship ?? false,\n enableNationsChampionship: form.championships?.enableNationsChampionship ?? false,\n enableTrophyChampionship: form.championships?.enableTrophyChampionship ?? false,\n },\n scoring: {\n patternId: form.scoring?.patternId || '',\n customScoringEnabled: form.scoring?.customScoringEnabled ?? false,\n },\n dropPolicy: {\n strategy: (form.dropPolicy?.strategy as 'none' | 'bestNResults' | 'dropWorstN') || 'bestNResults',\n n: form.dropPolicy?.n || 6,\n },\n timings: {\n practiceMinutes: form.timings?.practiceMinutes || 0,\n qualifyingMinutes: form.timings?.qualifyingMinutes || 0,\n sprintRaceMinutes: form.timings?.sprintRaceMinutes || 0,\n mainRaceMinutes: form.timings?.mainRaceMinutes || 0,\n sessionCount: form.timings?.sessionCount || 0,\n roundsPlanned: form.timings?.roundsPlanned || 0,\n },\n stewarding: {\n decisionMode: (form.stewarding?.decisionMode as 'owner_only' | 'admin_vote' | 'steward_panel') || 'admin_only',\n requiredVotes: form.stewarding?.requiredVotes || 0,\n requireDefense: form.stewarding?.requireDefense ?? false,\n defenseTimeLimit: form.stewarding?.defenseTimeLimit || 0,\n voteTimeLimit: form.stewarding?.voteTimeLimit || 0,\n protestDeadlineHours: form.stewarding?.protestDeadlineHours || 0,\n stewardingClosesHours: form.stewarding?.stewardingClosesHours || 0,\n notifyAccusedOnProtest: form.stewarding?.notifyAccusedOnProtest ?? true,\n notifyOnVoteRequired: form.stewarding?.notifyOnVoteRequired ?? true,\n },\n };\n\n const stepErrors = LeagueWizardCommandModel.validateLeagueWizardStep(formData, currentStep as any);\n setErrors((prev) => ({\n ...prev,\n ...stepErrors,\n }));\n return !LeagueWizardCommandModel.hasWizardErrors(stepErrors);\n };\n\n const goToNextStep = () => {\n if (!validateStep(step)) {\n return;\n }\n const nextStep = (step < 7 ? ((step + 1) as Step) : step);\n saveHighestStep(nextStep);\n setHighestCompletedStep((prev) => Math.max(prev, nextStep));\n onStepChange(stepToStepName(nextStep));\n };\n\n const goToPreviousStep = () => {\n const prevStep = (step > 1 ? ((step - 1) as Step) : step);\n onStepChange(stepToStepName(prevStep));\n };\n\n // Navigate to a specific step (only if it's been reached before)\n const goToStep = useCallback((targetStep: Step) => {\n if (targetStep <= highestCompletedStep) {\n onStepChange(stepToStepName(targetStep));\n }\n }, [highestCompletedStep, onStepChange]);\n\n const handleSubmit = async (event: FormEvent) => {\n event.preventDefault();\n if (loading) return;\n\n const ownerId = session?.user.userId;\n if (!ownerId) {\n setErrors((prev) => ({\n ...prev,\n submit: 'You must be logged in to create a league',\n }));\n return;\n }\n\n // Convert form to LeagueWizardFormData for validation\n const formData: any = {\n leagueId: form.leagueId || '',\n basics: {\n name: form.basics?.name || '',\n description: form.basics?.description || '',\n visibility: (form.basics?.visibility as 'public' | 'private' | 'unlisted') || 'public',\n gameId: form.basics?.gameId || 'iracing',\n },\n structure: {\n mode: (form.structure?.mode as 'solo' | 'fixedTeams') || 'solo',\n maxDrivers: form.structure?.maxDrivers || 0,\n maxTeams: form.structure?.maxTeams || 0,\n driversPerTeam: form.structure?.driversPerTeam || 0,\n },\n championships: {\n enableDriverChampionship: form.championships?.enableDriverChampionship ?? true,\n enableTeamChampionship: form.championships?.enableTeamChampionship ?? false,\n enableNationsChampionship: form.championships?.enableNationsChampionship ?? false,\n enableTrophyChampionship: form.championships?.enableTrophyChampionship ?? false,\n },\n scoring: {\n patternId: form.scoring?.patternId || '',\n customScoringEnabled: form.scoring?.customScoringEnabled ?? false,\n },\n dropPolicy: {\n strategy: (form.dropPolicy?.strategy as 'none' | 'bestNResults' | 'dropWorstN') || 'bestNResults',\n n: form.dropPolicy?.n || 6,\n },\n timings: {\n practiceMinutes: form.timings?.practiceMinutes || 0,\n qualifyingMinutes: form.timings?.qualifyingMinutes || 0,\n sprintRaceMinutes: form.timings?.sprintRaceMinutes || 0,\n mainRaceMinutes: form.timings?.mainRaceMinutes || 0,\n sessionCount: form.timings?.sessionCount || 0,\n roundsPlanned: form.timings?.roundsPlanned || 0,\n },\n stewarding: {\n decisionMode: (form.stewarding?.decisionMode as 'owner_only' | 'admin_vote' | 'steward_panel') || 'admin_only',\n requiredVotes: form.stewarding?.requiredVotes || 0,\n requireDefense: form.stewarding?.requireDefense ?? false,\n defenseTimeLimit: form.stewarding?.defenseTimeLimit || 0,\n voteTimeLimit: form.stewarding?.voteTimeLimit || 0,\n protestDeadlineHours: form.stewarding?.protestDeadlineHours || 0,\n stewardingClosesHours: form.stewarding?.stewardingClosesHours || 0,\n notifyAccusedOnProtest: form.stewarding?.notifyAccusedOnProtest ?? true,\n notifyOnVoteRequired: form.stewarding?.notifyOnVoteRequired ?? true,\n },\n };\n\n const allErrors = LeagueWizardCommandModel.validateAllLeagueWizardSteps(formData);\n setErrors((prev) => ({\n ...prev,\n ...allErrors,\n }));\n\n if (LeagueWizardCommandModel.hasWizardErrors(allErrors)) {\n onStepChange('basics');\n return;\n }\n\n setLoading(true);\n setErrors((prev) => {\n const { submit, ...rest } = prev;\n return rest;\n });\n\n try {\n // Use the mutation to create the league\n const result = await createLeagueMutation.mutateAsync({ form, ownerId });\n \n // Clear the draft on successful creation\n clearFormStorage();\n \n // Navigate to the new league\n router.push(`/leagues/${result.leagueId}`);\n } catch (err) {\n const message =\n err instanceof Error ? err.message : 'Failed to create league';\n setErrors((prev) => ({\n ...prev,\n submit: message,\n }));\n setLoading(false);\n }\n };\n\n // Handler for scoring preset selection (timings default from API)\n const handleScoringPresetChange = (patternId: string) => {\n setForm((prev) => {\n const selectedPreset = presets.find((p) => p.id === patternId);\n\n return {\n ...prev,\n scoring: {\n ...prev.scoring,\n patternId,\n customScoringEnabled: false,\n },\n timings: selectedPreset\n ? {\n ...prev.timings,\n practiceMinutes: prev.timings?.practiceMinutes ?? selectedPreset.defaultTimings.practiceMinutes,\n qualifyingMinutes: prev.timings?.qualifyingMinutes ?? selectedPreset.defaultTimings.qualifyingMinutes,\n sprintRaceMinutes: prev.timings?.sprintRaceMinutes ?? selectedPreset.defaultTimings.sprintRaceMinutes,\n mainRaceMinutes: prev.timings?.mainRaceMinutes ?? selectedPreset.defaultTimings.mainRaceMinutes,\n sessionCount: selectedPreset.defaultTimings.sessionCount,\n }\n : prev.timings,\n };\n });\n };\n \n const steps = [\n { id: 1 as Step, label: 'Basics', icon: FileText, shortLabel: 'Name' },\n { id: 2 as Step, label: 'Visibility', icon: Award, shortLabel: 'Type' },\n { id: 3 as Step, label: 'Structure', icon: Users, shortLabel: 'Mode' },\n { id: 4 as Step, label: 'Schedule', icon: Calendar, shortLabel: 'Time' },\n { id: 5 as Step, label: 'Scoring', icon: Trophy, shortLabel: 'Points' },\n { id: 6 as Step, label: 'Stewarding', icon: Scale, shortLabel: 'Rules' },\n { id: 7 as Step, label: 'Review', icon: CheckCircle2, shortLabel: 'Done' },\n ];\n\n const getStepTitle = (currentStep: Step): string => {\n switch (currentStep) {\n case 1:\n return 'Name your league';\n case 2:\n return 'Choose your destiny';\n case 3:\n return 'Choose the structure';\n case 4:\n return 'Set the schedule';\n case 5:\n return 'Scoring & championships';\n case 6:\n return 'Stewarding & protests';\n case 7:\n return 'Review & create';\n default:\n return '';\n }\n };\n\n const getStepSubtitle = (currentStep: Step): string => {\n switch (currentStep) {\n case 1:\n return 'Give your league a memorable name and tell your story.';\n case 2:\n return 'Will you compete for global rankings or race with friends?';\n case 3:\n return 'Define how races in this season will run.';\n case 4:\n return 'Plan when this season’s races happen.';\n case 5:\n return 'Choose how points and drop scores work for this season.';\n case 6:\n return 'Set how protests and stewarding work for this season.';\n case 7:\n return 'Review your league and first season before launching.';\n default:\n return '';\n }\n };\n\n const getStepContextLabel = (currentStep: Step): string => {\n if (currentStep === 1 || currentStep === 2) {\n return 'League setup';\n }\n if (currentStep >= 3 && currentStep <= 6) {\n return 'Season setup';\n }\n return 'League & Season summary';\n };\n\n const currentStepData = steps.find((s) => s.id === step);\n const CurrentStepIcon = currentStepData?.icon ?? FileText;\n\n return (\n <form onSubmit={handleSubmit} className=\"max-w-4xl mx-auto pb-8\">\n {/* Header with icon */}\n <div className=\"mb-8\">\n <div className=\"flex items-center gap-3 mb-3\">\n <div className=\"flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-primary-blue/20 to-primary-blue/5 border border-primary-blue/20\">\n <Sparkles className=\"w-5 h-5 text-primary-blue\" />\n </div>\n <div>\n <Heading level={1} className=\"text-2xl sm:text-3xl\">\n Create a new league\n </Heading>\n <p className=\"text-sm text-gray-500\">\n We'll also set up your first season in {steps.length} easy steps.\n </p>\n <p className=\"text-xs text-gray-500 mt-1\">\n A league is your long-term brand. Each season is a block of races you can run again and again.\n </p>\n </div>\n </div>\n </div>\n\n {/* Desktop Progress Bar */}\n <div className=\"hidden md:block mb-8\">\n <div className=\"relative\">\n {/* Background track */}\n <div className=\"absolute top-5 left-6 right-6 h-0.5 bg-charcoal-outline rounded-full\" />\n {/* Progress fill */}\n <div\n className=\"absolute top-5 left-6 h-0.5 bg-gradient-to-r from-primary-blue to-neon-aqua rounded-full transition-all duration-500 ease-out\"\n style={{ width: `calc(${((step - 1) / (steps.length - 1)) * 100}% - 48px)` }}\n />\n\n <div className=\"relative flex justify-between\">\n {steps.map((wizardStep) => {\n const isCompleted = wizardStep.id < step;\n const isCurrent = wizardStep.id === step;\n const isAccessible = wizardStep.id <= highestCompletedStep;\n const StepIcon = wizardStep.icon;\n\n return (\n <button\n key={wizardStep.id}\n type=\"button\"\n onClick={() => goToStep(wizardStep.id)}\n disabled={!isAccessible}\n className=\"flex flex-col items-center bg-transparent border-0 cursor-pointer disabled:cursor-not-allowed\"\n >\n <div\n className={`\n relative z-10 flex h-10 w-10 items-center justify-center rounded-full\n transition-all duration-300 ease-out\n ${isCurrent\n ? 'bg-primary-blue text-white shadow-[0_0_24px_rgba(25,140,255,0.5)] scale-110'\n : isCompleted\n ? 'bg-primary-blue text-white hover:scale-105'\n : isAccessible\n ? 'bg-iron-gray text-gray-400 border-2 border-charcoal-outline hover:border-primary-blue/50'\n : 'bg-iron-gray text-gray-500 border-2 border-charcoal-outline opacity-60'\n }\n `}\n >\n {isCompleted ? (\n <Check className=\"w-4 h-4\" strokeWidth={3} />\n ) : (\n <StepIcon className=\"w-4 h-4\" />\n )}\n </div>\n <div className=\"mt-2 text-center\">\n <p\n className={`text-xs font-medium transition-colors duration-200 ${\n isCurrent\n ? 'text-white'\n : isCompleted\n ? 'text-primary-blue'\n : isAccessible\n ? 'text-gray-400'\n : 'text-gray-500'\n }`}\n >\n {wizardStep.label}\n </p>\n </div>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n\n {/* Mobile Progress */}\n <div className=\"md:hidden mb-6\">\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center gap-2\">\n <CurrentStepIcon className=\"w-4 h-4 text-primary-blue\" />\n <span className=\"text-sm font-medium text-white\">{currentStepData?.label}</span>\n </div>\n <span className=\"text-xs text-gray-500\">\n {step}/{steps.length}\n </span>\n </div>\n <div className=\"h-1.5 bg-charcoal-outline rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-gradient-to-r from-primary-blue to-neon-aqua rounded-full transition-all duration-500 ease-out\"\n style={{ width: `${(step / steps.length) * 100}%` }}\n />\n </div>\n {/* Step dots */}\n <div className=\"flex justify-between mt-2 px-0.5\">\n {steps.map((s) => (\n <div\n key={s.id}\n className={`\n h-1.5 rounded-full transition-all duration-300\n ${s.id === step\n ? 'w-4 bg-primary-blue'\n : s.id < step\n ? 'w-1.5 bg-primary-blue/60'\n : 'w-1.5 bg-charcoal-outline'\n }\n `}\n />\n ))}\n </div>\n </div>\n\n {/* Main Card */}\n <Card className=\"relative overflow-hidden\">\n {/* Top gradient accent */}\n <div className=\"absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-transparent via-primary-blue to-transparent\" />\n\n {/* Step header */}\n <div className=\"flex items-start gap-4 mb-6\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-xl bg-primary-blue/10 shrink-0 transition-transform duration-300\">\n <CurrentStepIcon className=\"w-6 h-6 text-primary-blue\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <Heading level={2} className=\"text-xl sm:text-2xl text-white leading-tight\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span>{getStepTitle(step)}</span>\n <span className=\"inline-flex items-center px-2 py-0.5 rounded-full border border-charcoal-outline bg-iron-gray/60 text-[11px] font-medium text-gray-300\">\n {getStepContextLabel(step)}\n </span>\n </div>\n </Heading>\n <p className=\"text-sm text-gray-400 mt-1\">\n {getStepSubtitle(step)}\n </p>\n </div>\n <div className=\"hidden sm:flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-deep-graphite border border-charcoal-outline\">\n <span className=\"text-xs text-gray-500\">Step</span>\n <span className=\"text-sm font-semibold text-white\">{step}</span>\n <span className=\"text-xs text-gray-500\">/ {steps.length}</span>\n </div>\n </div>\n\n {/* Divider */}\n <div className=\"h-px bg-gradient-to-r from-transparent via-charcoal-outline to-transparent mb-6\" />\n\n {/* Step content with min-height for consistency */}\n <div className=\"min-h-[320px]\">\n {step === 1 && (\n <div className=\"animate-fade-in space-y-8\">\n <LeagueBasicsSection\n form={form}\n onChange={setForm}\n errors={errors.basics ?? {}}\n />\n <div className=\"rounded-xl border border-charcoal-outline bg-iron-gray/40 p-4\">\n <div className=\"flex items-center justify-between gap-2 mb-2\">\n <div>\n <p className=\"text-xs font-semibold text-gray-300 uppercase tracking-wide\">\n First season\n </p>\n <p className=\"text-xs text-gray-500\">\n Name the first season that will run in this league.\n </p>\n </div>\n </div>\n <div className=\"space-y-2 mt-2\">\n <label className=\"text-sm font-medium text-gray-300\">\n Season name\n </label>\n <Input\n value={form.seasonName ?? ''}\n onChange={(e) =>\n setForm((prev) => ({\n ...prev,\n seasonName: e.target.value,\n }))\n }\n placeholder=\"e.g., Season 1 (2025)\"\n />\n <p className=\"text-xs text-gray-500\">\n Seasons are the individual competitive runs inside your league. You can run Season 2, Season 3, or parallel seasons later.\n </p>\n </div>\n </div>\n </div>\n )}\n\n {step === 2 && (\n <div className=\"animate-fade-in\">\n <LeagueVisibilitySection\n form={form}\n onChange={setForm}\n errors={\n errors.basics?.visibility\n ? { visibility: errors.basics.visibility }\n : {}\n }\n />\n </div>\n )}\n\n {step === 3 && (\n <div className=\"animate-fade-in space-y-4\">\n <div className=\"mb-2\">\n <p className=\"text-xs text-gray-500\">\n Applies to: First season of this league.\n </p>\n <p className=\"text-xs text-gray-500\">\n These settings only affect this season. Future seasons can use different formats.\n </p>\n </div>\n <LeagueStructureSection\n form={form}\n onChange={setForm}\n readOnly={false}\n />\n </div>\n )}\n\n {step === 4 && (\n <div className=\"animate-fade-in space-y-4\">\n <div className=\"mb-2\">\n <p className=\"text-xs text-gray-500\">\n Applies to: First season of this league.\n </p>\n <p className=\"text-xs text-gray-500\">\n These settings only affect this season. Future seasons can use different formats.\n </p>\n </div>\n <LeagueTimingsSection\n form={form}\n onChange={setForm}\n errors={errors.timings ?? {}}\n />\n </div>\n )}\n\n {step === 5 && (\n <div className=\"animate-fade-in space-y-8\">\n <div className=\"mb-2\">\n <p className=\"text-xs text-gray-500\">\n Applies to: First season of this league.\n </p>\n <p className=\"text-xs text-gray-500\">\n These settings only affect this season. Future seasons can use different formats.\n </p>\n </div>\n {/* Scoring Pattern Selection */}\n <ScoringPatternSection\n scoring={form.scoring || {}}\n presets={presets}\n readOnly={presetsLoading}\n patternError={errors.scoring?.patternId ?? ''}\n onChangePatternId={handleScoringPresetChange}\n onToggleCustomScoring={() =>\n setForm((prev) => ({\n ...prev,\n scoring: {\n ...prev.scoring,\n customScoringEnabled: !(prev.scoring?.customScoringEnabled),\n },\n }))\n }\n />\n\n {/* Divider */}\n <div className=\"h-px bg-gradient-to-r from-transparent via-charcoal-outline to-transparent\" />\n \n {/* Championships & Drop Rules side by side on larger screens */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <ChampionshipsSection form={form} onChange={setForm} readOnly={presetsLoading} />\n <LeagueDropSection form={form} onChange={setForm} readOnly={false} />\n </div>\n\n {errors.submit && (\n <div className=\"flex items-start gap-3 rounded-lg bg-warning-amber/10 p-4 border border-warning-amber/20\">\n <AlertCircle className=\"w-5 h-5 text-warning-amber shrink-0 mt-0.5\" />\n <p className=\"text-sm text-warning-amber\">{errors.submit}</p>\n </div>\n )}\n </div>\n )}\n\n {step === 6 && (\n <div className=\"animate-fade-in space-y-4\">\n <div className=\"mb-2\">\n <p className=\"text-xs text-gray-500\">\n Applies to: First season of this league.\n </p>\n <p className=\"text-xs text-gray-500\">\n These settings only affect this season. Future seasons can use different formats.\n </p>\n </div>\n <LeagueStewardingSection\n form={form}\n onChange={setForm}\n readOnly={false}\n />\n </div>\n )}\n\n {step === 7 && (\n <div className=\"animate-fade-in space-y-6\">\n <LeagueReviewSummary form={form} presets={presets} />\n {errors.submit && (\n <div className=\"flex items-start gap-3 rounded-lg bg-warning-amber/10 p-4 border border-warning-amber/20\">\n <AlertCircle className=\"w-5 h-5 text-warning-amber shrink-0 mt-0.5\" />\n <p className=\"text-sm text-warning-amber\">{errors.submit}</p>\n </div>\n )}\n </div>\n )}\n </div>\n </Card>\n\n {/* Navigation */}\n <div className=\"flex justify-between items-center mt-6\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={step === 1 || loading}\n onClick={goToPreviousStep}\n className=\"flex items-center gap-2\"\n >\n <ChevronLeft className=\"w-4 h-4\" />\n <span className=\"hidden sm:inline\">Back</span>\n </Button>\n\n <div className=\"flex items-center gap-3\">\n {/* Mobile step dots */}\n <div className=\"flex sm:hidden items-center gap-1\">\n {steps.map((s) => (\n <div\n key={s.id}\n className={`\n h-1.5 rounded-full transition-all duration-300\n ${s.id === step ? 'w-3 bg-primary-blue' : s.id < step ? 'w-1.5 bg-primary-blue/50' : 'w-1.5 bg-charcoal-outline'}\n `}\n />\n ))}\n </div>\n\n {step < 7 ? (\n <Button\n type=\"button\"\n variant=\"primary\"\n disabled={loading}\n onClick={goToNextStep}\n className=\"flex items-center gap-2\"\n >\n <span>Continue</span>\n <ChevronRight className=\"w-4 h-4\" />\n </Button>\n ) : (\n <Button\n type=\"submit\"\n variant=\"primary\"\n disabled={loading}\n className=\"flex items-center gap-2 min-w-[150px] justify-center\"\n >\n {loading ? (\n <>\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n <span>Creating…</span>\n </>\n ) : (\n <>\n <Sparkles className=\"w-4 h-4\" />\n <span>Create League</span>\n </>\n )}\n </Button>\n )}\n </div>\n </div>\n\n {/* Helper text */}\n <p className=\"text-center text-xs text-gray-500 mt-4\">\n This will create your league and its first season. You can edit both later.\n </p>\n </form>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/create/page.tsx","messages":[{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module '@/components/leagues/CreateLeagueWizard'.","line":5,"column":32,"nodeType":"Literal","endLine":5,"endColumn":73},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":11,"column":1,"nodeType":"FunctionDeclaration","messageId":"message","endLine":24,"endColumn":2},{"ruleId":"gridpilot-rules/no-hardcoded-search-params","severity":2,"message":"Manual search param access with get(). Use SearchParamParser instead: import { SearchParamParser } from \"@/lib/routing/search-params\"","line":32,"column":9,"nodeType":"MemberExpression","messageId":"manualGetParam","endLine":32,"endColumn":25},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":36,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":46,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":37,"column":20,"nodeType":"NewExpression","messageId":"message","endLine":41,"endColumn":6},{"ruleId":"gridpilot-rules/no-hardcoded-search-params","severity":2,"message":"Manual URLSearchParams construction. Use SearchParamBuilder instead: import { SearchParamBuilder } from \"@/lib/routing/search-params\"","line":37,"column":20,"nodeType":"NewExpression","messageId":"manualSearchParams","endLine":41,"endColumn":6},{"ruleId":"gridpilot-rules/no-hardcoded-search-params","severity":2,"message":"Manual search param setting with set(). Use SearchParamBuilder instead","line":42,"column":5,"nodeType":"CallExpression","messageId":"manualSetParam","endLine":42,"endColumn":33},{"ruleId":"gridpilot-rules/no-hardcoded-search-params","severity":2,"message":"Manual search param setting with set(). Use SearchParamBuilder instead","line":42,"column":5,"nodeType":"MemberExpression","messageId":"manualSetParam","endLine":42,"endColumn":15}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport React from 'react';\nimport { useRouter, useSearchParams } from 'next/navigation';\nimport CreateLeagueWizard from '@/components/leagues/CreateLeagueWizard';\nimport { Section } from '@/ui/Section';\nimport { Container } from '@/ui/Container';\n\ntype StepName = 'basics' | 'visibility' | 'structure' | 'schedule' | 'scoring' | 'stewarding' | 'review';\n\nfunction normalizeStepName(raw: string | null): StepName {\n switch (raw) {\n case 'basics':\n case 'visibility':\n case 'structure':\n case 'schedule':\n case 'scoring':\n case 'stewarding':\n case 'review':\n return raw;\n default:\n return 'basics';\n }\n}\n\nexport default function CreateLeaguePage() {\n const router = useRouter();\n const searchParams = useSearchParams();\n\n const currentStepName = normalizeStepName(\n searchParams && typeof searchParams.get === 'function'\n ? searchParams.get('step')\n : null,\n );\n\n const handleStepChange = (stepName: StepName) => {\n const params = new URLSearchParams(\n searchParams && typeof searchParams.toString === 'function'\n ? searchParams.toString()\n : '',\n );\n params.set('step', stepName);\n const query = params.toString();\n const href = query ? `/leagues/create?${query}` : '/leagues/create';\n router.push(href);\n };\n\n return (\n <Section>\n <Container size=\"md\">\n <CreateLeagueWizard stepName={currentStepName} onStepChange={handleStepChange} />\n </Container>\n </Section>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/leagues/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/avatar/[driverId]/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/categories/[categoryId]/icon/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/leagues/[leagueId]/cover/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/leagues/[leagueId]/logo/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/sponsors/[sponsorId]/logo/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/teams/[teamId]/logo/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/media/tracks/[trackId]/image/route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/not-found.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/onboarding/OnboardingLayoutProps.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/onboarding/OnboardingWizardClient.tsx","messages":[{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module './OnboardingWizard'.","line":3,"column":34,"nodeType":"Literal","endLine":3,"endColumn":54}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { OnboardingWizard } from './OnboardingWizard';\nimport { routes } from '@/lib/routing/RouteConfig';\nimport { completeOnboardingAction } from '@/app/onboarding/completeOnboardingAction';\nimport { generateAvatarsAction } from '@/app/onboarding/generateAvatarsAction';\nimport { useAuth } from '@/lib/auth/AuthContext';\n\nexport function OnboardingWizardClient() {\n const { session } = useAuth();\n\n const handleCompleteOnboarding = async (input: {\n firstName: string;\n lastName: string;\n displayName: string;\n country: string;\n timezone?: string;\n }) => {\n try {\n const result = await completeOnboardingAction(input);\n\n if (result.isErr()) {\n return { success: false, error: result.getError() };\n }\n\n window.location.href = routes.protected.dashboard;\n return { success: true };\n } catch (error) {\n return { success: false, error: 'Failed to complete onboarding' };\n }\n };\n\n const handleGenerateAvatars = async (params: {\n facePhotoData: string;\n suitColor: string;\n }) => {\n if (!session?.user?.userId) {\n return { success: false, error: 'Not authenticated' };\n }\n\n try {\n const result = await generateAvatarsAction({\n userId: session.user.userId,\n facePhotoData: params.facePhotoData,\n suitColor: params.suitColor,\n });\n\n if (result.isErr()) {\n return { success: false, error: result.getError() };\n }\n\n const data = result.unwrap();\n return { success: true, data };\n } catch (error) {\n return { success: false, error: 'Failed to generate avatars' };\n }\n };\n\n return (\n <OnboardingWizard\n onCompleted={() => {\n window.location.href = routes.protected.dashboard;\n }}\n onCompleteOnboarding={handleCompleteOnboarding}\n onGenerateAvatars={handleGenerateAvatars}\n />\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/onboarding/completeOnboardingAction.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/onboarding/generateAvatarsAction.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/onboarding/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/onboarding/page.tsx","messages":[{"ruleId":"import/no-unresolved","severity":2,"message":"Unable to resolve path to module '@/components/onboarding/OnboardingWizardClient'.","line":2,"column":40,"nodeType":"Literal","endLine":2,"endColumn":88}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { redirect } from 'next/navigation';\nimport { OnboardingWizardClient } from '@/components/onboarding/OnboardingWizardClient';\nimport { OnboardingPageQuery } from '@/lib/page-queries/OnboardingPageQuery';\nimport { SearchParamBuilder } from '@/lib/routing/search-params/SearchParamBuilder';\nimport { routes } from '@/lib/routing/RouteConfig';\n\n/**\n * Onboarding Page\n *\n * Server Component that handles authentication and authorization.\n * Redirects to login if not authenticated.\n * Redirects to dashboard if already onboarded.\n */\nexport default async function OnboardingPage() {\n // Use PageQuery to check if user is already onboarded\n const result = await OnboardingPageQuery.execute();\n \n if (result.isErr()) {\n const error = result.getError();\n \n if (error === 'unauthorized') {\n redirect(`${routes.auth.login}${SearchParamBuilder.auth(routes.protected.onboarding)}`);\n } else if (error === 'serverError' || error === 'networkError') {\n // Show error page or let them proceed with a warning\n // For now, we'll let them proceed\n }\n } else {\n const viewData = result.unwrap();\n \n if (viewData.isAlreadyOnboarded) {\n redirect(routes.protected.dashboard);\n }\n }\n\n return <OnboardingWizardClient />;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/page.tsx","messages":[{"ruleId":"gridpilot-rules/rsc-no-unsafe-services","severity":2,"message":"Services import must be explicitly marked as server-safe - see apps/website/lib/contracts/view-models/ViewModel.ts","line":4,"column":1,"nodeType":"ImportDeclaration","messageId":"message","endLine":4,"endColumn":63}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageWrapper } from '@/components/shared/state/PageWrapper';\nimport { HomeTemplate, type HomeViewData } from '@/templates/HomeTemplate';\nimport { PageDataFetcher } from '@/lib/page/PageDataFetcher';\nimport { getHomeData } from '@/lib/services/home/getHomeData';\nimport { notFound } from 'next/navigation';\n\nexport default async function Page() {\n const data = await PageDataFetcher.fetchManual(async () => getHomeData());\n \n if (!data) {\n notFound();\n }\n \n const Template = ({ data }: { data: HomeViewData }) => <HomeTemplate viewData={data} />;\n \n return <PageWrapper data={data} Template={Template} />;\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/ProfilePageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/actions.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/leagues/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/liveries/page.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'Card' is defined but never used.","line":3,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":14},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":17,"column":19,"nodeType":"NewExpression","messageId":"message","endLine":17,"endColumn":29},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":25,"column":19,"nodeType":"NewExpression","messageId":"message","endLine":25,"endColumn":29},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":32,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":40,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":32,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":32,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":32,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":32,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":33,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":33,"endColumn":14},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":35,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":35,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":35,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":35,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":35,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":35,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":48,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":52,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":48,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":48,"endColumn":30},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":48,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":48,"endColumn":29}],"suppressedMessages":[],"errorCount":13,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import Link from 'next/link';\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { Container } from '@/ui/Container';\nimport { Heading } from '@/ui/Heading';\nimport { Grid } from '@/ui/Grid';\nimport { routes } from '@/lib/routing/RouteConfig';\nimport { LiveryCard } from '@/ui/LiveryCard';\n\nexport default async function ProfileLiveriesPage() {\n const mockLiveries = [\n {\n id: '1',\n carId: 'gt3-r',\n carName: 'Porsche 911 GT3 R (992)',\n thumbnailUrl: '',\n uploadedAt: new Date(),\n isValidated: true,\n },\n {\n id: '2',\n carId: 'f3',\n carName: 'Dallara F3',\n thumbnailUrl: '',\n uploadedAt: new Date(),\n isValidated: false,\n }\n ];\n\n return (\n <Container size=\"lg\" py={8}>\n <div className=\"flex items-center justify-between mb-8\">\n <div>\n <Heading level={1}>My Liveries</Heading>\n <p className=\"text-gray-400 mt-1\">Manage your custom car liveries</p>\n </div>\n <Link href={routes.protected.profileLiveryUpload}>\n <Button variant=\"primary\">Upload livery</Button>\n </Link>\n </div>\n\n <Grid cols={3} gap={6}>\n {mockLiveries.map((livery) => (\n <LiveryCard key={livery.id} livery={livery} />\n ))}\n </Grid>\n\n <div className=\"mt-12\">\n <Link href={routes.protected.profile}>\n <Button variant=\"secondary\">Back to profile</Button>\n </Link>\n </div>\n </Container>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/liveries/upload/page.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":13,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":13,"endColumn":12}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import Link from 'next/link';\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { Container } from '@/ui/Container';\nimport { Heading } from '@/ui/Heading';\nimport { routes } from '@/lib/routing/RouteConfig';\n\nexport default async function ProfileLiveryUploadPage() {\n return (\n <Container size=\"md\">\n <Heading level={1}>Upload livery</Heading>\n <Card>\n <p>Livery upload is currently unavailable.</p>\n <Link href={routes.protected.profileLiveries}>\n <Button variant=\"secondary\">Back to liveries</Button>\n </Link>\n </Card>\n </Container>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/settings/page.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":13,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":13,"endColumn":12}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import Link from 'next/link';\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { Container } from '@/ui/Container';\nimport { Heading } from '@/ui/Heading';\nimport { routes } from '@/lib/routing/RouteConfig';\n\nexport default async function ProfileSettingsPage() {\n return (\n <Container size=\"md\">\n <Heading level={1}>Settings</Heading>\n <Card>\n <p>Settings are currently unavailable.</p>\n <Link href={routes.protected.profile}>\n <Button variant=\"secondary\">Back to profile</Button>\n </Link>\n </Card>\n </Container>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/sponsorship-requests/SponsorshipRequestsClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/sponsorship-requests/SponsorshipRequestsPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/sponsorship-requests/actions.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/profile/sponsorship-requests/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/RacesPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/[id]/RaceDetailPageClient.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'showProtestModal' is assigned a value but never used.","line":37,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":37,"endColumn":26},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'setShowProtestModal' is assigned a value but never used.","line":37,"column":28,"nodeType":"Identifier","messageId":"unusedVar","endLine":37,"endColumn":47},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'showEndRaceModal' is assigned a value but never used.","line":38,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":38,"endColumn":26},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'setShowEndRaceModal' is assigned a value but never used.","line":38,"column":28,"nodeType":"Identifier","messageId":"unusedVar","endLine":38,"endColumn":47}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport React, { useState, useEffect } from 'react';\nimport { RaceDetailTemplate, type RaceDetailViewData } from '@/templates/RaceDetailTemplate';\n\ninterface RaceDetailPageClientProps {\n viewData: RaceDetailViewData;\n onBack: () => void;\n onRegister: () => void;\n onWithdraw: () => void;\n onCancel: () => void;\n onReopen: () => void;\n onEndRace: () => void;\n onFileProtest: () => void;\n onResultsClick: () => void;\n onStewardingClick: () => void;\n onLeagueClick: (id: string) => void;\n onDriverClick: (id: string) => void;\n isOwnerOrAdmin: boolean;\n}\n\nexport function RaceDetailPageClient({\n viewData,\n onBack,\n onRegister,\n onWithdraw,\n onCancel,\n onReopen,\n onEndRace,\n onFileProtest,\n onResultsClick,\n onStewardingClick,\n onLeagueClick,\n onDriverClick,\n isOwnerOrAdmin\n}: RaceDetailPageClientProps) {\n const [showProtestModal, setShowProtestModal] = useState(false);\n const [showEndRaceModal, setShowEndRaceModal] = useState(false);\n const [animatedRatingChange, setAnimatedRatingChange] = useState(0);\n\n const ratingChange = viewData.userResult?.ratingChange ?? null;\n\n useEffect(() => {\n if (ratingChange !== null) {\n let start = 0;\n const end = ratingChange;\n const duration = 1000;\n const startTime = performance.now();\n\n const animate = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(elapsed / duration, 1);\n const eased = 1 - Math.pow(1 - progress, 3);\n const current = Math.round(start + (end - start) * eased);\n setAnimatedRatingChange(current);\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n }\n };\n\n requestAnimationFrame(animate);\n }\n }, [ratingChange]);\n\n return (\n <RaceDetailTemplate\n viewData={viewData}\n isLoading={false}\n onBack={onBack}\n onRegister={onRegister}\n onWithdraw={onWithdraw}\n onCancel={onCancel}\n onReopen={onReopen}\n onEndRace={onEndRace}\n onFileProtest={onFileProtest}\n onResultsClick={onResultsClick}\n onStewardingClick={onStewardingClick}\n onLeagueClick={onLeagueClick}\n onDriverClick={onDriverClick}\n isOwnerOrAdmin={isOwnerOrAdmin}\n animatedRatingChange={animatedRatingChange}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/[id]/page.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_data' is defined but never used.","line":35,"column":32,"nodeType":"Identifier","messageId":"unusedVar","endLine":35,"endColumn":37},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":39,"column":24,"nodeType":"NewExpression","messageId":"message","endLine":39,"endColumn":64},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_data' is defined but never used.","line":80,"column":26,"nodeType":"Identifier","messageId":"unusedVar","endLine":80,"endColumn":31}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { notFound } from 'next/navigation';\nimport { PageWrapper } from '@/components/shared/state/PageWrapper';\nimport { RaceDetailTemplate } from '@/templates/RaceDetailTemplate';\nimport { RaceDetailPageQuery } from '@/lib/page-queries/races/RaceDetailPageQuery';\n\ninterface RaceDetailPageProps {\n params: {\n id: string;\n };\n}\n\nexport default async function RaceDetailPage({ params }: RaceDetailPageProps) {\n const raceId = params.id;\n \n if (!raceId) {\n notFound();\n }\n\n // Execute PageQuery\n const result = await RaceDetailPageQuery.execute({ raceId, driverId: '' });\n \n if (result.isErr()) {\n const error = result.getError();\n \n switch (error) {\n case 'notFound':\n notFound();\n case 'redirect':\n notFound();\n default:\n // Pass error to template via PageWrapper\n return (\n <PageWrapper\n data={null}\n Template={({ data: _data }) => (\n <RaceDetailTemplate\n viewData={undefined}\n isLoading={false}\n error={new Error('Failed to load race details')}\n onBack={() => {}}\n onRegister={() => {}}\n onWithdraw={() => {}}\n onCancel={() => {}}\n onReopen={() => {}}\n onEndRace={() => {}}\n onFileProtest={() => {}}\n onResultsClick={() => {}}\n onStewardingClick={() => {}}\n onLeagueClick={() => {}}\n onDriverClick={() => {}}\n isOwnerOrAdmin={false}\n animatedRatingChange={0}\n mutationLoading={{\n register: false,\n withdraw: false,\n cancel: false,\n reopen: false,\n complete: false,\n }}\n />\n )}\n loading={{ variant: 'skeleton', message: 'Loading race details...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: require('lucide-react').Flag,\n title: 'Race not found',\n description: 'The race may have been cancelled or deleted',\n action: { label: 'Back to Races', onClick: () => {} }\n }}\n />\n );\n }\n }\n \n const viewData = result.unwrap();\n \n return (\n <PageWrapper\n data={viewData}\n Template={({ data: _data }) => (\n <RaceDetailTemplate\n viewData={viewData}\n isLoading={false}\n error={null}\n onBack={() => {}}\n onRegister={() => {}}\n onWithdraw={() => {}}\n onCancel={() => {}}\n onReopen={() => {}}\n onEndRace={() => {}}\n onFileProtest={() => {}}\n onResultsClick={() => {}}\n onStewardingClick={() => {}}\n onLeagueClick={() => {}}\n onDriverClick={() => {}}\n isOwnerOrAdmin={false}\n animatedRatingChange={0}\n mutationLoading={{\n register: false,\n withdraw: false,\n cancel: false,\n reopen: false,\n complete: false,\n }}\n />\n )}\n loading={{ variant: 'skeleton', message: 'Loading race details...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: require('lucide-react').Flag,\n title: 'Race not found',\n description: 'The race may have been cancelled or deleted',\n action: { label: 'Back to Races', onClick: () => {} }\n }}\n />\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/[id]/results/page.tsx","messages":[{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":37,"column":20,"nodeType":"NewExpression","messageId":"message","endLine":37,"endColumn":60},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_data' is defined but never used.","line":39,"column":32,"nodeType":"Identifier","messageId":"unusedVar","endLine":39,"endColumn":37},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_data' is defined but never used.","line":88,"column":26,"nodeType":"Identifier","messageId":"unusedVar","endLine":88,"endColumn":31}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { notFound } from 'next/navigation';\nimport { StatefulPageWrapper } from '@/components/shared/state/StatefulPageWrapper';\nimport { RaceResultsTemplate } from '@/templates/RaceResultsTemplate';\nimport { RaceResultsPageQuery } from '@/lib/page-queries/races/RaceResultsPageQuery';\nimport { Trophy } from 'lucide-react';\n\ninterface RaceResultsPageProps {\n params: {\n id: string;\n };\n}\n\nexport default async function RaceResultsPage({ params }: RaceResultsPageProps) {\n const raceId = params.id;\n \n if (!raceId) {\n notFound();\n }\n\n // Execute PageQuery\n const result = await RaceResultsPageQuery.execute({ raceId });\n \n if (result.isErr()) {\n const error = result.getError();\n \n switch (error) {\n case 'notFound':\n notFound();\n case 'redirect':\n notFound();\n default:\n // Pass error to template via StatefulPageWrapper\n return (\n <StatefulPageWrapper\n data={null}\n isLoading={false}\n error={new Error('Failed to load race results')}\n retry={() => Promise.resolve()}\n Template={({ data: _data }) => (\n <RaceResultsTemplate\n viewData={{\n leagueId: '',\n raceId: '',\n raceTrack: '',\n raceScheduledAt: '',\n totalDrivers: 0,\n leagueName: '',\n raceSOF: null,\n results: [],\n penalties: [],\n pointsSystem: {},\n fastestLapTime: 0,\n }}\n isAdmin={false}\n isLoading={false}\n error={null}\n onBack={() => {}}\n onImportResults={() => Promise.resolve()}\n onPenaltyClick={() => {}}\n importing={false}\n importSuccess={false}\n importError={null}\n showImportForm={false}\n setShowImportForm={() => {}}\n />\n )}\n loading={{ variant: 'skeleton', message: 'Loading race results...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: Trophy,\n title: 'No results available',\n description: 'Race results will appear here once the race is completed',\n action: { label: 'Back to Race', onClick: () => {} }\n }}\n />\n );\n }\n }\n \n const viewData = result.unwrap();\n\n return (\n <StatefulPageWrapper\n data={viewData}\n isLoading={false}\n error={null}\n retry={() => Promise.resolve()}\n Template={({ data: _data }) => (\n <RaceResultsTemplate\n viewData={viewData}\n isAdmin={false}\n isLoading={false}\n error={null}\n onBack={() => {}}\n onImportResults={() => Promise.resolve()}\n onPenaltyClick={() => {}}\n importing={false}\n importSuccess={false}\n importError={null}\n showImportForm={false}\n setShowImportForm={() => {}}\n />\n )}\n loading={{ variant: 'skeleton', message: 'Loading race results...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: Trophy,\n title: 'No results available',\n description: 'Race results will appear here once the race is completed',\n action: { label: 'Back to Race', onClick: () => {} }\n }}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/[id]/stewarding/page.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":25,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":25,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[755,758],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[755,758],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":30,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":47,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":38,"column":15,"nodeType":"NewExpression","messageId":"message","endLine":38,"endColumn":59},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":43,"column":45,"nodeType":"NewExpression","messageId":"message","endLine":43,"endColumn":71},{"ruleId":"react-hooks/exhaustive-deps","severity":2,"message":"React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array.","line":51,"column":6,"nodeType":"ArrayExpression","endLine":51,"endColumn":14,"suggestions":[{"desc":"Update the dependencies array to be: [fetchData, raceId]","fix":{"range":[1399,1407],"text":"[fetchData, raceId]"}}]},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":54,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":56,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":58,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":62,"endColumn":4}],"suppressedMessages":[],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { notFound } from 'next/navigation';\nimport { PageWrapper } from '@/components/shared/state/PageWrapper';\nimport { RaceStewardingTemplate, type StewardingTab } from '@/templates/RaceStewardingTemplate';\nimport { RaceStewardingPageQuery } from '@/lib/page-queries/races/RaceStewardingPageQuery';\nimport { Gavel } from 'lucide-react';\nimport { useState, useEffect } from 'react';\n\ninterface RaceStewardingPageProps {\n params: {\n id: string;\n };\n}\n\nexport default function RaceStewardingPage({ params }: RaceStewardingPageProps) {\n const raceId = params.id;\n const [activeTab, setActiveTab] = useState<StewardingTab>('pending');\n \n if (!raceId) {\n notFound();\n }\n\n // Data state\n const [pageData, setPageData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Fetch function\n const fetchData = async () => {\n setIsLoading(true);\n setError(null);\n \n try {\n const result = await RaceStewardingPageQuery.execute({ raceId });\n \n if (result.isErr()) {\n throw new Error('Failed to fetch stewarding data');\n }\n \n setPageData(result.unwrap());\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'));\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n fetchData();\n }, [raceId]);\n\n // Actions\n const handleBack = () => {\n window.history.back();\n };\n\n const handleReviewProtest = (protestId: string) => {\n if (pageData?.league?.id) {\n window.location.href = `/leagues/${pageData.league.id}/stewarding/protests/${protestId}`;\n }\n };\n\n return (\n <PageWrapper\n data={pageData}\n isLoading={isLoading}\n error={error}\n retry={fetchData}\n Template={({ data }) => (\n <RaceStewardingTemplate\n viewData={data}\n isLoading={false}\n error={null}\n onBack={handleBack}\n onReviewProtest={handleReviewProtest}\n isAdmin={false}\n activeTab={activeTab}\n setActiveTab={setActiveTab}\n />\n )}\n loading={{ variant: 'skeleton', message: 'Loading stewarding data...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: Gavel,\n title: 'No stewarding data',\n description: 'No protests or penalties for this race',\n action: { label: 'Back to Race', onClick: handleBack }\n }}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/all/RacesAllPageClient.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":26,"column":76,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":26,"endColumn":79,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[776,779],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[776,779],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1344,1347],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1344,1347],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"react-hooks/exhaustive-deps","severity":2,"message":"React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array.","line":68,"column":6,"nodeType":"ArrayExpression","endLine":68,"endColumn":23,"suggestions":[{"desc":"Update the dependencies array to be: [fetchData, initialViewData]","fix":{"range":[2129,2146],"text":"[fetchData, initialViewData]"}}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":71,"column":52,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":71,"endColumn":55,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2221,2224],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2221,2224],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_data' is defined but never used.","line":128,"column":26,"nodeType":"Identifier","messageId":"unusedVar","endLine":128,"endColumn":31},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":131,"column":36,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":131,"endColumn":39,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4034,4037],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4034,4037],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useState, useEffect } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { StatefulPageWrapper } from '@/components/shared/state/StatefulPageWrapper';\nimport { RacesAllTemplate } from '@/templates/RacesAllTemplate';\nimport { RacesAllPageQuery } from '@/lib/page-queries/races/RacesAllPageQuery';\nimport { Flag } from 'lucide-react';\n\nimport { routes } from '@/lib/routing/RouteConfig';\n\nconst ITEMS_PER_PAGE = 10;\n\ninterface Race {\n id: string;\n track: string;\n car: string;\n scheduledAt: string;\n status: 'scheduled' | 'running' | 'completed' | 'cancelled';\n sessionType: string;\n leagueId?: string;\n leagueName?: string;\n strengthOfField?: number;\n}\n\nexport function RacesAllPageClient({ initialViewData }: { initialViewData: any }) {\n const router = useRouter();\n \n // Client-side state for filters and pagination\n const [currentPage, setCurrentPage] = useState(1);\n const [statusFilter, setStatusFilter] = useState<'scheduled' | 'running' | 'completed' | 'cancelled' | 'all'>('all');\n const [leagueFilter, setLeagueFilter] = useState<string>('all');\n const [searchQuery, setSearchQuery] = useState('');\n const [showFilters, setShowFilters] = useState(false);\n const [showFilterModal, setShowFilterModal] = useState(false);\n\n // Data state\n const [pageData, setPageData] = useState<any>(initialViewData);\n const [isLoading, setIsLoading] = useState(!initialViewData);\n const [error, setError] = useState<Error | null>(null);\n\n // Fetch data\n const fetchData = async () => {\n if (pageData && !isLoading) return; // Already have data from server\n setIsLoading(true);\n setError(null);\n \n try {\n const result = await RacesAllPageQuery.execute();\n \n if (result.isErr()) {\n throw new Error('Failed to fetch races');\n }\n \n setPageData(result.unwrap());\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'));\n } finally {\n setIsLoading(false);\n }\n };\n\n // Fetch on mount if no initial data\n useEffect(() => {\n if (!initialViewData) {\n fetchData();\n }\n }, [initialViewData]);\n\n // Transform data\n const races: Race[] = pageData?.races.map((race: any) => ({\n id: race.id,\n track: race.track || '',\n car: race.car || '',\n scheduledAt: race.scheduledAt,\n status: race.status as 'scheduled' | 'running' | 'completed' | 'cancelled',\n sessionType: 'race',\n leagueId: race.leagueId,\n leagueName: race.leagueName,\n strengthOfField: race.strengthOfField ?? undefined,\n })) ?? [];\n\n // Filter and paginate (Note: This should be done by API per contract)\n const filteredRaces = races.filter((race: Race) => {\n if (statusFilter !== 'all' && race.status !== statusFilter) {\n return false;\n }\n\n if (leagueFilter !== 'all' && race.leagueId !== leagueFilter) {\n return false;\n }\n\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n const matchesTrack = race.track.toLowerCase().includes(query);\n const matchesCar = race.car.toLowerCase().includes(query);\n const matchesLeague = race.leagueName?.toLowerCase().includes(query);\n if (!matchesTrack && !matchesCar && !matchesLeague) {\n return false;\n }\n }\n\n return true;\n });\n\n const totalPages = Math.ceil(filteredRaces.length / ITEMS_PER_PAGE);\n const paginatedRaces = filteredRaces.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE);\n\n // Actions\n const handleRaceClick = (raceId: string) => {\n router.push(routes.race.detail(raceId));\n };\n\n const handleLeagueClick = (leagueId: string) => {\n router.push(routes.league.detail(leagueId));\n };\n\n const handlePageChange = (page: number) => {\n setCurrentPage(page);\n };\n\n return (\n <StatefulPageWrapper\n data={pageData}\n isLoading={isLoading}\n error={error}\n retry={fetchData}\n Template={({ data: _data }) => (\n <RacesAllTemplate\n viewData={pageData}\n races={paginatedRaces as any}\n totalFilteredCount={filteredRaces.length}\n isLoading={false}\n currentPage={currentPage}\n totalPages={totalPages}\n itemsPerPage={ITEMS_PER_PAGE}\n onPageChange={handlePageChange}\n statusFilter={statusFilter}\n setStatusFilter={setStatusFilter}\n leagueFilter={leagueFilter}\n setLeagueFilter={setLeagueFilter}\n searchQuery={searchQuery}\n setSearchQuery={setSearchQuery}\n showFilters={showFilters}\n setShowFilters={setShowFilters}\n showFilterModal={showFilterModal}\n setShowFilterModal={setShowFilterModal}\n onRaceClick={handleRaceClick}\n onLeagueClick={handleLeagueClick}\n />\n )}\n loading={{ variant: 'skeleton', message: 'Loading races...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: Flag,\n title: 'No races found',\n description: 'There are no races available at the moment',\n }}\n />\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/all/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/races/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/billing/page.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'StatusBadge' is defined but never used.","line":9,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":21},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'ArrowRight' is defined but never used.","line":23,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":23,"endColumn":13},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":40,"column":1,"nodeType":"FunctionDeclaration","messageId":"message","endLine":116,"endColumn":2},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":51,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":54,"endColumn":4},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":67,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":76,"endColumn":6},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":71,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":75,"endColumn":10},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":77,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":113,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":77,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":77,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":77,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":77,"endColumn":57},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":78,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":102,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":78,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":78,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":78,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":78,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":79,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":83,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":79,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":81,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":79,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":81,"endColumn":14},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":82,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":82,"endColumn":100},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":84,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":84,"endColumn":16},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":85,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":92,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":85,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":85,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":85,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":85,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":86,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":86,"endColumn":77},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":86,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":86,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":86,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":86,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":88,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":90,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":88,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":88,"endColumn":117},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":88,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":88,"endColumn":116},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":94,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":96,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":94,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":94,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":94,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":94,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":99,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":99,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":99,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":99,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":99,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":99,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":103,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":112,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":103,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":103,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":103,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":103,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":105,"column":64,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":105,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":58,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":109,"endColumn":113},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":118,"column":1,"nodeType":"FunctionDeclaration","messageId":"message","endLine":213,"endColumn":2},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":164,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":169,"endColumn":6},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":168,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":168,"endColumn":154},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":170,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":189,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":170,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":170,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":170,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":170,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":171,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":173,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":171,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":171,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":171,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":171,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":172,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":172,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":174,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":188,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":174,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":174,"endColumn":41},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":174,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":174,"endColumn":40},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":175,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":180,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":175,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":175,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":175,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":175,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":176,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":176,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":176,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":176,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":176,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":176,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":177,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":179,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":177,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":177,"endColumn":100},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":177,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":177,"endColumn":99},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":181,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":187,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":181,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":181,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":181,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":181,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":182,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":182,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":183,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":183,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":184,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":184,"endColumn":19},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":185,"column":16,"nodeType":"MemberExpression","messageId":"message","endLine":185,"endColumn":57},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":185,"column":16,"nodeType":"NewExpression","messageId":"message","endLine":185,"endColumn":38},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":191,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":210,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":191,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":191,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":191,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":191,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":192,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":199,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":192,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":192,"endColumn":37},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":192,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":192,"endColumn":36},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":193,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":195,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":193,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":193,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":193,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":193,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":196,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":198,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":196,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":196,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":196,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":196,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":201,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":204,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":201,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":201,"endColumn":152},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":201,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":201,"endColumn":151},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":202,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":202,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":206,"column":37,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":206,"endColumn":109},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":207,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":207,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":227,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":232,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":227,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":227,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":227,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":227,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":228,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":231,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":228,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":228,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":228,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":228,"endColumn":37},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":229,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":229,"endColumn":127},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":229,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":229,"endColumn":127},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":229,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":229,"endColumn":124},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":230,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":230,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":230,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":230,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":230,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":230,"endColumn":39},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":238,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":247,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":238,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":238,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":238,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":238,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":239,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":246,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":239,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":239,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":239,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":239,"endColumn":37},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":240,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":240,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":240,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":240,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":240,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":240,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":242,"column":57,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":242,"endColumn":73},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":253,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":256,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":258,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":263,"endColumn":4},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":281,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":286,"endColumn":6},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":282,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":282,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":288,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":288,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":299,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":299,"endColumn":113},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":299,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":299,"endColumn":112},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":311,"column":24,"nodeType":"CallExpression","messageId":"message","endLine":311,"endColumn":121},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":317,"column":18,"nodeType":"MemberExpression","messageId":"message","endLine":317,"endColumn":73},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":317,"column":18,"nodeType":"NewExpression","messageId":"message","endLine":317,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":331,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":331,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":332,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":332,"endColumn":47},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":337,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":337,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":338,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":338,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":343,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":352,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":343,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":343,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":343,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":343,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":353,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":358,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":353,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":353,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":353,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":353,"endColumn":37},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":355,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":355,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":355,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":355,"endColumn":35},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":355,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":355,"endColumn":34},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":356,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":356,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":363,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":363,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":364,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":364,"endColumn":47},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":370,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":370,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":371,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":371,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":376,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":376,"endColumn":16},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":382,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":391,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":382,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":382,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":382,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":382,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":385,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":385,"endColumn":35},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":389,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":389,"endColumn":116},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":397,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":397,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":397,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":397,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":399,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":399,"endColumn":42},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":400,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":407,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":400,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":400,"endColumn":115},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":400,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":400,"endColumn":114},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":401,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":406,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":401,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":401,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":401,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":401,"endColumn":77},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":402,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":404,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":402,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":402,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":402,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":402,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":403,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":403,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":408,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":420,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":408,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":408,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":408,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":408,"endColumn":31},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":409,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":411,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":409,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":409,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":409,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":409,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":412,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":414,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":412,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":412,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":412,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":412,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":415,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":419,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":415,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":415,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":415,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":415,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":416,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":416,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":417,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":417,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":418,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":418,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":424,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":424,"endColumn":42},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":425,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":432,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":425,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":425,"endColumn":115},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":425,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":425,"endColumn":114},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":426,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":431,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":426,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":426,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":426,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":426,"endColumn":77},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":427,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":429,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":427,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":427,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":427,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":427,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":428,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":428,"endColumn":68},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":433,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":450,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":433,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":433,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":433,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":433,"endColumn":31},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":434,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":436,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":434,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":434,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":434,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":434,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":437,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":446,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":437,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":437,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":437,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":437,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":438,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":441,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":438,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":438,"endColumn":107},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":438,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":438,"endColumn":106},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":439,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":439,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":439,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":439,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":439,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":439,"endColumn":48},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":440,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":440,"endColumn":95},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":440,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":440,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":440,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":440,"endColumn":57},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":442,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":445,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":442,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":442,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":442,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":442,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":443,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":443,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":443,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":443,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":443,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":443,"endColumn":48},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":444,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":444,"endColumn":86},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":444,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":444,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":444,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":444,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":447,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":449,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":447,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":447,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":447,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":447,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":455,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":455,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":455,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":455,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":456,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":456,"endColumn":30},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":457,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":473,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":457,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":457,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":457,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":457,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":458,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":468,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":458,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":458,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":458,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":458,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":459,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":461,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":459,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":459,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":459,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":459,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":460,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":460,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":462,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":462,"endColumn":20},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":463,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":463,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":463,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":463,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":463,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":463,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":464,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":466,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":464,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":464,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":464,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":464,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":471,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":471,"endColumn":53}],"suppressedMessages":[],"errorCount":231,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { Card } from '@/ui/Card';\nimport { Button } from '@/ui/Button';\nimport { StatCard } from '@/ui/StatCard';\nimport { SectionHeader } from '@/ui/SectionHeader';\nimport { StatusBadge } from '@/ui/StatusBadge';\nimport { InfoBanner } from '@/ui/InfoBanner';\nimport { PageHeader } from '@/ui/PageHeader';\nimport { siteConfig } from '@/lib/siteConfig';\nimport { useSponsorBilling } from \"@/hooks/sponsor/useSponsorBilling\";\nimport {\n CreditCard,\n DollarSign,\n Calendar,\n Download,\n Plus,\n Check,\n AlertTriangle,\n FileText,\n ArrowRight,\n TrendingUp,\n Receipt,\n Building2,\n Wallet,\n Clock,\n ChevronRight,\n Info,\n ExternalLink,\n Percent\n} from 'lucide-react';\nimport type { PaymentMethodDTO, InvoiceDTO } from '@/lib/types/tbd/SponsorBillingDTO';\n\n// ============================================================================\n// Components\n// ============================================================================\n\nfunction PaymentMethodCard({\n method,\n onSetDefault,\n onRemove\n}: {\n method: PaymentMethodDTO;\n onSetDefault: () => void;\n onRemove: () => void;\n}) {\n const shouldReduceMotion = useReducedMotion();\n \n const getIcon = () => {\n if (method.type === 'sepa') return Building2;\n return CreditCard;\n };\n \n const Icon = getIcon();\n \n const displayLabel = method.type === 'sepa' && method.bankName\n ? `${method.bankName} •••• ${method.last4}`\n : `${method.brand} •••• ${method.last4}`;\n\n const expiryDisplay = method.expiryMonth && method.expiryYear\n ? `${method.expiryMonth}/${method.expiryYear}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: shouldReduceMotion ? 0 : 0.2 }}\n className={`p-4 rounded-xl border transition-all ${\n method.isDefault\n ? 'border-primary-blue/50 bg-gradient-to-r from-primary-blue/10 to-transparent shadow-[0_0_20px_rgba(25,140,255,0.1)]'\n : 'border-charcoal-outline bg-iron-gray/30 hover:border-charcoal-outline/80'\n }`}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={`w-12 h-12 rounded-xl flex items-center justify-center ${\n method.isDefault ? 'bg-primary-blue/20' : 'bg-iron-gray'\n }`}>\n <Icon className={`w-6 h-6 ${method.isDefault ? 'text-primary-blue' : 'text-gray-400'}`} />\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-white\">{displayLabel}</span>\n {method.isDefault && (\n <span className=\"px-2 py-0.5 rounded-full text-xs bg-primary-blue/20 text-primary-blue font-medium\">\n Default\n </span>\n )}\n </div>\n {expiryDisplay && (\n <span className=\"text-sm text-gray-500\">\n Expires {expiryDisplay}\n </span>\n )}\n {method.type === 'sepa' && (\n <span className=\"text-sm text-gray-500\">SEPA Direct Debit</span>\n )}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {!method.isDefault && (\n <Button variant=\"secondary\" onClick={onSetDefault} className=\"text-xs\">\n Set Default\n </Button>\n )}\n <Button variant=\"secondary\" onClick={onRemove} className=\"text-xs text-gray-400 hover:text-racing-red\">\n Remove\n </Button>\n </div>\n </div>\n </motion.div>\n );\n}\n\nfunction InvoiceRow({ invoice, index }: { invoice: InvoiceDTO; index: number }) {\n const shouldReduceMotion = useReducedMotion();\n \n const statusConfig = {\n paid: {\n icon: Check,\n label: 'Paid',\n color: 'text-performance-green',\n bg: 'bg-performance-green/10',\n border: 'border-performance-green/30'\n },\n pending: {\n icon: Clock,\n label: 'Pending',\n color: 'text-warning-amber',\n bg: 'bg-warning-amber/10',\n border: 'border-warning-amber/30'\n },\n overdue: {\n icon: AlertTriangle,\n label: 'Overdue',\n color: 'text-racing-red',\n bg: 'bg-racing-red/10',\n border: 'border-racing-red/30'\n },\n failed: {\n icon: AlertTriangle,\n label: 'Failed',\n color: 'text-racing-red',\n bg: 'bg-racing-red/10',\n border: 'border-racing-red/30'\n },\n };\n\n const typeLabels = {\n league: 'League',\n team: 'Team',\n driver: 'Driver',\n race: 'Race',\n platform: 'Platform',\n };\n\n const status = statusConfig[invoice.status as keyof typeof statusConfig];\n const StatusIcon = status.icon;\n\n return (\n <motion.div\n initial={{ opacity: 0, x: -10 }}\n animate={{ opacity: 1, x: 0 }}\n transition={{ duration: shouldReduceMotion ? 0 : 0.2, delay: shouldReduceMotion ? 0 : index * 0.05 }}\n className=\"flex items-center justify-between p-4 border-b border-charcoal-outline/50 last:border-b-0 hover:bg-iron-gray/20 transition-colors group\"\n >\n <div className=\"flex items-center gap-4 flex-1\">\n <div className=\"w-10 h-10 rounded-lg bg-iron-gray flex items-center justify-center\">\n <Receipt className=\"w-5 h-5 text-gray-400\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 mb-0.5\">\n <span className=\"font-medium text-white truncate\">{invoice.description}</span>\n <span className=\"px-2 py-0.5 rounded text-xs bg-iron-gray text-gray-400 flex-shrink-0\">\n {typeLabels[invoice.sponsorshipType as keyof typeof typeLabels]}\n </span>\n </div>\n <div className=\"flex items-center gap-3 text-sm text-gray-500\">\n <span>{invoice.invoiceNumber}</span>\n <span>•</span>\n <span>\n {new Date(invoice.date).toLocaleDateString()}\n </span>\n </div>\n </div>\n </div>\n \n <div className=\"flex items-center gap-6\">\n <div className=\"text-right\">\n <div className=\"font-semibold text-white\">\n ${invoice.totalAmount.toFixed(2)}\n </div>\n <div className=\"text-xs text-gray-500\">\n incl. ${invoice.vatAmount.toFixed(2)} VAT\n </div>\n </div>\n\n <div className={`flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${status.bg} ${status.color} border ${status.border}`}>\n <StatusIcon className=\"w-3 h-3\" />\n {status.label}\n </div>\n \n <Button variant=\"secondary\" className=\"text-xs opacity-0 group-hover:opacity-100 transition-opacity\">\n <Download className=\"w-3 h-3 mr-1\" />\n PDF\n </Button>\n </div>\n </motion.div>\n );\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport default function SponsorBillingPage() {\n const shouldReduceMotion = useReducedMotion();\n const [showAllInvoices, setShowAllInvoices] = useState(false);\n\n const { data: billingData, isLoading, error, retry } = useSponsorBilling('demo-sponsor-1');\n\n if (isLoading) {\n return (\n <div className=\"max-w-5xl mx-auto py-8 px-4 flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center\">\n <div className=\"w-8 h-8 border-2 border-primary-blue border-t-transparent rounded-full animate-spin mx-auto mb-4\" />\n <p className=\"text-gray-400\">Loading billing data...</p>\n </div>\n </div>\n );\n }\n\n if (error || !billingData) {\n return (\n <div className=\"max-w-5xl mx-auto py-8 px-4 flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center\">\n <p className=\"text-gray-400\">{error?.message || 'No billing data available'}</p>\n {error && (\n <Button variant=\"secondary\" onClick={retry} className=\"mt-4\">\n Retry\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n const data = billingData;\n\n const handleSetDefault = (methodId: string) => {\n // In a real app, this would call an API\n console.log('Setting default payment method:', methodId);\n };\n\n const handleRemoveMethod = (methodId: string) => {\n if (confirm('Remove this payment method?')) {\n // In a real app, this would call an API\n console.log('Removing payment method:', methodId);\n }\n };\n\n const containerVariants = {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: shouldReduceMotion ? 0 : 0.1,\n },\n },\n };\n\n const itemVariants = {\n hidden: { opacity: 0, y: 20 },\n visible: { opacity: 1, y: 0 },\n };\n\n return (\n <motion.div\n className=\"max-w-5xl mx-auto py-8 px-4\"\n variants={containerVariants}\n initial=\"hidden\"\n animate=\"visible\"\n >\n {/* Header */}\n <motion.div variants={itemVariants}>\n <PageHeader\n icon={Wallet}\n title=\"Billing & Payments\"\n description=\"Manage payment methods, view invoices, and track your sponsorship spending\"\n iconGradient=\"from-warning-amber/20 to-warning-amber/5\"\n iconBorder=\"border-warning-amber/30\"\n />\n </motion.div>\n\n {/* Stats Grid */}\n <motion.div variants={itemVariants} className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8\">\n <StatCard\n icon={DollarSign}\n label=\"Total Spent\"\n value={`$${data.stats.totalSpent.toFixed(2)}`}\n subValue=\"All time\"\n variant=\"green\"\n />\n <StatCard\n icon={AlertTriangle}\n label=\"Pending Payments\"\n value={`$${data.stats.pendingAmount.toFixed(2)}`}\n subValue={`${data.invoices.filter((i: { status: string }) => i.status === 'pending' || i.status === 'overdue').length} invoices`}\n variant=\"orange\"\n />\n <StatCard\n icon={Calendar}\n label=\"Next Payment\"\n value={new Date(data.stats.nextPaymentDate).toLocaleDateString()}\n subValue={`$${data.stats.nextPaymentAmount.toFixed(2)}`}\n variant=\"blue\"\n />\n <StatCard\n icon={TrendingUp}\n label=\"Monthly Average\"\n value={`$${data.stats.averageMonthlySpend.toFixed(2)}`}\n subValue=\"Last 6 months\"\n variant=\"blue\"\n />\n </motion.div>\n\n {/* Payment Methods */}\n <motion.div variants={itemVariants}>\n <Card className=\"mb-8 overflow-hidden\">\n <SectionHeader\n icon={CreditCard}\n title=\"Payment Methods\"\n action={\n <Button variant=\"secondary\" className=\"text-sm\">\n <Plus className=\"w-4 h-4 mr-2\" />\n Add Payment Method\n </Button>\n }\n />\n <div className=\"p-5 space-y-3\">\n {data.paymentMethods.map((method: PaymentMethodDTO) => (\n <PaymentMethodCard\n key={method.id}\n method={method}\n onSetDefault={() => handleSetDefault(method.id)}\n onRemove={() => handleRemoveMethod(method.id)}\n />\n ))}\n </div>\n <div className=\"px-5 pb-5\">\n <InfoBanner type=\"info\">\n <p className=\"mb-1\">We support Visa, Mastercard, American Express, and SEPA Direct Debit.</p>\n <p>All payment information is securely processed and stored by our payment provider.</p>\n </InfoBanner>\n </div>\n </Card>\n </motion.div>\n\n {/* Billing History */}\n <motion.div variants={itemVariants}>\n <Card className=\"mb-8 overflow-hidden\">\n <SectionHeader\n icon={FileText}\n title=\"Billing History\"\n color=\"text-warning-amber\"\n action={\n <Button variant=\"secondary\" className=\"text-sm\">\n <Download className=\"w-4 h-4 mr-2\" />\n Export All\n </Button>\n }\n />\n <div>\n {data.invoices.slice(0, showAllInvoices ? data.invoices.length : 4).map((invoice: InvoiceDTO, index: number) => (\n <InvoiceRow key={invoice.id} invoice={invoice} index={index} />\n ))}\n </div>\n {data.invoices.length > 4 && (\n <div className=\"p-4 border-t border-charcoal-outline\">\n <Button\n variant=\"secondary\"\n className=\"w-full\"\n onClick={() => setShowAllInvoices(!showAllInvoices)}\n >\n {showAllInvoices ? 'Show Less' : `View All ${data.invoices.length} Invoices`}\n <ChevronRight className={`w-4 h-4 ml-2 transition-transform ${showAllInvoices ? 'rotate-90' : ''}`} />\n </Button>\n </div>\n )}\n </Card>\n </motion.div>\n\n {/* Platform Fee & VAT Information */}\n <motion.div variants={itemVariants} className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* Platform Fee */}\n <Card className=\"overflow-hidden\">\n <div className=\"p-5 border-b border-charcoal-outline bg-gradient-to-r from-iron-gray/30 to-transparent\">\n <h3 className=\"font-semibold text-white flex items-center gap-3\">\n <div className=\"p-2 rounded-lg bg-iron-gray/50\">\n <Percent className=\"w-4 h-4 text-primary-blue\" />\n </div>\n Platform Fee\n </h3>\n </div>\n <div className=\"p-5\">\n <div className=\"text-3xl font-bold text-white mb-2\">\n {siteConfig.fees.platformFeePercent}%\n </div>\n <p className=\"text-sm text-gray-400 mb-4\">\n {siteConfig.fees.description}\n </p>\n <div className=\"text-xs text-gray-500 space-y-1\">\n <p>• Applied to all sponsorship payments</p>\n <p>• Covers platform maintenance and analytics</p>\n <p>• Ensures quality sponsorship placements</p>\n </div>\n </div>\n </Card>\n\n {/* VAT Information */}\n <Card className=\"overflow-hidden\">\n <div className=\"p-5 border-b border-charcoal-outline bg-gradient-to-r from-iron-gray/30 to-transparent\">\n <h3 className=\"font-semibold text-white flex items-center gap-3\">\n <div className=\"p-2 rounded-lg bg-iron-gray/50\">\n <Receipt className=\"w-4 h-4 text-performance-green\" />\n </div>\n VAT Information\n </h3>\n </div>\n <div className=\"p-5\">\n <p className=\"text-sm text-gray-400 mb-4\">\n {siteConfig.vat.notice}\n </p>\n <div className=\"space-y-3 text-sm\">\n <div className=\"flex justify-between items-center py-2 border-b border-charcoal-outline/50\">\n <span className=\"text-gray-500\">Standard VAT Rate</span>\n <span className=\"text-white font-medium\">{siteConfig.vat.standardRate}%</span>\n </div>\n <div className=\"flex justify-between items-center py-2\">\n <span className=\"text-gray-500\">B2B Reverse Charge</span>\n <span className=\"text-performance-green font-medium\">Available</span>\n </div>\n </div>\n <p className=\"text-xs text-gray-500 mt-4\">\n Enter your VAT ID in Settings to enable reverse charge for B2B transactions.\n </p>\n </div>\n </Card>\n </motion.div>\n\n {/* Billing Support */}\n <motion.div variants={itemVariants} className=\"mt-6\">\n <Card className=\"p-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-3 rounded-xl bg-iron-gray\">\n <Info className=\"w-5 h-5 text-gray-400\" />\n </div>\n <div>\n <h3 className=\"font-medium text-white\">Need help with billing?</h3>\n <p className=\"text-sm text-gray-500\">\n Contact our billing support for questions about invoices, payments, or refunds.\n </p>\n </div>\n </div>\n <Button variant=\"secondary\">\n Contact Support\n <ExternalLink className=\"w-4 h-4 ml-2\" />\n </Button>\n </div>\n </Card>\n </motion.div>\n </motion.div>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/campaigns/page.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AnimatePresence' is defined but never used.","line":5,"column":36,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":51},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'Filter' is defined but never used.","line":26,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":26,"endColumn":9},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AlertCircle' is defined but never used.","line":31,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":31,"endColumn":14},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'Handshake' is defined but never used.","line":36,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":36,"endColumn":12},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":101,"column":1,"nodeType":"FunctionDeclaration","messageId":"message","endLine":327,"endColumn":2},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":101,"column":58,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":101,"endColumn":61,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3026,3029],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3026,3029],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":115,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":123,"endColumn":4},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":126,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":131,"endColumn":6},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":132,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":136,"endColumn":10},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":138,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":164,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":138,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":138,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":138,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":138,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":139,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":159,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":139,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":139,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":139,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":139,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":140,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":142,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":140,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":140,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":140,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":140,"endColumn":107},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":141,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":141,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":143,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":143,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":144,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":157,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":144,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":144,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":144,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":144,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":145,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":147,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":145,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":145,"endColumn":119},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":145,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":145,"endColumn":118},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":149,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":155,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":149,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":153,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":149,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":153,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":160,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":163,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":160,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":160,"endColumn":180},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":160,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":160,"endColumn":179},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":161,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":161,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":167,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":167,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":167,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":167,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":167,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":167,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":169,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":169,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":169,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":169,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":169,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":169,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":174,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":186,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":174,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":174,"endColumn":98},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":174,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":174,"endColumn":97},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":175,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":178,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":175,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":175,"endColumn":86},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":175,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":175,"endColumn":85},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":176,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":176,"endColumn":40},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":177,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":177,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":177,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":177,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":177,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":177,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":179,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":182,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":179,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":179,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":179,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":179,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":180,"column":23,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":180,"endColumn":87},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":180,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":180,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":180,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":180,"endColumn":54},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":181,"column":16,"nodeType":"MemberExpression","messageId":"message","endLine":181,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":184,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":184,"endColumn":97},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":184,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":184,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":184,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":184,"endColumn":58},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`\"` can be escaped with `"`, `“`, `"`, `”`.","line":184,"column":59,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6921,6922],"text":"""},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"“"},"fix":{"range":[6921,6922],"text":"“"},"desc":"Replace with `“`."},{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6921,6922],"text":"""},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"”"},"fix":{"range":[6921,6922],"text":"”"},"desc":"Replace with `”`."}]},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`\"` can be escaped with `"`, `“`, `"`, `”`.","line":184,"column":92,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6954,6955],"text":"""},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"“"},"fix":{"range":[6954,6955],"text":"“"},"desc":"Replace with `“`."},{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6954,6955],"text":"""},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"”"},"fix":{"range":[6954,6955],"text":"”"},"desc":"Replace with `”`."}]},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":190,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":202,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":190,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":190,"endColumn":96},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":190,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":190,"endColumn":95},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":191,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":194,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":191,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":191,"endColumn":85},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":191,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":191,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":192,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":192,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":193,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":193,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":193,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":193,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":193,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":193,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":195,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":198,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":195,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":195,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":195,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":195,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":196,"column":27,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":196,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":196,"column":27,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":196,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":196,"column":33,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":196,"endColumn":58},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":197,"column":16,"nodeType":"MemberExpression","messageId":"message","endLine":197,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":199,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":201,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":199,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":199,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":199,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":199,"endColumn":54},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":200,"column":23,"nodeType":"MemberExpression","messageId":"message","endLine":200,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":206,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":220,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":206,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":206,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":206,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":206,"endColumn":91},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":207,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":210,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":207,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":207,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":207,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":207,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":208,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":208,"endColumn":46},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":209,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":209,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":209,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":209,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":209,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":209,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":212,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":214,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":212,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":212,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":212,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":212,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":213,"column":25,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":213,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":213,"column":25,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":213,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":213,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":213,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":216,"column":41,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":216,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":217,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":217,"endColumn":50},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":225,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":271,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":225,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":225,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":225,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":225,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":226,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":242,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":226,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":226,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":226,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":226,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":227,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":230,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":227,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":227,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":227,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":227,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":228,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":228,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":231,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":241,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":231,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":231,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":231,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":231,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":232,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":232,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":232,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":232,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":232,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":232,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":234,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":239,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":234,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":236,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":234,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":236,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":237,"column":72,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":237,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":237,"column":113,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":237,"endColumn":132},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":245,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":251,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":245,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":245,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":245,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":245,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":246,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":249,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":246,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":246,"endColumn":85},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":246,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":246,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":247,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":247,"endColumn":50},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":250,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":250,"endColumn":90},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":250,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":250,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":250,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":250,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":254,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":262,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":254,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":254,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":254,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":254,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":255,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":258,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":255,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":255,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":255,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":255,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":256,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":256,"endColumn":46},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":259,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":261,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":259,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":259,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":259,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":259,"endColumn":64},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":260,"column":18,"nodeType":"MemberExpression","messageId":"message","endLine":260,"endColumn":58},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":260,"column":109,"nodeType":"MemberExpression","messageId":"message","endLine":260,"endColumn":147},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":264,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":270,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":264,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":264,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":264,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":264,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":265,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":268,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":265,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":265,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":265,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":265,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":266,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":266,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":269,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":269,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":269,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":269,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":269,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":269,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":276,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":285,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":276,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":276,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":276,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":276,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":277,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":280,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":277,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":277,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":277,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":277,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":278,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":278,"endColumn":48},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":281,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":284,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":281,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":281,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":281,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":281,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":282,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":282,"endColumn":46},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":289,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":323,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":289,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":289,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":289,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":289,"endColumn":100},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":290,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":301,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":290,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":290,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":290,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":290,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":292,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":294,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":292,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":292,"endColumn":102},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":292,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":292,"endColumn":101},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":297,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":299,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":297,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":297,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":297,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":297,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":302,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":322,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":302,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":302,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":302,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":302,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":305,"column":45,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":305,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":306,"column":33,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":306,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":312,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":312,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":317,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":317,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":319,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":319,"endColumn":55},{"ruleId":"gridpilot-rules/no-hardcoded-search-params","severity":2,"message":"Manual search param access with get(). Use SearchParamParser instead: import { SearchParamParser } from \"@/lib/routing/search-params\"","line":337,"column":24,"nodeType":"MemberExpression","messageId":"manualGetParam","endLine":337,"endColumn":40},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":346,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":351,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":346,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":346,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":346,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":346,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":347,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":350,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":347,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":347,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":347,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":347,"endColumn":37},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":348,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":348,"endColumn":127},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":348,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":348,"endColumn":127},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":348,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":348,"endColumn":124},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":349,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":349,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":349,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":349,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":349,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":349,"endColumn":39},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":357,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":366,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":357,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":357,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":357,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":357,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":358,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":365,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":358,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":358,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":358,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":358,"endColumn":37},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":359,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":359,"endColumn":105},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":359,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":359,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":359,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":359,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":361,"column":57,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":361,"endColumn":73},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":373,"column":32,"nodeType":"CallExpression","messageId":"message","endLine":378,"endColumn":5},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":373,"column":61,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":373,"endColumn":64,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[14875,14878],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[14875,14878],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":383,"column":13,"nodeType":"CallExpression","messageId":"message","endLine":383,"endColumn":72},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":383,"column":42,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":383,"endColumn":45,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15272,15275],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15272,15275],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":384,"column":14,"nodeType":"CallExpression","messageId":"message","endLine":384,"endColumn":83},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":384,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":384,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15353,15356],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15353,15356],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":385,"column":15,"nodeType":"CallExpression","messageId":"message","endLine":385,"endColumn":76},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":385,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":385,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15445,15448],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15445,15448],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":386,"column":15,"nodeType":"CallExpression","messageId":"message","endLine":386,"endColumn":76},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":386,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":386,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15529,15532],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15529,15532],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":387,"column":22,"nodeType":"CallExpression","messageId":"message","endLine":387,"endColumn":131},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":387,"column":22,"nodeType":"CallExpression","messageId":"message","endLine":387,"endColumn":81},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":387,"column":51,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":387,"endColumn":54,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15620,15623],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15620,15623],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":387,"column":106,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":387,"endColumn":109,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15675,15678],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15675,15678],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":388,"column":23,"nodeType":"CallExpression","messageId":"message","endLine":388,"endColumn":96},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":388,"column":65,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":388,"endColumn":68,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15766,15769],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15766,15769],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":393,"column":14,"nodeType":"CallExpression","messageId":"message","endLine":393,"endColumn":72},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":393,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":393,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15890,15893],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15890,15893],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":394,"column":12,"nodeType":"CallExpression","messageId":"message","endLine":394,"endColumn":68},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":394,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":394,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15968,15971],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15968,15971],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":395,"column":14,"nodeType":"CallExpression","messageId":"message","endLine":395,"endColumn":72},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":395,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":395,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[16046,16049],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[16046,16049],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":396,"column":12,"nodeType":"CallExpression","messageId":"message","endLine":396,"endColumn":68},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":396,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":396,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[16124,16127],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[16124,16127],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":397,"column":15,"nodeType":"CallExpression","messageId":"message","endLine":397,"endColumn":74},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":397,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":397,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[16203,16206],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[16203,16206],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":401,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":613,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":401,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":401,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":401,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":401,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":403,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":419,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":403,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":403,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":403,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":403,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":404,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":404,"endColumn":14},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":405,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":408,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":405,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":405,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":405,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":405,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":406,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":406,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":409,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":409,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":409,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":409,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":409,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":409,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":411,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":418,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":411,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":411,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":411,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":411,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":414,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":414,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":423,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":427,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":426,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":426,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":429,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":429,"endColumn":16},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":430,"column":24,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":430,"endColumn":131},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":430,"column":24,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":430,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":430,"column":32,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":430,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":438,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":498,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":438,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":438,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":438,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":438,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":439,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":442,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":443,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":443,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":444,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":444,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":444,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":444,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":444,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":444,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":445,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":445,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":445,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":445,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":445,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":445,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":448,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":452,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":453,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":453,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":454,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":454,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":454,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":454,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":454,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":454,"endColumn":71},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":455,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":455,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":455,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":455,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":455,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":455,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":458,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":462,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":463,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":463,"endColumn":88},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":464,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":464,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":464,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":464,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":464,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":464,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":465,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":465,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":465,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":465,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":465,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":465,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":468,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":472,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":473,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":473,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":474,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":474,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":474,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":474,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":474,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":474,"endColumn":66},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":475,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":475,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":475,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":475,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":475,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":475,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":478,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":482,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":483,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":483,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":484,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":484,"endColumn":107},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":484,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":484,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":484,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":484,"endColumn":59},{"ruleId":"gridpilot-rules/rsc-no-intl","severity":2,"message":"Intl.* or toLocale* usage forbidden in presentation paths - see apps/website/lib/contracts/view-models/ViewModel.ts","line":484,"column":62,"nodeType":"MemberExpression","messageId":"message","endLine":484,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":485,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":485,"endColumn":75},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":485,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":485,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":485,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":485,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":488,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":492,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":493,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":493,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":494,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":494,"endColumn":118},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":494,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":494,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":494,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":494,"endColumn":66},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":495,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":495,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":495,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":495,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":495,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":495,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":501,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":573,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":501,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":501,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":501,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":501,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":503,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":512,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":503,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":503,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":503,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":503,"endColumn":41},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":504,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":504,"endColumn":93},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":505,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":511,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":505,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":511,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":510,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":510,"endColumn":181},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":515,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":540,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":515,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":515,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":515,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":515,"endColumn":78},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":521,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":537,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":521,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":529,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":524,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":528,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":530,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":530,"endColumn":42},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":532,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":536,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":532,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":534,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":532,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":534,"endColumn":20},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":543,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":572,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":543,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":543,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":543,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":543,"endColumn":65},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":550,"column":17,"nodeType":"CallExpression","messageId":"message","endLine":550,"endColumn":74},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":550,"column":46,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":550,"endColumn":49,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[22560,22563],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[22560,22563],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":552,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":569,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":552,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":560,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":555,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":559,"endColumn":20},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":563,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":567,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":563,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":565,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":563,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":565,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":577,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":577,"endColumn":44},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":578,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":578,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":579,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":579,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":579,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":579,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":579,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":579,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":580,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":584,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":580,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":580,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":580,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":580,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":585,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":604,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":585,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":585,"endColumn":75},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":585,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":585,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":588,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":588,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":594,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":594,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":600,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":600,"endColumn":46},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":607,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":611,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":607,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":607,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":607,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":607,"endColumn":63},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":608,"column":51,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":608,"endColumn":54,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[24938,24941],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[24938,24941],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":358,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useState } from 'react';\nimport { useSearchParams } from 'next/navigation';\nimport { motion, useReducedMotion, AnimatePresence } from 'framer-motion';\nimport Link from 'next/link';\nimport { Card } from '@/ui/Card';\nimport { Button } from '@/ui/Button';\nimport { InfoBanner } from '@/ui/InfoBanner';\nimport { useSponsorSponsorships } from \"@/hooks/sponsor/useSponsorSponsorships\";\nimport {\n Megaphone,\n Trophy,\n Users,\n Eye,\n Calendar,\n ExternalLink,\n Plus,\n ChevronRight,\n Check,\n Clock,\n XCircle,\n Car,\n Flag,\n Search,\n Filter,\n TrendingUp,\n BarChart3,\n ArrowUpRight,\n ArrowDownRight,\n AlertCircle,\n Send,\n ThumbsUp,\n ThumbsDown,\n RefreshCw,\n Handshake\n} from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype SponsorshipType = 'all' | 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';\ntype SponsorshipStatus = 'all' | 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst TYPE_CONFIG = {\n leagues: { icon: Trophy, color: 'text-primary-blue', bgColor: 'bg-primary-blue/10', label: 'League' },\n teams: { icon: Users, color: 'text-purple-400', bgColor: 'bg-purple-400/10', label: 'Team' },\n drivers: { icon: Car, color: 'text-performance-green', bgColor: 'bg-performance-green/10', label: 'Driver' },\n races: { icon: Flag, color: 'text-warning-amber', bgColor: 'bg-warning-amber/10', label: 'Race' },\n platform: { icon: Megaphone, color: 'text-racing-red', bgColor: 'bg-racing-red/10', label: 'Platform' },\n all: { icon: BarChart3, color: 'text-gray-400', bgColor: 'bg-gray-400/10', label: 'All' },\n};\n\nconst STATUS_CONFIG = {\n active: {\n icon: Check,\n color: 'text-performance-green',\n bgColor: 'bg-performance-green/10',\n borderColor: 'border-performance-green/30',\n label: 'Active'\n },\n pending_approval: {\n icon: Clock,\n color: 'text-warning-amber',\n bgColor: 'bg-warning-amber/10',\n borderColor: 'border-warning-amber/30',\n label: 'Awaiting Approval'\n },\n approved: {\n icon: ThumbsUp,\n color: 'text-primary-blue',\n bgColor: 'bg-primary-blue/10',\n borderColor: 'border-primary-blue/30',\n label: 'Approved'\n },\n rejected: {\n icon: ThumbsDown,\n color: 'text-racing-red',\n bgColor: 'bg-racing-red/10',\n borderColor: 'border-racing-red/30',\n label: 'Declined'\n },\n expired: {\n icon: XCircle,\n color: 'text-gray-400',\n bgColor: 'bg-gray-400/10',\n borderColor: 'border-gray-400/30',\n label: 'Expired'\n },\n};\n\n// ============================================================================\n// Components\n// ============================================================================\n\nfunction SponsorshipCard({ sponsorship }: { sponsorship: any }) {\n const shouldReduceMotion = useReducedMotion();\n \n const typeConfig = TYPE_CONFIG[sponsorship.type as keyof typeof TYPE_CONFIG];\n const statusConfig = STATUS_CONFIG[sponsorship.status as keyof typeof STATUS_CONFIG];\n const TypeIcon = typeConfig.icon;\n const StatusIcon = statusConfig.icon;\n\n const daysRemaining = Math.ceil((sponsorship.endDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24));\n const isExpiringSoon = daysRemaining > 0 && daysRemaining <= 30;\n const isPending = sponsorship.status === 'pending_approval';\n const isRejected = sponsorship.status === 'rejected';\n const isApproved = sponsorship.status === 'approved';\n\n const getEntityLink = () => {\n switch (sponsorship.type) {\n case 'leagues': return `/leagues/${sponsorship.entityId}`;\n case 'teams': return `/teams/${sponsorship.entityId}`;\n case 'drivers': return `/drivers/${sponsorship.entityId}`;\n case 'races': return `/races/${sponsorship.entityId}`;\n default: return '#';\n }\n };\n\n return (\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n whileHover={{ y: -2 }}\n transition={{ duration: 0.2 }}\n >\n <Card className={`hover:border-primary-blue/30 transition-all duration-300 ${\n isPending ? 'border-warning-amber/30' :\n isRejected ? 'border-racing-red/20 opacity-75' :\n isApproved ? 'border-primary-blue/30' : ''\n }`}>\n {/* Header */}\n <div className=\"flex items-start justify-between mb-4\">\n <div className=\"flex items-center gap-3\">\n <div className={`w-10 h-10 rounded-lg ${typeConfig.bgColor} flex items-center justify-center`}>\n <TypeIcon className={`w-5 h-5 ${typeConfig.color}`} />\n </div>\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className={`text-xs font-medium px-2 py-0.5 rounded ${typeConfig.bgColor} ${typeConfig.color}`}>\n {typeConfig.label}\n </span>\n {sponsorship.tier && (\n <span className={`text-xs font-medium px-2 py-0.5 rounded ${\n sponsorship.tier === 'main'\n ? 'bg-primary-blue/20 text-primary-blue'\n : 'bg-purple-400/20 text-purple-400'\n }`}>\n {sponsorship.tier === 'main' ? 'Main Sponsor' : 'Secondary'}\n </span>\n )}\n </div>\n </div>\n </div>\n <div className={`flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-medium border ${statusConfig.bgColor} ${statusConfig.color} ${statusConfig.borderColor}`}>\n <StatusIcon className=\"w-3 h-3\" />\n {statusConfig.label}\n </div>\n </div>\n\n {/* Entity Name */}\n <h3 className=\"text-lg font-semibold text-white mb-1\">{sponsorship.entityName}</h3>\n {sponsorship.details && (\n <p className=\"text-sm text-gray-500 mb-3\">{sponsorship.details}</p>\n )}\n\n {/* Application/Approval Info for non-active states */}\n {isPending && (\n <div className=\"mb-4 p-3 rounded-lg bg-warning-amber/5 border border-warning-amber/20\">\n <div className=\"flex items-center gap-2 text-warning-amber text-sm mb-2\">\n <Send className=\"w-4 h-4\" />\n <span className=\"font-medium\">Application Pending</span>\n </div>\n <p className=\"text-xs text-gray-400 mb-2\">\n Sent to <span className=\"text-gray-300\">{sponsorship.entityOwner}</span> on{' '}\n {sponsorship.applicationDate?.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}\n </p>\n {sponsorship.applicationMessage && (\n <p className=\"text-xs text-gray-500 italic\">\"{sponsorship.applicationMessage}\"</p>\n )}\n </div>\n )}\n\n {isApproved && (\n <div className=\"mb-4 p-3 rounded-lg bg-primary-blue/5 border border-primary-blue/20\">\n <div className=\"flex items-center gap-2 text-primary-blue text-sm mb-1\">\n <ThumbsUp className=\"w-4 h-4\" />\n <span className=\"font-medium\">Approved!</span>\n </div>\n <p className=\"text-xs text-gray-400\">\n Approved by <span className=\"text-gray-300\">{sponsorship.entityOwner}</span> on{' '}\n {sponsorship.approvalDate?.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}\n </p>\n <p className=\"text-xs text-gray-500 mt-1\">\n Starts {sponsorship.startDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </p>\n </div>\n )}\n\n {isRejected && (\n <div className=\"mb-4 p-3 rounded-lg bg-racing-red/5 border border-racing-red/20\">\n <div className=\"flex items-center gap-2 text-racing-red text-sm mb-1\">\n <ThumbsDown className=\"w-4 h-4\" />\n <span className=\"font-medium\">Application Declined</span>\n </div>\n {sponsorship.rejectionReason && (\n <p className=\"text-xs text-gray-400 mt-1\">\n Reason: <span className=\"text-gray-300\">{sponsorship.rejectionReason}</span>\n </p>\n )}\n <Button variant=\"secondary\" className=\"mt-2 text-xs\">\n <RefreshCw className=\"w-3 h-3 mr-1\" />\n Reapply\n </Button>\n </div>\n )}\n\n {/* Metrics Grid - Only show for active sponsorships */}\n {sponsorship.status === 'active' && (\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-3 mb-4\">\n <div className=\"bg-iron-gray/50 rounded-lg p-3\">\n <div className=\"flex items-center gap-1 text-gray-400 text-xs mb-1\">\n <Eye className=\"w-3 h-3\" />\n Impressions\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-white font-semibold\">{sponsorship.formattedImpressions}</span>\n {sponsorship.impressionsChange !== undefined && sponsorship.impressionsChange !== 0 && (\n <span className={`text-xs flex items-center ${\n sponsorship.impressionsChange > 0 ? 'text-performance-green' : 'text-racing-red'\n }`}>\n {sponsorship.impressionsChange > 0 ? <ArrowUpRight className=\"w-3 h-3\" /> : <ArrowDownRight className=\"w-3 h-3\" />}\n {Math.abs(sponsorship.impressionsChange)}%\n </span>\n )}\n </div>\n </div>\n \n {sponsorship.engagement && (\n <div className=\"bg-iron-gray/50 rounded-lg p-3\">\n <div className=\"flex items-center gap-1 text-gray-400 text-xs mb-1\">\n <TrendingUp className=\"w-3 h-3\" />\n Engagement\n </div>\n <div className=\"text-white font-semibold\">{sponsorship.engagement}%</div>\n </div>\n )}\n \n <div className=\"bg-iron-gray/50 rounded-lg p-3\">\n <div className=\"flex items-center gap-1 text-gray-400 text-xs mb-1\">\n <Calendar className=\"w-3 h-3\" />\n Period\n </div>\n <div className=\"text-white font-semibold text-xs\">\n {sponsorship.startDate.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })} - {sponsorship.endDate.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })}\n </div>\n </div>\n \n <div className=\"bg-iron-gray/50 rounded-lg p-3\">\n <div className=\"flex items-center gap-1 text-gray-400 text-xs mb-1\">\n <Trophy className=\"w-3 h-3\" />\n Investment\n </div>\n <div className=\"text-white font-semibold\">{sponsorship.formattedPrice}</div>\n </div>\n </div>\n )}\n\n {/* Basic info for non-active */}\n {sponsorship.status !== 'active' && (\n <div className=\"flex items-center gap-4 mb-4 text-sm\">\n <div className=\"flex items-center gap-1 text-gray-400\">\n <Calendar className=\"w-3.5 h-3.5\" />\n {sponsorship.periodDisplay}\n </div>\n <div className=\"flex items-center gap-1 text-gray-400\">\n <Trophy className=\"w-3.5 h-3.5\" />\n {sponsorship.formattedPrice}\n </div>\n </div>\n )}\n\n {/* Footer */}\n <div className=\"flex items-center justify-between pt-3 border-t border-charcoal-outline/50\">\n <div className=\"flex items-center gap-2\">\n {sponsorship.status === 'active' && (\n <span className={`text-xs ${isExpiringSoon ? 'text-warning-amber' : 'text-gray-500'}`}>\n {daysRemaining > 0 ? `${daysRemaining} days remaining` : 'Ended'}\n </span>\n )}\n {isPending && (\n <span className=\"text-xs text-gray-500\">\n Waiting for response...\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {sponsorship.type !== 'platform' && (\n <Link href={getEntityLink()}>\n <Button variant=\"secondary\" className=\"text-xs\">\n <ExternalLink className=\"w-3 h-3 mr-1\" />\n View\n </Button>\n </Link>\n )}\n {isPending && (\n <Button variant=\"secondary\" className=\"text-xs text-racing-red hover:bg-racing-red/10\">\n Cancel Application\n </Button>\n )}\n {sponsorship.status === 'active' && (\n <Button variant=\"secondary\" className=\"text-xs\">\n Details\n <ChevronRight className=\"w-3 h-3 ml-1\" />\n </Button>\n )}\n </div>\n </div>\n </Card>\n </motion.div>\n );\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport default function SponsorCampaignsPage() {\n const searchParams = useSearchParams();\n const shouldReduceMotion = useReducedMotion();\n\n const initialType = (searchParams.get('type') as SponsorshipType) || 'all';\n const [typeFilter, setTypeFilter] = useState<SponsorshipType>(initialType);\n const [statusFilter, setStatusFilter] = useState<SponsorshipStatus>('all');\n const [searchQuery, setSearchQuery] = useState('');\n\n const { data: sponsorshipsData, isLoading, error, retry } = useSponsorSponsorships('demo-sponsor-1');\n\n if (isLoading) {\n return (\n <div className=\"max-w-7xl mx-auto py-8 px-4 flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center\">\n <div className=\"w-8 h-8 border-2 border-primary-blue border-t-transparent rounded-full animate-spin mx-auto mb-4\" />\n <p className=\"text-gray-400\">Loading sponsorships...</p>\n </div>\n </div>\n );\n }\n\n if (error || !sponsorshipsData) {\n return (\n <div className=\"max-w-7xl mx-auto py-8 px-4 flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center\">\n <p className=\"text-gray-400\">{error?.getUserMessage() || 'No sponsorships data available'}</p>\n {error && (\n <Button variant=\"secondary\" onClick={retry} className=\"mt-4\">\n Retry\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n const data = sponsorshipsData;\n\n // Filter sponsorships\n const filteredSponsorships = data.sponsorships.filter((s: any) => {\n if (typeFilter !== 'all' && s.type !== typeFilter) return false;\n if (statusFilter !== 'all' && s.status !== statusFilter) return false;\n if (searchQuery && !s.entityName.toLowerCase().includes(searchQuery.toLowerCase())) return false;\n return true;\n });\n\n // Calculate stats\n const stats = {\n total: data.sponsorships.length,\n active: data.sponsorships.filter((s: any) => s.status === 'active').length,\n pending: data.sponsorships.filter((s: any) => s.status === 'pending_approval').length,\n approved: data.sponsorships.filter((s: any) => s.status === 'approved').length,\n rejected: data.sponsorships.filter((s: any) => s.status === 'rejected').length,\n totalInvestment: data.sponsorships.filter((s: any) => s.status === 'active').reduce((sum: number, s: any) => sum + s.price, 0),\n totalImpressions: data.sponsorships.reduce((sum: number, s: any) => sum + s.impressions, 0),\n };\n\n // Stats by type\n const statsByType = {\n leagues: data.sponsorships.filter((s: any) => s.type === 'leagues').length,\n teams: data.sponsorships.filter((s: any) => s.type === 'teams').length,\n drivers: data.sponsorships.filter((s: any) => s.type === 'drivers').length,\n races: data.sponsorships.filter((s: any) => s.type === 'races').length,\n platform: data.sponsorships.filter((s: any) => s.type === 'platform').length,\n };\n\n return (\n <div className=\"max-w-7xl mx-auto py-8 px-4\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-8\">\n <div>\n <h1 className=\"text-2xl font-bold text-white flex items-center gap-3\">\n <Megaphone className=\"w-7 h-7 text-primary-blue\" />\n My Sponsorships\n </h1>\n <p className=\"text-gray-400 mt-1\">Manage applications and active sponsorship campaigns</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <Link href=\"/leagues\">\n <Button variant=\"primary\">\n <Plus className=\"w-4 h-4 mr-2\" />\n Find Opportunities\n </Button>\n </Link>\n </div>\n </div>\n\n {/* Info Banner about how sponsorships work */}\n {stats.pending > 0 && (\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"mb-6\"\n >\n <InfoBanner type=\"info\" title=\"Sponsorship Applications\">\n <p>\n You have <strong className=\"text-white\">{stats.pending} pending application{stats.pending !== 1 ? 's' : ''}</strong> waiting for approval.\n League admins, team owners, and drivers review applications before accepting sponsorships.\n </p>\n </InfoBanner>\n </motion.div>\n )}\n\n {/* Quick Stats */}\n <div className=\"grid grid-cols-2 md:grid-cols-6 gap-4 mb-8\">\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n >\n <Card className=\"p-4\">\n <div className=\"text-2xl font-bold text-white\">{stats.total}</div>\n <div className=\"text-sm text-gray-400\">Total</div>\n </Card>\n </motion.div>\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.05 }}\n >\n <Card className=\"p-4\">\n <div className=\"text-2xl font-bold text-performance-green\">{stats.active}</div>\n <div className=\"text-sm text-gray-400\">Active</div>\n </Card>\n </motion.div>\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.1 }}\n >\n <Card className={`p-4 ${stats.pending > 0 ? 'border-warning-amber/30' : ''}`}>\n <div className=\"text-2xl font-bold text-warning-amber\">{stats.pending}</div>\n <div className=\"text-sm text-gray-400\">Pending</div>\n </Card>\n </motion.div>\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.15 }}\n >\n <Card className=\"p-4\">\n <div className=\"text-2xl font-bold text-primary-blue\">{stats.approved}</div>\n <div className=\"text-sm text-gray-400\">Approved</div>\n </Card>\n </motion.div>\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.2 }}\n >\n <Card className=\"p-4\">\n <div className=\"text-2xl font-bold text-white\">${stats.totalInvestment.toLocaleString()}</div>\n <div className=\"text-sm text-gray-400\">Active Investment</div>\n </Card>\n </motion.div>\n <motion.div\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.25 }}\n >\n <Card className=\"p-4\">\n <div className=\"text-2xl font-bold text-primary-blue\">{(stats.totalImpressions / 1000).toFixed(0)}k</div>\n <div className=\"text-sm text-gray-400\">Impressions</div>\n </Card>\n </motion.div>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-col lg:flex-row gap-4 mb-6\">\n {/* Search */}\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-500\" />\n <input\n type=\"text\"\n placeholder=\"Search sponsorships...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-10 pr-4 py-2.5 rounded-lg border border-charcoal-outline bg-iron-gray text-white placeholder-gray-500 focus:border-primary-blue focus:outline-none\"\n />\n </div>\n \n {/* Type Filter */}\n <div className=\"flex items-center gap-2 overflow-x-auto pb-2 lg:pb-0\">\n {(['all', 'leagues', 'teams', 'drivers', 'races', 'platform'] as const).map((type) => {\n const config = TYPE_CONFIG[type];\n const Icon = config.icon;\n const count = type === 'all' ? stats.total : statsByType[type];\n return (\n <button\n key={type}\n onClick={() => setTypeFilter(type)}\n className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium whitespace-nowrap transition-colors ${\n typeFilter === type\n ? 'bg-primary-blue text-white'\n : 'bg-iron-gray/50 text-gray-400 hover:bg-iron-gray'\n }`}\n >\n <Icon className=\"w-4 h-4\" />\n {config.label}\n <span className={`px-1.5 py-0.5 rounded text-xs ${\n typeFilter === type ? 'bg-white/20' : 'bg-charcoal-outline'\n }`}>\n {count}\n </span>\n </button>\n );\n })}\n </div>\n\n {/* Status Filter */}\n <div className=\"flex items-center gap-2 overflow-x-auto\">\n {(['all', 'active', 'pending_approval', 'approved', 'rejected'] as const).map((status) => {\n const config = status === 'all'\n ? { label: 'All', color: 'text-gray-400' }\n : STATUS_CONFIG[status];\n const count = status === 'all'\n ? stats.total\n : data.sponsorships.filter((s: any) => s.status === status).length;\n return (\n <button\n key={status}\n onClick={() => setStatusFilter(status)}\n className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap ${\n statusFilter === status\n ? 'bg-iron-gray text-white border border-charcoal-outline'\n : 'text-gray-500 hover:text-gray-300'\n }`}\n >\n {config.label}\n {count > 0 && status !== 'all' && (\n <span className={`ml-1.5 px-1.5 py-0.5 rounded text-xs ${\n status === 'pending_approval' ? 'bg-warning-amber/20 text-warning-amber' : 'bg-charcoal-outline'\n }`}>\n {count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Sponsorship List */}\n {filteredSponsorships.length === 0 ? (\n <Card className=\"text-center py-16\">\n <Megaphone className=\"w-12 h-12 text-gray-600 mx-auto mb-4\" />\n <h3 className=\"text-lg font-semibold text-white mb-2\">No sponsorships found</h3>\n <p className=\"text-gray-400 mb-6 max-w-md mx-auto\">\n {searchQuery || typeFilter !== 'all' || statusFilter !== 'all'\n ? 'Try adjusting your filters to see more results.'\n : 'Start sponsoring leagues, teams, or drivers to grow your brand visibility.'}\n </p>\n <div className=\"flex flex-col sm:flex-row gap-3 justify-center\">\n <Link href=\"/leagues\">\n <Button variant=\"primary\">\n <Trophy className=\"w-4 h-4 mr-2\" />\n Browse Leagues\n </Button>\n </Link>\n <Link href=\"/teams\">\n <Button variant=\"secondary\">\n <Users className=\"w-4 h-4 mr-2\" />\n Browse Teams\n </Button>\n </Link>\n <Link href=\"/drivers\">\n <Button variant=\"secondary\">\n <Car className=\"w-4 h-4 mr-2\" />\n Browse Drivers\n </Button>\n </Link>\n </div>\n </Card>\n ) : (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n {filteredSponsorships.map((sponsorship: any) => (\n <SponsorshipCard key={sponsorship.id} sponsorship={sponsorship} />\n ))}\n </div>\n )}\n </div>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/dashboard/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/layout.tsx","messages":[{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":26,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":28,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":26,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":26,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":26,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":26,"endColumn":51}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { headers } from 'next/headers';\nimport { redirect } from 'next/navigation';\nimport { createRouteGuard } from '@/lib/auth/createRouteGuard';\n\ninterface SponsorLayoutProps {\n children: React.ReactNode;\n}\n\n/**\n * Sponsor Layout\n *\n * Provides authentication protection for all sponsor-related routes.\n * Uses RouteGuard to enforce access control server-side.\n */\nexport default async function SponsorLayout({ children }: SponsorLayoutProps) {\n const headerStore = await headers();\n const pathname = headerStore.get('x-pathname') || '/';\n \n const guard = createRouteGuard();\n const result = await guard.enforce({ pathname });\n if (result.type === 'redirect') {\n redirect(result.to);\n }\n \n return (\n <div className=\"min-h-screen bg-deep-graphite\">\n {children}\n </div>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/leagues/SponsorLeaguesPageClient.tsx","messages":[{"ruleId":"import/no-default-export","severity":2,"message":"Prefer named exports.","line":6,"column":8,"nodeType":"ExportDefaultDeclaration","endLine":6,"endColumn":15},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":6,"column":68,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":6,"endColumn":71,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[269,272],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[269,272],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'setTierFilter' is assigned a value but never used.","line":8,"column":22,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":35},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'setAvailabilityFilter' is assigned a value but never used.","line":9,"column":30,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":51},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'setSortBy' is assigned a value but never used.","line":10,"column":18,"nodeType":"Identifier","messageId":"unusedVar","endLine":10,"endColumn":27},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":15,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":15,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[677,680],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[677,680],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":17,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":20,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1201,1204],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1201,1204],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":25,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":28,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1209,1212],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1209,1212],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport React, { useState, useMemo } from 'react';\nimport { SponsorLeaguesTemplate, type SortOption, type TierFilter, type AvailabilityFilter } from '@/templates/SponsorLeaguesTemplate';\n\nexport default function SponsorLeaguesPageClient({ data }: { data: any }) {\n const [searchQuery, setSearchQuery] = useState('');\n const [tierFilter, setTierFilter] = useState<TierFilter>('all');\n const [availabilityFilter, setAvailabilityFilter] = useState<AvailabilityFilter>('all');\n const [sortBy, setSortBy] = useState<SortOption>('rating');\n\n const filteredLeagues = useMemo(() => {\n if (!data?.leagues) return [];\n return data.leagues\n .filter((league: any) => {\n if (searchQuery && !league.name.toLowerCase().includes(searchQuery.toLowerCase())) {\n return false;\n }\n if (tierFilter !== 'all' && league.tier !== tierFilter) {\n return false;\n }\n if (availabilityFilter === 'main' && !league.mainSponsorSlot.available) {\n return false;\n }\n if (availabilityFilter === 'secondary' && league.secondarySlots.available === 0) {\n return false;\n }\n return true;\n })\n .sort((a: any, b: any) => {\n switch (sortBy) {\n case 'rating': return b.rating - a.rating;\n case 'drivers': return b.drivers - a.drivers;\n case 'price': return a.mainSponsorSlot.price - b.mainSponsorSlot.price;\n case 'views': return b.avgViewsPerRace - a.avgViewsPerRace;\n default: return 0;\n }\n });\n }, [data?.leagues, searchQuery, tierFilter, availabilityFilter, sortBy]);\n\n return (\n <SponsorLeaguesTemplate\n viewData={data}\n filteredLeagues={filteredLeagues}\n searchQuery={searchQuery}\n setSearchQuery={setSearchQuery}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/leagues/[id]/SponsorLeagueDetailPageClient.tsx","messages":[{"ruleId":"import/no-default-export","severity":2,"message":"Prefer named exports.","line":6,"column":8,"nodeType":"ExportDefaultDeclaration","endLine":6,"endColumn":15},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":6,"column":73,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":6,"endColumn":76,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[216,219],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[216,219],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport React, { useState } from 'react';\nimport { SponsorLeagueDetailTemplate } from '@/templates/SponsorLeagueDetailTemplate';\n\nexport default function SponsorLeagueDetailPageClient({ data }: { data: any }) {\n const [activeTab, setActiveTab] = useState<'overview' | 'drivers' | 'races' | 'sponsor'>('overview');\n const [selectedTier, setSelectedTier] = useState<'main' | 'secondary'>('main');\n\n return (\n <SponsorLeagueDetailTemplate\n viewData={data}\n activeTab={activeTab}\n setActiveTab={setActiveTab}\n selectedTier={selectedTier}\n setSelectedTier={setSelectedTier}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/leagues/[id]/page.tsx","messages":[{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":12,"column":18,"nodeType":"NewExpression","messageId":"message","endLine":12,"endColumn":37},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":13,"column":25,"nodeType":"NewExpression","messageId":"message","endLine":17,"endColumn":5},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":20,"column":21,"nodeType":"NewExpression","messageId":"message","endLine":20,"endColumn":74}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { notFound } from 'next/navigation';\nimport { PageWrapper } from '@/components/shared/state/PageWrapper';\nimport SponsorLeagueDetailPageClient from './SponsorLeagueDetailPageClient';\nimport { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\n\nexport default async function Page({ params }: { params: { id: string } }) {\n // Manual wiring: create dependencies\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: process.env.NODE_ENV === 'production',\n });\n\n // Create API client\n const apiClient = new SponsorsApiClient(baseUrl, errorReporter, logger);\n\n // Fetch data\n const data = await apiClient.getLeagueDetail(params.id);\n \n if (!data) notFound();\n \n // Data is already in the right format from API client\n return <PageWrapper data={data} Template={SponsorLeagueDetailPageClient} />;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/leagues/page.tsx","messages":[{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":11,"column":18,"nodeType":"NewExpression","messageId":"message","endLine":11,"endColumn":37},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":12,"column":25,"nodeType":"NewExpression","messageId":"message","endLine":16,"endColumn":5},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":19,"column":21,"nodeType":"NewExpression","messageId":"message","endLine":19,"endColumn":74},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":32,"column":20,"nodeType":"CallExpression","messageId":"message","endLine":32,"endColumn":79},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":32,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":32,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1279,1282],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1279,1282],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":33,"column":25,"nodeType":"CallExpression","messageId":"message","endLine":33,"endColumn":105},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":33,"column":61,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":33,"endColumn":64,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1384,1387],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1384,1387],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":34,"column":19,"nodeType":"CallExpression","messageId":"message","endLine":34,"endColumn":82},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":34,"column":55,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":34,"endColumn":58,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1484,1487],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1484,1487],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":36,"column":7,"nodeType":"CallExpression","messageId":"message","endLine":36,"endColumn":66},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1579,1582],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1579,1582],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":11,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageWrapper } from '@/components/shared/state/PageWrapper';\nimport SponsorLeaguesPageClient from './SponsorLeaguesPageClient';\nimport { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\n\nexport default async function Page() {\n // Manual wiring: create dependencies\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: process.env.NODE_ENV === 'production',\n });\n\n // Create API client\n const apiClient = new SponsorsApiClient(baseUrl, errorReporter, logger);\n\n // Fetch data\n const leaguesData = await apiClient.getAvailableLeagues();\n \n // Process data - move business logic to template\n if (!leaguesData) {\n return <PageWrapper data={undefined} Template={SponsorLeaguesPageClient} />;\n }\n \n // Calculate summary stats (business logic moved from view model)\n const stats = {\n total: leaguesData.length,\n mainAvailable: leaguesData.filter((l: any) => l.mainSponsorSlot.available).length,\n secondaryAvailable: leaguesData.reduce((sum: number, l: any) => sum + l.secondarySlots.available, 0),\n totalDrivers: leaguesData.reduce((sum: number, l: any) => sum + l.drivers, 0),\n avgCpm: Math.round(\n leaguesData.reduce((sum: number, l: any) => sum + l.cpm, 0) / leaguesData.length\n ),\n };\n\n const processedData = {\n leagues: leaguesData,\n stats,\n };\n \n return <PageWrapper data={processedData} Template={SponsorLeaguesPageClient} />;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/settings/page.tsx","messages":[{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":139,"column":1,"nodeType":"FunctionDeclaration","messageId":"message","endLine":153,"endColumn":2},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":143,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":148,"endColumn":6},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":147,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":147,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":149,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":149,"endColumn":39},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":150,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":150,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":150,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":150,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":150,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":150,"endColumn":44},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":167,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":173,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":169,"column":11,"nodeType":"NewExpression","messageId":"message","endLine":169,"endColumn":59},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":175,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":187,"endColumn":4},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":205,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":210,"endColumn":6},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":206,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":206,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":212,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":212,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":222,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":222,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":223,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":223,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":229,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":484,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":229,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":229,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":229,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":229,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":231,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":252,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":231,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":231,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":231,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":231,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":242,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":250,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":242,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":246,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":245,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":245,"endColumn":158},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":248,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":248,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":255,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":296,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":255,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":255,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":255,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":255,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":256,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":258,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":256,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":256,"endColumn":97},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":256,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":256,"endColumn":96},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":259,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":295,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":259,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":259,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":259,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":259,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":299,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":363,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":299,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":299,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":299,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":299,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":300,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":302,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":300,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":300,"endColumn":97},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":300,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":300,"endColumn":96},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":303,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":362,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":303,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":303,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":303,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":303,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":304,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":316,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":304,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":304,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":304,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":304,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":366,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":379,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":366,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":366,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":366,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":366,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":368,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":374,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":368,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":374,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":373,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":373,"endColumn":191},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":375,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":377,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":375,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":375,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":375,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":375,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":382,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":423,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":382,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":382,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":382,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":382,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":383,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":385,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":383,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":383,"endColumn":97},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":383,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":383,"endColumn":96},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":386,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":422,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":386,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":386,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":386,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":386,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":426,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":461,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":426,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":426,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":426,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":426,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":428,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":459,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":428,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":428,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":428,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":428,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":429,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":435,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":429,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":429,"endColumn":203},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":429,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":429,"endColumn":202},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":433,"column":34,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":433,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":436,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":458,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":436,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":436,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":436,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":436,"endColumn":42},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":437,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":454,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":437,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":437,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":437,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":437,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":438,"column":23,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":448,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":438,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":438,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":438,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":438,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":439,"column":25,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":443,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":439,"column":25,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":443,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":442,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":442,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":444,"column":25,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":447,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":444,"column":25,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":444,"endColumn":189},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":444,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":444,"endColumn":188},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":445,"column":35,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":445,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":450,"column":53,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":450,"endColumn":86},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":455,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":457,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":455,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":455,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":455,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":455,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":464,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":483,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":464,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":464,"endColumn":104},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":464,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":464,"endColumn":103},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":469,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":469,"endColumn":42},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":472,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":475,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":472,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":472,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":472,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":472,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":473,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":473,"endColumn":115},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":473,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":473,"endColumn":115},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":473,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":473,"endColumn":112},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":477,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":480,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":477,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":477,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":477,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":477,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":478,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":478,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":489,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":489,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":490,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":490,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":497,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":536,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":497,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":497,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":497,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":497,"endColumn":31},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":498,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":535,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":498,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":498,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":498,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":498,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":541,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":541,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":542,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":542,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":549,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":576,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":549,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":549,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":549,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":549,"endColumn":31},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":550,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":575,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":550,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":550,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":550,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":550,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":581,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":581,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":582,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":582,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":589,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":634,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":589,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":589,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":589,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":589,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":590,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":603,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":590,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":590,"endColumn":105},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":590,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":590,"endColumn":104},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":591,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":599,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":591,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":591,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":591,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":591,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":592,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":594,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":592,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":592,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":592,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":592,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":593,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":593,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":595,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":595,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":596,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":596,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":596,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":596,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":596,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":596,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":597,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":597,"endColumn":85},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":597,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":597,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":597,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":597,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":605,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":618,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":605,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":605,"endColumn":105},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":605,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":605,"endColumn":104},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":606,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":614,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":606,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":606,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":606,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":606,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":607,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":609,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":607,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":607,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":607,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":607,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":608,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":608,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":610,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":610,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":611,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":611,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":611,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":611,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":611,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":611,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":612,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":612,"endColumn":106},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":612,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":612,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":612,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":612,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":620,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":633,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":620,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":620,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":620,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":620,"endColumn":68},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":621,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":629,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":621,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":621,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":621,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":621,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":622,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":624,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":622,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":622,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":622,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":622,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":623,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":623,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":625,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":625,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":626,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":626,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":626,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":626,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":626,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":626,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":627,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":627,"endColumn":97},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":627,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":627,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":627,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":627,"endColumn":55},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":627,"column":80,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[23710,23747],"text":"Manage devices where you're logged in"},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[23710,23747],"text":"Manage devices where you‘re logged in"},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[23710,23747],"text":"Manage devices where you're logged in"},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[23710,23747],"text":"Manage devices where you’re logged in"},"desc":"Replace with `’`."}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":639,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":639,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":640,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":640,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":641,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":648,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":641,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":641,"endColumn":113},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":641,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":641,"endColumn":112},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":642,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":647,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":642,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":642,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":642,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":642,"endColumn":90},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":643,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":645,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":643,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":643,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":643,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":643,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":644,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":644,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":649,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":671,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":649,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":649,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":649,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":649,"endColumn":31},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":650,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":670,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":650,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":650,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":650,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":650,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":651,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":662,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":651,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":651,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":651,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":651,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":652,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":654,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":652,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":652,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":652,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":652,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":653,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":653,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":655,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":655,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":656,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":656,"endColumn":86},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":656,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":656,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":656,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":656,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":657,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":660,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":657,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":657,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":657,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":657,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":666,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":666,"endColumn":88}],"suppressedMessages":[],"errorCount":214,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { Card } from '@/ui/Card';\nimport { Button } from '@/ui/Button';\nimport { Input } from '@/ui/Input';\nimport { Toggle } from '@/ui/Toggle';\nimport { SectionHeader } from '@/ui/SectionHeader';\nimport { FormField } from '@/ui/FormField';\nimport { PageHeader } from '@/ui/PageHeader';\nimport { Image } from '@/ui/Image';\nimport {\n Settings,\n Building2,\n Mail,\n Globe,\n Upload,\n Save,\n Bell,\n Shield,\n Eye,\n Trash2,\n CheckCircle,\n User,\n Phone,\n MapPin,\n FileText,\n Link as LinkIcon,\n Image as ImageIcon,\n Lock,\n Key,\n Smartphone,\n AlertCircle\n} from 'lucide-react';\nimport { logoutAction } from '@/app/actions/logoutAction';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface SponsorProfile {\n companyName: string;\n contactName: string;\n contactEmail: string;\n contactPhone: string;\n website: string;\n description: string;\n logoUrl: string | null;\n industry: string;\n address: {\n street: string;\n city: string;\n country: string;\n postalCode: string;\n };\n taxId: string;\n socialLinks: {\n twitter: string;\n linkedin: string;\n instagram: string;\n };\n}\n\ninterface NotificationSettings {\n emailNewSponsorships: boolean;\n emailWeeklyReport: boolean;\n emailRaceAlerts: boolean;\n emailPaymentAlerts: boolean;\n emailNewOpportunities: boolean;\n emailContractExpiry: boolean;\n}\n\ninterface PrivacySettings {\n publicProfile: boolean;\n showStats: boolean;\n showActiveSponsorships: boolean;\n allowDirectContact: boolean;\n}\n\n// ============================================================================\n// Mock Data\n// ============================================================================\n\nconst MOCK_PROFILE: SponsorProfile = {\n companyName: 'Acme Racing Co.',\n contactName: 'John Smith',\n contactEmail: 'sponsor@acme-racing.com',\n contactPhone: '+1 (555) 123-4567',\n website: 'https://acme-racing.com',\n description: 'Premium sim racing equipment and accessories for competitive drivers. We specialize in high-performance steering wheels, pedals, and cockpit systems used by professionals worldwide.',\n logoUrl: null,\n industry: 'Racing Equipment',\n address: {\n street: '123 Racing Boulevard',\n city: 'Indianapolis',\n country: 'United States',\n postalCode: '46222',\n },\n taxId: 'US12-3456789',\n socialLinks: {\n twitter: '@acmeracing',\n linkedin: 'acme-racing-co',\n instagram: '@acmeracing',\n },\n};\n\nconst MOCK_NOTIFICATIONS: NotificationSettings = {\n emailNewSponsorships: true,\n emailWeeklyReport: true,\n emailRaceAlerts: false,\n emailPaymentAlerts: true,\n emailNewOpportunities: true,\n emailContractExpiry: true,\n};\n\nconst MOCK_PRIVACY: PrivacySettings = {\n publicProfile: true,\n showStats: false,\n showActiveSponsorships: true,\n allowDirectContact: true,\n};\n\nconst INDUSTRY_OPTIONS = [\n 'Racing Equipment',\n 'Automotive',\n 'Technology',\n 'Gaming & Esports',\n 'Energy Drinks',\n 'Apparel',\n 'Financial Services',\n 'Other',\n];\n\n// ============================================================================\n// Components\n// ============================================================================\n\nfunction SavedIndicator({ visible }: { visible: boolean }) {\n const shouldReduceMotion = useReducedMotion();\n \n return (\n <motion.div\n initial={{ opacity: 0, x: 20 }}\n animate={{ opacity: visible ? 1 : 0, x: visible ? 0 : 20 }}\n transition={{ duration: shouldReduceMotion ? 0 : 0.2 }}\n className=\"flex items-center gap-2 text-performance-green\"\n >\n <CheckCircle className=\"w-4 h-4\" />\n <span className=\"text-sm font-medium\">Changes saved</span>\n </motion.div>\n );\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport default function SponsorSettingsPage() {\n const shouldReduceMotion = useReducedMotion();\n const [profile, setProfile] = useState(MOCK_PROFILE);\n const [notifications, setNotifications] = useState(MOCK_NOTIFICATIONS);\n const [privacy, setPrivacy] = useState(MOCK_PRIVACY);\n const [saving, setSaving] = useState(false);\n const [saved, setSaved] = useState(false);\n\n const handleSaveProfile = async () => {\n setSaving(true);\n await new Promise(resolve => setTimeout(resolve, 800));\n setSaving(false);\n setSaved(true);\n setTimeout(() => setSaved(false), 3000);\n };\n\n const handleDeleteAccount = async () => {\n if (confirm('Are you sure you want to delete your sponsor account? This action cannot be undone. All sponsorship data will be permanently removed.')) {\n // Call the logout action and handle result\n const result = await logoutAction();\n if (result.isErr()) {\n console.error('Logout failed:', result.getError());\n // Could show error toast here\n return;\n }\n // Redirect to login after successful logout\n window.location.href = '/auth/login';\n }\n };\n\n const containerVariants = {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: shouldReduceMotion ? 0 : 0.1,\n },\n },\n };\n\n const itemVariants = {\n hidden: { opacity: 0, y: 20 },\n visible: { opacity: 1, y: 0 },\n };\n\n return (\n <motion.div\n className=\"max-w-4xl mx-auto py-8 px-4\"\n variants={containerVariants}\n initial=\"hidden\"\n animate=\"visible\"\n >\n {/* Header */}\n <motion.div variants={itemVariants}>\n <PageHeader\n icon={Settings}\n title=\"Sponsor Settings\"\n description=\"Manage your company profile, notifications, and security preferences\"\n action={<SavedIndicator visible={saved} />}\n />\n </motion.div>\n\n {/* Company Profile */}\n <motion.div variants={itemVariants}>\n <Card className=\"mb-6 overflow-hidden\">\n <SectionHeader\n icon={Building2}\n title=\"Company Profile\"\n description=\"Your public-facing company information\"\n />\n <div className=\"p-6 space-y-6\">\n {/* Company Basic Info */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <FormField label=\"Company Name\" icon={Building2} required>\n <Input\n type=\"text\"\n value={profile.companyName}\n onChange={(e) => setProfile({ ...profile, companyName: e.target.value })}\n placeholder=\"Your company name\"\n />\n </FormField>\n\n <FormField label=\"Industry\">\n <select\n value={profile.industry}\n onChange={(e) => setProfile({ ...profile, industry: e.target.value })}\n className=\"w-full px-3 py-2 bg-iron-gray border border-charcoal-outline rounded-lg text-white focus:outline-none focus:border-primary-blue\"\n >\n {INDUSTRY_OPTIONS.map(industry => (\n <option key={industry} value={industry}>{industry}</option>\n ))}\n </select>\n </FormField>\n </div>\n\n {/* Contact Information */}\n <div className=\"pt-4 border-t border-charcoal-outline/50\">\n <h3 className=\"text-sm font-semibold text-gray-400 uppercase tracking-wider mb-4\">\n Contact Information\n </h3>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <FormField label=\"Contact Name\" icon={User} required>\n <Input\n type=\"text\"\n value={profile.contactName}\n onChange={(e) => setProfile({ ...profile, contactName: e.target.value })}\n placeholder=\"Full name\"\n />\n </FormField>\n\n <FormField label=\"Contact Email\" icon={Mail} required>\n <Input\n type=\"email\"\n value={profile.contactEmail}\n onChange={(e) => setProfile({ ...profile, contactEmail: e.target.value })}\n placeholder=\"sponsor@company.com\"\n />\n </FormField>\n\n <FormField label=\"Phone Number\" icon={Phone}>\n <Input\n type=\"tel\"\n value={profile.contactPhone}\n onChange={(e) => setProfile({ ...profile, contactPhone: e.target.value })}\n placeholder=\"+1 (555) 123-4567\"\n />\n </FormField>\n\n <FormField label=\"Website\" icon={Globe}>\n <Input\n type=\"url\"\n value={profile.website}\n onChange={(e) => setProfile({ ...profile, website: e.target.value })}\n placeholder=\"https://company.com\"\n />\n </FormField>\n </div>\n </div>\n\n {/* Address */}\n <div className=\"pt-4 border-t border-charcoal-outline/50\">\n <h3 className=\"text-sm font-semibold text-gray-400 uppercase tracking-wider mb-4\">\n Business Address\n </h3>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"md:col-span-2\">\n <FormField label=\"Street Address\" icon={MapPin}>\n <Input\n type=\"text\"\n value={profile.address.street}\n onChange={(e) => setProfile({\n ...profile,\n address: { ...profile.address, street: e.target.value }\n })}\n placeholder=\"123 Main Street\"\n />\n </FormField>\n </div>\n\n <FormField label=\"City\">\n <Input\n type=\"text\"\n value={profile.address.city}\n onChange={(e) => setProfile({\n ...profile,\n address: { ...profile.address, city: e.target.value }\n })}\n placeholder=\"City\"\n />\n </FormField>\n\n <FormField label=\"Postal Code\">\n <Input\n type=\"text\"\n value={profile.address.postalCode}\n onChange={(e) => setProfile({\n ...profile,\n address: { ...profile.address, postalCode: e.target.value }\n })}\n placeholder=\"12345\"\n />\n </FormField>\n\n <FormField label=\"Country\">\n <Input\n type=\"text\"\n value={profile.address.country}\n onChange={(e) => setProfile({\n ...profile,\n address: { ...profile.address, country: e.target.value }\n })}\n placeholder=\"Country\"\n />\n </FormField>\n\n <FormField label=\"Tax ID / VAT Number\" icon={FileText}>\n <Input\n type=\"text\"\n value={profile.taxId}\n onChange={(e) => setProfile({ ...profile, taxId: e.target.value })}\n placeholder=\"XX12-3456789\"\n />\n </FormField>\n </div>\n </div>\n\n {/* Description */}\n <div className=\"pt-4 border-t border-charcoal-outline/50\">\n <FormField label=\"Company Description\">\n <textarea\n value={profile.description}\n onChange={(e) => setProfile({ ...profile, description: e.target.value })}\n placeholder=\"Tell potential sponsorship partners about your company, products, and what you're looking for in sponsorship opportunities...\"\n rows={4}\n className=\"w-full px-4 py-3 bg-iron-gray border border-charcoal-outline rounded-lg text-white placeholder-gray-500 focus:outline-none focus:border-primary-blue resize-none\"\n />\n <p className=\"text-xs text-gray-500 mt-1\">\n This description appears on your public sponsor profile.\n </p>\n </FormField>\n </div>\n\n {/* Social Links */}\n <div className=\"pt-4 border-t border-charcoal-outline/50\">\n <h3 className=\"text-sm font-semibold text-gray-400 uppercase tracking-wider mb-4\">\n Social Media\n </h3>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n <FormField label=\"Twitter / X\" icon={LinkIcon}>\n <Input\n type=\"text\"\n value={profile.socialLinks.twitter}\n onChange={(e) => setProfile({\n ...profile,\n socialLinks: { ...profile.socialLinks, twitter: e.target.value }\n })}\n placeholder=\"@username\"\n />\n </FormField>\n\n <FormField label=\"LinkedIn\" icon={LinkIcon}>\n <Input\n type=\"text\"\n value={profile.socialLinks.linkedin}\n onChange={(e) => setProfile({\n ...profile,\n socialLinks: { ...profile.socialLinks, linkedin: e.target.value }\n })}\n placeholder=\"company-name\"\n />\n </FormField>\n\n <FormField label=\"Instagram\" icon={LinkIcon}>\n <Input\n type=\"text\"\n value={profile.socialLinks.instagram}\n onChange={(e) => setProfile({\n ...profile,\n socialLinks: { ...profile.socialLinks, instagram: e.target.value }\n })}\n placeholder=\"@username\"\n />\n </FormField>\n </div>\n </div>\n\n {/* Logo Upload */}\n <div className=\"pt-4 border-t border-charcoal-outline/50\">\n <FormField label=\"Company Logo\" icon={ImageIcon}>\n <div className=\"flex items-start gap-6\">\n <div className=\"w-24 h-24 rounded-xl bg-gradient-to-br from-iron-gray to-deep-graphite border-2 border-dashed border-charcoal-outline flex items-center justify-center overflow-hidden\">\n {profile.logoUrl ? (\n <Image src={profile.logoUrl} alt=\"Company logo\" width={96} height={96} objectFit=\"cover\" />\n ) : (\n <Building2 className=\"w-10 h-10 text-gray-600\" />\n )}\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-3\">\n <label className=\"cursor-pointer\">\n <input\n type=\"file\"\n accept=\"image/png,image/jpeg,image/svg+xml\"\n className=\"hidden\"\n />\n <div className=\"px-4 py-2 rounded-lg bg-iron-gray border border-charcoal-outline text-gray-300 hover:bg-charcoal-outline transition-colors flex items-center gap-2\">\n <Upload className=\"w-4 h-4\" />\n Upload Logo\n </div>\n </label>\n {profile.logoUrl && (\n <Button variant=\"secondary\" className=\"text-sm text-gray-400\">\n Remove\n </Button>\n )}\n </div>\n <p className=\"text-xs text-gray-500 mt-2\">\n PNG, JPEG, or SVG. Max 2MB. Recommended size: 400x400px.\n </p>\n </div>\n </div>\n </FormField>\n </div>\n\n {/* Save Button */}\n <div className=\"pt-6 border-t border-charcoal-outline flex items-center justify-end gap-4\">\n <Button\n variant=\"primary\"\n onClick={handleSaveProfile}\n disabled={saving}\n className=\"min-w-[160px]\"\n >\n {saving ? (\n <span className=\"flex items-center gap-2\">\n <span className=\"w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin\" />\n Saving...\n </span>\n ) : (\n <span className=\"flex items-center gap-2\">\n <Save className=\"w-4 h-4\" />\n Save Profile\n </span>\n )}\n </Button>\n </div>\n </div>\n </Card>\n </motion.div>\n\n {/* Notification Preferences */}\n <motion.div variants={itemVariants}>\n <Card className=\"mb-6 overflow-hidden\">\n <SectionHeader\n icon={Bell}\n title=\"Email Notifications\"\n description=\"Control which emails you receive from GridPilot\"\n color=\"text-warning-amber\"\n />\n <div className=\"p-6\">\n <div className=\"space-y-1\">\n <Toggle\n checked={notifications.emailNewSponsorships}\n onChange={(checked) => setNotifications({ ...notifications, emailNewSponsorships: checked })}\n label=\"Sponsorship Approvals\"\n description=\"Receive confirmation when your sponsorship requests are approved\"\n />\n <Toggle\n checked={notifications.emailWeeklyReport}\n onChange={(checked) => setNotifications({ ...notifications, emailWeeklyReport: checked })}\n label=\"Weekly Analytics Report\"\n description=\"Get a weekly summary of your sponsorship performance\"\n />\n <Toggle\n checked={notifications.emailRaceAlerts}\n onChange={(checked) => setNotifications({ ...notifications, emailRaceAlerts: checked })}\n label=\"Race Day Alerts\"\n description=\"Be notified when sponsored leagues have upcoming races\"\n />\n <Toggle\n checked={notifications.emailPaymentAlerts}\n onChange={(checked) => setNotifications({ ...notifications, emailPaymentAlerts: checked })}\n label=\"Payment & Invoice Notifications\"\n description=\"Receive invoices and payment confirmations\"\n />\n <Toggle\n checked={notifications.emailNewOpportunities}\n onChange={(checked) => setNotifications({ ...notifications, emailNewOpportunities: checked })}\n label=\"New Sponsorship Opportunities\"\n description=\"Get notified about new leagues and drivers seeking sponsors\"\n />\n <Toggle\n checked={notifications.emailContractExpiry}\n onChange={(checked) => setNotifications({ ...notifications, emailContractExpiry: checked })}\n label=\"Contract Expiry Reminders\"\n description=\"Receive reminders before your sponsorship contracts expire\"\n />\n </div>\n </div>\n </Card>\n </motion.div>\n\n {/* Privacy & Visibility */}\n <motion.div variants={itemVariants}>\n <Card className=\"mb-6 overflow-hidden\">\n <SectionHeader\n icon={Eye}\n title=\"Privacy & Visibility\"\n description=\"Control how your profile appears to others\"\n color=\"text-performance-green\"\n />\n <div className=\"p-6\">\n <div className=\"space-y-1\">\n <Toggle\n checked={privacy.publicProfile}\n onChange={(checked) => setPrivacy({ ...privacy, publicProfile: checked })}\n label=\"Public Profile\"\n description=\"Allow leagues, teams, and drivers to view your sponsor profile\"\n />\n <Toggle\n checked={privacy.showStats}\n onChange={(checked) => setPrivacy({ ...privacy, showStats: checked })}\n label=\"Show Sponsorship Statistics\"\n description=\"Display your total sponsorships and investment amounts\"\n />\n <Toggle\n checked={privacy.showActiveSponsorships}\n onChange={(checked) => setPrivacy({ ...privacy, showActiveSponsorships: checked })}\n label=\"Show Active Sponsorships\"\n description=\"Let others see which leagues and teams you currently sponsor\"\n />\n <Toggle\n checked={privacy.allowDirectContact}\n onChange={(checked) => setPrivacy({ ...privacy, allowDirectContact: checked })}\n label=\"Allow Direct Contact\"\n description=\"Enable leagues and teams to send you sponsorship proposals\"\n />\n </div>\n </div>\n </Card>\n </motion.div>\n\n {/* Security */}\n <motion.div variants={itemVariants}>\n <Card className=\"mb-6 overflow-hidden\">\n <SectionHeader\n icon={Shield}\n title=\"Account Security\"\n description=\"Protect your sponsor account\"\n color=\"text-primary-blue\"\n />\n <div className=\"p-6 space-y-4\">\n <div className=\"flex items-center justify-between py-3 border-b border-charcoal-outline/50\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 rounded-lg bg-iron-gray\">\n <Key className=\"w-5 h-5 text-gray-400\" />\n </div>\n <div>\n <p className=\"text-gray-200 font-medium\">Password</p>\n <p className=\"text-sm text-gray-500\">Last changed 3 months ago</p>\n </div>\n </div>\n <Button variant=\"secondary\">\n Change Password\n </Button>\n </div>\n\n <div className=\"flex items-center justify-between py-3 border-b border-charcoal-outline/50\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 rounded-lg bg-iron-gray\">\n <Smartphone className=\"w-5 h-5 text-gray-400\" />\n </div>\n <div>\n <p className=\"text-gray-200 font-medium\">Two-Factor Authentication</p>\n <p className=\"text-sm text-gray-500\">Add an extra layer of security to your account</p>\n </div>\n </div>\n <Button variant=\"secondary\">\n Enable 2FA\n </Button>\n </div>\n\n <div className=\"flex items-center justify-between py-3\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 rounded-lg bg-iron-gray\">\n <Lock className=\"w-5 h-5 text-gray-400\" />\n </div>\n <div>\n <p className=\"text-gray-200 font-medium\">Active Sessions</p>\n <p className=\"text-sm text-gray-500\">Manage devices where you're logged in</p>\n </div>\n </div>\n <Button variant=\"secondary\">\n View Sessions\n </Button>\n </div>\n </div>\n </Card>\n </motion.div>\n\n {/* Danger Zone */}\n <motion.div variants={itemVariants}>\n <Card className=\"border-racing-red/30 overflow-hidden\">\n <div className=\"p-5 border-b border-racing-red/30 bg-gradient-to-r from-racing-red/10 to-transparent\">\n <h2 className=\"text-lg font-semibold text-racing-red flex items-center gap-3\">\n <div className=\"p-2 rounded-lg bg-racing-red/10\">\n <AlertCircle className=\"w-5 h-5 text-racing-red\" />\n </div>\n Danger Zone\n </h2>\n </div>\n <div className=\"p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 rounded-lg bg-racing-red/10\">\n <Trash2 className=\"w-5 h-5 text-racing-red\" />\n </div>\n <div>\n <p className=\"text-gray-200 font-medium\">Delete Sponsor Account</p>\n <p className=\"text-sm text-gray-500\">\n Permanently delete your account and all associated sponsorship data.\n This action cannot be undone.\n </p>\n </div>\n </div>\n <Button\n variant=\"secondary\"\n onClick={handleDeleteAccount}\n className=\"text-racing-red border-racing-red/30 hover:bg-racing-red/10\"\n >\n Delete Account\n </Button>\n </div>\n </div>\n </Card>\n </motion.div>\n </motion.div>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/sponsor/signup/page.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'Star' is defined but never used.","line":28,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":28,"endColumn":7},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":141,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":227,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":203,"column":15,"nodeType":"NewExpression","messageId":"message","endLine":203,"endColumn":62},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":216,"column":15,"nodeType":"NewExpression","messageId":"message","endLine":216,"endColumn":45},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":229,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":236,"endColumn":4},{"ruleId":"gridpilot-rules/rsc-no-sorting-filtering","severity":2,"message":"Sorting/filtering/reduce operations forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":233,"column":11,"nodeType":"CallExpression","messageId":"message","endLine":233,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":241,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":429,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":241,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":241,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":241,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":241,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":247,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":264,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":247,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":247,"endColumn":75},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":247,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":247,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":251,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":251,"endColumn":36},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":253,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":253,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":259,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":259,"endColumn":36},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":262,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":262,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":268,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":284,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":268,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":268,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":268,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":268,"endColumn":68},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":269,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":283,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":269,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":269,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":269,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":269,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":271,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":276,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":277,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":277,"endColumn":83},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":278,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":278,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":278,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":278,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":278,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":278,"endColumn":82},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":279,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":279,"endColumn":87},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":279,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":279,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":279,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":279,"endColumn":68},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":287,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":331,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":287,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":287,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":287,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":287,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":288,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":296,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":288,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":288,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":288,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":288,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":289,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":291,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":289,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":289,"endColumn":76},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":289,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":289,"endColumn":75},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":292,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":295,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":292,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":292,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":292,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":292,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":298,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":330,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":298,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":298,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":298,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":298,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":300,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":305,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":306,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":306,"endColumn":104},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":307,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":315,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":307,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":307,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":307,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":307,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":308,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":310,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":308,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":308,"endColumn":191},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":308,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":308,"endColumn":190},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":309,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":309,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":309,"column":34,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":309,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":311,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":311,"endColumn":26},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":312,"column":23,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":312,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":312,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":312,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":312,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":312,"endColumn":71},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":313,"column":23,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":313,"endColumn":97},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":313,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":313,"endColumn":76},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":313,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":313,"endColumn":75},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":317,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":317,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":317,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":317,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":317,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":317,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":319,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":326,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":319,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":319,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":319,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":319,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":321,"column":23,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":324,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":321,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":321,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":321,"column":35,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":321,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":322,"column":39,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":322,"endColumn":95},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":334,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":347,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":334,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":334,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":334,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":334,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":335,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":346,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":335,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":335,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":335,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":335,"endColumn":50},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":336,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":343,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":336,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":336,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":336,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":336,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":337,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":339,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":337,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":337,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":337,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":337,"endColumn":77},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":340,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":342,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":340,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":340,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":340,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":340,"endColumn":61},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":350,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":399,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":350,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":350,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":350,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":350,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":351,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":358,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":351,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":351,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":351,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":351,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":352,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":354,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":352,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":352,"endColumn":76},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":352,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":352,"endColumn":75},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":355,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":357,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":355,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":355,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":355,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":355,"endColumn":59},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":360,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":398,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":360,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":360,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":360,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":360,"endColumn":80},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":402,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":428,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":402,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":402,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":402,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":402,"endColumn":79},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":403,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":405,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":403,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":403,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":403,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":403,"endColumn":73},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":406,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":408,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":406,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":406,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":406,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":406,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":409,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":427,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":409,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":409,"endColumn":75},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":409,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":409,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":413,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":413,"endColumn":36},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":415,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":415,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":422,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":422,"endColumn":36},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":424,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":424,"endColumn":45},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":436,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":523,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":436,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":436,"endColumn":98},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":436,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":436,"endColumn":97},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":437,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":522,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":437,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":437,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":437,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":437,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":438,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":455,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":438,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":438,"endColumn":33},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":438,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":438,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":439,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":445,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":439,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":442,"endColumn":14},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":441,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":441,"endColumn":94},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":443,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":443,"endColumn":57},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":446,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":454,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":446,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":446,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":446,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":446,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":447,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":449,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":447,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":447,"endColumn":136},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":447,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":447,"endColumn":135},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":448,"column":28,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":448,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":450,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":450,"endColumn":20},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":451,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":451,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":451,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":451,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":451,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":451,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":452,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":452,"endColumn":87},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":452,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":452,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":452,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":452,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":457,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":457,"endColumn":32},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":458,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":508,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":458,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":458,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":458,"column":43,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":458,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":459,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":459,"endColumn":20},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":460,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":465,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":460,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":460,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":460,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":460,"endColumn":80},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":461,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":464,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":461,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":461,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":461,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":461,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":462,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":462,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":476,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":476,"endColumn":20},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":477,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":479,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":477,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":477,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":477,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":477,"endColumn":80},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":490,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":498,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":490,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":490,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":490,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":490,"endColumn":73},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":491,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":494,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":491,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":491,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":491,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":491,"endColumn":73},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":492,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":492,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":492,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":492,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":492,"column":42,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":492,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":495,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":497,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":495,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":495,"endColumn":85},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":495,"column":39,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":495,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":504,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":504,"endColumn":35},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":510,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":520,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":510,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":510,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":510,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":510,"endColumn":72},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":511,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":519,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":511,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":511,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":511,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":511,"endColumn":68},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":512,"column":20,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[17950,17989],"text":"\n Don't have an account?"},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[17950,17989],"text":"\n Don‘t have an account?"},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[17950,17989],"text":"\n Don't have an account?"},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[17950,17989],"text":"\n Don’t have an account?"},"desc":"Replace with `’`."}]},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":513,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":518,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":513,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":516,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":515,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":515,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":529,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":783,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":529,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":529,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":529,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":529,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":530,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":782,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":530,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":530,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":530,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":530,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":532,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":549,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":532,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":532,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":532,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":532,"endColumn":30},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":533,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":539,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":533,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":536,"endColumn":12},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":535,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":535,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":537,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":537,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":540,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":548,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":540,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":540,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":540,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":540,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":541,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":543,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":541,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":541,"endColumn":134},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":541,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":541,"endColumn":133},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":542,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":542,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":544,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":544,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":545,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":545,"endColumn":88},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":545,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":545,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":545,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":545,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":546,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":546,"endColumn":104},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":546,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":546,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":546,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":546,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":551,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":551,"endColumn":30},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":552,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":768,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":552,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":552,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":552,"column":41,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":552,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":554,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":554,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":555,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":558,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":555,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":555,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":555,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":555,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":556,"column":28,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":556,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":560,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":606,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":560,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":560,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":560,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":560,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":561,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":573,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":561,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":561,"endColumn":48},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":561,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":561,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":562,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":564,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":562,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":562,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":562,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":562,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":575,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":575,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":576,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":581,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":576,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":576,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":576,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":576,"endColumn":82},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":577,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":580,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":577,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":577,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":577,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":577,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":578,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":578,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":592,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":592,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":593,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":598,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":593,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":593,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":593,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":593,"endColumn":82},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":594,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":597,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":594,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":594,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":594,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":594,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":595,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":595,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":610,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":610,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":611,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":614,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":611,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":611,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":611,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":611,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":612,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":612,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":615,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":617,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":615,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":615,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":615,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":615,"endColumn":56},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":616,"column":53,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[22120,22216],"text":"\n Select the types of sponsorships you're interested in (optional)\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[22120,22216],"text":"\n Select the types of sponsorships you‘re interested in (optional)\n "},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[22120,22216],"text":"\n Select the types of sponsorships you're interested in (optional)\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[22120,22216],"text":"\n Select the types of sponsorships you’re interested in (optional)\n "},"desc":"Replace with `’`."}]},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":619,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":642,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":619,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":619,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":619,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":619,"endColumn":69},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":623,"column":21,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":639,"endColumn":30},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":623,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":634,"endColumn":22},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":627,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":633,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":635,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":635,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":635,"column":34,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":635,"endColumn":105},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":636,"column":23,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":638,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":636,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":636,"endColumn":107},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":636,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":636,"endColumn":106},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":646,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":646,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":647,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":652,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":647,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":647,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":647,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":647,"endColumn":78},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":648,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":651,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":648,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":648,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":648,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":648,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":649,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":649,"endColumn":60},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":653,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":671,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":653,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":653,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":653,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":653,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":654,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":656,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":654,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":654,"endColumn":146},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":654,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":654,"endColumn":145},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":655,"column":30,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":655,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":657,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":670,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":657,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":657,"endColumn":41},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":657,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":657,"endColumn":40},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":658,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":666,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":658,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":666,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":665,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":665,"endColumn":238},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":667,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":669,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":667,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":667,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":667,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":667,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":675,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":675,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":676,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":679,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":676,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":676,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":676,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":676,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":677,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":677,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":681,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":709,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":681,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":681,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":681,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":681,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":682,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":682,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":683,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":685,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":683,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":683,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":683,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":683,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":696,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":696,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":697,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":699,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":697,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":697,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":697,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":697,"endColumn":82},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":713,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":747,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":713,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":713,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":713,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":713,"endColumn":77},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":714,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":728,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":714,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":714,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":714,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":714,"endColumn":71},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":715,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":720,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":715,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":720,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":719,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":719,"endColumn":122},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":721,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":727,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":721,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":721,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":721,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":721,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":723,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":723,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":723,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":723,"endColumn":88},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":723,"column":42,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":723,"endColumn":87},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":725,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":725,"endColumn":108},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":725,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":725,"endColumn":90},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":725,"column":44,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":725,"endColumn":89},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":730,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":730,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":730,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":730,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":730,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":730,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":733,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":743,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":733,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":733,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":733,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":733,"endColumn":71},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":734,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":739,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":734,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":739,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":738,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":738,"endColumn":122},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":740,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":742,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":740,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":740,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":740,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":740,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":745,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":745,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":745,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":745,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":745,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":745,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":750,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":767,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":750,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":750,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":750,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":750,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":755,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":755,"endColumn":35},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":770,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":780,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":770,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":770,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":770,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":770,"endColumn":82},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":771,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":779,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":771,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":771,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":771,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":771,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in app/ is forbidden. Use components/ or ui/ elements.","line":773,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInApp","endLine":778,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":773,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":776,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":775,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":775,"endColumn":62}],"suppressedMessages":[],"errorCount":351,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { Card } from '@/ui/Card';\nimport { Button } from '@/ui/Button';\nimport { Input } from '@/ui/Input';\nimport { SponsorHero } from '@/components/sponsors/SponsorHero';\nimport { SponsorWorkflowMockup } from '@/components/sponsors/SponsorWorkflowMockup';\nimport { SponsorBenefitCard } from '@/components/sponsors/SponsorBenefitCard';\nimport { siteConfig } from '@/lib/siteConfig';\nimport {\n Building2,\n Mail,\n Globe,\n Upload,\n Eye,\n TrendingUp,\n Users,\n ArrowRight,\n Trophy,\n Car,\n Flag,\n Target,\n BarChart3,\n Shield,\n CheckCircle2,\n Star,\n Megaphone\n} from 'lucide-react';\n\n// Sponsorship type definitions\ninterface SponsorshipType {\n id: string;\n title: string;\n icon: typeof Trophy;\n description: string;\n benefits: string[];\n priceRange: string;\n color: string;\n}\n\nconst SPONSORSHIP_TYPES: SponsorshipType[] = [\n {\n id: 'leagues',\n title: 'League Sponsorship',\n icon: Trophy,\n description: 'Sponsor entire racing leagues and get your brand in front of all participants and viewers.',\n benefits: [\n 'Logo on all participant liveries',\n 'League page banner placement',\n 'Results page branding',\n 'Social media mentions'\n ],\n priceRange: '$200 - $2,000/season',\n color: 'text-primary-blue',\n },\n {\n id: 'teams',\n title: 'Team Sponsorship',\n icon: Users,\n description: 'Partner with competitive racing teams to build long-term brand associations.',\n benefits: [\n 'Team livery logo placement',\n 'Team profile visibility',\n 'Driver association',\n 'Event representation'\n ],\n priceRange: '$100 - $800/season',\n color: 'text-purple-400',\n },\n {\n id: 'drivers',\n title: 'Driver Sponsorship',\n icon: Car,\n description: 'Support individual drivers and grow with rising sim racing talent.',\n benefits: [\n 'Personal livery branding',\n 'Driver profile sponsor badge',\n 'Race results association',\n 'Direct driver partnership'\n ],\n priceRange: '$50 - $300/season',\n color: 'text-performance-green',\n },\n {\n id: 'races',\n title: 'Race Sponsorship',\n icon: Flag,\n description: 'Sponsor individual race events for targeted, high-impact exposure.',\n benefits: [\n 'Race title naming rights',\n 'Event page branding',\n 'Results page placement',\n 'Social media features'\n ],\n priceRange: '$50 - $500/race',\n color: 'text-warning-amber',\n },\n {\n id: 'platform',\n title: 'Platform Advertising',\n icon: Megaphone,\n description: 'Reach the entire GridPilot audience with strategic platform placements.',\n benefits: [\n 'Homepage banner ads',\n 'Sidebar placements',\n 'Newsletter inclusion',\n 'Cross-platform exposure'\n ],\n priceRange: '$100 - $1,000/month',\n color: 'text-racing-red',\n },\n];\n\n// Stats for social proof\nconst PLATFORM_STATS = [\n { value: '50,000+', label: 'Monthly Race Views' },\n { value: '12,000+', label: 'Active Drivers' },\n { value: '500+', label: 'Racing Leagues' },\n { value: '4.8%', label: 'Avg. Engagement Rate' },\n];\n\nexport default function SponsorSignupPage() {\n const shouldReduceMotion = useReducedMotion();\n const [mode, setMode] = useState<'landing' | 'signup' | 'login'>('landing');\n const [formData, setFormData] = useState({\n companyName: '',\n contactEmail: '',\n websiteUrl: '',\n logoFile: null as File | null,\n password: '',\n confirmPassword: '',\n interests: [] as string[],\n acceptTerms: false,\n acceptVat: false,\n });\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [submitting, setSubmitting] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n \n const newErrors: Record<string, string> = {};\n \n if (!formData.companyName.trim()) {\n newErrors.companyName = 'Company name required';\n }\n \n if (!formData.contactEmail.trim()) {\n newErrors.contactEmail = 'Contact email required';\n } else if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(formData.contactEmail)) {\n newErrors.contactEmail = 'Invalid email format';\n }\n\n if (mode === 'signup') {\n if (!formData.password.trim()) {\n newErrors.password = 'Password required';\n } else if (formData.password.length < 8) {\n newErrors.password = 'Password must be at least 8 characters';\n }\n \n if (formData.password !== formData.confirmPassword) {\n newErrors.confirmPassword = 'Passwords do not match';\n }\n\n if (!formData.acceptTerms) {\n newErrors.acceptTerms = 'You must accept the terms and conditions';\n }\n\n if (!formData.acceptVat) {\n newErrors.acceptVat = 'You must acknowledge the VAT policy';\n }\n }\n \n if (Object.keys(newErrors).length > 0) {\n setErrors(newErrors);\n return;\n }\n \n setSubmitting(true);\n \n try {\n // Note: Business logic for auth should be moved to a mutation\n // This is a temporary implementation for contract compliance\n const response = await fetch('/api/auth/signup', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: formData.contactEmail,\n password: formData.password,\n displayName: formData.companyName,\n sponsorData: {\n companyName: formData.companyName,\n websiteUrl: formData.websiteUrl,\n interests: formData.interests,\n },\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.message || 'Signup failed');\n }\n\n const loginResponse = await fetch('/api/auth/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: formData.contactEmail,\n password: formData.password,\n }),\n });\n\n if (!loginResponse.ok) {\n throw new Error('Auto-login failed');\n }\n\n // Navigate to dashboard\n window.location.href = '/sponsor/dashboard';\n } catch (err) {\n console.error('Sponsor signup failed:', err);\n alert('Registration failed. ' + (err instanceof Error ? err.message : 'Try again.'));\n } finally {\n setSubmitting(false);\n }\n };\n\n const toggleInterest = (id: string) => {\n setFormData(prev => ({\n ...prev,\n interests: prev.interests.includes(id)\n ? prev.interests.filter(i => i !== id)\n : [...prev.interests, id]\n }));\n };\n\n // Landing page for sponsors\n if (mode === 'landing') {\n return (\n <div className=\"min-h-screen bg-deep-graphite\">\n {/* Hero Section */}\n <SponsorHero\n title=\"Connect Your Brand with Sim Racing\"\n subtitle=\"Reach passionate racing communities through league, team, driver, and race sponsorships. Real exposure, measurable results.\"\n >\n <div className=\"flex flex-col sm:flex-row gap-4 justify-center\">\n <Button\n variant=\"primary\"\n onClick={() => setMode('signup')}\n className=\"px-8 py-3\"\n >\n <Building2 className=\"w-5 h-5 mr-2\" />\n Create Sponsor Account\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => setMode('login')}\n className=\"px-8 py-3\"\n >\n Sign In\n <ArrowRight className=\"w-5 h-5 ml-2\" />\n </Button>\n </div>\n </SponsorHero>\n\n {/* Platform Stats */}\n <div className=\"max-w-6xl mx-auto px-4 -mt-8 relative z-10\">\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {PLATFORM_STATS.map((stat, index) => (\n <motion.div\n key={stat.label}\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: index * 0.1 }}\n >\n <Card className=\"text-center p-4 bg-iron-gray/80 backdrop-blur-sm\">\n <div className=\"text-2xl sm:text-3xl font-bold text-white mb-1\">{stat.value}</div>\n <div className=\"text-xs sm:text-sm text-gray-400\">{stat.label}</div>\n </Card>\n </motion.div>\n ))}\n </div>\n </div>\n\n {/* Sponsorship Types Section */}\n <section className=\"max-w-6xl mx-auto px-4 py-16 sm:py-24\">\n <div className=\"text-center mb-12\">\n <h2 className=\"text-3xl sm:text-4xl font-bold text-white mb-4\">\n Sponsorship Opportunities\n </h2>\n <p className=\"text-gray-400 max-w-2xl mx-auto\">\n Choose how you want to connect with the sim racing community.\n Multiple sponsorship tiers and types to fit every budget and goal.\n </p>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {SPONSORSHIP_TYPES.map((type, index) => (\n <motion.div\n key={type.id}\n initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: index * 0.1 }}\n >\n <Card className=\"h-full hover:border-primary-blue/50 transition-all duration-300 group\">\n <div className=\"flex items-start gap-4 mb-4\">\n <div className={`w-12 h-12 rounded-xl bg-iron-gray border border-charcoal-outline flex items-center justify-center group-hover:border-primary-blue/50 transition-colors`}>\n <type.icon className={`w-6 h-6 ${type.color}`} />\n </div>\n <div>\n <h3 className=\"text-lg font-semibold text-white\">{type.title}</h3>\n <p className=\"text-sm text-primary-blue font-medium\">{type.priceRange}</p>\n </div>\n </div>\n \n <p className=\"text-sm text-gray-400 mb-4\">{type.description}</p>\n \n <ul className=\"space-y-2\">\n {type.benefits.map((benefit, i) => (\n <li key={i} className=\"flex items-center gap-2 text-sm text-gray-300\">\n <CheckCircle2 className=\"w-4 h-4 text-performance-green flex-shrink-0\" />\n {benefit}\n </li>\n ))}\n </ul>\n </Card>\n </motion.div>\n ))}\n </div>\n </section>\n\n {/* Workflow Mockup Section */}\n <section className=\"bg-iron-gray/30 py-16 sm:py-24\">\n <div className=\"max-w-6xl mx-auto px-4\">\n <div className=\"text-center mb-12\">\n <h2 className=\"text-3xl sm:text-4xl font-bold text-white mb-4\">\n How It Works\n </h2>\n <p className=\"text-gray-400 max-w-2xl mx-auto\">\n From discovery to results tracking — a seamless sponsorship experience.\n </p>\n </div>\n \n <SponsorWorkflowMockup />\n </div>\n </section>\n\n {/* Benefits Grid */}\n <section className=\"max-w-6xl mx-auto px-4 py-16 sm:py-24\">\n <div className=\"text-center mb-12\">\n <h2 className=\"text-3xl sm:text-4xl font-bold text-white mb-4\">\n Why Sponsor on GridPilot?\n </h2>\n <p className=\"text-gray-400 max-w-2xl mx-auto\">\n Professional tools and genuine community engagement make your sponsorship worthwhile.\n </p>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n <SponsorBenefitCard\n icon={Eye}\n title=\"Real Visibility\"\n description=\"Your logo appears on in-game liveries, league pages, and race results. Genuine exposure to engaged audiences.\"\n variant=\"highlight\"\n delay={0}\n />\n <SponsorBenefitCard\n icon={BarChart3}\n title=\"Detailed Analytics\"\n description=\"Track impressions, engagement rates, and ROI with comprehensive sponsorship analytics.\"\n delay={0.1}\n />\n <SponsorBenefitCard\n icon={Target}\n title=\"Targeted Reach\"\n description=\"Choose specific leagues, teams, or drivers that align with your brand and target audience.\"\n delay={0.2}\n />\n <SponsorBenefitCard\n icon={Shield}\n title=\"Trusted Platform\"\n description=\"Secure payments, automated invoicing, and professional support for your sponsorship needs.\"\n delay={0.3}\n />\n <SponsorBenefitCard\n icon={Users}\n title=\"Engaged Community\"\n description=\"Sim racing audiences are tech-savvy, passionate, and value authentic brand partnerships.\"\n delay={0.4}\n />\n <SponsorBenefitCard\n icon={TrendingUp}\n title=\"Growth Potential\"\n description=\"Scale your sponsorships as you see results. Start small or go big from day one.\"\n delay={0.5}\n />\n </div>\n </section>\n\n {/* CTA Section */}\n <section className=\"max-w-4xl mx-auto px-4 py-16 sm:py-24 text-center\">\n <h2 className=\"text-3xl sm:text-4xl font-bold text-white mb-4\">\n Ready to Grow Your Brand?\n </h2>\n <p className=\"text-gray-400 max-w-2xl mx-auto mb-8\">\n Join sponsors connecting with sim racing communities worldwide.\n </p>\n <div className=\"flex flex-col sm:flex-row gap-4 justify-center\">\n <Button\n variant=\"primary\"\n onClick={() => setMode('signup')}\n className=\"px-8 py-3\"\n >\n <Building2 className=\"w-5 h-5 mr-2\" />\n Get Started Now\n </Button>\n <Button\n variant=\"secondary\"\n as=\"a\"\n href={`mailto:${siteConfig.sponsorEmail}`}\n className=\"px-8 py-3\"\n >\n <Mail className=\"w-5 h-5 mr-2\" />\n Contact Sales\n </Button>\n </div>\n </section>\n </div>\n );\n }\n\n // Login form\n if (mode === 'login') {\n return (\n <div className=\"min-h-screen bg-deep-graphite flex items-center justify-center px-4 py-12\">\n <div className=\"w-full max-w-md\">\n <div className=\"mb-8\">\n <button\n onClick={() => setMode('landing')}\n className=\"text-sm text-gray-400 hover:text-white mb-6 flex items-center gap-2\"\n >\n <ArrowRight className=\"w-4 h-4 rotate-180\" />\n Back to overview\n </button>\n <div className=\"flex items-center gap-4 mb-2\">\n <div className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-primary-blue/10 border border-primary-blue/20\">\n <Building2 className=\"w-7 h-7 text-primary-blue\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-white\">Sponsor Sign In</h1>\n <p className=\"text-sm text-gray-400\">Access your sponsor dashboard</p>\n </div>\n </div>\n </div>\n\n <Card className=\"p-6\">\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n <div className=\"flex items-center gap-2\">\n <Mail className=\"w-4 h-4 text-gray-500\" />\n Email Address\n </div>\n </label>\n <Input\n type=\"email\"\n value={formData.contactEmail}\n onChange={(e) => setFormData({ ...formData, contactEmail: e.target.value })}\n placeholder=\"sponsor@company.com\"\n variant={errors.contactEmail ? 'error' : 'default'}\n errorMessage={errors.contactEmail}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n Password\n </label>\n <Input\n type=\"password\"\n value={formData.password}\n onChange={(e) => setFormData({ ...formData, password: e.target.value })}\n placeholder=\"••••••••\"\n variant={errors.password ? 'error' : 'default'}\n errorMessage={errors.password}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-sm\">\n <label className=\"flex items-center gap-2 text-gray-400\">\n <input type=\"checkbox\" className=\"rounded border-charcoal-outline bg-iron-gray\" />\n Remember me\n </label>\n <button type=\"button\" className=\"text-primary-blue hover:underline\">\n Forgot password?\n </button>\n </div>\n\n <Button\n type=\"submit\"\n variant=\"primary\"\n disabled={submitting}\n className=\"w-full\"\n >\n {submitting ? 'Signing in...' : 'Sign In'}\n </Button>\n </form>\n\n <div className=\"mt-6 pt-6 border-t border-charcoal-outline\">\n <p className=\"text-sm text-gray-400 text-center mb-4\">\n Don't have an account?{' '}\n <button\n onClick={() => setMode('signup')}\n className=\"text-primary-blue hover:underline\"\n >\n Create one\n </button>\n </p>\n </div>\n </Card>\n </div>\n </div>\n );\n }\n\n // Signup form\n return (\n <div className=\"min-h-screen bg-deep-graphite py-12 px-4\">\n <div className=\"max-w-2xl mx-auto\">\n {/* Header */}\n <div className=\"mb-8\">\n <button\n onClick={() => setMode('landing')}\n className=\"text-sm text-gray-400 hover:text-white mb-6 flex items-center gap-2\"\n >\n <ArrowRight className=\"w-4 h-4 rotate-180\" />\n Back to overview\n </button>\n <div className=\"flex items-center gap-4 mb-2\">\n <div className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-primary-blue/10 border border-primary-blue/20\">\n <Building2 className=\"w-7 h-7 text-primary-blue\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-white\">Create Sponsor Account</h1>\n <p className=\"text-sm text-gray-400\">Register your company to sponsor racing entities</p>\n </div>\n </div>\n </div>\n\n <Card className=\"p-6\">\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Company Information */}\n <div>\n <h3 className=\"text-lg font-semibold text-white mb-4 flex items-center gap-2\">\n <Building2 className=\"w-5 h-5 text-primary-blue\" />\n Company Information\n </h3>\n \n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div className=\"md:col-span-2\">\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n Company Name *\n </label>\n <Input\n type=\"text\"\n value={formData.companyName}\n onChange={(e) => setFormData({ ...formData, companyName: e.target.value })}\n placeholder=\"Your company name\"\n variant={errors.companyName ? 'error' : 'default'}\n errorMessage={errors.companyName}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n <div className=\"flex items-center gap-2\">\n <Mail className=\"w-4 h-4 text-gray-500\" />\n Contact Email *\n </div>\n </label>\n <Input\n type=\"email\"\n value={formData.contactEmail}\n onChange={(e) => setFormData({ ...formData, contactEmail: e.target.value })}\n placeholder=\"sponsor@company.com\"\n variant={errors.contactEmail ? 'error' : 'default'}\n errorMessage={errors.contactEmail}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n <div className=\"flex items-center gap-2\">\n <Globe className=\"w-4 h-4 text-gray-500\" />\n Website URL\n </div>\n </label>\n <Input\n type=\"url\"\n value={formData.websiteUrl}\n onChange={(e) => setFormData({ ...formData, websiteUrl: e.target.value })}\n placeholder=\"https://company.com\"\n />\n </div>\n </div>\n </div>\n\n {/* Sponsorship Interests */}\n <div>\n <h3 className=\"text-lg font-semibold text-white mb-4 flex items-center gap-2\">\n <Target className=\"w-5 h-5 text-purple-400\" />\n Sponsorship Interests\n </h3>\n <p className=\"text-sm text-gray-400 mb-4\">\n Select the types of sponsorships you're interested in (optional)\n </p>\n \n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-3\">\n {SPONSORSHIP_TYPES.map((type) => {\n const isSelected = formData.interests.includes(type.id);\n return (\n <button\n key={type.id}\n type=\"button\"\n onClick={() => toggleInterest(type.id)}\n className={`\n p-3 rounded-lg border text-left transition-all\n ${isSelected\n ? 'bg-primary-blue/10 border-primary-blue/50'\n : 'bg-iron-gray/50 border-charcoal-outline hover:border-charcoal-outline/80'\n }\n `}\n >\n <type.icon className={`w-5 h-5 ${isSelected ? type.color : 'text-gray-500'} mb-2`} />\n <p className={`text-sm font-medium ${isSelected ? 'text-white' : 'text-gray-400'}`}>\n {type.title.replace(' Sponsorship', '').replace(' Advertising', '')}\n </p>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Company Logo */}\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n <div className=\"flex items-center gap-2\">\n <Upload className=\"w-4 h-4 text-gray-500\" />\n Company Logo (optional)\n </div>\n </label>\n <div className=\"flex items-center gap-4\">\n <div className=\"w-16 h-16 rounded-lg bg-iron-gray border border-charcoal-outline flex items-center justify-center flex-shrink-0\">\n <Building2 className=\"w-6 h-6 text-gray-500\" />\n </div>\n <div className=\"flex-1\">\n <input\n type=\"file\"\n accept=\"image/png,image/jpeg,image/svg+xml\"\n onChange={(e) => {\n const file = e.target.files?.[0] || null;\n setFormData({ ...formData, logoFile: file });\n }}\n className=\"block w-full text-sm text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-primary-blue/10 file:text-primary-blue hover:file:bg-primary-blue/20\"\n />\n <p className=\"text-xs text-gray-500 mt-1\">\n PNG, JPEG, or SVG. Recommended: 500x500px transparent background.\n </p>\n </div>\n </div>\n </div>\n\n {/* Account Security */}\n <div>\n <h3 className=\"text-lg font-semibold text-white mb-4 flex items-center gap-2\">\n <Shield className=\"w-5 h-5 text-performance-green\" />\n Account Security\n </h3>\n \n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n Password *\n </label>\n <Input\n type=\"password\"\n value={formData.password}\n onChange={(e) => setFormData({ ...formData, password: e.target.value })}\n placeholder=\"Min. 8 characters\"\n variant={errors.password ? 'error' : 'default'}\n errorMessage={errors.password}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-300 mb-2\">\n Confirm Password *\n </label>\n <Input\n type=\"password\"\n value={formData.confirmPassword}\n onChange={(e) => setFormData({ ...formData, confirmPassword: e.target.value })}\n placeholder=\"Confirm password\"\n variant={errors.confirmPassword ? 'error' : 'default'}\n errorMessage={errors.confirmPassword}\n />\n </div>\n </div>\n </div>\n\n {/* Legal Agreements */}\n <div className=\"space-y-3 pt-4 border-t border-charcoal-outline\">\n <label className=\"flex items-start gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.acceptTerms}\n onChange={(e) => setFormData({ ...formData, acceptTerms: e.target.checked })}\n className=\"mt-1 rounded border-charcoal-outline bg-iron-gray text-primary-blue focus:ring-primary-blue\"\n />\n <span className=\"text-sm text-gray-400\">\n I accept the{' '}\n <a href=\"/legal/terms\" className=\"text-primary-blue hover:underline\">Terms of Service</a>\n {' '}and{' '}\n <a href=\"/legal/privacy\" className=\"text-primary-blue hover:underline\">Privacy Policy</a>\n {' '}*\n </span>\n </label>\n {errors.acceptTerms && (\n <p className=\"text-sm text-warning-amber\">{errors.acceptTerms}</p>\n )}\n\n <label className=\"flex items-start gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.acceptVat}\n onChange={(e) => setFormData({ ...formData, acceptVat: e.target.checked })}\n className=\"mt-1 rounded border-charcoal-outline bg-iron-gray text-primary-blue focus:ring-primary-blue\"\n />\n <span className=\"text-sm text-gray-400\">\n {siteConfig.vat.notice} A {siteConfig.fees.platformFeePercent}% platform fee applies to all sponsorships. *\n </span>\n </label>\n {errors.acceptVat && (\n <p className=\"text-sm text-warning-amber\">{errors.acceptVat}</p>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-3 pt-4\">\n <Button\n type=\"submit\"\n variant=\"primary\"\n disabled={submitting}\n className=\"flex-1\"\n >\n {submitting ? 'Creating Account...' : 'Create Sponsor Account'}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => setMode('landing')}\n disabled={submitting}\n >\n Cancel\n </Button>\n </div>\n </form>\n\n <div className=\"mt-6 pt-6 border-t border-charcoal-outline text-center\">\n <p className=\"text-sm text-gray-400\">\n Already have an account?{' '}\n <button\n onClick={() => setMode('login')}\n className=\"text-primary-blue hover:underline\"\n >\n Sign in\n </button>\n </p>\n </div>\n </Card>\n </div>\n </div>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/teams/TeamsPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/teams/[id]/TeamDetailPageClient.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/teams/[id]/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/teams/leaderboard/TeamLeaderboardPageWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/teams/leaderboard/page.tsx","messages":[{"ruleId":"gridpilot-rules/rsc-no-unsafe-services","severity":2,"message":"Services import must be explicitly marked as server-safe - see apps/website/lib/contracts/view-models/ViewModel.ts","line":2,"column":1,"nodeType":"ImportDeclaration","messageId":"message","endLine":2,"endColumn":64},{"ruleId":"gridpilot-rules/rsc-no-view-models","severity":2,"message":"ViewModels or Presenters import forbidden in server code - see apps/website/lib/contracts/view-models/ViewModel.ts","line":7,"column":1,"nodeType":"ImportDeclaration","messageId":"message","endLine":7,"endColumn":79},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":15,"column":19,"nodeType":"NewExpression","messageId":"message","endLine":15,"endColumn":36},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":25,"column":37,"nodeType":"NewExpression","messageId":"message","endLine":25,"endColumn":64},{"ruleId":"gridpilot-rules/rsc-no-object-construction","severity":2,"message":"Object construction with new forbidden (use PageQueries) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":28,"column":13,"nodeType":"NewExpression","messageId":"message","endLine":28,"endColumn":43},{"ruleId":"gridpilot-rules/rsc-no-local-helpers","severity":2,"message":"Local helper functions forbidden (only assert*/invariant* allowed) - see apps/website/lib/contracts/view-models/ViewModel.ts","line":35,"column":9,"nodeType":"VariableDeclarator","messageId":"message","endLine":38,"endColumn":4}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageWrapper } from '@/components/shared/state/PageWrapper';\nimport { TeamService } from '@/lib/services/teams/TeamService';\nimport { Trophy } from 'lucide-react';\nimport { redirect } from 'next/navigation';\nimport { routes } from '@/lib/routing/RouteConfig';\nimport { TeamLeaderboardPageWrapper } from './TeamLeaderboardPageWrapper';\nimport { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';\n\n// ============================================================================\n// MAIN PAGE COMPONENT\n// ============================================================================\n\nexport default async function TeamLeaderboardPage() {\n // Manual wiring: create dependencies\n const service = new TeamService();\n\n // Fetch data through service\n const result = await service.getAllTeams();\n\n // Handle result\n let data = null;\n let error = null;\n \n if (result.isOk()) {\n data = result.unwrap().map(t => new TeamSummaryViewModel(t));\n } else {\n const domainError = result.getError();\n error = new Error(domainError.message);\n }\n\n const hasData = (data?.length ?? 0) > 0;\n\n // Handle loading state (should be fast since we're using async/await)\n const isLoading = false;\n const retry = () => {\n // In server components, we can't retry without a reload\n redirect(routes.team.detail('leaderboard'));\n };\n\n return (\n <PageWrapper\n data={hasData ? data : null}\n isLoading={isLoading}\n error={error}\n retry={retry}\n Template={TeamLeaderboardPageWrapper}\n loading={{ variant: 'full-screen', message: 'Loading team leaderboard...' }}\n errorConfig={{ variant: 'full-screen' }}\n empty={{\n icon: Trophy,\n title: 'No teams found',\n description: 'There are no teams in the system yet.',\n }}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/app/teams/page.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/AppWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/TeamRankingsFilter.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/achievements/AchievementGrid.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/admin/UserFilters.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/admin/UserStatsSummary.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/auth/AuthWorkflowMockup.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/auth/UserRolesPreview.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dashboard/DashboardHeroWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dashboard/QuickActions.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Pure component in components/. Consider moving to ui/ for better reusability.","line":1,"column":1,"nodeType":null,"messageId":"pureComponentInComponents"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { routes } from '@/lib/routing/RouteConfig';\nimport { Trophy, Users } from 'lucide-react';\nimport { Box } from '@/ui/Box';\nimport { Heading } from '@/ui/Heading';\nimport { QuickActionItem } from '@/ui/QuickActionItem';\n\nexport function QuickActions() {\n return (\n <Box>\n <Heading level={3} mb={4}>Quick Actions</Heading>\n <Box display=\"flex\" flexDirection=\"col\" gap={2}>\n <QuickActionItem\n href={routes.public.leagues}\n label=\"Browse Leagues\"\n icon={Users}\n iconVariant=\"blue\"\n />\n <QuickActionItem\n href={routes.public.leaderboards}\n label=\"View Leaderboards\"\n icon={Trophy}\n iconVariant=\"amber\"\n />\n </Box>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/DebugModeToggle.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":127,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":127,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3912,3915],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3912,3915],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":176,"column":31,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":176,"endColumn":34,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[5414,5417],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[5414,5417],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":203,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":203,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":223,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":223,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":242,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":242,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":252,"column":65,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":252,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":256,"column":65,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":256,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":260,"column":65,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":260,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":310,"column":58,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":310,"endColumn":86},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":320,"column":55,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":320,"endColumn":83},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":353,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":353,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12435,12438],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12435,12438],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":355,"column":37,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":355,"endColumn":40,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12563,12566],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12563,12566],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":356,"column":18,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":356,"endColumn":21,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12585,12588],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12585,12588],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":359,"column":16,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":359,"endColumn":19,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12647,12650],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12647,12650],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":360,"column":16,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":360,"endColumn":19,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12713,12716],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12713,12716],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":15,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport type { ApiRequestLogger } from '@/lib/infrastructure/ApiRequestLogger';\nimport { getGlobalApiLogger } from '@/lib/infrastructure/ApiRequestLogger';\nimport type { GlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';\nimport { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';\nimport { Bug, Shield, X } from 'lucide-react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { Box } from '@/ui/Box';\nimport { Button } from '@/ui/Button';\nimport { Icon } from '@/ui/Icon';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\n// Extend Window interface for debug globals\ndeclare global {\n interface Window {\n __GRIDPILOT_FETCH_LOGGED__?: boolean;\n __GRIDPILOT_GLOBAL_HANDLER__?: GlobalErrorHandler;\n __GRIDPILOT_API_LOGGER__?: ApiRequestLogger;\n __GRIDPILOT_REACT_ERRORS__?: Array<{ error: unknown; componentStack?: string }>;\n }\n}\n\ninterface DebugModeToggleProps {\n /**\n * Whether to show the toggle (auto-detected from environment)\n */\n show?: boolean;\n}\n\n/**\n * Debug Mode Toggle Component\n * Provides a floating interface to control debug features and view real-time metrics\n */\nexport function DebugModeToggle({ show }: DebugModeToggleProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [debugEnabled, setDebugEnabled] = useState(false);\n const [metrics, setMetrics] = useState({\n errors: 0,\n apiRequests: 0,\n apiFailures: 0,\n });\n\n const isDev = process.env.NODE_ENV === 'development';\n const shouldShow = show ?? isDev;\n\n const updateMetrics = useCallback(() => {\n if (!debugEnabled) return;\n\n const globalHandler = getGlobalErrorHandler();\n const apiLogger = getGlobalApiLogger();\n\n const errorStats = globalHandler.getStats();\n const apiStats = apiLogger.getStats();\n\n setMetrics({\n errors: errorStats.total,\n apiRequests: apiStats.total,\n apiFailures: apiStats.failed,\n });\n }, [debugEnabled]);\n\n const initializeDebugFeatures = useCallback(() => {\n const globalHandler = getGlobalErrorHandler();\n const apiLogger = getGlobalApiLogger();\n\n // Initialize global error handler\n globalHandler.initialize();\n\n // Override fetch with logging\n if (!window.__GRIDPILOT_FETCH_LOGGED__) {\n const loggedFetch = apiLogger.createLoggedFetch();\n window.fetch = loggedFetch as typeof fetch;\n window.__GRIDPILOT_FETCH_LOGGED__ = true;\n }\n\n // Expose to window for easy access\n window.__GRIDPILOT_GLOBAL_HANDLER__ = globalHandler;\n window.__GRIDPILOT_API_LOGGER__ = apiLogger;\n\n console.log('%c[DEBUG MODE] Enabled', 'color: #00ff88; font-weight: bold; font-size: 14px;');\n }, []);\n\n useEffect(() => {\n if (!shouldShow) return;\n\n // Load debug state from localStorage\n const saved = localStorage.getItem('gridpilot_debug_enabled');\n if (saved === 'true') {\n setDebugEnabled(true);\n initializeDebugFeatures();\n }\n\n // Update metrics every 2 seconds\n const interval = setInterval(updateMetrics, 2000);\n return () => clearInterval(interval);\n }, [shouldShow, initializeDebugFeatures, updateMetrics]);\n\n useEffect(() => {\n // Save debug state\n if (shouldShow) {\n localStorage.setItem('gridpilot_debug_enabled', debugEnabled.toString());\n }\n }, [debugEnabled, shouldShow]);\n\n const toggleDebug = () => {\n const newEnabled = !debugEnabled;\n setDebugEnabled(newEnabled);\n\n if (newEnabled) {\n initializeDebugFeatures();\n } else {\n // Disable debug features\n const globalHandler = getGlobalErrorHandler();\n globalHandler.destroy();\n\n console.log('%c[DEBUG MODE] Disabled', 'color: #ff4444; font-weight: bold; font-size: 14px;');\n }\n };\n\n const triggerTestError = () => {\n if (!debugEnabled) return;\n\n // Trigger a test API error\n const testError = new Error('This is a test error for debugging');\n (testError as any).type = 'TEST_ERROR';\n \n const globalHandler = getGlobalErrorHandler();\n globalHandler.report(testError, { test: true, timestamp: Date.now() });\n\n console.log('%c[TEST] Error triggered', 'color: #ffaa00; font-weight: bold;', testError);\n };\n\n const triggerTestApiCall = async () => {\n if (!debugEnabled) return;\n\n try {\n // This will fail and be logged\n await fetch('https://httpstat.us/500');\n } catch (error) {\n // Already logged by interceptor\n console.log('%c[TEST] API call completed', 'color: #00aaff; font-weight: bold;');\n }\n };\n\n const clearAllLogs = () => {\n const globalHandler = getGlobalErrorHandler();\n const apiLogger = getGlobalApiLogger();\n\n globalHandler.clearHistory();\n apiLogger.clearHistory();\n\n setMetrics({ errors: 0, apiRequests: 0, apiFailures: 0 });\n\n console.log('%c[DEBUG] All logs cleared', 'color: #00ff88; font-weight: bold;');\n };\n\n const copyDebugInfo = async () => {\n const globalHandler = getGlobalErrorHandler();\n const apiLogger = getGlobalApiLogger();\n\n const debugInfo = {\n timestamp: new Date().toISOString(),\n environment: {\n mode: process.env.NODE_ENV,\n version: process.env.NEXT_PUBLIC_APP_VERSION,\n },\n browser: {\n userAgent: navigator.userAgent,\n language: navigator.language,\n platform: navigator.platform,\n },\n errors: globalHandler.getStats(),\n api: apiLogger.getStats(),\n reactErrors: (window as any).__GRIDPILOT_REACT_ERRORS__ || [],\n };\n\n try {\n await navigator.clipboard.writeText(JSON.stringify(debugInfo, null, 2));\n console.log('%c[DEBUG] Debug info copied to clipboard', 'color: #00ff88; font-weight: bold;');\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n };\n\n if (!shouldShow) {\n return null;\n }\n\n return (\n <Box position=\"fixed\" bottom=\"4\" left=\"4\" zIndex={50}>\n {/* Main Toggle Button */}\n {!isOpen && (\n <Box\n as=\"button\"\n onClick={() => setIsOpen(true)}\n p={3}\n rounded=\"full\"\n shadow=\"lg\"\n bg={debugEnabled ? 'bg-green-600' : 'bg-iron-gray'}\n color=\"text-white\"\n className=\"transition-all hover:scale-110\"\n title={debugEnabled ? 'Debug Mode Active' : 'Enable Debug Mode'}\n >\n <Icon icon={Bug} size={5} />\n </Box>\n )}\n\n {/* Debug Panel */}\n {isOpen && (\n <Box width=\"80\" bg=\"bg-deep-graphite\" border={true} borderColor=\"border-charcoal-outline\" rounded=\"xl\" shadow=\"2xl\" overflow=\"hidden\">\n {/* Header */}\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"between\" px={3} py={2} bg=\"bg-iron-gray/50\" borderBottom={true} borderColor=\"border-charcoal-outline\">\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Icon icon={Bug} size={4} color=\"text-green-400\" />\n <Text size=\"sm\" weight=\"semibold\" color=\"text-white\">Debug Control</Text>\n </Stack>\n <Box\n as=\"button\"\n onClick={() => setIsOpen(false)}\n p={1}\n className=\"hover:bg-charcoal-outline rounded\"\n >\n <Icon icon={X} size={4} color=\"text-gray-400\" />\n </Box>\n </Box>\n\n {/* Content */}\n <Box p={3}>\n <Stack gap={3}>\n {/* Debug Toggle */}\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"between\" bg=\"bg-iron-gray/30\" p={2} rounded=\"md\" border={true} borderColor=\"border-charcoal-outline\">\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Icon icon={Shield} size={4} color={debugEnabled ? 'text-green-400' : 'text-gray-500'} />\n <Text size=\"sm\" weight=\"medium\">Debug Mode</Text>\n </Stack>\n <Button\n onClick={toggleDebug}\n size=\"sm\"\n variant={debugEnabled ? 'primary' : 'secondary'}\n className={debugEnabled ? 'bg-green-600 hover:bg-green-700' : ''}\n >\n {debugEnabled ? 'ON' : 'OFF'}\n </Button>\n </Box>\n\n {/* Metrics */}\n {debugEnabled && (\n <Box display=\"grid\" gridCols={3} gap={2}>\n <Box bg=\"bg-iron-gray\" border={true} borderColor=\"border-charcoal-outline\" rounded=\"md\" p={2} textAlign=\"center\">\n <Text size=\"xs\" color=\"text-gray-500\" block style={{ fontSize: '10px' }}>Errors</Text>\n <Text size=\"lg\" weight=\"bold\" color=\"text-red-400\" block>{metrics.errors}</Text>\n </Box>\n <Box bg=\"bg-iron-gray\" border={true} borderColor=\"border-charcoal-outline\" rounded=\"md\" p={2} textAlign=\"center\">\n <Text size=\"xs\" color=\"text-gray-500\" block style={{ fontSize: '10px' }}>API</Text>\n <Text size=\"lg\" weight=\"bold\" color=\"text-blue-400\" block>{metrics.apiRequests}</Text>\n </Box>\n <Box bg=\"bg-iron-gray\" border={true} borderColor=\"border-charcoal-outline\" rounded=\"md\" p={2} textAlign=\"center\">\n <Text size=\"xs\" color=\"text-gray-500\" block style={{ fontSize: '10px' }}>Failures</Text>\n <Text size=\"lg\" weight=\"bold\" color=\"text-yellow-400\" block>{metrics.apiFailures}</Text>\n </Box>\n </Box>\n )}\n\n {/* Actions */}\n {debugEnabled && (\n <Stack gap={2}>\n <Text size=\"xs\" weight=\"semibold\" color=\"text-gray-400\">Test Actions</Text>\n <Box display=\"grid\" gridCols={2} gap={2}>\n <Button\n onClick={triggerTestError}\n variant=\"danger\"\n size=\"sm\"\n >\n Test Error\n </Button>\n <Button\n onClick={triggerTestApiCall}\n size=\"sm\"\n >\n Test API\n </Button>\n </Box>\n\n <Text size=\"xs\" weight=\"semibold\" color=\"text-gray-400\" mt={2}>Utilities</Text>\n <Box display=\"grid\" gridCols={2} gap={2}>\n <Button\n onClick={copyDebugInfo}\n variant=\"secondary\"\n size=\"sm\"\n >\n Copy Info\n </Button>\n <Button\n onClick={clearAllLogs}\n variant=\"secondary\"\n size=\"sm\"\n >\n Clear Logs\n </Button>\n </Box>\n </Stack>\n )}\n\n {/* Quick Links */}\n {debugEnabled && (\n <Stack gap={1}>\n <Text size=\"xs\" weight=\"semibold\" color=\"text-gray-400\">Quick Access</Text>\n <Box color=\"text-gray-500\" font=\"mono\" style={{ fontSize: '10px' }}>\n <Text block>• window.__GRIDPILOT_GLOBAL_HANDLER__</Text>\n <Text block>• window.__GRIDPILOT_API_LOGGER__</Text>\n <Text block>• window.__GRIDPILOT_REACT_ERRORS__</Text>\n </Box>\n </Stack>\n )}\n\n {/* Status */}\n <Box textAlign=\"center\" pt={2} borderTop={true} borderColor=\"border-charcoal-outline\">\n <Text size=\"xs\" color=\"text-gray-500\" style={{ fontSize: '10px' }}>\n {debugEnabled ? 'Debug features active' : 'Debug mode disabled'}\n {isDev && ' • Development Environment'}\n </Text>\n </Box>\n </Stack>\n </Box>\n </Box>\n )}\n </Box>\n );\n}\n\n/**\n * Hook for programmatic debug control\n */\nexport function useDebugMode() {\n const [debugEnabled, setDebugEnabled] = useState(false);\n\n useEffect(() => {\n const saved = localStorage.getItem('gridpilot_debug_enabled');\n setDebugEnabled(saved === 'true');\n }, []);\n\n const enable = useCallback(() => {\n setDebugEnabled(true);\n localStorage.setItem('gridpilot_debug_enabled', 'true');\n \n // Initialize debug features\n const globalHandler = getGlobalErrorHandler();\n globalHandler.initialize();\n\n const apiLogger = getGlobalApiLogger();\n if (!(window as any).__GRIDPILOT_FETCH_LOGGED__) {\n const loggedFetch = apiLogger.createLoggedFetch();\n window.fetch = loggedFetch as any;\n (window as any).__GRIDPILOT_FETCH_LOGGED__ = true;\n }\n\n (window as any).__GRIDPILOT_GLOBAL_HANDLER__ = globalHandler;\n (window as any).__GRIDPILOT_API_LOGGER__ = apiLogger;\n }, []);\n\n const disable = useCallback(() => {\n setDebugEnabled(false);\n localStorage.setItem('gridpilot_debug_enabled', 'false');\n \n const globalHandler = getGlobalErrorHandler();\n globalHandler.destroy();\n }, []);\n\n const toggle = useCallback(() => {\n if (debugEnabled) {\n disable();\n } else {\n enable();\n }\n }, [debugEnabled, enable, disable]);\n\n return {\n enabled: debugEnabled,\n enable,\n disable,\n toggle,\n };\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/DevToolbar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/sections/APIStatusSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/sections/NotificationSendSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/sections/NotificationTypeSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/sections/ReplaySection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/sections/UrgencySection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/dev/types.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/CreateDriverForm.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/DriverCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/DriverEntryRow.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":55,"column":9,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":55,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":89,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":89,"endColumn":43}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';\nimport { Zap } from 'lucide-react';\nimport { Badge } from '@/ui/Badge';\nimport { Box } from '@/ui/Box';\nimport { Icon } from '@/ui/Icon';\nimport { Image } from '@/ui/Image';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\ninterface DriverEntryRowProps {\n index: number;\n name: string;\n avatarUrl: string;\n country: string;\n rating?: number | null;\n isCurrentUser: boolean;\n onClick: () => void;\n}\n\nexport function DriverEntryRow({\n index,\n name,\n avatarUrl,\n country,\n rating,\n isCurrentUser,\n onClick,\n}: DriverEntryRowProps) {\n return (\n <Box\n onClick={onClick}\n display=\"flex\"\n alignItems=\"center\"\n gap={3}\n p={3}\n rounded=\"xl\"\n cursor=\"pointer\"\n transition\n bg={isCurrentUser ? 'bg-primary-blue/10' : 'transparent'}\n border\n borderColor={isCurrentUser ? 'border-primary-blue/30' : 'transparent'}\n hoverBorderColor={isCurrentUser ? 'primary-blue/40' : 'charcoal-outline/20'}\n >\n <Box \n display=\"flex\" \n alignItems=\"center\" \n justifyContent=\"center\" \n w=\"8\" \n h=\"8\" \n rounded=\"lg\" \n bg=\"bg-iron-gray\" \n color=\"text-gray-500\"\n style={{ fontWeight: 'bold', fontSize: '0.875rem' }}\n >\n {index + 1}\n </Box>\n\n <Box position=\"relative\" flexShrink={0}>\n <Box \n w=\"10\" \n h=\"10\" \n rounded=\"full\" \n overflow=\"hidden\" \n border={isCurrentUser} \n borderColor={isCurrentUser ? 'border-primary-blue' : ''}\n >\n <Image \n src={avatarUrl} \n alt={name} \n width={40} \n height={40} \n objectFit=\"cover\" \n fill\n />\n </Box>\n <Box \n position=\"absolute\" \n bottom=\"-0.5\" \n right=\"-0.5\" \n w=\"5\" \n h=\"5\" \n rounded=\"full\" \n bg=\"bg-deep-graphite\" \n display=\"flex\" \n alignItems=\"center\" \n justifyContent=\"center\" \n style={{ fontSize: '0.625rem' }}\n >\n {CountryFlagDisplay.fromCountryCode(country).toString()}\n </Box>\n </Box>\n\n <Box flexGrow={1} minWidth=\"0\">\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Text \n weight=\"semibold\" \n size=\"sm\" \n color={isCurrentUser ? 'text-primary-blue' : 'text-white'} \n truncate\n >\n {name}\n </Text>\n {isCurrentUser && <Badge variant=\"primary\">You</Badge>}\n </Stack>\n <Text size=\"xs\" color=\"text-gray-500\">{country}</Text>\n </Box>\n\n {rating != null && (\n <Badge variant=\"warning\">\n <Icon icon={Zap} size={3} />\n {rating}\n </Badge>\n )}\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/DriverIdentity.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/DriverProfile.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/DriverRankings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/DriverSummaryPillWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/FeaturedDriverCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/ProfileHeader.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":53,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":53,"endColumn":53}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport type { DriverViewModel } from '@/lib/view-models/DriverViewModel';\nimport { Badge } from '@/ui/Badge';\nimport { Box } from '@/ui/Box';\nimport { Button } from '@/ui/Button';\nimport { CountryFlag } from '@/ui/CountryFlag';\nimport { DriverRatingPill } from '@/ui/DriverRatingPill';\nimport { Heading } from '@/ui/Heading';\nimport { Image } from '@/ui/Image';\nimport { PlaceholderImage } from '@/ui/PlaceholderImage';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\ninterface ProfileHeaderProps {\n driver: DriverViewModel;\n rating?: number | null;\n rank?: number | null;\n isOwnProfile?: boolean;\n onEditClick?: () => void;\n teamName?: string | null;\n teamTag?: string | null;\n}\n\nexport function ProfileHeader({\n driver,\n rating,\n rank,\n isOwnProfile = false,\n onEditClick,\n teamName,\n teamTag,\n}: ProfileHeaderProps) {\n return (\n <Box display=\"flex\" alignItems=\"start\" justifyContent=\"between\">\n <Box display=\"flex\" alignItems=\"start\" gap={4}>\n <Box \n w=\"20\" \n h=\"20\" \n rounded=\"full\" \n bg=\"bg-gradient-to-br from-primary-blue to-purple-600\" \n overflow=\"hidden\" \n display=\"flex\" \n alignItems=\"center\" \n justifyContent=\"center\"\n >\n {driver.avatarUrl ? (\n <Image\n src={driver.avatarUrl}\n alt={driver.name}\n width={80}\n height={80}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <PlaceholderImage size={80} />\n )}\n </Box>\n \n <Box>\n <Box display=\"flex\" alignItems=\"center\" gap={3} mb={2}>\n <Heading level={1}>{driver.name}</Heading>\n {driver.country && <CountryFlag countryCode={driver.country} size=\"lg\" />}\n {teamTag && (\n <Badge variant=\"primary\">\n {teamTag}\n </Badge>\n )}\n </Box>\n \n <Box display=\"flex\" alignItems=\"center\" gap={4}>\n <Text size=\"sm\" color=\"text-gray-400\">iRacing ID: {driver.iracingId}</Text>\n {teamName && (\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Text size=\"sm\" color=\"text-gray-400\">•</Text>\n <Text size=\"sm\" color=\"text-primary-blue\">\n {teamTag ? `[${teamTag}] ${teamName}` : teamName}\n </Text>\n </Stack>\n )}\n </Box>\n\n {(typeof rating === 'number' || typeof rank === 'number') && (\n <Box mt={2}>\n <DriverRatingPill rating={rating ?? null} rank={rank ?? null} />\n </Box>\n )}\n </Box>\n </Box>\n\n {isOwnProfile && (\n <Button variant=\"secondary\" onClick={onEditClick}>\n Edit Profile\n </Button>\n )}\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/ProfileHero.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":58,"column":63,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":58,"endColumn":200},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":61,"column":14,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":61,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":62,"column":16,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":62,"endColumn":220},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":63,"column":18,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":63,"endColumn":132},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":69,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":69,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":76,"column":14,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":76,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":88,"column":67,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":88,"endColumn":215},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":90,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":90,"endColumn":86},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":95,"column":67,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":95,"endColumn":215},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":97,"column":29,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":97,"endColumn":88},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":98,"column":53,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":98,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":107,"column":62,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":107,"endColumn":112},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":22,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":109,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":113,"column":25,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":113,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":123,"column":22,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":123,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":135,"column":29,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":135,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":144,"column":28,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":144,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":146,"column":51,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":146,"endColumn":84},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":157,"column":71,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":157,"endColumn":273},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":158,"column":29,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":158,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":160,"column":37,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":160,"endColumn":98}],"suppressedMessages":[],"errorCount":21,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { mediaConfig } from '@/lib/config/mediaConfig';\nimport { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';\nimport { Box } from '@/ui/Box';\nimport { Button } from '@/ui/Button';\nimport { Heading } from '@/ui/Heading';\nimport { Image } from '@/ui/Image';\nimport { Link } from '@/ui/Link';\nimport { Stack } from '@/ui/Stack';\nimport { Surface } from '@/ui/Surface';\nimport { Text } from '@/ui/Text';\nimport { Calendar, Clock, ExternalLink, Globe, Star, Trophy, UserPlus } from 'lucide-react';\n\ninterface ProfileHeroProps {\n driver: {\n name: string;\n avatarUrl?: string;\n country: string;\n iracingId: number;\n joinedAt: string | Date;\n };\n stats: {\n rating: number;\n } | null;\n globalRank: number;\n timezone: string;\n socialHandles: {\n platform: string;\n handle: string;\n url: string;\n }[];\n onAddFriend: () => void;\n friendRequestSent: boolean;\n}\n\nfunction getSocialIcon(platform: string) {\n const { Twitter, Youtube, Twitch, MessageCircle } = require('lucide-react');\n switch (platform) {\n case 'twitter': return Twitter;\n case 'youtube': return Youtube;\n case 'twitch': return Twitch;\n case 'discord': return MessageCircle;\n default: return Globe;\n }\n}\n\nexport function ProfileHero({\n driver,\n stats,\n globalRank,\n timezone,\n socialHandles,\n onAddFriend,\n friendRequestSent,\n}: ProfileHeroProps) {\n return (\n <Surface variant=\"muted\" rounded=\"2xl\" border padding={6} style={{ background: 'linear-gradient(to bottom right, rgba(38, 38, 38, 0.8), rgba(38, 38, 38, 0.6), #0f1115)', borderColor: '#262626' }}>\n <Stack direction=\"row\" align=\"start\" gap={6} wrap>\n {/* Avatar */}\n <Box style={{ position: 'relative' }}>\n <Box style={{ width: '7rem', height: '7rem', borderRadius: '1rem', background: 'linear-gradient(to bottom right, #3b82f6, #9333ea)', padding: '0.25rem', boxShadow: '0 20px 25px -5px rgba(59, 130, 246, 0.2)' }}>\n <Box style={{ width: '100%', height: '100%', borderRadius: '0.75rem', overflow: 'hidden', backgroundColor: '#262626' }}>\n <Image\n src={driver.avatarUrl || mediaConfig.avatars.defaultFallback}\n alt={driver.name}\n width={144}\n height={144}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n </Box>\n </Box>\n </Box>\n\n {/* Driver Info */}\n <Box style={{ flex: 1, minWidth: 0 }}>\n <Stack direction=\"row\" align=\"center\" gap={3} wrap mb={2}>\n <Heading level={1}>{driver.name}</Heading>\n <Text size=\"4xl\" aria-label={`Country: ${driver.country}`}>\n {CountryFlagDisplay.fromCountryCode(driver.country).toString()}\n </Text>\n </Stack>\n\n {/* Rating and Rank */}\n <Stack direction=\"row\" align=\"center\" gap={4} wrap mb={4}>\n {stats && (\n <>\n <Surface variant=\"muted\" rounded=\"lg\" padding={1} style={{ backgroundColor: 'rgba(59, 130, 246, 0.1)', border: '1px solid rgba(59, 130, 246, 0.3)', paddingLeft: '0.75rem', paddingRight: '0.75rem' }}>\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Star style={{ width: '1rem', height: '1rem', color: '#3b82f6' }} />\n <Text font=\"mono\" weight=\"bold\" color=\"text-primary-blue\">{stats.rating}</Text>\n <Text size=\"xs\" color=\"text-gray-400\">Rating</Text>\n </Stack>\n </Surface>\n <Surface variant=\"muted\" rounded=\"lg\" padding={1} style={{ backgroundColor: 'rgba(250, 204, 21, 0.1)', border: '1px solid rgba(250, 204, 21, 0.3)', paddingLeft: '0.75rem', paddingRight: '0.75rem' }}>\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Trophy style={{ width: '1rem', height: '1rem', color: '#facc15' }} />\n <Text font=\"mono\" weight=\"bold\" style={{ color: '#facc15' }}>#{globalRank}</Text>\n <Text size=\"xs\" color=\"text-gray-400\">Global</Text>\n </Stack>\n </Surface>\n </>\n )}\n </Stack>\n\n {/* Meta info */}\n <Stack direction=\"row\" align=\"center\" gap={4} wrap style={{ fontSize: '0.875rem', color: '#9ca3af' }}>\n <Stack direction=\"row\" align=\"center\" gap={1.5}>\n <Globe style={{ width: '1rem', height: '1rem' }} />\n <Text size=\"sm\">iRacing: {driver.iracingId}</Text>\n </Stack>\n <Stack direction=\"row\" align=\"center\" gap={1.5}>\n <Calendar style={{ width: '1rem', height: '1rem' }} />\n <Text size=\"sm\">\n Joined{' '}\n {new Date(driver.joinedAt).toLocaleDateString('en-US', {\n month: 'short',\n year: 'numeric',\n })}\n </Text>\n </Stack>\n <Stack direction=\"row\" align=\"center\" gap={1.5}>\n <Clock style={{ width: '1rem', height: '1rem' }} />\n <Text size=\"sm\">{timezone}</Text>\n </Stack>\n </Stack>\n </Box>\n\n {/* Action Buttons */}\n <Box>\n <Button\n variant=\"primary\"\n onClick={onAddFriend}\n disabled={friendRequestSent}\n icon={<UserPlus style={{ width: '1rem', height: '1rem' }} />}\n >\n {friendRequestSent ? 'Request Sent' : 'Add Friend'}\n </Button>\n </Box>\n </Stack>\n\n {/* Social Handles */}\n {socialHandles.length > 0 && (\n <Box mt={6} pt={6} style={{ borderTop: '1px solid rgba(38, 38, 38, 0.5)' }}>\n <Stack direction=\"row\" align=\"center\" gap={2} wrap>\n <Text size=\"sm\" color=\"text-gray-500\" style={{ marginRight: '0.5rem' }}>Connect:</Text>\n {socialHandles.map((social) => {\n const Icon = getSocialIcon(social.platform);\n return (\n <Box key={social.platform}>\n <Link\n href={social.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n variant=\"ghost\"\n >\n <Surface variant=\"muted\" rounded=\"lg\" padding={1} style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', paddingLeft: '0.75rem', paddingRight: '0.75rem', backgroundColor: 'rgba(38, 38, 38, 0.5)', border: '1px solid #262626', color: '#9ca3af' }}>\n <Icon style={{ width: '1rem', height: '1rem' }} />\n <Text size=\"sm\">{social.handle}</Text>\n <ExternalLink style={{ width: '0.75rem', height: '0.75rem', opacity: 0.5 }} />\n </Surface>\n </Link>\n </Box>\n );\n })}\n </Stack>\n </Box>\n )}\n </Surface>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/ProfileRaceHistory.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/ProfileSettings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/drivers/ProfileStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/ApiErrorBoundary.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/DevErrorPanel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/EnhancedErrorBoundary.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/EnhancedFormError.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/ErrorAnalyticsDashboard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/ErrorDisplay.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/errors/NotificationIntegration.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/ActivityFeed.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/ActivityFeedItem.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":26,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":26,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":27,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":27,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":40,"column":12,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":40,"endColumn":44}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { ReactNode } from 'react';\nimport { Box } from '@/ui/Box';\nimport { Surface } from '@/ui/Surface';\nimport { Text } from '@/ui/Text';\n\ninterface ActivityFeedItemProps {\n icon: ReactNode;\n content: ReactNode;\n timestamp: string;\n}\n\nexport function ActivityFeedItem({\n icon,\n content,\n timestamp,\n}: ActivityFeedItemProps) {\n return (\n <Box\n display=\"flex\"\n alignItems=\"start\"\n gap={3}\n py={3}\n borderBottom\n style={{ borderColor: 'rgba(38, 38, 38, 0.3)' }}\n className=\"last:border-0\"\n >\n <Surface\n variant=\"muted\"\n w=\"8\"\n h=\"8\"\n rounded=\"full\"\n display=\"flex\"\n center\n flexShrink={0}\n >\n {icon}\n </Surface>\n <Box style={{ flex: 1, minWidth: 0 }}>\n <Text size=\"sm\" leading=\"relaxed\" block>\n {content}\n </Text>\n <Text size=\"xs\" color=\"text-gray-500\" mt={1} block>\n {timestamp}\n </Text>\n </Box>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/ActivityFeedList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/FeedItemCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/FeedLayout.tsx","messages":[{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":44,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":64,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":44,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":44,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":44,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":44,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":45,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":63,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":45,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":45,"endColumn":67},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":45,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":45,"endColumn":66},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":46,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":58,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":46,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":46,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":46,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":46,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":47,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":54,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":47,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":47,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":47,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":47,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":48,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":48,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":49,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":49,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":49,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":49,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":49,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":49,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":50,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":52,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":50,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":50,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":50,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":50,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":55,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":55,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":59,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":62,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":59,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":59,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":59,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":59,"endColumn":37}],"suppressedMessages":[],"errorCount":23,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Card } from '@/ui/Card';\nimport { FeedList } from '@/components/feed/FeedList';\nimport { UpcomingRacesSidebar } from '@/components/races/UpcomingRacesSidebar';\nimport { LatestResultsSidebar } from '@/components/races/LatestResultsSidebar';\n\ninterface FeedItemData {\n id: string;\n type: string;\n headline: string;\n body?: string;\n timestamp: string;\n formattedTime: string;\n ctaHref?: string;\n ctaLabel?: string;\n}\n\ntype FeedUpcomingRace = {\n id: string;\n track: string;\n car: string;\n scheduledAt: string | Date;\n};\n\ntype FeedLatestResult = {\n raceId: string;\n track: string;\n car: string;\n winnerName: string;\n scheduledAt: string | Date;\n};\n\ninterface FeedLayoutProps {\n feedItems: FeedItemData[];\n upcomingRaces: FeedUpcomingRace[];\n latestResults: FeedLatestResult[];\n}\n\nexport function FeedLayout({\n feedItems,\n upcomingRaces,\n latestResults\n}: FeedLayoutProps) {\n return (\n <section className=\"max-w-7xl mx-auto mt-16 mb-20\">\n <div className=\"flex flex-col gap-8 lg:grid lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <div className=\"flex items-baseline justify-between gap-4\">\n <div>\n <h2 className=\"text-2xl font-semibold text-white\">Activity</h2>\n <p className=\"text-sm text-gray-400\">\n See what your friends and leagues are doing right now.\n </p>\n </div>\n </div>\n <Card className=\"bg-iron-gray/80\">\n <FeedList items={feedItems} />\n </Card>\n </div>\n <aside className=\"space-y-6\">\n <UpcomingRacesSidebar races={upcomingRaces} />\n <LatestResultsSidebar results={latestResults} />\n </aside>\n </div>\n </section>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/FeedList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/feed/RecentActivity.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/AlternatingSection.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":98,"column":107,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":98,"endColumn":357}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { useParallax } from \"@/hooks/useScrollProgress\";\nimport { Box } from '@/ui/Box';\nimport { Container } from '@/ui/Container';\nimport { Heading } from '@/ui/Heading';\nimport { Text } from '@/ui/Text';\nimport { useRef } from 'react';\n\ninterface AlternatingSectionProps {\n heading: string;\n description: string | React.ReactNode;\n mockup: React.ReactNode;\n layout: 'text-left' | 'text-right';\n backgroundImage?: string;\n backgroundVideo?: string;\n}\n\nexport function AlternatingSection({\n heading,\n description,\n mockup,\n layout,\n backgroundImage,\n backgroundVideo\n}: AlternatingSectionProps) {\n const sectionRef = useRef<HTMLElement>(null);\n \n const bgParallax = useParallax(sectionRef, 0.2);\n\n return (\n <Box \n as=\"section\" \n ref={sectionRef} \n position=\"relative\" \n overflow=\"hidden\" \n bg=\"bg-deep-graphite\" \n px={{ base: 'calc(1rem+var(--sal))', lg: 8 }}\n py={{ base: 20, sm: 24, md: 32 }}\n >\n {backgroundVideo && (\n <>\n <Box\n as=\"video\"\n autoPlay\n loop\n muted\n playsInline\n position=\"absolute\"\n inset=\"0\"\n fullWidth\n fullHeight\n objectFit=\"cover\"\n opacity={0.2}\n maskImage=\"radial-gradient(ellipse at center, black 0%, rgba(0,0,0,0.8) 40%, transparent 70%)\"\n webkitMaskImage=\"radial-gradient(ellipse at center, black 0%, rgba(0,0,0,0.8) 40%, transparent 70%)\"\n >\n <Box as=\"source\" src={backgroundVideo} type=\"video/mp4\" />\n </Box>\n {/* Racing red accent for sections with background videos */}\n <Box position=\"absolute\" top=\"0\" left=\"0\" right=\"0\" h=\"px\" bg=\"linear-gradient(to right, transparent, rgba(239, 68, 68, 0.3), transparent)\" />\n </>\n )}\n {backgroundImage && !backgroundVideo && (\n <>\n <Box\n position=\"absolute\"\n inset=\"0\"\n bg={`url(${backgroundImage})`}\n backgroundSize=\"cover\"\n backgroundPosition=\"center\"\n maskImage=\"radial-gradient(ellipse at center, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.1) 40%, transparent 70%)\"\n webkitMaskImage=\"radial-gradient(ellipse at center, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.1) 40%, transparent 70%)\"\n transform={`translateY(${bgParallax * 0.3}px)`}\n />\n {/* Racing red accent for sections with background images */}\n <Box position=\"absolute\" top=\"0\" left=\"0\" right=\"0\" h=\"px\" bg=\"linear-gradient(to right, transparent, rgba(239, 68, 68, 0.3), transparent)\" />\n </>\n )}\n \n {/* Carbon fiber texture on sections without images or videos */}\n {!backgroundImage && !backgroundVideo && (\n <Box position=\"absolute\" inset=\"0\" opacity={0.3} bg=\"carbon-fiber\" />\n )}\n \n {/* Checkered pattern accent */}\n <Box position=\"absolute\" inset=\"0\" opacity={0.1} bg=\"checkered-pattern\" />\n \n <Container size=\"lg\" position=\"relative\" zIndex={10}>\n <Box display=\"grid\" gridCols={{ base: 1, lg: 2 }} gap={{ base: 8, md: 12, lg: 16 }} alignItems=\"center\">\n {/* Text Content - Always first on mobile, respects layout on desktop */}\n <Box\n display=\"flex\"\n flexDirection=\"column\"\n gap={{ base: 4, md: 6, lg: 8 }}\n order={{ lg: layout === 'text-right' ? 2 : 1 }}\n >\n <Heading level={2} fontSize={{ base: 'xl', md: '2xl', lg: '3xl', xl: '4xl' }} weight=\"medium\" style={{ background: 'linear-gradient(to right, #dc2626, #ffffff, #2563eb)', backgroundClip: 'text', WebkitBackgroundClip: 'text', color: 'transparent', filter: 'drop-shadow(0 0 15px rgba(220,0,0,0.4))', WebkitTextStroke: '0.5px rgba(220,0,0,0.2)' }}>\n {heading}\n </Heading>\n <Box display=\"flex\" flexDirection=\"column\" gap={{ base: 3, md: 5 }}>\n <Text size={{ base: 'sm', md: 'base', lg: 'lg' }} color=\"text-slate-400\" weight=\"light\" leading=\"relaxed\">\n {description}\n </Text>\n </Box>\n </Box>\n\n {/* Mockup - Always second on mobile, respects layout on desktop */}\n <Box\n position=\"relative\"\n order={{ lg: layout === 'text-right' ? 1 : 2 }}\n group\n >\n <Box \n fullWidth \n minHeight={{ base: '240px', md: '380px', lg: '440px' }} \n transition \n hoverScale\n maskImage={`linear-gradient(to ${layout === 'text-left' ? 'right' : 'left'}, white 50%, rgba(255,255,255,0.8) 70%, rgba(255,255,255,0.4) 85%, transparent 100%)`}\n webkitMaskImage={`linear-gradient(to ${layout === 'text-left' ? 'right' : 'left'}, white 50%, rgba(255,255,255,0.8) 70%, rgba(255,255,255,0.4) 85%, transparent 100%)`}\n >\n {mockup}\n </Box>\n </Box>\n </Box>\n </Container>\n </Box>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/BenefitCard.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":47,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":47,"endColumn":173},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":48,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":48,"endColumn":135},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":62,"column":36,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":62,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":67,"column":51,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":67,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":87,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":87,"endColumn":149}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { LucideIcon } from 'lucide-react';\nimport { useEffect, useState } from 'react';\nimport { Box } from '@/ui/Box';\nimport { Heading } from '@/ui/Heading';\nimport { Icon } from '@/ui/Icon';\nimport { Surface } from '@/ui/Surface';\nimport { Text } from '@/ui/Text';\n\ninterface BenefitCardProps {\n icon: LucideIcon;\n title: string;\n description: string;\n stats?: {\n value: string;\n label: string;\n };\n variant?: 'default' | 'highlight';\n delay?: number;\n}\n\nexport function BenefitCard({\n icon,\n title,\n description,\n stats,\n variant = 'default',\n delay = 0,\n}: BenefitCardProps) {\n const shouldReduceMotion = useReducedMotion();\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n const isHighlight = variant === 'highlight';\n\n const cardContent = (\n <Surface\n variant=\"muted\"\n rounded=\"xl\"\n border={true}\n padding={6}\n className={`relative h-full transition-all duration-300 group ${isHighlight ? 'border-primary-blue/30' : 'border-charcoal-outline hover:border-charcoal-outline/80'}`}\n style={isHighlight ? { background: 'linear-gradient(to bottom right, rgba(25, 140, 255, 0.1), rgba(25, 140, 255, 0.05))' } : {}}\n >\n {/* Icon */}\n <Box \n width=\"12\" \n height=\"12\" \n rounded=\"xl\" \n display=\"flex\" \n center \n mb={4}\n bg={isHighlight ? 'bg-primary-blue/20' : 'bg-iron-gray'}\n border={!isHighlight}\n borderColor=\"border-charcoal-outline\"\n >\n <Icon icon={icon} size={6} className={isHighlight ? 'text-primary-blue' : 'text-gray-400'} />\n </Box>\n\n {/* Content */}\n <Heading level={3} mb={2}>{title}</Heading>\n <Text size=\"sm\" color=\"text-gray-400\" block style={{ lineHeight: 1.625 }}>{description}</Text>\n\n {/* Stats */}\n {stats && (\n <Box mt={4} pt={4} borderTop={true} borderColor=\"border-charcoal-outline/50\">\n <Box display=\"flex\" alignItems=\"baseline\" gap={2}>\n <Text size=\"2xl\" weight=\"bold\" color={isHighlight ? 'text-primary-blue' : 'text-white'}>\n {stats.value}\n </Text>\n <Text size=\"sm\" color=\"text-gray-500\">{stats.label}</Text>\n </Box>\n </Box>\n )}\n\n {/* Highlight Glow Effect */}\n {isHighlight && (\n <Box \n position=\"absolute\" \n inset=\"0\" \n rounded=\"xl\" \n className=\"bg-gradient-to-br from-primary-blue/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none\" \n />\n )}\n </Surface>\n );\n\n if (!isMounted || shouldReduceMotion) {\n return <Box fullHeight>{cardContent}</Box>;\n }\n\n return (\n <Box\n as={motion.div}\n fullHeight\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.4, delay }}\n whileHover={{ y: -4, transition: { duration: 0.2 } }}\n >\n {cardContent}\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/FAQ.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/FeatureGrid.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":68,"column":46,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":68,"endColumn":296},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":86,"column":50,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":86,"endColumn":298}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { Section } from '@/ui/Section';\nimport { Container } from '@/ui/Container';\nimport { Heading } from '@/ui/Heading';\nimport { MockupStack } from '@/components/mockups/MockupStack';\nimport { Box } from '@/ui/Box';\nimport { Text } from '@/ui/Text';\nimport { Stack } from '@/ui/Stack';\nimport { LeagueHomeMockup } from '@/components/mockups/LeagueHomeMockup';\nimport { StandingsTableMockup } from '@/components/mockups/StandingsTableMockup';\nimport { TeamCompetitionMockup } from '@/components/mockups/TeamCompetitionMockup';\nimport { ProtestWorkflowMockup } from '@/components/mockups/ProtestWorkflowMockup';\nimport { LeagueDiscoveryMockup } from '@/components/mockups/LeagueDiscoveryMockup';\nimport { DriverProfileMockup } from '@/components/mockups/DriverProfileMockup';\n\nconst features = [\n {\n title: \"A Real Home for Your League\",\n description: \"Stop juggling Discord, spreadsheets, and iRacing admin panels. GridPilot brings everything into one dedicated platform built specifically for league racing.\",\n MockupComponent: LeagueHomeMockup\n },\n {\n title: \"Automatic Results & Standings\",\n description: \"Race happens. Results appear. Standings update. No manual data entry, no spreadsheet formulas, no waiting for someone to publish.\",\n MockupComponent: StandingsTableMockup\n },\n {\n title: \"Real Team Racing\",\n description: \"Constructors' championships that actually matter. Driver lineups. Team strategies. Multi-class racing done right.\",\n MockupComponent: TeamCompetitionMockup\n },\n {\n title: \"Clean Protests & Penalties\",\n description: \"Structured incident reporting with video clip references. Steward review workflows. Transparent penalty application. Professional race control.\",\n MockupComponent: ProtestWorkflowMockup\n },\n {\n title: \"Find Your Perfect League\",\n description: \"Search and discover leagues by game, region, and skill level. Browse featured competitions, check driver counts, and join communities that match your racing style.\",\n MockupComponent: LeagueDiscoveryMockup\n },\n {\n title: \"Your Racing Identity\",\n description: \"Cross-league driver profiles with career stats, achievements, and racing history. Build your reputation across multiple championships and showcase your progression.\",\n MockupComponent: DriverProfileMockup\n }\n];\n\nfunction FeatureCard({ feature, index }: { feature: typeof features[0], index: number }) {\n return (\n <Box\n display=\"flex\"\n flexDirection=\"column\"\n gap={6}\n group\n >\n <Box aspectRatio=\"video\" fullWidth position=\"relative\">\n <Box position=\"absolute\" inset=\"-0.5\" bg=\"linear-gradient(to right, rgba(239, 68, 68, 0.2), rgba(59, 130, 246, 0.2), rgba(239, 68, 68, 0.2))\" rounded=\"lg\" opacity={0} groupHoverOpacity={1} transition blur=\"sm\" />\n <Box position=\"relative\">\n <MockupStack index={index}>\n <feature.MockupComponent />\n </MockupStack>\n </Box>\n </Box>\n <Stack gap={3}>\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n <Heading level={3} weight=\"medium\" style={{ background: 'linear-gradient(to right, #dc2626, #ffffff, #2563eb)', backgroundClip: 'text', WebkitBackgroundClip: 'text', color: 'transparent', filter: 'drop-shadow(0 0 15px rgba(220,0,0,0.4))', WebkitTextStroke: '0.5px rgba(220,0,0,0.2)' }}>\n {feature.title}\n </Heading>\n </Box>\n <Text size={{ base: 'sm', sm: 'base' }} color=\"text-gray-400\" weight=\"light\" leading=\"relaxed\">\n {feature.description}\n </Text>\n </Stack>\n </Box>\n );\n}\n\nexport function FeatureGrid() {\n return (\n <Section variant=\"default\">\n <Container position=\"relative\" zIndex={10}>\n <Container size=\"sm\" center>\n <Box>\n <Heading level={2} weight=\"semibold\" style={{ background: 'linear-gradient(to right, #dc2626, #ffffff, #2563eb)', backgroundClip: 'text', WebkitBackgroundClip: 'text', color: 'transparent', filter: 'drop-shadow(0 0 20px rgba(220,0,0,0.5))', WebkitTextStroke: '1px rgba(220,0,0,0.2)' }}>\n Building for League Racing\n </Heading>\n <Text size={{ base: 'base', sm: 'lg' }} color=\"text-gray-400\" block mt={{ base: 4, sm: 6 }}>\n These features are in development. Join the community to help shape what gets built first\n </Text>\n </Box>\n </Container>\n <Box mx=\"auto\" mt={{ base: 8, sm: 12, md: 16 }} display=\"grid\" gridCols={{ base: 1, lg: 2, xl: 3 }} gap={{ base: 10, sm: 12, md: 16 }} maxWidth={{ base: '2xl', lg: 'none' }}>\n {features.map((feature, index) => (\n <FeatureCard key={feature.title} feature={feature} index={index} />\n ))}\n </Box>\n </Container>\n </Section>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/FeatureItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/LandingHero.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":56,"column":134,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":56,"endColumn":165},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":56,"column":166,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":56,"endColumn":198},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":57,"column":134,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":57,"endColumn":165},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":57,"column":166,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":57,"endColumn":200},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":58,"column":135,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":58,"endColumn":166},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":58,"column":167,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":58,"endColumn":201},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":72,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":79,"endColumn":15},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":81,"column":46,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[3644,3736],"text":"\n League racing is incredible. What's missing is everything around it.\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[3644,3736],"text":"\n League racing is incredible. What‘s missing is everything around it.\n "},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[3644,3736],"text":"\n League racing is incredible. What's missing is everything around it.\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[3644,3736],"text":"\n League racing is incredible. What’s missing is everything around it.\n "},"desc":"Replace with `’`."}]},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":89,"column":21,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[4000,4079],"text":"\n If you've been in any league, you know the feeling:\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[4000,4079],"text":"\n If you‘ve been in any league, you know the feeling:\n "},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[4000,4079],"text":"\n If you've been in any league, you know the feeling:\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[4000,4079],"text":"\n If you’ve been in any league, you know the feeling:\n "},"desc":"Replace with `’`."}]},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`'` can be escaped with `'`, `‘`, `'`, `’`.","line":120,"column":32,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[5520,5583],"text":"\n The ecosystem isn't built for this.\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"‘"},"fix":{"range":[5520,5583],"text":"\n The ecosystem isn‘t built for this.\n "},"desc":"Replace with `‘`."},{"messageId":"replaceWithAlt","data":{"alt":"'"},"fix":{"range":[5520,5583],"text":"\n The ecosystem isn't built for this.\n "},"desc":"Replace with `'`."},{"messageId":"replaceWithAlt","data":{"alt":"’"},"fix":{"range":[5520,5583],"text":"\n The ecosystem isn’t built for this.\n "},"desc":"Replace with `’`."}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":152,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":152,"endColumn":43},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":153,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":156,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":158,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":158,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":159,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":159,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":160,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":160,"endColumn":64}],"suppressedMessages":[],"errorCount":15,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\nimport { useRef } from 'react';\nimport { useParallax } from '@/hooks/useScrollProgress';\nimport { Box } from '@/ui/Box';\nimport { Button } from '@/ui/Button';\nimport { Container } from '@/ui/Container';\nimport { Heading } from '@/ui/Heading';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\nconst discordUrl = process.env.NEXT_PUBLIC_DISCORD_URL || '#';\n\nif (!process.env.NEXT_PUBLIC_DISCORD_URL) {\n console.warn('NEXT_PUBLIC_DISCORD_URL is not set. Discord button will use \"#\" as fallback.');\n}\n\nexport function LandingHero() {\n const sectionRef = useRef<HTMLElement>(null);\n \n const bgParallax = useParallax(sectionRef, 0.3);\n\n return (\n <Box \n as=\"section\" \n ref={sectionRef} \n position=\"relative\" \n overflow=\"hidden\" \n bg=\"bg-deep-graphite\" \n px={{ base: 'calc(1.5rem+var(--sal))', lg: 8 }}\n pt={{ base: 'calc(3rem+var(--sat))', sm: 'calc(4rem+var(--sat))' }}\n pb={{ base: 16, sm: 24 }}\n py={{ md: 32 }}\n >\n {/* Background image layer with parallax */}\n <Box\n position=\"absolute\"\n inset=\"0\"\n bg=\"url(/images/header.jpeg)\"\n backgroundSize=\"cover\"\n backgroundPosition=\"center\"\n maskImage=\"radial-gradient(ellipse at center, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.35) 40%, transparent 70%)\"\n webkitMaskImage=\"radial-gradient(ellipse at center, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.35) 40%, transparent 70%)\"\n transform={`translateY(${bgParallax * 0.5}px)`}\n />\n \n {/* Racing red accent gradient */}\n <Box position=\"absolute\" top=\"0\" left=\"0\" right=\"0\" h=\"1\" bg=\"linear-gradient(to right, transparent, rgba(220, 38, 38, 0.4), transparent)\" />\n \n {/* Racing stripes background */}\n <Box position=\"absolute\" inset=\"0\" opacity={0.3} bg=\"racing-stripes\" />\n \n {/* Checkered pattern overlay */}\n <Box position=\"absolute\" inset=\"0\" opacity={0.2} bg=\"checkered-pattern\" />\n \n {/* Speed lines - left side */}\n <Box position=\"absolute\" left=\"0\" top=\"1/4\" w=\"32\" h=\"px\" bg=\"linear-gradient(to right, transparent, rgba(59, 130, 246, 0.3))\" className=\"animate-speed-lines\" style={{ animationDelay: '0s' }} />\n <Box position=\"absolute\" left=\"0\" top=\"1/3\" w=\"24\" h=\"px\" bg=\"linear-gradient(to right, transparent, rgba(59, 130, 246, 0.2))\" className=\"animate-speed-lines\" style={{ animationDelay: '0.3s' }} />\n <Box position=\"absolute\" left=\"0\" top=\"2/5\" w=\"28\" h=\"px\" bg=\"linear-gradient(to right, transparent, rgba(59, 130, 246, 0.25))\" className=\"animate-speed-lines\" style={{ animationDelay: '0.6s' }} />\n \n {/* Carbon fiber accent - bottom */}\n <Box position=\"absolute\" bottom=\"0\" left=\"0\" right=\"0\" h=\"32\" opacity={0.5} bg=\"carbon-fiber\" />\n \n {/* Radial gradient overlay with racing red accent */}\n <Box position=\"absolute\" inset=\"0\" bg=\"radial-gradient(circle at center, rgba(220, 38, 38, 0.05), rgba(59, 130, 246, 0.05), transparent)\" opacity={0.6} pointerEvents=\"none\" />\n \n <Container size=\"sm\" position=\"relative\" zIndex={10}>\n <Stack gap={{ base: 6, sm: 8, md: 12 }}>\n <Heading\n level={1}\n fontSize={{ base: '2xl', sm: '4xl', md: '5xl', lg: '6xl' }}\n weight=\"semibold\"\n style={{ \n background: 'linear-gradient(to right, #dc2626, #ffffff, #2563eb)', \n backgroundClip: 'text', \n WebkitBackgroundClip: 'text', \n color: 'transparent', \n filter: 'drop-shadow(0 0 15px rgba(220,0,0,0.4))', \n WebkitTextStroke: '0.5px rgba(220,0,0,0.2)' \n }}\n >\n League racing is incredible. What's missing is everything around it.\n </Heading>\n <Box\n display=\"flex\"\n flexDirection=\"column\"\n gap={{ base: 4, sm: 6 }}\n >\n <Text size={{ base: 'sm', md: 'lg' }} align={{ base: 'left', md: 'center' }} color=\"text-slate-200\" weight=\"light\">\n If you've been in any league, you know the feeling:\n </Text>\n {/* Problem badges - mobile optimized */}\n <Box display=\"flex\" flexDirection={{ base: 'col', sm: 'row' }} flexWrap=\"wrap\" gap={{ base: 2, sm: 3 }} alignItems={{ base: 'stretch', sm: 'center' }} justifyContent=\"center\" maxWidth=\"2xl\" mx=\"auto\">\n {[\n 'Results scattered across Discord',\n 'No long-term identity',\n 'No career progression',\n 'Forgotten after each season'\n ].map((text) => (\n <Box \n key={text}\n display=\"flex\" \n alignItems=\"center\" \n gap={2.5} \n px={{ base: 3, sm: 5 }} \n py={2.5} \n bg=\"linear-gradient(to bottom right, rgba(30, 41, 59, 0.8), rgba(15, 23, 42, 0.8))\" \n border \n borderColor=\"border-red-500/20\" \n rounded=\"lg\" \n transition\n hoverBorderColor=\"border-red-500/40\"\n hoverScale\n >\n <Text color=\"text-red-500\" weight=\"semibold\">×</Text>\n <Text size={{ base: 'sm', sm: 'base' }} weight=\"medium\" color=\"text-slate-100\">{text}</Text>\n </Box>\n ))}\n </Box>\n <Text size={{ base: 'sm', md: 'lg' }} align={{ base: 'left', md: 'center' }} color=\"text-slate-200\" weight=\"light\">\n The ecosystem isn't built for this.\n </Text>\n <Text size={{ base: 'sm', md: 'lg' }} align={{ base: 'left', md: 'center' }} color=\"text-white\" weight=\"semibold\">\n GridPilot gives your league racing a real home.\n </Text>\n </Box>\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"center\">\n <Button\n as=\"a\"\n href={discordUrl}\n variant=\"primary\"\n px={8}\n py={4}\n size=\"lg\"\n bg=\"bg-[#5865F2]\"\n hoverBg=\"bg-[#4752C4]\"\n shadow=\"0 0 20px rgba(88,101,242,0.3)\"\n hoverScale\n transition\n aria-label=\"Join us on Discord\"\n >\n {/* Discord Logo SVG */}\n <Box\n as=\"svg\"\n w=\"7\"\n h=\"7\"\n viewBox=\"0 0 71 55\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n transition\n groupHoverScale\n >\n <g clipPath=\"url(#clip0)\">\n <path\n d=\"M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z\"\n fill=\"currentColor\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0\">\n <rect width=\"71\" height=\"55\" fill=\"white\"/>\n </clipPath>\n </defs>\n </Box>\n <Text>Join us on Discord</Text>\n </Button>\n </Box>\n </Stack>\n </Container>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/landing/LandingItems.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Pure component in components/. Consider moving to ui/ for better reusability.","line":1,"column":1,"nodeType":null,"messageId":"pureComponentInComponents"},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'Box' is defined but never used.","line":5,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":13}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport React from 'react';\nimport { Check } from 'lucide-react';\nimport { Box } from '@/ui/Box';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\nimport { Surface } from '@/ui/Surface';\nimport { Icon } from '@/ui/Icon';\n\nexport function FeatureItem({ text }: { text: string }) {\n return (\n <Surface variant=\"muted\" rounded=\"lg\" border padding={4} bg=\"rgba(15, 23, 42, 0.6)\" borderColor=\"rgba(51, 65, 85, 0.4)\">\n <Stack direction=\"row\" align=\"start\" gap={3}>\n <Surface variant=\"muted\" rounded=\"lg\" padding={2} bg=\"rgba(59, 130, 246, 0.1)\" border borderColor=\"rgba(59, 130, 246, 0.3)\">\n <Icon icon={Check} size={5} color=\"#3b82f6\" />\n </Surface>\n <Text color=\"text-slate-200\" leading=\"relaxed\" weight=\"light\">\n {text}\n </Text>\n </Stack>\n </Surface>\n );\n}\n\nexport function ResultItem({ text, color }: { text: string, color: string }) {\n return (\n <Surface variant=\"muted\" rounded=\"lg\" border padding={4} bg=\"rgba(15, 23, 42, 0.6)\" borderColor=\"rgba(51, 65, 85, 0.4)\">\n <Stack direction=\"row\" align=\"start\" gap={3}>\n <Surface variant=\"muted\" rounded=\"lg\" padding={2} bg={`${color}1A`} border borderColor={`${color}4D`}>\n <Icon icon={Check} size={5} color={color} />\n </Surface>\n <Text color=\"text-slate-200\" leading=\"relaxed\" weight=\"light\">\n {text}\n </Text>\n </Stack>\n </Surface>\n );\n}\n\nexport function StepItem({ step, text }: { step: number, text: string }) {\n return (\n <Surface variant=\"muted\" rounded=\"lg\" border padding={4} bg=\"rgba(15, 23, 42, 0.7)\" borderColor=\"rgba(51, 65, 85, 0.5)\">\n <Stack direction=\"row\" align=\"start\" gap={3}>\n <Surface variant=\"muted\" rounded=\"lg\" padding={2} bg=\"rgba(59, 130, 246, 0.1)\" border borderColor=\"rgba(59, 130, 246, 0.4)\" w=\"10\" h=\"10\" display=\"flex\" center>\n <Text weight=\"bold\" size=\"sm\" color=\"text-primary-blue\">{step}</Text>\n </Surface>\n <Text color=\"text-slate-200\" leading=\"relaxed\" weight=\"light\">\n {text}\n </Text>\n </Stack>\n </Surface>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/layout/HeaderContent.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Pure component in components/. Consider moving to ui/ for better reusability.","line":1,"column":1,"nodeType":null,"messageId":"pureComponentInComponents"},{"ruleId":"gridpilot-rules/no-nextjs-imports-in-ui","severity":2,"message":"Next.js imports are forbidden in components/. Pass navigation/routing from app/ or use callbacks.","line":2,"column":1,"nodeType":"ImportDeclaration","messageId":"noNextImports","endLine":2,"endColumn":32},{"ruleId":"gridpilot-rules/no-nextjs-imports-in-ui","severity":2,"message":"Next.js imports are forbidden in components/. Pass navigation/routing from app/ or use callbacks.","line":2,"column":1,"nodeType":"ImportDeclaration","messageId":"noNextImports","endLine":2,"endColumn":32},{"ruleId":"gridpilot-rules/no-nextjs-imports-in-ui","severity":2,"message":"Next.js imports are forbidden in components/. Pass navigation/routing from app/ or use callbacks.","line":3,"column":1,"nodeType":"ImportDeclaration","messageId":"noNextImports","endLine":3,"endColumn":30},{"ruleId":"gridpilot-rules/no-nextjs-imports-in-ui","severity":2,"message":"Next.js imports are forbidden in components/. Pass navigation/routing from app/ or use callbacks.","line":3,"column":1,"nodeType":"ImportDeclaration","messageId":"noNextImports","endLine":3,"endColumn":30},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":8,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":24,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":8,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":8,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":8,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":8,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":9,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":23,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":9,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":9,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":9,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":9,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":10,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":10,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":16,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":16,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":20,"column":47,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":20,"endColumn":85}],"suppressedMessages":[],"errorCount":14,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from 'react';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport { Text } from '@/ui/Text';\n\nexport function HeaderContent() {\n return (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-3\">\n <Link href=\"/\" className=\"inline-flex items-center\">\n <Image\n src=\"/images/logos/wordmark-rectangle-dark.svg\"\n alt=\"GridPilot\"\n width={160}\n height={30}\n className=\"h-6 w-auto md:h-8\"\n priority\n />\n </Link>\n <Text size=\"sm\" color=\"text-gray-400\" className=\"hidden sm:block font-light\">\n Making league racing less chaotic\n </Text>\n </div>\n </div>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/DriverLeaderboardPreview.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":59,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":59,"endColumn":56,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":90,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":90,"endColumn":115,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":108,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":108,"endColumn":78,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":120,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":120,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":131,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":131,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/LeaderboardItem.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":66,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":66,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":76,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":76,"endColumn":91},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":78,"column":33,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":78,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":88,"column":65,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":88,"endColumn":124},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":92,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":92,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":95,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":95,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":98,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":98,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":107,"column":55,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":107,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":111,"column":55,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":111,"endColumn":83}],"suppressedMessages":[],"errorCount":9,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from 'react';\nimport { Crown, Flag } from 'lucide-react';\nimport { Box } from '@/ui/Box';\nimport { Text } from '@/ui/Text';\nimport { Stack } from '@/ui/Stack';\nimport { Image } from '@/ui/Image';\nimport { mediaConfig } from '@/lib/config/mediaConfig';\n\ninterface LeaderboardItemProps {\n position: number;\n name: string;\n avatarUrl?: string;\n nationality: string;\n rating: number;\n wins: number;\n skillLevelLabel?: string;\n skillLevelColor?: string;\n categoryLabel?: string;\n categoryColor?: string;\n onClick: () => void;\n}\n\nexport function LeaderboardItem({\n position,\n name,\n avatarUrl,\n nationality,\n rating,\n wins,\n skillLevelLabel,\n skillLevelColor,\n categoryLabel,\n categoryColor,\n onClick,\n}: LeaderboardItemProps) {\n const getMedalColor = (pos: number) => {\n switch (pos) {\n case 1: return 'text-yellow-400';\n case 2: return 'text-gray-300';\n case 3: return 'text-amber-600';\n default: return 'text-gray-500';\n }\n };\n\n const getMedalBg = (pos: number) => {\n switch (pos) {\n case 1: return 'bg-yellow-400/10 border-yellow-400/30';\n case 2: return 'bg-gray-300/10 border-gray-300/30';\n case 3: return 'bg-amber-600/10 border-amber-600/30';\n default: return 'bg-iron-gray/50 border-charcoal-outline';\n }\n };\n\n return (\n <Box\n as=\"button\"\n type=\"button\"\n onClick={onClick}\n display=\"flex\"\n alignItems=\"center\"\n gap={4}\n px={4}\n py={3}\n fullWidth\n textAlign=\"left\"\n className=\"hover:bg-iron-gray/30 transition-colors group\"\n >\n {/* Position */}\n <Box \n width=\"8\" \n height=\"8\" \n display=\"flex\" \n center \n rounded=\"full\" \n border \n className={`${getMedalBg(position)} ${getMedalColor(position)} text-xs font-bold`}\n >\n {position <= 3 ? <Crown className=\"w-3.5 h-3.5\" /> : position}\n </Box>\n\n {/* Avatar */}\n <Box position=\"relative\" width=\"9\" height=\"9\" rounded=\"full\" overflow=\"hidden\" border={true} borderColor=\"border-charcoal-outline\">\n <Image src={avatarUrl || mediaConfig.avatars.defaultFallback} alt={name} fill objectFit=\"cover\" />\n </Box>\n\n {/* Info */}\n <Box flexGrow={1} minWidth=\"0\">\n <Text weight=\"medium\" color=\"text-white\" truncate block className=\"group-hover:text-primary-blue transition-colors\">\n {name}\n </Text>\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Flag className=\"w-3 h-3 text-gray-500\" />\n <Text size=\"xs\" color=\"text-gray-500\">{nationality}</Text>\n {categoryLabel && (\n <Text size=\"xs\" className={categoryColor}>{categoryLabel}</Text>\n )}\n {skillLevelLabel && (\n <Text size=\"xs\" className={skillLevelColor}>{skillLevelLabel}</Text>\n )}\n </Stack>\n </Box>\n\n {/* Stats */}\n <Stack direction=\"row\" align=\"center\" gap={4}>\n <Box textAlign=\"center\">\n <Text color=\"text-primary-blue\" weight=\"semibold\" font=\"mono\" block>{rating.toLocaleString()}</Text>\n <Text size=\"xs\" color=\"text-gray-500\" block style={{ fontSize: '10px' }}>Rating</Text>\n </Box>\n <Box textAlign=\"center\">\n <Text color=\"text-performance-green\" weight=\"semibold\" font=\"mono\" block>{wins}</Text>\n <Text size=\"xs\" color=\"text-gray-500\" block style={{ fontSize: '10px' }}>Wins</Text>\n </Box>\n </Stack>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/LeaderboardPreview.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/LeaderboardsHero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/RankingList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/RankingListItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leaderboards/TeamLeaderboardPreview.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":58,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":58,"endColumn":56,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":89,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":89,"endColumn":115,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":123,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":123,"endColumn":80,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":135,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":135,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":146,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":146,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ChampionshipStandings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ChampionshipStandingsList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/EmptyState.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/EndRaceModal.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/JoinLeagueButton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueActivityFeed.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueBasicsSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueChampionshipStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueDecalPlacementEditor.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":192,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":192,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":214,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":214,"endColumn":129,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":216,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":216,"endColumn":81,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":230,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":230,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":237,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":237,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":261,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":265,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":267,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":273,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":278,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":278,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":281,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":281,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":301,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":304,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":342,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":342,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":351,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":351,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":389,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":389,"endColumn":85,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":406,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":406,"endColumn":85,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":423,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":423,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":434,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":434,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":458,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":458,"endColumn":83,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":481,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":481,"endColumn":31,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueDropSection.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":97,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":97,"endColumn":95,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":195,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":195,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":199,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":199,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":207,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":207,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":222,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":222,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":229,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":229,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":395,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":395,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":399,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":399,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":409,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":409,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":412,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":412,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":422,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":422,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":428,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":428,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":439,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":439,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":445,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":445,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":456,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":456,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":462,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":462,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":477,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":477,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":516,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":516,"endColumn":101,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":566,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":566,"endColumn":114,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":570,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":570,"endColumn":72,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":587,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":587,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":591,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":591,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":611,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":611,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueMemberRow.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'driverId' is defined but never used.","line":27,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":27,"endColumn":11}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { ReactNode } from 'react';\nimport { TableRow, TableCell } from '@/ui/Table';\nimport { Box } from '@/ui/Box';\nimport { Text } from '@/ui/Text';\nimport { Badge } from '@/ui/Badge';\nimport { DriverIdentity } from '@/components/drivers/DriverIdentity';\nimport { DriverViewModel } from '@/lib/view-models/DriverViewModel';\n\ninterface LeagueMemberRowProps {\n driver?: DriverViewModel;\n driverId: string;\n isCurrentUser: boolean;\n isTopPerformer: boolean;\n role: string;\n roleVariant: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';\n joinedAt: string | Date;\n rating?: number | string;\n rank?: number | string;\n wins?: number;\n actions?: ReactNode;\n href: string;\n meta?: string | null;\n}\n\nexport function LeagueMemberRow({\n driver,\n driverId,\n isCurrentUser,\n isTopPerformer,\n role,\n roleVariant,\n joinedAt,\n rating,\n rank,\n wins,\n actions,\n href,\n meta,\n}: LeagueMemberRowProps) {\n const roleLabel = role.charAt(0).toUpperCase() + role.slice(1);\n\n return (\n <TableRow variant={isTopPerformer ? 'highlight' : 'default'}>\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n {driver ? (\n <DriverIdentity\n driver={driver}\n href={href}\n contextLabel={roleLabel}\n meta={meta}\n size=\"md\"\n />\n ) : (\n <Text color=\"text-white\">Unknown Driver</Text>\n )}\n {isCurrentUser && (\n <Text size=\"xs\" color=\"text-gray-500\">(You)</Text>\n )}\n {isTopPerformer && (\n <Text size=\"xs\">⭐</Text>\n )}\n </Box>\n </TableCell>\n <TableCell>\n <Text color=\"text-primary-blue\" weight=\"medium\">\n {rating || '—'}\n </Text>\n </TableCell>\n <TableCell>\n <Text color=\"text-gray-300\">\n #{rank || '—'}\n </Text>\n </TableCell>\n <TableCell>\n <Text color=\"text-green-400\" weight=\"medium\">\n {wins || 0}\n </Text>\n </TableCell>\n <TableCell>\n <Badge variant={roleVariant}>\n {roleLabel}\n </Badge>\n </TableCell>\n <TableCell>\n <Text color=\"text-white\" size=\"sm\">\n {new Date(joinedAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })}\n </Text>\n </TableCell>\n {actions && (\n <TableCell textAlign=\"right\">\n {actions}\n </TableCell>\n )}\n </TableRow>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueMembers.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":87,"column":25,"nodeType":"CallExpression","messageId":"message","endLine":110,"endColumn":5,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":206,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":206,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueMembershipFeesSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueOwnershipTransfer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueReviewSummary.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":78,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":78,"endColumn":32,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":86,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":86,"endColumn":31,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":193,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":193,"endColumn":33,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":197,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":197,"endColumn":33,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":230,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":230,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":342,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":342,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueSchedule.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":91,"column":22,"nodeType":"CallExpression","messageId":"message","endLine":91,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":94,"column":44,"nodeType":"CallExpression","messageId":"message","endLine":94,"endColumn":68,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":225,"column":35,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":225,"endColumn":64,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":237,"column":35,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":237,"endColumn":64,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueScoringSection.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":111,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":111,"endColumn":74,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":113,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":113,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":126,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":126,"endColumn":34,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":148,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":148,"endColumn":106,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":174,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":174,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":178,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":178,"endColumn":38,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":184,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":184,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":188,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":188,"endColumn":38,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":204,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":204,"endColumn":60,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":215,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":215,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":222,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":222,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":251,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":251,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":286,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":286,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":299,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":299,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":312,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":312,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":432,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":432,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":604,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":604,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":608,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":608,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":620,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":620,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":624,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":624,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":638,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":638,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":657,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":663,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":688,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":688,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":698,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":698,"endColumn":149,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":751,"column":29,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":751,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":755,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":755,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":762,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":762,"endColumn":50,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":768,"column":33,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":768,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":781,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":781,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":785,"column":31,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":785,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":804,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":804,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":811,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":817,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":836,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":836,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":848,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":848,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":894,"column":25,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":894,"endColumn":53,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":898,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":898,"endColumn":50,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":910,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":910,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":914,"column":25,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":914,"endColumn":53,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":931,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":931,"endColumn":120,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":951,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":951,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":961,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":961,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":973,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":973,"endColumn":50,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":986,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":986,"endColumn":75,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":993,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":993,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1006,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1006,"endColumn":75,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1026,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1026,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1038,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1038,"endColumn":61,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1051,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1051,"endColumn":61,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1206,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1206,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1210,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1210,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1222,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1222,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1226,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1226,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1244,"column":25,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1244,"endColumn":53,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1253,"column":25,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1253,"endColumn":52,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1281,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1289,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1310,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1310,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1316,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1316,"endColumn":38,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1320,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1320,"endColumn":109,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1328,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1328,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1385,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1385,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1389,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1389,"endColumn":52,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1396,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1396,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1402,"column":31,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1402,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1413,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1413,"endColumn":79,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1418,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1418,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1422,"column":29,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1422,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueSponsorshipsSection.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":55,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":55,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1931,1934],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1931,1934],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":224,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":224,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { Award, DollarSign, Star, X } from 'lucide-react';\nimport { useState } from 'react';\nimport { PendingSponsorshipRequests } from '../sponsors/PendingSponsorshipRequests';\nimport { Button } from '@/ui/Button';\nimport { Input } from '@/ui/Input';\nimport { Box } from '@/ui/Box';\nimport { Text } from '@/ui/Text';\nimport { Heading } from '@/ui/Heading';\nimport { Stack } from '@/ui/Stack';\nimport { Icon } from '@/ui/Icon';\nimport { Badge } from '@/ui/Badge';\nimport { StatBox } from '@/ui/StatBox';\n\nimport { useEffectiveDriverId } from \"@/hooks/useEffectiveDriverId\";\nimport { useLeagueSeasons } from \"@/hooks/league/useLeagueSeasons\";\nimport { useSponsorshipRequests } from \"@/hooks/league/useSponsorshipRequests\";\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { SPONSOR_SERVICE_TOKEN } from '@/lib/di/tokens';\n\ninterface SponsorshipSlot {\n tier: 'main' | 'secondary';\n sponsorName?: string;\n logoUrl?: string;\n price: number;\n isOccupied: boolean;\n}\n\ninterface LeagueSponsorshipsSectionProps {\n leagueId: string;\n seasonId?: string;\n readOnly?: boolean;\n}\n\nexport function LeagueSponsorshipsSection({\n leagueId,\n seasonId: propSeasonId,\n readOnly = false\n}: LeagueSponsorshipsSectionProps) {\n const currentDriverId = useEffectiveDriverId();\n const sponsorshipService = useInject(SPONSOR_SERVICE_TOKEN);\n \n const [slots, setSlots] = useState<SponsorshipSlot[]>([\n { tier: 'main', price: 500, isOccupied: false },\n { tier: 'secondary', price: 200, isOccupied: false },\n { tier: 'secondary', price: 200, isOccupied: false },\n ]);\n const [editingIndex, setEditingIndex] = useState<number | null>(null);\n const [tempPrice, setTempPrice] = useState<string>('');\n\n // Load season ID if not provided\n const { data: seasonsResult } = useLeagueSeasons(leagueId);\n const seasons = seasonsResult?.isOk() ? seasonsResult.unwrap() : [];\n const activeSeason = seasons.find((s: any) => s.status === 'active') ?? seasons[0];\n const seasonId = propSeasonId || activeSeason?.seasonId;\n\n // Load pending sponsorship requests\n const { data: pendingRequestsData, isLoading: requestsLoading, refetch: refetchRequests } = useSponsorshipRequests('season', seasonId || '');\n const pendingRequests = pendingRequestsData?.requests || [];\n\n const handleAcceptRequest = async (requestId: string) => {\n if (!currentDriverId) return;\n \n try {\n await sponsorshipService.acceptSponsorshipRequest(requestId, currentDriverId);\n await refetchRequests();\n } catch (err) {\n console.error('Failed to accept request:', err);\n alert(err instanceof Error ? err.message : 'Failed to accept request');\n }\n };\n\n const handleRejectRequest = async (requestId: string, reason?: string) => {\n if (!currentDriverId) return;\n \n try {\n await sponsorshipService.rejectSponsorshipRequest(requestId, currentDriverId, reason);\n await refetchRequests();\n } catch (err) {\n console.error('Failed to reject request:', err);\n alert(err instanceof Error ? err.message : 'Failed to reject request');\n }\n };\n\n const handleEditPrice = (index: number) => {\n const slot = slots[index];\n if (!slot) return;\n setEditingIndex(index);\n setTempPrice(slot.price.toString());\n };\n\n const handleSavePrice = (index: number) => {\n const price = parseFloat(tempPrice);\n if (!isNaN(price) && price > 0) {\n const updated = [...slots];\n const slot = updated[index];\n if (slot) {\n slot.price = price;\n setSlots(updated);\n }\n }\n setEditingIndex(null);\n setTempPrice('');\n };\n\n const handleCancelEdit = () => {\n setEditingIndex(null);\n setTempPrice('');\n };\n\n const totalRevenue = slots.reduce((sum, slot) => \n slot.isOccupied ? sum + slot.price : sum, 0\n );\n const platformFee = totalRevenue * 0.10;\n const netRevenue = totalRevenue - platformFee;\n\n const availableSlots = slots.filter(s => !s.isOccupied).length;\n\n return (\n <Stack gap={6}>\n {/* Header */}\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"between\">\n <Box>\n <Heading level={3}>Sponsorships</Heading>\n <Text size=\"sm\" color=\"text-gray-400\" mt={1} block>\n Define pricing for sponsor slots in this league. Sponsors pay per season.\n </Text>\n <Text size=\"xs\" color=\"text-gray-500\" mt={1} block>\n These sponsors are attached to seasons in this league, so you can change partners from season to season.\n </Text>\n </Box>\n {!readOnly && (\n <Box display=\"flex\" alignItems=\"center\" gap={2} px={3} py={1.5} rounded=\"full\" bg=\"bg-primary-blue/10\" border borderColor=\"border-primary-blue/30\">\n <Icon icon={DollarSign} size={4} color=\"var(--primary-blue)\" />\n <Text size=\"xs\" weight=\"medium\" color=\"text-primary-blue\">\n {availableSlots} slot{availableSlots !== 1 ? 's' : ''} available\n </Text>\n </Box>\n )}\n </Box>\n\n {/* Revenue Summary */}\n {totalRevenue > 0 && (\n <Box display=\"grid\" gridCols={3} gap={4}>\n <StatBox\n icon={DollarSign}\n label=\"Total Revenue\"\n value={`$${totalRevenue.toFixed(2)}`}\n color=\"var(--primary-blue)\"\n />\n <StatBox\n icon={DollarSign}\n label=\"Platform Fee (10%)\"\n value={`-$${platformFee.toFixed(2)}`}\n color=\"var(--warning-amber)\"\n />\n <StatBox\n icon={DollarSign}\n label=\"Net Revenue\"\n value={`$${netRevenue.toFixed(2)}`}\n color=\"var(--performance-green)\"\n />\n </Box>\n )}\n\n {/* Sponsorship Slots */}\n <Stack gap={3}>\n {slots.map((slot, index) => {\n const isEditing = editingIndex === index;\n const IconComp = slot.tier === 'main' ? Star : Award;\n \n return (\n <Box\n key={index}\n rounded=\"lg\"\n border\n borderColor=\"border-charcoal-outline\"\n bg=\"bg-deep-graphite/70\"\n p={4}\n >\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"between\" gap={4}>\n <Box display=\"flex\" alignItems=\"center\" gap={3} flexGrow={1}>\n <Box \n display=\"flex\" \n h=\"10\" \n w=\"10\" \n alignItems=\"center\" \n justifyContent=\"center\" \n rounded=\"lg\" \n bg={slot.tier === 'main' ? 'bg-primary-blue/10' : 'bg-gray-500/10'}\n >\n <Icon icon={IconComp} size={5} color={slot.tier === 'main' ? 'var(--primary-blue)' : 'var(--gray-400)'} />\n </Box>\n \n <Box flexGrow={1}>\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n <Heading level={4}>\n {slot.tier === 'main' ? 'Main Sponsor' : 'Secondary Sponsor'}\n </Heading>\n {slot.isOccupied && (\n <Badge variant=\"success\">\n Occupied\n </Badge>\n )}\n </Box>\n <Text size=\"xs\" color=\"text-gray-500\" mt={0.5} block>\n {slot.tier === 'main' \n ? 'Big livery slot • League page logo • Name in league title'\n : 'Small livery slot • League page logo'}\n </Text>\n </Box>\n </Box>\n\n <Box display=\"flex\" alignItems=\"center\" gap={3}>\n {isEditing ? (\n <Box display=\"flex\" alignItems=\"center\" gap={2}>\n <Input\n type=\"number\"\n value={tempPrice}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setTempPrice(e.target.value)}\n placeholder=\"Price\"\n // eslint-disable-next-line gridpilot-rules/component-classification\n className=\"w-32\"\n min=\"0\"\n step=\"0.01\"\n />\n <Button\n variant=\"primary\"\n onClick={() => handleSavePrice(index)}\n size=\"sm\"\n >\n Save\n </Button>\n <Button\n variant=\"secondary\"\n onClick={handleCancelEdit}\n size=\"sm\"\n >\n <Icon icon={X} size={4} />\n </Button>\n </Box>\n ) : (\n <>\n <Box textAlign=\"right\">\n <Text size=\"lg\" weight=\"bold\" color=\"text-white\" block>\n ${slot.price.toFixed(2)}\n </Text>\n <Text size=\"xs\" color=\"text-gray-500\" block>per season</Text>\n </Box>\n {!readOnly && !slot.isOccupied && (\n <Button\n variant=\"secondary\"\n onClick={() => handleEditPrice(index)}\n size=\"sm\"\n >\n Edit Price\n </Button>\n )}\n </>\n )}\n </Box>\n </Box>\n </Box>\n );\n })}\n </Stack>\n\n {/* Pending Sponsorship Requests */}\n {!readOnly && (pendingRequests.length > 0 || requestsLoading) && (\n <Box mt={8} pt={6} borderTop borderColor=\"border-charcoal-outline\">\n <PendingSponsorshipRequests\n entityType=\"season\"\n entityId={seasonId || ''}\n entityName=\"this league\"\n requests={pendingRequests}\n onAccept={handleAcceptRequest}\n onReject={handleRejectRequest}\n isLoading={requestsLoading}\n />\n </Box>\n )}\n\n {/* Alpha Notice */}\n <Box rounded=\"lg\" bg=\"bg-warning-amber/10\" border borderColor=\"border-warning-amber/30\" p={4}>\n <Text size=\"xs\" color=\"text-gray-400\" block>\n <Text weight=\"bold\" color=\"text-warning-amber\">Alpha Note:</Text> Sponsorship management is demonstration-only.\n In production, sponsors can browse leagues, select slots, and complete payment integration.\n </Text>\n </Box>\n </Stack>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueStewardingSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueStructureSection.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":99,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":99,"endColumn":95,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'maxTeams' is assigned a value but never used.","line":195,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":195,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'driversPerTeam' is assigned a value but never used.","line":195,"column":25,"nodeType":"Identifier","messageId":"unusedVar","endLine":195,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":424,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":424,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":576,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":576,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":647,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":647,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueSummaryCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueTabs.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":32,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":32,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueTimingsSection.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":156,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":156,"endColumn":107,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":163,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":163,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":189,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":189,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":205,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":205,"endColumn":121,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":220,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":220,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":230,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":230,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":240,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":240,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":253,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":253,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":260,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":260,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":267,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":267,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":360,"column":11,"nodeType":"CallExpression","messageId":"message","endLine":360,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":374,"column":11,"nodeType":"CallExpression","messageId":"message","endLine":374,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":379,"column":9,"nodeType":"CallExpression","messageId":"message","endLine":379,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":417,"column":11,"nodeType":"CallExpression","messageId":"message","endLine":417,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":485,"column":11,"nodeType":"CallExpression","messageId":"message","endLine":491,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":495,"column":9,"nodeType":"CallExpression","messageId":"message","endLine":500,"endColumn":11,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":533,"column":9,"nodeType":"CallExpression","messageId":"message","endLine":540,"endColumn":11,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-no-data-manipulation","severity":2,"message":"Components must not manipulate data - see apps/website/lib/contracts/view-data/ViewData.ts","line":544,"column":7,"nodeType":"CallExpression","messageId":"message","endLine":549,"endColumn":9,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":575,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":575,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":602,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":602,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":611,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":611,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":641,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":645,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":666,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":666,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":679,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":679,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":696,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":696,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":710,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":710,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":714,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":714,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":724,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":724,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":734,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":734,"endColumn":52,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":738,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":738,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":749,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":749,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":824,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":824,"endColumn":106,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":828,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":828,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":838,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":838,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":851,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":851,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":861,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":861,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":876,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":876,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":887,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":887,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":898,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":898,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":909,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":909,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":969,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":969,"endColumn":101,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":991,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":991,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1009,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1009,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1014,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1014,"endColumn":85,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1022,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1022,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1117,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1117,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1125,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1127,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1285,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1285,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1336,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1336,"endColumn":66,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1352,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1352,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1380,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1380,"endColumn":66,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1402,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1402,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1417,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1417,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1423,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1423,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1438,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1438,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1448,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1448,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1459,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1459,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1470,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1470,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1478,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1478,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1516,"column":29,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1516,"endColumn":56,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1544,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1544,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1587,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1587,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1604,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1604,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1608,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1608,"endColumn":77,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1639,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1639,"endColumn":66,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":1644,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":1644,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1656,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1656,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":1719,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":1719,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/LeagueVisibilitySection.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":101,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":101,"endColumn":95,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":340,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":340,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":362,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":362,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":519,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":519,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":543,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":543,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/MembershipStatus.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/PenaltyHistoryList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/PendingProtestsList.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'leagueId' is defined but never used.","line":25,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":25,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":35,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":35,"endColumn":63}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { DriverViewModel } from \"@/lib/view-models/DriverViewModel\";\nimport { ProtestViewModel } from \"@/lib/view-models/ProtestViewModel\";\nimport { RaceViewModel } from \"@/lib/view-models/RaceViewModel\";\nimport { Box } from \"@/ui/Box\";\nimport { Card } from \"@/ui/Card\";\nimport { ProtestListItem } from \"./ProtestListItem\";\nimport { Stack } from \"@/ui/Stack\";\nimport { Text } from \"@/ui/Text\";\nimport { Flag } from \"lucide-react\";\n\ninterface PendingProtestsListProps {\n protests: ProtestViewModel[];\n races: Record<string, RaceViewModel>;\n drivers: Record<string, DriverViewModel>;\n leagueId: string;\n onReviewProtest: (protest: ProtestViewModel) => void;\n onProtestReviewed: () => void;\n}\n\nexport function PendingProtestsList({\n protests,\n drivers,\n leagueId,\n onReviewProtest,\n}: PendingProtestsListProps) {\n\n if (protests.length === 0) {\n return (\n <Card>\n <Box p={12} textAlign=\"center\">\n <Stack align=\"center\" gap={4}>\n <Box w=\"16\" h=\"16\" rounded=\"full\" bg=\"bg-performance-green/10\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\">\n <Flag className=\"h-8 w-8 text-performance-green\" />\n </Box>\n <Box>\n <Text weight=\"semibold\" size=\"lg\" color=\"text-white\" block mb={2}>All Clear! 🏁</Text>\n <Text size=\"sm\" color=\"text-gray-400\">No pending protests to review</Text>\n </Box>\n </Stack>\n </Box>\n </Card>\n );\n }\n\n return (\n <Stack gap={4}>\n {protests.map((protest) => {\n const filedAt = protest.filedAt || protest.submittedAt;\n const daysSinceFiled = Math.floor((Date.now() - new Date(filedAt).getTime()) / (1000 * 60 * 60 * 24));\n const isUrgent = daysSinceFiled > 2;\n \n const protester = drivers[protest.protestingDriverId];\n const accused = drivers[protest.accusedDriverId];\n \n return (\n <ProtestListItem\n key={protest.id}\n protesterName={protester?.name || 'Unknown'}\n protesterHref={`/drivers/${protest.protestingDriverId}`}\n accusedName={accused?.name || 'Unknown'}\n accusedHref={`/drivers/${protest.accusedDriverId}`}\n status={protest.status}\n isUrgent={isUrgent}\n daysOld={daysSinceFiled}\n lap={protest.incident?.lap ?? 0}\n filedAtLabel={new Date(filedAt).toLocaleDateString()}\n description={protest.incident?.description || protest.description}\n proofVideoUrl={protest.proofVideoUrl || undefined}\n isAdmin={true}\n onReview={() => onReviewProtest(protest)}\n />\n );\n })}\n </Stack>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ProtestCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ProtestListItem.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":46,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":46,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[989,992],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[989,992],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":61,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":61,"endColumn":64}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { AlertCircle, AlertTriangle, Video } from 'lucide-react';\nimport { Badge } from '@/ui/Badge';\nimport { Box } from '@/ui/Box';\nimport { Button } from '@/ui/Button';\nimport { Card } from '@/ui/Card';\nimport { Icon } from '@/ui/Icon';\nimport { Link } from '@/ui/Link';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\ninterface ProtestListItemProps {\n protesterName: string;\n protesterHref: string;\n accusedName: string;\n accusedHref: string;\n status: string;\n isUrgent: boolean;\n daysOld: number;\n lap: number;\n filedAtLabel: string;\n description: string;\n proofVideoUrl?: string;\n decisionNotes?: string;\n isAdmin: boolean;\n onReview?: () => void;\n}\n\nexport function ProtestListItem({\n protesterName,\n protesterHref,\n accusedName,\n accusedHref,\n status,\n isUrgent,\n daysOld,\n lap,\n filedAtLabel,\n description,\n proofVideoUrl,\n decisionNotes,\n isAdmin,\n onReview,\n}: ProtestListItemProps) {\n const getStatusVariant = (s: string): any => {\n switch (s) {\n case 'pending':\n case 'under_review': return 'warning';\n case 'upheld': return 'danger';\n case 'dismissed': return 'default';\n case 'withdrawn': return 'primary';\n default: return 'warning';\n }\n };\n\n return (\n <Card \n borderLeft={isUrgent} \n borderColor={isUrgent ? 'border-red-500' : 'border-charcoal-outline'}\n style={isUrgent ? { borderLeftWidth: '4px' } : undefined}\n >\n <Stack direction=\"row\" align=\"start\" justify=\"between\" gap={4}>\n <Box flexGrow={1} minWidth=\"0\">\n <Stack direction=\"row\" align=\"center\" gap={2} mb={2} wrap>\n <Icon icon={AlertCircle} size={4} color=\"rgb(156, 163, 175)\" />\n <Link href={protesterHref}>\n <Text weight=\"medium\" color=\"text-white\">{protesterName}</Text>\n </Link>\n <Text size=\"sm\" color=\"text-gray-500\">vs</Text>\n <Link href={accusedHref}>\n <Text weight=\"medium\" color=\"text-white\">{accusedName}</Text>\n </Link>\n <Badge variant={getStatusVariant(status)}>\n {status.replace('_', ' ')}\n </Badge>\n {isUrgent && (\n <Badge variant=\"danger\" icon={AlertTriangle}>\n {daysOld}d old\n </Badge>\n )}\n </Stack>\n <Stack direction=\"row\" align=\"center\" gap={4} mb={2} wrap>\n <Text size=\"sm\" color=\"text-gray-400\">Lap {lap}</Text>\n <Text size=\"sm\" color=\"text-gray-400\">•</Text>\n <Text size=\"sm\" color=\"text-gray-400\">Filed {filedAtLabel}</Text>\n {proofVideoUrl && (\n <>\n <Text size=\"sm\" color=\"text-gray-400\">•</Text>\n <Link href={proofVideoUrl} target=\"_blank\">\n <Icon icon={Video} size={3.5} mr={1.5} />\n <Text size=\"sm\">Video Evidence</Text>\n </Link>\n </>\n )}\n </Stack>\n <Text size=\"sm\" color=\"text-gray-300\" block>{description}</Text>\n \n {decisionNotes && (\n <Box mt={4} p={3} bg=\"bg-charcoal-outline/30\" rounded=\"lg\" border borderColor=\"border-charcoal-outline/50\">\n <Text size=\"xs\" color=\"text-gray-500\" uppercase letterSpacing=\"0.05em\" block mb={1}>Steward Decision</Text>\n <Text size=\"sm\" color=\"text-gray-300\">{decisionNotes}</Text>\n </Box>\n )}\n </Box>\n {isAdmin && status === 'pending' && onReview && (\n <Button\n variant=\"primary\"\n onClick={onReview}\n size=\"sm\"\n >\n Review\n </Button>\n )}\n </Stack>\n </Card>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/QuickPenaltyModal.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":83,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":83,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ReadonlyLeagueInfo.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ReviewProtestModal.tsx","messages":[],"suppressedMessages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":65,"column":27,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":65,"endColumn":30,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2063,2066],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2063,2066],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":78,"column":36,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":78,"endColumn":39,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2587,2590],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2587,2590],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":411,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":411,"endColumn":69,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/ScheduleRaceCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/SponsorshipRequestCard.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":50,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":53,"endColumn":9,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":57,"column":14,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":57,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/SponsorshipSlotCard.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":37,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":40,"endColumn":9,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":61,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":61,"endColumn":65,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/StandingsTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/StewardingStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/leagues/TransactionRow.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/CareerProgressionMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":50,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":50,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":101,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":101,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":109,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":200,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":200,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/CompanionAutomationMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":138,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":138,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":243,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":243,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":304,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":304,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/DriverProfileMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":55,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":55,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":95,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":95,"endColumn":50,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":141,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":141,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/LeagueDiscoveryMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":115,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":115,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":119,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":119,"endColumn":380,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":210,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":210,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":223,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":223,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":232,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":232,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":241,"column":27,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":241,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":257,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":257,"endColumn":359,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":261,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":261,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":270,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":270,"endColumn":140,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":274,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":274,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":293,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":293,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":301,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":301,"endColumn":380,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":306,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":306,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":329,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":329,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":348,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":348,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/LeagueHomeMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":44,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":44,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":100,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":100,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":109,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":123,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":123,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":177,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":177,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":190,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":190,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/MockupStack.tsx","messages":[{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":31,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":68,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":31,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":31,"endColumn":160},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":31,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":31,"endColumn":125},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":31,"column":126,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":31,"endColumn":159},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":32,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":44,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":32,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":44,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":33,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":33,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":34,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":43,"endColumn":13},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":46,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":58,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":46,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":58,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":47,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":47,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":48,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":57,"endColumn":13},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":60,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":67,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":60,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":65,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":61,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":61,"endColumn":77},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":62,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":64,"endColumn":13},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":74,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":144,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":74,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":74,"endColumn":158},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":74,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":74,"endColumn":123},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":74,"column":124,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":74,"endColumn":157},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":75,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":89,"endColumn":9},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":76,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":76,"endColumn":87},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":77,"column":9,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":85,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":91,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":105,"endColumn":9},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":92,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":92,"endColumn":87},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":93,"column":9,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":101,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":107,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":130,"endColumn":8},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":108,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":108,"endColumn":75},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":9,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":111,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":131,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":141,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":132,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":132,"endColumn":70}],"suppressedMessages":[],"errorCount":31,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { ReactNode, useEffect, useState } from 'react';\n\ninterface MockupStackProps {\n children: ReactNode;\n index?: number;\n}\n\nexport function MockupStack({ children, index = 0 }: MockupStackProps) {\n const shouldReduceMotion = useReducedMotion();\n const [isMounted, setIsMounted] = useState(false);\n const [isMobile, setIsMobile] = useState(true); // Default to mobile (no animations)\n\n useEffect(() => {\n setIsMounted(true);\n const checkMobile = () => setIsMobile(window.innerWidth < 768);\n checkMobile();\n window.addEventListener('resize', checkMobile);\n return () => window.removeEventListener('resize', checkMobile);\n }, []);\n\n const seed = index * 1337;\n const rotation1 = ((seed * 17) % 80 - 40) / 20;\n const rotation2 = ((seed * 23) % 80 - 40) / 20;\n\n // On mobile or before mount, render without animations\n if (!isMounted || isMobile) {\n return (\n <div className=\"relative w-full h-full scale-60 sm:scale-70 md:scale-85 lg:scale-95 max-w-[85vw] mx-auto my-4 sm:my-0\" style={{ perspective: '1200px' }}>\n <div\n className=\"absolute rounded-lg bg-iron-gray/80 border border-charcoal-outline\"\n style={{\n rotate: `${rotation1}deg`,\n zIndex: 1,\n top: '-8px',\n left: '-8px',\n right: '-8px',\n bottom: '-8px',\n boxShadow: '0 12px 40px rgba(0,0,0,0.3)',\n opacity: 0.5,\n }}\n />\n \n <div\n className=\"absolute rounded-lg bg-iron-gray/90 border border-charcoal-outline\"\n style={{\n rotate: `${rotation2}deg`,\n zIndex: 2,\n top: '-4px',\n left: '-4px',\n right: '-4px',\n bottom: '-4px',\n boxShadow: '0 16px 48px rgba(0,0,0,0.35)',\n opacity: 0.7,\n }}\n />\n\n <div\n className=\"relative z-10 w-full h-full rounded-lg overflow-hidden\"\n style={{\n boxShadow: '0 20px 60px rgba(0,0,0,0.45)',\n }}\n >\n {children}\n </div>\n </div>\n );\n }\n\n // Desktop: render with animations\n return (\n <div className=\"relative w-full h-full scale-60 sm:scale-70 md:scale-85 lg:scale-95 max-w-[85vw] mx-auto my-4 sm:my-0\" style={{ perspective: '1200px' }}>\n <motion.div\n className=\"absolute rounded-lg bg-iron-gray/80 border border-charcoal-outline\"\n style={{\n rotate: `${rotation1}deg`,\n zIndex: 1,\n top: '-8px',\n left: '-8px',\n right: '-8px',\n bottom: '-8px',\n boxShadow: '0 12px 40px rgba(0,0,0,0.3)',\n }}\n initial={{ opacity: 0, scale: 0.92 }}\n animate={{ opacity: 0.5, scale: 1 }}\n transition={{ duration: 0.3, delay: 0.1 }}\n />\n \n <motion.div\n className=\"absolute rounded-lg bg-iron-gray/90 border border-charcoal-outline\"\n style={{\n rotate: `${rotation2}deg`,\n zIndex: 2,\n top: '-4px',\n left: '-4px',\n right: '-4px',\n bottom: '-4px',\n boxShadow: '0 16px 48px rgba(0,0,0,0.35)',\n }}\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 0.7, scale: 1 }}\n transition={{ duration: 0.3, delay: 0.15 }}\n />\n\n <motion.div\n className=\"relative z-10 w-full h-full rounded-lg overflow-hidden\"\n style={{\n boxShadow: '0 20px 60px rgba(0,0,0,0.45)',\n }}\n whileHover={\n shouldReduceMotion\n ? {}\n : {\n scale: 1.02,\n rotateY: 3,\n rotateX: -2,\n y: -12,\n transition: {\n type: 'spring',\n stiffness: 200,\n damping: 20,\n },\n }\n }\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.4, delay: 0.2 }}\n >\n <motion.div\n className=\"absolute inset-0 pointer-events-none rounded-lg\"\n whileHover={\n shouldReduceMotion\n ? {}\n : {\n boxShadow: '0 0 40px rgba(25, 140, 255, 0.4)',\n transition: { duration: 0.2 },\n }\n }\n />\n {children}\n </motion.div>\n </div>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/ProtestWorkflowMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":68,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":68,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":72,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":72,"endColumn":104,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":80,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":80,"endColumn":130,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":95,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":95,"endColumn":77,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":145,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":145,"endColumn":60,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":159,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":159,"endColumn":106,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":180,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":180,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":208,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":208,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":214,"column":23,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":214,"endColumn":134,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/RaceHistoryMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":67,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":67,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":124,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":124,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":132,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":132,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":140,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":140,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":148,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":148,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":156,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":156,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":184,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":184,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":206,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":206,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":217,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":217,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":226,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":226,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":240,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":240,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":252,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":252,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":261,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":261,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":275,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":275,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":287,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":287,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":296,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":296,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":310,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":310,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":322,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":322,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":331,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":331,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/SimPlatformMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":28,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":28,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":60,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":60,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":73,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":73,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":84,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":84,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":94,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":94,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":113,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":113,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":123,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":123,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":142,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":142,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":152,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":152,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":171,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":171,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":181,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":181,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":194,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":194,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/StandingsTableMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":25,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":25,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":34,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":34,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":66,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":66,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":77,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":77,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":91,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":91,"endColumn":62,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":125,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":125,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":136,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":136,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":144,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":144,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":153,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":153,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":157,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":157,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":164,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":164,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":172,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":172,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":217,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":217,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":236,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":236,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":289,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":289,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/TeamCompetitionMockup.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":49,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":49,"endColumn":65,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":60,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":65,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":71,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":71,"endColumn":140,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":80,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":80,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":89,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":89,"endColumn":94,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":116,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":116,"endColumn":65,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":128,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":132,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":145,"column":25,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":145,"endColumn":100,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":211,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":211,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":252,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":252,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":265,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":269,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":275,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":275,"endColumn":138,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":284,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":284,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":295,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":297,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":307,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":307,"endColumn":109,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":320,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":320,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":361,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":361,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":373,"column":19,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":377,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":391,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":391,"endColumn":67,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":402,"column":23,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":402,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":417,"column":21,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":419,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/mockups/WorkflowMockup.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/notifications/ModalNotification.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":182,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":182,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":192,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":192,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":204,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":204,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":214,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":214,"endColumn":119,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":234,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":234,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":264,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":264,"endColumn":102,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":327,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":327,"endColumn":185,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/notifications/NotificationCenter.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":125,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":125,"endColumn":61,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":193,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":193,"endColumn":64,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":215,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":215,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":234,"column":31,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":234,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":243,"column":35,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":243,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":264,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":264,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/notifications/NotificationProvider.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/notifications/ToastNotification.tsx","messages":[],"suppressedMessages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":118,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":118,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":120,"column":13,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":120,"endColumn":67,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/notifications/notificationTypes.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/onboarding/AvatarStep.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/onboarding/OnboardingWizard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/onboarding/PersonalInfoStep.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/profile/UserPill.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/FileProtestModal.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/ImportResultsForm.tsx","messages":[],"suppressedMessages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":34,"column":46,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":34,"endColumn":49,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1172,1175],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1172,1175],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}],"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/LatestResultsSidebar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/LiveRacesBanner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/NextRaceCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceEntryList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceFilterBar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceListItem.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":70,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":70,"endColumn":105},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":78,"column":57,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":78,"endColumn":95}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { ArrowRight, Car, ChevronRight, LucideIcon, Trophy, Zap } from 'lucide-react';\nimport { Badge } from '@/ui/Badge';\nimport { Box } from '@/ui/Box';\nimport { Heading } from '@/ui/Heading';\nimport { Icon } from '@/ui/Icon';\nimport { Link } from '@/ui/Link';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\ninterface RaceListItemProps {\n track: string;\n car: string;\n timeLabel?: string;\n relativeTimeLabel?: string;\n dateLabel?: string;\n dayLabel?: string;\n status: string;\n leagueName?: string | null;\n leagueHref?: string;\n strengthOfField?: number | null;\n onClick: () => void;\n statusConfig: {\n icon: LucideIcon;\n variant: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';\n label: string;\n };\n}\n\nexport function RaceListItem({\n track,\n car,\n timeLabel,\n relativeTimeLabel,\n dateLabel,\n dayLabel,\n status,\n leagueName,\n leagueHref,\n strengthOfField,\n onClick,\n statusConfig,\n}: RaceListItemProps) {\n const StatusIcon = statusConfig.icon;\n\n return (\n <Box\n onClick={onClick}\n position=\"relative\"\n overflow=\"hidden\"\n rounded=\"xl\"\n bg=\"bg-iron-gray\"\n border\n borderColor=\"border-charcoal-outline\"\n p={4}\n cursor=\"pointer\"\n transition\n hoverScale\n group\n >\n {/* Live indicator */}\n {status === 'running' && (\n <Box \n position=\"absolute\" \n top=\"0\" \n left=\"0\" \n right=\"0\" \n h=\"1\" \n style={{ background: 'linear-gradient(to right, #10b981, rgba(16, 185, 129, 0.5), #10b981)' }} \n />\n )}\n\n <Stack direction=\"row\" align=\"center\" gap={4}>\n {/* Time/Date Column */}\n <Box flexShrink={0} textAlign=\"center\" minWidth=\"60px\">\n {dateLabel && (\n <Text size=\"xs\" color=\"text-gray-500\" block style={{ textTransform: 'uppercase' }}>\n {dateLabel}\n </Text>\n )}\n <Text size={dayLabel ? \"2xl\" : \"lg\"} weight=\"bold\" color=\"text-white\" block>\n {dayLabel || timeLabel}\n </Text>\n <Text size=\"xs\" color={status === 'running' ? 'text-performance-green' : 'text-gray-400'} block>\n {status === 'running' ? 'LIVE' : relativeTimeLabel || timeLabel}\n </Text>\n </Box>\n\n {/* Divider */}\n <Box w=\"px\" h=\"10\" alignSelf=\"stretch\" bg=\"bg-charcoal-outline\" />\n\n {/* Main Content */}\n <Box flexGrow={1} minWidth=\"0\">\n <Stack direction=\"row\" align=\"start\" justify=\"between\" gap={4}>\n <Box minWidth=\"0\">\n <Heading level={3} truncate>\n {track}\n </Heading>\n <Stack direction=\"row\" align=\"center\" gap={3} mt={1}>\n <Stack direction=\"row\" align=\"center\" gap={1}>\n <Icon icon={Car} size={3.5} color=\"rgb(156, 163, 175)\" />\n <Text size=\"sm\" color=\"text-gray-400\">{car}</Text>\n </Stack>\n {strengthOfField && (\n <Stack direction=\"row\" align=\"center\" gap={1}>\n <Icon icon={Zap} size={3.5} color=\"rgb(245, 158, 11)\" />\n <Text size=\"sm\" color=\"text-gray-400\">SOF {strengthOfField}</Text>\n </Stack>\n )}\n </Stack>\n </Box>\n\n {/* Status Badge */}\n <Badge variant={statusConfig.variant}>\n <Icon icon={StatusIcon} size={3.5} />\n {statusConfig.label}\n </Badge>\n </Stack>\n\n {/* League Link */}\n {leagueName && leagueHref && (\n <Box mt={3} pt={3} borderTop borderColor=\"border-charcoal-outline\" bgOpacity={0.5}>\n <Link\n href={leagueHref}\n onClick={(e) => e.stopPropagation()}\n variant=\"primary\"\n size=\"sm\"\n >\n <Icon icon={Trophy} size={3.5} mr={2} />\n {leagueName}\n <Icon icon={ArrowRight} size={3} ml={2} />\n </Link>\n </Box>\n )}\n </Box>\n\n {/* Arrow */}\n <Icon icon={ChevronRight} size={5} color=\"rgb(115, 115, 115)\" flexShrink={0} />\n </Stack>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceListItemWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceResultCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceResultRow.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":48,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":48,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":49,"column":7,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":49,"endColumn":142},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":59,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":59,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":66,"column":132,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":66,"endColumn":175},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":69,"column":143,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":69,"endColumn":175},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":94,"column":32,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":94,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":100,"column":129,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":100,"endColumn":159}],"suppressedMessages":[],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';\nimport { Box } from '@/ui/Box';\nimport { Image } from '@/ui/Image';\nimport { Stack } from '@/ui/Stack';\nimport { Surface } from '@/ui/Surface';\nimport { Text } from '@/ui/Text';\n\ninterface ResultEntry {\n position: number;\n driverId: string;\n driverName: string;\n driverAvatar: string;\n country: string;\n car: string;\n laps: number;\n time: string;\n fastestLap: string;\n points: number;\n incidents: number;\n isCurrentUser: boolean;\n}\n\ninterface RaceResultRowProps {\n result: ResultEntry;\n points: number;\n}\n\nexport function RaceResultRow({ result, points }: RaceResultRowProps) {\n const { isCurrentUser, position, driverAvatar, driverName, country, car, laps, incidents, time, fastestLap } = result;\n\n const getPositionColor = (pos: number) => {\n if (pos === 1) return { bg: 'bg-yellow-500/20', color: 'text-yellow-400' };\n if (pos === 2) return { bg: 'bg-gray-400/20', color: 'text-gray-300' };\n if (pos === 3) return { bg: 'bg-amber-600/20', color: 'text-amber-600' };\n return { bg: 'bg-iron-gray/50', color: 'text-gray-500' };\n };\n\n const posConfig = getPositionColor(position);\n\n return (\n <Surface\n variant={isCurrentUser ? 'muted' : 'dark'}\n rounded=\"xl\"\n border={isCurrentUser}\n padding={3}\n className={isCurrentUser ? 'border-primary-blue/40' : ''}\n style={isCurrentUser ? { background: 'linear-gradient(to right, rgba(59, 130, 246, 0.2), rgba(59, 130, 246, 0.1), transparent)' } : {}}\n >\n <Stack direction=\"row\" align=\"center\" gap={3}>\n {/* Position */}\n <Box \n width=\"10\" \n height=\"10\" \n rounded=\"lg\" \n display=\"flex\" \n center \n className={`${posConfig.bg} ${posConfig.color}`}\n >\n <Text weight=\"bold\">{position}</Text>\n </Box>\n\n {/* Avatar */}\n <Box position=\"relative\" flexShrink={0}>\n <Box width=\"10\" height=\"10\" rounded=\"full\" overflow=\"hidden\" border={isCurrentUser} borderColor=\"border-primary-blue/50\" className={isCurrentUser ? 'border-2' : ''}>\n <Image src={driverAvatar} alt={driverName} width={40} height={40} fullWidth fullHeight objectFit=\"cover\" />\n </Box>\n <Box position=\"absolute\" bottom=\"-0.5\" right=\"-0.5\" width=\"5\" height=\"5\" rounded=\"full\" bg=\"bg-deep-graphite\" display=\"flex\" center style={{ fontSize: '0.625rem' }}>\n {CountryFlagDisplay.fromCountryCode(country).toString()}\n </Box>\n </Box>\n\n {/* Driver Info */}\n <Box flexGrow={1} minWidth=\"0\">\n <Stack direction=\"row\" align=\"center\" gap={2}>\n <Text weight=\"semibold\" size=\"sm\" color={isCurrentUser ? 'text-primary-blue' : 'text-white'} truncate>{driverName}</Text>\n {isCurrentUser && (\n <Box px={2} py={0.5} rounded=\"full\" bg=\"bg-primary-blue\">\n <Text size=\"xs\" weight=\"bold\" color=\"text-white\">YOU</Text>\n </Box>\n )}\n </Stack>\n <Stack direction=\"row\" align=\"center\" gap={2} mt={1}>\n <Text size=\"xs\" color=\"text-gray-500\">{car}</Text>\n <Text size=\"xs\" color=\"text-gray-500\">•</Text>\n <Text size=\"xs\" color=\"text-gray-500\">Laps: {laps}</Text>\n <Text size=\"xs\" color=\"text-gray-500\">•</Text>\n <Text size=\"xs\" color=\"text-gray-500\">Incidents: {incidents}</Text>\n </Stack>\n </Box>\n\n {/* Times */}\n <Box textAlign=\"right\" style={{ minWidth: '100px' }}>\n <Text size=\"sm\" font=\"mono\" color=\"text-white\" block>{time}</Text>\n <Text size=\"xs\" color=\"text-performance-green\" block mt={1}>FL: {fastestLap}</Text>\n </Box>\n\n {/* Points */}\n <Box p={2} rounded=\"lg\" border={true} borderColor=\"border-warning-amber/20\" bg=\"bg-warning-amber/10\" textAlign=\"center\" style={{ minWidth: '3.5rem' }}>\n <Text size=\"xs\" color=\"text-gray-500\" block>PTS</Text>\n <Text size=\"sm\" weight=\"bold\" color=\"text-warning-amber\">{points}</Text>\n </Box>\n </Stack>\n </Surface>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/RaceSidebar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/UpcomingRaces.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/UpcomingRacesList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/races/UpcomingRacesSidebar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/CapabilityGate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/CountrySelect.tsx","messages":[{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":109,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":189,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":109,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":109,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":29,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":109,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":111,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":133,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":111,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":120,"endColumn":8},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":115,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":119,"endColumn":97},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":121,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":131,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":121,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":121,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":121,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":121,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":122,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":122,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":124,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":127,"endColumn":20},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":124,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":124,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":124,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":124,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":126,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":126,"endColumn":21},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":129,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":129,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":129,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":129,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":129,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":129,"endColumn":44},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":132,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":132,"endColumn":108},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":137,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":182,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":137,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":137,"endColumn":142},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":137,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":137,"endColumn":141},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":139,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":151,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":139,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":139,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":139,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":139,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":140,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":150,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":140,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":140,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":140,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":140,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":141,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":141,"endColumn":97},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":142,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":149,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":142,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":149,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":148,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":148,"endColumn":188},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":154,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":181,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":154,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":154,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":154,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":154,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":157,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":174,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":157,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":166,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":161,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":165,"endColumn":22},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":167,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":170,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":167,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":167,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":167,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":167,"endColumn":60},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":169,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":169,"endColumn":27},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":172,"column":28,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":172,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":177,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":179,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":177,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":177,"endColumn":76},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":177,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":177,"endColumn":75},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":187,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":187,"endColumn":74},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":187,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":187,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":187,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":187,"endColumn":55}],"suppressedMessages":[],"errorCount":48,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { Check, ChevronDown, Globe, Search } from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\nimport { CountryFlag } from '@/ui/CountryFlag';\n\nexport interface Country {\n code: string;\n name: string;\n}\n\nexport const COUNTRIES: Country[] = [\n { code: 'US', name: 'United States' },\n { code: 'GB', name: 'United Kingdom' },\n { code: 'DE', name: 'Germany' },\n { code: 'NL', name: 'Netherlands' },\n { code: 'FR', name: 'France' },\n { code: 'IT', name: 'Italy' },\n { code: 'ES', name: 'Spain' },\n { code: 'AU', name: 'Australia' },\n { code: 'CA', name: 'Canada' },\n { code: 'BR', name: 'Brazil' },\n { code: 'JP', name: 'Japan' },\n { code: 'BE', name: 'Belgium' },\n { code: 'AT', name: 'Austria' },\n { code: 'CH', name: 'Switzerland' },\n { code: 'SE', name: 'Sweden' },\n { code: 'NO', name: 'Norway' },\n { code: 'DK', name: 'Denmark' },\n { code: 'FI', name: 'Finland' },\n { code: 'PL', name: 'Poland' },\n { code: 'PT', name: 'Portugal' },\n { code: 'CZ', name: 'Czech Republic' },\n { code: 'HU', name: 'Hungary' },\n { code: 'RU', name: 'Russia' },\n { code: 'MX', name: 'Mexico' },\n { code: 'AR', name: 'Argentina' },\n { code: 'CL', name: 'Chile' },\n { code: 'NZ', name: 'New Zealand' },\n { code: 'ZA', name: 'South Africa' },\n { code: 'IN', name: 'India' },\n { code: 'KR', name: 'South Korea' },\n { code: 'SG', name: 'Singapore' },\n { code: 'MY', name: 'Malaysia' },\n { code: 'TH', name: 'Thailand' },\n { code: 'AE', name: 'United Arab Emirates' },\n { code: 'SA', name: 'Saudi Arabia' },\n { code: 'IE', name: 'Ireland' },\n { code: 'GR', name: 'Greece' },\n { code: 'TR', name: 'Turkey' },\n { code: 'RO', name: 'Romania' },\n { code: 'UA', name: 'Ukraine' },\n];\n\ninterface CountrySelectProps {\n value: string;\n onChange: (value: string) => void;\n error?: boolean;\n errorMessage?: string;\n disabled?: boolean;\n placeholder?: string;\n}\n\nexport function CountrySelect({\n value,\n onChange,\n error,\n errorMessage,\n disabled,\n placeholder = 'Select country',\n}: CountrySelectProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [search, setSearch] = useState('');\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const selectedCountry = COUNTRIES.find(c => c.code === value);\n\n const filteredCountries = COUNTRIES.filter(country =>\n country.name.toLowerCase().includes(search.toLowerCase()) ||\n country.code.toLowerCase().includes(search.toLowerCase())\n );\n\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n setSearch('');\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n useEffect(() => {\n if (isOpen && inputRef.current) {\n inputRef.current.focus();\n }\n }, [isOpen]);\n\n const handleSelect = (code: string) => {\n onChange(code);\n setIsOpen(false);\n setSearch('');\n };\n\n return (\n <div ref={containerRef} className=\"relative\">\n {/* Trigger Button */}\n <button\n type=\"button\"\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n className={`flex items-center justify-between w-full rounded-md border-0 px-4 py-3 bg-iron-gray text-white shadow-sm ring-1 ring-inset transition-all duration-150 sm:text-sm ${\n error\n ? 'ring-warning-amber focus:ring-warning-amber'\n : 'ring-charcoal-outline focus:ring-primary-blue'\n } ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:ring-gray-500'}`}\n >\n <div className=\"flex items-center gap-3\">\n <Globe className=\"w-4 h-4 text-gray-500\" />\n {selectedCountry ? (\n <span className=\"flex items-center gap-2\">\n <CountryFlag countryCode={selectedCountry.code} size=\"md\" showTooltip={false} />\n <span>{selectedCountry.name}</span>\n </span>\n ) : (\n <span className=\"text-gray-500\">{placeholder}</span>\n )}\n </div>\n <ChevronDown className={`w-4 h-4 text-gray-500 transition-transform ${isOpen ? 'rotate-180' : ''}`} />\n </button>\n\n {/* Dropdown */}\n {isOpen && (\n <div className=\"absolute z-50 mt-2 w-full rounded-lg bg-iron-gray border border-charcoal-outline shadow-xl max-h-80 overflow-hidden\">\n {/* Search Input */}\n <div className=\"p-2 border-b border-charcoal-outline\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-500\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search countries...\"\n className=\"w-full rounded-md border-0 px-4 py-2 pl-9 bg-deep-graphite text-white text-sm placeholder:text-gray-500 focus:outline-none focus:ring-1 focus:ring-primary-blue\"\n />\n </div>\n </div>\n\n {/* Country List */}\n <div className=\"overflow-y-auto max-h-60\">\n {filteredCountries.length > 0 ? (\n filteredCountries.map((country) => (\n <button\n key={country.code}\n type=\"button\"\n onClick={() => handleSelect(country.code)}\n className={`flex items-center justify-between w-full px-4 py-2.5 text-left text-sm transition-colors ${\n value === country.code\n ? 'bg-primary-blue/20 text-white'\n : 'text-gray-300 hover:bg-deep-graphite'\n }`}\n >\n <span className=\"flex items-center gap-3\">\n <CountryFlag countryCode={country.code} size=\"md\" showTooltip={false} />\n <span>{country.name}</span>\n </span>\n {value === country.code && (\n <Check className=\"w-4 h-4 text-primary-blue\" />\n )}\n </button>\n ))\n ) : (\n <div className=\"px-4 py-6 text-center text-gray-500 text-sm\">\n No countries found\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Error Message */}\n {error && errorMessage && (\n <p className=\"mt-2 text-sm text-warning-amber\">{errorMessage}</p>\n )}\n </div>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/ModeGuard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/RangeField.tsx","messages":[{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":126,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":162,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":126,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":126,"endColumn":36},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":126,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":126,"endColumn":35},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":127,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":160,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":127,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":127,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":127,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":127,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":128,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":128,"endColumn":88},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":128,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":128,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":128,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":128,"endColumn":72},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":129,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":159,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":129,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":129,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":129,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":129,"endColumn":72},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":130,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":154,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":130,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":136,"endColumn":14},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":132,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":132,"endColumn":125},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":138,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":138,"endColumn":122},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":138,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":138,"endColumn":122},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":138,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":138,"endColumn":119},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":140,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":143,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":140,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":143,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":141,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":141,"endColumn":131},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":142,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":142,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":145,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":153,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":145,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":153,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":146,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":151,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":152,"column":17,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":152,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":155,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":158,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":155,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":155,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":155,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":155,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":156,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":156,"endColumn":102},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":156,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":156,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":156,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":156,"endColumn":80},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":157,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":157,"endColumn":77},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":157,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":157,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":157,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":157,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":161,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":161,"endColumn":76},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":161,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":161,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":161,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":161,"endColumn":64},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":167,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":269,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":167,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":167,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":167,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":167,"endColumn":31},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":168,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":171,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":168,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":168,"endColumn":66},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":168,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":168,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":169,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":169,"endColumn":83},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":169,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":169,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":169,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":169,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":170,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":170,"endColumn":80},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":170,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":170,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":170,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":170,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":174,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":177,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":174,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":174,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":174,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":174,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":175,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":175,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":175,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":175,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":175,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":175,"endColumn":71},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":176,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":176,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":176,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":176,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":176,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":176,"endColumn":50},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":181,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":220,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":181,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":187,"endColumn":8},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":183,"column":9,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":183,"endColumn":124},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":189,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":189,"endColumn":117},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":189,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":189,"endColumn":117},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":189,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":189,"endColumn":114},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":192,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":195,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":192,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":195,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":193,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":193,"endColumn":155},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":194,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":194,"endColumn":48},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":198,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":207,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":198,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":198,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":198,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":198,"endColumn":100},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":200,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":205,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":200,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":205,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":202,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":204,"endColumn":18},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":210,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":219,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":210,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":219,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":211,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":217,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":218,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":218,"endColumn":47},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":223,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":265,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":223,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":223,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":223,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":223,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":224,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":245,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":224,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":224,"endColumn":50},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":224,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":224,"endColumn":49},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":225,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":243,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":225,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":243,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":235,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":242,"endColumn":15},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":244,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":244,"endColumn":69},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":244,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":244,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":244,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":244,"endColumn":50},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":248,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":263,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":248,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":248,"endColumn":39},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":248,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":248,"endColumn":38},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":250,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":261,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":250,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":259,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":258,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":258,"endColumn":156},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":267,"column":22,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":267,"endColumn":75},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":267,"column":22,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":267,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":267,"column":25,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":267,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":268,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":268,"endColumn":70},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":268,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":268,"endColumn":59},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":268,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":268,"endColumn":58}],"suppressedMessages":[],"errorCount":103,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\ninterface RangeFieldProps {\n label: string;\n value: number;\n min: number;\n max: number;\n step?: number;\n onChange: (value: number) => void;\n helperText?: string;\n error?: string | undefined;\n disabled?: boolean;\n unitLabel?: string;\n rangeHint?: string;\n /** Show large value display above slider */\n showLargeValue?: boolean;\n /** Compact mode - single line */\n compact?: boolean;\n}\n\nexport function RangeField({\n label,\n value,\n min,\n max,\n step = 1,\n onChange,\n helperText,\n error,\n disabled,\n unitLabel = 'min',\n rangeHint,\n showLargeValue = false,\n compact = false,\n}: RangeFieldProps) {\n const [localValue, setLocalValue] = useState(value);\n const [isDragging, setIsDragging] = useState(false);\n const sliderRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Sync local value with prop when not dragging\n useEffect(() => {\n if (!isDragging) {\n setLocalValue(value);\n }\n }, [value, isDragging]);\n\n const clampedValue = Number.isFinite(localValue)\n ? Math.min(Math.max(localValue, min), max)\n : min;\n\n const rangePercent = ((clampedValue - min) / Math.max(max - min, 1)) * 100;\n\n const effectiveRangeHint =\n rangeHint ?? (min === 0 ? `Up to ${max} ${unitLabel}` : `${min}–${max} ${unitLabel}`);\n\n const calculateValueFromPosition = useCallback(\n (clientX: number) => {\n if (!sliderRef.current) return clampedValue;\n const rect = sliderRef.current.getBoundingClientRect();\n const percent = Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1);\n const rawValue = min + percent * (max - min);\n const steppedValue = Math.round(rawValue / step) * step;\n return Math.min(Math.max(steppedValue, min), max);\n },\n [min, max, step, clampedValue]\n );\n\n const handlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (disabled) return;\n e.preventDefault();\n setIsDragging(true);\n const newValue = calculateValueFromPosition(e.clientX);\n setLocalValue(newValue);\n onChange(newValue);\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n },\n [disabled, calculateValueFromPosition, onChange]\n );\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (!isDragging || disabled) return;\n const newValue = calculateValueFromPosition(e.clientX);\n setLocalValue(newValue);\n onChange(newValue);\n },\n [isDragging, disabled, calculateValueFromPosition, onChange]\n );\n\n const handlePointerUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value;\n if (raw === '') {\n setLocalValue(min);\n return;\n }\n const parsed = parseInt(raw, 10);\n if (!Number.isNaN(parsed)) {\n const clamped = Math.min(Math.max(parsed, min), max);\n setLocalValue(clamped);\n onChange(clamped);\n }\n };\n\n const handleInputBlur = () => {\n // Ensure value is synced on blur\n onChange(clampedValue);\n };\n\n // Quick preset buttons for common values\n const quickPresets = [\n Math.round(min + (max - min) * 0.25),\n Math.round(min + (max - min) * 0.5),\n Math.round(min + (max - min) * 0.75),\n ].filter((v, i, arr) => arr.indexOf(v) === i && v !== clampedValue);\n\n if (compact) {\n return (\n <div className=\"space-y-1.5\">\n <div className=\"flex items-center justify-between gap-3\">\n <label className=\"text-xs font-medium text-gray-400 shrink-0\">{label}</label>\n <div className=\"flex items-center gap-2 flex-1 max-w-[200px]\">\n <div\n ref={sliderRef}\n className={`relative flex-1 h-6 cursor-pointer touch-none ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n >\n {/* Track background */}\n <div className=\"absolute top-1/2 -translate-y-1/2 left-0 right-0 h-1.5 rounded-full bg-charcoal-outline\" />\n {/* Track fill */}\n <div\n className=\"absolute top-1/2 -translate-y-1/2 left-0 h-1.5 rounded-full bg-primary-blue transition-all duration-75\"\n style={{ width: `${rangePercent}%` }}\n />\n {/* Thumb */}\n <div\n className={`\n absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-4 h-4 rounded-full\n bg-white border-2 border-primary-blue shadow-md\n transition-transform duration-75\n ${isDragging ? 'scale-125 shadow-[0_0_12px_rgba(25,140,255,0.5)]' : ''}\n `}\n style={{ left: `${rangePercent}%` }}\n />\n </div>\n <div className=\"flex items-center gap-1 shrink-0\">\n <span className=\"text-sm font-semibold text-white w-8 text-right\">{clampedValue}</span>\n <span className=\"text-[10px] text-gray-500\">{unitLabel}</span>\n </div>\n </div>\n </div>\n {error && <p className=\"text-[10px] text-warning-amber\">{error}</p>}\n </div>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-baseline justify-between gap-2\">\n <label className=\"block text-sm font-medium text-gray-300\">{label}</label>\n <span className=\"text-[10px] text-gray-500\">{effectiveRangeHint}</span>\n </div>\n\n {showLargeValue && (\n <div className=\"flex items-baseline gap-1\">\n <span className=\"text-3xl font-bold text-white tabular-nums\">{clampedValue}</span>\n <span className=\"text-sm text-gray-400\">{unitLabel}</span>\n </div>\n )}\n\n {/* Custom slider */}\n <div\n ref={sliderRef}\n className={`relative h-8 cursor-pointer touch-none select-none ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n >\n {/* Track background */}\n <div className=\"absolute top-1/2 -translate-y-1/2 left-0 right-0 h-2 rounded-full bg-charcoal-outline/80\" />\n \n {/* Track fill with gradient */}\n <div\n className=\"absolute top-1/2 -translate-y-1/2 left-0 h-2 rounded-full bg-gradient-to-r from-primary-blue to-neon-aqua transition-all duration-75\"\n style={{ width: `${rangePercent}%` }}\n />\n\n {/* Tick marks */}\n <div className=\"absolute top-1/2 -translate-y-1/2 left-0 right-0 flex justify-between px-1\">\n {[0, 25, 50, 75, 100].map((tick) => (\n <div\n key={tick}\n className={`w-0.5 h-1 rounded-full transition-colors ${\n rangePercent >= tick ? 'bg-white/40' : 'bg-charcoal-outline'\n }`}\n />\n ))}\n </div>\n\n {/* Thumb */}\n <div\n className={`\n absolute top-1/2 -translate-y-1/2 -translate-x-1/2\n w-5 h-5 rounded-full bg-white border-2 border-primary-blue\n shadow-[0_2px_8px_rgba(0,0,0,0.3)]\n transition-all duration-75\n ${isDragging ? 'scale-125 shadow-[0_0_16px_rgba(25,140,255,0.6)]' : 'hover:scale-110'}\n `}\n style={{ left: `${rangePercent}%` }}\n />\n </div>\n\n {/* Value input and quick presets */}\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <input\n ref={inputRef}\n type=\"number\"\n min={min}\n max={max}\n step={step}\n value={clampedValue}\n onChange={handleInputChange}\n onBlur={handleInputBlur}\n disabled={disabled}\n className={`\n w-16 px-2 py-1.5 text-sm font-medium text-center rounded-lg\n bg-iron-gray border border-charcoal-outline text-white\n focus:border-primary-blue focus:ring-1 focus:ring-primary-blue focus:outline-none\n transition-colors\n ${error ? 'border-warning-amber' : ''}\n ${disabled ? 'opacity-50 cursor-not-allowed' : ''}\n `}\n />\n <span className=\"text-xs text-gray-400\">{unitLabel}</span>\n </div>\n\n {quickPresets.length > 0 && (\n <div className=\"flex gap-1\">\n {quickPresets.slice(0, 3).map((preset) => (\n <button\n key={preset}\n type=\"button\"\n onClick={() => {\n setLocalValue(preset);\n onChange(preset);\n }}\n disabled={disabled}\n className=\"px-2 py-1 text-[10px] rounded bg-charcoal-outline/50 text-gray-400 hover:bg-charcoal-outline hover:text-white transition-colors\"\n >\n {preset}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {helperText && <p className=\"text-xs text-gray-500\">{helperText}</p>}\n {error && <p className=\"text-xs text-warning-amber\">{error}</p>}\n </div>\n );\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/state/EmptyState.tsx","messages":[{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":9,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":15,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":9,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":9,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":9,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":9,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":10,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":10,"endColumn":96},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":11,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":11,"endColumn":96},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":12,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":12,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":13,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":13,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":14,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":14,"endColumn":113},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":18,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":23,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":18,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":18,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":18,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":18,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":19,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":19,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":20,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":20,"endColumn":89},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":21,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":21,"endColumn":99},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":22,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":22,"endColumn":99},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":26,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":31,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":26,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":26,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":26,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":26,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":27,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":27,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":28,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":28,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":29,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":29,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":30,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":30,"endColumn":120},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":34,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":38,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":34,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":34,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":34,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":34,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":35,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":35,"endColumn":92},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":36,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":36,"endColumn":122},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":37,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":37,"endColumn":98},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":41,"column":5,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":47,"endColumn":11},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":41,"column":5,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":41,"endColumn":101},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":41,"column":10,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":41,"endColumn":31},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":42,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":42,"endColumn":72},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":43,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":43,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":44,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":44,"endColumn":106},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":45,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":45,"endColumn":58},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":46,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":46,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":78,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":88,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":78,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":78,"endColumn":49},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":78,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":78,"endColumn":48},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":80,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":82,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":80,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":80,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":80,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":80,"endColumn":41},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":84,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":86,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":84,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":84,"endColumn":133},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":84,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":84,"endColumn":132},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":85,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":85,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":91,"column":7,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":93,"endColumn":12},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":91,"column":7,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":91,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":91,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":91,"endColumn":72},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":97,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":99,"endColumn":13},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":97,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":97,"endColumn":71},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":97,"column":12,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":97,"endColumn":70},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":104,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":115,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":104,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":104,"endColumn":46},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":104,"column":14,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":104,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":108,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":108,"endColumn":38},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":111,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":111,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":111,"column":28,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":111,"endColumn":52},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":124,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":133,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":124,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":129,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":125,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":125,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":130,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":132,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":130,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":130,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":130,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":130,"endColumn":44},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":138,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":169,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":138,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":143,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":139,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":139,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":144,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":168,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":144,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":144,"endColumn":55},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":144,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":144,"endColumn":54},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":147,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":149,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":147,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":147,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":147,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":147,"endColumn":51},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":148,"column":23,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":148,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":151,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":153,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":151,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":151,"endColumn":63},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":151,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":151,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":155,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":157,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":155,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":155,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":155,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":155,"endColumn":51},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":160,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":166,"endColumn":24},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":160,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":163,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":162,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":162,"endColumn":122},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":165,"column":33,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":165,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":165,"column":46,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":165,"endColumn":65},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":174,"column":9,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":231,"endColumn":15},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":174,"column":9,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":179,"endColumn":10},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":175,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":175,"endColumn":105},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":180,"column":11,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":230,"endColumn":17},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":180,"column":11,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":180,"endColumn":56},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":180,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":180,"endColumn":55},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":181,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":193,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":181,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":181,"endColumn":35},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":181,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":181,"endColumn":34},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":183,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":185,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":183,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":183,"endColumn":68},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":183,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":183,"endColumn":67},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":187,"column":17,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":191,"endColumn":23},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":187,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":187,"endColumn":54},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":187,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":187,"endColumn":53},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":188,"column":19,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":190,"endColumn":25},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":188,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":188,"endColumn":141},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":188,"column":24,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":188,"endColumn":140},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":189,"column":27,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":189,"endColumn":62},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":195,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":197,"endColumn":18},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":195,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":195,"endColumn":64},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":195,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":195,"endColumn":63},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":200,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":202,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":200,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":200,"endColumn":73},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":200,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":200,"endColumn":72},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":206,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":217,"endColumn":21},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":206,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":206,"endColumn":79},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":206,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":206,"endColumn":78},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":210,"column":19,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":210,"endColumn":44},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":213,"column":21,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":213,"endColumn":61},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":213,"column":34,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":213,"endColumn":58},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":221,"column":13,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":229,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":221,"column":13,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":221,"endColumn":57},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":221,"column":18,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":221,"endColumn":56},{"ruleId":"gridpilot-rules/no-raw-html-in-app","severity":2,"message":"Raw HTML in components/ should use ui/ elements instead.","line":223,"column":15,"nodeType":"JSXElement","messageId":"noRawHtmlInComponents","endLine":228,"endColumn":19},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":223,"column":15,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":226,"endColumn":16},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":225,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":225,"endColumn":62},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":250,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":250,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":267,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":267,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":283,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":283,"endColumn":28}],"suppressedMessages":[],"errorCount":125,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { Button } from '@/ui/Button';\nimport { EmptyStateProps } from '@/ui/state-types';\n\n// Illustration components (simple SVG representations)\nconst Illustrations = {\n racing: () => (\n <svg className=\"w-20 h-20\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 70 L80 70 L85 50 L80 30 L20 30 L15 50 Z\" fill=\"currentColor\" opacity=\"0.2\"/>\n <path d=\"M30 60 L70 60 L75 50 L70 40 L30 40 L25 50 Z\" fill=\"currentColor\" opacity=\"0.4\"/>\n <circle cx=\"35\" cy=\"65\" r=\"3\" fill=\"currentColor\"/>\n <circle cx=\"65\" cy=\"65\" r=\"3\" fill=\"currentColor\"/>\n <path d=\"M50 30 L50 20 M45 25 L50 20 L55 25\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\"/>\n </svg>\n ),\n league: () => (\n <svg className=\"w-20 h-20\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"50\" cy=\"35\" r=\"15\" fill=\"currentColor\" opacity=\"0.3\"/>\n <path d=\"M35 50 L50 45 L65 50 L65 70 L35 70 Z\" fill=\"currentColor\" opacity=\"0.2\"/>\n <path d=\"M40 55 L50 52 L60 55\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\"/>\n <path d=\"M40 62 L50 59 L60 62\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\"/>\n </svg>\n ),\n team: () => (\n <svg className=\"w-20 h-20\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"35\" cy=\"35\" r=\"8\" fill=\"currentColor\" opacity=\"0.3\"/>\n <circle cx=\"65\" cy=\"35\" r=\"8\" fill=\"currentColor\" opacity=\"0.3\"/>\n <circle cx=\"50\" cy=\"55\" r=\"10\" fill=\"currentColor\" opacity=\"0.2\"/>\n <path d=\"M35 45 L35 60 M65 45 L65 60 M50 65 L50 80\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\"/>\n </svg>\n ),\n sponsor: () => (\n <svg className=\"w-20 h-20\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"25\" y=\"25\" width=\"50\" height=\"50\" rx=\"8\" fill=\"currentColor\" opacity=\"0.2\"/>\n <path d=\"M35 50 L45 60 L65 40\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n <path d=\"M50 35 L50 65 M40 50 L60 50\" stroke=\"currentColor\" strokeWidth=\"2\" opacity=\"0.5\"/>\n </svg>\n ),\n driver: () => (\n <svg className=\"w-20 h-20\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"50\" cy=\"30\" r=\"8\" fill=\"currentColor\" opacity=\"0.3\"/>\n <path d=\"M42 38 L58 38 L55 55 L45 55 Z\" fill=\"currentColor\" opacity=\"0.2\"/>\n <path d=\"M45 55 L40 70 M55 55 L60 70\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\"/>\n <circle cx=\"40\" cy=\"72\" r=\"3\" fill=\"currentColor\"/>\n <circle cx=\"60\" cy=\"72\" r=\"3\" fill=\"currentColor\"/>\n </svg>\n ),\n} as const;\n\n/**\n * EmptyState Component\n * \n * Provides consistent empty/placeholder states with 3 variants:\n * - default: Standard empty state with icon, title, description, and action\n * - minimal: Simple version without extra styling\n * - full-page: Full page empty state with centered layout\n * \n * Supports both icons and illustrations for visual appeal.\n */\nexport function EmptyState({\n icon: Icon,\n title,\n description,\n action,\n variant = 'default',\n className = '',\n illustration,\n ariaLabel = 'Empty state',\n}: EmptyStateProps) {\n // Render illustration if provided\n const IllustrationComponent = illustration ? Illustrations[illustration] : null;\n\n // Common content\n const Content = () => (\n <>\n {/* Visual - Icon or Illustration */}\n <div className=\"flex justify-center mb-4\">\n {IllustrationComponent ? (\n <div className=\"text-gray-500\">\n <IllustrationComponent />\n </div>\n ) : Icon ? (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-iron-gray/60 border border-charcoal-outline/50\">\n <Icon className=\"w-8 h-8 text-gray-500\" />\n </div>\n ) : null}\n </div>\n\n {/* Title */}\n <h3 className=\"text-xl font-semibold text-white mb-2 text-center\">\n {title}\n </h3>\n\n {/* Description */}\n {description && (\n <p className=\"text-gray-400 mb-6 text-center leading-relaxed\">\n {description}\n </p>\n )}\n\n {/* Action Button */}\n {action && (\n <div className=\"flex justify-center\">\n <Button\n variant={action.variant || 'primary'}\n onClick={action.onClick}\n className=\"min-w-[140px]\"\n >\n {action.icon && (\n <action.icon className=\"w-4 h-4 mr-2\" />\n )}\n {action.label}\n </Button>\n </div>\n )}\n </>\n );\n\n // Render different variants\n switch (variant) {\n case 'default':\n return (\n <div\n className={`text-center py-12 ${className}`}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n <div className=\"max-w-md mx-auto\">\n <Content />\n </div>\n </div>\n );\n\n case 'minimal':\n return (\n <div\n className={`text-center py-8 ${className}`}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n <div className=\"max-w-sm mx-auto space-y-3\">\n {/* Minimal icon */}\n {Icon && (\n <div className=\"flex justify-center\">\n <Icon className=\"w-10 h-10 text-gray-600\" />\n </div>\n )}\n <h3 className=\"text-lg font-medium text-gray-300\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm text-gray-500\">\n {description}\n </p>\n )}\n {action && (\n <button\n onClick={action.onClick}\n className=\"text-sm text-primary-blue hover:text-blue-400 font-medium mt-2 inline-flex items-center gap-1\"\n >\n {action.label}\n {action.icon && <action.icon className=\"w-3 h-3\" />}\n </button>\n )}\n </div>\n </div>\n );\n\n case 'full-page':\n return (\n <div\n className={`fixed inset-0 bg-deep-graphite flex items-center justify-center p-6 ${className}`}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n <div className=\"max-w-lg w-full text-center\">\n <div className=\"mb-6\">\n {IllustrationComponent ? (\n <div className=\"text-gray-500 flex justify-center\">\n <IllustrationComponent />\n </div>\n ) : Icon ? (\n <div className=\"flex justify-center\">\n <div className=\"flex h-20 w-20 items-center justify-center rounded-3xl bg-iron-gray/60 border border-charcoal-outline/50\">\n <Icon className=\"w-10 h-10 text-gray-500\" />\n </div>\n </div>\n ) : null}\n </div>\n \n <h2 className=\"text-3xl font-bold text-white mb-4\">\n {title}\n </h2>\n \n {description && (\n <p className=\"text-gray-400 text-lg mb-8 leading-relaxed\">\n {description}\n </p>\n )}\n\n {action && (\n <div className=\"flex flex-col sm:flex-row gap-3 justify-center\">\n <Button\n variant={action.variant || 'primary'}\n onClick={action.onClick}\n className=\"min-w-[160px]\"\n >\n {action.icon && (\n <action.icon className=\"w-4 h-4 mr-2\" />\n )}\n {action.label}\n </Button>\n </div>\n )}\n\n {/* Additional helper text for full-page variant */}\n <div className=\"mt-8 text-sm text-gray-500\">\n Need help? Contact us at{' '}\n <a \n href=\"mailto:support@gridpilot.com\" \n className=\"text-primary-blue hover:underline\"\n >\n support@gridpilot.com\n </a>\n </div>\n </div>\n </div>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * Convenience component for default empty state\n */\nexport function DefaultEmptyState({ icon, title, description, action, className, illustration }: EmptyStateProps) {\n return (\n <EmptyState\n icon={icon}\n title={title}\n description={description}\n action={action}\n variant=\"default\"\n className={className}\n illustration={illustration}\n />\n );\n}\n\n/**\n * Convenience component for minimal empty state\n */\nexport function MinimalEmptyState({ icon, title, description, action, className }: Omit<EmptyStateProps, 'variant'>) {\n return (\n <EmptyState\n icon={icon}\n title={title}\n description={description}\n action={action}\n variant=\"minimal\"\n className={className}\n />\n );\n}\n\n/**\n * Convenience component for full-page empty state\n */\nexport function FullPageEmptyState({ icon, title, description, action, className, illustration }: EmptyStateProps) {\n return (\n <EmptyState\n icon={icon}\n title={title}\n description={description}\n action={action}\n variant=\"full-page\"\n className={className}\n illustration={illustration}\n />\n );\n}\n\n/**\n * Pre-configured empty states for common scenarios\n */\n\nimport { Activity, Lock, Search } from 'lucide-react';\n\nexport function NoDataEmptyState({ onRetry }: { onRetry?: () => void }) {\n return (\n <EmptyState\n icon={Activity}\n title=\"No data available\"\n description=\"There is nothing to display here at the moment\"\n action={onRetry ? { label: 'Refresh', onClick: onRetry } : undefined}\n variant=\"default\"\n />\n );\n}\n\nexport function NoResultsEmptyState({ onRetry }: { onRetry?: () => void }) {\n return (\n <EmptyState\n icon={Search}\n title=\"No results found\"\n description=\"Try adjusting your search or filters\"\n action={onRetry ? { label: 'Clear Filters', onClick: onRetry } : undefined}\n variant=\"default\"\n />\n );\n}\n\nexport function NoAccessEmptyState({ onBack }: { onBack?: () => void }) {\n return (\n <EmptyState\n icon={Lock}\n title=\"Access denied\"\n description=\"You don't have permission to view this content\"\n action={onBack ? { label: 'Go Back', onClick: onBack } : undefined}\n variant=\"full-page\"\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/state/ErrorDisplay.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":59,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":59,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":84,"column":64,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":84,"endColumn":93},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":105,"column":21,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":105,"endColumn":42},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":115,"column":17,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":115,"endColumn":53},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":115,"column":26,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":115,"endColumn":52},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"Raw HTML tags are forbidden in components and pages. Use UI components from ui/ instead.","line":116,"column":19,"nodeType":"JSXOpeningElement","messageId":"noRawHtml","endLine":116,"endColumn":82},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":116,"column":28,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":116,"endColumn":81},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":119,"column":98,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":119,"endColumn":148},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":137,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":137,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":189,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":189,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":200,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":200,"endColumn":92}],"suppressedMessages":[],"errorCount":11,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { ApiError } from '@/lib/api/base/ApiError';\nimport { AlertCircle, ArrowLeft, Home, RefreshCw } from 'lucide-react';\nimport { Box } from '@/ui/Box';\nimport { Button } from '@/ui/Button';\nimport { Heading } from '@/ui/Heading';\nimport { Icon } from '@/ui/Icon';\nimport { Stack } from '@/ui/Stack';\nimport { ErrorDisplayAction, ErrorDisplayProps } from '@/ui/state-types';\nimport { Surface } from '@/ui/Surface';\nimport { Text } from '@/ui/Text';\n\nexport function ErrorDisplay({\n error,\n onRetry,\n variant = 'full-screen',\n actions = [],\n showRetry = true,\n showNavigation = true,\n hideTechnicalDetails = false,\n className = '',\n}: ErrorDisplayProps) {\n const getErrorInfo = () => {\n const isApiError = error instanceof ApiError;\n \n return {\n title: isApiError ? 'API Error' : 'Unexpected Error',\n message: error.message || 'Something went wrong',\n statusCode: isApiError ? error.context.statusCode : undefined,\n details: isApiError ? error.context.responseText : undefined,\n isApiError,\n };\n };\n\n const errorInfo = getErrorInfo();\n\n const defaultActions: ErrorDisplayAction[] = [\n ...(showRetry && onRetry ? [{ label: 'Retry', onClick: onRetry, variant: 'primary' as const, icon: RefreshCw }] : []),\n ...(showNavigation ? [\n { label: 'Go Back', onClick: () => window.history.back(), variant: 'secondary' as const, icon: ArrowLeft },\n { label: 'Home', onClick: () => window.location.href = '/', variant: 'secondary' as const, icon: Home },\n ] : []),\n ...actions,\n ];\n\n switch (variant) {\n case 'full-screen':\n return (\n <Box\n position=\"fixed\"\n inset=\"0\"\n zIndex={50}\n bg=\"bg-deep-graphite\"\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n p={6}\n className={className}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <Box maxWidth=\"lg\" fullWidth textAlign=\"center\">\n <Box display=\"flex\" justifyContent=\"center\" mb={6}>\n <Box \n display=\"flex\" \n h=\"20\" \n w=\"20\" \n alignItems=\"center\" \n justifyContent=\"center\" \n rounded=\"3xl\" \n bg=\"bg-red-500/10\" \n border={true} \n borderColor=\"border-red-500/30\"\n >\n <Icon icon={AlertCircle} size={10} color=\"text-red-500\" />\n </Box>\n </Box>\n\n <Heading level={2} mb={3}>\n {errorInfo.title}\n </Heading>\n\n <Text size=\"lg\" color=\"text-gray-400\" block mb={6} style={{ lineHeight: 1.625 }}>\n {errorInfo.message}\n </Text>\n\n {errorInfo.isApiError && errorInfo.statusCode && (\n <Box mb={6} display=\"inline-flex\" alignItems=\"center\" gap={2} px={4} py={2} bg=\"bg-iron-gray/40\" rounded=\"lg\">\n <Text size=\"sm\" color=\"text-gray-300\" font=\"mono\">HTTP {errorInfo.statusCode}</Text>\n {errorInfo.details && !hideTechnicalDetails && (\n <Text size=\"sm\" color=\"text-gray-500\">- {errorInfo.details}</Text>\n )}\n </Box>\n )}\n\n {defaultActions.length > 0 && (\n <Stack direction={{ base: 'col', md: 'row' }} gap={3} justify=\"center\">\n {defaultActions.map((action, index) => (\n <Button\n key={index}\n onClick={action.onClick}\n variant={action.variant === 'primary' ? 'danger' : 'secondary'}\n icon={action.icon && <Icon icon={action.icon} size={4} />}\n className=\"px-6 py-3\"\n >\n {action.label}\n </Button>\n ))}\n </Stack>\n )}\n\n {!hideTechnicalDetails && process.env.NODE_ENV === 'development' && error.stack && (\n <Box mt={8} textAlign=\"left\">\n <details className=\"cursor-pointer\">\n <summary className=\"text-sm text-gray-500 hover:text-gray-400\">\n Technical Details\n </summary>\n <Box as=\"pre\" mt={2} p={4} bg=\"bg-black/50\" rounded=\"lg\" color=\"text-gray-400\" style={{ fontSize: '0.75rem', overflowX: 'auto' }}>\n {error.stack}\n </Box>\n </details>\n </Box>\n )}\n </Box>\n </Box>\n );\n\n case 'card':\n return (\n <Surface\n variant=\"muted\"\n border={true}\n borderColor=\"border-red-500/30\"\n rounded=\"xl\"\n p={6}\n className={className}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <Stack direction=\"row\" gap={4} align=\"start\">\n <Icon icon={AlertCircle} size={6} color=\"text-red-500\" />\n <Box flexGrow={1}>\n <Heading level={3} mb={1}>\n {errorInfo.title}\n </Heading>\n <Text size=\"sm\" color=\"text-gray-400\" block mb={3}>\n {errorInfo.message}\n </Text>\n\n {errorInfo.isApiError && errorInfo.statusCode && (\n <Text size=\"xs\" font=\"mono\" color=\"text-gray-500\" block mb={3}>\n HTTP {errorInfo.statusCode}\n {errorInfo.details && !hideTechnicalDetails && ` - ${errorInfo.details}`}\n </Text>\n )}\n\n {defaultActions.length > 0 && (\n <Stack direction=\"row\" gap={2}>\n {defaultActions.map((action, index) => (\n <Button\n key={index}\n onClick={action.onClick}\n variant={action.variant === 'primary' ? 'danger' : 'secondary'}\n size=\"sm\"\n >\n {action.label}\n </Button>\n ))}\n </Stack>\n )}\n </Box>\n </Stack>\n </Surface>\n );\n\n case 'inline':\n return (\n <Box\n display=\"inline-flex\"\n alignItems=\"center\"\n gap={2}\n px={3}\n py={2}\n bg=\"bg-red-500/10\"\n border={true}\n borderColor=\"border-red-500/30\"\n rounded=\"lg\"\n className={className}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <Icon icon={AlertCircle} size={4} color=\"text-red-500\" />\n <Text size=\"sm\" color=\"text-red-400\">{errorInfo.message}</Text>\n {onRetry && showRetry && (\n <Button\n variant=\"ghost\"\n onClick={onRetry}\n size=\"sm\"\n className=\"ml-2 text-xs text-red-300 hover:text-red-200 underline p-0 h-auto\"\n >\n Retry\n </Button>\n )}\n </Box>\n );\n\n default:\n return null;\n }\n}\n\nexport function ApiErrorDisplay({\n error,\n onRetry,\n variant = 'full-screen',\n hideTechnicalDetails = false,\n}: {\n error: ApiError;\n onRetry?: () => void;\n variant?: 'full-screen' | 'card' | 'inline';\n hideTechnicalDetails?: boolean;\n}) {\n return (\n <ErrorDisplay\n error={error}\n onRetry={onRetry}\n variant={variant}\n hideTechnicalDetails={hideTechnicalDetails}\n />\n );\n}\n\nexport function NetworkErrorDisplay({\n onRetry,\n variant = 'full-screen',\n}: {\n onRetry?: () => void;\n variant?: 'full-screen' | 'card' | 'inline';\n}) {\n return (\n <ErrorDisplay\n error={new Error('Network connection failed. Please check your internet connection.')}\n onRetry={onRetry}\n variant={variant}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/state/LoadingWrapper.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":61,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":61,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":68,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":68,"endColumn":110},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":79,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":79,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":91,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":91,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":109,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":116,"column":20,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":116,"endColumn":117},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":130,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":130,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":135,"column":16,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":135,"endColumn":111},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":148,"column":11,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":148,"endColumn":32},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":161,"column":15,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":161,"endColumn":40},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":162,"column":15,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":162,"endColumn":45},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":165,"column":22,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":165,"endColumn":117},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":185,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":185,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":199,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":199,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":212,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":212,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":225,"column":7,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":225,"endColumn":28}],"suppressedMessages":[],"errorCount":16,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { Box } from '@/ui/Box';\nimport { Stack } from '@/ui/Stack';\nimport { LoadingWrapperProps } from '@/ui/state-types';\nimport { Text } from '@/ui/Text';\n\n/**\n * LoadingWrapper Component\n * \n * Provides consistent loading states with multiple variants:\n * - spinner: Traditional loading spinner (default)\n * - skeleton: Skeleton screens for better UX\n * - full-screen: Centered in viewport\n * - inline: Compact inline loading\n * - card: Loading card placeholders\n * \n * All variants are fully accessible with ARIA labels and keyboard support.\n */\nexport function LoadingWrapper({\n variant = 'spinner',\n message = 'Loading...',\n className = '',\n size = 'md',\n skeletonCount = 3,\n cardConfig,\n ariaLabel = 'Loading content',\n}: LoadingWrapperProps) {\n // Size mappings for different variants\n const sizeClasses = {\n sm: {\n spinner: 'w-4 h-4 border-2',\n inline: 'xs' as const,\n card: 'h-24',\n },\n md: {\n spinner: 'w-10 h-10 border-2',\n inline: 'sm' as const,\n card: 'h-32',\n },\n lg: {\n spinner: 'w-16 h-16 border-4',\n inline: 'base' as const,\n card: 'h-40',\n },\n };\n\n const spinnerSize = sizeClasses[size].spinner;\n const inlineSize = sizeClasses[size].inline;\n const cardHeight = cardConfig?.height || sizeClasses[size].card;\n\n // Render different variants\n switch (variant) {\n case 'spinner':\n return (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n minHeight=\"200px\"\n className={className}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n <Stack align=\"center\" gap={3}>\n <Box\n className={`${spinnerSize} border-primary-blue border-t-transparent rounded-full animate-spin`}\n />\n <Text color=\"text-gray-400\" size=\"sm\">{message}</Text>\n </Stack>\n </Box>\n );\n\n case 'skeleton':\n return (\n <Stack\n gap={3}\n className={className}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n {Array.from({ length: skeletonCount }).map((_, index) => (\n <Box\n key={index}\n fullWidth\n bg=\"bg-iron-gray/40\"\n rounded=\"lg\"\n animate=\"pulse\"\n style={{ height: cardHeight }}\n />\n ))}\n </Stack>\n );\n\n case 'full-screen':\n return (\n <Box\n position=\"fixed\"\n inset=\"0\"\n zIndex={50}\n bg=\"bg-deep-graphite/90\"\n blur=\"sm\"\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n p={4}\n className={className}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n <Box textAlign=\"center\" maxWidth=\"md\">\n <Stack align=\"center\" gap={4}>\n <Box className=\"w-16 h-16 border-4 border-primary-blue border-t-transparent rounded-full animate-spin\" />\n <Text color=\"text-white\" size=\"lg\" weight=\"medium\">{message}</Text>\n <Text color=\"text-gray-400\" size=\"sm\">This may take a moment...</Text>\n </Stack>\n </Box>\n </Box>\n );\n\n case 'inline':\n return (\n <Box\n display=\"inline-flex\"\n alignItems=\"center\"\n gap={2}\n className={className}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n <Box className=\"w-4 h-4 border-2 border-primary-blue border-t-transparent rounded-full animate-spin\" />\n <Text color=\"text-gray-400\" size={inlineSize}>{message}</Text>\n </Box>\n );\n\n case 'card':\n const cardCount = cardConfig?.count || 3;\n const cardClassName = cardConfig?.className || '';\n \n return (\n <Box\n display=\"grid\"\n gap={4}\n className={className}\n role=\"status\"\n aria-label={ariaLabel}\n aria-live=\"polite\"\n >\n {Array.from({ length: cardCount }).map((_, index) => (\n <Box\n key={index}\n bg=\"bg-iron-gray/40\"\n rounded=\"xl\"\n overflow=\"hidden\"\n border\n borderColor=\"border-charcoal-outline/50\"\n className={cardClassName}\n style={{ height: cardHeight }}\n >\n <Box h=\"full\" w=\"full\" display=\"flex\" alignItems=\"center\" justifyContent=\"center\">\n <Box className=\"w-8 h-8 border-2 border-primary-blue border-t-transparent rounded-full animate-spin\" />\n </Box>\n </Box>\n ))}\n </Box>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * Convenience component for full-screen loading\n */\nexport function FullScreenLoading({ message = 'Loading...', className = '' }: Pick<LoadingWrapperProps, 'message' | 'className'>) {\n return (\n <LoadingWrapper\n variant=\"full-screen\"\n message={message}\n className={className}\n />\n );\n}\n\n/**\n * Convenience component for inline loading\n */\nexport function InlineLoading({ message = 'Loading...', size = 'sm', className = '' }: Pick<LoadingWrapperProps, 'message' | 'size' | 'className'>) {\n return (\n <LoadingWrapper\n variant=\"inline\"\n message={message}\n size={size}\n className={className}\n />\n );\n}\n\n/**\n * Convenience component for skeleton loading\n */\nexport function SkeletonLoading({ skeletonCount = 3, className = '' }: Pick<LoadingWrapperProps, 'skeletonCount' | 'className'>) {\n return (\n <LoadingWrapper\n variant=\"skeleton\"\n skeletonCount={skeletonCount}\n className={className}\n />\n );\n}\n\n/**\n * Convenience component for card loading\n */\nexport function CardLoading({ cardConfig, className = '' }: Pick<LoadingWrapperProps, 'cardConfig' | 'className'>) {\n return (\n <LoadingWrapper\n variant=\"card\"\n cardConfig={cardConfig}\n className={className}\n />\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/state/PageWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/state/StateContainer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/shared/state/StatefulPageWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/social/FriendsPreview.tsx","messages":[{"ruleId":"gridpilot-rules/no-hardcoded-routes","severity":2,"message":"Hardcoded link href \"/drivers/\". Use routes from RouteConfig.ts","line":42,"column":21,"nodeType":"TemplateElement","messageId":"hardcodedLink","endLine":42,"endColumn":33},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":45,"column":72,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":45,"endColumn":202},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":46,"column":22,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":46,"endColumn":173},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":52,"column":20,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":52,"endColumn":81}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { mediaConfig } from '@/lib/config/mediaConfig';\nimport { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';\nimport { Box } from '@/ui/Box';\nimport { Card } from '@/ui/Card';\nimport { Heading } from '@/ui/Heading';\nimport { Icon } from '@/ui/Icon';\nimport { Image } from '@/ui/Image';\nimport { Link } from '@/ui/Link';\nimport { Stack } from '@/ui/Stack';\nimport { Surface } from '@/ui/Surface';\nimport { Text } from '@/ui/Text';\nimport { Users } from 'lucide-react';\n\ninterface Friend {\n id: string;\n name: string;\n avatarUrl?: string;\n country: string;\n}\n\ninterface FriendsPreviewProps {\n friends: Friend[];\n}\n\nexport function FriendsPreview({ friends }: FriendsPreviewProps) {\n return (\n <Card>\n <Box mb={4}>\n <Stack direction=\"row\" align=\"center\" justify=\"between\">\n <Heading level={2} icon={<Icon icon={Users} size={5} color=\"#a855f7\" />}>\n Friends\n </Heading>\n <Text size=\"sm\" color=\"text-gray-500\" weight=\"normal\">({friends.length})</Text>\n </Stack>\n </Box>\n <Stack direction=\"row\" gap={3} wrap>\n {friends.slice(0, 8).map((friend) => (\n <Box key={friend.id}>\n <Link\n href={`/drivers/${friend.id}`}\n variant=\"ghost\"\n >\n <Surface variant=\"muted\" rounded=\"xl\" border padding={2} style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', backgroundColor: 'rgba(38, 38, 38, 0.5)', borderColor: '#262626' }}>\n <Box style={{ width: '2rem', height: '2rem', borderRadius: '9999px', overflow: 'hidden', background: 'linear-gradient(to bottom right, #3b82f6, #9333ea)' }}>\n <Image\n src={friend.avatarUrl || mediaConfig.avatars.defaultFallback}\n alt={friend.name}\n width={32}\n height={32}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n </Box>\n <Text size=\"sm\" color=\"text-white\">{friend.name}</Text>\n <Text size=\"lg\">{CountryFlagDisplay.fromCountryCode(friend.country).toString()}</Text>\n </Surface>\n </Link>\n </Box>\n ))}\n {friends.length > 8 && (\n <Box p={2}>\n <Text size=\"sm\" color=\"text-gray-500\">+{friends.length - 8} more</Text>\n </Box>\n )}\n </Stack>\n </Card>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/social/FriendsSidebar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/ActivityItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/AvailableLeagueCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/MetricBuilders.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/MetricCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/PendingSponsorshipRequests.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/RenewalAlert.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SlotTemplates.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorBenefitCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorHero.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":65,"column":11,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":65,"endColumn":28},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":75,"column":39,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":75,"endColumn":65},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":109,"column":9,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":109,"endColumn":26},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":143,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":143,"endColumn":98},{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":151,"column":13,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":151,"endColumn":81}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { Building2 } from 'lucide-react';\nimport { useEffect, useState } from 'react';\nimport { Box } from '@/ui/Box';\nimport { Heading } from '@/ui/Heading';\nimport { Icon } from '@/ui/Icon';\nimport { Text } from '@/ui/Text';\n\ninterface SponsorHeroProps {\n title: string;\n subtitle: string;\n children?: React.ReactNode;\n}\n\nexport function SponsorHero({ title, subtitle, children }: SponsorHeroProps) {\n const shouldReduceMotion = useReducedMotion();\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n const containerVariants = {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: 0.1,\n delayChildren: 0.1,\n },\n },\n };\n\n const itemVariants = {\n hidden: { opacity: 0, y: 20 },\n visible: {\n opacity: 1,\n y: 0,\n transition: { duration: 0.4, ease: 'easeOut' as const },\n },\n };\n\n const gridStyle = {\n backgroundImage: `\n linear-gradient(to right, #198CFF 1px, transparent 1px),\n linear-gradient(to bottom, #198CFF 1px, transparent 1px)\n `,\n backgroundSize: '40px 40px',\n };\n\n if (!isMounted || shouldReduceMotion) {\n return (\n <Box position=\"relative\" overflow=\"hidden\">\n {/* Background Pattern */}\n <Box position=\"absolute\" inset=\"0\" bg=\"bg-gradient-to-br from-primary-blue/5 via-transparent to-transparent\" />\n <Box position=\"absolute\" inset=\"0\" bg=\"bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-primary-blue/10 via-transparent to-transparent\" />\n \n {/* Grid Pattern */}\n <Box \n position=\"absolute\" \n inset=\"0\" \n bgOpacity={0.05}\n style={gridStyle}\n />\n\n <Box position=\"relative\" maxWidth=\"5xl\" mx=\"auto\" px={4} py={{ base: 16, sm: 24 }}>\n <Box textAlign=\"center\">\n <Box display=\"inline-flex\" alignItems=\"center\" gap={2} px={4} py={2} rounded=\"full\" bg=\"bg-primary-blue/10\" border={true} borderColor=\"border-primary-blue/20\" mb={6}>\n <Icon icon={Building2} size={4} color=\"text-primary-blue\" />\n <Text size=\"sm\" color=\"text-primary-blue\" weight=\"medium\">Sponsor Portal</Text>\n </Box>\n \n <Heading level={1} mb={6} className=\"tracking-tight\">\n {title}\n </Heading>\n \n <Text size=\"lg\" color=\"text-gray-400\" maxWidth=\"2xl\" mx=\"auto\" block mb={10}>\n {subtitle}\n </Text>\n\n {children}\n </Box>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box\n as={motion.div}\n position=\"relative\"\n overflow=\"hidden\"\n variants={containerVariants}\n initial=\"hidden\"\n animate=\"visible\"\n >\n {/* Background Pattern */}\n <Box position=\"absolute\" inset=\"0\" bg=\"bg-gradient-to-br from-primary-blue/5 via-transparent to-transparent\" />\n <Box position=\"absolute\" inset=\"0\" bg=\"bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-primary-blue/10 via-transparent to-transparent\" />\n \n {/* Animated Grid Pattern */}\n <Box \n as={motion.div}\n position=\"absolute\" \n inset=\"0\" \n bgOpacity={0.05}\n style={gridStyle}\n animate={{\n backgroundPosition: ['0px 0px', '40px 40px'],\n }}\n transition={{\n duration: 20,\n repeat: Infinity,\n ease: 'linear' as const,\n }}\n />\n\n <Box position=\"relative\" maxWidth=\"5xl\" mx=\"auto\" px={4} py={{ base: 16, sm: 24 }}>\n <Box textAlign=\"center\">\n <Box \n as={motion.div}\n variants={itemVariants}\n display=\"inline-flex\" \n alignItems=\"center\" \n gap={2} \n px={4} \n py={2} \n rounded=\"full\" \n bg=\"bg-primary-blue/10\" \n border={true} \n borderColor=\"border-primary-blue/20\" \n mb={6}\n >\n <Icon icon={Building2} size={4} color=\"text-primary-blue\" />\n <Text size=\"sm\" color=\"text-primary-blue\" weight=\"medium\">Sponsor Portal</Text>\n </Box>\n \n <Box\n as={motion.h1}\n variants={itemVariants}\n className=\"text-4xl sm:text-5xl lg:text-6xl font-bold text-white mb-6 tracking-tight\"\n >\n {title}\n </Box>\n \n <Box\n as={motion.p}\n variants={itemVariants}\n className=\"text-lg sm:text-xl text-gray-400 max-w-2xl mx-auto mb-10\"\n >\n {subtitle}\n </Box>\n\n <Box as={motion.div} variants={itemVariants}>\n {children}\n </Box>\n </Box>\n </Box>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorInsightsCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorInsightsCardHelpers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorInsightsCardTypes.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorTierCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorWorkflowMockup.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/sponsors/SponsorshipCategoryCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/CreateTeamForm.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/FeaturedRecruiting.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/JoinTeamButton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/SkillLevelSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamAdmin.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamHero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamHeroSection.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The style property is forbidden in components and pages. Use proper component props for styling.","line":34,"column":9,"nodeType":"JSXAttribute","messageId":"noStyle","endLine":37,"endColumn":11}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\n\nimport { Users } from 'lucide-react';\nimport { ReactNode } from 'react';\nimport { Badge } from '@/ui/Badge';\nimport { Box } from '@/ui/Box';\nimport { Heading } from '@/ui/Heading';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\n\ninterface TeamHeroSectionProps {\n title: ReactNode;\n description: string;\n statsContent: ReactNode;\n actionsContent: ReactNode;\n sideContent: ReactNode;\n}\n\nexport function TeamHeroSection({\n title,\n description,\n statsContent,\n actionsContent,\n sideContent,\n}: TeamHeroSectionProps) {\n return (\n <Box position=\"relative\" mb={10} overflow=\"hidden\">\n {/* Main Hero Card */}\n <Box \n position=\"relative\" \n py={12} \n px={8} \n rounded=\"2xl\" \n style={{\n background: 'linear-gradient(to bottom right, rgba(147, 51, 234, 0.3), rgba(38, 38, 38, 0.8), #0f1115)',\n borderColor: 'rgba(147, 51, 234, 0.2)',\n }}\n border\n >\n {/* Background decorations */}\n <Box position=\"absolute\" top=\"0\" right=\"0\" w=\"80\" h=\"80\" bg=\"bg-purple-500\" bgOpacity={0.1} rounded=\"full\" blur=\"3xl\" />\n <Box position=\"absolute\" bottom=\"0\" left=\"1/4\" w=\"64\" h=\"64\" bg=\"bg-neon-aqua\" bgOpacity={0.05} rounded=\"full\" blur=\"3xl\" />\n <Box position=\"absolute\" top=\"1/2\" right=\"1/4\" w=\"48\" h=\"48\" bg=\"bg-yellow-400\" bgOpacity={0.05} rounded=\"full\" blur=\"2xl\" />\n\n <Box position=\"relative\" zIndex={10}>\n <Stack direction={{ base: 'col', lg: 'row' }} align=\"start\" justify=\"between\" gap={8}>\n <Box maxWidth=\"xl\">\n {/* Badge */}\n <Box mb={4}>\n <Badge variant=\"primary\" icon={Users}>\n Team Racing\n </Badge>\n </Box>\n\n <Heading level={1}>\n {title}\n </Heading>\n\n <Text size=\"lg\" color=\"text-gray-400\" leading=\"relaxed\" block mt={4} mb={6}>\n {description}\n </Text>\n\n {/* Quick Stats */}\n <Stack direction=\"row\" gap={4} mb={6} wrap>\n {statsContent}\n </Stack>\n\n {/* CTA Buttons */}\n <Stack direction=\"row\" gap={3} wrap>\n {actionsContent}\n </Stack>\n </Box>\n\n {/* Side Content */}\n <Box w={{ base: 'full', lg: '72' }}>\n {sideContent}\n </Box>\n </Stack>\n </Box>\n </Box>\n </Box>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamHeroSectionWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamHeroStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamIdentity.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamLeaderboardPreviewWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamMembershipCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamPodium.tsx","messages":[{"ruleId":"gridpilot-rules/component-classification","severity":2,"message":"The className property is forbidden in components and pages. Use proper component props for styling.","line":76,"column":17,"nodeType":"JSXAttribute","messageId":"noClassName","endLine":76,"endColumn":43}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from 'react';\nimport { Trophy, Crown, Users } from 'lucide-react';\nimport type { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';\nimport { getMediaUrl } from '@/lib/utilities/media';\nimport { Box } from '@/ui/Box';\nimport { Stack } from '@/ui/Stack';\nimport { Text } from '@/ui/Text';\nimport { Icon } from '@/ui/Icon';\nimport { Button } from '@/ui/Button';\nimport { Image } from '@/ui/Image';\nimport { Podium, PodiumItem } from '@/ui/Podium';\n\ninterface TeamPodiumProps {\n teams: TeamSummaryViewModel[];\n onClick: (id: string) => void;\n}\n\nexport function TeamPodium({ teams, onClick }: TeamPodiumProps) {\n const top3 = teams.slice(0, 3) as [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel];\n if (teams.length < 3) return null;\n\n // Display order: 2nd, 1st, 3rd\n const podiumOrder: [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel] = [\n top3[1],\n top3[0],\n top3[2],\n ];\n const podiumHeights = ['28', '36', '20'];\n const podiumPositions = [2, 1, 3];\n\n const getPositionColor = (position: number) => {\n switch (position) {\n case 1:\n return 'text-yellow-400';\n case 2:\n return 'text-gray-300';\n case 3:\n return 'text-amber-600';\n default:\n return 'text-gray-500';\n }\n };\n\n const getBgColor = (position: number) => {\n switch (position) {\n case 1:\n return 'bg-gradient-to-br from-primary-blue/20 via-iron-gray/80 to-deep-graphite';\n case 2:\n return 'bg-iron-gray';\n case 3:\n return 'bg-gradient-to-br from-purple-600/20 via-iron-gray/80 to-deep-graphite';\n default:\n return 'bg-iron-gray/50';\n }\n };\n\n return (\n <Podium title=\"Top 3 Teams\">\n {podiumOrder.map((team, index) => {\n const position = podiumPositions[index] ?? 0;\n\n return (\n <PodiumItem\n key={team.id}\n position={position}\n height={podiumHeights[index] || '20'}\n bgColor={getBgColor(position)}\n positionColor={getPositionColor(position)}\n cardContent={\n <Button\n variant=\"ghost\"\n onClick={() => onClick(team.id)}\n h=\"auto\"\n mb={4}\n p={0}\n className=\"transition-all\"\n >\n <Box\n bg={getBgColor(position)}\n rounded=\"xl\"\n border={true}\n borderColor=\"border-charcoal-outline\"\n p={4}\n position=\"relative\"\n >\n {/* Crown for 1st place */}\n {position === 1 && (\n <Box position=\"absolute\" top=\"-4\" left=\"1/2\" translateX=\"-1/2\">\n <Box position=\"relative\">\n <Box animate=\"pulse\">\n <Icon icon={Crown} size={8} color=\"text-warning-amber\" />\n </Box>\n <Box position=\"absolute\" inset=\"0\" bg=\"bg-yellow-400\" bgOpacity={0.3} blur=\"md\" rounded=\"full\" />\n </Box>\n </Box>\n )}\n\n {/* Team logo */}\n <Box h=\"20\" w=\"20\" display=\"flex\" center rounded=\"xl\" bg=\"bg-deep-graphite\" border={true} borderColor=\"border-charcoal-outline\" overflow=\"hidden\" mb={3}>\n <Image\n src={team.logoUrl || getMediaUrl('team-logo', team.id)}\n alt={team.name}\n width={80}\n height={80}\n objectFit=\"cover\"\n />\n </Box>\n\n {/* Team name */}\n <Text weight=\"bold\" size=\"sm\" color=\"text-white\" align=\"center\" block truncate maxWidth=\"28\">\n {team.name}\n </Text>\n\n {/* Category */}\n {team.category && (\n <Text size=\"xs\" color=\"text-primary-blue\" align=\"center\" block mt={1}>\n {team.category}\n </Text>\n )}\n\n {/* Rating placeholder */}\n <Text size=\"xl\" weight=\"bold\" color={getPositionColor(position)} align=\"center\" block mt={1}>\n —\n </Text>\n\n {/* Stats row */}\n <Stack direction=\"row\" align=\"center\" justify=\"center\" gap={3} mt={2}>\n <Stack direction=\"row\" align=\"center\" gap={1}>\n <Icon icon={Trophy} size={3} color=\"text-performance-green\" />\n <Text size=\"xs\" color=\"text-gray-400\">{team.totalWins}</Text>\n </Stack>\n <Stack direction=\"row\" align=\"center\" gap={1}>\n <Icon icon={Users} size={3} color=\"text-primary-blue\" />\n <Text size=\"xs\" color=\"text-gray-400\">{team.memberCount}</Text>\n </Stack>\n </Stack>\n </Box>\n </Button>\n }\n />\n );\n })}\n </Podium>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamRankingsTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamRoster.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamRosterItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TeamStandings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/TopThreePodium.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/components/teams/WhyJoinTeamSection.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/env.d.ts","messages":[{"ruleId":"import/no-default-export","severity":2,"message":"Prefer named exports.","line":40,"column":10,"nodeType":"ExportDefaultDeclaration","endLine":40,"endColumn":17}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\ndeclare module 'framer-motion' {\n import type { ComponentType } from 'react';\n\n // Minimal shim to satisfy strict typing for usage in JSX\n export type MotionComponent = ComponentType<Record<string, unknown>>;\n\n export const motion: {\n div: MotionComponent;\n span: MotionComponent;\n button: MotionComponent;\n svg: MotionComponent;\n p: MotionComponent;\n [element: string]: MotionComponent;\n };\n\n export const AnimatePresence: ComponentType<Record<string, unknown>>;\n\n export function useReducedMotion(): boolean;\n\n // Shim motion values with a minimal interface exposing .set()\n export interface MotionValue<T = number> {\n get(): T;\n set(v: T): void;\n }\n\n export function useMotionValue(initial: number): MotionValue<number>;\n export function useSpring(value: MotionValue<number> | number, config?: Record<string, unknown>): MotionValue<number>;\n export function useTransform<TInput, TOutput>(\n value: MotionValue<TInput>,\n transformer: (input: TInput) => TOutput,\n ): MotionValue<TOutput>;\n}\n\ndeclare module '@next/third-party-devtools' {\n import type { ComponentType } from 'react';\n const Devtools: ComponentType<Record<string, unknown>>;\n export default Devtools;\n}\n\ndeclare module 'react/compiler-runtime' {\n export {};\n}\n\ndeclare global {\n namespace NodeJS {\n interface ProcessEnv {\n NODE_ENV?: 'development' | 'production' | 'test';\n\n // Website (public, exposed to browser)\n NEXT_PUBLIC_SITE_URL?: string;\n NEXT_PUBLIC_API_BASE_URL?: string;\n NEXT_PUBLIC_SITE_NAME?: string;\n NEXT_PUBLIC_SUPPORT_EMAIL?: string;\n NEXT_PUBLIC_SPONSOR_EMAIL?: string;\n NEXT_PUBLIC_LEGAL_COMPANY_NAME?: string;\n NEXT_PUBLIC_LEGAL_VAT_ID?: string;\n NEXT_PUBLIC_LEGAL_REGISTERED_COUNTRY?: string;\n NEXT_PUBLIC_LEGAL_REGISTERED_ADDRESS?: string;\n NEXT_PUBLIC_DISCORD_URL?: string;\n NEXT_PUBLIC_X_URL?: string;\n NEXT_TELEMETRY_DISABLED?: string;\n\n // Website (server-only)\n API_BASE_URL?: string;\n FEATURE_FLAGS?: string;\n\n // Vercel KV (server-only)\n KV_REST_API_URL?: string;\n KV_REST_API_TOKEN?: string;\n\n // Build/CI toggles (server-only)\n CI?: string;\n DOCKER?: string;\n }\n }\n}\n\nexport {};","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export { useCurrentSession } from './useCurrentSession';\nexport { useLogin } from './useLogin';\nexport { useLogout } from './useLogout';\nexport { useSignup } from './useSignup';\nexport { useForgotPassword } from './useForgotPassword';\nexport { useResetPassword } from './useResetPassword';","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/useCurrentSession.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/useForgotPassword.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/useLogin.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/useLogout.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/useResetPassword.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/auth/useSignup.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export { useCurrentDriver } from './useCurrentDriver';\nexport { useDriverLeaderboard } from '@/hooks/useDriverLeaderboard';\nexport { useDriverProfile } from './useDriverProfile';\nexport { useUpdateDriverProfile } from './useUpdateDriverProfile';\nexport { useCreateDriver } from './useCreateDriver';\nexport { useFindDriverById } from './useFindDriverById';","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/useCreateDriver.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/useCurrentDriver.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":7,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":7,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[327,330],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[327,330],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\ntype DriverData = any; // Replace with actual type\n\nexport function useCurrentDriver(\n options?: Omit<UseQueryOptions<DriverData, ApiError>, 'queryKey' | 'queryFn'>\n) {\n const driverService = useInject(DRIVER_SERVICE_TOKEN);\n\n const queryResult = useQuery({\n queryKey: ['currentDriver'],\n queryFn: () => driverService.getCurrentDriver(),\n ...options,\n });\n\n return enhanceQueryResult(queryResult);\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/useDriverProfile.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":22,"column":60,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":22,"endColumn":63,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1008,1011],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1008,1011],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';\nimport { ApiError } from '@/lib/api/base/ApiError';\nimport { DriverProfileViewModel } from '@/lib/view-models/DriverProfileViewModel';\n\nexport function useDriverProfile(\n driverId: string,\n options?: Omit<UseQueryOptions<DriverProfileViewModel, ApiError>, 'queryKey' | 'queryFn'>\n) {\n const driverService = useInject(DRIVER_SERVICE_TOKEN);\n\n const queryResult = useQuery({\n queryKey: ['driverProfile', driverId],\n queryFn: async () => {\n const result = await driverService.getDriverProfile(driverId);\n if (result.isErr()) {\n const error = result.getError();\n throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });\n }\n return new DriverProfileViewModel(result.unwrap() as any);\n },\n enabled: !!driverId,\n ...options,\n });\n\n return enhanceQueryResult(queryResult);\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/useDriverProfilePageData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/useFindDriverById.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/driver/useUpdateDriverProfile.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useAllLeagues.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useCreateLeague.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useCreateLeagueWithBlockers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueAdminStatus.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueDetail.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueMembershipMutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueMemberships.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueRaces.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueRosterAdmin.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueSchedule.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueScheduleAdminPageData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueSeasons.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueSettings.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueSponsorshipsPageData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueStewardingData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueStewardingMutations.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'variables' is defined but never used.","line":5,"column":12,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":166},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'variables' is defined but never used.","line":31,"column":12,"nodeType":"Identifier","messageId":"unusedVar","endLine":31,"endColumn":66}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { usePageMutation } from '@/lib/page/usePageData';\n\nexport function useLeagueStewardingMutations(onRefetch: () => void) {\n const acceptProtestMutation = usePageMutation(\n async (variables: { protestId: string; penaltyType: string; penaltyValue: number; stewardNotes: string; raceId: string; accusedDriverId: string; reason: string }) => {\n // TODO: Implement protest review and penalty application\n // await leagueStewardingService.reviewProtest({\n // protestId: variables.protestId,\n // stewardId: currentDriverId,\n // decision: 'uphold',\n // decisionNotes: variables.stewardNotes,\n // });\n \n // await leagueStewardingService.applyPenalty({\n // raceId: variables.raceId,\n // driverId: variables.accusedDriverId,\n // stewardId: currentDriverId,\n // type: variables.penaltyType,\n // value: variables.penaltyValue,\n // reason: variables.reason,\n // protestId: variables.protestId,\n // notes: variables.stewardNotes,\n // });\n },\n {\n onSuccess: () => onRefetch(),\n }\n );\n\n const rejectProtestMutation = usePageMutation(\n async (variables: { protestId: string; stewardNotes: string }) => {\n // TODO: Implement protest rejection\n // await leagueStewardingService.reviewProtest({\n // protestId: variables.protestId,\n // stewardId: currentDriverId,\n // decision: 'dismiss',\n // decisionNotes: variables.stewardNotes,\n // });\n },\n {\n onSuccess: () => onRefetch(),\n }\n );\n\n return { acceptProtestMutation, rejectProtestMutation };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueWalletPageData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":51,"column":67,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":51,"endColumn":70,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1850,1853],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1850,1853],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { usePageData } from '@/lib/page/usePageData';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { LEAGUE_WALLET_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { LeagueWalletViewModel } from '@/lib/view-models/LeagueWalletViewModel';\nimport { WalletTransactionViewModel } from '@/lib/view-models/WalletTransactionViewModel';\nimport { useLeagueWalletWithdrawalWithBlockers } from './useLeagueWalletWithdrawalWithBlockers';\n\nexport function useLeagueWalletPageData(leagueId: string) {\n const leagueWalletService = useInject(LEAGUE_WALLET_SERVICE_TOKEN);\n\n const queryResult = usePageData({\n queryKey: ['leagueWallet', leagueId],\n queryFn: async () => {\n const dto = await leagueWalletService.getWalletForLeague(leagueId);\n // Transform DTO to ViewModel at client boundary\n const transactions = dto.transactions.map(t => new WalletTransactionViewModel({\n id: t.id,\n type: t.type,\n description: t.description,\n amount: t.amount,\n fee: t.fee,\n netAmount: t.netAmount,\n date: new Date(t.date),\n status: t.status,\n reference: t.reference,\n }));\n return new LeagueWalletViewModel({\n balance: dto.balance,\n currency: dto.currency,\n totalRevenue: dto.totalRevenue,\n totalFees: dto.totalFees,\n totalWithdrawals: dto.totalWithdrawals,\n pendingPayouts: dto.pendingPayouts,\n transactions,\n canWithdraw: dto.canWithdraw,\n withdrawalBlockReason: dto.withdrawalBlockReason,\n });\n },\n enabled: !!leagueId,\n });\n\n return queryResult;\n}\n\n/**\n * @deprecated Use useLeagueWalletWithdrawalWithBlockers instead\n * This wrapper maintains backward compatibility while using the new blocker-aware hook\n */\nexport function useLeagueWalletWithdrawal(leagueId: string, data: any, refetch: () => void) {\n return useLeagueWalletWithdrawalWithBlockers(leagueId, data, refetch);\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useLeagueWalletWithdrawalWithBlockers.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":79,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":82,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[484,487],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[484,487],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { usePageMutation } from '@/lib/page/usePageData';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { LEAGUE_WALLET_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { SubmitBlocker, ThrottleBlocker } from '@/lib/blockers';\n\n/**\n * Hook for wallet withdrawals with client-side blockers\n * Handles UX prevention mechanisms (rate limiting, duplicate submission prevention)\n */\nexport function useLeagueWalletWithdrawalWithBlockers(leagueId: string, data: any, refetch: () => void) {\n const leagueWalletService = useInject(LEAGUE_WALLET_SERVICE_TOKEN);\n \n // Client-side blockers for UX improvement\n const submitBlocker = new SubmitBlocker();\n const throttle = new ThrottleBlocker(500);\n\n const withdrawMutation = usePageMutation(\n async ({ amount }: { amount: number }) => {\n if (!data) throw new Error('Wallet data not available');\n \n // Client-side blockers (UX only, not security)\n if (!submitBlocker.canExecute() || !throttle.canExecute()) {\n throw new Error('Request blocked due to rate limiting');\n }\n\n submitBlocker.block();\n throttle.block();\n \n try {\n const result = await leagueWalletService.withdraw(\n leagueId,\n amount,\n data.currency,\n 'season-2', // Current active season\n 'bank-account-***1234'\n );\n\n if (!result.success) {\n throw new Error(result.message || 'Withdrawal failed');\n }\n\n return result;\n } finally {\n submitBlocker.release();\n }\n },\n {\n onSuccess: () => {\n // Refetch wallet data after successful withdrawal\n refetch();\n },\n }\n );\n\n return withdrawMutation;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/usePenaltyMutation.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":10,"column":27,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":10,"endColumn":30,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[391,394],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[391,394],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { PENALTY_SERVICE_TOKEN } from '@/lib/di/tokens';\n\nexport function usePenaltyMutation() {\n const penaltyService = useInject(PENALTY_SERVICE_TOKEN);\n const queryClient = useQueryClient();\n\n const applyPenaltyMutation = useMutation({\n mutationFn: (command: any) => penaltyService.applyPenalty(command),\n onSuccess: () => {\n // Invalidate relevant queries to refresh data\n queryClient.invalidateQueries({ queryKey: ['leagueStewardingData'] });\n queryClient.invalidateQueries({ queryKey: ['penalties'] });\n },\n });\n\n return applyPenaltyMutation;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useProtestDetail.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/league/useSponsorshipRequests.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/onboarding/useCompleteOnboarding.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/onboarding/useGenerateAvatars.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'params' is defined but never used.","line":24,"column":24,"nodeType":"Identifier","messageId":"unusedVar","endLine":24,"endColumn":30},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'service' is assigned a value but never used.","line":25,"column":13,"nodeType":"Identifier","messageId":"unusedVar","endLine":25,"endColumn":20}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useMutation, UseMutationOptions } from '@tanstack/react-query';\nimport { OnboardingService } from '@/lib/services/onboarding/OnboardingService';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError } from '@/lib/contracts/services/Service';\n\ninterface GenerateAvatarsParams {\n userId: string;\n facePhotoData: string;\n suitColor: string;\n}\n\ninterface GenerateAvatarsResult {\n success: boolean;\n avatarUrls?: string[];\n errorMessage?: string;\n}\n\nexport function useGenerateAvatars(\n options?: Omit<UseMutationOptions<Result<GenerateAvatarsResult, DomainError>, Error, GenerateAvatarsParams>, 'mutationFn'>\n) {\n return useMutation<Result<GenerateAvatarsResult, DomainError>, Error, GenerateAvatarsParams>({\n mutationFn: async (params) => {\n const service = new OnboardingService();\n // This method doesn't exist in the service yet, but the hook is now created\n // The service will need to implement this or we need to adjust the architecture\n return Result.ok({ success: false, errorMessage: 'Not implemented' });\n },\n ...options,\n });\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/race/useAllRacesPageData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/race/useFileProtest.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/race/useRaceResultsPageData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/race/useRegisterForRace.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/race/useWithdrawFromRace.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export { useAvailableLeagues } from './useAvailableLeagues';\nexport { useSponsorDashboard } from './useSponsorDashboard';\nexport { useSponsorSponsorships } from './useSponsorSponsorships';\nexport { useSponsorBilling } from './useSponsorBilling';\nexport { useSponsorLeagueDetail } from './useSponsorLeagueDetail';","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/useAvailableLeagues.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/useSponsorBilling.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/useSponsorDashboard.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/useSponsorLeagueDetail.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/useSponsorMode.ts","messages":[{"ruleId":"import/no-named-as-default-member","severity":2,"message":"Caution: `React` also has a named export `useState`. Check if you meant to write `import {useState} from 'react'` instead.","line":6,"column":37,"nodeType":"MemberExpression","endLine":6,"endColumn":51},{"ruleId":"import/no-named-as-default-member","severity":2,"message":"Caution: `React` also has a named export `useEffect`. Check if you meant to write `import {useEffect} from 'react'` instead.","line":8,"column":3,"nodeType":"MemberExpression","endLine":8,"endColumn":18}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useAuth } from '@/lib/auth/AuthContext';\nimport React from 'react';\n\nexport function useSponsorMode(): boolean {\n const { session } = useAuth();\n const [isSponsor, setIsSponsor] = React.useState(false);\n \n React.useEffect(() => {\n if (!session) {\n setIsSponsor(false);\n return;\n }\n\n // Check session.role for sponsor\n const role = session.role;\n if (role === 'sponsor') {\n setIsSponsor(true);\n return;\n }\n\n // Fallback: check email patterns\n const email = session.email?.toLowerCase() || '';\n const displayName = session.displayName?.toLowerCase() || '';\n \n setIsSponsor(email.includes('sponsor') || displayName.includes('sponsor'));\n }, [session]);\n \n return isSponsor;\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/sponsor/useSponsorSponsorships.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export { useAllTeams } from './useAllTeams';\nexport { useTeamDetails } from './useTeamDetails';\nexport { useTeamMembers } from './useTeamMembers';\nexport { useTeamJoinRequests } from './useTeamJoinRequests';\nexport { useCreateTeam } from './useCreateTeam';\nexport { useUpdateTeam } from './useUpdateTeam';\nexport { useTeamMembership } from './useTeamMembership';\nexport { useApproveJoinRequest } from './useApproveJoinRequest';\nexport { useRejectJoinRequest } from './useRejectJoinRequest';\nexport { useTeamStandings } from './useTeamStandings';\nexport { useJoinTeam } from './useJoinTeam';\nexport { useLeaveTeam } from './useLeaveTeam';\nexport { useTeamRoster } from './useTeamRoster';","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useAllTeams.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useApproveJoinRequest.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useCreateTeam.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useJoinTeam.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'teamService' is assigned a value but never used.","line":13,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":13,"endColumn":20}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useMutation, UseMutationOptions } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { TEAM_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\ninterface JoinTeamParams {\n teamId: string;\n driverId: string;\n requiresApproval?: boolean;\n}\n\nexport function useJoinTeam(options?: Omit<UseMutationOptions<void, ApiError, JoinTeamParams>, 'mutationFn'>) {\n const teamService = useInject(TEAM_SERVICE_TOKEN);\n\n return useMutation<void, ApiError, JoinTeamParams>({\n mutationFn: async (params) => {\n // Note: Team join functionality would need to be added to teamService\n // For now, we'll use a placeholder\n console.log('Joining team:', params);\n if (params.requiresApproval) {\n alert('Join request sent! Wait for team approval.');\n } else {\n alert('Successfully joined team!');\n }\n },\n ...options,\n });\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useLeaveTeam.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'teamService' is assigned a value but never used.","line":12,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":12,"endColumn":20}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useMutation, UseMutationOptions } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { TEAM_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\ninterface LeaveTeamParams {\n teamId: string;\n driverId: string;\n}\n\nexport function useLeaveTeam(options?: Omit<UseMutationOptions<void, ApiError, LeaveTeamParams>, 'mutationFn'>) {\n const teamService = useInject(TEAM_SERVICE_TOKEN);\n\n return useMutation<void, ApiError, LeaveTeamParams>({\n mutationFn: async (params) => {\n // Note: Leave team functionality would need to be added to teamService\n // For now, we'll use a placeholder\n console.log('Leaving team:', params);\n alert('Successfully left team');\n },\n ...options,\n });\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useRejectJoinRequest.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useTeamDetails.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useTeamJoinRequests.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useTeamMembers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useTeamMembership.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'GetTeamMembershipOutputDTO' is defined but never used.","line":5,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":41}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useQuery } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { TEAM_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';\nimport type { GetTeamMembershipOutputDTO } from '@/lib/types/generated/GetTeamMembershipOutputDTO';\n\nexport function useTeamMembership(teamId: string, driverId: string) {\n const teamService = useInject(TEAM_SERVICE_TOKEN);\n\n const queryResult = useQuery({\n queryKey: ['teamMembership', teamId, driverId],\n queryFn: async () => {\n const result = await teamService.getMembership(teamId, driverId);\n if (result.isErr()) {\n throw result.getError();\n }\n return result.unwrap();\n },\n enabled: !!teamId && !!driverId,\n });\n\n return enhanceQueryResult(queryResult);\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useTeamRoster.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":9,"column":11,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":9,"endColumn":14,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[354,357],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[354,357],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'teamService' is assigned a value but never used.","line":21,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":21,"endColumn":20}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useQuery } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { TEAM_SERVICE_TOKEN, DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';\n\ntype TeamMemberRole = 'owner' | 'manager' | 'member';\n\ninterface TeamRosterMember {\n driver: any;\n role: TeamMemberRole;\n joinedAt: string;\n rating: number | null;\n overallRank: number | null;\n}\n\nexport function useTeamRoster(memberships: Array<{\n driverId: string;\n role: string;\n joinedAt: string;\n}>) {\n const teamService = useInject(TEAM_SERVICE_TOKEN);\n const driverService = useInject(DRIVER_SERVICE_TOKEN);\n\n const queryResult = useQuery<TeamRosterMember[]>({\n queryKey: ['teamRoster', memberships],\n queryFn: async () => {\n // Get driver details for each membership\n const membersWithDetails = await Promise.all(\n memberships.map(async (m) => {\n const driver = await driverService.findById(m.driverId);\n // Convert role to TeamMemberRole\n const role: TeamMemberRole = m.role === 'owner' ? 'owner' : \n m.role === 'manager' ? 'manager' : 'member';\n return {\n driver: driver || { id: m.driverId, name: 'Unknown Driver', country: 'Unknown', position: 'N/A', races: '0', impressions: '0', team: 'None' },\n role,\n joinedAt: m.joinedAt,\n rating: null, // DriverDTO doesn't include rating\n overallRank: null, // DriverDTO doesn't include overallRank\n };\n })\n );\n return membersWithDetails;\n },\n enabled: memberships.length > 0,\n });\n\n return enhanceQueryResult(queryResult);\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useTeamStandings.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'leagueService' is assigned a value but never used.","line":7,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":22}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useQuery } from '@tanstack/react-query';\nimport { useInject } from '@/lib/di/hooks/useInject';\nimport { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens';\nimport { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';\n\nexport function useTeamStandings(teamId: string, leagues: string[]) {\n const leagueService = useInject(LEAGUE_SERVICE_TOKEN);\n\n const queryResult = useQuery({\n queryKey: ['teamStandings', teamId, leagues],\n queryFn: async () => {\n // For demo purposes, create mock standings\n return leagues.map(leagueId => ({\n leagueId,\n leagueName: `League ${leagueId}`,\n position: Math.floor(Math.random() * 10) + 1,\n points: Math.floor(Math.random() * 100),\n wins: Math.floor(Math.random() * 5),\n racesCompleted: Math.floor(Math.random() * 10),\n }));\n },\n enabled: leagues.length > 0,\n });\n\n return enhanceQueryResult(queryResult);\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/team/useUpdateTeam.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useCapability.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useDriverLeaderboard.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useDriverSearch.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useEffectiveDriverId.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useEnhancedForm.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'createErrorContext' is defined but never used.","line":9,"column":77,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":95},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'ApiError' is defined but never used.","line":10,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":10,"endColumn":18},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":19,"column":53,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":19,"endColumn":56,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[659,662],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[659,662],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":27,"column":55,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":27,"endColumn":58,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[863,866],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[863,866],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":65,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":68,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1192,1195],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1192,1195],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":52,"column":58,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":52,"endColumn":61,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1900,1903],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1900,1903],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"react-hooks/exhaustive-deps","severity":2,"message":"React Hook useEffect has a missing dependency: 'getValues'. Either include it or remove the dependency array.","line":94,"column":6,"nodeType":"ArrayExpression","endLine":94,"endColumn":65,"suggestions":[{"desc":"Update the dependencies array to be: [formState.fields, formState.submitCount, getValues, options.validate]","fix":{"range":[3178,3237],"text":"[formState.fields, formState.submitCount, getValues, options.validate]"}}]},{"ruleId":"react-hooks/exhaustive-deps","severity":2,"message":"React Hook useCallback has a missing dependency: 'options'. Either include it or remove the dependency array.","line":213,"column":6,"nodeType":"ArrayExpression","endLine":213,"endColumn":35,"suggestions":[{"desc":"Update the dependencies array to be: [options, getValues]","fix":{"range":[6056,6085],"text":"[options, getValues]"}}]}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Enhanced Form Hook with Advanced Error Handling\n * \n * Provides comprehensive form state management, validation, and error handling\n * with both user-friendly and developer-friendly error messages.\n */\n\nimport { useState, useCallback, useEffect, FormEvent, ChangeEvent, Dispatch, SetStateAction } from 'react';\nimport { parseApiError, formatValidationErrorsForForm, logErrorWithContext, createErrorContext } from '@/lib/utils/errorUtils';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\nexport interface FormField<T> {\n value: T;\n error?: string;\n touched: boolean;\n validating: boolean;\n}\n\nexport interface FormState<T extends Record<string, any>> {\n fields: { [K in keyof T]: FormField<T[K]> };\n isValid: boolean;\n isSubmitting: boolean;\n submitError?: string;\n submitCount: number;\n}\n\nexport interface FormOptions<T extends Record<string, any>> {\n initialValues: T;\n validate?: (values: T) => Record<string, string> | Promise<Record<string, string>>;\n onSubmit: (values: T) => Promise<void>;\n onError?: (error: unknown, values: T) => void;\n onSuccess?: (values: T) => void;\n component?: string;\n}\n\nexport interface UseEnhancedFormReturn<T extends Record<string, any>> {\n formState: FormState<T>;\n setFormState: Dispatch<SetStateAction<FormState<T>>>;\n handleChange: (e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void;\n setFieldValue: <K extends keyof T>(field: K, value: T[K]) => void;\n setFieldError: <K extends keyof T>(field: K, error: string) => void;\n handleSubmit: (e: FormEvent<HTMLFormElement>) => Promise<void>;\n reset: () => void;\n setFormError: (error: string) => void;\n clearFieldError: <K extends keyof T>(field: K) => void;\n validateField: <K extends keyof T>(field: K) => Promise<void>;\n}\n\n/**\n * Enhanced form hook with comprehensive error handling\n */\nexport function useEnhancedForm<T extends Record<string, any>>(\n options: FormOptions<T>\n): UseEnhancedFormReturn<T> {\n const [formState, setFormState] = useState<FormState<T>>(() => ({\n fields: Object.keys(options.initialValues).reduce((acc, key) => ({\n ...acc,\n [key]: {\n value: options.initialValues[key as keyof T],\n error: undefined,\n touched: false,\n validating: false,\n }\n }), {} as { [K in keyof T]: FormField<T[K]> }),\n isValid: true,\n isSubmitting: false,\n submitError: undefined,\n submitCount: 0,\n }));\n\n // Validate form on change\n useEffect(() => {\n if (options.validate && formState.submitCount > 0) {\n const validateAsync = async () => {\n try {\n const errors = await options.validate!(getValues());\n setFormState(prev => ({\n ...prev,\n isValid: Object.keys(errors).length === 0,\n fields: Object.keys(prev.fields).reduce((acc, key) => ({\n ...acc,\n [key]: {\n ...prev.fields[key as keyof T],\n error: errors[key],\n }\n }), {} as { [K in keyof T]: FormField<T[K]> }),\n }));\n } catch (error) {\n console.error('Validation error:', error);\n }\n };\n validateAsync();\n }\n }, [formState.fields, formState.submitCount, options.validate]);\n\n const getValues = useCallback((): T => {\n return Object.keys(formState.fields).reduce((acc, key) => ({\n ...acc,\n [key]: formState.fields[key as keyof T].value,\n }), {} as T);\n }, [formState.fields]);\n\n const handleChange = useCallback((e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {\n const { name, value, type } = e.target;\n const checked = 'checked' in e.target ? e.target.checked : false;\n const fieldValue = type === 'checkbox' ? checked : value;\n \n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [name]: {\n ...prev.fields[name as keyof T],\n value: fieldValue as T[keyof T],\n touched: true,\n error: undefined, // Clear error on change\n },\n },\n }));\n }, []);\n\n const setFieldValue = useCallback(<K extends keyof T>(field: K, value: T[K]) => {\n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [field]: {\n ...prev.fields[field],\n value,\n touched: true,\n error: undefined,\n },\n },\n }));\n }, []);\n\n const setFieldError = useCallback(<K extends keyof T>(field: K, error: string) => {\n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [field]: {\n ...prev.fields[field],\n error,\n touched: true,\n },\n },\n isValid: false,\n }));\n }, []);\n\n const clearFieldError = useCallback(<K extends keyof T>(field: K) => {\n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [field]: {\n ...prev.fields[field],\n error: undefined,\n },\n },\n }));\n }, []);\n\n const setFormError = useCallback((error: string) => {\n setFormState(prev => ({\n ...prev,\n submitError: error,\n }));\n }, []);\n\n const validateField = useCallback(async <K extends keyof T>(field: K) => {\n if (!options.validate) return;\n \n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [field]: {\n ...prev.fields[field],\n validating: true,\n },\n },\n }));\n\n try {\n const values = getValues();\n const errors = await options.validate(values);\n \n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [field]: {\n ...prev.fields[field],\n error: errors[field as string],\n validating: false,\n },\n },\n }));\n } catch (error) {\n setFormState(prev => ({\n ...prev,\n fields: {\n ...prev.fields,\n [field]: {\n ...prev.fields[field],\n validating: false,\n },\n },\n }));\n }\n }, [options.validate, getValues]);\n\n const reset = useCallback(() => {\n setFormState({\n fields: Object.keys(options.initialValues).reduce((acc, key) => ({\n ...acc,\n [key]: {\n value: options.initialValues[key as keyof T],\n error: undefined,\n touched: false,\n validating: false,\n }\n }), {} as { [K in keyof T]: FormField<T[K]> }),\n isValid: true,\n isSubmitting: false,\n submitError: undefined,\n submitCount: 0,\n });\n }, [options.initialValues]);\n\n const handleSubmit = useCallback(async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n \n const values = getValues();\n \n // Increment submit count to trigger validation\n setFormState(prev => ({\n ...prev,\n submitCount: prev.submitCount + 1,\n isSubmitting: true,\n submitError: undefined,\n }));\n\n // Run validation if provided\n if (options.validate) {\n try {\n const errors = await options.validate(values);\n const hasErrors = Object.keys(errors).length > 0;\n \n if (hasErrors) {\n setFormState(prev => ({\n ...prev,\n isSubmitting: false,\n isValid: false,\n fields: Object.keys(prev.fields).reduce((acc, key) => ({\n ...acc,\n [key]: {\n ...prev.fields[key as keyof T],\n error: errors[key],\n touched: true,\n }\n }), {} as { [K in keyof T]: FormField<T[K]> }),\n }));\n return;\n }\n } catch (validationError) {\n logErrorWithContext(validationError, {\n timestamp: new Date().toISOString(),\n component: options.component || 'useEnhancedForm',\n action: 'validate',\n formData: values,\n });\n \n setFormState(prev => ({\n ...prev,\n isSubmitting: false,\n submitError: 'Validation failed. Please check your input.',\n }));\n return;\n }\n }\n\n // Submit the form\n try {\n await options.onSubmit(values);\n \n setFormState(prev => ({\n ...prev,\n isSubmitting: false,\n submitError: undefined,\n }));\n \n options.onSuccess?.(values);\n } catch (error) {\n const parsed = parseApiError(error);\n \n // Log for developers\n logErrorWithContext(error, {\n timestamp: new Date().toISOString(),\n component: options.component || 'useEnhancedForm',\n action: 'submit',\n formData: values,\n });\n\n // Handle validation errors from API\n if (parsed.isValidationError && parsed.validationErrors.length > 0) {\n const fieldErrors = formatValidationErrorsForForm(parsed.validationErrors);\n \n setFormState(prev => ({\n ...prev,\n isSubmitting: false,\n isValid: false,\n fields: Object.keys(prev.fields).reduce((acc, key) => ({\n ...acc,\n [key]: {\n ...prev.fields[key as keyof T],\n error: fieldErrors[key],\n touched: true,\n }\n }), {} as { [K in keyof T]: FormField<T[K]> }),\n }));\n } else {\n // General submit error\n setFormState(prev => ({\n ...prev,\n isSubmitting: false,\n submitError: parsed.userMessage,\n }));\n }\n \n options.onError?.(error, values);\n }\n }, [getValues, options]);\n\n return {\n formState,\n setFormState,\n handleChange,\n setFieldValue,\n setFieldError,\n handleSubmit,\n reset,\n setFormError,\n clearFieldError,\n validateField,\n };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useLeagueScoringPresets.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useLeagueWizardService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/usePenaltyTypesReference.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/hooks/useScrollProgress.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/adapters/MediaAdapter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/admin/AdminApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/analytics/AnalyticsApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/auth/AuthApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/base/ApiConnectionMonitor.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'ApiError' is defined but never used.","line":6,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":18},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'CircuitBreakerRegistry' is defined but never used.","line":7,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":32}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * API Connection Status Monitor and Health Checks\n */\n\nimport { EventEmitter } from 'events';\nimport { ApiError } from './ApiError';\nimport { CircuitBreakerRegistry } from './RetryHandler';\n\nexport type ConnectionStatus = 'connected' | 'disconnected' | 'degraded' | 'checking';\n\nexport interface ConnectionHealth {\n status: ConnectionStatus;\n lastCheck: Date | null;\n lastSuccess: Date | null;\n lastFailure: Date | null;\n consecutiveFailures: number;\n totalRequests: number;\n successfulRequests: number;\n failedRequests: number;\n averageResponseTime: number;\n}\n\nexport interface HealthCheckResult {\n healthy: boolean;\n responseTime: number;\n error?: string;\n timestamp: Date;\n}\n\nexport class ApiConnectionMonitor extends EventEmitter {\n private static instance: ApiConnectionMonitor;\n private health: ConnectionHealth;\n private isChecking = false;\n private checkInterval: NodeJS.Timeout | null = null;\n private healthCheckEndpoint: string;\n private readonly CHECK_INTERVAL = 30000; // 30 seconds\n private readonly DEGRADATION_THRESHOLD = 0.7; // 70% failure rate\n\n private constructor(healthCheckEndpoint: string = '/health') {\n super();\n this.healthCheckEndpoint = healthCheckEndpoint;\n this.health = {\n status: 'disconnected',\n lastCheck: null,\n lastSuccess: null,\n lastFailure: null,\n consecutiveFailures: 0,\n totalRequests: 0,\n successfulRequests: 0,\n failedRequests: 0,\n averageResponseTime: 0,\n };\n }\n\n static getInstance(healthCheckEndpoint?: string): ApiConnectionMonitor {\n if (!ApiConnectionMonitor.instance) {\n ApiConnectionMonitor.instance = new ApiConnectionMonitor(healthCheckEndpoint);\n }\n return ApiConnectionMonitor.instance;\n }\n\n /**\n * Start automatic health monitoring\n */\n startMonitoring(intervalMs?: number): void {\n if (this.checkInterval) {\n clearInterval(this.checkInterval);\n }\n\n const interval = intervalMs || this.CHECK_INTERVAL;\n this.checkInterval = setInterval(() => {\n this.performHealthCheck();\n }, interval);\n\n // Initial check\n this.performHealthCheck();\n }\n\n /**\n * Stop automatic health monitoring\n */\n stopMonitoring(): void {\n if (this.checkInterval) {\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n }\n }\n\n /**\n * Perform a manual health check\n */\n async performHealthCheck(): Promise<HealthCheckResult> {\n if (this.isChecking) {\n return {\n healthy: false,\n responseTime: 0,\n error: 'Check already in progress',\n timestamp: new Date(),\n };\n }\n\n this.isChecking = true;\n const startTime = Date.now();\n\n try {\n // Try multiple endpoints to determine actual connectivity\n const baseUrl = this.getBaseUrl();\n const endpointsToTry = [\n `${baseUrl}${this.healthCheckEndpoint}`,\n `${baseUrl}/api/health`,\n `${baseUrl}/status`,\n baseUrl, // Root endpoint\n ];\n\n let lastError: Error | null = null;\n let successfulResponse: Response | null = null;\n\n for (const endpoint of endpointsToTry) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 3000);\n\n const response = await fetch(endpoint, {\n method: 'GET',\n signal: controller.signal,\n cache: 'no-store',\n // Add credentials to handle auth\n credentials: 'include',\n });\n\n clearTimeout(timeoutId);\n\n // Consider any response (even 404) as connectivity success\n if (response.ok || response.status === 404 || response.status === 401) {\n successfulResponse = response;\n break;\n }\n } catch (endpointError) {\n lastError = endpointError as Error;\n // Try next endpoint\n continue;\n }\n }\n\n const responseTime = Date.now() - startTime;\n\n if (successfulResponse) {\n this.recordSuccess(responseTime);\n this.isChecking = false;\n\n return {\n healthy: true,\n responseTime,\n timestamp: new Date(),\n };\n } else {\n // If we got here, all endpoints failed\n const errorMessage = lastError?.message || 'All endpoints failed to respond';\n this.recordFailure(errorMessage);\n this.isChecking = false;\n\n return {\n healthy: false,\n responseTime,\n error: errorMessage,\n timestamp: new Date(),\n };\n }\n } catch (error) {\n const responseTime = Date.now() - startTime;\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n \n this.recordFailure(errorMessage);\n this.isChecking = false;\n\n return {\n healthy: false,\n responseTime,\n error: errorMessage,\n timestamp: new Date(),\n };\n }\n }\n\n /**\n * Record a successful API request\n */\n recordSuccess(responseTime: number = 0): void {\n this.health.totalRequests++;\n this.health.successfulRequests++;\n this.health.consecutiveFailures = 0;\n this.health.lastSuccess = new Date();\n this.health.lastCheck = new Date();\n\n // Update average response time\n const total = this.health.successfulRequests;\n this.health.averageResponseTime = \n ((this.health.averageResponseTime * (total - 1)) + responseTime) / total;\n\n this.updateStatus();\n this.emit('success', { responseTime });\n }\n\n /**\n * Record a failed API request\n */\n recordFailure(error: string | Error): void {\n this.health.totalRequests++;\n this.health.failedRequests++;\n this.health.consecutiveFailures++;\n this.health.lastFailure = new Date();\n this.health.lastCheck = new Date();\n\n this.updateStatus();\n this.emit('failure', { \n error: typeof error === 'string' ? error : error.message,\n consecutiveFailures: this.health.consecutiveFailures \n });\n }\n\n /**\n * Get current connection health\n */\n getHealth(): ConnectionHealth {\n return { ...this.health };\n }\n\n /**\n * Get current connection status\n */\n getStatus(): ConnectionStatus {\n return this.health.status;\n }\n\n /**\n * Check if API is currently available\n */\n isAvailable(): boolean {\n return this.health.status === 'connected' || this.health.status === 'degraded';\n }\n\n /**\n * Get reliability percentage\n */\n getReliability(): number {\n if (this.health.totalRequests === 0) return 0;\n return (this.health.successfulRequests / this.health.totalRequests) * 100;\n }\n\n /**\n * Reset all statistics\n */\n reset(): void {\n this.health = {\n status: 'disconnected',\n lastCheck: null,\n lastSuccess: null,\n lastFailure: null,\n consecutiveFailures: 0,\n totalRequests: 0,\n successfulRequests: 0,\n failedRequests: 0,\n averageResponseTime: 0,\n };\n this.emit('reset');\n }\n\n /**\n * Get detailed status report for development\n */\n getDebugReport(): string {\n const reliability = this.getReliability().toFixed(2);\n const avgTime = this.health.averageResponseTime.toFixed(2);\n \n return `API Connection Status:\n Status: ${this.health.status}\n Reliability: ${reliability}%\n Total Requests: ${this.health.totalRequests}\n Successful: ${this.health.successfulRequests}\n Failed: ${this.health.failedRequests}\n Consecutive Failures: ${this.health.consecutiveFailures}\n Avg Response Time: ${avgTime}ms\n Last Check: ${this.health.lastCheck?.toISOString() || 'never'}\n Last Success: ${this.health.lastSuccess?.toISOString() || 'never'}\n Last Failure: ${this.health.lastFailure?.toISOString() || 'never'}`;\n }\n\n private updateStatus(): void {\n const reliability = this.health.totalRequests > 0\n ? this.health.successfulRequests / this.health.totalRequests\n : 0;\n\n // More nuanced status determination\n if (this.health.totalRequests === 0) {\n // No requests yet - don't assume disconnected\n this.health.status = 'checking';\n } else if (this.health.consecutiveFailures >= 3) {\n // Multiple consecutive failures indicates real connectivity issue\n this.health.status = 'disconnected';\n } else if (reliability < this.DEGRADATION_THRESHOLD && this.health.totalRequests >= 5) {\n // Only degrade if we have enough samples and reliability is low\n this.health.status = 'degraded';\n } else if (reliability >= this.DEGRADATION_THRESHOLD || this.health.successfulRequests > 0) {\n // If we have any successes, we're connected\n this.health.status = 'connected';\n } else {\n // Default to checking if uncertain\n this.health.status = 'checking';\n }\n\n // Emit status change events (only on actual changes)\n if (this.health.status === 'disconnected') {\n this.emit('disconnected');\n } else if (this.health.status === 'degraded') {\n this.emit('degraded');\n } else if (this.health.status === 'connected') {\n this.emit('connected');\n } else if (this.health.status === 'checking') {\n this.emit('checking');\n }\n }\n\n private getBaseUrl(): string {\n // Try to get base URL from environment or fallback\n if (typeof window !== 'undefined') {\n return process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';\n }\n return process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';\n }\n}\n\n/**\n * Global connection status utility\n */\nexport const connectionMonitor = ApiConnectionMonitor.getInstance();\n\n/**\n * Hook for React components to monitor connection status\n */\nexport function useConnectionStatus() {\n const monitor = ApiConnectionMonitor.getInstance();\n \n return {\n status: monitor.getStatus(),\n health: monitor.getHealth(),\n isAvailable: monitor.isAvailable(),\n reliability: monitor.getReliability(),\n checkHealth: () => monitor.performHealthCheck(),\n getDebugReport: () => monitor.getDebugReport(),\n };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/base/ApiError.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/base/BaseApiClient.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'path' is defined but never used.","line":170,"column":42,"nodeType":"Identifier","messageId":"unusedVar","endLine":170,"endColumn":54},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'method' is defined but never used.","line":170,"column":56,"nodeType":"Identifier","messageId":"unusedVar","endLine":170,"endColumn":70},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'path' is defined but never used.","line":186,"column":51,"nodeType":"Identifier","messageId":"unusedVar","endLine":186,"endColumn":63}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Base API Client for HTTP operations\n *\n * Provides generic HTTP methods with common request/response handling,\n * error handling, authentication, retry logic, and circuit breaker.\n */\n\nimport { Logger } from '../../interfaces/Logger';\nimport { ErrorReporter } from '../../interfaces/ErrorReporter';\nimport { ApiError, ApiErrorType } from './ApiError';\nimport { RetryHandler, CircuitBreakerRegistry, DEFAULT_RETRY_CONFIG } from './RetryHandler';\nimport { ApiConnectionMonitor } from './ApiConnectionMonitor';\nimport { getGlobalApiLogger } from '@/lib/infrastructure/ApiRequestLogger';\n\nexport interface BaseApiClientOptions {\n timeout?: number;\n retry?: boolean;\n retryConfig?: typeof DEFAULT_RETRY_CONFIG;\n}\n\nexport class BaseApiClient {\n protected baseUrl: string;\n private errorReporter: ErrorReporter;\n private logger: Logger;\n private retryHandler: RetryHandler;\n private circuitBreakerRegistry: CircuitBreakerRegistry;\n private connectionMonitor: ApiConnectionMonitor;\n private defaultOptions: BaseApiClientOptions;\n\n constructor(\n baseUrl: string,\n errorReporter: ErrorReporter,\n logger: Logger,\n options: BaseApiClientOptions = {}\n ) {\n this.baseUrl = baseUrl;\n this.errorReporter = errorReporter;\n this.logger = logger;\n this.retryHandler = new RetryHandler(options.retryConfig || DEFAULT_RETRY_CONFIG);\n this.circuitBreakerRegistry = CircuitBreakerRegistry.getInstance();\n this.connectionMonitor = ApiConnectionMonitor.getInstance();\n this.defaultOptions = {\n timeout: options.timeout || 30000,\n retry: options.retry !== false,\n retryConfig: options.retryConfig || DEFAULT_RETRY_CONFIG,\n };\n\n // Start monitoring connection health\n this.connectionMonitor.startMonitoring();\n }\n\n /**\n * Classify HTTP status code into error type\n */\n private classifyError(status: number): ApiErrorType {\n if (status >= 500) return 'SERVER_ERROR';\n if (status === 429) return 'RATE_LIMIT_ERROR';\n if (status === 401 || status === 403) return 'AUTH_ERROR';\n if (status === 400) return 'VALIDATION_ERROR';\n if (status === 404) return 'NOT_FOUND';\n return 'UNKNOWN_ERROR';\n }\n\n /**\n * Create an ApiError from fetch response\n */\n private async createApiError(\n response: Response,\n method: string,\n path: string,\n retryCount: number = 0\n ): Promise<ApiError> {\n const status = response.status;\n const errorType = this.classifyError(status);\n \n let message = response.statusText;\n let responseText = '';\n\n try {\n responseText = await response.text();\n if (responseText) {\n const errorData = JSON.parse(responseText);\n if (errorData.message) {\n message = errorData.message;\n }\n }\n } catch {\n // Keep default message\n }\n\n return new ApiError(\n message,\n errorType,\n {\n endpoint: path,\n method,\n statusCode: status,\n responseText,\n timestamp: new Date().toISOString(),\n retryCount,\n }\n );\n }\n\n /**\n * Create an ApiError from network/timeout errors\n */\n private createNetworkError(\n error: Error,\n method: string,\n path: string,\n retryCount: number = 0\n ): ApiError {\n let errorType: ApiErrorType = 'NETWORK_ERROR';\n let message = error.message;\n\n // More specific error classification\n if (error.name === 'AbortError') {\n errorType = 'CANCELED_ERROR';\n message = 'Request was canceled';\n } else if (error.name === 'TypeError' && error.message.includes('fetch')) {\n errorType = 'NETWORK_ERROR';\n // Check for CORS specifically\n if (error.message.includes('Failed to fetch') || error.message.includes('fetch failed')) {\n message = 'Unable to connect to server. Possible CORS or network issue.';\n }\n } else if (error.message.includes('timeout') || error.message.includes('timed out')) {\n errorType = 'TIMEOUT_ERROR';\n message = 'Request timed out after 30 seconds';\n } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {\n errorType = 'NETWORK_ERROR';\n // This could be CORS, network down, or server not responding\n message = 'Network error: Unable to reach the API server';\n }\n\n return new ApiError(\n message,\n errorType,\n {\n endpoint: path,\n method,\n timestamp: new Date().toISOString(),\n retryCount,\n // Add helpful context for developers\n troubleshooting: this.getTroubleshootingContext(error, path),\n isRetryable: this.isRetryableError(errorType),\n isConnectivity: errorType === 'NETWORK_ERROR' || errorType === 'TIMEOUT_ERROR',\n developerHint: this.getDeveloperHint(error, path, method),\n },\n error\n );\n }\n\n /**\n * Check if error type is retryable\n */\n private isRetryableError(errorType: ApiErrorType): boolean {\n const retryableTypes: ApiErrorType[] = [\n 'NETWORK_ERROR',\n 'SERVER_ERROR',\n 'RATE_LIMIT_ERROR',\n 'TIMEOUT_ERROR',\n ];\n return retryableTypes.includes(errorType);\n }\n\n /**\n * Get developer-friendly hint for troubleshooting\n */\n private getDeveloperHint(error: Error, path: string, method: string): string {\n if (error.message.includes('fetch failed') || error.message.includes('Failed to fetch')) {\n return 'Check if API server is running and CORS is configured correctly';\n }\n if (error.message.includes('timeout')) {\n return 'Request timed out - consider increasing timeout or checking network';\n }\n if (error.message.includes('ECONNREFUSED')) {\n return 'Connection refused - verify API server address and port';\n }\n return 'Review network connection and API endpoint configuration';\n }\n\n /**\n * Get troubleshooting context for network errors\n */\n private getTroubleshootingContext(error: Error, path: string): string {\n if (typeof window !== 'undefined') {\n const baseUrl = this.baseUrl;\n const currentOrigin = window.location.origin;\n \n // Check if it's likely a CORS issue\n if (baseUrl && !baseUrl.includes(currentOrigin) && error.message.includes('Failed to fetch')) {\n return 'CORS issue likely. Check API server CORS configuration.';\n }\n \n // Check if API server is same origin\n if (baseUrl.includes(currentOrigin) || baseUrl.startsWith('/')) {\n return 'Same-origin request. Check if API server is running.';\n }\n }\n \n return 'Check network connection and API server status.';\n }\n\n protected async request<T>(\n method: string,\n path: string,\n data?: object | FormData,\n options: BaseApiClientOptions & { allowUnauthenticated?: boolean } = {},\n ): Promise<T> {\n const finalOptions = { ...this.defaultOptions, ...options };\n const endpoint = `${this.baseUrl}${path}`;\n\n // Check circuit breaker\n const circuitBreaker = this.circuitBreakerRegistry.getBreaker(path);\n if (!circuitBreaker.canExecute()) {\n const error = new ApiError(\n 'Circuit breaker is open - service temporarily unavailable',\n 'SERVER_ERROR',\n {\n endpoint: path,\n method,\n timestamp: new Date().toISOString(),\n }\n );\n this.handleError(error);\n throw error;\n }\n\n const executeRequest = async (signal: AbortSignal): Promise<T> => {\n const isFormData = typeof FormData !== 'undefined' && data instanceof FormData;\n const headers: HeadersInit = isFormData\n ? {}\n : {\n 'Content-Type': 'application/json',\n };\n\n const config: RequestInit = {\n method,\n headers,\n credentials: 'include',\n signal,\n };\n\n if (data) {\n config.body = isFormData ? data : JSON.stringify(data);\n }\n\n const startTime = Date.now();\n let requestId: string | undefined;\n\n // Log request start (only in development for maximum transparency)\n if (process.env.NODE_ENV === 'development') {\n try {\n const apiLogger = getGlobalApiLogger();\n const headerObj: Record<string, string> = {};\n if (typeof headers === 'object') {\n Object.entries(headers).forEach(([key, value]) => {\n headerObj[key] = value;\n });\n }\n requestId = apiLogger.logRequest(\n endpoint,\n method,\n headerObj,\n data\n );\n } catch (e) {\n // Silent fail - logger might not be initialized\n }\n }\n\n try {\n const response = await fetch(endpoint, config);\n const responseTime = Date.now() - startTime;\n\n // Record success for monitoring\n this.connectionMonitor.recordSuccess(responseTime);\n\n if (!response.ok) {\n if (\n finalOptions.allowUnauthenticated &&\n (response.status === 401 || response.status === 403)\n ) {\n // For auth probe endpoints, 401/403 is expected\n return null as T;\n }\n\n const error = await this.createApiError(response, method, path);\n circuitBreaker.recordFailure();\n this.connectionMonitor.recordFailure(error);\n this.handleError(error);\n\n // Log error\n if (process.env.NODE_ENV === 'development' && requestId) {\n try {\n const apiLogger = getGlobalApiLogger();\n apiLogger.logError(requestId, error, responseTime);\n } catch (e) {\n // Silent fail\n }\n }\n\n throw error;\n }\n\n // Record successful circuit breaker call\n circuitBreaker.recordSuccess();\n\n const text = await response.text();\n if (!text) {\n // Log empty response\n if (process.env.NODE_ENV === 'development' && requestId) {\n try {\n const apiLogger = getGlobalApiLogger();\n apiLogger.logResponse(requestId, response, null, responseTime);\n } catch (e) {\n // Silent fail\n }\n }\n return null as T;\n }\n\n const parsedData = JSON.parse(text) as T;\n\n // Log successful response\n if (process.env.NODE_ENV === 'development' && requestId) {\n try {\n const apiLogger = getGlobalApiLogger();\n apiLogger.logResponse(requestId, response, parsedData, responseTime);\n } catch (e) {\n // Silent fail\n }\n }\n\n return parsedData;\n\n } catch (error) {\n const responseTime = Date.now() - startTime;\n\n if (error instanceof ApiError) {\n throw error;\n }\n\n // Convert to ApiError\n const apiError = this.createNetworkError(error as Error, method, path);\n \n circuitBreaker.recordFailure();\n this.connectionMonitor.recordFailure(apiError);\n this.handleError(apiError);\n\n // Log network error\n if (process.env.NODE_ENV === 'development' && requestId) {\n try {\n const apiLogger = getGlobalApiLogger();\n apiLogger.logError(requestId, apiError, responseTime);\n } catch (e) {\n // Silent fail\n }\n }\n \n throw apiError;\n }\n };\n\n // Wrap with retry logic if enabled\n if (finalOptions.retry) {\n try {\n return await this.retryHandler.execute(executeRequest);\n } catch (error) {\n // If retry exhausted, throw the final error\n throw error;\n }\n } else {\n // No retry, just execute with timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), finalOptions.timeout);\n\n try {\n return await executeRequest(controller.signal);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * Handle errors - log and report\n */\n private handleError(error: ApiError): void {\n const severity = error.getSeverity();\n const message = error.getDeveloperMessage();\n\n // Enhanced context for better debugging\n const enhancedContext = {\n ...error.context,\n severity,\n isRetryable: error.isRetryable(),\n isConnectivity: error.isConnectivityIssue(),\n };\n\n // Use appropriate log level\n if (severity === 'error') {\n this.logger.error(message, error, enhancedContext);\n } else if (severity === 'warn') {\n this.logger.warn(message, enhancedContext);\n } else {\n this.logger.info(message, enhancedContext);\n }\n\n // Report to error tracking\n this.errorReporter.report(error, enhancedContext);\n }\n\n protected get<T>(path: string, options?: BaseApiClientOptions): Promise<T> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n protected post<T>(path: string, data: object, options?: BaseApiClientOptions): Promise<T> {\n return this.request<T>('POST', path, data, options);\n }\n\n protected put<T>(path: string, data: object, options?: BaseApiClientOptions): Promise<T> {\n return this.request<T>('PUT', path, data, options);\n }\n\n protected delete<T>(path: string, options?: BaseApiClientOptions): Promise<T> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n\n protected patch<T>(path: string, data: object, options?: BaseApiClientOptions): Promise<T> {\n return this.request<T>('PATCH', path, data, options);\n }\n\n /**\n * Get current connection health status\n */\n getConnectionStatus() {\n return {\n status: this.connectionMonitor.getStatus(),\n health: this.connectionMonitor.getHealth(),\n isAvailable: this.connectionMonitor.isAvailable(),\n reliability: this.connectionMonitor.getReliability(),\n };\n }\n\n /**\n * Force a health check\n */\n async checkHealth() {\n return this.connectionMonitor.performHealthCheck();\n }\n\n /**\n * Get circuit breaker status for debugging\n */\n getCircuitBreakerStatus() {\n return this.circuitBreakerRegistry.getStatus();\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/base/GracefulDegradation.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":40,"column":46,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":40,"endColumn":49,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[748,751],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[748,751],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Graceful degradation utilities for when API is unavailable\n */\n\nimport { ApiConnectionMonitor } from './ApiConnectionMonitor';\nimport { ApiError } from './ApiError';\n\nexport interface DegradationOptions<T> {\n /**\n * Fallback data to return when API is unavailable\n */\n fallback?: T;\n \n /**\n * Whether to throw error or return fallback\n */\n throwOnError?: boolean;\n \n /**\n * Maximum time to wait for API response\n */\n timeout?: number;\n \n /**\n * Whether to use cached data if available\n */\n useCache?: boolean;\n}\n\nexport interface CacheEntry<T> {\n data: T;\n timestamp: Date;\n expiry: Date;\n}\n\n/**\n * Simple in-memory cache for API responses\n */\nclass ResponseCache {\n private cache = new Map<string, CacheEntry<any>>();\n\n /**\n * Get cached data if not expired\n */\n get<T>(key: string): T | null {\n const entry = this.cache.get(key);\n if (!entry) return null;\n\n if (new Date() > entry.expiry) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.data;\n }\n\n /**\n * Set cached data with expiry\n */\n set<T>(key: string, data: T, ttlMs: number = 300000): void {\n const now = new Date();\n const expiry = new Date(now.getTime() + ttlMs);\n \n this.cache.set(key, {\n data,\n timestamp: now,\n expiry,\n });\n }\n\n /**\n * Clear all cached data\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get cache statistics\n */\n getStats() {\n return {\n size: this.cache.size,\n entries: Array.from(this.cache.entries()).map(([key, entry]) => ({\n key,\n timestamp: entry.timestamp,\n expiry: entry.expiry,\n })),\n };\n }\n}\n\n/**\n * Global cache instance\n */\nexport const responseCache = new ResponseCache();\n\n/**\n * Execute a function with graceful degradation\n */\nexport async function withGracefulDegradation<T>(\n fn: () => Promise<T>,\n options: DegradationOptions<T> = {}\n): Promise<T | undefined> {\n const {\n fallback,\n throwOnError = false,\n timeout = 10000,\n useCache = true,\n } = options;\n\n const monitor = ApiConnectionMonitor.getInstance();\n\n // Check if API is available\n if (!monitor.isAvailable()) {\n // Try cache first\n if (useCache && options.fallback) {\n const cacheKey = `graceful:${fn.toString()}`;\n const cached = responseCache.get<T>(cacheKey);\n if (cached) {\n return cached;\n }\n }\n\n // Return fallback\n if (fallback !== undefined) {\n return fallback;\n }\n\n // Throw error if no fallback\n if (throwOnError) {\n throw new ApiError(\n 'API unavailable and no fallback provided',\n 'NETWORK_ERROR',\n {\n timestamp: new Date().toISOString(),\n }\n );\n }\n\n // Return undefined (caller must handle)\n return undefined;\n }\n\n // API is available, try to execute\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const result = await Promise.race([\n fn(),\n new Promise<never>((_, reject) => {\n controller.signal.addEventListener('abort', () => {\n reject(new Error('Request timeout'));\n });\n }),\n ]);\n\n clearTimeout(timeoutId);\n\n // Cache the result if enabled\n if (useCache && result !== null && result !== undefined) {\n const cacheKey = `graceful:${fn.toString()}`;\n responseCache.set(cacheKey, result);\n }\n\n return result;\n\n } catch (error) {\n // Record failure in monitor\n if (error instanceof ApiError) {\n monitor.recordFailure(error);\n } else {\n monitor.recordFailure(error as Error);\n }\n\n // Try cache as fallback\n if (useCache && options.fallback) {\n const cacheKey = `graceful:${fn.toString()}`;\n const cached = responseCache.get<T>(cacheKey);\n if (cached) {\n return cached;\n }\n }\n\n // Return fallback if provided\n if (fallback !== undefined) {\n return fallback;\n }\n\n // Re-throw or return undefined\n if (throwOnError) {\n throw error;\n }\n\n return undefined;\n }\n}\n\n/**\n * Service wrapper for graceful degradation\n */\nexport class GracefulService<T> {\n private monitor: ApiConnectionMonitor;\n private cacheKey: string;\n\n constructor(\n private serviceName: string,\n private getData: () => Promise<T>,\n private defaultFallback: T\n ) {\n this.monitor = ApiConnectionMonitor.getInstance();\n this.cacheKey = `service:${serviceName}`;\n }\n\n /**\n * Get data with graceful degradation\n */\n async get(options: Partial<DegradationOptions<T>> = {}): Promise<T> {\n const result = await withGracefulDegradation(this.getData, {\n fallback: this.defaultFallback,\n throwOnError: false,\n useCache: true,\n ...options,\n });\n\n return result ?? this.defaultFallback;\n }\n\n /**\n * Force refresh data\n */\n async refresh(): Promise<T> {\n responseCache.clear(); // Clear cache for this service\n return this.get({ useCache: false });\n }\n\n /**\n * Get service health status\n */\n getStatus() {\n const health = this.monitor.getHealth();\n const isAvailable = this.monitor.isAvailable();\n \n return {\n serviceName: this.serviceName,\n available: isAvailable,\n reliability: health.totalRequests > 0 \n ? (health.successfulRequests / health.totalRequests) * 100 \n : 100,\n lastCheck: health.lastCheck,\n };\n }\n}\n\n/**\n * Offline mode detection\n */\nexport class OfflineDetector {\n private static instance: OfflineDetector;\n private isOffline = false;\n private listeners: Array<(isOffline: boolean) => void> = [];\n\n private constructor() {\n if (typeof window !== 'undefined') {\n window.addEventListener('online', () => this.setOffline(false));\n window.addEventListener('offline', () => this.setOffline(true));\n \n // Initial check\n this.isOffline = !navigator.onLine;\n }\n }\n\n static getInstance(): OfflineDetector {\n if (!OfflineDetector.instance) {\n OfflineDetector.instance = new OfflineDetector();\n }\n return OfflineDetector.instance;\n }\n\n private setOffline(offline: boolean): void {\n if (this.isOffline !== offline) {\n this.isOffline = offline;\n this.listeners.forEach(listener => listener(offline));\n }\n }\n\n /**\n * Check if browser is offline\n */\n isBrowserOffline(): boolean {\n return this.isOffline;\n }\n\n /**\n * Add listener for offline status changes\n */\n onStatusChange(callback: (isOffline: boolean) => void): void {\n this.listeners.push(callback);\n }\n\n /**\n * Remove listener\n */\n removeListener(callback: (isOffline: boolean) => void): void {\n this.listeners = this.listeners.filter(cb => cb !== callback);\n }\n}\n\n/**\n * Hook for offline detection\n */\nexport function useOfflineStatus() {\n if (typeof window === 'undefined') {\n return false; // Server-side\n }\n\n // This would need to be used in a React component context\n // For now, provide a simple check function\n return OfflineDetector.getInstance().isBrowserOffline();\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/base/RetryHandler.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'ApiErrorType' is defined but never used.","line":5,"column":20,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":32}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Retry logic and circuit breaker for API requests\n */\n\nimport { ApiError, ApiErrorType } from './ApiError';\n\nexport interface RetryConfig {\n maxRetries: number;\n baseDelay: number; // milliseconds\n maxDelay: number; // milliseconds\n backoffMultiplier: number;\n timeout: number; // milliseconds\n}\n\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 3,\n baseDelay: 1000,\n maxDelay: 10000,\n backoffMultiplier: 2,\n timeout: 30000,\n};\n\nexport interface CircuitBreakerConfig {\n failureThreshold: number;\n successThreshold: number;\n timeout: number; // milliseconds before trying again\n}\n\nexport const DEFAULT_CIRCUIT_BREAKER_CONFIG: CircuitBreakerConfig = {\n failureThreshold: 5,\n successThreshold: 3,\n timeout: 60000, // 1 minute\n};\n\nexport class CircuitBreaker {\n private failures = 0;\n private successes = 0;\n private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';\n private lastFailureTime: number | null = null;\n private readonly config: CircuitBreakerConfig;\n\n constructor(config: CircuitBreakerConfig = DEFAULT_CIRCUIT_BREAKER_CONFIG) {\n this.config = config;\n }\n\n /**\n * Check if request should proceed\n */\n canExecute(): boolean {\n if (this.state === 'CLOSED') {\n return true;\n }\n\n if (this.state === 'OPEN') {\n const now = Date.now();\n if (this.lastFailureTime && now - this.lastFailureTime > this.config.timeout) {\n this.state = 'HALF_OPEN';\n return true;\n }\n return false;\n }\n\n // HALF_OPEN - allow one request to test if service recovered\n return true;\n }\n\n /**\n * Record a successful request\n */\n recordSuccess(): void {\n if (this.state === 'HALF_OPEN') {\n this.successes++;\n if (this.successes >= this.config.successThreshold) {\n this.reset();\n }\n } else if (this.state === 'CLOSED') {\n // Keep failures in check\n this.failures = Math.max(0, this.failures - 1);\n }\n }\n\n /**\n * Record a failed request\n */\n recordFailure(): void {\n this.failures++;\n this.lastFailureTime = Date.now();\n\n if (this.state === 'HALF_OPEN') {\n this.state = 'OPEN';\n this.successes = 0;\n } else if (this.state === 'CLOSED' && this.failures >= this.config.failureThreshold) {\n this.state = 'OPEN';\n }\n }\n\n /**\n * Get current state\n */\n getState(): string {\n return this.state;\n }\n\n /**\n * Get failure count\n */\n getFailures(): number {\n return this.failures;\n }\n\n /**\n * Reset the circuit breaker\n */\n reset(): void {\n this.failures = 0;\n this.successes = 0;\n this.state = 'CLOSED';\n this.lastFailureTime = null;\n }\n}\n\nexport class RetryHandler {\n private config: RetryConfig;\n private abortController: AbortController | null = null;\n\n constructor(config: RetryConfig = DEFAULT_RETRY_CONFIG) {\n this.config = config;\n }\n\n /**\n * Execute a function with retry logic\n */\n async execute<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n isRetryable?: (error: ApiError) => boolean\n ): Promise<T> {\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n\n let lastError: Error | null = null;\n \n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n // Check if already aborted\n if (signal.aborted) {\n throw new Error('Request aborted');\n }\n\n const result = await fn(signal);\n return result;\n } catch (error) {\n lastError = error as Error;\n\n // Check if we should abort\n if (signal.aborted) {\n throw error;\n }\n\n // Check if this is the last attempt\n if (attempt === this.config.maxRetries) {\n break;\n }\n\n // Check if error is retryable\n if (error instanceof ApiError) {\n if (!error.isRetryable()) {\n throw error;\n }\n if (isRetryable && !isRetryable(error)) {\n throw error;\n }\n }\n\n // Calculate delay with exponential backoff\n const delay = this.calculateDelay(attempt);\n \n // Wait before retrying\n await this.sleep(delay, signal);\n }\n }\n\n // All retries exhausted\n throw lastError;\n }\n\n /**\n * Cancel the current request\n */\n abort(): void {\n if (this.abortController) {\n this.abortController.abort();\n }\n }\n\n /**\n * Calculate delay for retry attempt\n */\n private calculateDelay(attempt: number): number {\n const delay = Math.min(\n this.config.baseDelay * Math.pow(this.config.backoffMultiplier, attempt),\n this.config.maxDelay\n );\n // Add jitter to prevent thundering herd\n const jitter = Math.random() * 0.3 * delay;\n return delay + jitter;\n }\n\n /**\n * Sleep with abort support\n */\n private sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n signal.removeEventListener('abort', abortHandler);\n resolve();\n }, ms);\n\n const abortHandler = () => {\n clearTimeout(timeout);\n signal.removeEventListener('abort', abortHandler);\n reject(new Error('Request aborted during retry delay'));\n };\n\n signal.addEventListener('abort', abortHandler, { once: true });\n });\n }\n}\n\n/**\n * Global circuit breaker registry for different API endpoints\n */\nexport class CircuitBreakerRegistry {\n private static instance: CircuitBreakerRegistry;\n private breakers: Map<string, CircuitBreaker> = new Map();\n\n private constructor() {}\n\n static getInstance(): CircuitBreakerRegistry {\n if (!CircuitBreakerRegistry.instance) {\n CircuitBreakerRegistry.instance = new CircuitBreakerRegistry();\n }\n return CircuitBreakerRegistry.instance;\n }\n\n /**\n * Get or create circuit breaker for a specific endpoint\n */\n getBreaker(endpoint: string, config?: CircuitBreakerConfig): CircuitBreaker {\n if (!this.breakers.has(endpoint)) {\n this.breakers.set(endpoint, new CircuitBreaker(config));\n }\n return this.breakers.get(endpoint)!;\n }\n\n /**\n * Reset all circuit breakers\n */\n resetAll(): void {\n this.breakers.forEach(breaker => breaker.reset());\n }\n\n /**\n * Get status of all circuit breakers\n */\n getStatus(): Record<string, { state: string; failures: number }> {\n const status: Record<string, { state: string; failures: number }> = {};\n this.breakers.forEach((breaker, endpoint) => {\n status[endpoint] = {\n state: breaker.getState(),\n failures: breaker.getFailures(),\n };\n });\n return status;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/dashboard/DashboardApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/drivers/DriversApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { LeaguesApiClient } from './leagues/LeaguesApiClient';\nimport { RacesApiClient } from './races/RacesApiClient';\nimport { DriversApiClient } from './drivers/DriversApiClient';\nimport { TeamsApiClient } from './teams/TeamsApiClient';\nimport { SponsorsApiClient } from './sponsors/SponsorsApiClient';\nimport { MediaApiClient } from './media/MediaApiClient';\nimport { AnalyticsApiClient } from './analytics/AnalyticsApiClient';\nimport { AuthApiClient } from './auth/AuthApiClient';\nimport { PaymentsApiClient } from './payments/PaymentsApiClient';\nimport { DashboardApiClient } from './dashboard/DashboardApiClient';\nimport { PenaltiesApiClient } from './penalties/PenaltiesApiClient';\nimport { ProtestsApiClient } from './protests/ProtestsApiClient';\nimport { AdminApiClient } from './admin/AdminApiClient';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\n\n/**\n * Main API Client\n *\n * Orchestrates all domain-specific API clients with consistent configuration.\n */\nexport class ApiClient {\n public readonly leagues: LeaguesApiClient;\n public readonly races: RacesApiClient;\n public readonly drivers: DriversApiClient;\n public readonly teams: TeamsApiClient;\n public readonly sponsors: SponsorsApiClient;\n public readonly media: MediaApiClient;\n public readonly analytics: AnalyticsApiClient;\n public readonly auth: AuthApiClient;\n public readonly payments: PaymentsApiClient;\n public readonly dashboard: DashboardApiClient;\n public readonly penalties: PenaltiesApiClient;\n public readonly protests: ProtestsApiClient;\n public readonly admin: AdminApiClient;\n\n constructor(baseUrl: string) {\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: process.env.NODE_ENV === 'production',\n });\n\n this.leagues = new LeaguesApiClient(baseUrl, errorReporter, logger);\n this.races = new RacesApiClient(baseUrl, errorReporter, logger);\n this.drivers = new DriversApiClient(baseUrl, errorReporter, logger);\n this.teams = new TeamsApiClient(baseUrl, errorReporter, logger);\n this.sponsors = new SponsorsApiClient(baseUrl, errorReporter, logger);\n this.media = new MediaApiClient(baseUrl, errorReporter, logger);\n this.analytics = new AnalyticsApiClient(baseUrl, errorReporter, logger);\n this.auth = new AuthApiClient(baseUrl, errorReporter, logger);\n this.payments = new PaymentsApiClient(baseUrl, errorReporter, logger);\n this.dashboard = new DashboardApiClient(baseUrl, errorReporter, logger);\n this.penalties = new PenaltiesApiClient(baseUrl, errorReporter, logger);\n this.protests = new ProtestsApiClient(baseUrl, errorReporter, logger);\n this.admin = new AdminApiClient(baseUrl, errorReporter, logger);\n }\n}\n\n// ============================================================================\n// Singleton Instance\n// ============================================================================\n\nconst API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';\n\nexport const api = new ApiClient(API_BASE_URL);","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/leagues/LeaguesApiClient.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_example' is assigned a value but never used.","line":137,"column":22,"nodeType":"Identifier","messageId":"unusedVar","endLine":137,"endColumn":30},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_example' is assigned a value but never used.","line":148,"column":22,"nodeType":"Identifier","messageId":"unusedVar","endLine":148,"endColumn":30}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { BaseApiClient } from '../base/BaseApiClient';\nimport type { AllLeaguesWithCapacityDTO } from '../../types/generated/AllLeaguesWithCapacityDTO';\nimport type { TotalLeaguesDTO } from '../../types/generated/TotalLeaguesDTO';\nimport type { LeagueStandingsDTO } from '../../types/generated/LeagueStandingsDTO';\nimport type { LeagueScheduleDTO } from '../../types/generated/LeagueScheduleDTO';\nimport type { LeagueMembershipsDTO } from '../../types/generated/LeagueMembershipsDTO';\nimport type { CreateLeagueInputDTO } from '../../types/generated/CreateLeagueInputDTO';\nimport type { CreateLeagueOutputDTO } from '../../types/generated/CreateLeagueOutputDTO';\nimport type { SponsorshipDetailDTO } from '../../types/generated/SponsorshipDetailDTO';\nimport type { RaceDTO } from '../../types/generated/RaceDTO';\nimport type { GetLeagueAdminConfigOutputDTO } from '../../types/generated/GetLeagueAdminConfigOutputDTO';\nimport type { LeagueScoringPresetDTO } from '../../types/generated/LeagueScoringPresetDTO';\nimport type { LeagueSeasonSummaryDTO } from '../../types/generated/LeagueSeasonSummaryDTO';\nimport type { CreateLeagueScheduleRaceInputDTO } from '../../types/generated/CreateLeagueScheduleRaceInputDTO';\nimport type { CreateLeagueScheduleRaceOutputDTO } from '../../types/generated/CreateLeagueScheduleRaceOutputDTO';\nimport type { UpdateLeagueScheduleRaceInputDTO } from '../../types/generated/UpdateLeagueScheduleRaceInputDTO';\nimport type { LeagueScheduleRaceMutationSuccessDTO } from '../../types/generated/LeagueScheduleRaceMutationSuccessDTO';\nimport type { LeagueSeasonSchedulePublishOutputDTO } from '../../types/generated/LeagueSeasonSchedulePublishOutputDTO';\nimport type { LeagueRosterMemberDTO } from '../../types/generated/LeagueRosterMemberDTO';\nimport type { LeagueRosterJoinRequestDTO } from '../../types/generated/LeagueRosterJoinRequestDTO';\nimport type { ApproveJoinRequestOutputDTO } from '../../types/generated/ApproveJoinRequestOutputDTO';\nimport type { RejectJoinRequestOutputDTO } from '../../types/generated/RejectJoinRequestOutputDTO';\nimport type { UpdateLeagueMemberRoleOutputDTO } from '../../types/generated/UpdateLeagueMemberRoleOutputDTO';\nimport type { RemoveLeagueMemberOutputDTO } from '../../types/generated/RemoveLeagueMemberOutputDTO';\nimport type { AllLeaguesWithCapacityAndScoringDTO } from '../../types/AllLeaguesWithCapacityAndScoringDTO';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isRaceDTO(value: unknown): value is RaceDTO {\n if (!isRecord(value)) return false;\n return typeof value.id === 'string' && typeof value.name === 'string' && typeof value.date === 'string';\n}\n\nfunction parseRaceDTOArray(value: unknown): RaceDTO[] {\n if (!Array.isArray(value)) return [];\n return value.filter(isRaceDTO);\n}\n\n/**\n * Leagues API Client\n *\n * Handles all league-related API operations.\n */\nexport class LeaguesApiClient extends BaseApiClient {\n /** Get all leagues with capacity information */\n getAllWithCapacity(): Promise<AllLeaguesWithCapacityDTO> {\n return this.get<AllLeaguesWithCapacityDTO>('/leagues/all-with-capacity');\n }\n\n /** Get all leagues with capacity + scoring summary (for leagues page filters) */\n getAllWithCapacityAndScoring(): Promise<AllLeaguesWithCapacityAndScoringDTO> {\n return this.get<AllLeaguesWithCapacityAndScoringDTO>('/leagues/all-with-capacity-and-scoring');\n }\n\n /** Get total number of leagues */\n getTotal(): Promise<TotalLeaguesDTO> {\n return this.get<TotalLeaguesDTO>('/leagues/total-leagues');\n }\n\n /** Get league standings */\n getStandings(leagueId: string): Promise<LeagueStandingsDTO> {\n return this.get<LeagueStandingsDTO>(`/leagues/${leagueId}/standings`);\n }\n\n /** Get league schedule */\n getSchedule(leagueId: string, seasonId?: string): Promise<LeagueScheduleDTO> {\n const qs = seasonId ? `?seasonId=${encodeURIComponent(seasonId)}` : '';\n return this.get<LeagueScheduleDTO>(`/leagues/${leagueId}/schedule${qs}`);\n }\n\n /** Get league memberships */\n getMemberships(leagueId: string): Promise<LeagueMembershipsDTO> {\n return this.get<LeagueMembershipsDTO>(`/leagues/${leagueId}/memberships`);\n }\n\n /** Create a new league */\n create(input: CreateLeagueInputDTO): Promise<CreateLeagueOutputDTO> {\n return this.post<CreateLeagueOutputDTO>('/leagues', input);\n }\n\n /** Remove a member from league */\n removeMember(leagueId: string, performerDriverId: string, targetDriverId: string): Promise<{ success: boolean }> {\n return this.patch<{ success: boolean }>(`/leagues/${leagueId}/members/${targetDriverId}/remove`, { performerDriverId });\n }\n\n /** Update a member's role in league */\n updateMemberRole(leagueId: string, performerDriverId: string, targetDriverId: string, newRole: string): Promise<{ success: boolean }> {\n return this.patch<{ success: boolean }>(`/leagues/${leagueId}/members/${targetDriverId}/role`, { performerDriverId, newRole });\n }\n\n /** Get league seasons */\n getSeasons(leagueId: string): Promise<LeagueSeasonSummaryDTO[]> {\n return this.get<LeagueSeasonSummaryDTO[]>(`/leagues/${leagueId}/seasons`);\n }\n\n /** Get season sponsorships */\n getSeasonSponsorships(seasonId: string): Promise<{ sponsorships: SponsorshipDetailDTO[] }> {\n return this.get<{ sponsorships: SponsorshipDetailDTO[] }>(`/leagues/seasons/${seasonId}/sponsorships`);\n }\n\n /** Get league config */\n getLeagueConfig(leagueId: string): Promise<GetLeagueAdminConfigOutputDTO> {\n return this.get<GetLeagueAdminConfigOutputDTO>(`/leagues/${leagueId}/config`);\n }\n\n /** Get league scoring presets */\n getScoringPresets(): Promise<{ presets: LeagueScoringPresetDTO[] }> {\n return this.get<{ presets: LeagueScoringPresetDTO[] }>(`/leagues/scoring-presets`);\n }\n\n /** Transfer league ownership */\n transferOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<{ success: boolean }> {\n return this.post<{ success: boolean }>(`/leagues/${leagueId}/transfer-ownership`, {\n currentOwnerId,\n newOwnerId,\n });\n }\n\n /** Publish a league season schedule (admin/owner only; actor derived from session) */\n publishSeasonSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {\n return this.post<LeagueSeasonSchedulePublishOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/publish`, {});\n }\n\n /** Unpublish a league season schedule (admin/owner only; actor derived from session) */\n unpublishSeasonSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {\n return this.post<LeagueSeasonSchedulePublishOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/unpublish`, {});\n }\n\n /** Create a schedule race for a league season (admin/owner only; actor derived from session) */\n createSeasonScheduleRace(\n leagueId: string,\n seasonId: string,\n input: CreateLeagueScheduleRaceInputDTO,\n ): Promise<CreateLeagueScheduleRaceOutputDTO> {\n const { example: _example, ...payload } = input;\n return this.post<CreateLeagueScheduleRaceOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races`, payload);\n }\n\n /** Update a schedule race for a league season (admin/owner only; actor derived from session) */\n updateSeasonScheduleRace(\n leagueId: string,\n seasonId: string,\n raceId: string,\n input: UpdateLeagueScheduleRaceInputDTO,\n ): Promise<LeagueScheduleRaceMutationSuccessDTO> {\n const { example: _example, ...payload } = input;\n return this.patch<LeagueScheduleRaceMutationSuccessDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races/${raceId}`, payload);\n }\n\n /** Delete a schedule race for a league season (admin/owner only; actor derived from session) */\n deleteSeasonScheduleRace(\n leagueId: string,\n seasonId: string,\n raceId: string,\n ): Promise<LeagueScheduleRaceMutationSuccessDTO> {\n return this.delete<LeagueScheduleRaceMutationSuccessDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races/${raceId}`);\n }\n\n /** Get races for a league */\n async getRaces(leagueId: string): Promise<{ races: RaceDTO[] }> {\n const response = await this.get<{ races?: unknown }>(`/leagues/${leagueId}/races`);\n return { races: parseRaceDTOArray(response?.races) };\n }\n\n /** Admin roster: list current members (admin/owner only; actor derived from session) */\n getAdminRosterMembers(leagueId: string): Promise<LeagueRosterMemberDTO[]> {\n return this.get<LeagueRosterMemberDTO[]>(`/leagues/${leagueId}/admin/roster/members`);\n }\n\n /** Admin roster: list pending join requests (admin/owner only; actor derived from session) */\n getAdminRosterJoinRequests(leagueId: string): Promise<LeagueRosterJoinRequestDTO[]> {\n return this.get<LeagueRosterJoinRequestDTO[]>(`/leagues/${leagueId}/admin/roster/join-requests`);\n }\n\n /** Admin roster: approve a join request (admin/owner only; actor derived from session) */\n approveRosterJoinRequest(leagueId: string, joinRequestId: string): Promise<ApproveJoinRequestOutputDTO> {\n return this.post<ApproveJoinRequestOutputDTO>(`/leagues/${leagueId}/admin/roster/join-requests/${joinRequestId}/approve`, {});\n }\n\n /** Admin roster: reject a join request (admin/owner only; actor derived from session) */\n rejectRosterJoinRequest(leagueId: string, joinRequestId: string): Promise<RejectJoinRequestOutputDTO> {\n return this.post<RejectJoinRequestOutputDTO>(`/leagues/${leagueId}/admin/roster/join-requests/${joinRequestId}/reject`, {});\n }\n\n /** Admin roster: update member role (admin/owner only; actor derived from session) */\n updateRosterMemberRole(leagueId: string, targetDriverId: string, newRole: string): Promise<UpdateLeagueMemberRoleOutputDTO> {\n return this.patch<UpdateLeagueMemberRoleOutputDTO>(`/leagues/${leagueId}/admin/roster/members/${targetDriverId}/role`, { newRole });\n }\n\n /** Admin roster: remove member (admin/owner only; actor derived from session) */\n removeRosterMember(leagueId: string, targetDriverId: string): Promise<RemoveLeagueMemberOutputDTO> {\n return this.patch<RemoveLeagueMemberOutputDTO>(`/leagues/${leagueId}/admin/roster/members/${targetDriverId}/remove`, {});\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/media/MediaApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/payments/PaymentsApiClient.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'GetWalletTransactionsOutputDto' is defined but never used.","line":49,"column":6,"nodeType":"Identifier","messageId":"unusedVar","endLine":49,"endColumn":36},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'DeletePrizeInputDto' is defined but never used.","line":73,"column":6,"nodeType":"Identifier","messageId":"unusedVar","endLine":73,"endColumn":25}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { BaseApiClient } from '../base/BaseApiClient';\nimport type { MembershipFeeDTO } from '../../types/generated/MembershipFeeDTO';\nimport type { MemberPaymentDTO } from '../../types/generated/MemberPaymentDTO';\nimport type { PaymentDTO } from '../../types/generated/PaymentDTO';\nimport type { PrizeDTO } from '../../types/generated/PrizeDTO';\nimport type { TransactionDTO } from '../../types/generated/TransactionDTO';\nimport type { UpdatePaymentStatusInputDTO } from '../../types/generated/UpdatePaymentStatusInputDTO';\nimport type { WalletDTO } from '../../types/generated/WalletDTO';\n\n// Define missing types that are not fully generated\ntype GetPaymentsOutputDto = { payments: PaymentDTO[] };\ntype CreatePaymentInputDto = {\n type: 'sponsorship' | 'membership_fee';\n amount: number;\n payerId: string;\n payerType: 'sponsor' | 'driver';\n leagueId: string;\n seasonId?: string;\n};\ntype CreatePaymentOutputDto = { payment: PaymentDTO };\ntype GetMembershipFeesOutputDto = {\n fee: MembershipFeeDTO | null;\n payments: MemberPaymentDTO[]\n};\ntype GetPrizesOutputDto = { prizes: PrizeDTO[] };\ntype GetWalletOutputDto = {\n wallet: WalletDTO;\n transactions: TransactionDTO[]\n};\ntype ProcessWalletTransactionInputDto = {\n leagueId: string;\n type: 'deposit' | 'withdrawal' | 'platform_fee';\n amount: number;\n description: string;\n referenceId?: string;\n referenceType?: 'sponsorship' | 'membership_fee' | 'prize';\n};\ntype ProcessWalletTransactionOutputDto = {\n wallet: WalletDTO;\n transaction: TransactionDTO\n};\ntype UpdateMemberPaymentInputDto = {\n feeId: string;\n driverId: string;\n status?: 'pending' | 'paid' | 'overdue';\n paidAt?: Date | string;\n};\ntype UpdateMemberPaymentOutputDto = { payment: MemberPaymentDTO };\ntype GetWalletTransactionsOutputDto = { transactions: TransactionDTO[] };\ntype UpdatePaymentStatusOutputDto = { payment: PaymentDTO };\ntype UpsertMembershipFeeInputDto = {\n leagueId: string;\n seasonId?: string;\n type: 'season' | 'monthly' | 'per_race';\n amount: number;\n};\ntype UpsertMembershipFeeOutputDto = { fee: MembershipFeeDTO };\ntype CreatePrizeInputDto = {\n leagueId: string;\n seasonId: string;\n position: number;\n name: string;\n amount: number;\n type: 'cash' | 'merchandise' | 'other';\n description?: string;\n};\ntype CreatePrizeOutputDto = { prize: PrizeDTO };\ntype AwardPrizeInputDto = {\n prizeId: string;\n driverId: string;\n};\ntype AwardPrizeOutputDto = { prize: PrizeDTO };\ntype DeletePrizeInputDto = { prizeId: string };\ntype DeletePrizeOutputDto = { success: boolean };\n\n/**\n * Payments API Client\n *\n * Handles all payment-related API operations.\n */\nexport class PaymentsApiClient extends BaseApiClient {\n /** Get payments */\n getPayments(query?: { leagueId?: string; payerId?: string; type?: 'sponsorship' | 'membership_fee'; status?: 'pending' | 'completed' | 'failed' | 'refunded' }): Promise<GetPaymentsOutputDto> {\n const params = new URLSearchParams();\n if (query?.leagueId) params.append('leagueId', query.leagueId);\n if (query?.payerId) params.append('payerId', query.payerId);\n if (query?.type) params.append('type', query.type);\n if (query?.status) params.append('status', query.status);\n const queryString = params.toString();\n return this.get<GetPaymentsOutputDto>(`/payments${queryString ? `?${queryString}` : ''}`);\n }\n\n /** Create a payment */\n createPayment(input: CreatePaymentInputDto): Promise<CreatePaymentOutputDto> {\n return this.post<CreatePaymentOutputDto>('/payments', input);\n }\n\n /** Get membership fees */\n getMembershipFees(query: { leagueId: string; driverId?: string }): Promise<GetMembershipFeesOutputDto> {\n const params = new URLSearchParams();\n params.append('leagueId', query.leagueId);\n if (query.driverId) params.append('driverId', query.driverId);\n const queryString = params.toString();\n return this.get<GetMembershipFeesOutputDto>(`/payments/membership-fees?${queryString}`);\n }\n\n /** Get prizes */\n getPrizes(query?: { leagueId?: string; seasonId?: string }): Promise<GetPrizesOutputDto> {\n const params = new URLSearchParams();\n if (query?.leagueId) params.append('leagueId', query.leagueId);\n if (query?.seasonId) params.append('seasonId', query.seasonId);\n const queryString = params.toString();\n return this.get<GetPrizesOutputDto>(`/payments/prizes${queryString ? `?${queryString}` : ''}`);\n }\n\n /** Get wallet */\n getWallet(query?: { leagueId?: string }): Promise<GetWalletOutputDto> {\n const params = new URLSearchParams();\n if (query?.leagueId) params.append('leagueId', query.leagueId);\n const queryString = params.toString();\n return this.get<GetWalletOutputDto>(`/payments/wallets${queryString ? `?${queryString}` : ''}`);\n }\n\n /** Update payment status */\n updatePaymentStatus(input: UpdatePaymentStatusInputDTO): Promise<UpdatePaymentStatusOutputDto> {\n return this.patch<UpdatePaymentStatusOutputDto>('/payments/status', input);\n }\n\n /** Upsert membership fee */\n upsertMembershipFee(input: UpsertMembershipFeeInputDto): Promise<UpsertMembershipFeeOutputDto> {\n return this.post<UpsertMembershipFeeOutputDto>('/payments/membership-fees', input);\n }\n\n /** Update member payment */\n updateMemberPayment(input: UpdateMemberPaymentInputDto): Promise<UpdateMemberPaymentOutputDto> {\n return this.patch<UpdateMemberPaymentOutputDto>('/payments/membership-fees/member-payment', input);\n }\n\n /** Create prize */\n createPrize(input: CreatePrizeInputDto): Promise<CreatePrizeOutputDto> {\n return this.post<CreatePrizeOutputDto>('/payments/prizes', input);\n }\n\n /** Award prize */\n awardPrize(input: AwardPrizeInputDto): Promise<AwardPrizeOutputDto> {\n return this.patch<AwardPrizeOutputDto>('/payments/prizes/award', input);\n }\n\n /** Delete prize */\n deletePrize(prizeId: string): Promise<DeletePrizeOutputDto> {\n return this.delete<DeletePrizeOutputDto>(`/payments/prizes?prizeId=${prizeId}`);\n }\n\n /** Process wallet transaction */\n processWalletTransaction(input: ProcessWalletTransactionInputDto): Promise<ProcessWalletTransactionOutputDto> {\n return this.post<ProcessWalletTransactionOutputDto>('/payments/wallets/transactions', input);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/penalties/PenaltiesApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/policy/PolicyApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/protests/ProtestsApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/races/RacesApiClient.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AllRacesPageDTO' is defined but never used.","line":15,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":15,"endColumn":30},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'FilteredRacesPageDataDTO' is defined but never used.","line":16,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":16,"endColumn":39}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { BaseApiClient } from '../base/BaseApiClient';\nimport type { RaceStatsDTO } from '../../types/generated/RaceStatsDTO';\nimport type { RacesPageDataRaceDTO } from '../../types/generated/RacesPageDataRaceDTO';\nimport type { RaceResultsDetailDTO } from '../../types/generated/RaceResultsDetailDTO';\nimport type { RaceWithSOFDTO } from '../../types/generated/RaceWithSOFDTO';\nimport type { RegisterForRaceParamsDTO } from '../../types/generated/RegisterForRaceParamsDTO';\nimport type { ImportRaceResultsDTO } from '../../types/generated/ImportRaceResultsDTO';\nimport type { WithdrawFromRaceParamsDTO } from '../../types/generated/WithdrawFromRaceParamsDTO';\nimport type { RaceDetailRaceDTO } from '../../types/generated/RaceDetailRaceDTO';\nimport type { RaceDetailLeagueDTO } from '../../types/generated/RaceDetailLeagueDTO';\nimport type { RaceDetailEntryDTO } from '../../types/generated/RaceDetailEntryDTO';\nimport type { RaceDetailRegistrationDTO } from '../../types/generated/RaceDetailRegistrationDTO';\nimport type { RaceDetailUserResultDTO } from '../../types/generated/RaceDetailUserResultDTO';\nimport type { FileProtestCommandDTO } from '../../types/generated/FileProtestCommandDTO';\nimport type { AllRacesPageDTO } from '../../types/generated/AllRacesPageDTO';\nimport type { FilteredRacesPageDataDTO } from '../../types/tbd/FilteredRacesPageDataDTO';\n\n// Define missing types\nexport type RacesPageDataDTO = { races: RacesPageDataRaceDTO[] };\nexport type RaceDetailDTO = {\n race: RaceDetailRaceDTO | null;\n league: RaceDetailLeagueDTO | null;\n entryList: RaceDetailEntryDTO[];\n registration: RaceDetailRegistrationDTO;\n userResult: RaceDetailUserResultDTO | null;\n error?: string;\n};\nexport type ImportRaceResultsSummaryDTO = {\n success: boolean;\n raceId: string;\n driversProcessed: number;\n resultsRecorded: number;\n errors?: string[];\n};\n\n/**\n * Races API Client\n *\n * Handles all race-related API operations.\n */\nexport class RacesApiClient extends BaseApiClient {\n /** Get total number of races */\n getTotal(): Promise<RaceStatsDTO> {\n return this.get<RaceStatsDTO>('/races/total-races');\n }\n\n /** Get races page data */\n getPageData(leagueId?: string): Promise<RacesPageDataDTO> {\n const query = leagueId ? `?leagueId=${encodeURIComponent(leagueId)}` : '';\n return this.get<RacesPageDataDTO>(`/races/page-data${query}`);\n }\n\n /** Get race detail */\n getDetail(raceId: string, driverId: string): Promise<RaceDetailDTO> {\n return this.get<RaceDetailDTO>(`/races/${raceId}?driverId=${driverId}`);\n }\n\n /** Get race results detail */\n getResultsDetail(raceId: string): Promise<RaceResultsDetailDTO> {\n return this.get<RaceResultsDetailDTO>(`/races/${raceId}/results`);\n }\n\n /** Get race with strength of field */\n getWithSOF(raceId: string): Promise<RaceWithSOFDTO> {\n return this.get<RaceWithSOFDTO>(`/races/${raceId}/sof`);\n }\n\n /** Register for race */\n register(raceId: string, input: RegisterForRaceParamsDTO): Promise<void> {\n return this.post<void>(`/races/${raceId}/register`, input);\n }\n\n /** Import race results */\n importResults(raceId: string, input: ImportRaceResultsDTO): Promise<ImportRaceResultsSummaryDTO> {\n return this.post<ImportRaceResultsSummaryDTO>(`/races/${raceId}/import-results`, input);\n }\n\n /** Withdraw from race */\n withdraw(raceId: string, input: WithdrawFromRaceParamsDTO): Promise<void> {\n return this.post<void>(`/races/${raceId}/withdraw`, input);\n }\n\n /** Cancel race */\n cancel(raceId: string): Promise<void> {\n return this.post<void>(`/races/${raceId}/cancel`, {});\n }\n\n /** Complete race */\n complete(raceId: string): Promise<void> {\n return this.post<void>(`/races/${raceId}/complete`, {});\n }\n\n /** Re-open race */\n reopen(raceId: string): Promise<void> {\n return this.post<void>(`/races/${raceId}/reopen`, {});\n }\n\n /** File a protest */\n fileProtest(input: FileProtestCommandDTO): Promise<void> {\n return this.post<void>('/races/protests/file', input);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/sponsors/SponsorsApiClient.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":69,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":69,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3185,3188],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3185,3188],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":70,"column":15,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":70,"endColumn":18,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3206,3209],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3206,3209],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":71,"column":12,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":71,"endColumn":15,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3224,3227],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3224,3227],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":77,"column":34,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":77,"endColumn":37,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3376,3379],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3376,3379],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":83,"column":13,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":83,"endColumn":16,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3542,3545],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3542,3545],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":84,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":84,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3560,3563],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3560,3563],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":85,"column":12,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":85,"endColumn":15,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3578,3581],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3578,3581],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":92,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":92,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3745,3748],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3745,3748],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":93,"column":20,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":93,"endColumn":23,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3769,3772],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3769,3772],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":94,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":94,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3787,3790],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3787,3790],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":100,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":100,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3936,3939],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3936,3939],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":11,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { BaseApiClient } from '../base/BaseApiClient';\nimport type { CreateSponsorInputDTO } from '../../types/generated/CreateSponsorInputDTO';\nimport type { SponsorDashboardDTO } from '../../types/generated/SponsorDashboardDTO';\nimport type { SponsorSponsorshipsDTO } from '../../types/generated/SponsorSponsorshipsDTO';\nimport type { GetPendingSponsorshipRequestsOutputDTO } from '../../types/generated/GetPendingSponsorshipRequestsOutputDTO';\nimport type { AcceptSponsorshipRequestInputDTO } from '../../types/generated/AcceptSponsorshipRequestInputDTO';\nimport type { RejectSponsorshipRequestInputDTO } from '../../types/generated/RejectSponsorshipRequestInputDTO';\nimport type { GetSponsorOutputDTO } from '../../types/generated/GetSponsorOutputDTO';\nimport type { SponsorDTO } from '../../types/generated/SponsorDTO';\n\n// Types that are not yet generated\nexport type CreateSponsorOutputDto = { id: string; name: string };\nexport type GetEntitySponsorshipPricingResultDto = { pricing: Array<{ entityType: string; price: number }> };\nexport type GetSponsorsOutputDto = { sponsors: SponsorDTO[] };\n\n/**\n * Sponsors API Client\n *\n * Handles all sponsor-related API operations.\n */\nexport class SponsorsApiClient extends BaseApiClient {\n /** Get sponsorship pricing */\n getPricing(): Promise<GetEntitySponsorshipPricingResultDto> {\n return this.get<GetEntitySponsorshipPricingResultDto>('/sponsors/pricing');\n }\n\n /** Get all sponsors */\n getAll(): Promise<GetSponsorsOutputDto> {\n return this.get<GetSponsorsOutputDto>('/sponsors');\n }\n\n /** Create a new sponsor */\n create(input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDto> {\n return this.post<CreateSponsorOutputDto>('/sponsors', input);\n }\n\n /** Get sponsor dashboard */\n getDashboard(sponsorId: string): Promise<SponsorDashboardDTO | null> {\n return this.get<SponsorDashboardDTO | null>(`/sponsors/dashboard/${sponsorId}`);\n }\n\n /** Get sponsor sponsorships */\n getSponsorships(sponsorId: string): Promise<SponsorSponsorshipsDTO | null> {\n return this.get<SponsorSponsorshipsDTO | null>(`/sponsors/${sponsorId}/sponsorships`);\n }\n\n /** Get sponsor by ID */\n getSponsor(sponsorId: string): Promise<GetSponsorOutputDTO | null> {\n return this.get<GetSponsorOutputDTO | null>(`/sponsors/${sponsorId}`);\n }\n\n /** Get pending sponsorship requests for an entity */\n getPendingSponsorshipRequests(params: { entityType: string; entityId: string }): Promise<GetPendingSponsorshipRequestsOutputDTO> {\n return this.get<GetPendingSponsorshipRequestsOutputDTO>(`/sponsors/requests?entityType=${params.entityType}&entityId=${params.entityId}`);\n }\n\n /** Accept a sponsorship request */\n acceptSponsorshipRequest(requestId: string, input: AcceptSponsorshipRequestInputDTO): Promise<void> {\n return this.post(`/sponsors/requests/${requestId}/accept`, input);\n }\n\n /** Reject a sponsorship request */\n rejectSponsorshipRequest(requestId: string, input: RejectSponsorshipRequestInputDTO): Promise<void> {\n return this.post(`/sponsors/requests/${requestId}/reject`, input);\n }\n\n /** Get sponsor billing information */\n getBilling(sponsorId: string): Promise<{\n paymentMethods: any[];\n invoices: any[];\n stats: any;\n }> {\n return this.get(`/sponsors/billing/${sponsorId}`);\n }\n\n /** Get available leagues for sponsorship */\n getAvailableLeagues(): Promise<any[]> {\n return this.get('/sponsors/leagues/available');\n }\n\n /** Get detailed league information */\n getLeagueDetail(leagueId: string): Promise<{\n league: any;\n drivers: any[];\n races: any[];\n }> {\n return this.get(`/sponsors/leagues/${leagueId}/detail`);\n }\n\n /** Get sponsor settings */\n getSettings(sponsorId: string): Promise<{\n profile: any;\n notifications: any;\n privacy: any;\n }> {\n return this.get(`/sponsors/settings/${sponsorId}`);\n }\n\n /** Update sponsor settings */\n updateSettings(sponsorId: string, input: any): Promise<void> {\n return this.put(`/sponsors/settings/${sponsorId}`, input);\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/teams/TeamsApiClient.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'LeagueMemberDTO' is defined but never used.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":25}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { LeagueMemberDTO } from '@/lib/types/generated/LeagueMemberDTO';\nimport type { GetAllTeamsOutputDTO } from '@/lib/types/generated/GetAllTeamsOutputDTO';\nimport type { GetTeamDetailsOutputDTO } from '@/lib/types/generated/GetTeamDetailsOutputDTO';\nimport type { GetTeamMembersOutputDTO } from '@/lib/types/generated/GetTeamMembersOutputDTO';\nimport type { GetTeamJoinRequestsOutputDTO } from '@/lib/types/generated/GetTeamJoinRequestsOutputDTO';\nimport type { CreateTeamInputDTO } from '@/lib/types/generated/CreateTeamInputDTO';\nimport type { CreateTeamOutputDTO } from '@/lib/types/generated/CreateTeamOutputDTO';\nimport type { UpdateTeamInputDTO } from '@/lib/types/generated/UpdateTeamInputDTO';\nimport type { UpdateTeamOutputDTO } from '@/lib/types/generated/UpdateTeamOutputDTO';\nimport type { GetDriverTeamOutputDTO } from '@/lib/types/generated/GetDriverTeamOutputDTO';\nimport type { GetTeamMembershipOutputDTO } from '@/lib/types/generated/GetTeamMembershipOutputDTO';\nimport { BaseApiClient } from '../base/BaseApiClient';\n\n/**\n * Teams API Client\n *\n * Handles all team-related API operations.\n */\nexport class TeamsApiClient extends BaseApiClient {\n /** Get all teams */\n getAll(): Promise<GetAllTeamsOutputDTO> {\n return this.get<GetAllTeamsOutputDTO>('/teams/all');\n }\n\n /** Get team details */\n getDetails(teamId: string): Promise<GetTeamDetailsOutputDTO | null> {\n return this.get<GetTeamDetailsOutputDTO | null>(`/teams/${teamId}`);\n }\n\n /** Get team members */\n getMembers(teamId: string): Promise<GetTeamMembersOutputDTO> {\n return this.get<GetTeamMembersOutputDTO>(`/teams/${teamId}/members`);\n }\n\n /** Get team join requests */\n getJoinRequests(teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {\n return this.get<GetTeamJoinRequestsOutputDTO>(`/teams/${teamId}/join-requests`);\n }\n\n /** Create a new team */\n create(input: CreateTeamInputDTO): Promise<CreateTeamOutputDTO> {\n return this.post<CreateTeamOutputDTO>('/teams', input);\n }\n\n /** Update team */\n update(teamId: string, input: UpdateTeamInputDTO): Promise<UpdateTeamOutputDTO> {\n return this.patch<UpdateTeamOutputDTO>(`/teams/${teamId}`, input);\n }\n\n /** Get driver's team */\n getDriverTeam(driverId: string): Promise<GetDriverTeamOutputDTO | null> {\n return this.get<GetDriverTeamOutputDTO | null>(`/teams/driver/${driverId}`);\n }\n\n /** Get membership for a driver in a team */\n getMembership(teamId: string, driverId: string): Promise<GetTeamMembershipOutputDTO | null> {\n return this.get<GetTeamMembershipOutputDTO | null>(`/teams/${teamId}/members/${driverId}`);\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/api/wallets/WalletsApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/apiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/AuthContext.tsx","messages":[{"ruleId":"gridpilot-rules/lib-no-next-imports","severity":2,"message":"Next.js imports are forbidden in lib/ directory. Found: useRouter from \"next/navigation\"","line":10,"column":10,"nodeType":"ImportSpecifier","messageId":"noNextImports","endLine":10,"endColumn":19}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n type ReactNode,\n} from 'react';\nimport { useRouter } from 'next/navigation';\n\nimport type { SessionViewModel } from '@/lib/view-models/SessionViewModel';\nimport { useCurrentSession } from \"@/hooks/auth/useCurrentSession\";\nimport { useLogout } from \"@/hooks/auth/useLogout\";\n\nexport type AuthContextValue = {\n session: SessionViewModel | null;\n loading: boolean;\n login: (returnTo?: string) => void;\n logout: () => Promise<void>;\n refreshSession: () => Promise<void>;\n};\n\nconst AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\ninterface AuthProviderProps {\n initialSession?: SessionViewModel | null;\n children: ReactNode;\n}\n\nexport function AuthProvider({ initialSession = null, children }: AuthProviderProps) {\n const router = useRouter();\n \n // Use React-Query hooks for session management\n const { data: session, isLoading, refetch: refreshSession } = useCurrentSession({\n initialData: initialSession,\n });\n\n // Use mutation hooks for logout\n const logoutMutation = useLogout();\n\n const login = useCallback(\n (returnTo?: string) => {\n const search = new URLSearchParams();\n if (returnTo) {\n search.set('returnTo', returnTo);\n }\n\n const target = search.toString()\n ? `/auth/login?${search.toString()}`\n : '/auth/login';\n\n router.push(target);\n },\n [router],\n );\n\n const logout = useCallback(async () => {\n try {\n await logoutMutation.mutateAsync();\n router.push('/');\n router.refresh();\n } catch (error) {\n console.error('Logout failed:', error);\n router.push('/');\n }\n }, [logoutMutation, router]);\n\n const handleRefreshSession = useCallback(async () => {\n await refreshSession();\n }, [refreshSession]);\n\n const value = useMemo(\n () => ({\n session: session ?? null,\n loading: isLoading,\n login,\n logout,\n refreshSession: handleRefreshSession,\n }),\n [session, isLoading, login, logout, handleRefreshSession],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextValue {\n const ctx = useContext(AuthContext);\n if (!ctx) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n return ctx;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/AuthFlowRouter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/AuthRedirectBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/LoginFlowController.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/PathnameInterpreter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/ReturnToSanitizer.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/RouteAccessPolicy.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/RouteCatalog.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":117,"column":16,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":117,"endColumn":19,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2832,2835],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2832,2835],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":153,"column":28,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":153,"endColumn":31,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3819,3822],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3819,3822],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { routes, routeMatchers } from '../routing/RouteConfig';\n\n/**\n * RouteCatalog exposes route IDs and patterns for matching\n * \n * Route IDs follow the pattern: 'category.routeName'\n * Examples:\n * - 'auth.login' → '/auth/login'\n * - 'protected.dashboard' → '/dashboard'\n * - 'league.detail' → '/leagues/[id]' (pattern)\n */\nexport class RouteCatalog {\n /**\n * List all public route IDs\n * Public routes are accessible without authentication\n */\n listPublicRoutes(): string[] {\n return [\n 'public.home',\n 'public.leagues',\n 'public.drivers',\n 'public.teams',\n 'public.leaderboards',\n 'public.races',\n 'public.sponsorSignup',\n 'auth.login',\n 'auth.signup',\n 'auth.forgotPassword',\n 'auth.resetPassword',\n 'auth.iRacingStart',\n 'auth.iRacingCallback',\n 'error.notFound',\n 'error.serverError',\n // Parameterized public routes\n 'league.detail',\n 'league.rulebook',\n 'league.schedule',\n 'league.standings',\n 'driver.detail',\n 'team.detail',\n 'race.detail',\n 'race.results',\n 'race.all',\n ];\n }\n\n /**\n * List all protected route IDs\n * Protected routes require authentication\n */\n listProtectedRoutes(): string[] {\n return [\n 'protected.dashboard',\n 'protected.onboarding',\n 'protected.profile',\n 'protected.profileSettings',\n 'protected.profileLeagues',\n 'protected.profileLiveries',\n 'protected.profileLiveryUpload',\n 'protected.profileSponsorshipRequests',\n 'sponsor.root',\n 'sponsor.dashboard',\n 'sponsor.billing',\n 'sponsor.campaigns',\n 'sponsor.leagues',\n 'sponsor.settings',\n 'admin.root',\n 'admin.users',\n 'league.create',\n 'race.root',\n 'team.root',\n 'team.leaderboard',\n ];\n }\n\n /**\n * List all admin route IDs\n * Admin routes require admin-level permissions\n */\n listAdminRoutes(): string[] {\n return [\n 'admin.root',\n 'admin.users',\n 'league.rosterAdmin',\n 'league.scheduleAdmin',\n 'league.stewarding',\n 'league.settings',\n 'league.sponsorships',\n 'league.wallet',\n 'race.stewarding',\n ];\n }\n\n /**\n * List all sponsor route IDs\n * Sponsor routes require sponsor role\n */\n listSponsorRoutes(): string[] {\n return [\n 'sponsor.root',\n 'sponsor.dashboard',\n 'sponsor.billing',\n 'sponsor.campaigns',\n 'sponsor.leagues',\n 'sponsor.settings',\n ];\n }\n\n /**\n * Get the path pattern for a route ID\n * @param routeId - Route ID in format 'category.routeName'\n * @returns Path pattern (e.g., '/auth/login' or '/leagues/[id]')\n * @throws Error if route ID is unknown\n */\n getPattern(routeId: string): string {\n const parts = routeId.split('.');\n let route: any = routes;\n\n for (const part of parts) {\n route = route[part];\n if (!route) {\n throw new Error(`Unknown route ID: ${routeId}`);\n }\n }\n\n // Handle parameterized routes\n if (typeof route === 'function') {\n // Return pattern with placeholder\n const paramPattern = route('placeholder');\n return paramPattern.replace('/placeholder', '/[id]');\n }\n\n return route as string;\n }\n\n /**\n * Check if a path is an auth page\n * @param logicalPath - Path to check\n * @returns True if path is an auth page\n */\n isAuthPage(logicalPath: string): boolean {\n return routeMatchers.isInGroup(logicalPath, 'auth');\n }\n\n /**\n * Get all route patterns with their IDs\n * @returns Array of route patterns with IDs\n */\n getAllPatterns(): Array<{ routeId: string; pattern: string }> {\n const patterns: Array<{ routeId: string; pattern: string }> = [];\n\n // Helper to traverse routes and build patterns\n const traverse = (obj: any, prefix: string) => {\n for (const [key, value] of Object.entries(obj)) {\n const routeId = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'function') {\n // Parameterized route\n const pattern = value('placeholder').replace('/placeholder', '/[id]');\n patterns.push({ routeId, pattern });\n } else if (typeof value === 'object' && value !== null) {\n // Nested category\n traverse(value, routeId);\n } else if (typeof value === 'string') {\n // Simple route\n patterns.push({ routeId, pattern: value });\n }\n }\n };\n\n traverse(routes, '');\n return patterns;\n }\n\n /**\n * Get route ID by path\n * @param path - Path to find\n * @returns Route ID or null if not found\n * \n * Note: This method prioritizes exact matches over parameterized matches.\n * For example, '/leagues/create' will match 'league.create' before 'league.detail'.\n */\n getRouteIdByPath(path: string): string | null {\n const allPatterns = this.getAllPatterns();\n \n // First, try exact matches\n for (const { routeId, pattern } of allPatterns) {\n if (pattern === path) {\n return routeId;\n }\n }\n \n // Then, try parameterized matches\n for (const { routeId, pattern } of allPatterns) {\n if (pattern.includes('[')) {\n const paramPattern = pattern.replace(/\\[([^\\]]+)\\]/g, '([^/]+)');\n const regex = new RegExp(`^${paramPattern}$`);\n if (regex.test(path)) {\n return routeId;\n }\n }\n }\n\n return null;\n }\n\n /**\n * Check if a path requires specific role-based access\n * @param logicalPath - Path to check\n * @returns Array of required roles or null\n */\n getRequiredRoles(logicalPath: string): string[] | null {\n // Check admin routes\n if (routeMatchers.isInGroup(logicalPath, 'admin')) {\n return ['system-owner', 'super-admin', 'league-admin'];\n }\n \n // Check sponsor routes\n if (routeMatchers.isInGroup(logicalPath, 'sponsor')) {\n return ['sponsor'];\n }\n \n // Check league admin routes (specific patterns)\n if (logicalPath.match(/\\/leagues\\/[^/]+\\/(roster\\/admin|schedule\\/admin|stewarding|settings|sponsorships|wallet)/)) {\n return ['system-owner', 'super-admin', 'league-admin'];\n }\n \n // Check race stewarding routes\n if (logicalPath.match(/\\/races\\/[^/]+\\/stewarding/)) {\n return ['system-owner', 'super-admin', 'league-steward'];\n }\n \n // Public or auth-only routes (no specific role)\n return null;\n }\n\n /**\n * Get the home path for a specific role\n * @param role - The role name\n * @returns The logical path for that role's home page\n */\n getRoleHome(role: string): string {\n const roleHomeMap: Record<string, string> = {\n 'driver': '/dashboard',\n 'sponsor': '/sponsor/dashboard',\n 'league-admin': '/admin',\n 'league-steward': '/admin',\n 'league-owner': '/admin',\n 'system-owner': '/admin',\n 'super-admin': '/admin',\n };\n\n return roleHomeMap[role] || '/dashboard';\n }\n\n /**\n * Get the route ID for a specific role's home page\n * @param role - The role name\n * @returns The route ID for that role's home page\n */\n getRoleHomeRouteId(role: string): string {\n const roleHomeRouteMap: Record<string, string> = {\n 'driver': 'protected.dashboard',\n 'sponsor': 'sponsor.dashboard',\n 'league-admin': 'admin',\n 'league-steward': 'admin',\n 'league-owner': 'admin',\n 'system-owner': 'admin',\n 'super-admin': 'admin',\n };\n\n return roleHomeRouteMap[role] || 'protected.dashboard';\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/RouteGuard.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/RoutePathBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/auth/createRouteGuard.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/blockers/Blocker.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/blockers/SubmitBlocker.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/blockers/ThrottleBlocker.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/blockers/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * @file index.ts\n * Blockers exports\n */\n\nexport { Blocker } from './Blocker';\nexport { SubmitBlocker } from './SubmitBlocker';\nexport { ThrottleBlocker } from './ThrottleBlocker';","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/AdminDashboardViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/AdminUsersViewDataBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":21,"column":91,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":21,"endColumn":94,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[720,723],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[720,723],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":22,"column":91,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":22,"endColumn":94,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[830,833],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[830,833],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":23,"column":119,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":23,"endColumn":122,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[968,971],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[968,971],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { UserListResponse } from '@/lib/types/admin';\nimport { AdminUsersViewData } from '@/lib/view-data/AdminUsersViewData';\n\n/**\n * AdminUsersViewDataBuilder\n * \n * Server-side builder that transforms API DTO\n * into ViewData for the AdminUsersTemplate.\n * \n * Deterministic, side-effect free.\n */\nexport class AdminUsersViewDataBuilder {\n static build(apiDto: UserListResponse): AdminUsersViewData {\n const users = apiDto.users.map(user => ({\n id: user.id,\n email: user.email,\n displayName: user.displayName,\n roles: user.roles,\n status: user.status,\n isSystemAdmin: user.isSystemAdmin,\n createdAt: typeof user.createdAt === 'string' ? user.createdAt : (user.createdAt as any).toISOString(),\n updatedAt: typeof user.updatedAt === 'string' ? user.updatedAt : (user.updatedAt as any).toISOString(),\n lastLoginAt: user.lastLoginAt ? (typeof user.lastLoginAt === 'string' ? user.lastLoginAt : (user.lastLoginAt as any).toISOString()) : undefined,\n primaryDriverId: user.primaryDriverId,\n }));\n\n return {\n users,\n total: apiDto.total,\n page: apiDto.page,\n limit: apiDto.limit,\n totalPages: apiDto.totalPages,\n // Pre-computed derived values for template\n activeUserCount: users.filter(u => u.status === 'active').length,\n adminCount: users.filter(u => u.isSystemAdmin).length,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/AvatarViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/CategoryIconViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/CompleteOnboardingViewData.ts","messages":[{"ruleId":"gridpilot-rules/view-data-builder-contract","severity":2,"message":"View Data Builders must have a static build() method","line":1,"column":1,"nodeType":"Program","messageId":"missingBuildMethod","endLine":5,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export interface CompleteOnboardingViewData {\n success: boolean;\n driverId?: string;\n errorMessage?: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/CompleteOnboardingViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/DashboardViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/DriverProfileViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/DriverRankingsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/DriversViewDataBuilder.ts","messages":[{"ruleId":"gridpilot-rules/view-data-builder-contract","severity":2,"message":"Parameter must be named \"apiDto\", not \"pageDto\" or other names","line":1,"column":1,"nodeType":"Program","messageId":"wrongParameterName","endLine":26,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { DriversLeaderboardDTO } from '@/lib/types/generated/DriversLeaderboardDTO';\nimport type { DriversViewData } from '@/lib/types/view-data/DriversViewData';\n\nexport class DriversViewDataBuilder {\n static build(dto: DriversLeaderboardDTO): DriversViewData {\n return {\n drivers: dto.drivers.map(driver => ({\n id: driver.id,\n name: driver.name,\n rating: driver.rating,\n skillLevel: driver.skillLevel,\n category: driver.category,\n nationality: driver.nationality,\n racesCompleted: driver.racesCompleted,\n wins: driver.wins,\n podiums: driver.podiums,\n isActive: driver.isActive,\n rank: driver.rank,\n avatarUrl: driver.avatarUrl,\n })),\n totalRaces: dto.totalRaces,\n totalWins: dto.totalWins,\n activeCount: dto.activeCount,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/ForgotPasswordViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/GenerateAvatarsViewData.ts","messages":[{"ruleId":"gridpilot-rules/view-data-builder-contract","severity":2,"message":"View Data Builders must have a static build() method","line":1,"column":1,"nodeType":"Program","messageId":"missingBuildMethod","endLine":5,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export interface GenerateAvatarsViewData {\n success: boolean;\n avatarUrls: string[];\n errorMessage?: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/GenerateAvatarsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeaderboardsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueCoverViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder.ts","messages":[{"ruleId":"gridpilot-rules/view-data-builder-contract","severity":2,"message":"Parameter must be named \"apiDto\", not \"pageDto\" or other names","line":1,"column":1,"nodeType":"Program","messageId":"wrongParameterName","endLine":92,"endColumn":2},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":21,"column":15,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":21,"endColumn":18,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1025,1028],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1025,1028],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'r' is defined but never used.","line":40,"column":39,"nodeType":"Identifier","messageId":"unusedVar","endLine":40,"endColumn":40}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { LeagueWithCapacityAndScoringDTO } from '@/lib/types/generated/LeagueWithCapacityAndScoringDTO';\nimport type { LeagueMembershipsDTO } from '@/lib/types/generated/LeagueMembershipsDTO';\nimport type { RaceDTO } from '@/lib/types/generated/RaceDTO';\nimport type { GetDriverOutputDTO } from '@/lib/types/generated/GetDriverOutputDTO';\nimport type { LeagueScoringConfigDTO } from '@/lib/types/generated/LeagueScoringConfigDTO';\nimport type { LeagueDetailViewData, LeagueInfoData, LiveRaceData, DriverSummaryData, SponsorInfo } from '@/lib/view-data/LeagueDetailViewData';\n\n/**\n * LeagueDetailViewDataBuilder\n *\n * Transforms API DTOs into LeagueDetailViewData for server-side rendering.\n * Deterministic; side-effect free; no HTTP calls.\n */\nexport class LeagueDetailViewDataBuilder {\n static build(input: {\n league: LeagueWithCapacityAndScoringDTO;\n owner: GetDriverOutputDTO | null;\n scoringConfig: LeagueScoringConfigDTO | null;\n memberships: LeagueMembershipsDTO;\n races: RaceDTO[];\n sponsors: any[];\n }): LeagueDetailViewData {\n const { league, owner, scoringConfig, memberships, races, sponsors } = input;\n \n // Calculate running races - using available fields from RaceDTO\n const runningRaces: LiveRaceData[] = races\n .filter(r => r.name.includes('Running')) // Placeholder filter\n .map(r => ({\n id: r.id,\n name: r.name,\n date: r.date,\n registeredCount: 0,\n strengthOfField: 0,\n }));\n \n // Calculate info data\n const membersCount = Array.isArray(memberships.members) ? memberships.members.length : 0;\n const completedRacesCount = races.filter(r => r.name.includes('Completed')).length; // Placeholder\n const avgSOF = races.length > 0\n ? Math.round(races.reduce((sum, r) => sum + 0, 0) / races.length)\n : null;\n \n const info: LeagueInfoData = {\n name: league.name,\n description: league.description || '',\n membersCount,\n racesCount: completedRacesCount,\n avgSOF,\n structure: `Solo • ${league.settings?.maxDrivers ?? 32} max`,\n scoring: scoringConfig?.scoringPresetId || 'Standard',\n createdAt: league.createdAt,\n discordUrl: league.socialLinks?.discordUrl,\n youtubeUrl: league.socialLinks?.youtubeUrl,\n websiteUrl: league.socialLinks?.websiteUrl,\n };\n \n // Convert owner to driver summary\n const ownerSummary: DriverSummaryData | null = owner ? {\n driverId: owner.id,\n driverName: owner.name,\n avatarUrl: owner.avatarUrl || null,\n rating: null,\n rank: null,\n roleBadgeText: 'Owner',\n roleBadgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',\n profileUrl: `/drivers/${owner.id}`,\n } : null;\n \n // Convert sponsors\n const sponsorInfo: SponsorInfo[] = sponsors.map(s => ({\n id: s.id,\n name: s.name,\n tier: s.tier,\n logoUrl: s.logoUrl,\n websiteUrl: s.websiteUrl,\n tagline: s.tagline,\n }));\n \n return {\n leagueId: league.id,\n name: league.name,\n description: league.description || '',\n info,\n runningRaces,\n sponsors: sponsorInfo,\n ownerSummary,\n adminSummaries: [], // Would need additional data\n stewardSummaries: [], // Would need additional data\n sponsorInsights: null, // Only for sponsor mode\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueLogoViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueRosterAdminViewDataBuilder.ts","messages":[{"ruleId":"gridpilot-rules/view-data-builder-contract","severity":2,"message":"Parameter must be named \"apiDto\", not \"pageDto\" or other names","line":1,"column":1,"nodeType":"Program","messageId":"wrongParameterName","endLine":47,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { LeagueRosterMemberDTO } from '@/lib/types/generated/LeagueRosterMemberDTO';\nimport type { LeagueRosterJoinRequestDTO } from '@/lib/types/generated/LeagueRosterJoinRequestDTO';\nimport type { LeagueRosterAdminViewData, RosterMemberData, JoinRequestData } from '@/lib/view-data/LeagueRosterAdminViewData';\n\n/**\n * LeagueRosterAdminViewDataBuilder\n *\n * Transforms API DTOs into LeagueRosterAdminViewData for server-side rendering.\n * Deterministic; side-effect free; no HTTP calls.\n */\nexport class LeagueRosterAdminViewDataBuilder {\n static build(input: {\n leagueId: string;\n members: LeagueRosterMemberDTO[];\n joinRequests: LeagueRosterJoinRequestDTO[];\n }): LeagueRosterAdminViewData {\n const { leagueId, members, joinRequests } = input;\n \n // Transform members\n const rosterMembers: RosterMemberData[] = members.map(member => ({\n driverId: member.driverId,\n driver: {\n id: member.driverId,\n name: member.driver?.name || 'Unknown Driver',\n },\n role: member.role,\n joinedAt: member.joinedAt,\n }));\n \n // Transform join requests\n const requests: JoinRequestData[] = joinRequests.map(req => ({\n id: req.id,\n driver: {\n id: req.driverId,\n name: 'Unknown Driver', // driver field is unknown type\n },\n requestedAt: req.requestedAt,\n message: req.message,\n }));\n \n return {\n leagueId,\n members: rosterMembers,\n joinRequests: requests,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueScheduleViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueSettingsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueSponsorshipsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueStandingsViewDataBuilder.ts","messages":[{"ruleId":"gridpilot-rules/view-data-builder-contract","severity":2,"message":"Parameter must be named \"apiDto\", not \"pageDto\" or other names","line":1,"column":1,"nodeType":"Program","messageId":"wrongParameterName","endLine":75,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { LeagueStandingsViewData, StandingEntryData, DriverData, LeagueMembershipData } from '@/lib/view-data/LeagueStandingsViewData';\nimport type { LeagueStandingDTO } from '@/lib/types/generated/LeagueStandingDTO';\nimport type { LeagueMemberDTO } from '@/lib/types/generated/LeagueMemberDTO';\n\ninterface LeagueStandingsApiDto {\n standings: LeagueStandingDTO[];\n}\n\ninterface LeagueMembershipsApiDto {\n members: LeagueMemberDTO[];\n}\n\n/**\n * LeagueStandingsViewDataBuilder\n *\n * Transforms API DTOs into LeagueStandingsViewData for server-side rendering.\n * Deterministic; side-effect free; no HTTP calls.\n */\nexport class LeagueStandingsViewDataBuilder {\n static build(\n standingsDto: LeagueStandingsApiDto,\n membershipsDto: LeagueMembershipsApiDto,\n leagueId: string\n ): LeagueStandingsViewData {\n const standings = standingsDto.standings || [];\n const members = membershipsDto.members || [];\n\n // Convert LeagueStandingDTO to StandingEntryData\n const standingData: StandingEntryData[] = standings.map(standing => ({\n driverId: standing.driverId,\n position: standing.position,\n totalPoints: standing.points,\n racesFinished: standing.races,\n racesStarted: standing.races,\n avgFinish: null, // Not in DTO\n penaltyPoints: 0, // Not in DTO\n bonusPoints: 0, // Not in DTO\n }));\n\n // Extract unique drivers from standings\n const driverMap = new Map<string, DriverData>();\n standings.forEach(standing => {\n if (standing.driver && !driverMap.has(standing.driver.id)) {\n const driver = standing.driver;\n driverMap.set(driver.id, {\n id: driver.id,\n name: driver.name,\n avatarUrl: null, // DTO may not have this\n iracingId: driver.iracingId,\n rating: undefined,\n country: driver.country,\n });\n }\n });\n const driverData: DriverData[] = Array.from(driverMap.values());\n\n // Convert LeagueMemberDTO to LeagueMembershipData\n const membershipData: LeagueMembershipData[] = members.map(member => ({\n driverId: member.driverId,\n leagueId: leagueId,\n role: (member.role as LeagueMembershipData['role']) || 'member',\n joinedAt: member.joinedAt,\n status: 'active' as const,\n }));\n\n return {\n standings: standingData,\n drivers: driverData,\n memberships: membershipData,\n leagueId,\n currentDriverId: null, // Would need to get from auth\n isAdmin: false, // Would need to check permissions\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeagueWalletViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LeaguesViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/LoginViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/OnboardingPageViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/OnboardingViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/ProfileLeaguesViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/ProfileViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/ProtestDetailViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/RaceDetailViewDataBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":10,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":10,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[388,391],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[388,391],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":71,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":74,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1557,1560],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1557,1560],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RaceDetailViewData, RaceDetailRace, RaceDetailLeague, RaceDetailEntry, RaceDetailRegistration, RaceDetailUserResult } from '@/lib/view-data/races/RaceDetailViewData';\n\n/**\n * Race Detail View Data Builder\n * \n * Transforms API DTO into ViewData for the race detail template.\n * Deterministic, side-effect free.\n */\nexport class RaceDetailViewDataBuilder {\n static build(apiDto: any): RaceDetailViewData {\n if (!apiDto || !apiDto.race) {\n return {\n race: {\n id: '',\n track: '',\n car: '',\n scheduledAt: '',\n status: 'scheduled',\n sessionType: 'race',\n },\n entryList: [],\n registration: {\n isUserRegistered: false,\n canRegister: false,\n },\n canReopenRace: false,\n };\n }\n\n const race: RaceDetailRace = {\n id: apiDto.race.id,\n track: apiDto.race.track,\n car: apiDto.race.car,\n scheduledAt: apiDto.race.scheduledAt,\n status: apiDto.race.status as 'scheduled' | 'running' | 'completed' | 'cancelled',\n sessionType: apiDto.race.sessionType,\n };\n\n const league: RaceDetailLeague | undefined = apiDto.league ? {\n id: apiDto.league.id,\n name: apiDto.league.name,\n description: apiDto.league.description || undefined,\n settings: {\n maxDrivers: apiDto.league.settings?.maxDrivers || 32,\n qualifyingFormat: apiDto.league.settings?.qualifyingFormat || 'Open',\n },\n } : undefined;\n\n const entryList: RaceDetailEntry[] = apiDto.entryList.map((entry: any) => ({\n id: entry.id,\n name: entry.name,\n avatarUrl: entry.avatarUrl,\n country: entry.country,\n rating: entry.rating,\n isCurrentUser: entry.isCurrentUser,\n }));\n\n const registration: RaceDetailRegistration = {\n isUserRegistered: apiDto.registration.isUserRegistered,\n canRegister: apiDto.registration.canRegister,\n };\n\n const userResult: RaceDetailUserResult | undefined = apiDto.userResult ? {\n position: apiDto.userResult.position,\n startPosition: apiDto.userResult.startPosition,\n positionChange: apiDto.userResult.positionChange,\n incidents: apiDto.userResult.incidents,\n isClean: apiDto.userResult.isClean,\n isPodium: apiDto.userResult.isPodium,\n ratingChange: apiDto.userResult.ratingChange,\n } : undefined;\n\n return {\n race,\n league,\n entryList,\n registration,\n userResult,\n canReopenRace: apiDto.canReopenRace || false,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/RaceResultsViewDataBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":10,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":10,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[335,338],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[335,338],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":22,"column":78,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":22,"endColumn":81,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[635,638],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[635,638],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":84,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":87,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1235,1238],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1235,1238],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RaceResultsViewData, RaceResultsResult, RaceResultsPenalty } from '@/lib/view-data/races/RaceResultsViewData';\n\n/**\n * Race Results View Data Builder\n * \n * Transforms API DTO into ViewData for the race results template.\n * Deterministic, side-effect free.\n */\nexport class RaceResultsViewDataBuilder {\n static build(apiDto: any): RaceResultsViewData {\n if (!apiDto) {\n return {\n raceSOF: null,\n results: [],\n penalties: [],\n pointsSystem: {},\n fastestLapTime: 0,\n };\n }\n\n // Transform results\n const results: RaceResultsResult[] = (apiDto.results || []).map((result: any) => ({\n position: result.position,\n driverId: result.driverId,\n driverName: result.driverName,\n driverAvatar: result.avatarUrl,\n country: result.country || 'US',\n car: result.car || 'Unknown',\n laps: result.laps || 0,\n time: result.time || '0:00.00',\n fastestLap: result.fastestLap?.toString() || '0.00',\n points: result.points || 0,\n incidents: result.incidents || 0,\n isCurrentUser: result.isCurrentUser || false,\n }));\n\n // Transform penalties\n const penalties: RaceResultsPenalty[] = (apiDto.penalties || []).map((penalty: any) => ({\n driverId: penalty.driverId,\n driverName: penalty.driverName || 'Unknown',\n type: penalty.type as 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points',\n value: penalty.value || 0,\n reason: penalty.reason || 'Penalty applied',\n notes: penalty.notes,\n }));\n\n return {\n raceTrack: apiDto.race?.track,\n raceScheduledAt: apiDto.race?.scheduledAt,\n totalDrivers: apiDto.stats?.totalDrivers,\n leagueName: apiDto.league?.name,\n raceSOF: apiDto.strengthOfField || null,\n results,\n penalties,\n pointsSystem: apiDto.pointsSystem || {},\n fastestLapTime: apiDto.fastestLapTime || 0,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/RaceStewardingViewDataBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":10,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":10,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[337,340],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[337,340],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":35,"column":79,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":35,"endColumn":82,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[951,954],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[951,954],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":81,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":84,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1398,1401],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1398,1401],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":63,"column":67,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":63,"endColumn":70,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1831,1834],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1831,1834],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RaceStewardingViewData, Protest, Penalty, Driver } from '@/lib/view-data/races/RaceStewardingViewData';\n\n/**\n * Race Stewarding View Data Builder\n * \n * Transforms API DTO into ViewData for the race stewarding template.\n * Deterministic, side-effect free.\n */\nexport class RaceStewardingViewDataBuilder {\n static build(apiDto: any): RaceStewardingViewData {\n if (!apiDto) {\n return {\n race: null,\n league: null,\n pendingProtests: [],\n resolvedProtests: [],\n penalties: [],\n driverMap: {},\n pendingCount: 0,\n resolvedCount: 0,\n penaltiesCount: 0,\n };\n }\n\n const race = apiDto.race ? {\n id: apiDto.race.id,\n track: apiDto.race.track,\n scheduledAt: apiDto.race.scheduledAt,\n } : null;\n\n const league = apiDto.league ? {\n id: apiDto.league.id,\n } : null;\n\n const pendingProtests: Protest[] = (apiDto.pendingProtests || []).map((p: any) => ({\n id: p.id,\n protestingDriverId: p.protestingDriverId,\n accusedDriverId: p.accusedDriverId,\n incident: {\n lap: p.incident?.lap || 0,\n description: p.incident?.description || '',\n },\n filedAt: p.filedAt,\n status: p.status,\n proofVideoUrl: p.proofVideoUrl,\n decisionNotes: p.decisionNotes,\n }));\n\n const resolvedProtests: Protest[] = (apiDto.resolvedProtests || []).map((p: any) => ({\n id: p.id,\n protestingDriverId: p.protestingDriverId,\n accusedDriverId: p.accusedDriverId,\n incident: {\n lap: p.incident?.lap || 0,\n description: p.incident?.description || '',\n },\n filedAt: p.filedAt,\n status: p.status,\n proofVideoUrl: p.proofVideoUrl,\n decisionNotes: p.decisionNotes,\n }));\n\n const penalties: Penalty[] = (apiDto.penalties || []).map((p: any) => ({\n id: p.id,\n driverId: p.driverId,\n type: p.type,\n value: p.value || 0,\n reason: p.reason || '',\n notes: p.notes,\n }));\n\n const driverMap: Record<string, Driver> = apiDto.driverMap || {};\n\n return {\n race,\n league,\n pendingProtests,\n resolvedProtests,\n penalties,\n driverMap,\n pendingCount: apiDto.pendingCount || pendingProtests.length,\n resolvedCount: apiDto.resolvedCount || resolvedProtests.length,\n penaltiesCount: apiDto.penaltiesCount || penalties.length,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/RacesAllViewDataBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'RacesAllRace' is defined but never used.","line":1,"column":28,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":40},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":10,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":10,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[295,298],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[295,298],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[362,365],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[362,365],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RacesAllViewData, RacesAllRace } from '@/lib/view-data/races/RacesAllViewData';\n\n/**\n * Races All View Data Builder\n * \n * Transforms API DTO into ViewData for the all races template.\n * Deterministic, side-effect free.\n */\nexport class RacesAllViewDataBuilder {\n static build(apiDto: any): RacesAllViewData {\n const races = apiDto.races.map((race: any) => ({\n id: race.id,\n track: race.track,\n car: race.car,\n scheduledAt: race.scheduledAt,\n status: race.status as 'scheduled' | 'running' | 'completed' | 'cancelled',\n sessionType: 'race',\n leagueId: race.leagueId,\n leagueName: race.leagueName,\n strengthOfField: race.strengthOfField ?? undefined,\n }));\n\n return {\n races,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/RacesViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/ResetPasswordViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/RulebookViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/SignupViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/SponsorDashboardViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/SponsorLogoViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/SponsorshipRequestsPageViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/SponsorshipRequestsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/StewardingViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/TeamDetailViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/TeamLogoViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/TeamsViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/TrackImageViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/types/ForgotPasswordViewData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[236,239],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[236,239],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Forgot Password View Data\n * \n * ViewData for the forgot password template.\n */\n\nexport interface ForgotPasswordViewData {\n returnTo: string;\n showSuccess: boolean;\n successMessage?: string;\n magicLink?: string;\n formState: any; // Will be managed by client component\n isSubmitting: boolean;\n submitError?: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/types/FormFieldState.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/types/FormState.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/types/LoginViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/types/ResetPasswordViewData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[228,231],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[228,231],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Reset Password View Data\n * \n * ViewData for the reset password template.\n */\n\nexport interface ResetPasswordViewData {\n token: string;\n returnTo: string;\n showSuccess: boolean;\n successMessage?: string;\n formState: any; // Will be managed by client component\n isSubmitting: boolean;\n submitError?: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-data/types/SignupViewData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":9,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":9,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[137,140],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[137,140],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Signup View Data\n * \n * ViewData for the signup template.\n */\n\nexport interface SignupViewData {\n returnTo: string;\n formState: any; // Will be managed by client component\n isSubmitting: boolean;\n submitError?: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/DriverProfileViewModelBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":114,"column":33,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":114,"endColumn":36,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4521,4524],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4521,4524],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":122,"column":25,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":122,"endColumn":28,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4778,4781],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4778,4781],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":123,"column":29,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":123,"endColumn":32,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4851,4854],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4851,4854],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO';\nimport type { DriverProfileDriverSummaryDTO } from '@/lib/types/generated/DriverProfileDriverSummaryDTO';\nimport type { DriverProfileStatsDTO } from '@/lib/types/generated/DriverProfileStatsDTO';\nimport type { DriverProfileFinishDistributionDTO } from '@/lib/types/generated/DriverProfileFinishDistributionDTO';\nimport type { DriverProfileTeamMembershipDTO } from '@/lib/types/generated/DriverProfileTeamMembershipDTO';\nimport type { DriverProfileSocialSummaryDTO } from '@/lib/types/generated/DriverProfileSocialSummaryDTO';\nimport type { DriverProfileExtendedProfileDTO } from '@/lib/types/generated/DriverProfileExtendedProfileDTO';\nimport { DriverProfileViewModel } from '@/lib/view-models/DriverProfileViewModel';\nimport type {\n DriverProfileDriverSummaryViewModel,\n DriverProfileStatsViewModel,\n DriverProfileFinishDistributionViewModel,\n DriverProfileTeamMembershipViewModel,\n DriverProfileSocialSummaryViewModel,\n DriverProfileExtendedProfileViewModel,\n} from '@/lib/view-models/DriverProfileViewModel';\n\n/**\n * DriverProfileViewModelBuilder\n *\n * Transforms GetDriverProfileOutputDTO into DriverProfileViewModel.\n * Deterministic, side-effect free, no HTTP calls.\n */\nexport class DriverProfileViewModelBuilder {\n /**\n * Build ViewModel from API DTO\n * \n * @param apiDto - The API transport DTO\n * @returns ViewModel ready for template\n */\n static build(apiDto: GetDriverProfileOutputDTO): DriverProfileViewModel {\n return new DriverProfileViewModel({\n currentDriver: apiDto.currentDriver ? this.transformCurrentDriver(apiDto.currentDriver) : null,\n stats: apiDto.stats ? this.transformStats(apiDto.stats) : null,\n finishDistribution: apiDto.finishDistribution ? this.transformFinishDistribution(apiDto.finishDistribution) : null,\n teamMemberships: apiDto.teamMemberships.map(m => this.transformTeamMembership(m)),\n socialSummary: this.transformSocialSummary(apiDto.socialSummary),\n extendedProfile: apiDto.extendedProfile ? this.transformExtendedProfile(apiDto.extendedProfile) : null,\n });\n }\n\n private static transformCurrentDriver(dto: DriverProfileDriverSummaryDTO): DriverProfileDriverSummaryViewModel {\n return {\n id: dto.id,\n name: dto.name,\n country: dto.country,\n avatarUrl: dto.avatarUrl || '', // Handle undefined\n iracingId: dto.iracingId || null,\n joinedAt: dto.joinedAt,\n rating: dto.rating ?? null,\n globalRank: dto.globalRank ?? null,\n consistency: dto.consistency ?? null,\n bio: dto.bio || null,\n totalDrivers: dto.totalDrivers ?? null,\n };\n }\n\n private static transformStats(dto: DriverProfileStatsDTO): DriverProfileStatsViewModel {\n return {\n totalRaces: dto.totalRaces,\n wins: dto.wins,\n podiums: dto.podiums,\n dnfs: dto.dnfs,\n avgFinish: dto.avgFinish ?? null,\n bestFinish: dto.bestFinish ?? null,\n worstFinish: dto.worstFinish ?? null,\n finishRate: dto.finishRate ?? null,\n winRate: dto.winRate ?? null,\n podiumRate: dto.podiumRate ?? null,\n percentile: dto.percentile ?? null,\n rating: dto.rating ?? null,\n consistency: dto.consistency ?? null,\n overallRank: dto.overallRank ?? null,\n };\n }\n\n private static transformFinishDistribution(dto: DriverProfileFinishDistributionDTO): DriverProfileFinishDistributionViewModel {\n return {\n totalRaces: dto.totalRaces,\n wins: dto.wins,\n podiums: dto.podiums,\n topTen: dto.topTen,\n dnfs: dto.dnfs,\n other: dto.other,\n };\n }\n\n private static transformTeamMembership(dto: DriverProfileTeamMembershipDTO): DriverProfileTeamMembershipViewModel {\n return {\n teamId: dto.teamId,\n teamName: dto.teamName,\n teamTag: dto.teamTag || null,\n role: dto.role,\n joinedAt: dto.joinedAt,\n isCurrent: dto.isCurrent,\n };\n }\n\n private static transformSocialSummary(dto: DriverProfileSocialSummaryDTO): DriverProfileSocialSummaryViewModel {\n return {\n friendsCount: dto.friendsCount,\n friends: dto.friends.map(f => ({\n id: f.id,\n name: f.name,\n country: f.country,\n avatarUrl: f.avatarUrl || '', // Handle undefined\n })),\n };\n }\n\n private static transformExtendedProfile(dto: DriverProfileExtendedProfileDTO): DriverProfileExtendedProfileViewModel {\n return {\n socialHandles: dto.socialHandles.map(h => ({\n platform: h.platform as any, // Type assertion - assuming valid platform\n handle: h.handle,\n url: h.url,\n })),\n achievements: dto.achievements.map(a => ({\n id: a.id,\n title: a.title,\n description: a.description,\n icon: a.icon as any, // Type assertion - assuming valid icon\n rarity: a.rarity as any, // Type assertion - assuming valid rarity\n earnedAt: a.earnedAt,\n })),\n racingStyle: dto.racingStyle,\n favoriteTrack: dto.favoriteTrack,\n favoriteCar: dto.favoriteCar,\n timezone: dto.timezone,\n availableHours: dto.availableHours,\n lookingForTeam: dto.lookingForTeam,\n openToRequests: dto.openToRequests,\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/DriversViewModelBuilder.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'DriverLeaderboardItemDTO' is defined but never used.","line":2,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":39}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { DriversLeaderboardDTO } from '@/lib/types/generated/DriversLeaderboardDTO';\nimport type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';\nimport { DriverLeaderboardViewModel } from '@/lib/view-models/DriverLeaderboardViewModel';\n\n/**\n * DriversViewModelBuilder\n * \n * Transforms DriversLeaderboardDTO into DriverLeaderboardViewModel.\n * Deterministic, side-effect free, no HTTP calls.\n */\nexport class DriversViewModelBuilder {\n static build(apiDto: DriversLeaderboardDTO): DriverLeaderboardViewModel {\n return new DriverLeaderboardViewModel({\n drivers: apiDto.drivers,\n });\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/ForgotPasswordViewModelBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/LoginViewModelBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/OnboardingViewModelBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/ResetPasswordViewModelBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/builders/view-models/SignupViewModelBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/command-models/auth/LoginCommandModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/command-models/auth/SignupCommandModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/command-models/leagues/LeagueWizardCommandModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/command-models/protests/ProtestDecisionCommandModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/config/apiBaseUrl.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/config/env.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/config/mediaConfig.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/Result.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":21,"column":26,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":21,"endColumn":29,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[471,474],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[471,474],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":21,"column":32,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":21,"endColumn":35,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[477,480],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[477,480],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":23,"column":22,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":23,"endColumn":25,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[520,523],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[520,523],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_defaultValue' is defined but never used.","line":32,"column":12,"nodeType":"Identifier","messageId":"unusedVar","endLine":32,"endColumn":28},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":26,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":29,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1239,1242],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1239,1242],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":32,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":35,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1245,1248],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1245,1248],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_fn' is defined but never used.","line":51,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":51,"endColumn":32},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":51,"column":23,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":51,"endColumn":26,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1335,1338],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1335,1338],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":52,"column":20,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":52,"endColumn":23,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1383,1386],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1383,1386],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":9,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Result type for operations that can fail\n * \n * Inspired by Rust's Result type, this provides a type-safe way to handle\n * success and error cases without exceptions.\n */\n\nexport interface ResultOk<T> {\n isOk(): true;\n isErr(): false;\n unwrap(): T;\n unwrapOr(defaultValue: T): T;\n getError(): never;\n map<U>(fn: (value: T) => U): ResultOk<U>;\n}\n\nexport interface ResultError<E> {\n isOk(): false;\n isErr(): true;\n unwrap(): never;\n unwrapOr(defaultValue: any): any;\n getError(): E;\n map<U>(fn: (value: any) => U): ResultError<E>;\n}\n\nexport class Ok<T> implements ResultOk<T> {\n constructor(private readonly value: T) {}\n\n isOk(): true { return true; }\n isErr(): false { return false; }\n unwrap(): T { return this.value; }\n unwrapOr(_defaultValue: T): T { return this.value; }\n getError(): never {\n throw new Error('Cannot get error from Ok result');\n }\n map<U>(fn: (value: T) => U): ResultOk<U> {\n return new Ok(fn(this.value));\n }\n}\n\nexport class Err<E> implements ResultError<E> {\n constructor(private readonly error: E) {}\n\n isOk(): false { return false; }\n isErr(): true { return true; }\n unwrap(): never {\n throw new Error(`Called unwrap on error: ${this.error}`);\n }\n unwrapOr(defaultValue: any): any { return defaultValue; }\n getError(): E { return this.error; }\n map<U>(_fn: (value: any) => U): ResultError<E> {\n return this as any;\n }\n}\n\n/**\n * Result type alias\n */\nexport type Result<T, E> = ResultOk<T> | ResultError<E>;\n\n/**\n * Result class with static factory methods\n * \n * Usage:\n * - Result.ok(value) creates a successful Result\n * - Result.err(error) creates an error Result\n */\nexport const Result = {\n ok<T>(value: T): Result<T, never> {\n return new Ok(value);\n },\n \n err<E>(error: E): Result<never, E> {\n return new Err(error);\n },\n};\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/api/ApiClient.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/builders/ViewDataBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/builders/ViewModelBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/display-objects/DisplayObject.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/mutations/Mutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/mutations/MutationError.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":21,"column":49,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":21,"endColumn":52,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[774,777],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[774,777],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Mutation Error Type\n * \n * Errors that can be handled by the client after a mutation.\n * These are mapped from DomainErrors by Mutations.\n */\n\nexport type MutationError =\n | 'userNotFound' // User doesn't exist\n | 'noPermission' // Insufficient permissions\n | 'invalidData' // Validation failed\n | 'updateFailed' // Update operation failed\n | 'deleteFailed' // Delete operation failed\n | 'createFailed' // Create operation failed\n | 'networkError' // Network/communication error\n | 'serverError' // Generic server error\n | 'notImplemented' // Feature not implemented\n | 'unknown'; // Unknown error\n\n// Helper to map DomainError to MutationError\nexport function mapToMutationError(domainError: any): MutationError {\n const errorType = domainError?.type || domainError?.name || 'unknown';\n \n switch (errorType) {\n case 'notFound':\n case 'NotFoundError':\n case 'userNotFound':\n return 'userNotFound';\n case 'unauthorized':\n case 'UnauthorizedError':\n case 'ForbiddenError':\n return 'noPermission';\n case 'validationError':\n case 'ValidationError':\n return 'invalidData';\n case 'serverError':\n case 'ServerError':\n case 'HttpServerError':\n return 'serverError';\n case 'networkError':\n case 'NetworkError':\n return 'networkError';\n case 'notImplemented':\n case 'NotImplementedError':\n return 'notImplemented';\n default:\n return 'unknown';\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/page-queries/PageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/page-queries/PageQueryResult.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/page-queries/PresentationError.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":18,"column":53,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":18,"endColumn":56,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[698,701],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[698,701],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Presentation Error Type\n * \n * Errors that can be handled by the presentation layer (RSC pages, templates).\n * These are mapped from DomainErrors by PageQueries.\n */\n\nexport type PresentationError = \n | 'notFound' // Resource not found - show 404 page\n | 'redirect' // Redirect to another page (e.g., login)\n | 'unauthorized' // Not authorized - show access denied\n | 'serverError' // Generic server error\n | 'networkError' // Network/communication error\n | 'validationError' // Invalid input data\n | 'unknown'; // Unknown error\n\n// Helper to map DomainError to PresentationError\nexport function mapToPresentationError(domainError: any): PresentationError {\n const errorType = domainError?.type || domainError?.name || 'unknown';\n \n switch (errorType) {\n case 'notFound':\n case 'NotFoundError':\n return 'notFound';\n case 'unauthorized':\n case 'UnauthorizedError':\n case 'ForbiddenError':\n return 'unauthorized';\n case 'serverError':\n case 'ServerError':\n case 'HttpServerError':\n return 'serverError';\n case 'networkError':\n case 'NetworkError':\n return 'networkError';\n case 'validationError':\n case 'ValidationError':\n return 'validationError';\n default:\n return 'unknown';\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/presenters/Presenter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/services/Service.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/types/primitives.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/view-data/ViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/contracts/view-models/ViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/container.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":43,"column":60,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":43,"endColumn":63,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1186,1189],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1186,1189],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'promises' is assigned a value but never used.","line":47,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":47,"endColumn":17}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Container } from 'inversify';\n\n// Module imports\nimport { ApiModule } from './modules/api.module';\nimport { AuthModule } from './modules/auth.module';\nimport { CoreModule } from './modules/core.module';\nimport { DriverModule } from './modules/driver.module';\nimport { LeagueModule } from './modules/league.module';\nimport { TeamModule } from './modules/team.module';\nimport { RaceModule } from './modules/race.module';\nimport { LandingModule } from './modules/landing.module';\nimport { PolicyModule } from './modules/policy.module';\nimport { SponsorModule } from './modules/sponsor.module';\nimport { AnalyticsModule } from './modules/analytics.module';\n\n/**\n * Creates and configures the root DI container\n */\nexport function createContainer(): Container {\n const container = new Container();\n\n // Load all modules\n container.load(\n CoreModule,\n ApiModule,\n AuthModule,\n LeagueModule,\n DriverModule,\n TeamModule,\n RaceModule,\n LandingModule,\n PolicyModule,\n SponsorModule,\n AnalyticsModule\n );\n\n return container;\n}\n\n/**\n * Creates a container for testing with mock overrides\n */\nexport function createTestContainer(overrides: Map<symbol, any> = new Map()): Container {\n const container = createContainer();\n \n // Apply mock overrides using rebind\n const promises = Array.from(overrides.entries()).map(([token, mockInstance]) => {\n return container.rebind(token).then(bind => bind.toConstantValue(mockInstance));\n });\n \n // Return container immediately, mocks will be available after promises resolve\n // For synchronous testing, users can bind directly before loading modules\n return container;\n}\n\n/**\n * Container lifecycle management\n */\nexport class ContainerManager {\n private static instance: ContainerManager | null = null;\n private container: Container | null = null;\n\n private constructor() {}\n\n static getInstance(): ContainerManager {\n if (!ContainerManager.instance) {\n ContainerManager.instance = new ContainerManager();\n }\n return ContainerManager.instance;\n }\n\n getContainer(): Container {\n if (!this.container) {\n this.container = createContainer();\n }\n return this.container;\n }\n\n createScopedContainer(): Container {\n // In this version, we create a new container\n return new Container();\n }\n\n dispose(): void {\n if (this.container) {\n this.container.unbindAll();\n this.container = null;\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/hooks/useInject.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1000,1003],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1000,1003],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useContext, useMemo } from 'react';\nimport { ContainerContext } from '../providers/ContainerProvider';\n\n/**\n * Primary injection hook - gets a service by token\n *\n * @example\n * const leagueService = useInject(LEAGUE_SERVICE_TOKEN);\n */\nexport function useInject<T extends symbol>(token: T): T extends { type: infer U } ? U : unknown {\n const container = useContext(ContainerContext);\n \n if (!container) {\n throw new Error('useInject must be used within ContainerProvider');\n }\n\n return useMemo(() => {\n try {\n return container.get(token) as T extends { type: infer U } ? U : unknown;\n } catch (error) {\n console.error(`Failed to resolve token ${token.toString()}:`, error);\n throw error;\n }\n }, [container, token]);\n}\n\n/**\n * Hook to get multiple services at once\n * \n * @example\n * const [leagueService, driverService] = useInjectMany([\n * LEAGUE_SERVICE_TOKEN,\n * DRIVER_SERVICE_TOKEN\n * ]);\n */\nexport function useInjectMany<T extends any[]>(tokens: symbol[]): T {\n const container = useContext(ContainerContext);\n \n if (!container) {\n throw new Error('useInjectMany must be used within ContainerProvider');\n }\n\n return useMemo(() => {\n return tokens.map(token => container.get(token)) as T;\n }, [container, tokens]);\n}\n\n/**\n * Hook to get all services of a given type (tag-based resolution)\n * \n * @example\n * const allServices = useInjectAll<Service>('Service');\n */\nexport function useInjectAll<T>(serviceIdentifier: string | symbol): T[] {\n const container = useContext(ContainerContext);\n \n if (!container) {\n throw new Error('useInjectAll must be used within ContainerProvider');\n }\n\n return useMemo(() => {\n return container.getAll<T>(serviceIdentifier);\n }, [container, serviceIdentifier]);\n}\n\n/**\n * Hook for optional service injection (returns null if not found)\n * \n * @example\n * const optionalService = useInjectOptional(MAYBE_SERVICE_TOKEN);\n */\nexport function useInjectOptional<T>(token: symbol): T | null {\n const container = useContext(ContainerContext);\n \n return useMemo(() => {\n if (!container) {\n return null;\n }\n try {\n return container.get<T>(token);\n } catch {\n return null;\n }\n }, [container, token]);\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/hooks/useReactQueryWithApiError.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":8,"column":42,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":8,"endColumn":45,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[308,311],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[308,311],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":27,"column":52,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":27,"endColumn":55,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[820,823],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[820,823],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { UseQueryResult } from '@tanstack/react-query';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\n/**\n * Converts React-Query error to ApiError for StateContainer compatibility\n * This eliminates the need to repeat error conversion logic in every hook\n */\nexport function convertToApiError(error: any): ApiError | null {\n if (!error) return null;\n \n if (error instanceof ApiError) {\n return error;\n }\n \n return new ApiError(\n error.message || 'An unexpected error occurred',\n 'UNKNOWN_ERROR',\n { timestamp: new Date().toISOString() },\n error instanceof Error ? error : undefined\n );\n}\n\n/**\n * Helper function to enhance React-Query result with ApiError conversion\n * Returns the same structure as before but with DRY error handling\n */\nexport function enhanceQueryResult<TData, TError = any>(\n queryResult: UseQueryResult<TData, TError>\n) {\n const apiError = convertToApiError(queryResult.error);\n \n return {\n ...queryResult,\n error: apiError, // Directly return ApiError for StateContainer compatibility\n retry: async () => {\n await queryResult.refetch();\n },\n };\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"// Must be first import - enables decorator metadata\nimport 'reflect-metadata';\n\n// Core exports\nexport * from './container';\nexport * from './tokens';\n\n// React integration\nexport * from './hooks/useInject';\nexport * from './hooks/useReactQueryWithApiError';\nexport * from './providers/ContainerProvider';\n\n// Modules\nexport * from './modules/api.module';\nexport * from './modules/auth.module';\nexport * from './modules/core.module';\nexport * from './modules/driver.module';\nexport * from './modules/league.module';\nexport * from './modules/race.module';\nexport * from './modules/team.module';\nexport * from './modules/landing.module';\nexport * from './modules/policy.module';\nexport * from './modules/sponsor.module';","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/analytics.module.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/api.module.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":42,"column":18,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":42,"endColumn":21,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1702,1705],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1702,1705],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":43,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":43,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1720,1723],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1720,1723],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ContainerModule } from 'inversify';\nimport { RacesApiClient } from '../../api/races/RacesApiClient';\nimport { DriversApiClient } from '../../api/drivers/DriversApiClient';\nimport { TeamsApiClient } from '../../api/teams/TeamsApiClient';\nimport { LeaguesApiClient } from '../../api/leagues/LeaguesApiClient';\nimport { SponsorsApiClient } from '../../api/sponsors/SponsorsApiClient';\nimport { PaymentsApiClient } from '../../api/payments/PaymentsApiClient';\nimport { WalletsApiClient } from '../../api/wallets/WalletsApiClient';\nimport { AuthApiClient } from '../../api/auth/AuthApiClient';\nimport { AnalyticsApiClient } from '../../api/analytics/AnalyticsApiClient';\nimport { MediaApiClient } from '../../api/media/MediaApiClient';\nimport { DashboardApiClient } from '../../api/dashboard/DashboardApiClient';\nimport { PolicyApiClient } from '../../api/policy/PolicyApiClient';\nimport { ProtestsApiClient } from '../../api/protests/ProtestsApiClient';\nimport { PenaltiesApiClient } from '../../api/penalties/PenaltiesApiClient';\n\nimport { \n LOGGER_TOKEN,\n ERROR_REPORTER_TOKEN,\n CONFIG_TOKEN,\n LEAGUE_API_CLIENT_TOKEN,\n DRIVER_API_CLIENT_TOKEN,\n TEAM_API_CLIENT_TOKEN,\n RACE_API_CLIENT_TOKEN,\n SPONSOR_API_CLIENT_TOKEN,\n PAYMENT_API_CLIENT_TOKEN,\n WALLET_API_CLIENT_TOKEN,\n AUTH_API_CLIENT_TOKEN,\n ANALYTICS_API_CLIENT_TOKEN,\n MEDIA_API_CLIENT_TOKEN,\n DASHBOARD_API_CLIENT_TOKEN,\n POLICY_API_CLIENT_TOKEN,\n PROTEST_API_CLIENT_TOKEN,\n PENALTY_API_CLIENT_TOKEN\n} from '../tokens';\n\nexport const ApiModule = new ContainerModule((options) => {\n const bind = options.bind;\n\n // Factory for creating API clients with shared dependencies\n const createApiClient = (\n ClientClass: any,\n context: any\n ) => {\n const getConfig = context.get(CONFIG_TOKEN);\n const baseUrl = getConfig(); // Call function to get fresh config\n const errorReporter = context.get(ERROR_REPORTER_TOKEN);\n const logger = context.get(LOGGER_TOKEN);\n \n return new ClientClass(baseUrl, errorReporter, logger);\n };\n\n // Register all API clients\n bind<LeaguesApiClient>(LEAGUE_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(LeaguesApiClient, ctx))\n .inSingletonScope();\n\n bind<DriversApiClient>(DRIVER_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(DriversApiClient, ctx))\n .inSingletonScope();\n\n bind<TeamsApiClient>(TEAM_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(TeamsApiClient, ctx))\n .inSingletonScope();\n\n bind<RacesApiClient>(RACE_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(RacesApiClient, ctx))\n .inSingletonScope();\n\n bind<SponsorsApiClient>(SPONSOR_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(SponsorsApiClient, ctx))\n .inSingletonScope();\n\n bind<PaymentsApiClient>(PAYMENT_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(PaymentsApiClient, ctx))\n .inSingletonScope();\n\n bind<WalletsApiClient>(WALLET_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(WalletsApiClient, ctx))\n .inSingletonScope();\n\n bind<AuthApiClient>(AUTH_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(AuthApiClient, ctx))\n .inSingletonScope();\n\n bind<AnalyticsApiClient>(ANALYTICS_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(AnalyticsApiClient, ctx))\n .inSingletonScope();\n\n bind<MediaApiClient>(MEDIA_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(MediaApiClient, ctx))\n .inSingletonScope();\n\n bind<DashboardApiClient>(DASHBOARD_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(DashboardApiClient, ctx))\n .inSingletonScope();\n\n bind<PolicyApiClient>(POLICY_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(PolicyApiClient, ctx))\n .inSingletonScope();\n\n bind<ProtestsApiClient>(PROTEST_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(ProtestsApiClient, ctx))\n .inSingletonScope();\n\n bind<PenaltiesApiClient>(PENALTY_API_CLIENT_TOKEN)\n .toDynamicValue(ctx => createApiClient(PenaltiesApiClient, ctx))\n .inSingletonScope();\n});","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/auth.module.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AuthApiClient' is defined but never used.","line":4,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":23},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AUTH_API_CLIENT_TOKEN' is defined but never used.","line":9,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":24}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ContainerModule } from 'inversify';\nimport { AuthService } from '../../services/auth/AuthService';\nimport { SessionService } from '../../services/auth/SessionService';\nimport { AuthApiClient } from '../../api/auth/AuthApiClient';\n\nimport {\n AUTH_SERVICE_TOKEN,\n SESSION_SERVICE_TOKEN,\n AUTH_API_CLIENT_TOKEN\n} from '../tokens';\n\nexport const AuthModule = new ContainerModule((options) => {\n const bind = options.bind;\n\n // Session Service\n bind<SessionService>(SESSION_SERVICE_TOKEN)\n .to(SessionService)\n .inSingletonScope();\n\n // Auth Service - now creates its own dependencies\n bind<AuthService>(AUTH_SERVICE_TOKEN)\n .to(AuthService)\n .inSingletonScope();\n});\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/core.module.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/driver.module.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'DRIVER_API_CLIENT_TOKEN' is defined but never used.","line":2,"column":32,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":55},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'DriversApiClient' is defined but never used.","line":5,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":26}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ContainerModule } from 'inversify';\nimport { DRIVER_SERVICE_TOKEN, DRIVER_API_CLIENT_TOKEN, ONBOARDING_SERVICE_TOKEN } from '../tokens';\nimport { DriverService } from '@/lib/services/drivers/DriverService';\nimport { OnboardingService } from '@/lib/services/onboarding/OnboardingService';\nimport { DriversApiClient } from '@/lib/api/drivers/DriversApiClient';\n\nexport const DriverModule = new ContainerModule((options) => {\n const bind = options.bind;\n\n bind(DRIVER_SERVICE_TOKEN)\n .to(DriverService)\n .inSingletonScope();\n\n bind(ONBOARDING_SERVICE_TOKEN)\n .toDynamicValue(() => {\n return new OnboardingService();\n })\n .inSingletonScope();\n});","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/landing.module.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'RACE_API_CLIENT_TOKEN' is defined but never used.","line":2,"column":33,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":54},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'LEAGUE_API_CLIENT_TOKEN' is defined but never used.","line":2,"column":56,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":79},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'TEAM_API_CLIENT_TOKEN' is defined but never used.","line":2,"column":81,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":102},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AUTH_API_CLIENT_TOKEN' is defined but never used.","line":2,"column":104,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":125},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'RacesApiClient' is defined but never used.","line":4,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":24},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'LeaguesApiClient' is defined but never used.","line":5,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":26},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'TeamsApiClient' is defined but never used.","line":6,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":24},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'AuthApiClient' is defined but never used.","line":7,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":23}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ContainerModule } from 'inversify';\nimport { LANDING_SERVICE_TOKEN, RACE_API_CLIENT_TOKEN, LEAGUE_API_CLIENT_TOKEN, TEAM_API_CLIENT_TOKEN, AUTH_API_CLIENT_TOKEN } from '../tokens';\nimport { LandingService } from '@/lib/services/landing/LandingService';\nimport { RacesApiClient } from '@/lib/api/races/RacesApiClient';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { TeamsApiClient } from '@/lib/api/teams/TeamsApiClient';\nimport { AuthApiClient } from '@/lib/api/auth/AuthApiClient';\n\nexport const LandingModule = new ContainerModule((options) => {\n const bind = options.bind;\n\n // Landing Service\n bind<LandingService>(LANDING_SERVICE_TOKEN)\n .to(LandingService)\n .inSingletonScope();\n});","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/league.module.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/policy.module.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'POLICY_API_CLIENT_TOKEN' is defined but never used.","line":2,"column":32,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":55},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'PolicyApiClient' is defined but never used.","line":4,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":25}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ContainerModule } from 'inversify';\nimport { POLICY_SERVICE_TOKEN, POLICY_API_CLIENT_TOKEN } from '../tokens';\nimport { PolicyService } from '@/lib/services/policy/PolicyService';\nimport { PolicyApiClient } from '@/lib/api/policy/PolicyApiClient';\n\nexport const PolicyModule = new ContainerModule((options) => {\n const bind = options.bind;\n\n // Policy Service\n bind<PolicyService>(POLICY_SERVICE_TOKEN)\n .to(PolicyService)\n .inSingletonScope();\n});","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/race.module.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'RacesApiClient' is defined but never used.","line":6,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":24},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'ProtestsApiClient' is defined but never used.","line":7,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":27},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'PenaltiesApiClient' is defined but never used.","line":8,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":28},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'RACE_API_CLIENT_TOKEN' is defined but never used.","line":14,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":14,"endColumn":24},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'PROTEST_API_CLIENT_TOKEN' is defined but never used.","line":15,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":15,"endColumn":27},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'PENALTY_API_CLIENT_TOKEN' is defined but never used.","line":16,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":16,"endColumn":27}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ContainerModule } from 'inversify';\nimport { RaceService } from '@/lib/services/races/RaceService';\nimport { RaceResultsService } from '@/lib/services/races/RaceResultsService';\nimport { RaceStewardingService } from '@/lib/services/races/RaceStewardingService';\n\nimport { RacesApiClient } from '@/lib/api/races/RacesApiClient';\nimport { ProtestsApiClient } from '@/lib/api/protests/ProtestsApiClient';\nimport { PenaltiesApiClient } from '@/lib/api/penalties/PenaltiesApiClient';\n\nimport {\n RACE_SERVICE_TOKEN,\n RACE_RESULTS_SERVICE_TOKEN,\n RACE_STEWARDING_SERVICE_TOKEN,\n RACE_API_CLIENT_TOKEN,\n PROTEST_API_CLIENT_TOKEN,\n PENALTY_API_CLIENT_TOKEN,\n} from '../tokens';\n\nexport const RaceModule = new ContainerModule((options) => {\n const bind = options.bind;\n\n // Race Service - creates its own dependencies per contract\n bind<RaceService>(RACE_SERVICE_TOKEN)\n .to(RaceService)\n .inSingletonScope();\n\n // Race Results Service - creates its own dependencies per contract\n bind<RaceResultsService>(RACE_RESULTS_SERVICE_TOKEN)\n .to(RaceResultsService)\n .inSingletonScope();\n\n // Race Stewarding Service - creates its own dependencies per contract\n bind<RaceStewardingService>(RACE_STEWARDING_SERVICE_TOKEN)\n .to(RaceStewardingService)\n .inSingletonScope();\n});","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/sponsor.module.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/modules/team.module.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/providers/ContainerProvider.tsx","messages":[{"ruleId":"react-hooks/exhaustive-deps","severity":2,"message":"React Hook useMemo has an unnecessary dependency: 'scoped'. Either exclude it or remove the dependency array.","line":34,"column":6,"nodeType":"ArrayExpression","endLine":34,"endColumn":33,"suggestions":[{"desc":"Update the dependencies array to be: [providedContainer]","fix":{"range":[907,934],"text":"[providedContainer]"}}]},{"ruleId":"react-hooks/exhaustive-deps","severity":2,"message":"React Hook useMemo has an unnecessary dependency: 'rootContainer'. Either exclude it or remove the dependency array.","line":63,"column":6,"nodeType":"ArrayExpression","endLine":63,"endColumn":21,"suggestions":[{"desc":"Update the dependencies array to be: []","fix":{"range":[1621,1636],"text":"[]"}}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { createContext, ReactNode, useContext, useMemo } from 'react';\nimport { Container } from 'inversify';\nimport { createContainer } from '../container';\n\nexport const ContainerContext = createContext<Container | null>(null);\n\ninterface ContainerProviderProps {\n children: ReactNode;\n /**\n * Optional container instance (for testing or custom configuration)\n */\n container?: Container;\n /**\n * Create scoped container for request/session isolation\n */\n scoped?: boolean;\n}\n\nexport function ContainerProvider({ \n children, \n container: providedContainer,\n scoped = false \n}: ContainerProviderProps) {\n const container = useMemo(() => {\n if (providedContainer) {\n return providedContainer;\n }\n \n const rootContainer = createContainer();\n // Note: This version doesn't support child containers, so scoped just returns root\n return rootContainer;\n }, [providedContainer, scoped]);\n\n return (\n <ContainerContext.Provider value={container}>\n {children}\n </ContainerContext.Provider>\n );\n}\n\n/**\n * Hook to access the container directly\n */\nexport function useContainer(): Container {\n const container = useContext(ContainerContext);\n if (!container) {\n throw new Error('useContainer must be used within ContainerProvider');\n }\n return container;\n}\n\n/**\n * Hook to get a scoped container for request isolation\n * (In this version, returns root container)\n */\nexport function useScopedContainer(): Container {\n const rootContainer = useContainer();\n return useMemo(() => {\n // Return new container for isolation\n return new Container();\n }, [rootContainer]);\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/di/tokens.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/AchievementDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/CountryFlagDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/DashboardConsistencyDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/DashboardCountDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/DashboardDateDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/DashboardLeaguePositionDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/DashboardRankDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/LeagueRoleDisplay.ts","messages":[{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":8,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":25,"endColumn":12}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export type LeagueRole = 'owner' | 'admin' | 'steward' | 'member';\n\nexport interface LeagueRoleDisplayData {\n text: string;\n badgeClasses: string;\n}\n\nexport const leagueRoleDisplay: Record<LeagueRole, LeagueRoleDisplayData> = {\n owner: {\n text: 'Owner',\n badgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',\n },\n admin: {\n text: 'Admin',\n badgeClasses: 'bg-purple-500/10 text-purple-400 border-purple-500/30',\n },\n steward: {\n text: 'Steward',\n badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',\n },\n member: {\n text: 'Member',\n badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',\n },\n} as const;\n\n// For backward compatibility, also export the class with static method\nexport class LeagueRoleDisplay {\n static getLeagueRoleDisplay(role: LeagueRole) {\n return leagueRoleDisplay[role];\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/LeagueWizardValidationMessages.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/MedalDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/ProfileDisplay.ts","messages":[{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":17,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":31,"endColumn":12},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":33,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":36,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":48,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":69,"endColumn":12},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":71,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":73,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":86,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":93,"endColumn":12},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":95,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":97,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":108,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":125,"endColumn":12},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":127,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":129,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":140,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":146,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":153,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":160,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":176,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":179,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":186,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":189,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":196,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":199,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":206,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":209,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":216,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":219,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":226,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":229,"endColumn":2},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":240,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":257,"endColumn":12},{"ruleId":"gridpilot-rules/display-no-business-logic","severity":2,"message":"Display Objects must be class-based and export only classes - see apps/website/lib/contracts/display-objects/DisplayObject.ts","line":259,"column":1,"nodeType":"ExportNamedDeclaration","messageId":"message","endLine":261,"endColumn":2}],"suppressedMessages":[],"errorCount":18,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Profile Display Objects\n * \n * Deterministic formatting for profile data.\n * NO Intl.*, NO Date.toLocale*, NO dynamic formatting.\n */\n\n// ============================================================================\n// COUNTRY FLAG DISPLAY\n// ============================================================================\n\nexport interface CountryFlagDisplayData {\n flag: string;\n label: string;\n}\n\nexport const countryFlagDisplay: Record<string, CountryFlagDisplayData> = {\n // Common country codes - add as needed\n US: { flag: '🇺🇸', label: 'United States' },\n GB: { flag: '🇬🇧', label: 'United Kingdom' },\n DE: { flag: '🇩🇪', label: 'Germany' },\n FR: { flag: '🇫🇷', label: 'France' },\n IT: { flag: '🇮🇹', label: 'Italy' },\n ES: { flag: '🇪🇸', label: 'Spain' },\n JP: { flag: '🇯🇵', label: 'Japan' },\n AU: { flag: '🇦🇺', label: 'Australia' },\n CA: { flag: '🇨🇦', label: 'Canada' },\n BR: { flag: '🇧🇷', label: 'Brazil' },\n // Fallback for unknown codes\n DEFAULT: { flag: '🏁', label: 'Unknown' },\n} as const;\n\nexport function getCountryFlagDisplay(countryCode: string): CountryFlagDisplayData {\n const code = countryCode.toUpperCase();\n return countryFlagDisplay[code] || countryFlagDisplay.DEFAULT;\n}\n\n// ============================================================================\n// ACHIEVEMENT RARITY DISPLAY\n// ============================================================================\n\nexport interface AchievementRarityDisplayData {\n text: string;\n badgeClasses: string;\n borderClasses: string;\n}\n\nexport const achievementRarityDisplay: Record<string, AchievementRarityDisplayData> = {\n common: {\n text: 'Common',\n badgeClasses: 'bg-gray-400/10 text-gray-400',\n borderClasses: 'border-gray-400/30',\n },\n rare: {\n text: 'Rare',\n badgeClasses: 'bg-primary-blue/10 text-primary-blue',\n borderClasses: 'border-primary-blue/30',\n },\n epic: {\n text: 'Epic',\n badgeClasses: 'bg-purple-400/10 text-purple-400',\n borderClasses: 'border-purple-400/30',\n },\n legendary: {\n text: 'Legendary',\n badgeClasses: 'bg-yellow-400/10 text-yellow-400',\n borderClasses: 'border-yellow-400/30',\n },\n} as const;\n\nexport function getAchievementRarityDisplay(rarity: string): AchievementRarityDisplayData {\n return achievementRarityDisplay[rarity] || achievementRarityDisplay.common;\n}\n\n// ============================================================================\n// ACHIEVEMENT ICON DISPLAY\n// ============================================================================\n\nexport type AchievementIconType = 'trophy' | 'medal' | 'star' | 'crown' | 'target' | 'zap';\n\nexport interface AchievementIconDisplayData {\n name: string;\n // Icon component will be resolved in UI layer\n}\n\nexport const achievementIconDisplay: Record<AchievementIconType, AchievementIconDisplayData> = {\n trophy: { name: 'Trophy' },\n medal: { name: 'Medal' },\n star: { name: 'Star' },\n crown: { name: 'Crown' },\n target: { name: 'Target' },\n zap: { name: 'Zap' },\n} as const;\n\nexport function getAchievementIconDisplay(icon: string): AchievementIconDisplayData {\n return achievementIconDisplay[icon as AchievementIconType] || achievementIconDisplay.trophy;\n}\n\n// ============================================================================\n// SOCIAL PLATFORM DISPLAY\n// ============================================================================\n\nexport interface SocialPlatformDisplayData {\n name: string;\n hoverClasses: string;\n}\n\nexport const socialPlatformDisplay: Record<string, SocialPlatformDisplayData> = {\n twitter: {\n name: 'Twitter',\n hoverClasses: 'hover:text-sky-400 hover:bg-sky-400/10',\n },\n youtube: {\n name: 'YouTube',\n hoverClasses: 'hover:text-red-500 hover:bg-red-500/10',\n },\n twitch: {\n name: 'Twitch',\n hoverClasses: 'hover:text-purple-400 hover:bg-purple-400/10',\n },\n discord: {\n name: 'Discord',\n hoverClasses: 'hover:text-indigo-400 hover:bg-indigo-400/10',\n },\n} as const;\n\nexport function getSocialPlatformDisplay(platform: string): SocialPlatformDisplayData {\n return socialPlatformDisplay[platform] || socialPlatformDisplay.discord;\n}\n\n// ============================================================================\n// DATE FORMATTING (DETERMINISTIC)\n// ============================================================================\n\n/**\n * Format date string to \"Month Year\" format\n * Input: ISO date string (e.g., \"2024-01-15T10:30:00Z\")\n * Output: \"Jan 2024\"\n */\nexport function formatMonthYear(dateString: string): string {\n const date = new Date(dateString);\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const month = months[date.getUTCMonth()];\n const year = date.getUTCFullYear();\n return `${month} ${year}`;\n}\n\n/**\n * Format date string to \"Month Day, Year\" format\n * Input: ISO date string\n * Output: \"Jan 15, 2024\"\n */\nexport function formatMonthDayYear(dateString: string): string {\n const date = new Date(dateString);\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const month = months[date.getUTCMonth()];\n const day = date.getUTCDate();\n const year = date.getUTCFullYear();\n return `${month} ${day}, ${year}`;\n}\n\n// ============================================================================\n// STATISTICS FORMATTING\n// ============================================================================\n\nexport interface StatDisplayData {\n value: string;\n label: string;\n}\n\n/**\n * Format percentage with 1 decimal place\n * Input: 0.1234\n * Output: \"12.3%\"\n */\nexport function formatPercentage(value: number | null): string {\n if (value === null || value === undefined) return '0.0%';\n return `${(value * 100).toFixed(1)}%`;\n}\n\n/**\n * Format finish position\n * Input: 1\n * Output: \"P1\"\n */\nexport function formatFinishPosition(position: number | null): string {\n if (position === null || position === undefined) return 'P-';\n return `P${position}`;\n}\n\n/**\n * Format average finish with 1 decimal place\n * Input: 3.456\n * Output: \"P3.5\"\n */\nexport function formatAvgFinish(avg: number | null): string {\n if (avg === null || avg === undefined) return 'P-';\n return `P${avg.toFixed(1)}`;\n}\n\n/**\n * Format rating (whole number)\n * Input: 1234.56\n * Output: \"1235\"\n */\nexport function formatRating(rating: number | null): string {\n if (rating === null || rating === undefined) return '0';\n return Math.round(rating).toString();\n}\n\n/**\n * Format consistency percentage\n * Input: 87.5\n * Output: \"88%\"\n */\nexport function formatConsistency(consistency: number | null): string {\n if (consistency === null || consistency === undefined) return '0%';\n return `${Math.round(consistency)}%`;\n}\n\n/**\n * Format percentile\n * Input: 15.5\n * Output: \"Top 16%\"\n */\nexport function formatPercentile(percentile: number | null): string {\n if (percentile === null || percentile === undefined) return 'Top -%';\n return `Top ${Math.round(percentile)}%`;\n}\n\n// ============================================================================\n// TEAM ROLE DISPLAY\n// ============================================================================\n\nexport interface TeamRoleDisplayData {\n text: string;\n badgeClasses: string;\n}\n\nexport const teamRoleDisplay: Record<string, TeamRoleDisplayData> = {\n owner: {\n text: 'Owner',\n badgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',\n },\n admin: {\n text: 'Admin',\n badgeClasses: 'bg-purple-500/10 text-purple-400 border-purple-500/30',\n },\n steward: {\n text: 'Steward',\n badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',\n },\n member: {\n text: 'Member',\n badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',\n },\n} as const;\n\nexport function getTeamRoleDisplay(role: string): TeamRoleDisplayData {\n return teamRoleDisplay[role] || teamRoleDisplay.member;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/RatingDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/SkillLevelDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/display-objects/WinRateDisplay.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/feature/FeatureFlagProvider.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/feature/FeatureFlagService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/gateways/SessionGateway.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/ApiRequestLogger.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/ConsoleErrorReporter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/EnhancedErrorReporter.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'notificationSystem' is assigned a value but never used.","line":11,"column":5,"nodeType":"Identifier","messageId":"unusedVar","endLine":11,"endColumn":28},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":25,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":28,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[404,407],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[404,407],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Enhanced Error Reporter with user notifications and environment-specific handling\n */\n\nimport { ErrorReporter } from '../interfaces/ErrorReporter';\nimport { Logger } from '../interfaces/Logger';\nimport { ApiError } from '../api/base/ApiError';\nimport { connectionMonitor } from '../api/base/ApiConnectionMonitor';\n\n// Import notification system (will be used if available)\nlet notificationSystem: any = null;\ntry {\n // Dynamically import to avoid circular dependencies\n import('@/components/notifications/NotificationProvider').then(module => {\n notificationSystem = module;\n }).catch(() => {\n // Notification system not available yet\n });\n} catch {\n // Silent fail - notification system may not be initialized\n}\n\nexport interface EnhancedErrorReporterOptions {\n /**\n * Whether to show user-facing notifications\n */\n showUserNotifications?: boolean;\n \n /**\n * Whether to log to console (always true in dev)\n */\n logToConsole?: boolean;\n \n /**\n * Whether to report to external service (e.g., Sentry)\n */\n reportToExternal?: boolean;\n \n /**\n * Custom error handler for specific error types\n */\n customHandlers?: Record<string, (error: ApiError) => void>;\n}\n\nexport class EnhancedErrorReporter implements ErrorReporter {\n private options: EnhancedErrorReporterOptions;\n private logger: Logger;\n private errorBuffer: Array<{ error: ApiError; context: unknown }> = [];\n private readonly MAX_BUFFER_SIZE = 50;\n\n constructor(logger: Logger, options: EnhancedErrorReporterOptions = {}) {\n this.logger = logger;\n this.options = {\n showUserNotifications: options.showUserNotifications ?? true,\n logToConsole: options.logToConsole ?? true,\n reportToExternal: options.reportToExternal ?? false,\n customHandlers: options.customHandlers || {},\n };\n }\n\n /**\n * Main error reporting method\n */\n report(error: Error, context?: unknown): void {\n // Only handle ApiError instances for enhanced reporting\n if (!(error instanceof ApiError)) {\n // For non-API errors, use basic logging\n if (this.options.logToConsole) {\n console.error('Non-API Error:', error, context);\n }\n return;\n }\n\n // Add to buffer for potential batch reporting\n this.addToBuffer(error, context);\n\n // Log based on environment and severity\n this.logError(error, context);\n\n // Handle custom error types\n this.handleCustomHandlers(error);\n\n // Show user notifications if enabled\n if (this.options.showUserNotifications) {\n this.showUserNotification(error);\n }\n\n // Report to external services if configured\n if (this.options.reportToExternal) {\n this.reportToExternal(error, context);\n }\n\n // Update connection monitor\n if (error.isConnectivityIssue()) {\n connectionMonitor.recordFailure(error);\n }\n }\n\n /**\n * Log error with appropriate severity\n */\n private logError(error: ApiError, context: unknown): void {\n if (!this.options.logToConsole) return;\n\n const isDev = process.env.NODE_ENV === 'development';\n const severity = error.getSeverity();\n\n const message = isDev ? error.getDeveloperMessage() : error.getUserMessage();\n const contextObj = typeof context === 'object' && context !== null ? context : {};\n const errorContextObj = typeof error.context === 'object' && error.context !== null ? error.context : {};\n \n const logContext = {\n ...errorContextObj,\n ...contextObj,\n type: error.type,\n isRetryable: error.isRetryable(),\n isConnectivity: error.isConnectivityIssue(),\n };\n\n if (severity === 'error') {\n this.logger.error(message, error, logContext);\n if (isDev) {\n console.error(`[API-ERROR] ${message}`, { error, context: logContext });\n }\n } else if (severity === 'warn') {\n this.logger.warn(message, logContext);\n if (isDev) {\n console.warn(`[API-WARN] ${message}`, { context: logContext });\n }\n } else {\n this.logger.info(message, logContext);\n if (isDev) {\n console.log(`[API-INFO] ${message}`, { context: logContext });\n }\n }\n }\n\n /**\n * Show user-facing notification\n */\n private showUserNotification(error: ApiError): void {\n const isDev = process.env.NODE_ENV === 'development';\n\n // In development, we might want to show more details\n if (isDev) {\n // Use console notification in dev\n console.log(`%c[USER-NOTIFICATION] ${error.getUserMessage()}`, \n 'background: #222; color: #bada55; padding: 4px 8px; border-radius: 4px;'\n );\n return;\n }\n\n // In production, use the notification system if available\n // This is a deferred import to avoid circular dependencies\n if (typeof window !== 'undefined') {\n setTimeout(() => {\n try {\n // Try to access notification context if available\n const notificationEvent = new CustomEvent('gridpilot-notification', {\n detail: {\n type: 'error',\n title: this.getNotificationTitle(error),\n message: error.getUserMessage(),\n variant: error.isConnectivityIssue() ? 'modal' : 'toast',\n autoDismiss: !error.isConnectivityIssue(),\n }\n });\n window.dispatchEvent(notificationEvent);\n } catch (e) {\n // Fallback to browser alert if notification system unavailable\n if (error.isConnectivityIssue()) {\n console.warn('API Error:', error.getUserMessage());\n }\n }\n }, 100);\n }\n }\n\n /**\n * Get appropriate notification title\n */\n private getNotificationTitle(error: ApiError): string {\n switch (error.type) {\n case 'NETWORK_ERROR':\n return 'Connection Lost';\n case 'TIMEOUT_ERROR':\n return 'Request Timed Out';\n case 'AUTH_ERROR':\n return 'Authentication Required';\n case 'SERVER_ERROR':\n return 'Server Error';\n case 'RATE_LIMIT_ERROR':\n return 'Rate Limit Reached';\n default:\n return 'Something Went Wrong';\n }\n }\n\n /**\n * Handle custom error type handlers\n */\n private handleCustomHandlers(error: ApiError): void {\n if (this.options.customHandlers && this.options.customHandlers[error.type]) {\n try {\n this.options.customHandlers[error.type]!(error);\n } catch (handlerError) {\n console.error('Custom error handler failed:', handlerError);\n }\n }\n }\n\n /**\n * Report to external services (placeholder for future integration)\n */\n private reportToExternal(error: ApiError, context: unknown): void {\n // Placeholder for external error reporting (e.g., Sentry, LogRocket)\n // In a real implementation, this would send to your error tracking service\n \n if (process.env.NODE_ENV === 'development') {\n const contextObj = typeof context === 'object' && context !== null ? context : {};\n console.log('[EXTERNAL-REPORT] Would report:', {\n type: error.type,\n message: error.message,\n context: { ...error.context, ...contextObj },\n timestamp: new Date().toISOString(),\n });\n }\n }\n\n /**\n * Add error to buffer for potential batch reporting\n */\n private addToBuffer(error: ApiError, context: unknown): void {\n this.errorBuffer.push({ error, context });\n \n // Keep buffer size in check\n if (this.errorBuffer.length > this.MAX_BUFFER_SIZE) {\n this.errorBuffer.shift();\n }\n }\n\n /**\n * Get buffered errors\n */\n getBufferedErrors(): Array<{ error: ApiError; context: unknown }> {\n return [...this.errorBuffer];\n }\n\n /**\n * Clear error buffer\n */\n clearBuffer(): void {\n this.errorBuffer = [];\n }\n\n /**\n * Batch report buffered errors\n */\n flush(): void {\n if (this.errorBuffer.length === 0) return;\n\n if (this.options.logToConsole) {\n console.groupCollapsed(`[API-REPORT] Flushing ${this.errorBuffer.length} buffered errors`);\n this.errorBuffer.forEach(({ error, context }) => {\n console.log(`${error.type}: ${error.message}`, { error, context });\n });\n console.groupEnd();\n }\n\n // In production, this would batch send to external service\n if (this.options.reportToExternal) {\n const batch = this.errorBuffer.map(({ error, context }) => {\n const contextObj = typeof context === 'object' && context !== null ? context : {};\n return {\n type: error.type,\n message: error.message,\n context: { ...error.context, ...contextObj },\n timestamp: new Date().toISOString(),\n };\n });\n \n console.log('[EXTERNAL-REPORT] Batch:', batch);\n }\n\n this.clearBuffer();\n }\n\n /**\n * Update options dynamically\n */\n updateOptions(newOptions: Partial<EnhancedErrorReporterOptions>): void {\n this.options = { ...this.options, ...newOptions };\n }\n}\n\n/**\n * Global error reporter instance\n */\nlet globalReporter: EnhancedErrorReporter | null = null;\n\nexport function getGlobalErrorReporter(): EnhancedErrorReporter {\n if (!globalReporter) {\n // Import the console logger\n const { ConsoleLogger } = require('./logging/ConsoleLogger');\n globalReporter = new EnhancedErrorReporter(new ConsoleLogger(), {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: process.env.NODE_ENV === 'production',\n });\n }\n return globalReporter;\n}\n\n/**\n * Helper function to report API errors easily\n */\nexport function reportApiError(\n error: ApiError,\n context?: unknown,\n reporter?: EnhancedErrorReporter\n): void {\n const rep = reporter || getGlobalErrorReporter();\n rep.report(error, context);\n}\n\n/**\n * React hook for error reporting\n */\nexport function useErrorReporter() {\n const reporter = getGlobalErrorReporter();\n \n return {\n report: (error: Error, context?: unknown) => reporter.report(error, context),\n flush: () => reporter.flush(),\n getBuffered: () => reporter.getBufferedErrors(),\n updateOptions: (opts: Partial<EnhancedErrorReporterOptions>) => reporter.updateOptions(opts),\n };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/ErrorReplay.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'globalHandler' is assigned a value but never used.","line":51,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":51,"endColumn":24},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":290,"column":43,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":290,"endColumn":46,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8312,8315],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8312,8315],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":308,"column":28,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":308,"endColumn":31,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8768,8771],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8768,8771],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Error Replay System\n * Allows developers to replay errors with the exact same context\n */\n\nimport { getGlobalErrorHandler } from './GlobalErrorHandler';\nimport { getGlobalApiLogger } from './ApiRequestLogger';\nimport { ApiError } from '../api/base/ApiError';\n\nexport interface ReplayContext {\n timestamp: string;\n error: {\n message: string;\n type: string;\n stack?: string;\n context?: unknown;\n };\n environment: {\n userAgent: string;\n url: string;\n viewport: { width: number; height: number };\n language: string;\n platform: string;\n };\n apiRequests: Array<{\n url: string;\n method: string;\n duration?: number;\n status?: number;\n error?: string;\n }>;\n reactErrors: Array<{\n message: string;\n componentStack?: string;\n }>;\n metadata: {\n mode: string;\n timestamp: string;\n replayId: string;\n };\n}\n\nexport class ErrorReplaySystem {\n private replayHistory: ReplayContext[] = [];\n private readonly MAX_REPLAYS = 20;\n\n /**\n * Capture current state for replay\n */\n captureReplay(error: Error | ApiError, additionalContext: Record<string, unknown> = {}): ReplayContext {\n const globalHandler = getGlobalErrorHandler();\n const apiLogger = getGlobalApiLogger();\n\n const replayId = `replay_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n const replay: ReplayContext = {\n timestamp: new Date().toISOString(),\n error: {\n message: error.message,\n type: error instanceof ApiError ? error.type : error.name || 'Error',\n stack: error.stack,\n context: error instanceof ApiError ? error.context : additionalContext,\n },\n environment: {\n userAgent: navigator.userAgent,\n url: window.location.href,\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n },\n language: navigator.language,\n platform: navigator.platform,\n },\n apiRequests: apiLogger.getHistory().slice(-10).map(log => ({\n url: log.url,\n method: log.method,\n duration: log.response?.duration,\n status: log.response?.status,\n error: log.error?.message,\n })),\n reactErrors: (window as { __GRIDPILOT_REACT_ERRORS__?: Array<{ error?: { message?: string }; componentStack?: string }> }).__GRIDPILOT_REACT_ERRORS__?.slice(-5).map((e) => ({\n message: e.error?.message || 'Unknown React error',\n componentStack: e.componentStack,\n })) || [],\n metadata: {\n mode: process.env.NODE_ENV || 'unknown',\n timestamp: new Date().toISOString(),\n replayId,\n },\n };\n\n this.replayHistory.push(replay);\n\n // Keep only last N replays\n if (this.replayHistory.length > this.MAX_REPLAYS) {\n this.replayHistory = this.replayHistory.slice(-this.MAX_REPLAYS);\n }\n\n // Store in localStorage for persistence across sessions\n this.persistReplay(replay);\n\n return replay;\n }\n\n /**\n * Persist replay to localStorage\n */\n private persistReplay(replay: ReplayContext): void {\n try {\n const key = `gridpilot_replay_${replay.metadata.replayId}`;\n localStorage.setItem(key, JSON.stringify(replay));\n \n // Also add to index\n const indexKey = 'gridpilot_replay_index';\n const existing = JSON.parse(localStorage.getItem(indexKey) || '[]');\n existing.push({\n id: replay.metadata.replayId,\n timestamp: replay.timestamp,\n error: replay.error.message,\n type: replay.error.type,\n });\n localStorage.setItem(indexKey, JSON.stringify(existing.slice(-this.MAX_REPLAYS)));\n } catch (e) {\n // Storage might be full or disabled\n console.warn('Failed to persist replay:', e);\n }\n }\n\n /**\n * Get all replays\n */\n getReplays(): ReplayContext[] {\n return [...this.replayHistory];\n }\n\n /**\n * Get replay by ID\n */\n getReplay(replayId: string): ReplayContext | null {\n // Check memory first\n const inMemory = this.replayHistory.find(r => r.metadata.replayId === replayId);\n if (inMemory) return inMemory;\n\n // Check localStorage\n try {\n const key = `gridpilot_replay_${replayId}`;\n const stored = localStorage.getItem(key);\n if (stored) {\n return JSON.parse(stored);\n }\n } catch (e) {\n console.warn('Failed to load replay from storage:', e);\n }\n\n return null;\n }\n\n /**\n * Replay an error by re-executing it with the same context\n */\n async replay(replayId: string): Promise<void> {\n const replay = this.getReplay(replayId);\n if (!replay) {\n console.error(`Replay ${replayId} not found`);\n return;\n }\n\n console.groupCollapsed(`%c[REPLAY] Replaying error: ${replay.error.message}`, \n 'color: #00ff88; font-weight: bold; font-size: 14px;'\n );\n\n console.log('Original Error:', replay.error);\n console.log('Environment:', replay.environment);\n console.log('API Requests:', replay.apiRequests);\n console.log('React Errors:', replay.reactErrors);\n console.log('Metadata:', replay.metadata);\n\n // Recreate the error\n const error = replay.error.type === 'ApiError'\n ? new ApiError(\n replay.error.message,\n ((replay.error.context as { type?: string } | undefined)?.type as import('../api/base/ApiError').ApiErrorType) || 'UNKNOWN_ERROR',\n {\n timestamp: replay.timestamp,\n ...(replay.error.context as Record<string, unknown> | undefined),\n }\n )\n : new Error(replay.error.message);\n\n if (replay.error.stack) {\n error.stack = replay.error.stack;\n }\n\n // Report through global handler\n const globalHandler = getGlobalErrorHandler();\n globalHandler.report(error, {\n source: 'replay',\n replayId: replay.metadata.replayId,\n originalTimestamp: replay.timestamp,\n environment: replay.environment,\n apiRequests: replay.apiRequests,\n reactErrors: replay.reactErrors,\n });\n\n console.groupEnd();\n\n // Show a notification\n if (typeof window !== 'undefined') {\n const notificationEvent = new CustomEvent('gridpilot-notification', {\n detail: {\n type: 'replay_success',\n title: 'Error Replay Complete',\n message: `Replayed error from ${new Date(replay.timestamp).toLocaleString()}`,\n variant: 'toast',\n }\n });\n window.dispatchEvent(notificationEvent);\n }\n }\n\n /**\n * Export replay data\n */\n exportReplay(replayId: string, format: 'json' | 'text' = 'json'): string {\n const replay = this.getReplay(replayId);\n if (!replay) {\n return 'Replay not found';\n }\n\n if (format === 'json') {\n return JSON.stringify(replay, null, 2);\n }\n\n // Text format\n return `\nError Replay Report\n===================\n\nReplay ID: ${replay.metadata.replayId}\nTimestamp: ${replay.timestamp}\n\nERROR\n-----\nType: ${replay.error.type}\nMessage: ${replay.error.message}\nStack: ${replay.error.stack || 'N/A'}\n\nENVIRONMENT\n-----------\nUser Agent: ${replay.environment.userAgent}\nURL: ${replay.environment.url}\nViewport: ${replay.environment.viewport.width}x${replay.environment.viewport.height}\nLanguage: ${replay.environment.language}\nPlatform: ${replay.environment.platform}\n\nAPI REQUESTS (${replay.apiRequests.length})\n----------------${replay.apiRequests.map(req => `\n ${req.method} ${req.url}\n ${req.status ? `Status: ${req.status}` : ''} ${req.duration ? `Duration: ${req.duration}ms` : ''}\n ${req.error ? `Error: ${req.error}` : ''}\n`).join('')}\n\nREACT ERRORS (${replay.reactErrors.length})\n----------------${replay.reactErrors.map(react => `\n ${react.message}\n ${react.componentStack ? `Component Stack: ${react.componentStack}` : ''}\n`).join('')}\n\nMETADATA\n--------\nMode: ${replay.metadata.mode}\nOriginal Timestamp: ${replay.metadata.timestamp}\n`;\n }\n\n /**\n * Delete replay\n */\n deleteReplay(replayId: string): void {\n // Remove from memory\n this.replayHistory = this.replayHistory.filter(r => r.metadata.replayId !== replayId);\n\n // Remove from localStorage\n try {\n localStorage.removeItem(`gridpilot_replay_${replayId}`);\n \n // Update index\n const indexKey = 'gridpilot_replay_index';\n const existing = JSON.parse(localStorage.getItem(indexKey) || '[]');\n const updated = existing.filter((r: any) => r.id !== replayId);\n localStorage.setItem(indexKey, JSON.stringify(updated));\n } catch (e) {\n console.warn('Failed to delete replay:', e);\n }\n }\n\n /**\n * Clear all replays\n */\n clearAll(): void {\n this.replayHistory = [];\n\n // Clear from localStorage\n try {\n const indexKey = 'gridpilot_replay_index';\n const existing = JSON.parse(localStorage.getItem(indexKey) || '[]');\n \n existing.forEach((r: any) => {\n localStorage.removeItem(`gridpilot_replay_${r.id}`);\n });\n \n localStorage.removeItem(indexKey);\n } catch (e) {\n console.warn('Failed to clear replays:', e);\n }\n }\n\n /**\n * Get replay index (summary of all available replays)\n */\n getReplayIndex(): Array<{ id: string; timestamp: string; error: string; type: string }> {\n try {\n const indexKey = 'gridpilot_replay_index';\n const stored = localStorage.getItem(indexKey);\n if (stored) {\n return JSON.parse(stored);\n }\n } catch (e) {\n console.warn('Failed to load replay index:', e);\n }\n\n // Return in-memory index\n return this.replayHistory.map(r => ({\n id: r.metadata.replayId,\n timestamp: r.timestamp,\n error: r.error.message,\n type: r.error.type,\n }));\n }\n\n /**\n * Auto-capture errors for replay\n */\n autoCapture(error: Error | ApiError, context: Record<string, unknown> = {}): void {\n // Only capture in development or if explicitly enabled\n if (process.env.NODE_ENV !== 'development') {\n return;\n }\n\n const replay = this.captureReplay(error, context);\n \n if (console) {\n console.log('%c[REPLAY] Captured error for replay', 'color: #00ff88; font-weight: bold;', {\n replayId: replay.metadata.replayId,\n message: replay.error.message,\n });\n }\n }\n}\n\n/**\n * Global instance accessor\n */\nlet globalReplayInstance: ErrorReplaySystem | null = null;\n\nexport function getGlobalReplaySystem(): ErrorReplaySystem {\n if (!globalReplayInstance) {\n globalReplayInstance = new ErrorReplaySystem();\n }\n return globalReplayInstance;\n}\n\n/**\n * Initialize replay system\n */\nexport function initializeReplaySystem(): ErrorReplaySystem {\n const system = new ErrorReplaySystem();\n globalReplayInstance = system;\n return system;\n}\n\n/**\n * React hook for error replay\n */\nexport function useErrorReplay() {\n const system = getGlobalReplaySystem();\n\n return {\n capture: (error: Error | ApiError, context?: Record<string, unknown>) => \n system.captureReplay(error, context),\n replay: (replayId: string) => system.replay(replayId),\n getReplays: () => system.getReplays(),\n getReplay: (replayId: string) => system.getReplay(replayId),\n exportReplay: (replayId: string, format?: 'json' | 'text') => \n system.exportReplay(replayId, format),\n deleteReplay: (replayId: string) => system.deleteReplay(replayId),\n clearAll: () => system.clearAll(),\n getReplayIndex: () => system.getReplayIndex(),\n };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/GlobalErrorHandler.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":233,"column":16,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":233,"endColumn":19,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6962,6965],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6962,6965],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":257,"column":31,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":257,"endColumn":34,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7687,7690],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7687,7690],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":258,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":258,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7743,7746],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7743,7746],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":259,"column":42,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":259,"endColumn":45,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7812,7815],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7812,7815],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":261,"column":33,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":261,"endColumn":36,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7889,7892],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7889,7892],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":262,"column":38,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":262,"endColumn":41,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7946,7949],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7946,7949],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":263,"column":33,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":263,"endColumn":36,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8009,8012],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8009,8012],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":264,"column":28,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":264,"endColumn":31,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8062,8065],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8062,8065],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":470,"column":23,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":470,"endColumn":26,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[14614,14617],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[14614,14617],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":471,"column":37,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":471,"endColumn":40,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[14673,14676],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[14673,14676],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":10,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Enhanced Global Error Handler for Maximum Developer Transparency\n * Captures all uncaught errors, promise rejections, and React errors\n */\n\nimport { ApiError } from '../api/base/ApiError';\nimport { getGlobalErrorReporter } from './EnhancedErrorReporter';\nimport { ConsoleLogger } from './logging/ConsoleLogger';\nimport { getGlobalReplaySystem } from './ErrorReplay';\n\nexport interface GlobalErrorHandlerOptions {\n /**\n * Enable detailed error overlays in development\n */\n showDevOverlay?: boolean;\n \n /**\n * Log all errors to console with maximum detail\n */\n verboseLogging?: boolean;\n \n /**\n * Capture stack traces with enhanced context\n */\n captureEnhancedStacks?: boolean;\n \n /**\n * Report to external services (Sentry, etc.)\n */\n reportToExternal?: boolean;\n \n /**\n * Custom error filter to ignore certain errors\n */\n errorFilter?: (error: Error) => boolean;\n}\n\nexport class GlobalErrorHandler {\n private options: GlobalErrorHandlerOptions;\n private logger: ConsoleLogger;\n private errorReporter: ReturnType<typeof getGlobalErrorReporter>;\n private errorHistory: Array<{\n error: Error | ApiError;\n timestamp: string;\n context?: unknown;\n stackEnhanced?: string;\n }> = [];\n private readonly MAX_HISTORY = 100;\n private isInitialized = false;\n\n constructor(options: GlobalErrorHandlerOptions = {}) {\n this.options = {\n showDevOverlay: options.showDevOverlay ?? process.env.NODE_ENV === 'development',\n verboseLogging: options.verboseLogging ?? process.env.NODE_ENV === 'development',\n captureEnhancedStacks: options.captureEnhancedStacks ?? process.env.NODE_ENV === 'development',\n reportToExternal: options.reportToExternal ?? process.env.NODE_ENV === 'production',\n errorFilter: options.errorFilter,\n };\n\n this.logger = new ConsoleLogger();\n this.errorReporter = getGlobalErrorReporter();\n }\n\n /**\n * Initialize global error handlers\n */\n initialize(): void {\n if (this.isInitialized) {\n console.warn('[GlobalErrorHandler] Already initialized');\n return;\n }\n\n // Only initialize in browser environment\n if (typeof window === 'undefined') {\n if (this.options.verboseLogging) {\n this.logger.info('Global error handler skipped (server-side)');\n }\n return;\n }\n\n // Handle uncaught JavaScript errors\n window.addEventListener('error', this.handleWindowError);\n \n // Handle unhandled promise rejections\n window.addEventListener('unhandledrejection', this.handleUnhandledRejection);\n \n // Override console.error to capture framework errors\n this.overrideConsoleError();\n \n // React error boundary fallback\n this.setupReactErrorHandling();\n\n this.isInitialized = true;\n\n if (this.options.verboseLogging) {\n this.logger.info('Global error handler initialized', {\n devOverlay: this.options.showDevOverlay,\n verboseLogging: this.options.verboseLogging,\n enhancedStacks: this.options.captureEnhancedStacks,\n });\n }\n }\n\n /**\n * Handle window errors (uncaught JavaScript errors)\n */\n private handleWindowError = (event: ErrorEvent): void => {\n const error = event.error;\n \n // Apply error filter if provided\n if (this.options.errorFilter && !this.options.errorFilter(error)) {\n return;\n }\n\n // Check if this is a network/CORS error (expected in some cases)\n if (error instanceof TypeError && error.message.includes('fetch')) {\n this.logger.warn('Network error detected', {\n type: 'network_error',\n message: error.message,\n url: event.filename,\n line: event.lineno,\n col: event.colno,\n });\n return; // Don't prevent default for network errors\n }\n\n const enhancedContext = this.captureEnhancedContext('window_error', {\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n message: event.message,\n });\n\n // Log with appropriate detail\n this.logErrorWithMaximumDetail(error, enhancedContext);\n\n // Store in history\n this.addToHistory(error, enhancedContext);\n\n // Report to external if enabled (but not for network errors)\n if (this.options.reportToExternal) {\n this.reportToExternal(error, enhancedContext);\n }\n\n // Auto-capture for replay in development\n if (this.options.showDevOverlay) {\n const replaySystem = getGlobalReplaySystem();\n replaySystem.autoCapture(error, enhancedContext);\n }\n\n // Prevent default error logging in dev to avoid duplicates\n if (this.options.showDevOverlay) {\n event.preventDefault();\n }\n };\n\n /**\n * Handle unhandled promise rejections\n */\n private handleUnhandledRejection = (event: PromiseRejectionEvent): void => {\n const error = event.reason;\n \n // Apply error filter if provided\n if (this.options.errorFilter && !this.options.errorFilter(error)) {\n return;\n }\n\n // Check if this is a network error (expected)\n if (error instanceof TypeError && error.message.includes('fetch')) {\n this.logger.warn('Unhandled promise rejection - network error', {\n type: 'network_error',\n message: error.message,\n });\n return;\n }\n\n const enhancedContext = this.captureEnhancedContext('unhandled_promise', {\n promise: event.promise,\n reason: typeof error === 'string' ? error : error?.message || 'Unknown promise rejection',\n });\n\n // Log with appropriate detail\n this.logErrorWithMaximumDetail(error, enhancedContext);\n\n // Store in history\n this.addToHistory(error, enhancedContext);\n\n // Report to external if enabled (but not for network errors)\n if (this.options.reportToExternal) {\n this.reportToExternal(error, enhancedContext);\n }\n\n // Prevent default logging\n if (this.options.showDevOverlay) {\n event.preventDefault();\n }\n };\n\n /**\n * Override console.error to capture framework errors\n */\n private overrideConsoleError(): void {\n const originalError = console.error;\n \n console.error = (...args: unknown[]): void => {\n // Call original first\n originalError.apply(console, args);\n\n // Try to extract error from arguments\n const error = args.find(arg => arg instanceof Error) || \n args.find(arg => typeof arg === 'object' && arg !== null && 'message' in arg) ||\n new Error(args.map(a => String(a)).join(' '));\n\n if (error instanceof Error) {\n const enhancedContext = this.captureEnhancedContext('console_error', {\n originalArgs: args,\n });\n\n // Store in history\n this.addToHistory(error, enhancedContext);\n\n // No overlay - just enhanced console logging\n }\n };\n }\n\n /**\n * Setup React-specific error handling\n */\n private setupReactErrorHandling(): void {\n // This will be used by React Error Boundaries\n // We'll provide a global registry for React errors\n (window as any).__GRIDPILOT_REACT_ERRORS__ = [];\n }\n\n /**\n * Capture enhanced context with stack trace and environment info\n */\n private captureEnhancedContext(type: string, additionalContext: Record<string, unknown> = {}): Record<string, unknown> {\n const stack = new Error().stack;\n \n return {\n type,\n timestamp: new Date().toISOString(),\n userAgent: navigator.userAgent,\n url: window.location.href,\n language: navigator.language,\n platform: navigator.platform,\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n },\n screen: {\n width: window.screen.width,\n height: window.screen.height,\n },\n memory: (performance as any).memory ? {\n usedJSHeapSize: (performance as any).memory.usedJSHeapSize,\n totalJSHeapSize: (performance as any).memory.totalJSHeapSize,\n } : null,\n connection: (navigator as any).connection ? {\n effectiveType: (navigator as any).connection.effectiveType,\n downlink: (navigator as any).connection.downlink,\n rtt: (navigator as any).connection.rtt,\n } : null,\n ...additionalContext,\n enhancedStack: this.options.captureEnhancedStacks ? this.enhanceStackTrace(stack) : undefined,\n };\n }\n\n /**\n * Enhance stack trace with additional context\n */\n private enhanceStackTrace(stack?: string): string | undefined {\n if (!stack) return undefined;\n\n // Add source map information if available\n const lines = stack.split('\\n').slice(1); // Remove first line (error message)\n \n const enhanced = lines.map(line => {\n // Try to extract file and line info\n const match = line.match(/at (.+) \\((.+):(\\d+):(\\d+)\\)/) || \n line.match(/at (.+):(\\d+):(\\d+)/);\n \n if (match) {\n const func = match[1] || 'anonymous';\n const file = match[2] || match[1];\n const lineNum = match[3] || match[2];\n const colNum = match[4] || match[3];\n \n // Add source map comment if in development\n if (process.env.NODE_ENV === 'development' && file && file.includes('.js')) {\n return `at ${func} (${file}:${lineNum}:${colNum}) [Source Map: ${file}.map]`;\n }\n \n return `at ${func} (${file}:${lineNum}:${colNum})`;\n }\n \n return line.trim();\n });\n\n return enhanced.join('\\n');\n }\n\n /**\n * Log error with appropriate detail\n */\n private logErrorWithMaximumDetail(error: Error | ApiError, context: Record<string, unknown>): void {\n if (!this.options.verboseLogging) return;\n\n const isApiError = error instanceof ApiError;\n const isWarning = isApiError && error.getSeverity() === 'warn';\n\n if (isWarning) {\n // Simplified warning output\n this.logger.warn(error.message, context);\n return;\n }\n\n // Full error details for actual errors\n this.logger.error(error.message, error, context);\n\n // In development, show additional details\n if (process.env.NODE_ENV === 'development') {\n console.groupCollapsed(`%c[ERROR DETAIL] ${error.name || 'Error'}`, 'color: #ff4444; font-weight: bold; font-size: 14px;');\n \n console.log('%cError Details:', 'color: #666; font-weight: bold;', {\n name: error.name,\n message: error.message,\n type: isApiError ? error.type : 'N/A',\n severity: isApiError ? error.getSeverity() : 'error',\n retryable: isApiError ? error.isRetryable() : 'N/A',\n connectivity: isApiError ? error.isConnectivityIssue() : 'N/A',\n });\n\n console.log('%cContext:', 'color: #666; font-weight: bold;', context);\n\n if (isApiError && error.context?.developerHint) {\n console.log('%c💡 Developer Hint:', 'color: #00aaff; font-weight: bold;', error.context.developerHint);\n }\n\n console.groupEnd();\n }\n }\n\n\n /**\n * Report error to external services\n */\n private reportToExternal(error: Error | ApiError, context: Record<string, unknown>): void {\n // This is a placeholder for external error reporting (Sentry, LogRocket, etc.)\n // In a real implementation, you would send structured data to your error tracking service\n \n if (this.options.verboseLogging) {\n console.log('[EXTERNAL REPORT] Would send to error tracking service:', {\n error: {\n name: error.name,\n message: error.message,\n stack: error.stack,\n type: error instanceof ApiError ? error.type : undefined,\n },\n context,\n timestamp: new Date().toISOString(),\n });\n }\n }\n\n /**\n * Add error to history\n */\n private addToHistory(error: Error | ApiError, context: Record<string, unknown>): void {\n const entry = {\n error,\n timestamp: new Date().toISOString(),\n context,\n stackEnhanced: context.enhancedStack as string | undefined,\n };\n\n this.errorHistory.push(entry);\n\n // Keep only last N errors\n if (this.errorHistory.length > this.MAX_HISTORY) {\n this.errorHistory = this.errorHistory.slice(-this.MAX_HISTORY);\n }\n }\n\n /**\n * Get error history\n */\n getErrorHistory(): Array<{ error: Error | ApiError; timestamp: string; context?: unknown; stackEnhanced?: string }> {\n return [...this.errorHistory];\n }\n\n /**\n * Clear error history\n */\n clearHistory(): void {\n this.errorHistory = [];\n if (this.options.verboseLogging) {\n this.logger.info('Error history cleared');\n }\n }\n\n /**\n * Get statistics about errors\n */\n getStats(): {\n total: number;\n byType: Record<string, number>;\n recent: Array<{ timestamp: string; message: string; type: string }>;\n } {\n const stats = {\n total: this.errorHistory.length,\n byType: {} as Record<string, number>,\n recent: this.errorHistory.slice(-10).map(entry => ({\n timestamp: entry.timestamp,\n message: entry.error.message,\n type: entry.error instanceof ApiError ? entry.error.type : entry.error.name || 'Error',\n })),\n };\n\n this.errorHistory.forEach(entry => {\n const type = entry.error instanceof ApiError ? entry.error.type : entry.error.name || 'Error';\n stats.byType[type] = (stats.byType[type] || 0) + 1;\n });\n\n return stats;\n }\n\n /**\n * Manually report an error\n */\n report(error: Error | ApiError, additionalContext: Record<string, unknown> = {}): void {\n const context = this.captureEnhancedContext('manual_report', additionalContext);\n \n // Check if this is a network error (don't report to external services)\n const isNetworkError = error.message.includes('fetch') ||\n error.message.includes('Failed to fetch') ||\n error.message.includes('NetworkError');\n\n if (isNetworkError) {\n this.logger.warn(`Manual error report: ${error.message}`, context);\n } else {\n this.logErrorWithMaximumDetail(error, context);\n }\n\n this.addToHistory(error, context);\n\n // Auto-capture for replay in development\n if (this.options.showDevOverlay) {\n const replaySystem = getGlobalReplaySystem();\n replaySystem.autoCapture(error, context);\n }\n\n // Only report non-network errors to external services\n if (this.options.reportToExternal && !isNetworkError) {\n this.reportToExternal(error, context);\n }\n }\n\n /**\n * Destroy the error handler and remove all listeners\n */\n destroy(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('error', this.handleWindowError);\n window.removeEventListener('unhandledrejection', this.handleUnhandledRejection);\n \n // Restore original console.error\n if ((console as any)._originalError) {\n console.error = (console as any)._originalError;\n }\n }\n\n this.isInitialized = false;\n\n if (this.options.verboseLogging) {\n this.logger.info('Global error handler destroyed');\n }\n }\n}\n\n/**\n * Global instance accessor\n */\nlet globalErrorHandlerInstance: GlobalErrorHandler | null = null;\n\nexport function getGlobalErrorHandler(): GlobalErrorHandler {\n if (!globalErrorHandlerInstance) {\n globalErrorHandlerInstance = new GlobalErrorHandler();\n }\n return globalErrorHandlerInstance;\n}\n\n/**\n * Initialize global error handling\n */\nexport function initializeGlobalErrorHandling(options?: GlobalErrorHandlerOptions): GlobalErrorHandler {\n const handler = new GlobalErrorHandler(options);\n handler.initialize();\n globalErrorHandlerInstance = handler;\n return handler;\n}\n\n/**\n * React hook for manual error reporting\n */\nexport function useGlobalErrorHandler() {\n const handler = getGlobalErrorHandler();\n \n return {\n report: (error: Error | ApiError, context?: Record<string, unknown>) => handler.report(error, context),\n getHistory: () => handler.getErrorHistory(),\n getStats: () => handler.getStats(),\n clearHistory: () => handler.clearHistory(),\n };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/logging/ConsoleErrorReporter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/logging/ConsoleLogger.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":44,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":44,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1362,1365],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1362,1365],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":76,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":76,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2701,2704],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2701,2704],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Logger } from '../../interfaces/Logger';\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport class ConsoleLogger implements Logger {\n private readonly COLORS: Record<LogLevel, string> = {\n debug: '#888888',\n info: '#00aaff',\n warn: '#ffaa00',\n error: '#ff4444',\n };\n\n private readonly EMOJIS: Record<LogLevel, string> = {\n debug: '🐛',\n info: 'ℹ️',\n warn: '⚠️',\n error: '❌',\n };\n\n private readonly PREFIXES: Record<LogLevel, string> = {\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n };\n\n private shouldLog(level: LogLevel): boolean {\n if (process.env.NODE_ENV === 'test') return level === 'error';\n if (process.env.NODE_ENV === 'production') return level !== 'debug';\n return true;\n }\n\n private formatOutput(level: LogLevel, source: string, message: string, context?: unknown, error?: Error): void {\n const color = this.COLORS[level];\n const emoji = this.EMOJIS[level];\n const prefix = this.PREFIXES[level];\n \n // Edge runtime doesn't support console.groupCollapsed/groupEnd\n // Fallback to simple logging for compatibility\n const supportsGrouping = typeof console.groupCollapsed === 'function' && typeof console.groupEnd === 'function';\n \n if (supportsGrouping) {\n // Safe to call - we've verified both functions exist\n (console as any).groupCollapsed(`%c${emoji} [${source.toUpperCase()}] ${prefix}: ${message}`, `color: ${color}; font-weight: bold;`);\n } else {\n // Simple format for edge runtime\n console.log(`${emoji} [${source.toUpperCase()}] ${prefix}: ${message}`);\n }\n \n console.log(`%cTimestamp:`, 'color: #666; font-weight: bold;', new Date().toISOString());\n console.log(`%cSource:`, 'color: #666; font-weight: bold;', source);\n \n if (context) {\n console.log(`%cContext:`, 'color: #666; font-weight: bold;');\n // console.dir may not be available in edge runtime\n if (typeof console.dir === 'function') {\n console.dir(context, { depth: 3, colors: true });\n } else {\n console.log(JSON.stringify(context, null, 2));\n }\n }\n \n if (error) {\n console.log(`%cError Details:`, 'color: #666; font-weight: bold;');\n console.log(`%cType:`, 'color: #ff4444; font-weight: bold;', error.name);\n console.log(`%cMessage:`, 'color: #ff4444; font-weight: bold;', error.message);\n \n if (process.env.NODE_ENV === 'development' && error.stack) {\n console.log(`%cStack Trace:`, 'color: #666; font-weight: bold;');\n console.log(error.stack);\n }\n }\n \n if (supportsGrouping) {\n // Safe to call - we've verified the function exists\n (console as any).groupEnd();\n }\n }\n\n debug(message: string, context?: unknown): void {\n if (!this.shouldLog('debug')) return;\n this.formatOutput('debug', 'website', message, context);\n }\n\n info(message: string, context?: unknown): void {\n if (!this.shouldLog('info')) return;\n this.formatOutput('info', 'website', message, context);\n }\n\n warn(message: string, context?: unknown): void {\n if (!this.shouldLog('warn')) return;\n this.formatOutput('warn', 'website', message, context);\n }\n\n error(message: string, error?: Error, context?: unknown): void {\n if (!this.shouldLog('error')) return;\n this.formatOutput('error', 'website', message, context, error);\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/infrastructure/logging/logger.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/interfaces/ErrorReporter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/interfaces/Logger.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/leagueCovers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/leagueMembership.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/leagueRoles.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/admin/DeleteUserMutation.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'input' is defined but never used.","line":18,"column":17,"nodeType":"Identifier","messageId":"unusedVar","endLine":18,"endColumn":42}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { AdminService } from '@/lib/services/admin/AdminService';\nimport { Result } from '@/lib/contracts/Result';\nimport { MutationError, mapToMutationError } from '@/lib/contracts/mutations/MutationError';\nimport { Mutation } from '@/lib/contracts/mutations/Mutation';\n\n/**\n * DeleteUserMutation\n *\n * Framework-agnostic mutation for deleting users.\n * Called from Server Actions.\n *\n * Input: { userId: string }\n * Output: Result<void, MutationError>\n *\n * Pattern: Server Action → Mutation → Service → API Client\n */\nexport class DeleteUserMutation implements Mutation<{ userId: string }, void, MutationError> {\n async execute(input: { userId: string }): Promise<Result<void, MutationError>> {\n try {\n // Manual construction: Service creates its own dependencies\n const service = new AdminService();\n \n const result = await service.deleteUser();\n \n if (result.isErr()) {\n return Result.err(mapToMutationError(result.getError()));\n }\n \n return Result.ok(undefined);\n } catch (err) {\n return Result.err('deleteFailed');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/admin/UpdateUserStatusMutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/ForgotPasswordMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":15,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":15,"endColumn":36},{"ruleId":"gridpilot-rules/mutation-must-use-builders","severity":2,"message":"Mutations must use ViewDataBuilder to transform DTOs or return simple types - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":16,"column":3,"nodeType":"MethodDefinition","messageId":"mustUseBuilder","endLine":28,"endColumn":4},{"ruleId":"gridpilot-rules/mutation-must-map-errors","severity":2,"message":"Mutations must map service errors via mapToMutationError(result.getError()) before returning Result.err(...) - see apps/website/lib/contracts/mutations/Mutation.ts","line":21,"column":9,"nodeType":"ReturnStatement","messageId":"mustMapMutationError","endLine":21,"endColumn":54},{"ruleId":"gridpilot-rules/mutation-must-use-builders","severity":2,"message":"Mutations must not return DTOs directly, use builders to create ViewData or return simple types like void, string, or primitive values","line":23,"column":7,"nodeType":"ReturnStatement","messageId":"noDirectDtoReturn","endLine":23,"endColumn":41},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":24,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":24,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[874,877],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[874,877],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Forgot Password Mutation\n *\n * Framework-agnostic mutation for forgot password operations.\n * Called from Server Actions.\n *\n * Pattern: Server Action → Mutation → Service → API Client\n */\n\nimport { Result } from '@/lib/contracts/Result';\nimport { AuthService } from '@/lib/services/auth/AuthService';\nimport { ForgotPasswordDTO } from '@/lib/types/generated/ForgotPasswordDTO';\nimport { ForgotPasswordResult } from '@/lib/mutations/auth/types/ForgotPasswordResult';\n\nexport class ForgotPasswordMutation {\n async execute(params: ForgotPasswordDTO): Promise<Result<ForgotPasswordResult, string>> {\n try {\n const authService = new AuthService();\n const result = await authService.forgotPassword(params);\n if (result.isErr()) {\n return Result.err(result.getError().message);\n }\n return Result.ok(result.unwrap());\n } catch (error: any) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to send reset link';\n return Result.err(errorMessage);\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/LoginMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":15,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":15,"endColumn":27},{"ruleId":"gridpilot-rules/mutation-must-map-errors","severity":2,"message":"Mutations must map service errors via mapToMutationError(result.getError()) before returning Result.err(...) - see apps/website/lib/contracts/mutations/Mutation.ts","line":21,"column":9,"nodeType":"ReturnStatement","messageId":"mustMapMutationError","endLine":21,"endColumn":54},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":24,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":24,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[833,836],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[833,836],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Login Mutation\n *\n * Framework-agnostic mutation for login operations.\n * Called from Server Actions.\n *\n * Pattern: Server Action → Mutation → Service → API Client\n */\n\nimport { Result } from '@/lib/contracts/Result';\nimport { AuthService } from '@/lib/services/auth/AuthService';\nimport { SessionViewModel } from '@/lib/view-models/SessionViewModel';\nimport { LoginParamsDTO } from '@/lib/types/generated/LoginParamsDTO';\n\nexport class LoginMutation {\n async execute(params: LoginParamsDTO): Promise<Result<SessionViewModel, string>> {\n try {\n const authService = new AuthService();\n const result = await authService.login(params);\n if (result.isErr()) {\n return Result.err(result.getError().message);\n }\n return Result.ok(new SessionViewModel(result.unwrap().user));\n } catch (error: any) {\n const errorMessage = error instanceof Error ? error.message : 'Login failed';\n return Result.err(errorMessage);\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/LogoutMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":13,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":13,"endColumn":28}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Logout Mutation\n *\n * Framework-agnostic mutation for logout operations.\n * Called from Server Actions.\n *\n * Pattern: Server Action → Mutation → Service → API Client\n */\n\nimport { Result } from '@/lib/contracts/Result';\nimport { AuthService } from '@/lib/services/auth/AuthService';\n\nexport class LogoutMutation {\n async execute(): Promise<Result<void, string>> {\n try {\n const authService = new AuthService();\n await authService.logout();\n return Result.ok(undefined);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Logout failed';\n return Result.err(errorMessage);\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/ResetPasswordMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":15,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":15,"endColumn":35},{"ruleId":"gridpilot-rules/mutation-must-use-builders","severity":2,"message":"Mutations must use ViewDataBuilder to transform DTOs or return simple types - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":16,"column":3,"nodeType":"MethodDefinition","messageId":"mustUseBuilder","endLine":28,"endColumn":4},{"ruleId":"gridpilot-rules/mutation-must-map-errors","severity":2,"message":"Mutations must map service errors via mapToMutationError(result.getError()) before returning Result.err(...) - see apps/website/lib/contracts/mutations/Mutation.ts","line":21,"column":9,"nodeType":"ReturnStatement","messageId":"mustMapMutationError","endLine":21,"endColumn":54},{"ruleId":"gridpilot-rules/mutation-must-use-builders","severity":2,"message":"Mutations must not return DTOs directly, use builders to create ViewData or return simple types like void, string, or primitive values","line":23,"column":7,"nodeType":"ReturnStatement","messageId":"noDirectDtoReturn","endLine":23,"endColumn":41},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":24,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":24,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[864,867],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[864,867],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Reset Password Mutation\n *\n * Framework-agnostic mutation for reset password operations.\n * Called from Server Actions.\n *\n * Pattern: Server Action → Mutation → Service → API Client\n */\n\nimport { Result } from '@/lib/contracts/Result';\nimport { AuthService } from '@/lib/services/auth/AuthService';\nimport { ResetPasswordDTO } from '@/lib/types/generated/ResetPasswordDTO';\nimport { ResetPasswordResult } from '@/lib/mutations/auth/types/ResetPasswordResult';\n\nexport class ResetPasswordMutation {\n async execute(params: ResetPasswordDTO): Promise<Result<ResetPasswordResult, string>> {\n try {\n const authService = new AuthService();\n const result = await authService.resetPassword(params);\n if (result.isErr()) {\n return Result.err(result.getError().message);\n }\n return Result.ok(result.unwrap());\n } catch (error: any) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to reset password';\n return Result.err(errorMessage);\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/SignupMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":15,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":15,"endColumn":28},{"ruleId":"gridpilot-rules/mutation-must-map-errors","severity":2,"message":"Mutations must map service errors via mapToMutationError(result.getError()) before returning Result.err(...) - see apps/website/lib/contracts/mutations/Mutation.ts","line":21,"column":9,"nodeType":"ReturnStatement","messageId":"mustMapMutationError","endLine":21,"endColumn":54},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":24,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":24,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[840,843],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[840,843],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Signup Mutation\n *\n * Framework-agnostic mutation for signup operations.\n * Called from Server Actions.\n *\n * Pattern: Server Action → Mutation → Service → API Client\n */\n\nimport { Result } from '@/lib/contracts/Result';\nimport { AuthService } from '@/lib/services/auth/AuthService';\nimport { SessionViewModel } from '@/lib/view-models/SessionViewModel';\nimport { SignupParamsDTO } from '@/lib/types/generated/SignupParamsDTO';\n\nexport class SignupMutation {\n async execute(params: SignupParamsDTO): Promise<Result<SessionViewModel, string>> {\n try {\n const authService = new AuthService();\n const result = await authService.signup(params);\n if (result.isErr()) {\n return Result.err(result.getError().message);\n }\n return Result.ok(new SessionViewModel(result.unwrap().user));\n } catch (error: any) {\n const errorMessage = error instanceof Error ? error.message : 'Signup failed';\n return Result.err(errorMessage);\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/types/ForgotPasswordResult.ts","messages":[{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":8,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":11,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Forgot Password Mutation Result\n *\n * Result type for forgot password operations.\n * This represents the successful outcome of a forgot password mutation.\n */\n\nexport interface ForgotPasswordResult {\n message: string;\n magicLink?: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/auth/types/ResetPasswordResult.ts","messages":[{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":8,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":10,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Reset Password Mutation Result\n *\n * Result type for reset password operations.\n * This represents the successful outcome of a reset password mutation.\n */\n\nexport interface ResetPasswordResult {\n message: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/drivers/UpdateDriverProfileMutation.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_error' is defined but never used.","line":13,"column":29,"nodeType":"Identifier","messageId":"unusedVar","endLine":13,"endColumn":48}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport type { Mutation } from '@/lib/contracts/mutations/Mutation';\nimport type { DomainError } from '@/lib/contracts/services/Service';\nimport { DriverProfileUpdateService } from '@/lib/services/drivers/DriverProfileUpdateService';\n\nexport interface UpdateDriverProfileCommand {\n bio?: string;\n country?: string;\n}\n\ntype UpdateDriverProfileMutationError = 'DRIVER_PROFILE_UPDATE_FAILED';\n\nconst mapToMutationError = (_error: DomainError): UpdateDriverProfileMutationError => {\n return 'DRIVER_PROFILE_UPDATE_FAILED';\n};\n\nexport class UpdateDriverProfileMutation\n implements Mutation<UpdateDriverProfileCommand, void, UpdateDriverProfileMutationError>\n{\n async execute(\n command: UpdateDriverProfileCommand,\n ): Promise<Result<void, UpdateDriverProfileMutationError>> {\n const service = new DriverProfileUpdateService();\n const result = await service.updateProfile({ bio: command.bio, country: command.country });\n\n if (result.isErr()) {\n return Result.err(mapToMutationError(result.getError()));\n }\n\n return Result.ok(undefined);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/leagues/CreateLeagueMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":12,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":12,"endColumn":34},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":26,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":26,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[859,862],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[859,862],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport type { CreateLeagueInputDTO } from '@/lib/types/generated/CreateLeagueInputDTO';\nimport { DomainError } from '@/lib/contracts/services/Service';\n\n/**\n * CreateLeagueMutation\n * \n * Framework-agnostic mutation for creating leagues.\n * Can be called from Server Actions or other contexts.\n */\nexport class CreateLeagueMutation {\n private service: LeagueService;\n\n constructor() {\n this.service = new LeagueService();\n }\n\n async execute(input: CreateLeagueInputDTO): Promise<Result<string, DomainError>> {\n try {\n const result = await this.service.createLeague(input);\n if (result.isErr()) {\n return Result.err(result.getError());\n }\n return Result.ok(result.unwrap().leagueId);\n } catch (error: any) {\n console.error('CreateLeagueMutation failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to create league' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/leagues/ProtestReviewMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":13,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":13,"endColumn":35},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":23,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":23,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[854,857],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[854,857],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":32,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":32,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1213,1216],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1213,1216],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":40,"column":56,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":40,"endColumn":59,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1605,1608],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1605,1608],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":41,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":41,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1631,1634],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1631,1634],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { ProtestService } from '@/lib/services/protests/ProtestService';\nimport type { ApplyPenaltyCommandDTO } from '@/lib/types/generated/ApplyPenaltyCommandDTO';\nimport type { RequestProtestDefenseCommandDTO } from '@/lib/types/generated/RequestProtestDefenseCommandDTO';\nimport { DomainError } from '@/lib/contracts/services/Service';\n\n/**\n * ProtestReviewMutation\n * \n * Framework-agnostic mutation for protest review operations.\n * Can be called from Server Actions or other contexts.\n */\nexport class ProtestReviewMutation {\n private service: ProtestService;\n\n constructor() {\n this.service = new ProtestService();\n }\n\n async applyPenalty(input: ApplyPenaltyCommandDTO): Promise<Result<void, DomainError>> {\n try {\n return await this.service.applyPenalty(input);\n } catch (error: any) {\n console.error('applyPenalty failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to apply penalty' });\n }\n }\n\n async requestDefense(input: RequestProtestDefenseCommandDTO): Promise<Result<void, DomainError>> {\n try {\n return await this.service.requestDefense(input);\n } catch (error: any) {\n console.error('requestDefense failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to request defense' });\n }\n }\n\n async reviewProtest(input: { protestId: string; stewardId: string; decision: string; decisionNotes: string }): Promise<Result<void, DomainError>> {\n try {\n return await this.service.reviewProtest(input as any);\n } catch (error: any) {\n console.error('reviewProtest failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to review protest' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/leagues/RosterAdminMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":14,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":14,"endColumn":33},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":19,"column":21,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":19,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'apiClient' is assigned a value but never used.","line":22,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":22,"endColumn":20},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":22,"column":23,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":22,"endColumn":75}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport type { MembershipRole } from '@/lib/types/MembershipRole';\n\n/**\n * RosterAdminMutation\n * \n * Framework-agnostic mutation for roster administration operations.\n * Can be called from Server Actions or other contexts.\n */\nexport class RosterAdminMutation {\n private service: LeagueService;\n\n constructor() {\n // Manual wiring for serverless\n const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n \n this.service = new LeagueService();\n }\n\n async approveJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<void, string>> {\n try {\n await this.service.approveJoinRequest(leagueId, joinRequestId);\n return Result.ok(undefined);\n } catch (error) {\n console.error('approveJoinRequest failed:', error);\n return Result.err('Failed to approve join request');\n }\n }\n\n async rejectJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<void, string>> {\n try {\n await this.service.rejectJoinRequest(leagueId, joinRequestId);\n return Result.ok(undefined);\n } catch (error) {\n console.error('rejectJoinRequest failed:', error);\n return Result.err('Failed to reject join request');\n }\n }\n\n async updateMemberRole(leagueId: string, driverId: string, role: MembershipRole): Promise<Result<void, string>> {\n try {\n await this.service.updateMemberRole(leagueId, driverId, role);\n return Result.ok(undefined);\n } catch (error) {\n console.error('updateMemberRole failed:', error);\n return Result.err('Failed to update member role');\n }\n }\n\n async removeMember(leagueId: string, driverId: string): Promise<Result<void, string>> {\n try {\n await this.service.removeMember(leagueId, driverId);\n return Result.ok(undefined);\n } catch (error) {\n console.error('removeMember failed:', error);\n return Result.err('Failed to remove member');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/leagues/ScheduleAdminMutation.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'CreateLeagueScheduleRaceInputDTO' is defined but never used.","line":6,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":47},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'UpdateLeagueScheduleRaceInputDTO' is defined but never used.","line":7,"column":15,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":47},{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":15,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":15,"endColumn":35},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":20,"column":21,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":20,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'apiClient' is assigned a value but never used.","line":23,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":23,"endColumn":20},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":23,"column":23,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":23,"endColumn":75}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport type { CreateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceInputDTO';\nimport type { UpdateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/UpdateLeagueScheduleRaceInputDTO';\n\n/**\n * ScheduleAdminMutation\n * \n * Framework-agnostic mutation for schedule administration operations.\n * Can be called from Server Actions or other contexts.\n */\nexport class ScheduleAdminMutation {\n private service: LeagueService;\n\n constructor() {\n // Manual wiring for serverless\n const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n \n this.service = new LeagueService();\n }\n\n async publishSchedule(leagueId: string, seasonId: string): Promise<Result<void, string>> {\n try {\n await this.service.publishAdminSchedule(leagueId, seasonId);\n return Result.ok(undefined);\n } catch (error) {\n console.error('publishSchedule failed:', error);\n return Result.err('Failed to publish schedule');\n }\n }\n\n async unpublishSchedule(leagueId: string, seasonId: string): Promise<Result<void, string>> {\n try {\n await this.service.unpublishAdminSchedule(leagueId, seasonId);\n return Result.ok(undefined);\n } catch (error) {\n console.error('unpublishSchedule failed:', error);\n return Result.err('Failed to unpublish schedule');\n }\n }\n\n async createRace(leagueId: string, seasonId: string, input: { track: string; car: string; scheduledAtIso: string }): Promise<Result<void, string>> {\n try {\n await this.service.createAdminScheduleRace(leagueId, seasonId, input);\n return Result.ok(undefined);\n } catch (error) {\n console.error('createRace failed:', error);\n return Result.err('Failed to create race');\n }\n }\n\n async updateRace(leagueId: string, seasonId: string, raceId: string, input: Partial<{ track: string; car: string; scheduledAtIso: string }>): Promise<Result<void, string>> {\n try {\n await this.service.updateAdminScheduleRace(leagueId, seasonId, raceId, input);\n return Result.ok(undefined);\n } catch (error) {\n console.error('updateRace failed:', error);\n return Result.err('Failed to update race');\n }\n }\n\n async deleteRace(leagueId: string, seasonId: string, raceId: string): Promise<Result<void, string>> {\n try {\n await this.service.deleteAdminScheduleRace(leagueId, seasonId, raceId);\n return Result.ok(undefined);\n } catch (error) {\n console.error('deleteRace failed:', error);\n return Result.err('Failed to delete race');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/leagues/StewardingMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":13,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":13,"endColumn":32},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":18,"column":21,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":18,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'apiClient' is assigned a value but never used.","line":21,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":21,"endColumn":20},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":21,"column":23,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":21,"endColumn":75}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\n\n/**\n * StewardingMutation\n * \n * Framework-agnostic mutation for stewarding operations.\n * Can be called from Server Actions or other contexts.\n */\nexport class StewardingMutation {\n private service: LeagueService;\n\n constructor() {\n // Manual wiring for serverless\n const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n \n this.service = new LeagueService();\n }\n\n async applyPenalty(input: {\n protestId: string;\n penaltyType: string;\n penaltyValue: number;\n stewardNotes: string;\n raceId: string;\n accusedDriverId: string;\n reason: string;\n }): Promise<Result<void, string>> {\n try {\n // TODO: Implement when penalty API is available\n // For now, return success\n console.log('applyPenalty called with:', input);\n return Result.ok(undefined);\n } catch (error) {\n console.error('applyPenalty failed:', error);\n return Result.err('Failed to apply penalty');\n }\n }\n\n async requestDefense(input: {\n protestId: string;\n stewardId: string;\n }): Promise<Result<void, string>> {\n try {\n // TODO: Implement when defense API is available\n // For now, return success\n console.log('requestDefense called with:', input);\n return Result.ok(undefined);\n } catch (error) {\n console.error('requestDefense failed:', error);\n return Result.err('Failed to request defense');\n }\n }\n\n async quickPenalty(input: {\n leagueId: string;\n driverId: string;\n raceId: string;\n penaltyType: string;\n penaltyValue: number;\n reason: string;\n adminId: string;\n }): Promise<Result<void, string>> {\n try {\n // TODO: Implement when quick penalty API is available\n // For now, return success\n console.log('quickPenalty called with:', input);\n return Result.ok(undefined);\n } catch (error) {\n console.error('quickPenalty failed:', error);\n return Result.err('Failed to apply quick penalty');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/leagues/WalletMutation.ts","messages":[{"ruleId":"gridpilot-rules/mutation-contract","severity":2,"message":"Mutation classes must implement Mutation<TInput, TOutput, TError> - see apps/website/lib/contracts/mutations/Mutation.ts","line":13,"column":14,"nodeType":"Identifier","messageId":"mustImplementMutationInterface","endLine":13,"endColumn":28},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":18,"column":21,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":18,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'apiClient' is assigned a value but never used.","line":21,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":21,"endColumn":20},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":21,"column":23,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":21,"endColumn":75}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\n\n/**\n * WalletMutation\n * \n * Framework-agnostic mutation for wallet operations.\n * Can be called from Server Actions or other contexts.\n */\nexport class WalletMutation {\n private service: LeagueService;\n\n constructor() {\n // Manual wiring for serverless\n const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n \n this.service = new LeagueService();\n }\n\n async withdraw(leagueId: string, amount: number): Promise<Result<void, string>> {\n try {\n // TODO: Implement when wallet withdrawal API is available\n // For now, return success\n console.log('withdraw called with:', { leagueId, amount });\n return Result.ok(undefined);\n } catch (error) {\n console.error('withdraw failed:', error);\n return Result.err('Failed to withdraw funds');\n }\n }\n\n async exportTransactions(leagueId: string): Promise<Result<void, string>> {\n try {\n // TODO: Implement when export API is available\n // For now, return success\n console.log('exportTransactions called with:', { leagueId });\n return Result.ok(undefined);\n } catch (error) {\n console.error('exportTransactions failed:', error);\n return Result.err('Failed to export transactions');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/onboarding/CompleteOnboardingMutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/onboarding/GenerateAvatarsMutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/sponsors/AcceptSponsorshipRequestMutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/mutations/sponsors/RejectSponsorshipRequestMutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/AdminDashboardPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/AdminUsersPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/CreateLeaguePageQuery.ts","messages":[{"ruleId":"gridpilot-rules/page-query-must-use-builders","severity":2,"message":"PageQueries must use ViewDataBuilder to transform DTOs - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":1,"column":1,"nodeType":"Program","messageId":"mustUseBuilder","endLine":50,"endColumn":2},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":1,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":50,"endColumn":2},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":57,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":60,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[499,502],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[499,502],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":35,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":38,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[546,549],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[546,549],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":15,"column":21,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":15,"endColumn":52},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":18,"column":23,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":18,"endColumn":75},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":46,"column":42,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":46,"endColumn":45,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1718,1721],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1718,1721],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { Result } from '@/lib/contracts/Result';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\n\n/**\n * CreateLeaguePageQuery\n * \n * Fetches data needed for the create league page.\n */\nexport class CreateLeaguePageQuery implements PageQuery<any, void> {\n async execute(): Promise<Result<any, 'notFound' | 'redirect' | 'CREATE_LEAGUE_FETCH_FAILED' | 'UNKNOWN_ERROR'>> {\n // Manual wiring: create API client\n const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n \n try {\n // Get scoring presets for the form\n const presetsData = await apiClient.getScoringPresets();\n \n return Result.ok({\n scoringPresets: presetsData.presets || [],\n });\n } catch (error) {\n console.error('CreateLeaguePageQuery failed:', error);\n \n if (error instanceof Error) {\n if (error.message.includes('403') || error.message.includes('401')) {\n return Result.err('redirect');\n }\n if (error.message.includes('404')) {\n return Result.err('notFound');\n }\n if (error.message.includes('5') || error.message.includes('server')) {\n return Result.err('CREATE_LEAGUE_FETCH_FAILED');\n }\n }\n \n return Result.err('UNKNOWN_ERROR');\n }\n }\n\n static async execute(): Promise<Result<any, 'notFound' | 'redirect' | 'CREATE_LEAGUE_FETCH_FAILED' | 'UNKNOWN_ERROR'>> {\n const query = new CreateLeaguePageQuery();\n return query.execute();\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/DashboardPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/DriverProfilePageQuery.ts","messages":[{"ruleId":"gridpilot-rules/page-query-contract","severity":2,"message":"PageQuery class must implement PageQuery<TPageDto, TParams> interface - see apps/website/lib/contracts/page-queries/PageQuery.ts","line":13,"column":8,"nodeType":"ClassDeclaration","messageId":"message","endLine":55,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { DriverProfilePageService } from '@/lib/services/drivers/DriverProfilePageService';\nimport { DriverProfileViewDataBuilder } from '@/lib/builders/view-data/DriverProfileViewDataBuilder';\nimport type { DriverProfileViewData } from '@/lib/types/view-data/DriverProfileViewData';\n\n/**\n * DriverProfilePageQuery\n *\n * Server-side data fetcher for the driver profile page.\n * Returns Result<ViewData, PresentationError>\n * Uses Service for data access and ViewDataBuilder for transformation.\n */\nexport class DriverProfilePageQuery {\n /**\n * Execute the driver profile page query\n *\n * @param driverId - The driver ID to fetch profile for\n * @returns Result with ViewData or error\n */\n static async execute(driverId: string | null): Promise<Result<DriverProfileViewData, string>> {\n if (!driverId) {\n return Result.err('NotFound');\n }\n\n try {\n // Manual wiring: construct dependencies explicitly\n const service = new DriverProfilePageService();\n\n const result = await service.getDriverProfile(driverId);\n\n if (result.isErr()) {\n const error = result.getError();\n\n if (error === 'notFound') {\n return Result.err('NotFound');\n }\n\n if (error === 'unauthorized') {\n return Result.err('Unauthorized');\n }\n\n return Result.err('Error');\n }\n\n // Build ViewData from DTO\n const dto = result.unwrap();\n const viewData = DriverProfileViewDataBuilder.build(dto);\n return Result.ok(viewData);\n\n } catch (error) {\n console.error('DriverProfilePageQuery failed:', error);\n return Result.err('Error');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/DriverRankingsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/DriversPageQuery.ts","messages":[{"ruleId":"gridpilot-rules/page-query-contract","severity":2,"message":"PageQuery class must implement PageQuery<TPageDto, TParams> interface - see apps/website/lib/contracts/page-queries/PageQuery.ts","line":13,"column":8,"nodeType":"ClassDeclaration","messageId":"message","endLine":46,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { DriversPageService } from '@/lib/services/drivers/DriversPageService';\nimport { DriversViewDataBuilder } from '@/lib/builders/view-data/DriversViewDataBuilder';\nimport type { DriversViewData } from '@/lib/types/view-data/DriversViewData';\n\n/**\n * DriversPageQuery\n *\n * Server-side data fetcher for the drivers listing page.\n * Returns Result<ViewData, PresentationError>\n * Uses Service for data access and ViewDataBuilder for transformation.\n */\nexport class DriversPageQuery {\n /**\n * Execute the drivers page query\n *\n * @returns Result with ViewData or error\n */\n static async execute(): Promise<Result<DriversViewData, string>> {\n try {\n // Manual wiring: construct dependencies explicitly\n const service = new DriversPageService();\n\n const result = await service.getLeaderboard();\n\n if (result.isErr()) {\n const error = result.getError();\n\n if (error === 'notFound') {\n return Result.err('NotFound');\n }\n\n return Result.err('Error');\n }\n\n // Build ViewData from DTO\n const dto = result.unwrap();\n const viewData = DriversViewDataBuilder.build(dto);\n return Result.ok(viewData);\n\n } catch (error) {\n console.error('DriversPageQuery failed:', error);\n return Result.err('Error');\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeaderboardsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueDetailPageQuery.ts","messages":[{"ruleId":"gridpilot-rules/page-query-must-use-builders","severity":2,"message":"PageQueries must use ViewDataBuilder to transform DTOs - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":1,"column":1,"nodeType":"Program","messageId":"mustUseBuilder","endLine":29,"endColumn":1},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":57,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":60,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[508,511],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[508,511],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":51,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":54,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[592,595],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[592,595],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":24,"column":58,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":24,"endColumn":61,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[990,993],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[990,993],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';\n\n/**\n * LeagueDetail page query\n * Returns the raw API DTO for the league detail page\n * No DI container usage - constructs dependencies explicitly\n */\nexport class LeagueDetailPageQuery implements PageQuery<any, string, PresentationError> {\n async execute(leagueId: string): Promise<Result<any, PresentationError>> {\n const service = new LeagueService();\n const result = await service.getLeagueDetailData(leagueId);\n\n if (result.isErr()) {\n return Result.err(mapToPresentationError(result.getError()));\n }\n\n return Result.ok(result.unwrap());\n }\n\n // Static method to avoid object construction in server code\n static async execute(leagueId: string): Promise<Result<any, PresentationError>> {\n const query = new LeagueDetailPageQuery();\n return query.execute(leagueId);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueProtestDetailPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueProtestReviewPageQuery.ts","messages":[{"ruleId":"gridpilot-rules/page-query-must-use-builders","severity":2,"message":"PageQueries must use ViewDataBuilder to transform DTOs - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":1,"column":1,"nodeType":"Program","messageId":"mustUseBuilder","endLine":77,"endColumn":2},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":1,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":77,"endColumn":2},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":64,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":67,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[579,582],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[579,582],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":14,"column":81,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":14,"endColumn":84,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[707,710],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[707,710],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":16,"column":21,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":16,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'leaguesApiClient' is assigned a value but never used.","line":19,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":19,"endColumn":27},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":19,"column":30,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":19,"endColumn":82},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'protestsApiClient' is assigned a value but never used.","line":20,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":20,"endColumn":28},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":20,"column":31,"nodeType":"NewExpression","messageId":"mustUseServices","endLine":20,"endColumn":84},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":73,"column":88,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":73,"endColumn":91,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2762,2765],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2762,2765],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":10,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { Result } from '@/lib/contracts/Result';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ProtestsApiClient } from '@/lib/api/protests/ProtestsApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\n\n/**\n * LeagueProtestReviewPageQuery\n * \n * Fetches protest detail data for review.\n */\nexport class LeagueProtestReviewPageQuery implements PageQuery<any, { leagueId: string; protestId: string }> {\n async execute(input: { leagueId: string; protestId: string }): Promise<Result<any, 'notFound' | 'redirect' | 'PROTEST_FETCH_FAILED' | 'UNKNOWN_ERROR'>> {\n // Manual wiring: create API clients\n const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n const leaguesApiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n const protestsApiClient = new ProtestsApiClient(baseUrl, errorReporter, logger);\n \n try {\n // Get protest details\n // Note: This would need a getProtestDetail method on ProtestsApiClient\n // For now, return placeholder data\n const protestDetail = {\n protest: {\n id: input.protestId,\n raceId: 'placeholder',\n protestingDriverId: 'placeholder',\n accusedDriverId: 'placeholder',\n description: 'Placeholder protest',\n status: 'pending',\n submittedAt: new Date().toISOString(),\n },\n race: {\n id: 'placeholder',\n name: 'Placeholder Race',\n scheduledAt: new Date().toISOString(),\n },\n protestingDriver: {\n id: 'placeholder',\n name: 'Placeholder Protester',\n },\n accusedDriver: {\n id: 'placeholder',\n name: 'Placeholder Accused',\n },\n penaltyTypes: [],\n defaultReasons: {},\n };\n \n return Result.ok(protestDetail);\n } catch (error) {\n console.error('LeagueProtestReviewPageQuery failed:', error);\n \n if (error instanceof Error) {\n if (error.message.includes('403') || error.message.includes('401')) {\n return Result.err('redirect');\n }\n if (error.message.includes('404')) {\n return Result.err('notFound');\n }\n if (error.message.includes('5') || error.message.includes('server')) {\n return Result.err('PROTEST_FETCH_FAILED');\n }\n }\n \n return Result.err('UNKNOWN_ERROR');\n }\n }\n\n static async execute(input: { leagueId: string; protestId: string }): Promise<Result<any, 'notFound' | 'redirect' | 'PROTEST_FETCH_FAILED' | 'UNKNOWN_ERROR'>> {\n const query = new LeagueProtestReviewPageQuery();\n return query.execute(input);\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueRosterAdminPageQuery.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":62,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":65,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[579,582],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[579,582],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":51,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":54,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[663,666],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[663,666],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":25,"column":58,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":25,"endColumn":61,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1068,1071],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1068,1071],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { LeagueRosterAdminViewDataBuilder } from '@/lib/builders/view-data/LeagueRosterAdminViewDataBuilder';\nimport { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';\n\n/**\n * LeagueRosterAdminPageQuery\n * \n * Fetches league roster admin data (members and join requests).\n */\nexport class LeagueRosterAdminPageQuery implements PageQuery<any, string, PresentationError> {\n async execute(leagueId: string): Promise<Result<any, PresentationError>> {\n const service = new LeagueService();\n const result = await service.getRosterAdminData(leagueId);\n\n if (result.isErr()) {\n return Result.err(mapToPresentationError(result.getError()));\n }\n\n const viewData = LeagueRosterAdminViewDataBuilder.build(result.unwrap());\n return Result.ok(viewData);\n }\n\n static async execute(leagueId: string): Promise<Result<any, PresentationError>> {\n const query = new LeagueRosterAdminPageQuery();\n return query.execute(leagueId);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueRulebookPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueScheduleAdminPageQuery.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":64,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":67,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[551,554],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[551,554],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":81,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":84,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[679,682],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[679,682],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":24,"column":42,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":24,"endColumn":45,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1101,1104],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1101,1104],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":88,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":91,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1404,1407],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1404,1407],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { Result } from '@/lib/contracts/Result';\nimport { LeagueService } from '@/lib/services/leagues/LeagueService';\nimport { LeagueScheduleViewDataBuilder } from '@/lib/builders/view-data/LeagueScheduleViewDataBuilder';\nimport { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';\n\n/**\n * LeagueScheduleAdminPageQuery\n * \n * Fetches league schedule admin data.\n */\nexport class LeagueScheduleAdminPageQuery implements PageQuery<any, { leagueId: string; seasonId?: string }> {\n async execute(input: { leagueId: string; seasonId?: string }): Promise<Result<any, PresentationError>> {\n const service = new LeagueService();\n const result = await service.getScheduleAdminData(input.leagueId, input.seasonId);\n\n if (result.isErr()) {\n return Result.err(mapToPresentationError(result.getError()));\n }\n\n const data = result.unwrap();\n const viewData = LeagueScheduleViewDataBuilder.build({\n leagueId: data.leagueId,\n races: data.schedule.races.map((r: any) => ({\n id: r.id,\n name: r.name,\n date: r.scheduledAt,\n track: r.track,\n car: r.car,\n sessionType: r.sessionType,\n })),\n });\n return Result.ok(viewData);\n }\n\n static async execute(input: { leagueId: string; seasonId?: string }): Promise<Result<any, PresentationError>> {\n const query = new LeagueScheduleAdminPageQuery();\n return query.execute(input);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueSchedulePageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueSettingsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueSponsorshipsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueStandingsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueStewardingPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeagueWalletPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/LeaguesPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/OnboardingPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/ProfileLeaguesPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/ProfilePageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/SponsorDashboardPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/SponsorshipRequestsPageDto.ts","messages":[{"ruleId":"gridpilot-rules/page-query-filename","severity":2,"message":"PageQuery files must end with PageQuery.ts - see apps/website/lib/contracts/page-queries/PageQuery.ts","line":1,"column":1,"nodeType":null,"messageId":"message"},{"ruleId":"gridpilot-rules/page-query-must-use-builders","severity":2,"message":"PageQueries must use ViewDataBuilder to transform DTOs - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":1,"column":1,"nodeType":"Program","messageId":"mustUseBuilder","endLine":16,"endColumn":1},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":1,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":16,"endColumn":1}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export interface SponsorshipRequestsPageDto {\n sections: Array<{\n entityType: 'driver' | 'team' | 'season';\n entityId: string;\n entityName: string;\n requests: Array<{\n requestId: string;\n sponsorId: string;\n sponsorName: string;\n message: string | null;\n createdAtIso: string;\n raw: unknown;\n }>;\n }>;\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/SponsorshipRequestsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/TeamDetailPageQuery.ts","messages":[{"ruleId":"gridpilot-rules/single-export-per-file","severity":2,"message":"File should have exactly one export. Found 2 exports: TeamDetailPageDto, TeamDetailPageQuery","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":120,"endColumn":1}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { Result } from '@/lib/contracts/Result';\nimport { TeamService } from '@/lib/services/teams/TeamService';\nimport { TeamDetailViewDataBuilder } from '@/lib/builders/view-data/TeamDetailViewDataBuilder';\nimport type { TeamDetailViewData } from '@/lib/view-data/TeamDetailViewData';\nimport { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';\nimport { SessionGateway } from '@/lib/gateways/SessionGateway';\nimport type { TeamMemberViewModel } from '@/lib/view-models/TeamMemberViewModel';\n\n/**\n * TeamDetailPageDto - Raw serializable data for team detail page\n * Contains only raw data, no derived/computed properties\n */\nexport interface TeamDetailPageDto {\n team: {\n id: string;\n name: string;\n tag: string;\n description?: string;\n ownerId: string;\n leagues: string[];\n createdAt?: string;\n specialization?: string;\n region?: string;\n languages?: string[];\n category?: string;\n membership?: {\n role: string;\n joinedAt: string;\n isActive: boolean;\n } | null;\n canManage: boolean;\n };\n memberships: Array<{\n driverId: string;\n driverName: string;\n role: 'owner' | 'manager' | 'member';\n joinedAt: string;\n isActive: boolean;\n avatarUrl: string;\n }>;\n currentDriverId: string;\n}\n\n/**\n * TeamDetailPageQuery - Server-side composition for team detail page\n */\nexport class TeamDetailPageQuery implements PageQuery<TeamDetailViewData, string> {\n async execute(teamId: string): Promise<Result<TeamDetailViewData, PresentationError>> {\n // Get session to determine current driver\n const sessionGateway = new SessionGateway();\n const session = await sessionGateway.getSession();\n \n if (!session?.user?.primaryDriverId) {\n return Result.err('notFound');\n }\n\n const currentDriverId = session.user.primaryDriverId;\n const service = new TeamService();\n \n // Fetch team details\n const teamResult = await service.getTeamDetails(teamId, currentDriverId);\n \n if (teamResult.isErr()) {\n return Result.err(mapToPresentationError(teamResult.getError()));\n }\n\n const teamData = teamResult.unwrap();\n\n // Fetch team members\n const membersResult = await service.getTeamMembers(teamId, currentDriverId, teamData.ownerId);\n \n if (membersResult.isErr()) {\n return Result.err(mapToPresentationError(membersResult.getError()));\n }\n\n const membersData = membersResult.unwrap();\n \n // Transform to raw serializable DTO\n const dto: TeamDetailPageDto = {\n team: {\n id: teamData.id,\n name: teamData.name,\n tag: teamData.tag,\n description: teamData.description,\n ownerId: teamData.ownerId,\n leagues: teamData.leagues,\n createdAt: teamData.createdAt,\n specialization: teamData.specialization,\n region: teamData.region,\n languages: teamData.languages,\n category: teamData.category,\n membership: teamData.membership ? {\n role: teamData.membership.role,\n joinedAt: teamData.membership.joinedAt,\n isActive: teamData.membership.isActive,\n } : null,\n canManage: teamData.canManage,\n },\n memberships: membersData.map((member: TeamMemberViewModel) => ({\n driverId: member.driverId,\n driverName: member.driverName,\n role: member.role,\n joinedAt: member.joinedAt,\n isActive: member.isActive,\n avatarUrl: member.avatarUrl,\n })),\n currentDriverId,\n };\n\n const viewData = TeamDetailViewDataBuilder.build(dto);\n return Result.ok(viewData);\n }\n\n static async execute(teamId: string): Promise<Result<TeamDetailViewData, PresentationError>> {\n const query = new TeamDetailPageQuery();\n return query.execute(teamId);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/TeamsPageQuery.ts","messages":[{"ruleId":"gridpilot-rules/single-export-per-file","severity":2,"message":"File should have exactly one export. Found 2 exports: TeamsPageDto, TeamsPageQuery","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":41,"endColumn":1}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';\nimport { TeamService } from '@/lib/services/teams/TeamService';\nimport type { TeamsViewData } from '@/lib/view-data/TeamsViewData';\nimport { TeamsViewDataBuilder } from '@/lib/builders/view-data/TeamsViewDataBuilder';\nimport type { TeamListItemDTO } from '@/lib/types/generated/TeamListItemDTO';\n\nexport interface TeamsPageDto {\n teams: TeamListItemDTO[];\n}\n\n/**\n * TeamsPageQuery - Server-side composition for teams list page\n * Manual wiring only; no ContainerManager; no PageDataFetcher\n */\nexport class TeamsPageQuery implements PageQuery<TeamsViewData, void> {\n async execute(): Promise<Result<TeamsViewData, PresentationError>> {\n try {\n // Manual dependency creation\n const service = new TeamService();\n \n // Fetch teams\n const result = await service.getAllTeams();\n \n if (result.isErr()) {\n return Result.err(mapToPresentationError(result.getError()));\n }\n\n const teams = result.unwrap();\n \n // Transform to ViewData using builder\n const viewData = TeamsViewDataBuilder.build({ teams });\n\n return Result.ok(viewData);\n } catch (error) {\n return Result.err('unknown');\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/auth/ForgotPasswordPageQuery.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1453,1456],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1453,1456],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { ForgotPasswordViewDataBuilder } from '@/lib/builders/view-data/ForgotPasswordViewDataBuilder';\nimport { ForgotPasswordViewData } from '@/lib/builders/view-data/types/ForgotPasswordViewData';\nimport { AuthPageService } from '@/lib/services/auth/AuthPageService';\nimport { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';\n\nexport class ForgotPasswordPageQuery implements PageQuery<ForgotPasswordViewData, URLSearchParams> {\n async execute(searchParams: URLSearchParams): Promise<Result<ForgotPasswordViewData, string>> {\n // Parse and validate search parameters\n const parsedResult = SearchParamParser.parseAuth(searchParams);\n if (parsedResult.isErr()) {\n return Result.err(`Invalid search parameters: ${parsedResult.getError()}`);\n }\n\n const { returnTo, token } = parsedResult.unwrap();\n\n try {\n // Use service to process parameters\n const authService = new AuthPageService();\n const serviceResult = await authService.processForgotPasswordParams({ returnTo, token });\n \n if (serviceResult.isErr()) {\n return Result.err(serviceResult.getError().message);\n }\n\n // Transform to ViewData using builder\n const viewData = ForgotPasswordViewDataBuilder.build(serviceResult.unwrap());\n return Result.ok(viewData);\n } catch (error: any) {\n return Result.err(error.message || 'Failed to execute forgot password page query');\n }\n }\n\n // Static factory method for convenience\n static async execute(searchParams: URLSearchParams): Promise<Result<ForgotPasswordViewData, string>> {\n const query = new ForgotPasswordPageQuery();\n return query.execute(searchParams);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/auth/LoginPageQuery.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1372,1375],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1372,1375],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { LoginViewDataBuilder } from '@/lib/builders/view-data/LoginViewDataBuilder';\nimport { LoginViewData } from '@/lib/builders/view-data/types/LoginViewData';\nimport { AuthPageService } from '@/lib/services/auth/AuthPageService';\nimport { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';\n\nexport class LoginPageQuery implements PageQuery<LoginViewData, URLSearchParams> {\n async execute(searchParams: URLSearchParams): Promise<Result<LoginViewData, string>> {\n // Parse and validate search parameters\n const parsedResult = SearchParamParser.parseAuth(searchParams);\n if (parsedResult.isErr()) {\n return Result.err(`Invalid search parameters: ${parsedResult.getError()}`);\n }\n\n const { returnTo, token } = parsedResult.unwrap();\n\n try {\n // Use service to process parameters\n const authService = new AuthPageService();\n const serviceResult = await authService.processLoginParams({ returnTo, token });\n \n if (serviceResult.isErr()) {\n return Result.err(serviceResult.getError().message);\n }\n\n // Transform to ViewData using builder\n const viewData = LoginViewDataBuilder.build(serviceResult.unwrap());\n return Result.ok(viewData);\n } catch (error: any) {\n return Result.err(error.message || 'Failed to execute login page query');\n }\n }\n\n // Static factory method for convenience\n static async execute(searchParams: URLSearchParams): Promise<Result<LoginViewData, string>> {\n const query = new LoginPageQuery();\n return query.execute(searchParams);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/auth/ResetPasswordPageQuery.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1444,1447],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1444,1447],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { ResetPasswordViewDataBuilder } from '@/lib/builders/view-data/ResetPasswordViewDataBuilder';\nimport { ResetPasswordViewData } from '@/lib/builders/view-data/types/ResetPasswordViewData';\nimport { AuthPageService } from '@/lib/services/auth/AuthPageService';\nimport { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';\n\nexport class ResetPasswordPageQuery implements PageQuery<ResetPasswordViewData, URLSearchParams> {\n async execute(searchParams: URLSearchParams): Promise<Result<ResetPasswordViewData, string>> {\n // Parse and validate search parameters\n const parsedResult = SearchParamParser.parseAuth(searchParams);\n if (parsedResult.isErr()) {\n return Result.err(`Invalid search parameters: ${parsedResult.getError()}`);\n }\n\n const { returnTo, token } = parsedResult.unwrap();\n\n try {\n // Use service to process parameters\n const authService = new AuthPageService();\n const serviceResult = await authService.processResetPasswordParams({ returnTo, token });\n \n if (serviceResult.isErr()) {\n return Result.err(serviceResult.getError().message);\n }\n\n // Transform to ViewData using builder\n const viewData = ResetPasswordViewDataBuilder.build(serviceResult.unwrap());\n return Result.ok(viewData);\n } catch (error: any) {\n return Result.err(error.message || 'Failed to execute reset password page query');\n }\n }\n\n // Static factory method for convenience\n static async execute(searchParams: URLSearchParams): Promise<Result<ResetPasswordViewData, string>> {\n const query = new ResetPasswordPageQuery();\n return query.execute(searchParams);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/auth/SignupPageQuery.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1381,1384],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1381,1384],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { SignupViewDataBuilder } from '@/lib/builders/view-data/SignupViewDataBuilder';\nimport { SignupViewData } from '@/lib/builders/view-data/types/SignupViewData';\nimport { Result } from '@/lib/contracts/Result';\nimport { PageQuery } from '@/lib/contracts/page-queries/PageQuery';\nimport { AuthPageService } from '@/lib/services/auth/AuthPageService';\nimport { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';\n\nexport class SignupPageQuery implements PageQuery<SignupViewData, URLSearchParams> {\n async execute(searchParams: URLSearchParams): Promise<Result<SignupViewData, string>> {\n // Parse and validate search parameters\n const parsedResult = SearchParamParser.parseAuth(searchParams);\n if (parsedResult.isErr()) {\n return Result.err(`Invalid search parameters: ${parsedResult.getError()}`);\n }\n\n const { returnTo, token } = parsedResult.unwrap();\n\n try {\n // Use service to process parameters\n const authService = new AuthPageService();\n const serviceResult = await authService.processSignupParams({ returnTo, token });\n \n if (serviceResult.isErr()) {\n return Result.err(serviceResult.getError().message);\n }\n\n // Transform to ViewData using builder\n const viewData = SignupViewDataBuilder.build(serviceResult.unwrap());\n return Result.ok(viewData);\n } catch (error: any) {\n return Result.err(error.message || 'Failed to execute signup page query');\n }\n }\n\n // Static factory method for convenience\n static async execute(searchParams: URLSearchParams): Promise<Result<SignupViewData, string>> {\n const query = new SignupPageQuery();\n return query.execute(searchParams);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetAvatarPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetCategoryIconPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetLeagueCoverPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetLeagueLogoPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetSponsorLogoPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetTeamLogoPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/media/GetTrackImagePageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/page-dtos/DriverRankingsPageDto.ts","messages":[{"ruleId":"gridpilot-rules/page-query-filename","severity":2,"message":"PageQuery files must end with PageQuery.ts - see apps/website/lib/contracts/page-queries/PageQuery.ts","line":1,"column":1,"nodeType":null,"messageId":"message"},{"ruleId":"gridpilot-rules/page-query-must-use-builders","severity":2,"message":"PageQueries must use ViewDataBuilder to transform DTOs - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":1,"column":1,"nodeType":"Program","messageId":"mustUseBuilder","endLine":10,"endColumn":2},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":1,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":10,"endColumn":2}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';\n\n/**\n * DriverRankingsPageDto - Raw data structure for Driver Rankings page\n * Plain data, no methods, no business logic\n */\n\nexport interface DriverRankingsPageDto {\n drivers: DriverLeaderboardItemDTO[];\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/page-dtos/LeaderboardsPageDto.ts","messages":[{"ruleId":"gridpilot-rules/page-query-filename","severity":2,"message":"PageQuery files must end with PageQuery.ts - see apps/website/lib/contracts/page-queries/PageQuery.ts","line":1,"column":1,"nodeType":null,"messageId":"message"},{"ruleId":"gridpilot-rules/page-query-must-use-builders","severity":2,"message":"PageQueries must use ViewDataBuilder to transform DTOs - see apps/website/lib/contracts/builders/ViewDataBuilder.ts","line":1,"column":1,"nodeType":"Program","messageId":"mustUseBuilder","endLine":7,"endColumn":2},{"ruleId":"gridpilot-rules/clean-error-handling","severity":2,"message":"PageQueries and Mutations must use Services for data access, not API Clients directly.","line":1,"column":1,"nodeType":"Program","messageId":"mustUseServices","endLine":7,"endColumn":2}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';\nimport type { TeamListItemDTO } from '@/lib/types/generated/TeamListItemDTO';\n\nexport interface LeaderboardsPageDto {\n drivers: { drivers: DriverLeaderboardItemDTO[] };\n teams: { teams: TeamListItemDTO[] };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/races/RaceDetailPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/races/RaceResultsPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/races/RaceStewardingPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/races/RacesAllPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page-queries/races/RacesPageQuery.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page/PageDataFetcher.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":55,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":58,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[842,845],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[842,845],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export interface FetchResult<T> {\n data: T | null;\n errors: Record<string, Error>;\n hasErrors: boolean;\n}\n\nexport class PageDataFetcher {\n /**\n * Fetch using manual service instantiation\n * Use for: Multiple dependencies, request-scoped services, or auth context\n * RECOMMENDED for SSR\n */\n static async fetchManual<TData>(\n serviceFactory: () => Promise<TData> | TData\n ): Promise<TData | null> {\n try {\n const result = await serviceFactory();\n return result;\n } catch (error) {\n console.error('Failed to fetch manual:', error);\n return null;\n }\n }\n\n /**\n * Fetch multiple datasets in parallel with error aggregation\n * Use for: Pages needing multiple service calls\n * UPDATED: Returns both data and errors for proper handling\n */\n static async fetchMultiple<T extends Record<string, any>>(\n queries: T\n ): Promise<FetchResult<{ [K in keyof T]: T[K] }>> {\n const results = {} as { [K in keyof T]: T[K] };\n const errors = {} as Record<string, Error>;\n \n const entries = await Promise.all(\n Object.entries(queries).map(async ([key, query]) => {\n try {\n const result = await query();\n return [key, { success: true, data: result }] as const;\n } catch (error) {\n console.error(`Failed to fetch ${key}:`, error);\n return [key, { success: false, error: error instanceof Error ? error : new Error(String(error)) }] as const;\n }\n })\n );\n\n entries.forEach(([key, result]) => {\n if (typeof result === 'object' && result !== null && 'success' in result) {\n if (result.success) {\n results[key as keyof T] = (result as { data: T[keyof T] }).data;\n } else {\n errors[key] = (result as { error: Error }).error;\n }\n }\n });\n\n return {\n data: results,\n errors,\n hasErrors: Object.keys(errors).length > 0\n };\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/page/usePageData.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'UseQueryOptions' is defined but never used.","line":4,"column":32,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":47},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":28,"column":23,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":28,"endColumn":26,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[766,769],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[766,769],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":58,"column":62,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":58,"endColumn":65,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1539,1542],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1539,1542],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'key' is defined but never used.","line":64,"column":44,"nodeType":"Identifier","messageId":"unusedVar","endLine":64,"endColumn":47},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":65,"column":27,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":65,"endColumn":30,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1733,1736],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1733,1736],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'queryKey' is defined but never used.","line":135,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":135,"endColumn":21},{"ruleId":"import/no-named-as-default-member","severity":2,"message":"Caution: `React` also has a named export `useState`. Check if you meant to write `import {useState} from 'react'` instead.","line":137,"column":39,"nodeType":"MemberExpression","endLine":137,"endColumn":53},{"ruleId":"import/no-named-as-default-member","severity":2,"message":"Caution: `React` also has a named export `useEffect`. Check if you meant to write `import {useEffect} from 'react'` instead.","line":139,"column":3,"nodeType":"MemberExpression","endLine":139,"endColumn":18}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport React from 'react';\nimport { useQuery, useQueries, UseQueryOptions, useMutation, UseMutationOptions } from '@tanstack/react-query';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\nexport interface PageDataConfig<TData, TError = ApiError> {\n queryKey: string[];\n queryFn: () => Promise<TData>;\n enabled?: boolean;\n staleTime?: number;\n onError?: (error: TError) => void;\n}\n\n/**\n * Single query hook - STANDARDIZED PATTERN\n * Use for: Simple CSR pages\n *\n * @example\n * const { data, isLoading, error, refetch } = usePageData({\n * queryKey: ['profile'],\n * queryFn: () => driverService.getProfile(),\n * });\n */\nexport function usePageData<TData, TError = ApiError>(\n config: PageDataConfig<TData, TError>\n) {\n const queryOptions: any = {\n queryKey: config.queryKey,\n queryFn: config.queryFn,\n enabled: config.enabled ?? true,\n staleTime: config.staleTime ?? 1000 * 60 * 5,\n };\n \n if (config.onError) {\n queryOptions.onError = config.onError;\n }\n \n return useQuery<TData, TError>(queryOptions);\n}\n\n/**\n * Multiple queries hook - STANDARDIZED PATTERN\n * Use for: Complex CSR pages with multiple data sources\n *\n * @example\n * const { data, isLoading, error, refetch } = usePageDataMultiple({\n * results: {\n * queryKey: ['raceResults', raceId],\n * queryFn: () => service.getResults(raceId),\n * },\n * sof: {\n * queryKey: ['raceSOF', raceId],\n * queryFn: () => service.getSOF(raceId),\n * },\n * });\n */\nexport function usePageDataMultiple<T extends Record<string, any>>(\n queries: {\n [K in keyof T]: PageDataConfig<T[K]>;\n }\n) {\n const queryResults = useQueries({\n queries: Object.entries(queries).map(([key, config]) => {\n const queryOptions: any = {\n queryKey: config.queryKey,\n queryFn: config.queryFn,\n enabled: config.enabled ?? true,\n staleTime: config.staleTime ?? 1000 * 60 * 5,\n };\n if (config.onError) {\n queryOptions.onError = config.onError;\n }\n return queryOptions;\n }),\n });\n\n // Combine results\n const combined = {} as { [K in keyof T]: T[K] | null };\n const keys = Object.keys(queries) as (keyof T)[];\n \n keys.forEach((key, index) => {\n const result = queryResults[index]?.data;\n if (result !== undefined) {\n combined[key] = result as T[typeof key];\n } else {\n combined[key] = null as T[typeof key] | null;\n }\n });\n\n const isLoading = queryResults.some(q => q.isLoading);\n const error = queryResults.find(q => q.error)?.error ?? null;\n\n return {\n data: combined,\n isLoading,\n error,\n refetch: () => queryResults.forEach(q => q.refetch()),\n };\n}\n\n/**\n * Mutation hook wrapper - STANDARDIZED PATTERN\n * Use for: All mutation operations\n *\n * @example\n * const mutation = usePageMutation(\n * (variables) => service.mutateData(variables),\n * { onSuccess: () => refetch() }\n * );\n */\nexport function usePageMutation<TData, TVariables, TError = ApiError>(\n mutationFn: (variables: TVariables) => Promise<TData>,\n options?: Omit<UseMutationOptions<TData, TError, TVariables>, 'mutationFn'>\n) {\n return useMutation<TData, TError, TVariables>({\n mutationFn,\n ...options,\n });\n}\n\n/**\n * SSR Hydration Hook - NEW\n * Use for: Passing SSR data to CSR to avoid re-fetching\n *\n * @example\n * // In SSR page\n * const ssrData = await PageDataFetcher.fetch(...);\n *\n * // In client component\n * const { data } = useHydrateSSRData(ssrData, ['queryKey']);\n */\nexport function useHydrateSSRData<TData>(\n ssrData: TData | null,\n queryKey: string[]\n): { data: TData | null; isHydrated: boolean } {\n const [isHydrated, setIsHydrated] = React.useState(false);\n \n React.useEffect(() => {\n if (ssrData !== null) {\n setIsHydrated(true);\n }\n }, [ssrData]);\n\n return {\n data: ssrData,\n isHydrated,\n };\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/providers/QueryClientProvider.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/rate-limit.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/routing/RouteConfig.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_locale' is defined but never used.","line":360,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":360,"endColumn":19},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":366,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":366,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[9939,9942],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[9939,9942],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * @file RouteConfig.ts\n * Centralized routing configuration for clean, maintainable paths\n *\n * Design Principles:\n * - Single source of truth for all routes\n * - i18n-ready: paths can be localized\n * - Type-safe: compile-time checking\n * - Easy to refactor: change in one place\n * - Environment-specific: can vary by mode\n */\n\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\n\nconst logger = new ConsoleLogger();\n\nexport interface RouteDefinition {\n path: string;\n name: string;\n description?: string;\n}\n\nexport interface RouteGroup {\n auth: {\n login: string;\n signup: string;\n forgotPassword: string;\n resetPassword: string;\n };\n public: {\n home: string;\n leagues: string;\n drivers: string;\n teams: string;\n leaderboards: string;\n races: string;\n sponsorSignup: string;\n };\n protected: {\n dashboard: string;\n onboarding: string;\n profile: string;\n profileSettings: string;\n profileLeagues: string;\n profileLiveries: string;\n profileLiveryUpload: string;\n profileSponsorshipRequests: string;\n };\n sponsor: {\n root: string;\n dashboard: string;\n billing: string;\n campaigns: string;\n leagues: string;\n leagueDetail: (id: string) => string;\n settings: string;\n };\n admin: {\n root: string;\n users: string;\n };\n league: {\n detail: (id: string) => string;\n rosterAdmin: (id: string) => string;\n rulebook: (id: string) => string;\n schedule: (id: string) => string;\n scheduleAdmin: (id: string) => string;\n settings: (id: string) => string;\n sponsorships: (id: string) => string;\n standings: (id: string) => string;\n stewarding: (id: string) => string;\n wallet: (id: string) => string;\n create: string;\n };\n race: {\n root: string;\n all: string;\n detail: (id: string) => string;\n results: (id: string) => string;\n stewarding: (id: string) => string;\n };\n team: {\n root: string;\n leaderboard: string;\n detail: (id: string) => string;\n };\n driver: {\n root: string;\n detail: (id: string) => string;\n };\n leaderboards: {\n root: string;\n drivers: string;\n };\n error: {\n notFound: string;\n serverError: string;\n };\n}\n\n/**\n * Route configuration with i18n support\n * \n * Usage:\n * ```typescript\n * import { routes } from '@/lib/routing/RouteConfig';\n * \n * // Navigate to login\n * router.push(routes.auth.login);\n * \n * // Navigate to league detail\n * router.push(routes.league.detail('league-123'));\n * \n * // Check if current path is protected\n * if (currentPath.startsWith(routes.protected.dashboard)) {\n * // Handle protected route\n * }\n * ```\n */\nexport const routes: RouteGroup & { leaderboards: { root: string; drivers: string } } = {\n auth: {\n login: '/auth/login',\n signup: '/auth/signup',\n forgotPassword: '/auth/forgot-password',\n resetPassword: '/auth/reset-password',\n },\n public: {\n home: '/',\n leagues: '/leagues',\n drivers: '/drivers',\n teams: '/teams',\n leaderboards: '/leaderboards',\n races: '/races',\n sponsorSignup: '/sponsor/signup',\n },\n protected: {\n dashboard: '/dashboard',\n onboarding: '/onboarding',\n profile: '/profile',\n profileSettings: '/profile/settings',\n profileLeagues: '/profile/leagues',\n profileLiveries: '/profile/liveries',\n profileLiveryUpload: '/profile/liveries/upload',\n profileSponsorshipRequests: '/profile/sponsorship-requests',\n },\n sponsor: {\n root: '/sponsor',\n dashboard: '/sponsor/dashboard',\n billing: '/sponsor/billing',\n campaigns: '/sponsor/campaigns',\n leagues: '/sponsor/leagues',\n leagueDetail: (id: string) => `/sponsor/leagues/${id}`,\n settings: '/sponsor/settings',\n },\n admin: {\n root: '/admin',\n users: '/admin/users',\n },\n league: {\n detail: (id: string) => `/leagues/${id}`,\n rosterAdmin: (id: string) => `/leagues/${id}/roster/admin`,\n rulebook: (id: string) => `/leagues/${id}/rulebook`,\n schedule: (id: string) => `/leagues/${id}/schedule`,\n scheduleAdmin: (id: string) => `/leagues/${id}/schedule/admin`,\n settings: (id: string) => `/leagues/${id}/settings`,\n sponsorships: (id: string) => `/leagues/${id}/sponsorships`,\n standings: (id: string) => `/leagues/${id}/standings`,\n stewarding: (id: string) => `/leagues/${id}/stewarding`,\n wallet: (id: string) => `/leagues/${id}/wallet`,\n create: '/leagues/create',\n },\n race: {\n root: '/races',\n all: '/races/all',\n detail: (id: string) => `/races/${id}`,\n results: (id: string) => `/races/${id}/results`,\n stewarding: (id: string) => `/races/${id}/stewarding`,\n },\n team: {\n root: '/teams',\n leaderboard: '/teams/leaderboard',\n detail: (id: string) => `/teams/${id}`,\n },\n driver: {\n root: '/drivers',\n detail: (id: string) => `/drivers/${id}`,\n },\n leaderboards: {\n root: '/leaderboards',\n drivers: '/leaderboards/drivers',\n },\n error: {\n notFound: '/404',\n serverError: '/500',\n },\n};\n\n/**\n * Route matcher utilities for pattern matching\n */\nexport const routeMatchers = {\n /**\n * Check if path matches a pattern\n */\n matches(path: string, pattern: string): boolean {\n // Exact match\n if (pattern === path) return true;\n \n // Wildcard match (starts with)\n if (pattern.endsWith('/*') && path.startsWith(pattern.slice(0, -2))) {\n return true;\n }\n \n // Parameterized match (e.g., /leagues/[id])\n const paramPattern = pattern.replace(/\\[([^\\]]+)\\]/g, '([^/]+)');\n const regex = new RegExp(`^${paramPattern}$`);\n return regex.test(path);\n },\n\n /**\n * Check if path is in a route group\n */\n isInGroup(path: string, group: keyof RouteGroup): boolean {\n const groupRoutes = routes[group];\n \n // Handle nested objects (like sponsor.leagueDetail)\n const values = Object.values(groupRoutes);\n \n return values.some(value => {\n if (typeof value === 'function') {\n // For parameterized routes, check pattern\n const pattern = value('placeholder');\n return path.startsWith(pattern.replace('/placeholder', ''));\n }\n return path.startsWith(value as string);\n });\n },\n\n /**\n * Get all public route patterns\n */\n getPublicPatterns(): string[] {\n return [\n routes.public.home,\n routes.public.leagues,\n routes.public.drivers,\n routes.public.teams,\n routes.public.leaderboards,\n routes.public.races,\n routes.public.sponsorSignup,\n routes.auth.login,\n routes.auth.signup,\n routes.auth.forgotPassword,\n routes.auth.resetPassword,\n routes.error.notFound,\n routes.error.serverError,\n ];\n },\n\n /**\n * Check if path is public\n */\n isPublic(path: string): boolean {\n logger.info('[RouteConfig] isPublic check', { path });\n \n const publicPatterns = this.getPublicPatterns();\n\n // Check exact matches\n if (publicPatterns.includes(path)) {\n logger.info('[RouteConfig] Path is public (exact match)', { path });\n return true;\n }\n\n // Treat top-level detail pages as public (e2e relies on this)\n // Examples: /leagues/:id, /races/:id, /drivers/:id, /teams/:id\n const segments = path.split('/').filter(Boolean);\n if (segments.length === 2) {\n const [group, slug] = segments;\n if (group === 'leagues' && slug !== 'create') {\n logger.info('[RouteConfig] Path is public (league detail)', { path });\n return true;\n }\n if (group === 'races') {\n logger.info('[RouteConfig] Path is public (race detail)', { path });\n return true;\n }\n if (group === 'drivers') {\n logger.info('[RouteConfig] Path is public (driver detail)', { path });\n return true;\n }\n if (group === 'teams') {\n logger.info('[RouteConfig] Path is public (team detail)', { path });\n return true;\n }\n }\n\n // Check parameterized patterns\n const isPublicParam = publicPatterns.some(pattern => {\n if (pattern.includes('[')) {\n const paramPattern = pattern.replace(/\\[([^\\]]+)\\]/g, '([^/]+)');\n const regex = new RegExp(`^${paramPattern}$`);\n return regex.test(path);\n }\n return false;\n });\n \n if (isPublicParam) {\n logger.info('[RouteConfig] Path is public (parameterized match)', { path });\n } else {\n logger.info('[RouteConfig] Path is NOT public', { path });\n }\n \n return isPublicParam;\n },\n\n /**\n * Check if path requires authentication\n */\n requiresAuth(path: string): boolean {\n return !this.isPublic(path);\n },\n\n /**\n * Check if path requires specific role\n */\n requiresRole(path: string): string[] | null {\n logger.info('[RouteConfig] requiresRole check', { path });\n \n if (this.isInGroup(path, 'admin')) {\n // Website session roles come from the API and are more specific than just \"admin\".\n // Keep \"admin\"/\"owner\" for backwards compatibility.\n const roles = ['admin', 'owner', 'league-admin', 'league-steward', 'league-owner', 'system-owner', 'super-admin'];\n logger.info('[RouteConfig] Path requires admin roles', { path, roles });\n return roles;\n }\n if (this.isInGroup(path, 'sponsor')) {\n logger.info('[RouteConfig] Path requires sponsor role', { path });\n return ['sponsor'];\n }\n logger.info('[RouteConfig] Path requires no specific role', { path });\n return null;\n },\n};\n\n/**\n * i18n-ready path builder\n * \n * Usage:\n * ```typescript\n * // With current locale\n * const path = buildPath('leagueDetail', { id: '123' });\n * \n * // With specific locale\n * const path = buildPath('leagueDetail', { id: '123' }, 'de');\n * ```\n */\nexport function buildPath(\n routeName: string,\n params: Record<string, string> = {},\n _locale?: string\n): string {\n // This is a placeholder for future i18n implementation\n // For now, it just builds the path using the route config\n \n const parts = routeName.split('.');\n let route: any = routes;\n \n for (const part of parts) {\n route = route[part];\n if (!route) {\n throw new Error(`Unknown route: ${routeName}`);\n }\n }\n \n if (typeof route === 'function') {\n const paramKeys = Object.keys(params);\n const paramKey = paramKeys[0];\n if (!paramKey) {\n throw new Error(`Route ${routeName} requires parameters`);\n }\n return route(params[paramKey]);\n }\n \n return route as string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/routing/search-params/SearchParamBuilder.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/routing/search-params/SearchParamParser.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/routing/search-params/SearchParamTypes.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/routing/search-params/SearchParamValidators.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'value' is defined but never used.","line":87,"column":27,"nodeType":"Identifier","messageId":"unusedVar","endLine":87,"endColumn":47}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * @file SearchParamValidators.ts\n * Pure validation logic for search parameters\n * No side effects, no dependencies\n */\n\nexport interface ValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\nexport class SearchParamValidators {\n // Auth validators\n static validateReturnTo(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n if (!value.startsWith('/')) {\n return { isValid: false, errors: ['returnTo must start with /'] };\n }\n if (value.includes('://') || value.includes('//')) {\n return { isValid: false, errors: ['returnTo must be a relative path'] };\n }\n return { isValid: true, errors: [] };\n }\n\n static validateToken(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n if (value.length === 0) {\n return { isValid: false, errors: ['token cannot be empty'] };\n }\n return { isValid: true, errors: [] };\n }\n\n static validateEmail(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n if (!value.includes('@')) {\n return { isValid: false, errors: ['email must be valid'] };\n }\n return { isValid: true, errors: [] };\n }\n\n // Sponsor validators\n static validateCampaignType(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n const validTypes = ['leagues', 'teams', 'drivers', 'races', 'platform'];\n if (!validTypes.includes(value)) {\n return { isValid: false, errors: [`type must be one of: ${validTypes.join(', ')}`] };\n }\n return { isValid: true, errors: [] };\n }\n\n // Pagination validators\n static validatePage(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n const num = parseInt(value);\n if (isNaN(num) || num < 1) {\n return { isValid: false, errors: ['page must be a positive integer'] };\n }\n return { isValid: true, errors: [] };\n }\n\n static validateLimit(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n const num = parseInt(value);\n if (isNaN(num) || num < 1) {\n return { isValid: false, errors: ['limit must be a positive integer'] };\n }\n return { isValid: true, errors: [] };\n }\n\n // Sorting validators\n static validateOrder(value: string | null): ValidationResult {\n if (value === null) return { isValid: true, errors: [] };\n if (!['asc', 'desc'].includes(value)) {\n return { isValid: false, errors: ['order must be asc or desc'] };\n }\n return { isValid: true, errors: [] };\n }\n\n // Generic validators\n static validateRequired(value: string | null, fieldName: string): ValidationResult {\n if (value === null || value.length === 0) {\n return { isValid: false, errors: [`${fieldName} is required`] };\n }\n return { isValid: true, errors: [] };\n }\n\n static validateOptional(value: string | null): ValidationResult {\n return { isValid: true, errors: [] };\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/admin/AdminService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/analytics/DashboardService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/AuthPageParams.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":7,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":10,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Auth Page Parameters\n * \n * Input parameters for auth page processing.\n */\n\nexport interface AuthPageParams {\n returnTo?: string | null;\n token?: string | null;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/AuthPageService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/AuthService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1627,1630],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1627,1630],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":47,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":47,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1940,1943],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1940,1943],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":56,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":56,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2208,2211],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2208,2211],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":65,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":65,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2570,2573],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2570,2573],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":74,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":74,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2926,2929],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2926,2929],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":83,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":83,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3233,3236],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3233,3236],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { AuthApiClient } from '@/lib/api/auth/AuthApiClient';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport type { AuthSessionDTO } from '@/lib/types/generated/AuthSessionDTO';\nimport type { LoginParamsDTO } from '@/lib/types/generated/LoginParamsDTO';\nimport type { SignupParamsDTO } from '@/lib/types/generated/SignupParamsDTO';\nimport type { ForgotPasswordDTO } from '@/lib/types/generated/ForgotPasswordDTO';\nimport type { ResetPasswordDTO } from '@/lib/types/generated/ResetPasswordDTO';\nimport { isProductionEnvironment } from '@/lib/config/env';\n\n/**\n * Auth Service\n *\n * Orchestrates authentication operations.\n * Returns raw API DTOs. No ViewModels or UX logic.\n */\nexport class AuthService implements Service {\n private apiClient: AuthApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: false,\n logToConsole: true,\n reportToExternal: isProductionEnvironment(),\n });\n this.apiClient = new AuthApiClient(baseUrl, errorReporter, logger);\n }\n\n async login(params: LoginParamsDTO): Promise<Result<AuthSessionDTO, DomainError>> {\n try {\n const dto = await this.apiClient.login(params);\n return Result.ok(dto);\n } catch (error: any) {\n return Result.err({ type: 'unauthorized', message: error.message || 'Login failed' });\n }\n }\n\n async signup(params: SignupParamsDTO): Promise<Result<AuthSessionDTO, DomainError>> {\n try {\n const dto = await this.apiClient.signup(params);\n return Result.ok(dto);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Signup failed' });\n }\n }\n\n async logout(): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.logout();\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Logout failed' });\n }\n }\n\n async forgotPassword(params: ForgotPasswordDTO): Promise<Result<{ message: string; magicLink?: string }, DomainError>> {\n try {\n const result = await this.apiClient.forgotPassword(params);\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Forgot password request failed' });\n }\n }\n\n async resetPassword(params: ResetPasswordDTO): Promise<Result<{ message: string }, DomainError>> {\n try {\n const result = await this.apiClient.resetPassword(params);\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Reset password failed' });\n }\n }\n\n async getSession(): Promise<Result<AuthSessionDTO | null, DomainError>> {\n try {\n const dto = await this.apiClient.getSession();\n return Result.ok(dto);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch session' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/SessionService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/types/ForgotPasswordPageDTO.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":8,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":10,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Forgot Password Page DTO\n * \n * Data transfer object for forgot password page composition.\n * Used by AuthPageService and ForgotPasswordViewDataBuilder.\n */\n\nexport interface ForgotPasswordPageDTO {\n returnTo: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/types/LoginPageDTO.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":8,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":11,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Login Page DTO\n * \n * Data transfer object for login page composition.\n * Used by AuthPageService and LoginViewDataBuilder.\n */\n\nexport interface LoginPageDTO {\n returnTo: string;\n hasInsufficientPermissions: boolean;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/types/ResetPasswordPageDTO.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":8,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":11,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Reset Password Page DTO\n * \n * Data transfer object for reset password page composition.\n * Used by AuthPageService and ResetPasswordViewDataBuilder.\n */\n\nexport interface ResetPasswordPageDTO {\n token: string;\n returnTo: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/auth/types/SignupPageDTO.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":8,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":10,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Signup Page DTO\n * \n * Data transfer object for signup page composition.\n * Used by AuthPageService and SignupViewDataBuilder.\n */\n\nexport interface SignupPageDTO {\n returnTo: string;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/DriverProfilePageService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/DriverProfileReadService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/DriverProfileService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/DriverProfileUpdateService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/DriverService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":32,"column":48,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":32,"endColumn":51,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1476,1479],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1476,1479],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1615,1618],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1615,1618],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":48,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":48,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2052,2055],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2052,2055],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":60,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":60,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2420,2423],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2420,2423],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":72,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":72,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2826,2829],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2826,2829],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":84,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":84,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3247,3250],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3247,3250],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":96,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":96,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3621,3624],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3621,3624],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":108,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":108,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4088,4091],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4088,4091],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { DriversApiClient } from '@/lib/api/drivers/DriversApiClient';\nimport type { CompleteOnboardingInputDTO } from '@/lib/types/generated/CompleteOnboardingInputDTO';\nimport type { GetDriverOutputDTO } from '@/lib/types/generated/GetDriverOutputDTO';\nimport type { CompleteOnboardingOutputDTO } from '@/lib/types/generated/CompleteOnboardingOutputDTO';\nimport type { DriverDTO } from '@/lib/types/generated/DriverDTO';\nimport type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\n\n/**\n * Driver Service - DTO Only\n *\n * Returns raw API DTOs. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n */\nexport class DriverService implements Service {\n private readonly apiClient: DriversApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger);\n this.apiClient = new DriversApiClient(baseUrl, errorReporter, logger);\n }\n\n /**\n * Get driver leaderboard (returns DTO)\n */\n async getDriverLeaderboard(): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getLeaderboard();\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get leaderboard' });\n }\n }\n\n /**\n * Complete driver onboarding (returns DTO)\n */\n async completeDriverOnboarding(input: CompleteOnboardingInputDTO): Promise<Result<CompleteOnboardingOutputDTO, DomainError>> {\n try {\n const data = await this.apiClient.completeOnboarding(input);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to complete onboarding' });\n }\n }\n\n /**\n * Get current driver (returns DTO)\n */\n async getCurrentDriver(): Promise<Result<DriverDTO | null, DomainError>> {\n try {\n const data = await this.apiClient.getCurrent();\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get current driver' });\n }\n }\n\n /**\n * Get driver profile (returns DTO)\n */\n async getDriverProfile(driverId: string): Promise<Result<GetDriverProfileOutputDTO, DomainError>> {\n try {\n const data = await this.apiClient.getDriverProfile(driverId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get driver profile' });\n }\n }\n\n /**\n * Update current driver profile (returns DTO)\n */\n async updateProfile(updates: { bio?: string; country?: string }): Promise<Result<DriverDTO, DomainError>> {\n try {\n const data = await this.apiClient.updateProfile(updates);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to update profile' });\n }\n }\n\n /**\n * Find driver by ID (returns DTO)\n */\n async findById(id: string): Promise<Result<GetDriverOutputDTO | null, DomainError>> {\n try {\n const data = await this.apiClient.getDriver(id);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to find driver' });\n }\n }\n\n /**\n * Find multiple drivers by IDs (returns DTOs)\n */\n async findByIds(ids: string[]): Promise<Result<GetDriverOutputDTO[], DomainError>> {\n try {\n const drivers = await Promise.all(ids.map(id => this.apiClient.getDriver(id)));\n return Result.ok(drivers.filter((d): d is GetDriverOutputDTO => d !== null));\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to find drivers' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/DriversPageService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/LiveryService.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":11,"column":21,"nodeType":"Identifier","messageId":"unusedVar","endLine":11,"endColumn":38},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":34,"column":22,"nodeType":"Identifier","messageId":"unusedVar","endLine":34,"endColumn":39},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_file' is defined but never used.","line":34,"column":41,"nodeType":"Identifier","messageId":"unusedVar","endLine":34,"endColumn":52}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport type { DomainError, Service } from '@/lib/contracts/services/Service';\nimport type { GetLiveriesOutputDTO } from '@/lib/types/tbd/GetLiveriesOutputDTO';\n\n/**\n * Livery Service\n *\n * Provides livery management functionality.\n */\nexport class LiveryService implements Service {\n async getLiveries(_driverId: string): Promise<Result<GetLiveriesOutputDTO, DomainError>> {\n // Mock data for now\n const mockLiveries: GetLiveriesOutputDTO = {\n liveries: [\n {\n id: 'livery-1',\n name: 'Default Livery',\n imageUrl: '/mock-livery-1.png',\n createdAt: new Date().toISOString(),\n isActive: true,\n },\n {\n id: 'livery-2',\n name: 'Custom Livery',\n imageUrl: '/mock-livery-2.png',\n createdAt: new Date(Date.now() - 86400000).toISOString(),\n isActive: false,\n },\n ],\n };\n return Result.ok(mockLiveries);\n }\n\n async uploadLivery(_driverId: string, _file: File): Promise<Result<{ liveryId: string }, DomainError>> {\n // Mock implementation\n return Result.ok({ liveryId: 'new-livery-id' });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/drivers/SettingsService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/error/ErrorAnalyticsService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":100,"endColumn":1},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":54,"column":26,"nodeType":"CallExpression","messageId":"message","endLine":56,"endColumn":52},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":58,"column":26,"nodeType":"CallExpression","messageId":"message","endLine":58,"endColumn":59},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":86,"column":18,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":86,"endColumn":53},{"ruleId":"gridpilot-rules/no-direct-process-env","severity":2,"message":"Do not read process.env directly here. Use `getWebsiteServerEnv()` / `getWebsitePublicEnv()` (apps/website/lib/config/env.ts) or a dedicated config helper (e.g. getWebsiteApiBaseUrl()).","line":87,"column":20,"nodeType":"MemberExpression","messageId":"noProcessEnv","endLine":87,"endColumn":54},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":95,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":95,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3089,3092],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3089,3092],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';\nimport { getGlobalApiLogger } from '@/lib/infrastructure/ApiRequestLogger';\nimport { ApiError } from '@/lib/api/base/ApiError';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { getWebsiteServerEnv } from '@/lib/config/env';\n\nexport interface ErrorStats {\n totalErrors: number;\n errorsByType: Record<string, number>;\n errorsByTime: Array<{ time: string; count: number }>;\n recentErrors: Array<{\n timestamp: string;\n message: string;\n type: string;\n context?: unknown;\n }>;\n apiStats: {\n totalRequests: number;\n successful: number;\n failed: number;\n averageDuration: number;\n slowestRequests: Array<{ url: string; duration: number }>;\n };\n environment: {\n mode: string;\n version?: string;\n buildTime?: string;\n };\n}\n\nexport class ErrorAnalyticsService implements Service {\n static getErrorAnalyticsStats(): ErrorStats {\n const globalHandler = getGlobalErrorHandler();\n const apiLogger = getGlobalApiLogger();\n\n const errorHistory = globalHandler.getErrorHistory();\n const errorStats = globalHandler.getStats();\n const apiStats = apiLogger.getStats();\n\n // Group errors by time (last 10 minutes)\n const timeGroups = new Map<string, number>();\n const now = Date.now();\n const tenMinutesAgo = now - (10 * 60 * 1000);\n\n errorHistory.forEach(entry => {\n const entryTime = new Date(entry.timestamp).getTime();\n if (entryTime >= tenMinutesAgo) {\n const timeKey = new Date(entry.timestamp).toLocaleTimeString();\n timeGroups.set(timeKey, (timeGroups.get(timeKey) || 0) + 1);\n }\n });\n\n const errorsByTime = Array.from(timeGroups.entries())\n .map(([time, count]) => ({ time, count }))\n .sort((a, b) => a.time.localeCompare(b.time));\n\n const recentErrors = errorHistory.slice(-10).reverse().map(entry => ({\n timestamp: entry.timestamp,\n message: entry.error.message,\n type: entry.error instanceof ApiError ? entry.error.type : entry.error.name || 'Error',\n context: entry.context,\n }));\n\n const slowestRequests = apiLogger.getSlowestRequests(5).map(log => ({\n url: log.url,\n duration: log.response?.duration || 0,\n }));\n\n const env = getWebsiteServerEnv();\n\n return {\n totalErrors: errorStats.total,\n errorsByType: errorStats.byType,\n errorsByTime,\n recentErrors,\n apiStats: {\n totalRequests: apiStats.total,\n successful: apiStats.successful,\n failed: apiStats.failed,\n averageDuration: apiStats.averageDuration,\n slowestRequests,\n },\n environment: {\n mode: env.NODE_ENV || 'unknown',\n version: process.env.NEXT_PUBLIC_APP_VERSION,\n buildTime: process.env.NEXT_PUBLIC_BUILD_TIME,\n },\n };\n }\n\n async getErrorAnalyticsStats(): Promise<Result<ErrorStats, DomainError>> {\n try {\n return Result.ok(ErrorAnalyticsService.getErrorAnalyticsStats());\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get error analytics stats' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/home/getHomeData.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Services must be classes named *Service, not functions. Found function \"getHomeData\" in lib/services/","line":1,"column":1,"nodeType":"Program","messageId":"notAClass","endLine":74,"endColumn":1},{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Services cannot use redirect(). Use PageQueries or Client Components for navigation.","line":1,"column":1,"nodeType":"Program","messageId":"noRedirect","endLine":74,"endColumn":1},{"ruleId":"gridpilot-rules/lib-no-next-imports","severity":2,"message":"redirect() must be used in app/ directory, not lib/ directory","line":1,"column":10,"nodeType":"ImportSpecifier","messageId":"noNextRedirect","endLine":1,"endColumn":18}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { redirect } from 'next/navigation';\nimport { routes } from '@/lib/routing/RouteConfig';\nimport { FeatureFlagService } from '@/lib/feature/FeatureFlagService';\n\n// API Clients\nimport { RacesApiClient } from '@/lib/api/races/RacesApiClient';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { TeamsApiClient } from '@/lib/api/teams/TeamsApiClient';\n\n// Services\nimport { SessionService } from '@/lib/services/auth/SessionService';\n\n// Infrastructure\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\n\n// DTO types\nimport type { HomeViewData } from '@/templates/HomeTemplate';\n\nexport async function getHomeData(): Promise<HomeViewData> {\n // Manual wiring: construct dependencies explicitly\n const baseUrl = getWebsiteApiBaseUrl();\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n\n // Construct API clients\n const racesApiClient = new RacesApiClient(baseUrl, errorReporter, logger);\n const leaguesApiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n const teamsApiClient = new TeamsApiClient(baseUrl, errorReporter, logger);\n\n // Construct services\n const sessionService = new SessionService();\n\n // Check session and redirect if logged in\n const sessionResult = await sessionService.getSession();\n if (sessionResult.isOk() && sessionResult.unwrap()) {\n redirect(routes.protected.dashboard);\n }\n\n // Get feature flags\n const featureService = await FeatureFlagService.fromAPI();\n const isAlpha = featureService.isEnabled('alpha_features');\n\n // Get home discovery data (manual implementation)\n const [racesDto, leaguesDto, teamsDto] = await Promise.all([\n racesApiClient.getPageData(),\n leaguesApiClient.getAllWithCapacity(),\n teamsApiClient.getAll(),\n ]);\n\n // Return DTOs directly (no ViewModels)\n return {\n isAlpha,\n upcomingRaces: racesDto.races.slice(0, 4).map(r => ({\n id: r.id,\n track: r.track,\n car: r.car,\n formattedDate: new Date(r.scheduledAt).toLocaleDateString(),\n })),\n topLeagues: leaguesDto.leagues.slice(0, 4).map(l => ({\n id: l.id,\n name: l.name,\n description: l.description,\n })),\n teams: teamsDto.teams.slice(0, 4).map(t => ({\n id: t.id,\n name: t.name,\n description: t.description,\n logoUrl: t.logoUrl,\n })),\n };\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/landing/LandingService.ts","messages":[],"suppressedMessages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'email' is assigned a value but never used.","line":45,"column":11,"nodeType":"Identifier","messageId":"unusedVar","endLine":45,"endColumn":16,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leaderboards/DriverRankingsService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":59,"endColumn":2}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { DriversApiClient } from '@/lib/api/drivers/DriversApiClient';\nimport { Result } from '@/lib/contracts/Result';\nimport { Service, DomainError } from '@/lib/contracts/services/Service';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\nexport interface DriverRankingsData {\n drivers: DriverLeaderboardItemDTO[];\n}\n\nexport class DriverRankingsService implements Service {\n async getDriverRankings(): Promise<Result<DriverRankingsData, DomainError>> {\n try {\n const baseUrl = getWebsiteApiBaseUrl();\n const errorReporter = new ConsoleErrorReporter();\n const logger = new ConsoleLogger();\n \n const apiClient = new DriversApiClient(baseUrl, errorReporter, logger);\n const result = await apiClient.getLeaderboard();\n \n if (!result || !result.drivers) {\n return Result.err({ type: 'notFound', message: 'No driver rankings available' });\n }\n\n const data: DriverRankingsData = {\n drivers: result.drivers,\n };\n \n return Result.ok(data);\n } catch (error) {\n // Convert ApiError to DomainError\n if (error instanceof ApiError) {\n switch (error.type) {\n case 'NOT_FOUND':\n return Result.err({ type: 'notFound', message: error.message });\n case 'AUTH_ERROR':\n return Result.err({ type: 'unauthorized', message: error.message });\n case 'SERVER_ERROR':\n return Result.err({ type: 'serverError', message: error.message });\n case 'NETWORK_ERROR':\n case 'TIMEOUT_ERROR':\n return Result.err({ type: 'networkError', message: error.message });\n default:\n return Result.err({ type: 'unknown', message: error.message });\n }\n }\n \n // Handle non-ApiError cases\n if (error instanceof Error) {\n return Result.err({ type: 'unknown', message: error.message });\n }\n \n return Result.err({ type: 'unknown', message: 'Driver rankings fetch failed' });\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leaderboards/LeaderboardsService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/league/LeagueActivityService.ts","messages":[{"ruleId":"gridpilot-rules/services-implement-contract","severity":2,"message":"Service methods must return Promise<Result<T, DomainError>>","line":5,"column":8,"nodeType":"ClassDeclaration","messageId":"mustReturnResult","endLine":45,"endColumn":2},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":6,"column":37,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":6,"endColumn":40,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[294,297],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[294,297],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":9,"column":28,"nodeType":"CallExpression","messageId":"message","endLine":11,"endColumn":93},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":14,"column":27,"nodeType":"CallExpression","messageId":"message","endLine":16,"endColumn":93},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":20,"column":7,"nodeType":"CallExpression","messageId":"message","endLine":25,"endColumn":9},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":29,"column":7,"nodeType":"CallExpression","messageId":"message","endLine":34,"endColumn":9},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":38,"column":5,"nodeType":"CallExpression","messageId":"message","endLine":38,"endColumn":77},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":40,"column":7,"nodeType":"CallExpression","messageId":"message","endLine":40,"endColumn":31}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { LeagueActivity } from '@/components/leagues/LeagueActivityFeed';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\n\nexport class LeagueActivityService implements Service {\n processLeagueActivities(raceList: any[], limit: number): Result<LeagueActivity[], DomainError> {\n const activities: LeagueActivity[] = [];\n \n const completedRaces = raceList\n .filter((r) => r.status === 'completed')\n .sort((a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime())\n .slice(0, 5);\n\n const upcomingRaces = raceList\n .filter((r) => r.status === 'scheduled')\n .sort((a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime())\n .slice(0, 3);\n\n for (const race of completedRaces) {\n activities.push({\n type: 'race_completed',\n raceId: race.id,\n raceName: `${race.track} - ${race.car}`,\n timestamp: new Date(race.scheduledAt),\n });\n }\n\n for (const race of upcomingRaces) {\n activities.push({\n type: 'race_scheduled',\n raceId: race.id,\n raceName: `${race.track} - ${race.car}`,\n timestamp: new Date(new Date(race.scheduledAt).getTime() - 7 * 24 * 60 * 60 * 1000), // Simulate schedule announcement\n });\n }\n\n // Sort all activities by timestamp\n activities.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n if (activities.length > limit) {\n activities.splice(limit);\n }\n\n return Result.ok(activities);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueMembershipService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":123,"endColumn":1},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":19,"column":54,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":19,"endColumn":57,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[969,972],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[969,972],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":32,"column":61,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":32,"endColumn":64,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1405,1408],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1405,1408],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":46,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":49,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1620,1623],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1620,1623],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":42,"column":56,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":42,"endColumn":59,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1743,1746],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1743,1746],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":43,"column":27,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":43,"endColumn":30,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1777,1780],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1777,1780],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"gridpilot-rules/services-must-be-pure","severity":2,"message":"Services must be pure functions, no side effects allowed - see apps/website/lib/contracts/services/Service.ts","line":47,"column":9,"nodeType":"CallExpression","messageId":"message","endLine":47,"endColumn":57},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":56,"column":75,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":56,"endColumn":78,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2279,2282],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2279,2282],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":62,"column":54,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":62,"endColumn":57,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2445,2448],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2445,2448],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":66,"column":39,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":66,"endColumn":42,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2571,2574],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2571,2574],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_leagueId' is defined but never used.","line":70,"column":20,"nodeType":"Identifier","messageId":"unusedVar","endLine":70,"endColumn":37},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":70,"column":39,"nodeType":"Identifier","messageId":"unusedVar","endLine":70,"endColumn":56},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_leagueId' is defined but never used.","line":74,"column":21,"nodeType":"Identifier","messageId":"unusedVar","endLine":74,"endColumn":38},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":74,"column":40,"nodeType":"Identifier","messageId":"unusedVar","endLine":74,"endColumn":57},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":90,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":90,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3405,3408],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3405,3408],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":100,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":100,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3894,3897],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3894,3897],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":109,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":109,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4307,4310],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4307,4310],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":118,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":118,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4725,4728],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4725,4728],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":18,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { Result } from '@/lib/contracts/Result';\nimport { Service, type DomainError } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { isProductionEnvironment } from '@/lib/config/env';\nimport type { LeagueRosterMemberDTO } from '@/lib/types/generated/LeagueRosterMemberDTO';\nimport type { LeagueRosterJoinRequestDTO } from '@/lib/types/generated/LeagueRosterJoinRequestDTO';\n\nexport interface LeagueRosterAdminData {\n leagueId: string;\n members: LeagueRosterMemberDTO[];\n joinRequests: LeagueRosterJoinRequestDTO[];\n}\n\nexport class LeagueMembershipService implements Service {\n private apiClient: LeaguesApiClient;\n private static cachedMemberships = new Map<string, any[]>();\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: false,\n logToConsole: true,\n reportToExternal: isProductionEnvironment(),\n });\n this.apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n }\n\n static getMembership(leagueId: string, driverId: string): any | null {\n const members = this.cachedMemberships.get(leagueId);\n if (!members) return null;\n return members.find(m => m.driverId === driverId) || null;\n }\n\n static getLeagueMembers(leagueId: string): any[] {\n return this.cachedMemberships.get(leagueId) || [];\n }\n\n static getAllMembershipsForDriver(driverId: string): any[] {\n const allMemberships: any[] = [];\n for (const [leagueId, members] of this.cachedMemberships.entries()) {\n const membership = members.find(m => m.driverId === driverId);\n if (membership) {\n allMemberships.push({ ...membership, leagueId });\n }\n }\n return allMemberships;\n }\n\n async fetchLeagueMemberships(leagueId: string): Promise<void> {\n try {\n const members = await this.apiClient.getMemberships(leagueId);\n LeagueMembershipService.cachedMemberships.set(leagueId, (members as any).members || []);\n } catch (error) {\n console.error('Failed to fetch memberships', error);\n }\n }\n\n getMembership(leagueId: string, driverId: string): any | null {\n return LeagueMembershipService.getMembership(leagueId, driverId);\n }\n\n getLeagueMembers(leagueId: string): any[] {\n return LeagueMembershipService.getLeagueMembers(leagueId);\n }\n\n async joinLeague(_leagueId: string, _driverId: string): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'joinLeague' });\n }\n\n async leaveLeague(_leagueId: string, _driverId: string): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'leaveLeague' });\n }\n\n async getRosterAdminData(leagueId: string): Promise<Result<LeagueRosterAdminData, DomainError>> {\n try {\n const [members, joinRequests] = await Promise.all([\n this.apiClient.getAdminRosterMembers(leagueId),\n this.apiClient.getAdminRosterJoinRequests(leagueId),\n ]);\n\n return Result.ok({\n leagueId,\n members,\n joinRequests,\n });\n } catch (error: any) {\n console.error('LeagueMembershipService.getRosterAdminData failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch roster data' });\n }\n }\n\n async removeMember(leagueId: string, targetDriverId: string): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.removeRosterMember(leagueId, targetDriverId);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to remove member' });\n }\n }\n\n async approveJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.approveRosterJoinRequest(leagueId, joinRequestId);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to approve join request' });\n }\n }\n\n async rejectJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.rejectRosterJoinRequest(leagueId, joinRequestId);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to reject join request' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueRulebookService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueScheduleService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":376,"endColumn":1},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":75,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":75,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3738,3741],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3738,3741],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":98,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":98,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4514,4517],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4514,4517],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":121,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":121,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[5419,5422],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[5419,5422],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":139,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":139,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6034,6037],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6034,6037],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":153,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":153,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6595,6598],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6595,6598],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":162,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":162,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6939,6942],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6939,6942],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":171,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":171,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7291,7294],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7291,7294],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":184,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":184,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7822,7825],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7822,7825],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":193,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":193,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8228,8231],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8228,8231],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":202,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":202,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8634,8637],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8634,8637],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":216,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":216,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[9213,9216],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[9213,9216],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":231,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":231,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[9825,9828],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[9825,9828],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":240,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":240,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[10252,10255],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[10252,10255],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":265,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":265,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[11313,11316],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[11313,11316],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":279,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":279,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[11816,11819],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[11816,11819],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":296,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":296,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12414,12417],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12414,12417],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":305,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":305,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[12759,12762],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[12759,12762],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":314,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":314,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[13162,13165],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[13162,13165],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":323,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":323,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[13607,13610],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[13607,13610],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":332,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":332,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[13971,13974],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[13971,13974],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":341,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":341,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[14352,14355],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[14352,14355],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":350,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":350,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[14771,14774],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[14771,14774],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":359,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":359,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15189,15192],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15189,15192],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":24,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { LeaguesApiClient } from \"@/lib/api/leagues/LeaguesApiClient\";\nimport { DriversApiClient } from \"@/lib/api/drivers/DriversApiClient\";\nimport { SponsorsApiClient } from \"@/lib/api/sponsors/SponsorsApiClient\";\nimport { RacesApiClient } from \"@/lib/api/races/RacesApiClient\";\nimport { CreateLeagueInputDTO } from \"@/lib/types/generated/CreateLeagueInputDTO\";\nimport { CreateLeagueOutputDTO } from \"@/lib/types/generated/CreateLeagueOutputDTO\";\nimport type { MembershipRole } from \"@/lib/types/MembershipRole\";\nimport type { LeagueRosterJoinRequestDTO } from \"@/lib/types/generated/LeagueRosterJoinRequestDTO\";\nimport type { TotalLeaguesDTO } from '@/lib/types/generated/TotalLeaguesDTO';\nimport type { LeagueSeasonSummaryDTO } from '@/lib/types/generated/LeagueSeasonSummaryDTO';\nimport type { LeagueScheduleDTO } from '@/lib/types/generated/LeagueScheduleDTO';\nimport type { CreateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceInputDTO';\nimport type { CreateLeagueScheduleRaceOutputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceOutputDTO';\nimport type { UpdateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/UpdateLeagueScheduleRaceInputDTO';\nimport type { LeagueScheduleRaceMutationSuccessDTO } from '@/lib/types/generated/LeagueScheduleRaceMutationSuccessDTO';\nimport type { LeagueSeasonSchedulePublishOutputDTO } from '@/lib/types/generated/LeagueSeasonSchedulePublishOutputDTO';\nimport type { LeagueRosterMemberDTO } from '@/lib/types/generated/LeagueRosterMemberDTO';\nimport type { LeagueMembershipsDTO } from '@/lib/types/generated/LeagueMembershipsDTO';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { isProductionEnvironment } from '@/lib/config/env';\nimport { AllLeaguesWithCapacityAndScoringDTO } from '@/lib/types/AllLeaguesWithCapacityAndScoringDTO';\nimport type { LeagueWithCapacityAndScoringDTO } from '@/lib/types/generated/LeagueWithCapacityAndScoringDTO';\n\nexport interface LeagueScheduleAdminData {\n leagueId: string;\n seasonId: string;\n seasons: LeagueSeasonSummaryDTO[];\n schedule: LeagueScheduleDTO;\n}\n\nexport interface LeagueRosterAdminData {\n leagueId: string;\n members: LeagueRosterMemberDTO[];\n joinRequests: LeagueRosterJoinRequestDTO[];\n}\n\nexport interface LeagueDetailData {\n league: LeagueWithCapacityAndScoringDTO;\n apiDto: AllLeaguesWithCapacityAndScoringDTO;\n}\n\n/**\n * League Service - DTO Only\n *\n * Returns Result<ApiDto, DomainError>. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n * @server-safe\n */\nexport class LeagueService implements Service {\n private apiClient: LeaguesApiClient;\n private driversApiClient?: DriversApiClient;\n private sponsorsApiClient?: SponsorsApiClient;\n private racesApiClient?: RacesApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: false,\n logToConsole: true,\n reportToExternal: isProductionEnvironment(),\n });\n this.apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);\n // Optional clients can be initialized if needed\n }\n\n async getAllLeagues(): Promise<Result<AllLeaguesWithCapacityAndScoringDTO, DomainError>> {\n try {\n const dto = await this.apiClient.getAllWithCapacityAndScoring();\n return Result.ok(dto);\n } catch (error: any) {\n console.error('LeagueService.getAllLeagues failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch leagues' });\n }\n }\n\n async getLeagueDetailData(leagueId: string): Promise<Result<LeagueDetailData, DomainError>> {\n try {\n const apiDto = await this.apiClient.getAllWithCapacityAndScoring();\n \n if (!apiDto || !apiDto.leagues) {\n return Result.err({ type: 'notFound', message: 'Leagues not found' });\n }\n \n const league = apiDto.leagues.find(l => l.id === leagueId);\n if (!league) {\n return Result.err({ type: 'notFound', message: 'League not found' });\n }\n \n return Result.ok({\n league,\n apiDto,\n });\n } catch (error: any) {\n console.error('LeagueService.getLeagueDetailData failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch league detail' });\n }\n }\n\n async getScheduleAdminData(leagueId: string, seasonId?: string): Promise<Result<LeagueScheduleAdminData, DomainError>> {\n try {\n const seasons = await this.apiClient.getSeasons(leagueId);\n \n if (!seasons || seasons.length === 0) {\n return Result.err({ type: 'notFound', message: 'No seasons found for league' });\n }\n \n const targetSeasonId = seasonId || (seasons.find(s => s.status === 'active')?.seasonId || seasons[0].seasonId);\n const schedule = await this.apiClient.getSchedule(leagueId, targetSeasonId);\n \n return Result.ok({\n leagueId,\n seasonId: targetSeasonId,\n seasons,\n schedule,\n });\n } catch (error: any) {\n console.error('LeagueService.getScheduleAdminData failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch schedule admin data' });\n }\n }\n\n async getRosterAdminData(leagueId: string): Promise<Result<LeagueRosterAdminData, DomainError>> {\n try {\n const [members, joinRequests] = await Promise.all([\n this.apiClient.getAdminRosterMembers(leagueId),\n this.apiClient.getAdminRosterJoinRequests(leagueId),\n ]);\n\n return Result.ok({\n leagueId,\n members,\n joinRequests,\n });\n } catch (error: any) {\n console.error('LeagueService.getRosterAdminData failed:', error);\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch roster data' });\n }\n }\n\n async getLeagueStandings(): Promise<Result<never, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'League standings endpoint not implemented' });\n }\n\n async getLeagueStats(): Promise<Result<TotalLeaguesDTO, DomainError>> {\n try {\n const data = await this.apiClient.getTotal();\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch league stats' });\n }\n }\n\n async getLeagueSchedule(leagueId: string): Promise<Result<LeagueScheduleDTO, DomainError>> {\n try {\n const data = await this.apiClient.getSchedule(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch league schedule' });\n }\n }\n\n async getLeagueSeasons(leagueId: string): Promise<Result<LeagueSeasonSummaryDTO[], DomainError>> {\n try {\n const data = await this.apiClient.getSeasons(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch league seasons' });\n }\n }\n\n async getLeagueSeasonSummaries(leagueId: string): Promise<Result<LeagueSeasonSummaryDTO[], DomainError>> {\n return this.getLeagueSeasons(leagueId);\n }\n\n async getAdminSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueScheduleDTO, DomainError>> {\n try {\n const data = await this.apiClient.getSchedule(leagueId, seasonId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch admin schedule' });\n }\n }\n\n async publishAdminSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {\n try {\n const data = await this.apiClient.publishSeasonSchedule(leagueId, seasonId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to publish schedule' });\n }\n }\n\n async unpublishAdminSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {\n try {\n const data = await this.apiClient.unpublishSeasonSchedule(leagueId, seasonId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to unpublish schedule' });\n }\n }\n\n async createAdminScheduleRace(\n leagueId: string,\n seasonId: string,\n input: { track: string; car: string; scheduledAtIso: string },\n ): Promise<Result<CreateLeagueScheduleRaceOutputDTO, DomainError>> {\n try {\n const payload: CreateLeagueScheduleRaceInputDTO = { ...input, example: '' };\n const data = await this.apiClient.createSeasonScheduleRace(leagueId, seasonId, payload);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to create race' });\n }\n }\n\n async updateAdminScheduleRace(\n leagueId: string,\n seasonId: string,\n raceId: string,\n input: Partial<{ track: string; car: string; scheduledAtIso: string }>,\n ): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {\n try {\n const payload: UpdateLeagueScheduleRaceInputDTO = { ...input, example: '' };\n const data = await this.apiClient.updateSeasonScheduleRace(leagueId, seasonId, raceId, payload);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to update race' });\n }\n }\n\n async deleteAdminScheduleRace(leagueId: string, seasonId: string, raceId: string): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {\n try {\n const data = await this.apiClient.deleteSeasonScheduleRace(leagueId, seasonId, raceId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to delete race' });\n }\n }\n\n async getLeagueScheduleDto(leagueId: string, seasonId: string): Promise<Result<LeagueScheduleDTO, DomainError>> {\n return this.getAdminSchedule(leagueId, seasonId);\n }\n\n async publishLeagueSeasonSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {\n return this.publishAdminSchedule(leagueId, seasonId);\n }\n\n async unpublishLeagueSeasonSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {\n return this.unpublishAdminSchedule(leagueId, seasonId);\n }\n\n async createLeagueSeasonScheduleRace(\n leagueId: string,\n seasonId: string,\n input: CreateLeagueScheduleRaceInputDTO,\n ): Promise<Result<CreateLeagueScheduleRaceOutputDTO, DomainError>> {\n try {\n const data = await this.apiClient.createSeasonScheduleRace(leagueId, seasonId, input);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to create race' });\n }\n }\n\n async updateLeagueSeasonScheduleRace(\n leagueId: string,\n seasonId: string,\n raceId: string,\n input: UpdateLeagueScheduleRaceInputDTO,\n ): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {\n try {\n const data = await this.apiClient.updateSeasonScheduleRace(leagueId, seasonId, raceId, input);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to update race' });\n }\n }\n\n async deleteLeagueSeasonScheduleRace(\n leagueId: string,\n seasonId: string,\n raceId: string,\n ): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {\n return this.deleteAdminScheduleRace(leagueId, seasonId, raceId);\n }\n\n async getLeagueMemberships(leagueId: string): Promise<Result<LeagueMembershipsDTO, DomainError>> {\n try {\n const data = await this.apiClient.getMemberships(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch memberships' });\n }\n }\n\n async createLeague(input: CreateLeagueInputDTO): Promise<Result<CreateLeagueOutputDTO, DomainError>> {\n try {\n const data = await this.apiClient.create(input);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to create league' });\n }\n }\n\n async removeMember(leagueId: string, targetDriverId: string): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.removeRosterMember(leagueId, targetDriverId);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to remove member' });\n }\n }\n\n async updateMemberRole(leagueId: string, targetDriverId: string, newRole: MembershipRole): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.updateRosterMemberRole(leagueId, targetDriverId, newRole);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to update member role' });\n }\n }\n\n async getAdminRosterMembers(leagueId: string): Promise<Result<LeagueRosterMemberDTO[], DomainError>> {\n try {\n const data = await this.apiClient.getAdminRosterMembers(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch roster members' });\n }\n }\n\n async getAdminRosterJoinRequests(leagueId: string): Promise<Result<LeagueRosterJoinRequestDTO[], DomainError>> {\n try {\n const data = await this.apiClient.getAdminRosterJoinRequests(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch join requests' });\n }\n }\n\n async approveJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.approveRosterJoinRequest(leagueId, joinRequestId);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to approve join request' });\n }\n }\n\n async rejectJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<{ success: boolean }, DomainError>> {\n try {\n const dto = await this.apiClient.rejectRosterJoinRequest(leagueId, joinRequestId);\n return Result.ok({ success: dto.success });\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to reject join request' });\n }\n }\n\n async getLeagueDetail(): Promise<Result<never, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'League detail endpoint not implemented' });\n }\n\n async getLeagueDetailPageData(): Promise<Result<never, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'League detail page data endpoint not implemented' });\n }\n\n async getScoringPresets(): Promise<Result<never, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'Scoring presets endpoint not implemented' });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueSettingsService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":29,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":32,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1332,1335],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1332,1335],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { Service, type DomainError } from '@/lib/contracts/services/Service';\nimport { type LeagueSettingsApiDto } from '@/lib/types/tbd/LeagueSettingsApiDto';\n\nexport class LeagueSettingsService implements Service {\n private static cachedMemberships = new Map<string, unknown[]>();\n\n async getSettingsData(leagueId: string): Promise<Result<LeagueSettingsApiDto, DomainError>> {\n // Mock data since backend not implemented\n const mockData: LeagueSettingsApiDto = {\n leagueId,\n league: {\n id: leagueId,\n name: 'Mock League',\n description: 'A mock league for demonstration',\n visibility: 'public',\n ownerId: 'owner-123',\n createdAt: '2024-01-01T00:00:00Z',\n updatedAt: '2024-01-01T00:00:00Z',\n },\n config: {\n maxDrivers: 20,\n scoringPresetId: 'preset-1',\n allowLateJoin: true,\n requireApproval: false,\n },\n };\n return Result.ok(mockData);\n }\n\n static getCachedMembershipsIterator(): IterableIterator<[string, unknown[]]> {\n return this.cachedMemberships.entries();\n }\n\n static getMembership(leagueId: string, driverId: string): unknown | null {\n const members = this.cachedMemberships.get(leagueId);\n if (!members) return null;\n return members.find((m: any) => m.driverId === driverId) || null;\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueSponsorshipsService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueStandingsService.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_leagueId' is defined but never used.","line":21,"column":26,"nodeType":"Identifier","messageId":"unusedVar","endLine":21,"endColumn":43}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { Service, type DomainError } from '@/lib/contracts/services/Service';\nimport { type LeagueStandingsApiDto, type LeagueMembershipsApiDto } from '@/lib/types/tbd/LeagueStandingsApiDto';\nimport { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\n\nexport class LeagueStandingsService implements Service {\n private apiClient: LeaguesApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n this.apiClient = new LeaguesApiClient(\n baseUrl,\n new ConsoleErrorReporter(),\n new ConsoleLogger()\n );\n }\n\n async getStandingsData(_leagueId: string): Promise<Result<{ standings: LeagueStandingsApiDto; memberships: LeagueMembershipsApiDto }, DomainError>> {\n // Mock data since backend may not be implemented\n const mockStandings: LeagueStandingsApiDto = {\n standings: [\n {\n driverId: 'driver1',\n driver: {\n id: 'driver1',\n name: 'John Doe',\n iracingId: '12345',\n country: 'US',\n joinedAt: new Date().toISOString(),\n },\n points: 100,\n position: 1,\n wins: 2,\n podiums: 3,\n races: 5,\n },\n {\n driverId: 'driver2',\n driver: {\n id: 'driver2',\n name: 'Jane Smith',\n iracingId: '67890',\n country: 'UK',\n joinedAt: new Date().toISOString(),\n },\n points: 80,\n position: 2,\n wins: 1,\n podiums: 2,\n races: 5,\n },\n ],\n };\n\n const mockMemberships: LeagueMembershipsApiDto = {\n members: [\n {\n driverId: 'driver1',\n driver: {\n id: 'driver1',\n name: 'John Doe',\n iracingId: '12345',\n country: 'US',\n joinedAt: new Date().toISOString(),\n },\n role: 'member',\n joinedAt: new Date().toISOString(),\n },\n {\n driverId: 'driver2',\n driver: {\n id: 'driver2',\n name: 'Jane Smith',\n iracingId: '67890',\n country: 'UK',\n joinedAt: new Date().toISOString(),\n },\n role: 'member',\n joinedAt: new Date().toISOString(),\n },\n ],\n };\n\n return Result.ok({ standings: mockStandings, memberships: mockMemberships });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueStewardingService.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_leagueId' is defined but never used.","line":19,"column":35,"nodeType":"Identifier","messageId":"unusedVar","endLine":19,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_protestId' is defined but never used.","line":19,"column":54,"nodeType":"Identifier","messageId":"unusedVar","endLine":19,"endColumn":72},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":19,"column":90,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":19,"endColumn":93,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[698,701],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[698,701],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { Service, type DomainError } from '@/lib/contracts/services/Service';\nimport { type StewardingApiDto } from '@/lib/types/tbd/StewardingApiDto';\n\nexport class LeagueStewardingService implements Service {\n async getStewardingData(leagueId: string): Promise<Result<StewardingApiDto, DomainError>> {\n // Mock data since backend not implemented\n const mockData: StewardingApiDto = {\n leagueId,\n totalPending: 0,\n totalResolved: 0,\n totalPenalties: 0,\n races: [],\n drivers: []\n };\n return Result.ok(mockData);\n }\n\n async getProtestDetailViewModel(_leagueId: string, _protestId: string): Promise<Result<any, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getProtestDetailViewModel' });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/LeagueWalletService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/ProfileLeaguesService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":96,"endColumn":1},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":81,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":81,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2985,2988],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2985,2988],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ApiClient } from '@/lib/api';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { Result } from '@/lib/contracts/Result';\nimport { Service, type DomainError } from '@/lib/contracts/services/Service';\n\nexport interface ProfileLeaguesPageDto {\n ownedLeagues: Array<{\n leagueId: string;\n name: string;\n description: string;\n membershipRole: 'owner' | 'admin' | 'steward' | 'member';\n }>;\n memberLeagues: Array<{\n leagueId: string;\n name: string;\n description: string;\n membershipRole: 'owner' | 'admin' | 'steward' | 'member';\n }>;\n}\n\ninterface MembershipDTO {\n driverId: string;\n role: string;\n status?: 'active' | 'inactive';\n}\n\nexport class ProfileLeaguesService implements Service {\n async getProfileLeagues(driverId: string): Promise<Result<ProfileLeaguesPageDto, DomainError>> {\n try {\n const baseUrl = getWebsiteApiBaseUrl();\n const apiClient = new ApiClient(baseUrl);\n \n const leaguesDto = await apiClient.leagues.getAllWithCapacity();\n \n if (!leaguesDto?.leagues) {\n return Result.err({ type: 'notFound', message: 'Leagues not found' });\n }\n\n // Fetch all memberships in parallel\n const leagueMemberships = await Promise.all(\n leaguesDto.leagues.map(async (league) => {\n try {\n const membershipsDto = await apiClient.leagues.getMemberships(league.id);\n \n let memberships: MembershipDTO[] = [];\n if (membershipsDto && typeof membershipsDto === 'object') {\n if ('members' in membershipsDto && Array.isArray((membershipsDto as { members?: unknown }).members)) {\n memberships = (membershipsDto as { members: MembershipDTO[] }).members;\n } else if ('memberships' in membershipsDto && Array.isArray((membershipsDto as { memberships?: unknown }).memberships)) {\n memberships = (membershipsDto as { memberships: MembershipDTO[] }).memberships;\n }\n }\n \n const currentMembership = memberships.find((m) => m.driverId === driverId);\n \n if (currentMembership && currentMembership.status === 'active') {\n return {\n leagueId: league.id,\n name: league.name,\n description: league.description,\n membershipRole: currentMembership.role as 'owner' | 'admin' | 'steward' | 'member',\n };\n }\n return null;\n } catch {\n return null;\n }\n })\n );\n\n // Filter and categorize\n const validLeagues = leagueMemberships.filter((l): l is NonNullable<typeof l> => l !== null);\n \n const ownedLeagues = validLeagues.filter((l) => l.membershipRole === 'owner');\n const memberLeagues = validLeagues.filter((l) => l.membershipRole !== 'owner');\n\n return Result.ok({\n ownedLeagues,\n memberLeagues,\n });\n } catch (error: any) {\n const errorAny = error as { statusCode?: number; message?: string };\n \n if (errorAny.statusCode === 404 || errorAny.message?.toLowerCase().includes('not found')) {\n return Result.err({ type: 'notFound', message: 'Profile leagues not found' });\n }\n \n if (errorAny.statusCode === 302 || errorAny.message?.toLowerCase().includes('redirect')) {\n return Result.err({ type: 'unauthorized', message: 'Unauthorized access' });\n }\n\n return Result.err({ type: 'unknown', message: error.message || 'Failed to fetch profile leagues' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/leagues/ProtestDetailService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/media/MediaService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/onboarding/OnboardingService.ts","messages":[],"suppressedMessages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'input' is defined but never used.","line":58,"column":25,"nodeType":"Identifier","messageId":"unusedVar","endLine":58,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/payments/PaymentService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/payments/WalletService.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":13,"column":26,"nodeType":"Identifier","messageId":"unusedVar","endLine":13,"endColumn":43}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\n\n/**\n * Wallet Service - DTO Only\n *\n * Returns raw API DTOs. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n */\nexport class WalletService implements Service {\n constructor() {}\n\n async getWalletBalance(_driverId: string): Promise<Result<{ balance: number; currency: string }, DomainError>> {\n return Result.ok({ balance: 0, currency: 'USD' });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/penalties/PenaltyService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":28,"column":54,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":28,"endColumn":57,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1117,1120],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1117,1120],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":32,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":32,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1274,1277],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1274,1277],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":44,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":44,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1674,1677],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1674,1677],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":52,"column":29,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":52,"endColumn":32,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1860,1863],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1860,1863],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":56,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":56,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2016,2019],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2016,2019],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PenaltiesApiClient } from '@/lib/api/penalties/PenaltiesApiClient';\nimport type { PenaltyTypesReferenceDTO } from '@/lib/types/PenaltyTypesReferenceDTO';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\n\n/**\n * Penalty Service\n *\n * Orchestrates penalty operations by coordinating API calls and view model creation.\n * All dependencies are injected via constructor.\n */\nexport class PenaltyService implements Service {\n private readonly apiClient: PenaltiesApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger);\n this.apiClient = new PenaltiesApiClient(baseUrl, errorReporter, logger);\n }\n\n /**\n * Find penalties by race ID\n */\n async findByRaceId(raceId: string): Promise<Result<any[], DomainError>> {\n try {\n const dto = await this.apiClient.getRacePenalties(raceId);\n return Result.ok(dto.penalties);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to find penalties' });\n }\n }\n\n /**\n * Get allowed penalty types and semantics\n */\n async getPenaltyTypesReference(): Promise<Result<PenaltyTypesReferenceDTO, DomainError>> {\n try {\n const data = await this.apiClient.getPenaltyTypesReference();\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get penalty types' });\n }\n }\n\n /**\n * Apply a penalty\n */\n async applyPenalty(input: any): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.applyPenalty(input);\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to apply penalty' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/policy/PolicyService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":100,"endColumn":1},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1179,1182],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1179,1182],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PolicyApiClient, type FeatureState, type PolicySnapshotDto } from '@/lib/api/policy/PolicyApiClient';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\n\nexport interface CapabilityEvaluationResult {\n isLoading: boolean;\n isError: boolean;\n capabilityState: FeatureState | null;\n shouldShowChildren: boolean;\n shouldShowComingSoon: boolean;\n}\n\nexport class PolicyService implements Service {\n private readonly apiClient: PolicyApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger);\n this.apiClient = new PolicyApiClient(baseUrl, errorReporter, logger);\n }\n\n async getSnapshot(): Promise<Result<PolicySnapshotDto, DomainError>> {\n try {\n const data = await this.apiClient.getSnapshot();\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get policy snapshot' });\n }\n }\n\n getCapabilityState(snapshot: PolicySnapshotDto, capabilityKey: string): FeatureState {\n return snapshot.capabilities[capabilityKey] ?? 'hidden';\n }\n\n isCapabilityEnabled(snapshot: PolicySnapshotDto, capabilityKey: string): boolean {\n return this.getCapabilityState(snapshot, capabilityKey) === 'enabled';\n }\n\n /**\n * Evaluate capability state and determine what should be rendered\n * Centralizes the logic for capability-based UI rendering\n */\n evaluateCapability(\n snapshot: PolicySnapshotDto | null,\n capabilityKey: string,\n isLoading: boolean,\n isError: boolean\n ): CapabilityEvaluationResult {\n if (isLoading || isError || !snapshot) {\n return {\n isLoading,\n isError,\n capabilityState: null,\n shouldShowChildren: false,\n shouldShowComingSoon: false,\n };\n }\n\n const capabilityState = this.getCapabilityState(snapshot, capabilityKey);\n \n return {\n isLoading,\n isError,\n capabilityState,\n shouldShowChildren: capabilityState === 'enabled',\n shouldShowComingSoon: capabilityState === 'coming_soon',\n };\n }\n\n /**\n * Get the appropriate content based on capability state\n * Handles fallback and coming soon logic\n */\n getCapabilityContent(\n snapshot: PolicySnapshotDto | null,\n capabilityKey: string,\n isLoading: boolean,\n isError: boolean,\n children: React.ReactNode,\n fallback: React.ReactNode = null,\n comingSoon: React.ReactNode = null\n ): React.ReactNode {\n const evaluation = this.evaluateCapability(snapshot, capabilityKey, isLoading, isError);\n\n if (evaluation.shouldShowChildren) {\n return children;\n }\n\n if (evaluation.shouldShowComingSoon) {\n return comingSoon ?? fallback;\n }\n\n return fallback;\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/protests/ProtestService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":27,"column":61,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":27,"endColumn":64,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1288,1291],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1288,1291],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":31,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":31,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1438,1441],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1438,1441],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":77,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":80,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1641,1644],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1641,1644],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":40,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":40,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1801,1804],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1801,1804],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2123,2126],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2123,2126],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":58,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":58,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2460,2463],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2460,2463],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":67,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":67,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2789,2792],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2789,2792],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":72,"column":54,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":72,"endColumn":57,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2964,2967],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2964,2967],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":76,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":76,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3110,3113],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3110,3113],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":9,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ProtestsApiClient } from '@/lib/api/protests/ProtestsApiClient';\nimport type { ApplyPenaltyCommandDTO } from '@/lib/types/generated/ApplyPenaltyCommandDTO';\nimport type { RequestProtestDefenseCommandDTO } from '@/lib/types/generated/RequestProtestDefenseCommandDTO';\nimport type { ReviewProtestCommandDTO } from '@/lib/types/generated/ReviewProtestCommandDTO';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\n\n/**\n * Protest Service - DTO Only\n *\n * Returns raw API DTOs. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n */\nexport class ProtestService implements Service {\n private readonly apiClient: ProtestsApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger);\n this.apiClient = new ProtestsApiClient(baseUrl, errorReporter, logger);\n }\n\n async getLeagueProtests(leagueId: string): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getLeagueProtests(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get league protests' });\n }\n }\n\n async getProtestById(leagueId: string, protestId: string): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getLeagueProtest(leagueId, protestId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to get protest' });\n }\n }\n\n async applyPenalty(input: ApplyPenaltyCommandDTO): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.applyPenalty(input);\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to apply penalty' });\n }\n }\n\n async requestDefense(input: RequestProtestDefenseCommandDTO): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.requestDefense(input);\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to request defense' });\n }\n }\n\n async reviewProtest(input: ReviewProtestCommandDTO): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.reviewProtest(input);\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to review protest' });\n }\n }\n\n async findByRaceId(raceId: string): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getRaceProtests(raceId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to find protests' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/races/RaceResultsService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":31,"column":62,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":31,"endColumn":65,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1129,1132],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1129,1132],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":35,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":35,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1276,1279],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1276,1279],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":53,"column":52,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":53,"endColumn":55,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1734,1737],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1734,1737],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":57,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":57,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1875,1878],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1875,1878],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RacesApiClient } from '@/lib/api/races/RacesApiClient';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\n/**\n * Race Results Service\n * \n * Orchestration service for race results operations.\n * Returns raw API DTOs. No ViewModels or UX logic.\n */\nexport class RaceResultsService implements Service {\n private apiClient: RacesApiClient;\n\n constructor() {\n // Service creates its own dependencies\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new ConsoleErrorReporter();\n \n this.apiClient = new RacesApiClient(baseUrl, errorReporter, logger);\n }\n\n /**\n * Get race results detail\n * Returns results for a specific race\n */\n async getRaceResultsDetail(raceId: string): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getResultsDetail(raceId);\n return Result.ok(data);\n } catch (error: any) {\n if (error instanceof ApiError) {\n return Result.err({\n type: this.mapApiErrorType(error.type),\n message: error.message\n });\n }\n return Result.err({\n type: 'unknown',\n message: error.message || 'Failed to fetch race results'\n });\n }\n }\n\n /**\n * Get race with strength of field\n * Returns race data with SOF calculation\n */\n async getWithSOF(raceId: string): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getWithSOF(raceId);\n return Result.ok(data);\n } catch (error: any) {\n if (error instanceof ApiError) {\n return Result.err({\n type: this.mapApiErrorType(error.type),\n message: error.message\n });\n }\n return Result.err({\n type: 'unknown',\n message: error.message || 'Failed to fetch race SOF'\n });\n }\n }\n\n private mapApiErrorType(apiErrorType: string): DomainError['type'] {\n switch (apiErrorType) {\n case 'NOT_FOUND':\n return 'notFound';\n case 'AUTH_ERROR':\n return 'unauthorized';\n case 'VALIDATION_ERROR':\n return 'validation';\n case 'SERVER_ERROR':\n return 'serverError';\n case 'NETWORK_ERROR':\n return 'networkError';\n default:\n return 'unknown';\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/races/RaceService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":25,"column":53,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":25,"endColumn":56,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1005,1008],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1005,1008],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":30,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":30,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1243,1246],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1243,1246],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":35,"column":62,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":35,"endColumn":65,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1399,1402],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1399,1402],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":39,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":39,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1543,1546],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1543,1546],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":44,"column":58,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":44,"endColumn":61,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1703,1706],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1703,1706],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":48,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":48,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1865,1868],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1865,1868],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_raceId' is defined but never used.","line":53,"column":25,"nodeType":"Identifier","messageId":"unusedVar","endLine":53,"endColumn":40},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_leagueId' is defined but never used.","line":53,"column":42,"nodeType":"Identifier","messageId":"unusedVar","endLine":53,"endColumn":59},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":53,"column":61,"nodeType":"Identifier","messageId":"unusedVar","endLine":53,"endColumn":78},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_raceId' is defined but never used.","line":57,"column":26,"nodeType":"Identifier","messageId":"unusedVar","endLine":57,"endColumn":41},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":57,"column":43,"nodeType":"Identifier","messageId":"unusedVar","endLine":57,"endColumn":60},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_command' is defined but never used.","line":61,"column":21,"nodeType":"Identifier","messageId":"unusedVar","endLine":61,"endColumn":34},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":61,"column":31,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":61,"endColumn":34,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2382,2385],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2382,2385],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":13,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RacesApiClient } from '@/lib/api/races/RacesApiClient';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\n/**\n * Race Service - DTO Only\n *\n * Returns raw API DTOs. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n */\nexport class RaceService implements Service {\n private apiClient: RacesApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new ConsoleErrorReporter();\n this.apiClient = new RacesApiClient(baseUrl, errorReporter, logger);\n }\n\n async getRaceById(raceId: string): Promise<Result<any, DomainError>> {\n try {\n // This would need a driverId, but for now we'll use a placeholder\n const data = await this.apiClient.getDetail(raceId, 'placeholder-driver-id');\n return Result.ok(data);\n } catch (error: any) {\n return Result.err(this.mapError(error, 'Failed to fetch race by ID'));\n }\n }\n\n async getRacesByLeagueId(leagueId: string): Promise<Result<any, DomainError>> {\n try {\n const data = await this.apiClient.getPageData(leagueId);\n return Result.ok(data);\n } catch (error: any) {\n return Result.err(this.mapError(error, 'Failed to fetch races by league ID'));\n }\n }\n\n async findByLeagueId(leagueId: string): Promise<Result<any[], DomainError>> {\n try {\n const result = await this.apiClient.getPageData(leagueId);\n return Result.ok(result.races || []);\n } catch (error: any) {\n return Result.err(this.mapError(error, 'Failed to find races by league ID'));\n }\n }\n\n async registerForRace(_raceId: string, _leagueId: string, _driverId: string): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'registerForRace' });\n }\n\n async withdrawFromRace(_raceId: string, _driverId: string): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'withdrawFromRace' });\n }\n\n async fileProtest(_command: any): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'fileProtest' });\n }\n\n private mapError(error: unknown, defaultMessage: string): DomainError {\n if (error instanceof ApiError) {\n return {\n type: this.mapApiErrorType(error.type),\n message: error.message\n };\n }\n return {\n type: 'unknown',\n message: defaultMessage\n };\n }\n\n private mapApiErrorType(apiErrorType: string): DomainError['type'] {\n switch (apiErrorType) {\n case 'NOT_FOUND':\n return 'notFound';\n case 'AUTH_ERROR':\n return 'unauthorized';\n case 'VALIDATION_ERROR':\n return 'validation';\n case 'SERVER_ERROR':\n return 'serverError';\n case 'NETWORK_ERROR':\n return 'networkError';\n default:\n return 'unknown';\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/races/RaceStewardingService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":37,"column":59,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":37,"endColumn":62,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1571,1574],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1571,1574],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":47,"column":54,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":47,"endColumn":57,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1985,1988],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1985,1988],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":59,"column":55,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":59,"endColumn":58,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2319,2322],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2319,2322],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":60,"column":56,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":60,"endColumn":59,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2438,2441],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2438,2441],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":80,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":80,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3044,3047],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3044,3047],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { RacesApiClient } from '@/lib/api/races/RacesApiClient';\nimport { ProtestsApiClient } from '@/lib/api/protests/ProtestsApiClient';\nimport { PenaltiesApiClient } from '@/lib/api/penalties/PenaltiesApiClient';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { ApiError } from '@/lib/api/base/ApiError';\n\n/**\n * Race Stewarding Service\n * \n * Orchestration service for race stewarding operations.\n * Returns raw API DTOs. No ViewModels or UX logic.\n */\nexport class RaceStewardingService implements Service {\n private racesApiClient: RacesApiClient;\n private protestsApiClient: ProtestsApiClient;\n private penaltiesApiClient: PenaltiesApiClient;\n\n constructor() {\n // Service creates its own dependencies\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new ConsoleErrorReporter();\n \n this.racesApiClient = new RacesApiClient(baseUrl, errorReporter, logger);\n this.protestsApiClient = new ProtestsApiClient(baseUrl, errorReporter, logger);\n this.penaltiesApiClient = new PenaltiesApiClient(baseUrl, errorReporter, logger);\n }\n\n /**\n * Get race stewarding data\n * Returns protests and penalties for a race\n */\n async getRaceStewarding(raceId: string): Promise<Result<any, DomainError>> {\n try {\n // Fetch data in parallel\n const [raceDetail, protests, penalties] = await Promise.all([\n this.racesApiClient.getDetail(raceId, ''),\n this.protestsApiClient.getRaceProtests(raceId),\n this.penaltiesApiClient.getRacePenalties(raceId),\n ]);\n\n // Transform data to match view model structure\n const protestsData = protests.protests.map((p: any) => ({\n id: p.id,\n protestingDriverId: p.protestingDriverId,\n accusedDriverId: p.accusedDriverId,\n incident: {\n lap: p.lap,\n description: p.description,\n },\n filedAt: p.filedAt,\n status: p.status,\n }));\n\n const pendingProtests = protestsData.filter((p: any) => p.status === 'pending' || p.status === 'under_review');\n const resolvedProtests = protestsData.filter((p: any) =>\n p.status === 'upheld' ||\n p.status === 'dismissed' ||\n p.status === 'withdrawn'\n );\n\n const data = {\n race: raceDetail.race,\n league: raceDetail.league,\n protests: protestsData,\n penalties: penalties.penalties,\n driverMap: { ...protests.driverMap, ...penalties.driverMap },\n pendingProtests,\n resolvedProtests,\n pendingCount: pendingProtests.length,\n resolvedCount: resolvedProtests.length,\n penaltiesCount: penalties.penalties.length,\n };\n\n return Result.ok(data);\n } catch (error: any) {\n if (error instanceof ApiError) {\n return Result.err({\n type: this.mapApiErrorType(error.type),\n message: error.message\n });\n }\n return Result.err({\n type: 'unknown',\n message: error.message || 'Failed to fetch stewarding data'\n });\n }\n }\n\n private mapApiErrorType(apiErrorType: string): DomainError['type'] {\n switch (apiErrorType) {\n case 'NOT_FOUND':\n return 'notFound';\n case 'AUTH_ERROR':\n return 'unauthorized';\n case 'VALIDATION_ERROR':\n return 'validation';\n case 'SERVER_ERROR':\n return 'serverError';\n case 'NETWORK_ERROR':\n return 'networkError';\n default:\n return 'unknown';\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/races/RacesService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/sponsors/SponsorService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":45,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":45,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2192,2195],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2192,2195],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":57,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":57,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2646,2649],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2646,2649],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":69,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":69,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3117,3120],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3117,3120],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_sponsorId' is defined but never used.","line":74,"column":20,"nodeType":"Identifier","messageId":"unusedVar","endLine":74,"endColumn":38},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":98,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":98,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4315,4318],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4315,4318],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":107,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":107,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4736,4739],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4736,4739],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":116,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":116,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[5167,5170],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[5167,5170],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { getWebsiteServerEnv } from '@/lib/config/env';\nimport type { SponsorDashboardDTO } from '@/lib/types/generated/SponsorDashboardDTO';\nimport type { SponsorSponsorshipsDTO } from '@/lib/types/generated/SponsorSponsorshipsDTO';\nimport type { GetSponsorOutputDTO } from '@/lib/types/generated/GetSponsorOutputDTO';\nimport type { GetPendingSponsorshipRequestsOutputDTO } from '@/lib/types/generated/GetPendingSponsorshipRequestsOutputDTO';\nimport type { SponsorBillingDTO } from '@/lib/types/tbd/SponsorBillingDTO';\nimport type { AvailableLeaguesDTO } from '@/lib/types/tbd/AvailableLeaguesDTO';\nimport type { LeagueDetailForSponsorDTO } from '@/lib/types/tbd/LeagueDetailForSponsorDTO';\nimport type { SponsorSettingsDTO } from '@/lib/types/tbd/SponsorSettingsDTO';\n\n/**\n * Sponsor Service - DTO Only\n *\n * Returns raw API DTOs. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n */\nexport class SponsorService implements Service {\n private apiClient: SponsorsApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const { NODE_ENV } = getWebsiteServerEnv();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: NODE_ENV === 'production',\n });\n this.apiClient = new SponsorsApiClient(baseUrl, errorReporter, logger);\n }\n\n async getSponsorById(sponsorId: string): Promise<Result<GetSponsorOutputDTO, DomainError>> {\n try {\n const result = await this.apiClient.getSponsor(sponsorId);\n if (!result) {\n return Result.err({ type: 'notFound', message: 'Sponsor not found' });\n }\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'unknown', message: error.message || 'Failed to get sponsor' });\n }\n }\n\n async getSponsorDashboard(sponsorId: string): Promise<Result<SponsorDashboardDTO, DomainError>> {\n try {\n const result = await this.apiClient.getDashboard(sponsorId);\n if (!result) {\n return Result.err({ type: 'notFound', message: 'Dashboard not found' });\n }\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'notImplemented', message: error.message || 'getSponsorDashboard' });\n }\n }\n\n async getSponsorSponsorships(sponsorId: string): Promise<Result<SponsorSponsorshipsDTO, DomainError>> {\n try {\n const result = await this.apiClient.getSponsorships(sponsorId);\n if (!result) {\n return Result.err({ type: 'notFound', message: 'Sponsorships not found' });\n }\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'notImplemented', message: error.message || 'getSponsorSponsorships' });\n }\n }\n\n async getBilling(_sponsorId: string): Promise<Result<SponsorBillingDTO, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getBilling' });\n }\n\n async getAvailableLeagues(): Promise<Result<AvailableLeaguesDTO, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getAvailableLeagues' });\n }\n\n async getLeagueDetail(): Promise<Result<LeagueDetailForSponsorDTO, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getLeagueDetail' });\n }\n\n async getSettings(): Promise<Result<SponsorSettingsDTO, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getSettings' });\n }\n\n async updateSettings(): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'updateSettings' });\n }\n\n async acceptSponsorshipRequest(requestId: string, sponsorId: string): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.acceptSponsorshipRequest(requestId, { respondedBy: sponsorId });\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'unknown', message: error.message || 'Failed to accept sponsorship request' });\n }\n }\n\n async rejectSponsorshipRequest(requestId: string, sponsorId: string, reason?: string): Promise<Result<void, DomainError>> {\n try {\n await this.apiClient.rejectSponsorshipRequest(requestId, { respondedBy: sponsorId, reason });\n return Result.ok(undefined);\n } catch (error: any) {\n return Result.err({ type: 'unknown', message: error.message || 'Failed to reject sponsorship request' });\n }\n }\n\n async getPendingSponsorshipRequests(input: { entityType: string; entityId: string }): Promise<Result<GetPendingSponsorshipRequestsOutputDTO, DomainError>> {\n try {\n const result = await this.apiClient.getPendingSponsorshipRequests(input);\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'notImplemented', message: error.message || 'getPendingSponsorshipRequests' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/sponsors/SponsorshipRequestsReadService.ts","messages":[{"ruleId":"gridpilot-rules/service-function-format","severity":2,"message":"Service files should only export the Service class.","line":1,"column":1,"nodeType":"Program","messageId":"multipleExports","endLine":88,"endColumn":1},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":80,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":80,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2535,2538],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2535,2538],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { isProductionEnvironment } from '@/lib/config/env';\nimport { Result } from '@/lib/contracts/Result';\nimport type { Service, DomainError } from '@/lib/contracts/services/Service';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\n\nexport interface PendingSponsorshipRequestDto {\n requestId: string;\n sponsorId: string;\n sponsorName: string;\n message: string | null;\n createdAtIso: string;\n}\n\nexport interface SponsorshipRequestsReadApiDto {\n sections: Array<{\n entityType: 'driver' | 'team' | 'season';\n entityId: string;\n entityName: string;\n requests: PendingSponsorshipRequestDto[];\n }>;\n}\n\nexport class SponsorshipRequestsReadService implements Service {\n private readonly client: SponsorsApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: isProductionEnvironment(),\n });\n\n this.client = new SponsorsApiClient(baseUrl, errorReporter, logger);\n }\n\n async getPendingRequestsForDriver(\n driverId: string,\n ): Promise<Result<SponsorshipRequestsReadApiDto, DomainError>> {\n try {\n const response = await this.client.getPendingSponsorshipRequests({\n entityType: 'driver',\n entityId: driverId,\n });\n\n const requests = (response.requests ?? []).map((r) => {\n const raw = r as unknown as {\n id?: string;\n requestId?: string;\n sponsorId?: string;\n sponsorName?: string;\n message?: unknown;\n createdAt?: string;\n createdAtIso?: string;\n };\n\n return {\n requestId: String(raw.id ?? raw.requestId ?? ''),\n sponsorId: String(raw.sponsorId ?? ''),\n sponsorName: String(raw.sponsorName ?? 'Sponsor'),\n message: typeof raw.message === 'string' ? raw.message : null,\n createdAtIso: String(raw.createdAt ?? raw.createdAtIso ?? ''),\n };\n });\n\n return Result.ok({\n sections: [\n {\n entityType: 'driver',\n entityId: driverId,\n entityName: 'Your Profile',\n requests,\n },\n ],\n });\n } catch (error: any) {\n const errorAny = error as { statusCode?: number; message?: string };\n if (errorAny.statusCode === 401) return Result.err({ type: 'unauthorized', message: 'Unauthorized' });\n if (errorAny.statusCode === 404) return Result.err({ type: 'notFound', message: 'Not found' });\n return Result.err({ type: 'serverError', message: error.message || 'Server error' });\n }\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/sponsors/SponsorshipRequestsService.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/teams/TeamJoinService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1536,1539],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1536,1539],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { TeamsApiClient } from '@/lib/api/teams/TeamsApiClient';\nimport { TeamJoinRequestViewModel } from '@/lib/view-models/TeamJoinRequestViewModel';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { isProductionEnvironment } from '@/lib/config/env';\n\n/**\n * Team Join Service - ViewModels\n *\n * Returns ViewModels for team join requests.\n * Handles presentation logic for join request management.\n */\nexport class TeamJoinService implements Service {\n private apiClient: TeamsApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: isProductionEnvironment(),\n });\n this.apiClient = new TeamsApiClient(baseUrl, errorReporter, logger);\n }\n\n async getJoinRequests(teamId: string, currentDriverId: string, isOwner: boolean): Promise<Result<TeamJoinRequestViewModel[], DomainError>> {\n try {\n const result = await this.apiClient.getJoinRequests(teamId);\n return Result.ok(result.requests.map(request => \n new TeamJoinRequestViewModel(request, currentDriverId, isOwner)\n ));\n } catch (error: any) {\n return Result.err({ type: 'serverError', message: error.message || 'Failed to fetch join requests' });\n }\n }\n\n async approveJoinRequest(): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'Not implemented: API endpoint for approving join requests' });\n }\n\n async rejectJoinRequest(): Promise<Result<void, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'Not implemented: API endpoint for rejecting join requests' });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/services/teams/TeamService.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":35,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":35,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1431,1434],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1431,1434],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_currentDriverId' is defined but never used.","line":40,"column":41,"nodeType":"Identifier","messageId":"unusedVar","endLine":40,"endColumn":65},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":40,"column":83,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":40,"endColumn":86,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1628,1631],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1628,1631],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":47,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":47,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1879,1882],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1879,1882],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":56,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":56,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2342,2345],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2342,2345],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_teamId' is defined but never used.","line":61,"column":29,"nodeType":"Identifier","messageId":"unusedVar","endLine":61,"endColumn":44},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":61,"column":62,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":61,"endColumn":65,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2525,2528],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2525,2528],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_input' is defined but never used.","line":65,"column":20,"nodeType":"Identifier","messageId":"unusedVar","endLine":65,"endColumn":31},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":65,"column":28,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":65,"endColumn":31,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2661,2664],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2661,2664],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":65,"column":49,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":65,"endColumn":52,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2682,2685],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2682,2685],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_teamId' is defined but never used.","line":69,"column":20,"nodeType":"Identifier","messageId":"unusedVar","endLine":69,"endColumn":35},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_input' is defined but never used.","line":69,"column":37,"nodeType":"Identifier","messageId":"unusedVar","endLine":69,"endColumn":48},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":69,"column":45,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":69,"endColumn":48,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2826,2829],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2826,2829],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":69,"column":66,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":69,"endColumn":69,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2847,2850],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2847,2850],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":73,"column":23,"nodeType":"Identifier","messageId":"unusedVar","endLine":73,"endColumn":40},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":73,"column":58,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":73,"endColumn":61,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3004,3007],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3004,3007],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_teamId' is defined but never used.","line":77,"column":23,"nodeType":"Identifier","messageId":"unusedVar","endLine":77,"endColumn":38},{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'_driverId' is defined but never used.","line":77,"column":40,"nodeType":"Identifier","messageId":"unusedVar","endLine":77,"endColumn":57},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":77,"column":75,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":77,"endColumn":78,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3181,3184],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3181,3184],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":19,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { TeamsApiClient } from '@/lib/api/teams/TeamsApiClient';\nimport type { TeamListItemDTO } from '@/lib/types/generated/TeamListItemDTO';\nimport { TeamMemberViewModel } from '@/lib/view-models/TeamMemberViewModel';\nimport { Result } from '@/lib/contracts/Result';\nimport { DomainError, Service } from '@/lib/contracts/services/Service';\nimport { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';\nimport { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';\nimport { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';\nimport { isProductionEnvironment } from '@/lib/config/env';\n\n/**\n * Team Service - DTO Only\n *\n * Returns raw API DTOs. No ViewModels or UX logic.\n * All client-side presentation logic must be handled by hooks/components.\n */\nexport class TeamService implements Service {\n private apiClient: TeamsApiClient;\n\n constructor() {\n const baseUrl = getWebsiteApiBaseUrl();\n const logger = new ConsoleLogger();\n const errorReporter = new EnhancedErrorReporter(logger, {\n showUserNotifications: true,\n logToConsole: true,\n reportToExternal: isProductionEnvironment(),\n });\n this.apiClient = new TeamsApiClient(baseUrl, errorReporter, logger);\n }\n\n async getAllTeams(): Promise<Result<TeamListItemDTO[], DomainError>> {\n try {\n const result = await this.apiClient.getAll();\n return Result.ok(result.teams);\n } catch (error: any) {\n return Result.err({ type: 'unknown', message: error.message || 'Failed to fetch teams' });\n }\n }\n\n async getTeamDetails(_teamId: string, _currentDriverId: string): Promise<Result<any, DomainError>> {\n try {\n const result = await this.apiClient.getDetails(_teamId);\n if (!result) {\n return Result.err({ type: 'notFound', message: 'Team not found' });\n }\n return Result.ok(result);\n } catch (error: any) {\n return Result.err({ type: 'unknown', message: error.message || 'Failed to fetch team details' });\n }\n }\n\n async getTeamMembers(teamId: string, currentDriverId: string, ownerId: string): Promise<Result<TeamMemberViewModel[], DomainError>> {\n try {\n const result = await this.apiClient.getMembers(teamId);\n return Result.ok(result.members.map(member => new TeamMemberViewModel(member, currentDriverId, ownerId)));\n } catch (error: any) {\n return Result.err({ type: 'unknown', message: error.message || 'Failed to fetch team members' });\n }\n }\n\n async getTeamJoinRequests(_teamId: string): Promise<Result<any, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getTeamJoinRequests' });\n }\n\n async createTeam(_input: any): Promise<Result<any, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'createTeam' });\n }\n\n async updateTeam(_teamId: string, _input: any): Promise<Result<any, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'updateTeam' });\n }\n\n async getDriverTeam(_driverId: string): Promise<Result<any, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getDriverTeam' });\n }\n\n async getMembership(_teamId: string, _driverId: string): Promise<Result<any, DomainError>> {\n return Result.err({ type: 'notImplemented', message: 'getMembership' });\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/siteConfig.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/AllLeaguesWithCapacityAndScoringDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/LeaderboardsData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/League.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/LeagueConfigFormModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/LeagueMembership.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/MediaBinaryDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/MembershipRole.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/PenaltyTypesReferenceDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/Weekday.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/WizardErrors.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/admin.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/AdminUserDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/AvailableLeaguesDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/FilteredRacesPageDataDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/GetLiveriesOutputDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/LeagueDetailForSponsorDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/LeagueScheduleApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/LeagueSettingsApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/LeagueSponsorshipsApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/LeagueStandingsApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/LeagueWalletApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/ProtestDetailApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/RulebookApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/SponsorBillingDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/SponsorSettingsDTO.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/StewardingApiDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/tbd/TeamsLeaderboardDto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/view-data/DriverProfileViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/types/view-data/DriversViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/LeagueMembershipUtility.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":28,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":31,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[539,542],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[539,542],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":22,"column":83,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":22,"endColumn":86,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[880,883],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[880,883],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { LeagueSettingsService } from '@/lib/services/leagues/LeagueSettingsService';\nimport { LeagueRoleUtility } from '@/lib/utilities/LeagueRoleUtility';\n\nexport class LeagueMembershipUtility {\n /**\n * Derive a driver's primary league from cached memberships.\n * Prefers any active membership and returns the first matching league.\n */\n static getPrimaryLeagueIdForDriver(driverId: string): string | null {\n for (const [leagueId, members] of LeagueSettingsService.getCachedMembershipsIterator()) {\n if (members.some((m: any) => m.driverId === driverId && m.status === 'active')) {\n return leagueId;\n }\n }\n return null;\n }\n\n /**\n * Check if a driver is owner or admin of a league.\n */\n static isOwnerOrAdmin(leagueId: string, driverId: string): boolean {\n const membership = LeagueSettingsService.getMembership(leagueId, driverId) as any;\n if (!membership) return false;\n return LeagueRoleUtility.isLeagueAdminOrHigherRole(membership.role);\n }\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/LeagueRoleUtility.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/ScoringPresetApplier.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/authValidation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/media.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/raceStatus.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":4,"column":9,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":4,"endColumn":12,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[122,125],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[122,125],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Clock, PlayCircle, CheckCircle2, XCircle } from 'lucide-react';\n\nexport interface RaceStatusConfigData {\n icon: any;\n color: string;\n bg: string;\n border: string;\n label: string;\n}\n\nexport const raceStatusConfig: Record<string, RaceStatusConfigData> = {\n scheduled: {\n icon: Clock,\n color: 'text-primary-blue',\n bg: 'bg-primary-blue/10',\n border: 'border-primary-blue/30',\n label: 'Scheduled',\n },\n running: {\n icon: PlayCircle,\n color: 'text-performance-green',\n bg: 'bg-performance-green/10',\n border: 'border-performance-green/30',\n label: 'LIVE',\n },\n completed: {\n icon: CheckCircle2,\n color: 'text-gray-400',\n bg: 'bg-gray-500/10',\n border: 'border-gray-500/30',\n label: 'Completed',\n },\n cancelled: {\n icon: XCircle,\n color: 'text-warning-amber',\n bg: 'bg-warning-amber/10',\n border: 'border-warning-amber/30',\n label: 'Cancelled',\n },\n} as const;","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utilities/roster-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utils/errorUtils.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":56,"column":64,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":56,"endColumn":67,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1614,1617],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1614,1617],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":64,"column":63,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":64,"endColumn":66,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2035,2038],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2035,2038],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Enhanced Error Utilities for GridPilot\n * \n * Provides comprehensive error handling, validation, and user-friendly error messages\n * for both end users and developers.\n */\n\nimport { ApiError } from '@/lib/api/base/ApiError';\n\nexport interface ValidationError {\n field: string;\n message: string;\n value?: unknown;\n}\n\nexport interface EnhancedErrorContext {\n timestamp?: string;\n component?: string;\n action?: string;\n formData?: Record<string, unknown>;\n userId?: string;\n sessionId?: string;\n}\n\n/**\n * Parse API error response to extract validation errors or user-friendly messages\n */\nexport function parseApiError(error: unknown): {\n userMessage: string;\n developerMessage: string;\n validationErrors: ValidationError[];\n isValidationError: boolean;\n} {\n const result = {\n userMessage: 'An unexpected error occurred',\n developerMessage: '',\n validationErrors: [] as ValidationError[],\n isValidationError: false,\n };\n\n if (error instanceof ApiError) {\n result.developerMessage = error.getDeveloperMessage();\n \n // Check if it's a validation error\n if (error.type === 'VALIDATION_ERROR') {\n result.isValidationError = true;\n result.userMessage = 'Please check your input and try again';\n \n // Try to parse validation details from response\n try {\n if (error.context.responseText) {\n const parsed = JSON.parse(error.context.responseText);\n \n // Handle NestJS validation error format\n if (parsed.message && Array.isArray(parsed.message)) {\n result.validationErrors = parsed.message.map((msg: any) => ({\n field: msg.property || msg.field || 'unknown',\n message: msg.constraints ? Object.values(msg.constraints).join(', ') : msg.message || 'Invalid value',\n value: msg.value,\n }));\n } \n // Handle custom error format\n else if (parsed.errors && Array.isArray(parsed.errors)) {\n result.validationErrors = parsed.errors.map((err: any) => ({\n field: err.field || err.property || 'unknown',\n message: err.message || 'Invalid value',\n value: err.value,\n }));\n }\n // Handle single message\n else if (parsed.message && typeof parsed.message === 'string') {\n result.userMessage = parsed.message;\n }\n }\n } catch (e) {\n // If parsing fails, use default messages\n }\n } else {\n result.userMessage = error.getUserMessage();\n }\n } else if (error instanceof Error) {\n result.userMessage = error.message;\n result.developerMessage = error.message;\n } else {\n result.userMessage = 'An unknown error occurred';\n result.developerMessage = String(error);\n }\n\n return result;\n}\n\n/**\n * Format validation errors for display in forms\n */\nexport function formatValidationErrorsForForm(\n validationErrors: ValidationError[]\n): Record<string, string> {\n const formErrors: Record<string, string> = {};\n \n validationErrors.forEach((error) => {\n // Map API field names to form field names\n const fieldName = mapApiFieldToFormField(error.field);\n formErrors[fieldName] = error.message;\n });\n \n return formErrors;\n}\n\n/**\n * Map API field names to form field names\n */\nfunction mapApiFieldToFormField(apiField: string): string {\n const fieldMap: Record<string, string> = {\n 'rememberMe': 'rememberMe',\n 'email': 'email',\n 'password': 'password',\n 'displayName': 'displayName',\n 'firstName': 'firstName',\n 'lastName': 'lastName',\n 'confirmPassword': 'confirmPassword',\n 'role': 'role',\n };\n \n return fieldMap[apiField] || apiField;\n}\n\n/**\n * Create enhanced error context for debugging\n */\nexport function createErrorContext(\n error: unknown,\n context: EnhancedErrorContext\n): EnhancedErrorContext {\n return {\n timestamp: new Date().toISOString(),\n ...context,\n };\n}\n\n/**\n * Check if error is retryable\n */\nexport function isRetryable(error: unknown): boolean {\n if (error instanceof ApiError) {\n return error.isRetryable();\n }\n return false;\n}\n\n/**\n * Check if error is a network connectivity issue\n */\nexport function isConnectivityError(error: unknown): boolean {\n if (error instanceof ApiError) {\n return error.isConnectivityIssue();\n }\n return false;\n}\n\n/**\n * Get error severity for logging and display\n */\nexport function getErrorSeverity(error: unknown): 'error' | 'warning' | 'info' {\n if (error instanceof ApiError) {\n const severity = error.getSeverity();\n if (severity === 'error') return 'error';\n if (severity === 'warn') return 'warning';\n return 'info';\n }\n return 'error';\n}\n\n/**\n * Create user-friendly error summary\n */\nexport function createUserErrorSummary(error: unknown): {\n title: string;\n description: string;\n action: string;\n} {\n const parsed = parseApiError(error);\n \n if (parsed.isValidationError) {\n return {\n title: 'Invalid Input',\n description: parsed.userMessage,\n action: 'Please review your input and try again',\n };\n }\n \n if (isConnectivityError(error)) {\n return {\n title: 'Connection Issue',\n description: 'Unable to connect to the server',\n action: 'Check your internet connection and try again',\n };\n }\n \n if (isRetryable(error)) {\n return {\n title: 'Temporary Issue',\n description: parsed.userMessage,\n action: 'Please try again in a moment',\n };\n }\n \n return {\n title: 'Error',\n description: parsed.userMessage,\n action: 'Please try again or contact support if the issue persists',\n };\n}\n\n/**\n * Log error with context (only in development)\n */\nexport function logErrorWithContext(\n error: unknown,\n context: EnhancedErrorContext\n): void {\n if (process.env.NODE_ENV !== 'development') return;\n \n const parsed = parseApiError(error);\n const severity = getErrorSeverity(error);\n \n console.group(`🚨 [${severity.toUpperCase()}] ${context.component || 'Unknown'} - ${context.action || 'Unknown action'}`);\n console.error('User Message:', parsed.userMessage);\n console.error('Developer Message:', parsed.developerMessage);\n if (parsed.validationErrors.length > 0) {\n console.error('Validation Errors:', parsed.validationErrors);\n }\n if (context.formData) {\n console.error('Form Data:', context.formData);\n }\n console.error('Context:', context);\n console.error('Original Error:', error);\n console.groupEnd();\n}\n\n/**\n * Delay execution for retry logic\n */\nexport async function delay(ms: number): Promise<void> {\n await new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Retry operation with exponential backoff\n */\nexport async function retryWithBackoff<T>(\n operation: () => Promise<T>,\n maxRetries: number = 3,\n baseDelay: number = 1000\n): Promise<T> {\n let lastError: unknown;\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error;\n \n if (attempt === maxRetries || !isRetryable(error)) {\n throw error;\n }\n \n // Exponential backoff: 1s, 2s, 4s\n const delayMs = baseDelay * Math.pow(2, attempt);\n await delay(delayMs);\n }\n }\n \n throw lastError;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/utils/validation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/AdminDashboardViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/AdminUsersViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/AvatarViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/CategoryIconViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/DashboardViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/DriverRankingItem.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/DriverRankingsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeaderboardDriverItem.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeaderboardTeamItem.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeaderboardsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueAdminScheduleViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueCoverViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueDetailViewData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":9,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":12,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[994,997],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[994,997],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * LeagueDetailViewData - Pure ViewData for LeagueDetailTemplate\n * Contains only raw serializable data, no methods or computed properties\n */\n\nexport interface LeagueInfoData {\n name: string;\n description?: string;\n membersCount: number;\n racesCount: number;\n avgSOF: number | null;\n structure: string;\n scoring: string;\n createdAt: string;\n discordUrl?: string;\n youtubeUrl?: string;\n websiteUrl?: string;\n}\n\nexport interface SponsorInfo {\n id: string;\n name: string;\n tier: 'main' | 'secondary';\n logoUrl?: string;\n websiteUrl?: string;\n tagline?: string;\n}\n\nexport interface LiveRaceData {\n id: string;\n name: string;\n date: string;\n registeredCount?: number;\n strengthOfField?: number;\n}\n\nexport interface DriverSummaryData {\n driverId: string;\n driverName: string;\n avatarUrl: string | null;\n rating: number | null;\n rank: number | null;\n roleBadgeText: string;\n roleBadgeClasses: string;\n profileUrl: string;\n}\n\nexport interface SponsorMetric {\n icon: any; // React component (lucide-react icon)\n label: string;\n value: string | number;\n color?: string;\n trend?: {\n value: number;\n isPositive: boolean;\n };\n}\n\nexport interface SponsorshipSlot {\n tier: 'main' | 'secondary';\n available: boolean;\n price: number;\n benefits: string[];\n}\n\nexport interface LeagueDetailViewData {\n // Basic info\n leagueId: string;\n name: string;\n description: string;\n \n // Info card data\n info: LeagueInfoData;\n \n // Live races\n runningRaces: LiveRaceData[];\n \n // Sponsors\n sponsors: SponsorInfo[];\n \n // Management\n ownerSummary: DriverSummaryData | null;\n adminSummaries: DriverSummaryData[];\n stewardSummaries: DriverSummaryData[];\n \n // Sponsor insights (for sponsor mode)\n sponsorInsights: {\n avgViewsPerRace: number;\n engagementRate: string;\n estimatedReach: number;\n tier: 'premium' | 'standard' | 'starter';\n trustScore: number;\n discordMembers: number;\n monthlyActivity: number;\n mainSponsorAvailable: boolean;\n secondarySlotsAvailable: number;\n mainSponsorPrice: number;\n secondaryPrice: number;\n totalImpressions: number;\n metrics: SponsorMetric[];\n slots: SponsorshipSlot[];\n } | null;\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueLogoViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueRosterAdminViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueRulebookViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueScheduleViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeagueStandingsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/LeaguesViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/OnboardingPageViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/PodiumDriver.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/ProfileLeaguesViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/ProfileViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/RacesViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/SponsorDashboardViewData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":21,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":21,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[682,685],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[682,685],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":22,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":22,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[707,710],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[707,710],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export interface SponsorDashboardViewData {\n sponsorName: string;\n totalImpressions: string;\n totalInvestment: string;\n metrics: {\n impressionsChange: number;\n viewersChange: number;\n exposureChange: number;\n };\n categoryData: {\n leagues: { count: number; impressions: number };\n teams: { count: number; impressions: number };\n drivers: { count: number; impressions: number };\n races: { count: number; impressions: number };\n platform: { count: number; impressions: number };\n };\n sponsorships: Record<string, unknown>; // From DTO\n activeSponsorships: number;\n formattedTotalInvestment: string;\n costPerThousandViews: string;\n upcomingRenewals: any[];\n recentActivity: any[];\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/SponsorLogoViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/SponsorshipRequestsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/TeamDetailViewData.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":7,"column":9,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":7,"endColumn":12,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[185,188],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[185,188],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * TeamDetailViewData - Pure ViewData for TeamDetailTemplate\n * Contains only raw serializable data, no methods or computed properties\n */\n\nexport interface SponsorMetric {\n icon: any; // React component (lucide-react icon)\n label: string;\n value: string | number;\n color?: string;\n trend?: {\n value: number;\n isPositive: boolean;\n };\n}\n\nexport interface TeamDetailData {\n id: string;\n name: string;\n tag: string;\n description?: string;\n ownerId: string;\n leagues: string[];\n createdAt?: string;\n specialization?: string;\n region?: string;\n languages?: string[];\n category?: string;\n membership?: {\n role: string;\n joinedAt: string;\n isActive: boolean;\n } | null;\n canManage: boolean;\n}\n\nexport interface TeamMemberData {\n driverId: string;\n driverName: string;\n role: 'owner' | 'manager' | 'member';\n joinedAt: string;\n isActive: boolean;\n avatarUrl: string;\n}\n\nexport interface TeamTab {\n id: 'overview' | 'roster' | 'standings' | 'admin';\n label: string;\n visible: boolean;\n}\n\nexport interface TeamDetailViewData {\n team: TeamDetailData;\n memberships: TeamMemberData[];\n currentDriverId: string;\n isAdmin: boolean;\n teamMetrics: SponsorMetric[];\n tabs: TeamTab[];\n}\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/TeamLeaderboardViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/TeamLogoViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/TeamsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/TrackImageViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/LeagueScheduleViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/LeagueSettingsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/LeagueSponsorshipsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/LeagueWalletViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/ProtestDetailViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/RulebookViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/leagues/StewardingViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/races/RaceDetailViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/races/RaceResultsViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/races/RaceStewardingViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/races/RacesAllViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-data/races/RacesViewData.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ActivityItemViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[271,274],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[271,274],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Activity Item View Model\n *\n * View model for recent activity items.\n */\nexport class ActivityItemViewModel {\n id: string;\n type: 'race' | 'league' | 'team' | 'driver' | 'platform';\n message: string;\n time: string;\n impressions?: number;\n\n constructor(data: any) {\n this.id = data.id;\n this.type = data.type;\n this.message = data.message;\n this.time = data.time;\n this.impressions = data.impressions;\n }\n\n get typeColor(): string {\n const colors = {\n race: 'bg-warning-amber',\n league: 'bg-primary-blue',\n team: 'bg-purple-400',\n driver: 'bg-performance-green',\n platform: 'bg-racing-red',\n };\n return colors[this.type] || 'bg-gray-500';\n }\n\n get formattedImpressions(): string | null {\n return this.impressions ? this.impressions.toLocaleString() : null;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/AdminUserViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/AnalyticsDashboardViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/AnalyticsMetricsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/AvailableLeaguesViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":9,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":9,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[200,203],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[200,203],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":28,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":28,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[737,740],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[737,740],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Available Leagues View Model\n *\n * View model for leagues available for sponsorship.\n */\nexport class AvailableLeaguesViewModel {\n leagues: AvailableLeagueViewModel[];\n\n constructor(leagues: any[]) {\n this.leagues = leagues.map(league => new AvailableLeagueViewModel(league));\n }\n}\n\nexport class AvailableLeagueViewModel {\n id: string;\n name: string;\n game: string;\n drivers: number;\n avgViewsPerRace: number;\n mainSponsorSlot: { available: boolean; price: number };\n secondarySlots: { available: number; total: number; price: number };\n rating: number;\n tier: 'premium' | 'standard' | 'starter';\n nextRace?: string;\n seasonStatus: 'active' | 'upcoming' | 'completed';\n description: string;\n\n constructor(data: any) {\n this.id = data.id;\n this.name = data.name;\n this.game = data.game;\n this.drivers = data.drivers;\n this.avgViewsPerRace = data.avgViewsPerRace;\n this.mainSponsorSlot = data.mainSponsorSlot;\n this.secondarySlots = data.secondarySlots;\n this.rating = data.rating;\n this.tier = data.tier;\n this.nextRace = data.nextRace;\n this.seasonStatus = data.seasonStatus;\n this.description = data.description;\n }\n\n get formattedAvgViews(): string {\n return `${(this.avgViewsPerRace / 1000).toFixed(1)}k`;\n }\n\n get cpm(): number {\n return Math.round((this.mainSponsorSlot.price / this.avgViewsPerRace) * 1000);\n }\n\n get formattedCpm(): string {\n return `$${this.cpm}`;\n }\n\n get hasAvailableSlots(): boolean {\n return this.mainSponsorSlot.available || this.secondarySlots.available > 0;\n }\n\n get tierConfig() {\n const configs = {\n premium: { color: 'text-yellow-400', bgColor: 'bg-yellow-500/10', border: 'border-yellow-500/30', icon: '⭐' },\n standard: { color: 'text-primary-blue', bgColor: 'bg-primary-blue/10', border: 'border-primary-blue/30', icon: '🏆' },\n starter: { color: 'text-gray-400', bgColor: 'bg-gray-500/10', border: 'border-gray-500/30', icon: '🚀' },\n };\n return configs[this.tier];\n }\n\n get statusConfig() {\n const configs = {\n active: { color: 'text-performance-green', bg: 'bg-performance-green/10', label: 'Active Season' },\n upcoming: { color: 'text-warning-amber', bg: 'bg-warning-amber/10', label: 'Starting Soon' },\n completed: { color: 'text-gray-400', bg: 'bg-gray-400/10', label: 'Season Ended' },\n };\n return configs[this.seasonStatus];\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/AvatarGenerationViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/AvatarViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/BillingViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":12,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":12,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[289,292],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[289,292],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":15,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":18,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[310,313],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[310,313],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":14,"column":12,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":14,"endColumn":15,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[328,331],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[328,331],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":32,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":32,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[797,800],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[797,800],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":71,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":71,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1805,1808],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1805,1808],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":110,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":110,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2982,2985],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2982,2985],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Billing View Model\n *\n * View model for sponsor billing data with UI-specific transformations.\n */\nexport class BillingViewModel {\n paymentMethods: PaymentMethodViewModel[];\n invoices: InvoiceViewModel[];\n stats: BillingStatsViewModel;\n\n constructor(data: {\n paymentMethods: any[];\n invoices: any[];\n stats: any;\n }) {\n this.paymentMethods = data.paymentMethods.map(pm => new PaymentMethodViewModel(pm));\n this.invoices = data.invoices.map(inv => new InvoiceViewModel(inv));\n this.stats = new BillingStatsViewModel(data.stats);\n }\n}\n\nexport class PaymentMethodViewModel {\n id: string;\n type: 'card' | 'bank' | 'sepa';\n last4: string;\n brand?: string;\n isDefault: boolean;\n expiryMonth?: number;\n expiryYear?: number;\n bankName?: string;\n\n constructor(data: any) {\n this.id = data.id;\n this.type = data.type;\n this.last4 = data.last4;\n this.brand = data.brand;\n this.isDefault = data.isDefault;\n this.expiryMonth = data.expiryMonth;\n this.expiryYear = data.expiryYear;\n this.bankName = data.bankName;\n }\n\n get displayLabel(): string {\n if (this.type === 'sepa' && this.bankName) {\n return `${this.bankName} •••• ${this.last4}`;\n }\n return `${this.brand} •••• ${this.last4}`;\n }\n\n get expiryDisplay(): string | null {\n if (this.expiryMonth && this.expiryYear) {\n return `${String(this.expiryMonth).padStart(2, '0')}/${this.expiryYear}`;\n }\n return null;\n }\n}\n\nexport class InvoiceViewModel {\n id: string;\n invoiceNumber: string;\n date: Date;\n dueDate: Date;\n amount: number;\n vatAmount: number;\n totalAmount: number;\n status: 'paid' | 'pending' | 'overdue' | 'failed';\n description: string;\n sponsorshipType: 'league' | 'team' | 'driver' | 'race' | 'platform';\n pdfUrl: string;\n\n constructor(data: any) {\n this.id = data.id;\n this.invoiceNumber = data.invoiceNumber;\n this.date = new Date(data.date);\n this.dueDate = new Date(data.dueDate);\n this.amount = data.amount;\n this.vatAmount = data.vatAmount;\n this.totalAmount = data.totalAmount;\n this.status = data.status;\n this.description = data.description;\n this.sponsorshipType = data.sponsorshipType;\n this.pdfUrl = data.pdfUrl;\n }\n\n get formattedTotalAmount(): string {\n return `€${this.totalAmount.toLocaleString('de-DE', { minimumFractionDigits: 2 })}`;\n }\n\n get formattedVatAmount(): string {\n return `€${this.vatAmount.toLocaleString('de-DE', { minimumFractionDigits: 2 })}`;\n }\n\n get formattedDate(): string {\n return this.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });\n }\n\n get isOverdue(): boolean {\n return this.status === 'overdue' || (this.status === 'pending' && new Date() > this.dueDate);\n }\n}\n\nexport class BillingStatsViewModel {\n totalSpent: number;\n pendingAmount: number;\n nextPaymentDate: Date;\n nextPaymentAmount: number;\n activeSponsorships: number;\n averageMonthlySpend: number;\n\n constructor(data: any) {\n this.totalSpent = data.totalSpent;\n this.pendingAmount = data.pendingAmount;\n this.nextPaymentDate = new Date(data.nextPaymentDate);\n this.nextPaymentAmount = data.nextPaymentAmount;\n this.activeSponsorships = data.activeSponsorships;\n this.averageMonthlySpend = data.averageMonthlySpend;\n }\n\n get formattedTotalSpent(): string {\n return `€${this.totalSpent.toLocaleString('de-DE')}`;\n }\n\n get formattedPendingAmount(): string {\n return `€${this.pendingAmount.toLocaleString('de-DE', { minimumFractionDigits: 2 })}`;\n }\n\n get formattedNextPaymentAmount(): string {\n return `€${this.nextPaymentAmount.toLocaleString('de-DE', { minimumFractionDigits: 2 })}`;\n }\n\n get formattedAverageMonthlySpend(): string {\n return `€${this.averageMonthlySpend.toLocaleString('de-DE')}`;\n }\n\n get formattedNextPaymentDate(): string {\n return this.nextPaymentDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/CompleteOnboardingViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/CreateLeagueViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/CreateTeamViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DeleteMediaViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverLeaderboardItemViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverLeaderboardViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverProfileDriverSummaryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverProfileViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverRegistrationStatusViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverSummaryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverTeamViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/DriverViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/EmailSignupViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/HomeDiscoveryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ImportRaceResultsSummaryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueAdminRosterJoinRequestViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueAdminRosterMemberViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueAdminScheduleViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueAdminViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":9,"column":11,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":9,"endColumn":14,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[282,285],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[282,285],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":14,"column":13,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":14,"endColumn":16,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[403,406],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[403,406],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { LeagueMemberViewModel } from './LeagueMemberViewModel';\nimport type { LeagueJoinRequestViewModel } from './LeagueJoinRequestViewModel';\n\n/**\n * League admin view model\n * Transform from DTO to ViewModel with UI fields\n */\nexport class LeagueAdminViewModel {\n config: any;\n members: LeagueMemberViewModel[];\n joinRequests: LeagueJoinRequestViewModel[];\n\n constructor(dto: {\n config: any;\n members: LeagueMemberViewModel[];\n joinRequests: LeagueJoinRequestViewModel[];\n }) {\n this.config = dto.config;\n this.members = dto.members;\n this.joinRequests = dto.joinRequests;\n }\n\n /** UI-specific: Total pending requests count */\n get pendingRequestsCount(): number {\n return this.joinRequests.length;\n }\n\n /** UI-specific: Whether there are any pending requests */\n get hasPendingRequests(): boolean {\n return this.joinRequests.length > 0;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueCardViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueDetailPageViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueDetailViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":31,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":34,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[250,253],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[250,253],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":45,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":48,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[264,267],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[264,267],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":59,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":62,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[278,281],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[278,281],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":40,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":40,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1155,1158],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1155,1158],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":107,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":107,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3069,3072],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3069,3072],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":129,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":129,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3535,3538],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3535,3538],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * League Detail View Model\n *\n * View model for detailed league information for sponsors.\n */\nexport class LeagueDetailViewModel {\n league: LeagueViewModel;\n drivers: DriverViewModel[];\n races: RaceViewModel[];\n\n constructor(data: { league: any; drivers: any[]; races: any[] }) {\n this.league = new LeagueViewModel(data.league);\n this.drivers = data.drivers.map(driver => new DriverViewModel(driver));\n this.races = data.races.map(race => new RaceViewModel(race));\n }\n}\n\nexport class LeagueViewModel {\n id: string;\n name: string;\n game: string;\n tier: 'premium' | 'standard' | 'starter';\n season: string;\n description: string;\n drivers: number;\n races: number;\n completedRaces: number;\n totalImpressions: number;\n avgViewsPerRace: number;\n engagement: number;\n rating: number;\n seasonStatus: 'active' | 'upcoming' | 'completed';\n seasonDates: { start: string; end: string };\n nextRace?: { name: string; date: string };\n sponsorSlots: {\n main: { available: boolean; price: number; benefits: string[] };\n secondary: { available: number; total: number; price: number; benefits: string[] };\n };\n\n constructor(data: any) {\n this.id = data.id;\n this.name = data.name;\n this.game = data.game;\n this.tier = data.tier;\n this.season = data.season;\n this.description = data.description;\n this.drivers = data.drivers;\n this.races = data.races;\n this.completedRaces = data.completedRaces;\n this.totalImpressions = data.totalImpressions;\n this.avgViewsPerRace = data.avgViewsPerRace;\n this.engagement = data.engagement;\n this.rating = data.rating;\n this.seasonStatus = data.seasonStatus;\n this.seasonDates = data.seasonDates;\n this.nextRace = data.nextRace;\n this.sponsorSlots = data.sponsorSlots;\n }\n\n get formattedTotalImpressions(): string {\n return this.totalImpressions.toLocaleString();\n }\n\n get formattedAvgViewsPerRace(): string {\n return this.avgViewsPerRace.toLocaleString();\n }\n\n get projectedTotalViews(): number {\n return Math.round(this.avgViewsPerRace * this.races);\n }\n\n get formattedProjectedTotal(): string {\n return this.projectedTotalViews.toLocaleString();\n }\n\n get mainSponsorCpm(): number {\n return Math.round((this.sponsorSlots.main.price / this.projectedTotalViews) * 1000);\n }\n\n get formattedMainSponsorCpm(): string {\n return `$${this.mainSponsorCpm.toFixed(2)}`;\n }\n\n get racesLeft(): number {\n return this.races - this.completedRaces;\n }\n\n get tierConfig() {\n const configs = {\n premium: { color: 'text-yellow-400', bgColor: 'bg-yellow-500/10', border: 'border-yellow-500/30' },\n standard: { color: 'text-primary-blue', bgColor: 'bg-primary-blue/10', border: 'border-primary-blue/30' },\n starter: { color: 'text-gray-400', bgColor: 'bg-gray-500/10', border: 'border-gray-500/30' },\n };\n return configs[this.tier];\n }\n}\n\nexport class DriverViewModel {\n id: string;\n name: string;\n country: string;\n position: number;\n races: number;\n impressions: number;\n team: string;\n\n constructor(data: any) {\n this.id = data.id;\n this.name = data.name;\n this.country = data.country;\n this.position = data.position;\n this.races = data.races;\n this.impressions = data.impressions;\n this.team = data.team;\n }\n\n get formattedImpressions(): string {\n return this.impressions.toLocaleString();\n }\n}\n\nexport class RaceViewModel {\n id: string;\n name: string;\n date: Date;\n views: number;\n status: 'upcoming' | 'completed';\n\n constructor(data: any) {\n this.id = data.id;\n this.name = data.name;\n this.date = new Date(data.date);\n this.views = data.views;\n this.status = data.status;\n }\n\n get formattedDate(): string {\n return this.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n }\n\n get formattedViews(): string {\n return this.views.toLocaleString();\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueJoinRequestViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueMemberViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueMembershipsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeaguePageDetailViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":15,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":15,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[335,338],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[335,338],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * League Page Detail View Model\n *\n * View model for league page details.\n */\nexport class LeaguePageDetailViewModel {\n id: string;\n name: string;\n description: string;\n ownerId: string;\n ownerName: string;\n isAdmin: boolean;\n mainSponsor: { name: string; logoUrl: string; websiteUrl: string } | null;\n\n constructor(data: any) {\n this.id = data.id;\n this.name = data.name;\n this.description = data.description;\n this.ownerId = data.ownerId;\n this.ownerName = data.ownerName;\n this.isAdmin = data.isAdmin;\n this.mainSponsor = data.mainSponsor;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueScheduleViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueScoringChampionshipViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueScoringConfigViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueScoringPresetViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueScoringPresetsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueScoringSectionViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueSeasonSummaryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueSettingsViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'LeagueScoringPresetsViewModel' is defined but never used.","line":3,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":39}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';\nimport type { LeagueScoringPresetDTO } from '@/lib/types/generated/LeagueScoringPresetDTO';\nimport { LeagueScoringPresetsViewModel } from './LeagueScoringPresetsViewModel';\nimport { DriverSummaryViewModel } from './DriverSummaryViewModel';\n\n/**\n * View Model for league settings page\n * Combines league config, presets, owner, and members\n */\nexport class LeagueSettingsViewModel {\n league: {\n id: string;\n name: string;\n ownerId: string;\n };\n config: LeagueConfigFormModel;\n presets: LeagueScoringPresetDTO[];\n owner: DriverSummaryViewModel | null;\n members: DriverSummaryViewModel[];\n\n constructor(dto: {\n league: {\n id: string;\n name: string;\n ownerId: string;\n createdAt: string;\n };\n config: LeagueConfigFormModel;\n presets: LeagueScoringPresetDTO[];\n owner: DriverSummaryViewModel | null;\n members: DriverSummaryViewModel[];\n }) {\n this.league = dto.league;\n this.config = dto.config;\n this.presets = dto.presets;\n this.owner = dto.owner;\n this.members = dto.members;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueStandingsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueStatsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueStewardingViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueSummaryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/LeagueWalletViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/MediaViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/MembershipFeeViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/OnboardingViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/PaymentViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/PrizeViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ProfileOverviewViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ProtestDetailViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ProtestDriverViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ProtestViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceDetailEntryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceDetailUserResultViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceDetailsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceListItemViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceResultViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceResultsDetailViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceStatsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceStewardingViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RaceWithSOFViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RacesPageViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RecordEngagementInputViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RecordEngagementOutputViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RecordPageViewInputViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RecordPageViewOutputViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RemoveMemberViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RenewalAlertViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[266,269],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[266,269],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Renewal Alert View Model\n *\n * View model for upcoming renewal alerts.\n */\nexport class RenewalAlertViewModel {\n id: string;\n name: string;\n type: 'league' | 'team' | 'driver' | 'race' | 'platform';\n renewDate: Date;\n price: number;\n\n constructor(data: any) {\n this.id = data.id;\n this.name = data.name;\n this.type = data.type;\n this.renewDate = new Date(data.renewDate);\n this.price = data.price;\n }\n\n get formattedPrice(): string {\n return `$${this.price}`;\n }\n\n get formattedRenewDate(): string {\n return this.renewDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });\n }\n\n get typeIcon() {\n const icons = {\n league: 'Trophy',\n team: 'Users',\n driver: 'Car',\n race: 'Flag',\n platform: 'Megaphone',\n };\n return icons[this.type] || 'Trophy';\n }\n\n get daysUntilRenewal(): number {\n const now = new Date();\n const diffTime = this.renewDate.getTime() - now.getTime();\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n }\n\n get isUrgent(): boolean {\n return this.daysUntilRenewal <= 30;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/RequestAvatarGenerationViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/ScoringConfigurationViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SessionViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorSettingsViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":32,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":35,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[276,279],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[276,279],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":52,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":55,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[296,299],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[296,299],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":66,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":69,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[310,313],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[310,313],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":40,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":40,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[979,982],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[979,982],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":67,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":67,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1807,1810],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1807,1810],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":83,"column":21,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":83,"endColumn":24,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2330,2333],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2330,2333],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Sponsor Settings View Model\n *\n * View model for sponsor settings data.\n */\nexport class SponsorSettingsViewModel {\n profile: SponsorProfileViewModel;\n notifications: NotificationSettingsViewModel;\n privacy: PrivacySettingsViewModel;\n\n constructor(data: { profile: any; notifications: any; privacy: any }) {\n this.profile = new SponsorProfileViewModel(data.profile);\n this.notifications = new NotificationSettingsViewModel(data.notifications);\n this.privacy = new PrivacySettingsViewModel(data.privacy);\n }\n}\n\nexport class SponsorProfileViewModel {\n companyName: string;\n contactName: string;\n contactEmail: string;\n contactPhone: string;\n website: string;\n description: string;\n logoUrl: string | null;\n industry: string;\n address: {\n street: string;\n city: string;\n country: string;\n postalCode: string;\n };\n taxId: string;\n socialLinks: {\n twitter: string;\n linkedin: string;\n instagram: string;\n };\n\n constructor(data: any) {\n this.companyName = data.companyName;\n this.contactName = data.contactName;\n this.contactEmail = data.contactEmail;\n this.contactPhone = data.contactPhone;\n this.website = data.website;\n this.description = data.description;\n this.logoUrl = data.logoUrl;\n this.industry = data.industry;\n this.address = data.address;\n this.taxId = data.taxId;\n this.socialLinks = data.socialLinks;\n }\n\n get fullAddress(): string {\n return `${this.address.street}, ${this.address.city}, ${this.address.postalCode}, ${this.address.country}`;\n }\n}\n\nexport class NotificationSettingsViewModel {\n emailNewSponsorships: boolean;\n emailWeeklyReport: boolean;\n emailRaceAlerts: boolean;\n emailPaymentAlerts: boolean;\n emailNewOpportunities: boolean;\n emailContractExpiry: boolean;\n\n constructor(data: any) {\n this.emailNewSponsorships = data.emailNewSponsorships;\n this.emailWeeklyReport = data.emailWeeklyReport;\n this.emailRaceAlerts = data.emailRaceAlerts;\n this.emailPaymentAlerts = data.emailPaymentAlerts;\n this.emailNewOpportunities = data.emailNewOpportunities;\n this.emailContractExpiry = data.emailContractExpiry;\n }\n}\n\nexport class PrivacySettingsViewModel {\n publicProfile: boolean;\n showStats: boolean;\n showActiveSponsorships: boolean;\n allowDirectContact: boolean;\n\n constructor(data: any) {\n this.publicProfile = data.publicProfile;\n this.showStats = data.showStats;\n this.showActiveSponsorships = data.showActiveSponsorships;\n this.allowDirectContact = data.allowDirectContact;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorSponsorshipsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorshipDetailViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorshipPricingViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorshipRequestViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/SponsorshipViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/StandingEntryViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":36,"column":12,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":36,"endColumn":15,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1104,1107],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1104,1107],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { LeagueStandingDTO } from '@/lib/types/generated/LeagueStandingDTO';\n\nexport class StandingEntryViewModel {\n driverId: string;\n position: number;\n points: number;\n wins: number;\n podiums: number;\n races: number;\n\n private leaderPoints: number;\n private nextPoints: number;\n private currentUserId: string;\n private previousPosition?: number;\n\n constructor(dto: LeagueStandingDTO, leaderPoints: number, nextPoints: number, currentUserId: string, previousPosition?: number) {\n this.driverId = dto.driverId;\n this.position = dto.position;\n this.points = dto.points;\n this.wins = dto.wins ?? 0;\n this.podiums = dto.podiums ?? 0;\n this.races = dto.races ?? 0;\n this.leaderPoints = leaderPoints;\n this.nextPoints = nextPoints;\n this.currentUserId = currentUserId;\n this.previousPosition = previousPosition;\n }\n\n /** UI-specific: Badge for position display */\n get positionBadge(): string {\n return this.position.toString();\n }\n\n // Note: The generated DTO is incomplete\n // These fields will need to be added when the OpenAPI spec is updated\n driver?: any;\n\n /** UI-specific: Points difference to leader */\n get pointsGapToLeader(): number {\n return this.points - this.leaderPoints;\n }\n\n /** UI-specific: Points difference to next position */\n get pointsGapToNext(): number {\n return this.points - this.nextPoints;\n }\n\n /** UI-specific: Whether this entry is the current user */\n get isCurrentUser(): boolean {\n return this.driverId === this.currentUserId;\n }\n\n /** UI-specific: Trend compared to previous */\n get trend(): 'up' | 'down' | 'same' {\n if (!this.previousPosition) return 'same';\n if (this.position < this.previousPosition) return 'up';\n if (this.position > this.previousPosition) return 'down';\n return 'same';\n }\n\n /** UI-specific: Arrow for trend */\n get trendArrow(): string {\n switch (this.trend) {\n case 'up': return '↑';\n case 'down': return '↓';\n default: return '-';\n }\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/TeamCardViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/TeamDetailsViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/TeamJoinRequestViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/TeamMemberViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/TeamSummaryViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/UpcomingRaceCardViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/UpdateAvatarViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/UpdateTeamViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/UploadMediaViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/UserProfileViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/WalletTransactionViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/WalletViewModel.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":2,"message":"'FullTransactionDto' is defined but never used.","line":2,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":28},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":14,"column":49,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":14,"endColumn":52,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[410,413],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[410,413],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { WalletDTO } from '@/lib/types/generated/WalletDTO';\nimport { FullTransactionDto, WalletTransactionViewModel } from './WalletTransactionViewModel';\n\nexport class WalletViewModel {\n id: string;\n leagueId: string;\n balance: number;\n totalRevenue: number;\n totalPlatformFees: number;\n totalWithdrawn: number;\n createdAt: string;\n currency: string;\n\n constructor(dto: WalletDTO & { transactions?: any[] }) {\n this.id = dto.id;\n this.leagueId = dto.leagueId;\n this.balance = dto.balance;\n this.totalRevenue = dto.totalRevenue;\n this.totalPlatformFees = dto.totalPlatformFees;\n this.totalWithdrawn = dto.totalWithdrawn;\n this.createdAt = dto.createdAt;\n this.currency = dto.currency;\n\n // Map transactions if provided\n this.transactions = dto.transactions?.map(t => new WalletTransactionViewModel(t)) || [];\n }\n\n transactions: WalletTransactionViewModel[] = [];\n\n /** UI-specific: Formatted balance */\n get formattedBalance(): string {\n return `${this.currency} ${this.balance.toFixed(2)}`;\n }\n\n /** UI-specific: Balance color */\n get balanceColor(): string {\n return this.balance >= 0 ? 'green' : 'red';\n }\n\n /** UI-specific: Recent transactions (last 5) */\n get recentTransactions(): WalletTransactionViewModel[] {\n return this.transactions.slice(0, 5);\n }\n\n /** UI-specific: Total transactions count */\n get totalTransactions(): number {\n return this.transactions.length;\n }\n}","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/auth/ForgotPasswordViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/auth/LoginViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/auth/ResetPasswordViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/auth/SignupViewModel.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/lib/view-models/index.ts","messages":[{"ruleId":"gridpilot-rules/no-index-files","severity":2,"message":"Index files are banned. Use explicit imports and barrel exports. Example: Instead of \"import { foo } from \"./\", use \"import { foo } from \"./foo\" and export from \"./foo\" explicitly.","line":1,"column":1,"nodeType":null,"messageId":"indexFile"}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"export * from './ActivityItemViewModel';\nexport * from './AnalyticsDashboardViewModel';\nexport * from './AnalyticsMetricsViewModel';\nexport * from './AvailableLeaguesViewModel';\nexport * from './AvatarGenerationViewModel';\nexport * from './AvatarViewModel';\nexport * from './BillingViewModel';\nexport * from './CompleteOnboardingViewModel';\nexport * from './CreateLeagueViewModel';\nexport * from './CreateTeamViewModel';\nexport * from './DeleteMediaViewModel';\nexport * from './DriverLeaderboardItemViewModel';\nexport * from './DriverLeaderboardViewModel';\nexport * from './DriverProfileViewModel';\nexport * from './DriverRegistrationStatusViewModel';\nexport * from './DriverSummaryViewModel';\nexport * from './DriverTeamViewModel';\nexport * from './DriverViewModel';\nexport * from './EmailSignupViewModel';\nexport * from './HomeDiscoveryViewModel';\nexport * from './ImportRaceResultsSummaryViewModel';\nexport * from './LeagueAdminViewModel';\nexport * from './LeagueCardViewModel';\nexport * from './LeagueDetailPageViewModel';\nexport { LeagueDetailViewModel, LeagueViewModel } from './LeagueDetailViewModel';\nexport * from './LeagueJoinRequestViewModel';\nexport * from './LeagueMembershipsViewModel';\nexport * from './LeagueMemberViewModel';\nexport * from './LeaguePageDetailViewModel';\nexport * from './LeagueScheduleViewModel';\nexport * from './LeagueScoringChampionshipViewModel';\nexport * from './LeagueScoringConfigViewModel';\nexport * from './LeagueScoringPresetsViewModel';\nexport * from './LeagueScoringPresetViewModel';\nexport * from './LeagueScoringSectionViewModel';\nexport * from './LeagueSettingsViewModel';\nexport * from './LeagueStandingsViewModel';\nexport * from './LeagueStatsViewModel';\nexport * from './LeagueStewardingViewModel';\nexport * from './LeagueSummaryViewModel';\nexport * from './LeagueWalletViewModel';\nexport * from './MediaViewModel';\nexport * from './MembershipFeeViewModel';\nexport * from './PaymentViewModel';\nexport * from './PrizeViewModel';\nexport * from './ProfileOverviewViewModel';\nexport * from './ProtestDriverViewModel';\nexport * from './ProtestViewModel';\nexport * from './RaceDetailEntryViewModel';\nexport * from './RaceDetailUserResultViewModel';\nexport * from './RaceDetailsViewModel';\nexport * from './RaceListItemViewModel';\nexport * from './RaceResultsDetailViewModel';\nexport * from './RaceResultViewModel';\nexport * from './RacesPageViewModel';\nexport * from './RaceStatsViewModel';\nexport * from './RaceStewardingViewModel';\nexport * from './RaceViewModel';\nexport * from './RaceWithSOFViewModel';\nexport * from './RecordEngagementInputViewModel';\nexport * from './RecordEngagementOutputViewModel';\nexport * from './RecordPageViewInputViewModel';\nexport * from './RecordPageViewOutputViewModel';\nexport * from './RemoveMemberViewModel';\nexport * from './RenewalAlertViewModel';\nexport * from './RequestAvatarGenerationViewModel';\nexport * from './ScoringConfigurationViewModel';\nexport * from './SessionViewModel';\nexport * from './SponsorSettingsViewModel';\nexport * from './SponsorshipDetailViewModel';\nexport * from './SponsorshipPricingViewModel';\nexport * from './SponsorshipRequestViewModel';\nexport * from './SponsorshipViewModel';\nexport * from './SponsorSponsorshipsViewModel';\nexport * from './SponsorViewModel';\nexport * from './StandingEntryViewModel';\nexport * from './TeamCardViewModel';\nexport * from './TeamDetailsViewModel';\nexport * from './TeamJoinRequestViewModel';\nexport * from './TeamMemberViewModel';\nexport * from './TeamSummaryViewModel';\nexport * from './UpcomingRaceCardViewModel';\nexport * from './UpdateAvatarViewModel';\nexport * from './UpdateTeamViewModel';\nexport * from './UploadMediaViewModel';\nexport * from './UserProfileViewModel';\nexport * from './WalletTransactionViewModel';\nexport * from './WalletViewModel';\n","usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/middleware.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/next-env.d.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/AdminDashboardTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/AdminUsersTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/DashboardTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/DriverProfileTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/DriverRankingsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/DriversTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/HomeTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeaderboardsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueAdminScheduleTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueDetailTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueRulebookTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueScheduleTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueSettingsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueSponsorshipsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/LeagueStandingsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/ProfileLeaguesTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/ProfileTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RaceDetailTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RaceResultsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RaceStewardingTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RacesAllTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RacesTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RosterAdminTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/RulebookTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/SponsorDashboardTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/SponsorLeagueDetailTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/SponsorLeaguesTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/SponsorshipRequestsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/TeamDetailTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/TeamLeaderboardTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/TeamsTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/auth/ForgotPasswordTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/auth/LoginTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/auth/ResetPasswordTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/templates/auth/SignupTemplate.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/types/third-party-shims.d.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Accordion.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/AchievementCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ActiveDriverCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ActivityItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/AuthContainer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/AuthError.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/AuthLoading.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/AvailableLeagueCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Avatar.tsx","messages":[],"suppressedMessages":[{"ruleId":"@next/next/no-img-element","severity":2,"message":"Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element","line":17,"column":5,"nodeType":"JSXOpeningElement","endLine":25,"endColumn":7,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/BorderTabs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Box.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Breadcrumbs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Button.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CareerHighlights.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CareerStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CategoryDistribution.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CategoryDistributionCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CategoryIcon.tsx","messages":[],"suppressedMessages":[{"ruleId":"@next/next/no-img-element","severity":2,"message":"Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element","line":17,"column":5,"nodeType":"JSXOpeningElement","endLine":25,"endColumn":7,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Checkbox.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CircularProgress.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Container.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/CountryFlag.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DangerZone.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DashboardHero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DashboardLayoutWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DateHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DecorativeBlur.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DiscordCTA.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DriverRatingPill.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DriverStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DriverSummaryPill.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DriversSearch.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/DurationField.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ErrorActionButtons.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ErrorBanner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ErrorPageContainer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FeedEmptyState.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FeedItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FilePicker.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FilterGroup.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FinishDistributionChart.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Footer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FormField.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FriendItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/FriendsList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/GoalCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Grid.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/GridItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Header.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Heading.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Hero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/HorizontalBarChart.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/HorizontalStatCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/HorizontalStatItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Icon.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/IconButton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Image.tsx","messages":[],"suppressedMessages":[{"ruleId":"@next/next/no-img-element","severity":2,"message":"Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element","line":27,"column":5,"nodeType":"JSXOpeningElement","endLine":39,"endColumn":7,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/InfoBanner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/InfoBox.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/InfoItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/InlinePenaltyButton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Input.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/JoinRequestItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/JoinRequestList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeaderboardList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueCover.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueCoverWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueListItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueLogo.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueLogoWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueMemberTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LeagueSummaryCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Link.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LiveRaceBanner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LiveRaceItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LiveryCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/LoadingSpinner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/MainContent.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/MedalBadge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/MilestoneItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/MiniStat.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Modal.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ModalIcon.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/NextRaceCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingCardAccent.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingContainer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingError.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingForm.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingHelpText.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/OnboardingNavigation.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PageHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PageHero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Pagination.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PenaltyFAB.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PenaltyRow.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PerformanceMetrics.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PerformanceOverview.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PlaceholderImage.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Podium.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PointsTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/PresetCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ProfileBio.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ProfileLayoutShell.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ProfileStatGrid.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ProfileTabs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/ProgressBar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/QuickActionItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/QuickActionLink.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceDetailCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceFilterModal.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceHero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceHeroWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceJoinButton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RacePageHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RacePenaltyRowWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceResultCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceResultHero.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceResultList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceResultsHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceResultsTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceStatusBadge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceStewardingStats.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceSummaryItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RaceUserResultWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RacingProfile.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RankBadge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RankingsPodium.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RankingsTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RatingBreakdown.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RatingComponent.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RatingHistoryItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RecruitingTeamCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RecruitingTeamGrid.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RenewalItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/RulebookTabs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SectionHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SegmentedControl.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Select.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SidebarActionLink.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SidebarRaceItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Skeleton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SkillDistribution.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SkillLevelButton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SkillLevelHeader.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorActivityItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorLogo.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorMetricCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorSlotCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorTierCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorshipCategoryCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorshipRequestItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SponsorshipTierBadge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Stack.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StandingsItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StandingsList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StatBox.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StatCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StatGridItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StatItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StatusBadge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StatusIndicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StepIndicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/StewardingTabs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/SummaryItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Surface.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TabContent.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TabNavigation.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Table.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamCardWrapper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamFilter.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamGrid.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamLadderRow.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamLadderTable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamLeaderboardItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamLeaderboardPreview.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamLogo.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamMembershipCard.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamMembershipGrid.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamRosterList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamSearchBar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamStatItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TeamTag.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Text.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TextArea.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/Toggle.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/TrackImage.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/UpcomingRaceItem.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/icons/DiscordIcon.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/Users/marcmintel/Projects/gridpilot/apps/website/ui/state-types.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]}] |