make website run

This commit is contained in:
2025-12-17 14:40:46 +01:00
parent daa4bb6576
commit a213a5cf9f
54 changed files with 196 additions and 352 deletions

View File

@@ -1,7 +1,6 @@
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';
import { getAuthService } from '../../../../lib/auth';
const STATE_COOKIE = 'gp_demo_auth_state';

View File

@@ -25,7 +25,6 @@ import {
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import { getAuthService } from '@/lib/auth';
import type {
DashboardOverviewViewModel,
DashboardFeedItemSummaryViewModel,

View File

@@ -36,13 +36,6 @@ import {
Megaphone,
DollarSign,
} from 'lucide-react';
import {
getGetProfileOverviewUseCase,
getGetDriverTeamUseCase,
getImageService,
getGetAllTeamsUseCase,
getGetTeamMembersUseCase,
} from '@/lib/di-container';
import { AllTeamsPresenter } from '@/lib/presenters/AllTeamsPresenter';
import { TeamMembersPresenter } from '@/lib/presenters/TeamMembersPresenter';
import { Driver, EntityMappers, type Team } from '@core/racing';

View File

@@ -27,7 +27,6 @@ import Button from '@/components/ui/Button';
import Input from '@/components/ui/Input';
import Card from '@/components/ui/Card';
import Heading from '@/components/ui/Heading';
import { getGetDriversLeaderboardUseCase } from '@/lib/di-container';
import { DriversLeaderboardPresenter } from '@/lib/presenters/DriversLeaderboardPresenter';
import type { DriverLeaderboardItemViewModel, SkillLevel } from '@core/racing/application/presenters/IDriversLeaderboardPresenter';
import Image from 'next/image';

View File

@@ -4,14 +4,12 @@ import Image from 'next/image';
import Link from 'next/link';
import './globals.css';
import { getAppMode } from '@/lib/mode';
import { getAuthService } from '@/lib/auth';
import { AlphaNav } from '@/components/alpha/AlphaNav';
import AlphaBanner from '@/components/alpha/AlphaBanner';
import AlphaFooter from '@/components/alpha/AlphaFooter';
import { AuthProvider } from '@/lib/auth/AuthContext';
import NotificationProvider from '@/components/notifications/NotificationProvider';
import DevToolbar from '@/components/dev/DevToolbar';
import { initializeDIContainer } from '@/lib/di-setup';
export const dynamic = 'force-dynamic';
@@ -50,12 +48,11 @@ export default async function RootLayout({
}: {
children: React.ReactNode;
}) {
await initializeDIContainer();
const mode = getAppMode();
if (mode === 'alpha') {
const authService = getAuthService();
const session = await authService.getCurrentSession();
//const session = await authService.getCurrentSession();
const session = null;
return (
<html lang="en" className="scroll-smooth overflow-x-hidden">

View File

@@ -19,7 +19,6 @@ import {
import Button from '@/components/ui/Button';
import Input from '@/components/ui/Input';
import Heading from '@/components/ui/Heading';
import { getGetDriversLeaderboardUseCase } from '@/lib/di-container';
import { DriversLeaderboardPresenter } from '@/lib/presenters/DriversLeaderboardPresenter';
import type { DriverLeaderboardItemViewModel, SkillLevel } from '@core/racing/application/presenters/IDriversLeaderboardPresenter';
import Image from 'next/image';

View File

@@ -20,7 +20,6 @@ import {
} from 'lucide-react';
import Button from '@/components/ui/Button';
import Heading from '@/components/ui/Heading';
import { getGetDriversLeaderboardUseCase, getGetTeamsLeaderboardUseCase } from '@/lib/di-container';
import { DriversLeaderboardPresenter } from '@/lib/presenters/DriversLeaderboardPresenter';
import { TeamsLeaderboardPresenter } from '@/lib/presenters/TeamsLeaderboardPresenter';
import type { DriverLeaderboardItemViewModel, SkillLevel } from '@core/racing/application/presenters/IDriversLeaderboardPresenter';

View File

@@ -4,14 +4,6 @@ import React, { useState, useEffect } from 'react';
import { useParams, usePathname, useRouter } from 'next/navigation';
import Breadcrumbs from '@/components/layout/Breadcrumbs';
import LeagueHeader from '@/components/leagues/LeagueHeader';
import {
getLeagueRepository,
getDriverRepository,
getLeagueMembershipRepository,
getSeasonRepository,
getSponsorRepository,
getSeasonSponsorshipRepository,
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';
import type { League } from '@core/racing/domain/entities/League';

View File

@@ -23,19 +23,6 @@ import {
type LeagueScoringConfigDTO,
Race,
} from '@core/racing';
import {
getLeagueRepository,
getRaceRepository,
getDriverRepository,
getGetLeagueScoringConfigUseCase,
getDriverStats,
getAllDriverRankings,
getGetLeagueStatsUseCase,
getSeasonRepository,
getSponsorRepository,
getSeasonSponsorshipRepository,
getCompleteRaceUseCase,
} from '@/lib/di-container';
import { LeagueScoringConfigPresenter } from '@/lib/presenters/LeagueScoringConfigPresenter';
import { Trophy, Star, ExternalLink, Calendar, Users } from 'lucide-react';
import { getMembership, getLeagueMembers } from '@/lib/leagueMembership';

View File

@@ -3,10 +3,6 @@
import { useState, useEffect } from 'react';
import { useParams } from 'next/navigation';
import Card from '@/components/ui/Card';
import {
getLeagueRepository,
getGetLeagueScoringConfigUseCase
} from '@/lib/di-container';
import { LeagueScoringConfigPresenter } from '@/lib/presenters/LeagueScoringConfigPresenter';
import type { LeagueScoringConfigDTO } from '@core/racing/application/dto/LeagueScoringConfigDTO';
import type { League } from '@core/racing/domain/entities/League';

View File

@@ -6,7 +6,6 @@ import LeagueSchedule from '@/components/leagues/LeagueSchedule';
import ScheduleRaceForm from '@/components/leagues/ScheduleRaceForm';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { getLeagueMembershipRepository } from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';

View File

@@ -4,16 +4,6 @@ import { useState, useEffect, useMemo } from 'react';
import { useParams, useRouter } from 'next/navigation';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import {
getLeagueRepository,
getDriverRepository,
getGetLeagueFullConfigUseCase,
getLeagueMembershipRepository,
getDriverStats,
getAllDriverRankings,
getListLeagueScoringPresetsUseCase,
getTransferLeagueOwnershipUseCase
} from '@/lib/di-container';
import { LeagueFullConfigPresenter } from '@/lib/presenters/LeagueFullConfigPresenter';
import { LeagueScoringPresetsPresenter } from '@/lib/presenters/LeagueScoringPresetsPresenter';
import { useEffectiveDriverId } from '@/lib/currentDriver';

View File

@@ -5,10 +5,6 @@ import { useParams } from 'next/navigation';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import { LeagueSponsorshipsSection } from '@/components/leagues/LeagueSponsorshipsSection';
import {
getLeagueRepository,
getLeagueMembershipRepository,
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';
import { AlertTriangle, Building, DollarSign } from 'lucide-react';

View File

@@ -9,11 +9,6 @@ import {
type DriverDTO,
type LeagueDriverSeasonStatsDTO,
} from '@core/racing';
import {
getGetLeagueDriverSeasonStatsUseCase,
getDriverRepository,
getLeagueMembershipRepository
} from '@/lib/di-container';
import { LeagueDriverSeasonStatsPresenter } from '@/lib/presenters/LeagueDriverSeasonStatsPresenter';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';

View File

@@ -8,15 +8,6 @@ import Button from '@/components/ui/Button';
import { ReviewProtestModal } from '@/components/leagues/ReviewProtestModal';
import QuickPenaltyModal from '@/components/leagues/QuickPenaltyModal';
import PenaltyFAB from '@/components/leagues/PenaltyFAB';
import {
getRaceRepository,
getProtestRepository,
getDriverRepository,
getLeagueMembershipRepository,
getReviewProtestUseCase,
getApplyPenaltyUseCase,
getPenaltyRepository
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';
import type { Protest } from '@core/racing/domain/entities/Protest';

View File

@@ -5,16 +5,6 @@ import { useParams, useRouter } from 'next/navigation';
import Link from 'next/link';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import {
getProtestRepository,
getRaceRepository,
getDriverRepository,
getLeagueMembershipRepository,
getReviewProtestUseCase,
getApplyPenaltyUseCase,
getRequestProtestDefenseUseCase,
getSendNotificationUseCase
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';
import type { Protest } from '@core/racing/domain/entities/Protest';

View File

@@ -32,7 +32,7 @@ import Input from '@/components/ui/Input';
import Heading from '@/components/ui/Heading';
import type { LeagueSummaryViewModel } from '@core/racing/application/presenters/IAllLeaguesWithCapacityAndScoringPresenter';
import { AllLeaguesWithCapacityAndScoringPresenter } from '@/lib/presenters/AllLeaguesWithCapacityAndScoringPresenter';
import { getGetAllLeaguesWithCapacityAndScoringUseCase } from '@/lib/di-container';
// ============================================================================
// TYPES

View File

@@ -1,5 +1,4 @@
import { redirect } from 'next/navigation';
import { getAuthService } from '@/lib/auth';
import OnboardingWizard from '@/components/onboarding/OnboardingWizard';
export const dynamic = 'force-dynamic';

View File

@@ -1,7 +1,6 @@
import { redirect } from 'next/navigation';
import { getAppMode } from '@/lib/mode';
import { getAuthService } from '@/lib/auth';
import Hero from '@/components/landing/Hero';
import AlternatingSection from '@/components/landing/AlternatingSection';
import FeatureGrid from '@/components/landing/FeatureGrid';
@@ -15,23 +14,19 @@ import SimPlatformMockup from '@/components/mockups/SimPlatformMockup';
import MockupStack from '@/components/ui/MockupStack';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import {
topLeagues,
teams,
getUpcomingRaces,
} from '@core/testing-support';
export default async function HomePage() {
const authService = getAuthService();
const session = await authService.getCurrentSession();
const session = null; // TODO
if (session) {
redirect('/dashboard');
}
const mode = getAppMode();
const isAlpha = mode === 'alpha';
const upcomingRaces = getUpcomingRaces(3);
// const upcomingRaces = getUpcomingRaces(3);
const upcomingRaces = []; // TODO
const topLeagues = []; // TODO
const teams = []; // TODO
return (
<main className="min-h-screen">

View File

@@ -4,7 +4,6 @@ import { useEffect, useState } from 'react';
import Link from 'next/link';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import { getLeagueRepository, getLeagueMembershipRepository } from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import type { League } from '@core/racing/domain/entities/League';
import type { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';

View File

@@ -34,11 +34,6 @@ import {
Percent,
Activity,
} from 'lucide-react';
import {
getGetProfileOverviewUseCase,
getImageService,
getUpdateDriverProfileUseCase,
} from '@/lib/di-container';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import type {
ProfileOverviewViewModel,

View File

@@ -6,16 +6,7 @@ import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import Breadcrumbs from '@/components/layout/Breadcrumbs';
import PendingSponsorshipRequests, { type PendingRequestDTO } from '@/components/sponsors/PendingSponsorshipRequests';
import {
getGetPendingSponsorshipRequestsUseCase,
getAcceptSponsorshipRequestUseCase,
getRejectSponsorshipRequestUseCase,
getDriverRepository,
getLeagueRepository,
getTeamRepository,
getLeagueMembershipRepository,
getTeamMembershipRepository,
} from '@/lib/di-container';
import { PendingSponsorshipRequestsPresenter } from '@/lib/presenters/PendingSponsorshipRequestsPresenter';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';

View File

@@ -8,7 +8,7 @@ import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import Breadcrumbs from '@/components/layout/Breadcrumbs';
import SponsorInsightsCard, { useSponsorMode, MetricBuilders, SlotTemplates } from '@/components/sponsors/SponsorInsightsCard';
import { getImageService } from '@/lib/di-container';
import { TeamMembersPresenter } from '@/lib/presenters/TeamMembersPresenter';
import { TeamDetailsPresenter } from '@/lib/presenters/TeamDetailsPresenter';
import type { TeamDetailsViewModel } from '@core/racing/application/presenters/ITeamDetailsPresenter';
@@ -16,11 +16,7 @@ import TeamRoster from '@/components/teams/TeamRoster';
import TeamStandings from '@/components/teams/TeamStandings';
import TeamAdmin from '@/components/teams/TeamAdmin';
import JoinTeamButton from '@/components/teams/JoinTeamButton';
import {
getGetTeamDetailsUseCase,
getGetTeamMembersUseCase,
getTeamMembershipRepository,
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { Users, Trophy, TrendingUp, Star, Zap } from 'lucide-react';

View File

@@ -22,7 +22,6 @@ import {
import Button from '@/components/ui/Button';
import Input from '@/components/ui/Input';
import Heading from '@/components/ui/Heading';
import { getGetTeamsLeaderboardUseCase } from '@/lib/di-container';
import { TeamsLeaderboardPresenter } from '@/lib/presenters/TeamsLeaderboardPresenter';
import type {
TeamLeaderboardItemViewModel,

View File

@@ -28,7 +28,6 @@ import Card from '@/components/ui/Card';
import Input from '@/components/ui/Input';
import Heading from '@/components/ui/Heading';
import CreateTeamForm from '@/components/teams/CreateTeamForm';
import { getGetTeamsLeaderboardUseCase } from '@/lib/di-container';
import { TeamsLeaderboardPresenter } from '@/lib/presenters/TeamsLeaderboardPresenter';
import type { TeamLeaderboardItemViewModel, SkillLevel } from '@core/racing/application/presenters/ITeamsLeaderboardPresenter';

View File

@@ -3,7 +3,6 @@
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { getSendNotificationUseCase, getRaceRepository, getLeagueRepository } from '@/lib/di-container';
import type { NotificationUrgency } from '@core/notifications/application';
import {
Bell,
@@ -182,135 +181,135 @@ export default function DevToolbar() {
return null;
}
const handleSendNotification = async () => {
setSending(true);
try {
const sendNotification = getSendNotificationUseCase();
// const handleSendNotification = async () => {
// setSending(true);
// try {
// const sendNotification = getSendNotificationUseCase();
const raceRepository = getRaceRepository();
const leagueRepository = getLeagueRepository();
// const raceRepository = getRaceRepository();
// const leagueRepository = getLeagueRepository();
const [allRaces, allLeagues] = await Promise.all([
raceRepository.findAll(),
leagueRepository.findAll(),
]);
// const [allRaces, allLeagues] = await Promise.all([
// raceRepository.findAll(),
// leagueRepository.findAll(),
// ]);
const completedRaces = allRaces.filter((race) => race.status === 'completed');
const scheduledRaces = allRaces.filter((race) => race.status === 'scheduled');
// const completedRaces = allRaces.filter((race) => race.status === 'completed');
// const scheduledRaces = allRaces.filter((race) => race.status === 'scheduled');
const primaryRace = completedRaces[0] ?? allRaces[0];
const secondaryRace = scheduledRaces[0] ?? allRaces[1] ?? primaryRace;
const primaryLeague = allLeagues[0];
// const primaryRace = completedRaces[0] ?? allRaces[0];
// const secondaryRace = scheduledRaces[0] ?? allRaces[1] ?? primaryRace;
// const primaryLeague = allLeagues[0];
const notificationDeadline =
selectedUrgency === 'modal'
? new Date(Date.now() + 48 * 60 * 60 * 1000)
: undefined;
// const notificationDeadline =
// selectedUrgency === 'modal'
// ? new Date(Date.now() + 48 * 60 * 60 * 1000)
// : undefined;
let title: string;
let body: string;
let notificationType: 'protest_filed' | 'protest_defense_requested' | 'protest_vote_required' | 'race_performance_summary' | 'race_final_results';
let actionUrl: string;
// let title: string;
// let body: string;
// let notificationType: 'protest_filed' | 'protest_defense_requested' | 'protest_vote_required' | 'race_performance_summary' | 'race_final_results';
// let actionUrl: string;
switch (selectedType) {
case 'protest_filed': {
const raceId = primaryRace?.id;
title = '🚨 Protest Filed Against You';
body =
'A protest has been filed against you for unsafe rejoining during a recent race. Please review the incident details.';
notificationType = 'protest_filed';
actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races';
break;
}
case 'defense_requested': {
const raceId = secondaryRace?.id ?? primaryRace?.id;
title = '⚖️ Defense Requested';
body =
'A steward has requested your defense regarding a recent incident. Please provide your side of the story within 48 hours.';
notificationType = 'protest_defense_requested';
actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races';
break;
}
case 'vote_required': {
const leagueId = primaryLeague?.id;
title = '🗳️ Your Vote Required';
body =
'As a league steward, you are required to vote on an open protest. Please review the case and cast your vote.';
notificationType = 'protest_vote_required';
actionUrl = leagueId ? `/leagues/${leagueId}/stewarding` : '/leagues';
break;
}
case 'race_performance_summary': {
const raceId = primaryRace?.id;
const leagueId = primaryLeague?.id;
title = '🏁 Race Complete: Performance Summary';
body =
'Your Monza Grand Prix race is finished! You finished P1 with 0 incidents. Provisional rating: +25 points. View full results and standings.';
notificationType = 'race_performance_summary';
actionUrl = raceId ? `/races/${raceId}` : '/races';
break;
}
case 'race_final_results': {
const leagueId = primaryLeague?.id;
title = '🏆 Final Results: Monza Grand Prix';
body =
'Stewarding is now closed. Your final result: P1 (+25 rating). No penalties were applied. View championship standings.';
notificationType = 'race_final_results';
actionUrl = leagueId ? `/leagues/${leagueId}/standings` : '/leagues';
break;
}
}
// switch (selectedType) {
// case 'protest_filed': {
// const raceId = primaryRace?.id;
// title = '🚨 Protest Filed Against You';
// body =
// 'A protest has been filed against you for unsafe rejoining during a recent race. Please review the incident details.';
// notificationType = 'protest_filed';
// actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races';
// break;
// }
// case 'defense_requested': {
// const raceId = secondaryRace?.id ?? primaryRace?.id;
// title = '⚖️ Defense Requested';
// body =
// 'A steward has requested your defense regarding a recent incident. Please provide your side of the story within 48 hours.';
// notificationType = 'protest_defense_requested';
// actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races';
// break;
// }
// case 'vote_required': {
// const leagueId = primaryLeague?.id;
// title = '🗳️ Your Vote Required';
// body =
// 'As a league steward, you are required to vote on an open protest. Please review the case and cast your vote.';
// notificationType = 'protest_vote_required';
// actionUrl = leagueId ? `/leagues/${leagueId}/stewarding` : '/leagues';
// break;
// }
// case 'race_performance_summary': {
// const raceId = primaryRace?.id;
// const leagueId = primaryLeague?.id;
// title = '🏁 Race Complete: Performance Summary';
// body =
// 'Your Monza Grand Prix race is finished! You finished P1 with 0 incidents. Provisional rating: +25 points. View full results and standings.';
// notificationType = 'race_performance_summary';
// actionUrl = raceId ? `/races/${raceId}` : '/races';
// break;
// }
// case 'race_final_results': {
// const leagueId = primaryLeague?.id;
// title = '🏆 Final Results: Monza Grand Prix';
// body =
// 'Stewarding is now closed. Your final result: P1 (+25 rating). No penalties were applied. View championship standings.';
// notificationType = 'race_final_results';
// actionUrl = leagueId ? `/leagues/${leagueId}/standings` : '/leagues';
// break;
// }
// }
const actions =
selectedUrgency === 'modal'
? selectedType.startsWith('race_')
? [
{ label: selectedType === 'race_performance_summary' ? '🏁 View Race Results' : '🏆 View Standings', type: 'primary' as const, href: actionUrl, actionId: 'view' },
{ label: '🎉 Share Achievement', type: 'secondary' as const, actionId: 'share' },
]
: [
{ label: 'View Protest', type: 'primary' as const, href: actionUrl, actionId: 'view' },
{ label: 'Dismiss', type: 'secondary' as const, actionId: 'dismiss' },
]
: [];
// const actions =
// selectedUrgency === 'modal'
// ? selectedType.startsWith('race_')
// ? [
// { label: selectedType === 'race_performance_summary' ? '🏁 View Race Results' : '🏆 View Standings', type: 'primary' as const, href: actionUrl, actionId: 'view' },
// { label: '🎉 Share Achievement', type: 'secondary' as const, actionId: 'share' },
// ]
// : [
// { label: 'View Protest', type: 'primary' as const, href: actionUrl, actionId: 'view' },
// { label: 'Dismiss', type: 'secondary' as const, actionId: 'dismiss' },
// ]
// : [];
await sendNotification.execute({
recipientId: currentDriverId,
type: notificationType,
title,
body,
actionUrl,
urgency: selectedUrgency as NotificationUrgency,
requiresResponse: selectedUrgency === 'modal' && !selectedType.startsWith('race_'),
actions,
data: {
...(selectedType.startsWith('protest_') ? {
protestId: `demo-protest-${Date.now()}`,
} : {}),
...(selectedType.startsWith('race_') ? {
raceEventId: `demo-race-event-${Date.now()}`,
sessionId: `demo-session-${Date.now()}`,
position: 1,
positionChange: 0,
incidents: 0,
provisionalRatingChange: 25,
finalRatingChange: 25,
hadPenaltiesApplied: false,
} : {}),
raceId: primaryRace?.id ?? '',
leagueId: primaryLeague?.id ?? '',
...(notificationDeadline && selectedType.startsWith('protest_') ? { deadline: notificationDeadline } : {}),
},
});
// await sendNotification.execute({
// recipientId: currentDriverId,
// type: notificationType,
// title,
// body,
// actionUrl,
// urgency: selectedUrgency as NotificationUrgency,
// requiresResponse: selectedUrgency === 'modal' && !selectedType.startsWith('race_'),
// actions,
// data: {
// ...(selectedType.startsWith('protest_') ? {
// protestId: `demo-protest-${Date.now()}`,
// } : {}),
// ...(selectedType.startsWith('race_') ? {
// raceEventId: `demo-race-event-${Date.now()}`,
// sessionId: `demo-session-${Date.now()}`,
// position: 1,
// positionChange: 0,
// incidents: 0,
// provisionalRatingChange: 25,
// finalRatingChange: 25,
// hadPenaltiesApplied: false,
// } : {}),
// raceId: primaryRace?.id ?? '',
// leagueId: primaryLeague?.id ?? '',
// ...(notificationDeadline && selectedType.startsWith('protest_') ? { deadline: notificationDeadline } : {}),
// },
// });
setLastSent(`${selectedType}-${selectedUrgency}`);
setTimeout(() => setLastSent(null), 3000);
} catch (error) {
console.error('Failed to send demo notification:', error);
} finally {
setSending(false);
}
};
// setLastSent(`${selectedType}-${selectedUrgency}`);
// setTimeout(() => setLastSent(null), 3000);
// } catch (error) {
// console.error('Failed to send demo notification:', error);
// } finally {
// setSending(false);
// }
// };
if (isMinimized) {
return (

View File

@@ -5,7 +5,6 @@ import { useRouter } from 'next/navigation';
import Input from '../ui/Input';
import Button from '../ui/Button';
import { Driver } from '@core/racing';
import { getDriverRepository } from '../../lib/di-container';
interface FormErrors {
name?: string;

View File

@@ -1,7 +1,6 @@
import Link from 'next/link';
import Image from 'next/image';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import { getImageService } from '@/lib/di-container';
export interface DriverIdentityProps {
driver: DriverDTO;

View File

@@ -8,7 +8,6 @@ import CareerHighlights from './CareerHighlights';
import DriverRankings from './DriverRankings';
import PerformanceMetrics from './PerformanceMetrics';
import { useEffect, useState } from 'react';
import { getLeagueRankings, getGetDriverTeamUseCase, getGetProfileOverviewUseCase } from '@/lib/di-container';
import { DriverTeamPresenter } from '@/lib/presenters/DriverTeamPresenter';
import { getPrimaryLeagueIdForDriver } from '@/lib/leagueMembership';
import type { ProfileOverviewViewModel } from '@core/racing/application/presenters/IProfileOverviewPresenter';

View File

@@ -4,7 +4,6 @@ import { useState, useEffect } from 'react';
import Card from '../ui/Card';
import Button from '../ui/Button';
import RaceResultCard from '../races/RaceResultCard';
import { getRaceRepository, getLeagueRepository, getResultRepository } from '@/lib/di-container';
import { Race } from '@core/racing/domain/entities/Race';
import { Result } from '@core/racing/domain/entities/Result';
import { League } from '@core/racing/domain/entities/League';

View File

@@ -2,7 +2,6 @@
import Card from '../ui/Card';
import RankBadge from './RankBadge';
import { getLeagueRankings, getGetProfileOverviewUseCase } from '@/lib/di-container';
import { useState, useEffect } from 'react';
import { getPrimaryLeagueIdForDriver } from '@/lib/leagueMembership';
import type { ProfileOverviewViewModel } from '@core/racing/application/presenters/IProfileOverviewPresenter';

View File

@@ -3,7 +3,6 @@ import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import Image from 'next/image';
import type { FeedItemDTO } from '@core/social/application/dto/FeedItemDTO';
import { getDriverRepository, getImageService } from '@/lib/di-container';
function timeAgo(timestamp: Date | string): string {
const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;

View File

@@ -5,7 +5,6 @@ import { useRouter } from 'next/navigation';
import Input from '../ui/Input';
import Button from '../ui/Button';
import { League } from '@core/racing/domain/entities/League';
import { getLeagueRepository, getDriverRepository } from '../../lib/di-container';
interface FormErrors {
name?: string;

View File

@@ -22,9 +22,7 @@ import Button from '@/components/ui/Button';
import Heading from '@/components/ui/Heading';
import LeagueReviewSummary from '@/components/leagues/LeagueReviewSummary';
import Input from '@/components/ui/Input';
import {
getListLeagueScoringPresetsQuery,
} from '@/lib/di-container';
import {
validateLeagueWizardStep,
validateAllLeagueWizardSteps,

View File

@@ -4,7 +4,6 @@ import { useState } from 'react';
import Button from '../ui/Button';
import { getMembership, type MembershipStatus } from '@/lib/leagueMembership';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import { getJoinLeagueUseCase, getLeagueMembershipRepository } from '@/lib/di-container';
interface JoinLeagueButtonProps {
leagueId: string;

View File

@@ -3,7 +3,6 @@
import { Calendar, Award, UserPlus, UserMinus, Shield, Flag, AlertTriangle } from 'lucide-react';
import { Race, Penalty } from '@core/racing';
import type { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
import { getDriverRepository, getPenaltyRepository, getRaceRepository } from '@/lib/di-container';
import { useEffect, useState } from 'react';
import type { Driver } from '@core/racing';

View File

@@ -14,7 +14,6 @@ import {
} from 'lucide-react';
import type { LeagueSummaryViewModel } from '@core/racing/application/presenters/IAllLeaguesWithCapacityAndScoringPresenter';
import { getLeagueCoverClasses } from '@/lib/leagueCovers';
import { getImageService } from '@/lib/di-container';
interface LeagueCardProps {
league: LeagueSummaryViewModel;

View File

@@ -5,12 +5,7 @@ import Link from 'next/link';
import Image from 'next/image';
import MembershipStatus from '@/components/leagues/MembershipStatus';
import FeatureLimitationTooltip from '@/components/alpha/FeatureLimitationTooltip';
import {
getDriverRepository,
getDriverStats,
getAllDriverRankings,
getImageService,
} from '@/lib/di-container';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import { EntityMappers } from '@core/racing/application/mappers/EntityMappers';
import DriverSummaryPill from '@/components/profile/DriverSummaryPill';

View File

@@ -4,7 +4,6 @@ import { useState, useEffect, useCallback } from 'react';
import DriverIdentity from '@/components/drivers/DriverIdentity';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import { EntityMappers } from '@core/racing/application/mappers/EntityMappers';
import { getDriverRepository, getDriverStats } from '@/lib/di-container';
import {
getLeagueMembers,
type LeagueMembership,

View File

@@ -5,12 +5,7 @@ import Button from '../ui/Button';
import Input from '../ui/Input';
import { DollarSign, Star, Award, Plus, X, Bell } from 'lucide-react';
import PendingSponsorshipRequests, { type PendingRequestDTO } from '../sponsors/PendingSponsorshipRequests';
import {
getGetPendingSponsorshipRequestsUseCase,
getAcceptSponsorshipRequestUseCase,
getRejectSponsorshipRequestUseCase,
getSeasonRepository,
} from '@/lib/di-container';
import { PendingSponsorshipRequestsPresenter } from '@/lib/presenters/PendingSponsorshipRequestsPresenter';
import { useEffectiveDriverId } from '@/lib/currentDriver';

View File

@@ -2,7 +2,6 @@
import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import { getQuickPenaltyUseCase } from '@/lib/di-container';
import Button from '@/components/ui/Button';
import { AlertTriangle, Clock, Flag, Zap } from 'lucide-react';

View File

@@ -8,8 +8,6 @@ import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import type { LeagueDriverSeasonStatsDTO } from '@core/racing/application/dto/LeagueDriverSeasonStatsDTO';
import type { LeagueMembership, MembershipRole } from '@/lib/leagueMembership';
import { getLeagueRoleDisplay } from '@/lib/leagueRoles';
import { getDriverStats } from '@/lib/di-container';
import { getImageService } from '@/lib/di-container';
import CountryFlag from '@/components/ui/CountryFlag';
// Position background colors

View File

@@ -4,10 +4,6 @@ import React, { useState, useEffect, useRef } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import {
getNotificationRepository,
getMarkNotificationReadUseCase,
} from '@/lib/di-container';
import type { Notification } from '@core/notifications/application';
import {
Bell,
@@ -52,23 +48,24 @@ export default function NotificationCenter() {
const currentDriverId = useEffectiveDriverId();
// Polling for new notifications
useEffect(() => {
const loadNotifications = async () => {
try {
const repo = getNotificationRepository();
const allNotifications = await repo.findByRecipientId(currentDriverId);
setNotifications(allNotifications);
} catch (error) {
console.error('Failed to load notifications:', error);
}
};
// TODO
// useEffect(() => {
// const loadNotifications = async () => {
// try {
// const repo = getNotificationRepository();
// const allNotifications = await repo.findByRecipientId(currentDriverId);
// setNotifications(allNotifications);
// } catch (error) {
// console.error('Failed to load notifications:', error);
// }
// };
loadNotifications();
// loadNotifications();
// Poll every 5 seconds
const interval = setInterval(loadNotifications, 5000);
return () => clearInterval(interval);
}, [currentDriverId]);
// // Poll every 5 seconds
// const interval = setInterval(loadNotifications, 5000);
// return () => clearInterval(interval);
// }, [currentDriverId]);
// Close panel when clicking outside
useEffect(() => {

View File

@@ -2,10 +2,7 @@
import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import {
getNotificationRepository,
getMarkNotificationReadUseCase,
} from '@/lib/di-container';
import type { Notification } from '@core/notifications/application';
import ToastNotification from './ToastNotification';
import ModalNotification from './ModalNotification';
@@ -44,45 +41,46 @@ export default function NotificationProvider({ children }: NotificationProviderP
const currentDriverId = useEffectiveDriverId();
// Poll for new notifications
useEffect(() => {
const loadNotifications = async () => {
try {
const repo = getNotificationRepository();
const allNotifications = await repo.findByRecipientId(currentDriverId);
setNotifications(allNotifications);
// TODO
// useEffect(() => {
// const loadNotifications = async () => {
// try {
// const repo = getNotificationRepository();
// const allNotifications = await repo.findByRecipientId(currentDriverId);
// setNotifications(allNotifications);
// Check for new notifications that need toast/modal display
allNotifications.forEach((notification) => {
// Check both unread and action_required status for modals
const shouldDisplay = (notification.isUnread() || notification.isActionRequired()) &&
!seenNotificationIds.has(notification.id);
// // Check for new notifications that need toast/modal display
// allNotifications.forEach((notification) => {
// // Check both unread and action_required status for modals
// const shouldDisplay = (notification.isUnread() || notification.isActionRequired()) &&
// !seenNotificationIds.has(notification.id);
if (shouldDisplay) {
// Mark as seen to prevent duplicate displays
setSeenNotificationIds((prev) => new Set([...prev, notification.id]));
// if (shouldDisplay) {
// // Mark as seen to prevent duplicate displays
// setSeenNotificationIds((prev) => new Set([...prev, notification.id]));
// Handle based on urgency
if (notification.isModal()) {
// Modal takes priority - show immediately
setModalNotification(notification);
} else if (notification.isToast()) {
// Add to toast queue
setToastNotifications((prev) => [...prev, notification]);
}
// Silent notifications just appear in the notification center
}
});
} catch (error) {
console.error('Failed to load notifications:', error);
}
};
// // Handle based on urgency
// if (notification.isModal()) {
// // Modal takes priority - show immediately
// setModalNotification(notification);
// } else if (notification.isToast()) {
// // Add to toast queue
// setToastNotifications((prev) => [...prev, notification]);
// }
// // Silent notifications just appear in the notification center
// }
// });
// } catch (error) {
// console.error('Failed to load notifications:', error);
// }
// };
loadNotifications();
// loadNotifications();
// Poll every 2 seconds for responsiveness
const interval = setInterval(loadNotifications, 2000);
return () => clearInterval(interval);
}, [currentDriverId, seenNotificationIds]);
// // Poll every 2 seconds for responsiveness
// const interval = setInterval(loadNotifications, 2000);
// return () => clearInterval(interval);
// }, [currentDriverId, seenNotificationIds]);
// Prevent body scroll when modal is open
useEffect(() => {

View File

@@ -4,7 +4,6 @@ import Image from 'next/image';
import Link from 'next/link';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import DriverRating from '@/components/profile/DriverRatingPill';
import { getImageService } from '@/lib/di-container';
export interface DriverSummaryPillProps {
driver: DriverDTO;

View File

@@ -3,7 +3,6 @@
import Image from 'next/image';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import Button from '../ui/Button';
import { getImageService } from '@/lib/di-container';
import DriverRatingPill from '@/components/profile/DriverRatingPill';
import CountryFlag from '@/components/ui/CountryFlag';

View File

@@ -4,13 +4,7 @@ import Link from 'next/link';
import { useEffect, useMemo, useState } from 'react';
import { LogOut, Settings, Star, Paintbrush, Building2, BarChart3, Megaphone, CreditCard, Handshake } from 'lucide-react';
import { useAuth } from '@/lib/auth/AuthContext';
import {
getDriverStats,
getLeagueRankings,
getAllDriverRankings,
getDriverRepository,
getImageService,
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
import type { DriverDTO } from '@core/racing/application/dto/DriverDTO';
import { EntityMappers } from '@core/racing/application/mappers/EntityMappers';

View File

@@ -3,7 +3,6 @@
import { useState } from 'react';
import Modal from '@/components/ui/Modal';
import Button from '@/components/ui/Button';
import { getFileProtestUseCase } from '@/lib/di-container';
import type { ProtestIncident } from '@core/racing/domain/entities/Protest';
import {
AlertTriangle,

View File

@@ -21,7 +21,6 @@ import {
Check,
Loader2,
} from 'lucide-react';
import { getApplyForSponsorshipUseCase, getSponsorRepository } from '@/lib/di-container';
// ============================================================================
// TYPES

View File

@@ -4,7 +4,6 @@ import { useState } from 'react';
import { useRouter } from 'next/navigation';
import Button from '@/components/ui/Button';
import Input from '@/components/ui/Input';
import { getCreateTeamUseCase } from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
interface CreateTeamFormProps {

View File

@@ -2,11 +2,6 @@
import { useState, useEffect } from 'react';
import Button from '@/components/ui/Button';
import {
getJoinTeamUseCase,
getLeaveTeamUseCase,
getTeamMembershipRepository,
} from '@/lib/di-container';
import { useEffectiveDriverId } from '@/lib/currentDriver';
type TeamMembershipStatus = 'active' | 'pending' | 'inactive';

View File

@@ -16,7 +16,6 @@ import {
Globe,
Languages,
} from 'lucide-react';
import { getImageService } from '@/lib/di-container';
interface TeamCardProps {
id: string;

View File

@@ -2,7 +2,6 @@
import { useRouter } from 'next/navigation';
import Image from 'next/image';
import { getImageService } from '@/lib/di-container';
export interface TeamLadderRowProps {
rank: number;

View File

@@ -24,7 +24,7 @@
"docker:prod:down": "docker-compose -f docker-compose.prod.yml down",
"docker:prod:logs": "docker-compose -f docker-compose.prod.yml logs -f",
"docker:prod:clean": "docker-compose -f docker-compose.prod.yml down -v",
"api:build": "npm run build --workspace=@core/api",
"api:build": "npm run build --workspace=@gridpilot/api",
"test": "vitest run \"$@\"",
"test:unit": "vitest run tests/unit",
"test:integration": "vitest run tests/integration",
@@ -39,16 +39,16 @@
"test:companion-hosted": "vitest run --config vitest.e2e.config.ts tests/e2e/companion/companion-ui-full-workflow.e2e.test.ts",
"typecheck": "tsc --noEmit",
"test:types": "tsc --noEmit -p tsconfig.tests.json",
"companion:dev": "npm run dev --workspace=@core/companion",
"companion:build": "npm run build --workspace=@core/companion",
"companion:start": "npm run start --workspace=@core/companion",
"companion:dev": "npm run dev --workspace=@gridpilot/companion",
"companion:build": "npm run build --workspace=@gridpilot/companion",
"companion:start": "npm run start --workspace=@gridpilot/companion",
"env:website:merge": "node scripts/merge-website-env.js",
"website:dev": "npm run env:website:merge && npm run dev --workspace=@core/website",
"website:build": "npm run env:website:merge && npm run build --workspace=@core/website",
"website:start": "npm run start --workspace=@core/website",
"website:lint": "npm run lint --workspace=@core/website",
"website:type-check": "npm run type-check --workspace=@core/website",
"website:clean": "npm run clean --workspace=@core/website",
"website:dev": "npm run env:website:merge && npm run dev --workspace=@gridpilot/website",
"website:build": "npm run env:website:merge && npm run build --workspace=@gridpilot/website",
"website:start": "npm run start --workspace=@gridpilot/website",
"website:lint": "npm run lint --workspace=@gridpilot/website",
"website:type-check": "npm run type-check --workspace=@gridpilot/website",
"website:clean": "npm run clean --workspace=@gridpilot/website",
"deploy:website:preview": "npx vercel deploy --cwd apps/website",
"deploy:website:prod": "npx vercel deploy --prod",
"deploy:website": "npm run deploy:website:prod",