website refactor

This commit is contained in:
2026-01-21 13:34:08 +01:00
parent 7075765d98
commit 69c9305d59
3 changed files with 385 additions and 328 deletions

View File

@@ -1,7 +1,7 @@
import 'reflect-metadata'; import 'reflect-metadata';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { LeagueModule } from './LeagueModule'; import { LeagueModule } from './LeagueModule';
import { import {

View File

@@ -79,6 +79,42 @@ describe('RouteConfig', () => {
expect(routeMatchers.isPublic('/admin')).toBe(false); expect(routeMatchers.isPublic('/admin')).toBe(false);
expect(routeMatchers.isPublic('/sponsor/dashboard')).toBe(false); expect(routeMatchers.isPublic('/sponsor/dashboard')).toBe(false);
}); });
it('should return true for league sub-pages (schedule, standings, roster, rulebook)', () => {
// Test with various league IDs
const leagueId = '123';
const anotherLeagueId = 'abc-def-456';
// Schedule page
expect(routeMatchers.isPublic(`/leagues/${leagueId}/schedule`)).toBe(true);
expect(routeMatchers.isPublic(`/leagues/${anotherLeagueId}/schedule`)).toBe(true);
// Standings page
expect(routeMatchers.isPublic(`/leagues/${leagueId}/standings`)).toBe(true);
expect(routeMatchers.isPublic(`/leagues/${anotherLeagueId}/standings`)).toBe(true);
// Roster page
expect(routeMatchers.isPublic(`/leagues/${leagueId}/roster`)).toBe(true);
expect(routeMatchers.isPublic(`/leagues/${anotherLeagueId}/roster`)).toBe(true);
// Rulebook page
expect(routeMatchers.isPublic(`/leagues/${leagueId}/rulebook`)).toBe(true);
expect(routeMatchers.isPublic(`/leagues/${anotherLeagueId}/rulebook`)).toBe(true);
});
it('should return true for league detail page', () => {
expect(routeMatchers.isPublic('/leagues/123')).toBe(true);
expect(routeMatchers.isPublic('/leagues/abc-def')).toBe(true);
});
it('should return false for league admin pages', () => {
expect(routeMatchers.isPublic('/leagues/123/schedule/admin')).toBe(false);
expect(routeMatchers.isPublic('/leagues/123/roster/admin')).toBe(false);
expect(routeMatchers.isPublic('/leagues/123/settings')).toBe(false);
expect(routeMatchers.isPublic('/leagues/123/sponsorships')).toBe(false);
expect(routeMatchers.isPublic('/leagues/123/stewarding')).toBe(false);
expect(routeMatchers.isPublic('/leagues/123/wallet')).toBe(false);
});
}); });
describe('routeMatchers.requiresAuth()', () => { describe('routeMatchers.requiresAuth()', () => {

View File

@@ -61,6 +61,7 @@ export interface RouteGroup {
}; };
league: { league: {
detail: (id: string) => string; detail: (id: string) => string;
roster: (id: string) => string;
rosterAdmin: (id: string) => string; rosterAdmin: (id: string) => string;
rulebook: (id: string) => string; rulebook: (id: string) => string;
schedule: (id: string) => string; schedule: (id: string) => string;
@@ -161,6 +162,7 @@ export const routes: RouteGroup & { leaderboards: { root: string; drivers: strin
}, },
league: { league: {
detail: (id: string) => `/leagues/${id}`, detail: (id: string) => `/leagues/${id}`,
roster: (id: string) => `/leagues/${id}/roster`,
rosterAdmin: (id: string) => `/leagues/${id}/roster/admin`, rosterAdmin: (id: string) => `/leagues/${id}/roster/admin`,
rulebook: (id: string) => `/leagues/${id}/rulebook`, rulebook: (id: string) => `/leagues/${id}/rulebook`,
schedule: (id: string) => `/leagues/${id}/schedule`, schedule: (id: string) => `/leagues/${id}/schedule`,
@@ -212,11 +214,20 @@ export const routeMatchers = {
// Exact match // Exact match
if (pattern === path) return true; if (pattern === path) return true;
// Wildcard match (starts with) // Wildcard match (ends with /*)
if (pattern.endsWith('/*') && path.startsWith(pattern.slice(0, -2))) { if (pattern.endsWith('/*') && path.startsWith(pattern.slice(0, -2))) {
return true; return true;
} }
// Wildcard match (contains /* in the middle)
if (pattern.includes('/*')) {
// Convert wildcard pattern to regex
// e.g., /leagues/*/schedule -> ^/leagues/[^/]+/schedule$
const regexPattern = pattern.replace(/\*/g, '[^/]+');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(path);
}
// Parameterized match (e.g., /leagues/[id]) // Parameterized match (e.g., /leagues/[id])
const paramPattern = pattern.replace(/\[([^\]]+)\]/g, '([^/]+)'); const paramPattern = pattern.replace(/\[([^\]]+)\]/g, '([^/]+)');
const regex = new RegExp(`^${paramPattern}$`); const regex = new RegExp(`^${paramPattern}$`);
@@ -262,6 +273,11 @@ export const routeMatchers = {
routes.auth.resetPassword, routes.auth.resetPassword,
routes.error.notFound, routes.error.notFound,
routes.error.serverError, routes.error.serverError,
// League sub-pages (public)
routes.league.schedule('*'),
routes.league.standings('*'),
routes.league.roster('*'),
routes.league.rulebook('*'),
]; ];
}, },
@@ -302,13 +318,18 @@ export const routeMatchers = {
} }
} }
// Check parameterized patterns // Check parameterized patterns and wildcard patterns
const isPublicParam = publicPatterns.some(pattern => { const isPublicParam = publicPatterns.some(pattern => {
// Check for parameterized patterns (e.g., /leagues/[id])
if (pattern.includes('[')) { if (pattern.includes('[')) {
const paramPattern = pattern.replace(/\[([^\]]+)\]/g, '([^/]+)'); const paramPattern = pattern.replace(/\[([^\]]+)\]/g, '([^/]+)');
const regex = new RegExp(`^${paramPattern}$`); const regex = new RegExp(`^${paramPattern}$`);
return regex.test(path); return regex.test(path);
} }
// Check for wildcard patterns (e.g., /leagues/*)
if (pattern.includes('/*')) {
return this.matches(path, pattern);
}
return false; return false;
}); });