website refactor
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { DashboardPageQuery } from '@/lib/page-queries/DashboardPageQuery';
|
||||
import { DashboardTemplate } from '@/templates/DashboardTemplate';
|
||||
import { logger } from '@/lib/infrastructure/logging/logger';
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const result = await DashboardPageQuery.execute();
|
||||
@@ -15,7 +16,7 @@ export default async function DashboardPage() {
|
||||
redirect('/');
|
||||
} else {
|
||||
// serverError, networkError, unknown, validationError, unauthorized
|
||||
console.error('Dashboard error:', error);
|
||||
logger.error('Dashboard error', undefined, { errorType: error });
|
||||
notFound();
|
||||
}
|
||||
}
|
||||
|
||||
5
apps/website/app/health/route.ts
Normal file
5
apps/website/app/health/route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import React from 'react';
|
||||
import './globals.css';
|
||||
import { AppWrapper } from '@/components/AppWrapper';
|
||||
import { RootAppShellTemplate } from '@/templates/layout/RootAppShellTemplate';
|
||||
import { getWebsiteServerEnv } from '@/lib/config/env';
|
||||
import { logger } from '@/lib/infrastructure/logging/logger';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
@@ -46,7 +48,8 @@ export default async function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
// Initialize debug tools in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const env = getWebsiteServerEnv();
|
||||
if (env.NODE_ENV === 'development') {
|
||||
try {
|
||||
initializeGlobalErrorHandling({
|
||||
showDevOverlay: true,
|
||||
@@ -59,7 +62,7 @@ export default async function RootLayout({
|
||||
logResponses: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('Failed to initialize debug tools:', error);
|
||||
logger.warn('Failed to initialize debug tools', { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { notFound, redirect } from 'next/navigation';
|
||||
import { DriverRankingsPageQuery } from '@/lib/page-queries/DriverRankingsPageQuery';
|
||||
import { DriverRankingsPageClient } from './DriverRankingsPageClient';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { logger } from '@/lib/infrastructure/logging/logger';
|
||||
|
||||
export default async function DriverLeaderboardPage() {
|
||||
const result = await DriverRankingsPageQuery.execute();
|
||||
@@ -16,7 +17,7 @@ export default async function DriverLeaderboardPage() {
|
||||
redirect(routes.public.home);
|
||||
} else {
|
||||
// serverError, networkError, unknown, validationError, unauthorized
|
||||
console.error('Driver rankings error:', error);
|
||||
logger.error('Driver rankings error:', undefined, { error });
|
||||
notFound();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { notFound, redirect } from 'next/navigation';
|
||||
import { LeaderboardsPageQuery } from '@/lib/page-queries/LeaderboardsPageQuery';
|
||||
import { LeaderboardsPageClient } from './LeaderboardsPageClient';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { logger } from '@/lib/infrastructure/logging/logger';
|
||||
|
||||
export default async function LeaderboardsPage() {
|
||||
const result = await LeaderboardsPageQuery.execute();
|
||||
@@ -16,7 +17,7 @@ export default async function LeaderboardsPage() {
|
||||
redirect(routes.public.home);
|
||||
} else {
|
||||
// serverError, networkError, unknown, validationError, unauthorized
|
||||
console.error('Leaderboards error:', error);
|
||||
logger.error('Leaderboards error:', undefined, { error });
|
||||
notFound();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { LeagueCard } from '@/components/leagues/LeagueCard';
|
||||
import { LeagueCard } from '@/components/leagues/LeagueCardWrapper';
|
||||
import { LeagueSummaryViewModel } from '@/lib/view-models/LeagueSummaryViewModel';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import type { LeaguesViewData } from '@/lib/view-data/LeaguesViewData';
|
||||
import { Box } from '@/ui/Box';
|
||||
@@ -26,7 +27,6 @@ import {
|
||||
type LucideIcon,
|
||||
} from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { getMediaUrl } from '@/lib/utilities/media';
|
||||
|
||||
// ============================================================================
|
||||
// TYPES
|
||||
@@ -252,15 +252,7 @@ export function LeaguesPageClient({ viewData }: LeaguesTemplateProps) {
|
||||
{filteredLeagues.map((league) => (
|
||||
<LeagueCard
|
||||
key={league.id}
|
||||
id={league.id}
|
||||
name={league.name}
|
||||
description={league.description || undefined}
|
||||
coverUrl={getMediaUrl('league-cover', league.id)}
|
||||
logoUrl={league.logoUrl || undefined}
|
||||
gameName={league.scoring?.gameName}
|
||||
memberCount={league.usedDriverSlots || 0}
|
||||
maxMembers={league.maxDrivers}
|
||||
championshipType={(league.scoring?.primaryChampionshipType as 'driver' | 'team' | 'nations' | 'trophy') || 'driver'}
|
||||
league={league as unknown as LeagueSummaryViewModel}
|
||||
onClick={() => router.push(routes.league.detail(league.id))}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { LeagueRulebookTemplate } from '@/templates/LeagueRulebookTemplate';
|
||||
import { type RulebookSection } from '@/ui/RulebookTabs';
|
||||
import { type RulebookSection } from '@/components/leagues/RulebookTabs';
|
||||
import type { LeagueRulebookViewData } from '@/lib/view-data/LeagueRulebookViewData';
|
||||
|
||||
interface LeagueRulebookPageClientProps {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { StewardingQueuePanel } from '@/components/leagues/StewardingQueuePanel';
|
||||
import { PenaltyFAB } from '@/ui/PenaltyFAB';
|
||||
import { PenaltyFAB } from '@/components/races/PenaltyFAB';
|
||||
import { QuickPenaltyModal } from '@/components/leagues/QuickPenaltyModal';
|
||||
import { ReviewProtestModal } from '@/components/leagues/ReviewProtestModal';
|
||||
import { StewardingStats } from '@/components/leagues/StewardingStats';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { RacesTemplate, type TimeFilter, type RaceStatusFilter } from '@/templates/RacesTemplate';
|
||||
import type { RacesViewData } from '@/lib/view-data/RacesViewData';
|
||||
|
||||
@@ -9,6 +10,7 @@ interface RacesPageClientProps {
|
||||
}
|
||||
|
||||
export function RacesPageClient({ viewData }: RacesPageClientProps) {
|
||||
const router = useRouter();
|
||||
const [statusFilter, setStatusFilter] = useState<RaceStatusFilter>('all');
|
||||
const [leagueFilter, setLeagueFilter] = useState<string>('all');
|
||||
const [timeFilter, setTimeFilter] = useState<TimeFilter>('upcoming');
|
||||
@@ -56,8 +58,8 @@ export function RacesPageClient({ viewData }: RacesPageClientProps) {
|
||||
setTimeFilter={setTimeFilter}
|
||||
showFilterModal={showFilterModal}
|
||||
setShowFilterModal={setShowFilterModal}
|
||||
onRaceClick={(id) => console.log('Race click', id)}
|
||||
onLeagueClick={(id) => console.log('League click', id)}
|
||||
onRaceClick={(id) => router.push(`/races/${id}`)}
|
||||
onLeagueClick={(id) => router.push(`/leagues/${id}`)}
|
||||
onWithdraw={(id) => console.log('Withdraw', id)}
|
||||
onCancel={(id) => console.log('Cancel', id)}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { headers } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { createRouteGuard } from '@/lib/auth/createRouteGuard';
|
||||
import { Box } from '@/ui/Box';
|
||||
|
||||
interface SponsorLayoutProps {
|
||||
children: React.ReactNode;
|
||||
@@ -23,8 +24,8 @@ export default async function SponsorLayout({ children }: SponsorLayoutProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-deep-graphite">
|
||||
<Box minHeight="screen" bg="bg-deep-graphite">
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { SponsorLeaguesTemplate, type SortOption, type TierFilter, type AvailabilityFilter } from '@/templates/SponsorLeaguesTemplate';
|
||||
|
||||
export default function SponsorLeaguesPageClient({ data }: { data: unknown }) {
|
||||
export function SponsorLeaguesPageClient({ data }: { data: unknown }) {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [tierFilter] = useState<TierFilter>('all');
|
||||
const [availabilityFilter] = useState<AvailabilityFilter>('all');
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { SponsorLeagueDetailTemplate } from '@/templates/SponsorLeagueDetailTemplate';
|
||||
|
||||
export default function SponsorLeagueDetailPageClient({ data }: { data: any }) {
|
||||
export function SponsorLeagueDetailPageClient({ data }: { data: any }) {
|
||||
const [activeTab, setActiveTab] = useState<'overview' | 'drivers' | 'races' | 'sponsor'>('overview');
|
||||
const [selectedTier, setSelectedTier] = useState<'main' | 'secondary'>('main');
|
||||
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { PageWrapper } from '@/components/shared/state/PageWrapper';
|
||||
import SponsorLeagueDetailPageClient from './SponsorLeagueDetailPageClient';
|
||||
import { SponsorLeagueDetailPageClient } from './SponsorLeagueDetailPageClient';
|
||||
import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';
|
||||
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||
import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
|
||||
import { getWebsiteServerEnv } from '@/lib/config/env';
|
||||
|
||||
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
// Manual wiring: create dependencies
|
||||
const baseUrl = getWebsiteApiBaseUrl();
|
||||
const env = getWebsiteServerEnv();
|
||||
const logger = new ConsoleLogger();
|
||||
const errorReporter = new EnhancedErrorReporter(logger, {
|
||||
showUserNotifications: true,
|
||||
logToConsole: true,
|
||||
reportToExternal: process.env.NODE_ENV === 'production',
|
||||
reportToExternal: env.NODE_ENV === 'production',
|
||||
});
|
||||
|
||||
// Create API client
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { PageWrapper } from '@/components/shared/state/PageWrapper';
|
||||
import SponsorLeaguesPageClient from './SponsorLeaguesPageClient';
|
||||
import { SponsorLeaguesPageClient } from './SponsorLeaguesPageClient';
|
||||
import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';
|
||||
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||
import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
|
||||
import { getWebsiteServerEnv } from '@/lib/config/env';
|
||||
|
||||
export default async function Page() {
|
||||
// Manual wiring: create dependencies
|
||||
const baseUrl = getWebsiteApiBaseUrl();
|
||||
const env = getWebsiteServerEnv();
|
||||
const logger = new ConsoleLogger();
|
||||
const errorReporter = new EnhancedErrorReporter(logger, {
|
||||
showUserNotifications: true,
|
||||
logToConsole: true,
|
||||
reportToExternal: process.env.NODE_ENV === 'production',
|
||||
reportToExternal: env.NODE_ENV === 'production',
|
||||
});
|
||||
|
||||
// Create API client
|
||||
|
||||
@@ -5,6 +5,8 @@ import { SponsorSettingsTemplate } from '@/templates/SponsorSettingsTemplate';
|
||||
import { logoutAction } from '@/app/actions/logoutAction';
|
||||
import { ConfirmDialog } from '@/components/shared/ux/ConfirmDialog';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { logger } from '@/lib/infrastructure/logging/logger';
|
||||
|
||||
// ============================================================================
|
||||
// Mock Data
|
||||
@@ -61,7 +63,7 @@ export default function SponsorSettingsPage() {
|
||||
const handleSaveProfile = async () => {
|
||||
setSaving(true);
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
console.log('Profile saved:', profile);
|
||||
logger.info('Profile saved', { profile });
|
||||
setSaving(false);
|
||||
setSaved(true);
|
||||
setTimeout(() => setSaved(false), 3000);
|
||||
@@ -71,11 +73,11 @@ export default function SponsorSettingsPage() {
|
||||
setIsDeleting(true);
|
||||
const result = await logoutAction();
|
||||
if (result.isErr()) {
|
||||
console.error('Logout failed:', result.getError());
|
||||
logger.error('Logout failed', new Error(result.getError()));
|
||||
setIsDeleting(false);
|
||||
return;
|
||||
}
|
||||
router.push('/auth/login');
|
||||
router.push(routes.auth.login);
|
||||
};
|
||||
|
||||
const viewData = {
|
||||
|
||||
Reference in New Issue
Block a user