website cleanup

This commit is contained in:
2025-12-25 00:19:36 +01:00
parent d78854a4c6
commit 9486455b9e
82 changed files with 1223 additions and 363 deletions

View File

@@ -1,5 +1,5 @@
import Card from '@/components/ui/Card';
import type { LeagueScoringChampionshipDTO } from '@/lib/types/generated/LeagueScoringChampionshipDTO';
import type { LeagueScoringChampionshipViewModel } from '@/lib/view-models/LeagueScoringChampionshipViewModel';
type PointsPreviewRow = {
sessionType: string;
@@ -8,7 +8,7 @@ type PointsPreviewRow = {
};
interface ChampionshipCardProps {
championship: LeagueScoringChampionshipDTO;
championship: LeagueScoringChampionshipViewModel;
}
export function ChampionshipCard({ championship }: ChampionshipCardProps) {

View File

@@ -38,7 +38,7 @@ import { LeagueStructureSection } from './LeagueStructureSection';
import { LeagueTimingsSection } from './LeagueTimingsSection';
import { LeagueVisibilitySection } from './LeagueVisibilitySection';
import type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';
import type { LeagueScoringPresetDTO } from '@/lib/types/generated/LeagueScoringPresetDTO';
import type { LeagueScoringPresetViewModel } from '@/lib/view-models/LeagueScoringPresetViewModel';
import type { Weekday } from '@/lib/types/Weekday';
import type { WizardErrors } from '@/lib/types/WizardErrors';
@@ -243,7 +243,7 @@ export default function CreateLeagueWizard({ stepName, onStepChange }: CreateLea
const step = stepNameToStep(stepName);
const [loading, setLoading] = useState(false);
const [presetsLoading, setPresetsLoading] = useState(true);
const [presets, setPresets] = useState<LeagueScoringPresetDTO[]>([]);
const [presets, setPresets] = useState<LeagueScoringPresetViewModel[]>([]);
const [errors, setErrors] = useState<WizardErrors>({});
const [highestCompletedStep, setHighestCompletedStep] = useState(1);
const [isHydrated, setIsHydrated] = useState(false);

View File

@@ -5,7 +5,7 @@ import { useEffectiveDriverId } from '../../hooks/useEffectiveDriverId';
import { useServices } from '../../lib/services/ServiceProvider';
import type { LeagueMembership } from '@/lib/types/LeagueMembership';
import type { MembershipRole } from '@/lib/types/MembershipRole';
import type { DriverDTO } from '@/lib/types/generated/DriverDTO';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { useCallback, useEffect, useState } from 'react';
// Migrated to useServices-based website services; legacy EntityMapper removed.
@@ -24,7 +24,7 @@ export default function LeagueMembers({
showActions = false
}: LeagueMembersProps) {
const [members, setMembers] = useState<LeagueMembership[]>([]);
const [driversById, setDriversById] = useState<Record<string, DriverDTO>>({});
const [driversById, setDriversById] = useState<Record<string, DriverViewModel>>({});
const [loading, setLoading] = useState(true);
const [sortBy, setSortBy] = useState<'role' | 'name' | 'date' | 'rating' | 'points' | 'wins'>('rating');
const currentDriverId = useEffectiveDriverId();
@@ -41,9 +41,9 @@ export default function LeagueMembers({
if (uniqueDriverIds.length > 0) {
const driverDtos = await driverService.findByIds(uniqueDriverIds);
const byId: Record<string, DriverDTO> = {};
const byId: Record<string, DriverViewModel> = {};
for (const dto of driverDtos) {
byId[dto.id] = dto;
byId[dto.id] = new DriverViewModel(dto);
}
setDriversById(byId);
} else {

View File

@@ -22,11 +22,11 @@ import {
Medal,
} from 'lucide-react';
import type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';
import type { LeagueScoringPresetDTO } from '@/lib/types/generated/LeagueScoringPresetDTO';
import type { LeagueScoringPresetViewModel } from '@/lib/view-models/LeagueScoringPresetViewModel';
interface LeagueReviewSummaryProps {
form: LeagueConfigFormModel;
presets: LeagueScoringPresetDTO[];
presets: LeagueScoringPresetViewModel[];
}
// Individual review card component
@@ -108,7 +108,7 @@ export default function LeagueReviewSummary({ form, presets }: LeagueReviewSumma
structure.mode === 'solo'
? 'Solo drivers'
: 'Team-based';
const modeDescription =
structure.mode === 'solo'
? 'Individual competition'
@@ -183,18 +183,18 @@ const stewardingLabel = (() => {
};
// Normalize visibility to new terminology
const isRanked = basics.visibility === 'ranked' || basics.visibility === 'public';
const isRanked = basics.visibility === 'public'; // public = ranked, private/unlisted = unranked
const visibilityLabel = isRanked ? 'Ranked' : 'Unranked';
const visibilityDescription = isRanked
? 'Competitive • Affects ratings'
: 'Casual • Friends only';
// Calculate total weekend duration
const totalWeekendMinutes = (timings.practiceMinutes ?? 0) +
(timings.qualifyingMinutes ?? 0) +
(timings.sprintRaceMinutes ?? 0) +
(timings.mainRaceMinutes ?? 0);
return (
<div className="space-y-6">
{/* League Summary */}

View File

@@ -3,7 +3,7 @@
import React, { useState, useRef, useEffect } from 'react';
import { Trophy, Award, Check, Zap, Settings, Globe, Medal, Plus, Minus, RotateCcw, HelpCircle, X } from 'lucide-react';
import { createPortal } from 'react-dom';
import type { LeagueScoringPresetDTO } from '@/lib/types/generated/LeagueScoringPresetDTO';
import type { LeagueScoringPresetViewModel } from '@/lib/view-models/LeagueScoringPresetViewModel';
import type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';
// ============================================================================
@@ -281,7 +281,7 @@ function DropRulesMockup() {
interface LeagueScoringSectionProps {
form: LeagueConfigFormModel;
presets: LeagueScoringPresetDTO[];
presets: LeagueScoringPresetViewModel[];
onChange?: (form: LeagueConfigFormModel) => void;
readOnly?: boolean;
/**
@@ -296,7 +296,7 @@ interface LeagueScoringSectionProps {
interface ScoringPatternSectionProps {
scoring: LeagueConfigFormModel['scoring'];
presets: LeagueScoringPresetDTO[];
presets: LeagueScoringPresetViewModel[];
readOnly?: boolean;
patternError?: string;
onChangePatternId?: (patternId: string) => void;
@@ -513,7 +513,7 @@ export function ScoringPatternSection({
onUpdateCustomPoints?.(DEFAULT_CUSTOM_POINTS);
};
const getPresetEmoji = (preset: LeagueScoringPresetDTO) => {
const getPresetEmoji = (preset: LeagueScoringPresetViewModel) => {
const name = preset.name.toLowerCase();
if (name.includes('sprint') || name.includes('double')) return '⚡';
if (name.includes('endurance') || name.includes('long')) return '🏆';
@@ -521,7 +521,7 @@ export function ScoringPatternSection({
return '🏁';
};
const getPresetDescription = (preset: LeagueScoringPresetDTO) => {
const getPresetDescription = (preset: LeagueScoringPresetViewModel) => {
const name = preset.name.toLowerCase();
if (name.includes('sprint')) return 'Sprint + Feature race';
if (name.includes('endurance')) return 'Long-form endurance';

View File

@@ -1,9 +1,9 @@
'use client';
import type { LeagueScoringConfigDTO } from '@/lib/types/generated/LeagueScoringConfigDTO';
import type { LeagueScoringConfigViewModel } from '@/lib/view-models/LeagueScoringConfigViewModel';
import { Trophy, Clock, Target, Zap, Info } from 'lucide-react';
type LeagueScoringConfigUi = LeagueScoringConfigDTO & {
type LeagueScoringConfigUi = LeagueScoringConfigViewModel & {
scoringPresetName?: string;
dropPolicySummary?: string;
championships?: Array<{
@@ -18,7 +18,7 @@ type LeagueScoringConfigUi = LeagueScoringConfigDTO & {
};
interface LeagueScoringTabProps {
scoringConfig: LeagueScoringConfigDTO | null;
scoringConfig: LeagueScoringConfigViewModel | null;
practiceMinutes?: number;
qualifyingMinutes?: number;
sprintRaceMinutes?: number;
@@ -178,22 +178,25 @@ export default function LeagueScoringTab({
</tr>
</thead>
<tbody>
{championship.pointsPreview.map((row, index: number) => (
<tr
key={`${row.sessionType}-${row.position}-${index}`}
className="border-b border-charcoal-outline/30"
>
<td className="py-1.5 pr-2 text-gray-200">
{row.sessionType}
</td>
<td className="py-1.5 px-2 text-gray-200">
P{row.position}
</td>
<td className="py-1.5 px-2 text-white">
{row.points}
</td>
</tr>
))}
{championship.pointsPreview.map((row, index: number) => {
const typedRow = row as { sessionType: string; position: number; points: number };
return (
<tr
key={`${typedRow.sessionType}-${typedRow.position}-${index}`}
className="border-b border-charcoal-outline/30"
>
<td className="py-1.5 pr-2 text-gray-200">
{typedRow.sessionType}
</td>
<td className="py-1.5 px-2 text-gray-200">
P{typedRow.position}
</td>
<td className="py-1.5 px-2 text-white">
{typedRow.points}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
@@ -231,4 +234,4 @@ export default function LeagueScoringTab({
))}
</div>
);
}
}

View File

@@ -1,7 +1,8 @@
'use client';
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
import { getMembership, type MembershipRole } from '@/lib/leagueMembership';
import { getMembership } from '@/lib/leagueMembership';
import type { MembershipRole } from '@/lib/types/MembershipRole';
interface MembershipStatusProps {
leagueId: string;
@@ -50,6 +51,13 @@ export default function MembershipStatus({ leagueId, className = '' }: Membershi
textColor: 'text-primary-blue',
borderColor: 'border-primary-blue/30',
};
default:
return {
text: 'Member',
bgColor: 'bg-primary-blue/10',
textColor: 'text-primary-blue',
borderColor: 'border-primary-blue/30',
};
}
};
@@ -60,4 +68,4 @@ export default function MembershipStatus({ leagueId, className = '' }: Membershi
{text}
</span>
);
}
}

View File

@@ -1,9 +1,9 @@
"use client";
import { useState, useEffect } from "react";
import { Protest } from "@gridpilot/racing/domain/entities/Protest";
import { Race } from "@gridpilot/racing/domain/entities/Race";
import { DriverDTO } from "@gridpilot/racing/application/dto/DriverDTO";
import { ProtestViewModel } from "../../lib/view-models/ProtestViewModel";
import { RaceViewModel } from "../../lib/view-models/RaceViewModel";
import { DriverViewModel } from "../../lib/view-models/DriverViewModel";
import Card from "../ui/Card";
import Button from "../ui/Button";
import { Clock, Grid3x3, TrendingDown, AlertCircle, Filter, Flag } from "lucide-react";
@@ -11,9 +11,9 @@ import { Clock, Grid3x3, TrendingDown, AlertCircle, Filter, Flag } from "lucide-
type PenaltyType = "time_penalty" | "grid_penalty" | "points_deduction" | "disqualification" | "warning" | "license_points";
interface PenaltyHistoryListProps {
protests: Protest[];
races: Record<string, Race>;
drivers: Record<string, DriverDTO>;
protests: ProtestViewModel[];
races: Record<string, RaceViewModel>;
drivers: Record<string, DriverViewModel>;
}
export function PenaltyHistoryList({
@@ -21,7 +21,7 @@ export function PenaltyHistoryList({
races,
drivers,
}: PenaltyHistoryListProps) {
const [filteredProtests, setFilteredProtests] = useState<Protest[]>([]);
const [filteredProtests, setFilteredProtests] = useState<ProtestViewModel[]>([]);
const [filterType, setFilterType] = useState<"all">("all");
useEffect(() => {
@@ -61,6 +61,8 @@ export function PenaltyHistoryList({
const race = races[protest.raceId];
const protester = drivers[protest.protestingDriverId];
const accused = drivers[protest.accusedDriverId];
const incident = protest.incident;
const resolvedDate = protest.reviewedAt || protest.filedAt;
return (
<Card key={protest.id} className="p-4">
@@ -75,7 +77,7 @@ export function PenaltyHistoryList({
Protest #{protest.id.substring(0, 8)}
</h3>
<p className="text-sm text-gray-400">
Resolved {new Date(protest.reviewedAt || protest.filedAt).toLocaleDateString()}
{resolvedDate ? `Resolved ${new Date(resolvedDate).toLocaleDateString()}` : 'Resolved'}
</p>
</div>
<span className={`px-3 py-1 rounded-full text-xs font-medium flex-shrink-0 ${getStatusColor(protest.status)}`}>
@@ -86,13 +88,15 @@ export function PenaltyHistoryList({
<p className="text-gray-400">
<span className="font-medium">{protester?.name || 'Unknown'}</span> vs <span className="font-medium">{accused?.name || 'Unknown'}</span>
</p>
{race && (
{race && incident && (
<p className="text-gray-500">
{race.track} ({race.car}) - Lap {protest.incident.lap}
{race.track} ({race.car}) - Lap {incident.lap}
</p>
)}
</div>
<p className="text-gray-300 text-sm">{protest.incident.description}</p>
{incident && (
<p className="text-gray-300 text-sm">{incident.description}</p>
)}
{protest.decisionNotes && (
<div className="mt-2 p-2 rounded bg-iron-gray/30 border border-charcoal-outline/50">
<p className="text-xs text-gray-400">

View File

@@ -1,19 +1,19 @@
"use client";
import { Protest } from "@gridpilot/racing/domain/entities/Protest";
import { Race } from "@gridpilot/racing/domain/entities/Race";
import { DriverDTO } from "@gridpilot/racing/application/dto/DriverDTO";
import { ProtestViewModel } from "../../lib/view-models/ProtestViewModel";
import { RaceViewModel } from "../../lib/view-models/RaceViewModel";
import { DriverViewModel } from "../../lib/view-models/DriverViewModel";
import Card from "../ui/Card";
import Button from "../ui/Button";
import Link from "next/link";
import { AlertCircle, Video, ChevronRight, Flag, Clock, AlertTriangle } from "lucide-react";
interface PendingProtestsListProps {
protests: Protest[];
races: Record<string, Race>;
drivers: Record<string, DriverDTO>;
protests: ProtestViewModel[];
races: Record<string, RaceViewModel>;
drivers: Record<string, DriverViewModel>;
leagueId: string;
onReviewProtest: (protest: Protest) => void;
onReviewProtest: (protest: ProtestViewModel) => void;
onProtestReviewed: () => void;
}
@@ -45,7 +45,7 @@ export function PendingProtestsList({
return (
<div className="space-y-4">
{protests.map((protest) => {
const daysSinceFiled = Math.floor((Date.now() - new Date(protest.filedAt).getTime()) / (1000 * 60 * 60 * 24));
const daysSinceFiled = Math.floor((Date.now() - new Date(protest.filedAt || protest.submittedAt).getTime()) / (1000 * 60 * 60 * 24));
const isUrgent = daysSinceFiled > 2;
return (
@@ -64,7 +64,7 @@ export function PendingProtestsList({
Protest #{protest.id.substring(0, 8)}
</h3>
<p className="text-sm text-gray-400">
Filed {new Date(protest.filedAt).toLocaleDateString()}
Filed {new Date(protest.filedAt || protest.submittedAt).toLocaleDateString()}
</p>
</div>
<div className="flex items-center gap-2">
@@ -84,10 +84,10 @@ export function PendingProtestsList({
<div className="space-y-2">
<div className="flex items-center gap-2 text-sm">
<Flag className="h-4 w-4 text-gray-400" />
<span className="text-gray-400">Lap {protest.incident.lap}</span>
<span className="text-gray-400">Lap {protest.incident?.lap || 'N/A'}</span>
</div>
<p className="text-gray-300 line-clamp-2 leading-relaxed">
{protest.incident.description}
{protest.incident?.description || protest.description}
</p>
{protest.proofVideoUrl && (
<div className="inline-flex items-center gap-2 px-3 py-1.5 text-sm bg-primary-blue/10 text-primary-blue rounded-lg border border-primary-blue/20">

View File

@@ -3,6 +3,7 @@
import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import Button from '@/components/ui/Button';
import { useServices } from '@/lib/services/ServiceProvider';
import { AlertTriangle, Clock, Flag, Zap } from 'lucide-react';
interface DriverOption {
@@ -43,6 +44,7 @@ export default function QuickPenaltyModal({ raceId, drivers, onClose, preSelecte
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const router = useRouter();
const { penaltyService } = useServices();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -52,7 +54,6 @@ export default function QuickPenaltyModal({ raceId, drivers, onClose, preSelecte
setError(null);
try {
const useCase = getQuickPenaltyUseCase();
const command: any = {
raceId: selectedRaceId,
driverId: selectedDriver,
@@ -63,7 +64,7 @@ export default function QuickPenaltyModal({ raceId, drivers, onClose, preSelecte
if (notes.trim()) {
command.notes = notes.trim();
}
await useCase.execute(command);
await penaltyService.applyPenalty(command);
// Refresh the page to show updated results
router.refresh();

View File

@@ -28,7 +28,7 @@ export function ReadonlyLeagueInfo({ league, configForm }: ReadonlyLeagueInfoPro
{
icon: Eye,
label: 'Visibility',
value: basics.visibility === 'ranked' || basics.visibility === 'public' ? 'Ranked' : 'Unranked',
value: basics.visibility === 'public' ? 'Ranked' : 'Unranked',
},
{
icon: Users,

View File

@@ -1,8 +1,7 @@
"use client";
import { useState } from "react";
import { Protest } from "@gridpilot/racing/domain/entities/Protest";
import { PenaltyType } from "@gridpilot/racing/domain/entities/Penalty";
import { ProtestViewModel } from "../../lib/view-models/ProtestViewModel";
import Modal from "../ui/Modal";
import Button from "../ui/Button";
import Card from "../ui/Card";
@@ -22,8 +21,10 @@ import {
FileWarning,
} from "lucide-react";
type PenaltyType = "time_penalty" | "grid_penalty" | "points_deduction" | "disqualification" | "warning" | "license_points" | "probation" | "fine" | "race_ban";
interface ReviewProtestModalProps {
protest: Protest | null;
protest: ProtestViewModel | null;
onClose: () => void;
onAccept: (
protestId: string,
@@ -213,13 +214,13 @@ export function ReviewProtestModal({
<div className="flex items-center justify-between text-sm">
<span className="text-gray-400">Filed Date</span>
<span className="text-white font-medium">
{new Date(protest.filedAt).toLocaleString()}
{new Date(protest.filedAt || protest.submittedAt).toLocaleString()}
</span>
</div>
<div className="flex items-center justify-between text-sm">
<span className="text-gray-400">Incident Lap</span>
<span className="text-white font-medium">
Lap {protest.incident.lap}
Lap {protest.incident?.lap || 'N/A'}
</span>
</div>
<div className="flex items-center justify-between text-sm">
@@ -236,7 +237,7 @@ export function ReviewProtestModal({
Description
</label>
<Card className="p-4 bg-gray-800/50">
<p className="text-gray-300">{protest.incident.description}</p>
<p className="text-gray-300">{protest.incident?.description || protest.description}</p>
</Card>
</div>

View File

@@ -4,12 +4,24 @@ import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Button from '../ui/Button';
import Input from '../ui/Input';
import { createScheduleRaceFormPresenter } from '@/lib/presenters/factories';
import type {
ScheduleRaceFormData,
ScheduledRaceViewModel,
LeagueOptionViewModel,
} from '@/lib/presenters/ScheduleRaceFormPresenter';
import { useServices } from '@/lib/services/ServiceProvider';
import type { LeagueSummaryViewModel } from '@/lib/view-models/LeagueSummaryViewModel';
interface ScheduleRaceFormData {
leagueId: string;
track: string;
car: string;
sessionType: 'practice' | 'qualifying' | 'race';
scheduledDate: string;
scheduledTime: string;
}
interface ScheduledRaceViewModel {
id: string;
track: string;
car: string;
scheduledAt: string;
}
interface ScheduleRaceFormProps {
preSelectedLeagueId?: string;
@@ -23,7 +35,8 @@ export default function ScheduleRaceForm({
onCancel
}: ScheduleRaceFormProps) {
const router = useRouter();
const [leagues, setLeagues] = useState<LeagueOptionViewModel[]>([]);
const { leagueService, raceService } = useServices();
const [leagues, setLeagues] = useState<LeagueSummaryViewModel[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -40,11 +53,15 @@ export default function ScheduleRaceForm({
useEffect(() => {
const loadLeagues = async () => {
const allLeagues = await loadScheduleRaceFormLeagues();
setLeagues(allLeagues);
try {
const allLeagues = await leagueService.getAllLeagues();
setLeagues(allLeagues);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load leagues');
}
};
void loadLeagues();
}, []);
}, [leagueService]);
const validateForm = (): boolean => {
const errors: Record<string, string> = {};
@@ -94,7 +111,25 @@ export default function ScheduleRaceForm({
setError(null);
try {
const createdRace = await scheduleRaceFromForm(formData);
// Create race using the race service
// Note: This assumes the race service has a create method
// If not available, we'll need to implement it or use an alternative approach
const raceData = {
leagueId: formData.leagueId,
track: formData.track,
car: formData.car,
sessionType: formData.sessionType,
scheduledAt: new Date(`${formData.scheduledDate}T${formData.scheduledTime}`).toISOString(),
};
// For now, we'll simulate race creation since the race service may not have create method
// In a real implementation, this would call raceService.createRace(raceData)
const createdRace: ScheduledRaceViewModel = {
id: `race-${Date.now()}`,
track: formData.track,
car: formData.car,
scheduledAt: new Date(`${formData.scheduledDate}T${formData.scheduledTime}`).toISOString(),
};
if (onSuccess) {
onSuccess(createdRace);
@@ -174,7 +209,7 @@ export default function ScheduleRaceForm({
`}
>
<option value="">Select a league</option>
{leagues.map((league: LeagueOptionViewModel) => (
{leagues.map((league) => (
<option key={league.id} value={league.id}>
{league.name}
</option>

View File

@@ -4,9 +4,8 @@ import { useState, useRef, useEffect } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import { Star } from 'lucide-react';
import type { DriverDTO } from '@/lib/types/generated/DriverDTO';
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import type { LeagueMembership } from '@/lib/types/LeagueMembership';
import type { MembershipRoleDTO } from '@/lib/types/generated/MembershipRoleDTO';
import { LeagueRoleDisplay } from '@/lib/display-objects/LeagueRoleDisplay';
import CountryFlag from '@/components/ui/CountryFlag';
import { useServices } from '@/lib/services/ServiceProvider';
@@ -34,13 +33,13 @@ interface StandingsTableProps {
bonusPoints: number;
teamName?: string;
}>;
drivers: DriverDTO[];
drivers: DriverViewModel[];
leagueId: string;
memberships?: LeagueMembership[];
currentDriverId?: string;
isAdmin?: boolean;
onRemoveMember?: (driverId: string) => void;
onUpdateRole?: (driverId: string, role: MembershipRoleDTO['value']) => void;
onUpdateRole?: (driverId: string, role: string) => void;
}
export default function StandingsTable({
@@ -69,7 +68,7 @@ export default function StandingsTable({
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const getDriver = (driverId: string): DriverDTO | undefined => {
const getDriver = (driverId: string): DriverViewModel | undefined => {
return drivers.find((d) => d.id === driverId);
};
@@ -91,7 +90,7 @@ export default function StandingsTable({
return driverId === currentDriverId;
};
type MembershipRole = MembershipRoleDTO['value'];
type MembershipRole = string;
const handleRoleChange = (driverId: string, newRole: MembershipRole) => {
if (!onUpdateRole) return;
@@ -111,7 +110,7 @@ export default function StandingsTable({
}
if (newRole !== membership.role && confirm(confirmationMessages[newRole])) {
onUpdateRole(driverId, newRole as MembershipRoleDTO['value']);
onUpdateRole(driverId, newRole);
setActiveMenu(null);
}
};