website refactor

This commit is contained in:
2026-01-18 00:17:01 +01:00
parent 69d4cce7f1
commit 4b66c682a0
18 changed files with 847 additions and 87 deletions

View File

@@ -61,7 +61,7 @@ export default function SponsorBillingPage() {
{
label: 'Pending Payments',
value: `$${billingData.stats.pendingAmount.toFixed(2)}`,
subValue: `${billingData.invoices.filter(i => i.status === 'pending' || i.status === 'overdue').length} invoices`,
subValue: `${billingData.invoices.filter((i: any) => i.status === 'pending' || i.status === 'overdue').length} invoices`,
icon: AlertTriangle,
variant: (billingData.stats.pendingAmount > 0 ? 'warning' : 'default') as 'warning' | 'default',
},
@@ -81,7 +81,7 @@ export default function SponsorBillingPage() {
},
];
const transactions = billingData.invoices.map(inv => ({
const transactions = billingData.invoices.map((inv: any) => ({
id: inv.id,
date: inv.date,
description: inv.description,

View File

@@ -63,7 +63,7 @@ export function LeagueSponsorshipsSection({
if (!currentDriverId) return;
try {
await sponsorshipService.acceptSponsorshipRequest(requestId, currentDriverId);
await (sponsorshipService as any).acceptSponsorshipRequest(requestId, currentDriverId);
await refetchRequests();
} catch (err) {
console.error('Failed to accept request:', err);
@@ -75,7 +75,7 @@ export function LeagueSponsorshipsSection({
if (!currentDriverId) return;
try {
await sponsorshipService.rejectSponsorshipRequest(requestId, currentDriverId, reason);
await (sponsorshipService as any).rejectSponsorshipRequest(requestId, currentDriverId, reason);
await refetchRequests();
} catch (err) {
console.error('Failed to reject request:', err);

View File

@@ -9,7 +9,7 @@ export function useSponsorshipRequests(entityType: string, entityId: string) {
const queryResult = useQuery({
queryKey: ['sponsorshipRequests', entityType, entityId],
queryFn: async () => {
const result = await sponsorshipService.getPendingSponsorshipRequests({
const result = await (sponsorshipService as any).getPendingSponsorshipRequests({
entityType,
entityId,
});

View File

@@ -9,7 +9,7 @@ export function useSponsorBilling(sponsorId: string) {
const queryResult = useQuery({
queryKey: ['sponsorBilling', sponsorId],
queryFn: async () => {
const result = await sponsorService.getBilling(sponsorId);
const result = await (sponsorService as any).getBilling(sponsorId);
if (result.isErr()) {
throw new Error(result.getError().message);
}

View File

@@ -326,6 +326,12 @@ export const routeMatchers = {
requiresRole(path: string): string[] | null {
logger.info('[RouteConfig] requiresRole check', { path });
// Public routes never require a role
if (this.isPublic(path)) {
logger.info('[RouteConfig] Path is public, no role required', { path });
return null;
}
if (this.isInGroup(path, 'admin')) {
// Website session roles come from the API and are more specific than just "admin".
// Keep "admin"/"owner" for backwards compatibility.

View File

@@ -1,16 +1,5 @@
export interface DriverProfileDriverSummaryViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
iracingId: string | null;
joinedAt: string;
rating: number | null;
globalRank: number | null;
consistency: number | null;
bio: string | null;
totalDrivers: number | null;
}
import { DriverProfileDriverSummaryViewModel } from "./DriverProfileDriverSummaryViewModel";
export type { DriverProfileDriverSummaryViewModel };
export interface DriverProfileStatsViewModel {
totalRaces: number;

View File

@@ -1,3 +1,6 @@
import { DriverViewModel as SharedDriverViewModel } from "./DriverViewModel";
import { RaceViewModel as SharedRaceViewModel } from "./RaceViewModel";
/**
* League Detail View Model
*
@@ -5,13 +8,13 @@
*/
export class LeagueDetailViewModel {
league: LeagueViewModel;
drivers: DriverViewModel[];
races: RaceViewModel[];
drivers: SharedDriverViewModel[];
races: SharedRaceViewModel[];
constructor(data: { league: unknown; drivers: unknown[]; races: unknown[] }) {
this.league = new LeagueViewModel(data.league);
this.drivers = data.drivers.map(driver => new DriverViewModel(driver));
this.races = data.races.map(race => new RaceViewModel(race));
this.drivers = data.drivers.map(driver => new SharedDriverViewModel(driver as any));
this.races = data.races.map(race => new SharedRaceViewModel(race as any));
}
}
@@ -96,55 +99,3 @@ export class LeagueViewModel {
return configs[this.tier];
}
}
export class DriverViewModel {
id: string;
name: string;
country: string;
position: number;
races: number;
impressions: number;
team: string;
constructor(data: unknown) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const d = data as any;
this.id = d.id;
this.name = d.name;
this.country = d.country;
this.position = d.position;
this.races = d.races;
this.impressions = d.impressions;
this.team = d.team;
}
get formattedImpressions(): string {
return this.impressions.toLocaleString();
}
}
export class RaceViewModel {
id: string;
name: string;
date: Date;
views: number;
status: 'upcoming' | 'completed';
constructor(data: unknown) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const d = data as any;
this.id = d.id;
this.name = d.name;
this.date = new Date(d.date);
this.views = d.views;
this.status = d.status;
}
get formattedDate(): string {
return this.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}
get formattedViews(): string {
return this.views.toLocaleString();
}
}