From a98bc2178f90b22b2470d52a6810a948b5f7e1ea Mon Sep 17 00:00:00 2001 From: Fabrice LAMANT Date: Fri, 6 Feb 2026 21:05:06 +0100 Subject: [PATCH] use path instead of querystring for filters --- scraper/ics-generator.ts | 1 - scraper/scraper.ts | 1 - ui/app/{ => [[...slug]]}/page.tsx | 122 ++++++++++++++++-------------- ui/app/layout.tsx | 7 +- 4 files changed, 69 insertions(+), 62 deletions(-) rename ui/app/{ => [[...slug]]}/page.tsx (84%) diff --git a/scraper/ics-generator.ts b/scraper/ics-generator.ts index c2c051826..d51bf21d4 100644 --- a/scraper/ics-generator.ts +++ b/scraper/ics-generator.ts @@ -106,7 +106,6 @@ export class ICSGenerator { .map((competitorId) => this.getCompetitor(competitorId, lang.code)) .map((competitor) => `\\n${competitor.flag} ${competitor.name}`).join(""); description += `${competitors}`; - } lines.push(summary); diff --git a/scraper/scraper.ts b/scraper/scraper.ts index 3b727d5ba..dcbd510e2 100644 --- a/scraper/scraper.ts +++ b/scraper/scraper.ts @@ -190,7 +190,6 @@ export class Scraper { return; if (!this.nocs.some((n) => n.key === key)) { - console.log(key); this.nocs.push({ key, name: {} }); } const noc = this.nocs.find((n) => n.key === key)!; diff --git a/ui/app/page.tsx b/ui/app/[[...slug]]/page.tsx similarity index 84% rename from ui/app/page.tsx rename to ui/app/[[...slug]]/page.tsx index 181e5e003..4c553a66b 100644 --- a/ui/app/page.tsx +++ b/ui/app/[[...slug]]/page.tsx @@ -1,22 +1,26 @@ +/* eslint-disable @next/next/no-html-link-for-pages */ "use client"; -import { loadSchedule } from "../lib/data"; -import { useEffect, useState } from "react"; -import Flag from "./flag"; -import { COPY, COPY_SUCCESS, FILTER_BY_COUNTRY, FILTER_BY_SPORT, LANGUAGE, MADE_BY_FABRICE, NOT_AFFILIATED, NO_EVENT_FOR_FILTERS } from "../lib/text"; +import { loadSchedule } from "../../lib/data"; +import { use, useEffect, useState } from "react"; +import Flag from "../flag"; +import { COPY, COPY_SUCCESS, FILTER_BY_COUNTRY, FILTER_BY_SPORT, LANGUAGE, MADE_BY_FABRICE, NOT_AFFILIATED, NO_EVENT_FOR_FILTERS } from "../../lib/text"; import useLocalStorage from "@/lib/local-storage"; import { GoogleAnalytics } from "@next/third-parties/google"; import { Google_Sans, SUSE_Mono } from "next/font/google"; +import { permanentRedirect, usePathname } from "next/navigation"; const googleSans = Google_Sans({ variable: "--font-google-sans", subsets: ["latin"], + fallback: ["sans-serif"], }); const suseMono = SUSE_Mono({ variable: "--font-suse-mono", subsets: ["latin"], + fallback: ["sans-serif"], }); export interface MultilingualString { @@ -68,8 +72,17 @@ export interface Calendar { const COLORS = ['azzurro', 'giallo', 'rosa', 'rosso', 'verde', 'viola']; -export default function Home() { +const DEFAULT_NOC = "world"; +const DEFAULT_SPORT = "all-sports"; + +export default function Home({ + params, +}: { + params: Promise<{ slug: string }> +}) { const qs = typeof window !== 'undefined' ? window.location.search ? new URLSearchParams(window.location.search) : new URLSearchParams() : new URLSearchParams(); + const { slug } = use(params); + const pathname = usePathname(); const [data, setData] = useState(null); const [language, setLanguage] = useLocalStorage('lang', (navigator.language || 'en').split('-')[0]); @@ -79,46 +92,45 @@ export default function Home() { return text[`${language}`] || text['en'] || Object.values(text)[0] || ''; }; - const generateLink = ({ noc, sport, lang }: { noc?: string; sport?: string, lang?: string }) => { - const currentParams = new URLSearchParams(qs.toString()); - if (noc !== undefined) { - if (noc === "") { - currentParams.delete('noc'); - } else { - currentParams.set('noc', noc); - } - } + const getParams = () => ({ + noc: slug?.length ? slug[0].toLowerCase() : DEFAULT_NOC, + sport: slug?.length && slug.length >= 2 ? slug[1].toLowerCase() : DEFAULT_SPORT, + }) - if (sport !== undefined) { - if (sport === "") { - currentParams.delete('sport'); - } else { - currentParams.set('sport', sport); - } - } - - if (lang !== undefined) { - if (lang === "") { - currentParams.delete('lang'); - } else { - currentParams.set('lang', lang); - } - } - const paramString = currentParams.toString(); - return paramString ? `./?${paramString}` : '.'; + const generateLink = ({ noc, sport }: { noc?: string; sport?: string }) => { + const { noc: newNOC, sport: newSport } = getParams(); + return `/${noc || newNOC}/${sport || newSport}`.toLowerCase(); } const generateCalendarLink = () => { const host = typeof window !== 'undefined' ? window.location.host : ''; - const noc = (qs.get('noc') || 'calendar').toLowerCase(); - const sport = (qs.get('sport') || 'all-sports').toLowerCase(); + const { noc, sport } = getParams(); - return `http://${host}/api/data/${language}/${sport}/${noc}.ics`; + return `http://${host}/api/data/${language}/${sport}/${noc === DEFAULT_NOC ? "calendar" : noc}.ics`; }; const getColor = (i: number) => COLORS[i % COLORS.length]; useEffect(() => { + let selectedNOC = DEFAULT_NOC; + let selectedSport = DEFAULT_SPORT; + if (qs.get('noc')) { + selectedNOC = qs.get('noc')!.toLowerCase(); + } else if (slug && slug.length >= 1) { + selectedNOC = slug[0].toLowerCase(); + } + + if (qs.get('sport')) { + selectedSport = qs.get('sport')!.toLowerCase(); + } else if (slug && slug.length >= 2) { + selectedSport = slug[1].toLowerCase(); + } + + const expectedUrl = `/${selectedNOC}/${selectedSport}`; + if (pathname !== expectedUrl) { + permanentRedirect(expectedUrl); + } + if (data == null) { loadSchedule() .then(setData) @@ -133,19 +145,20 @@ export default function Home() { return false; } - const sport = qs.get('sport'); - if (sport && event.sport !== sport) { - visible = false; - } + const { noc, sport } = getParams(); - const noc = qs.get('noc'); - if (noc) { - if (!event.nocs.includes(noc)) { + if (noc !== DEFAULT_NOC) { + if (!event.nocs.includes(noc.toUpperCase())) { visible = false; } } - + if (sport !== DEFAULT_SPORT) { + if (event.sport !== sport.toUpperCase()) { + visible = false; + } + } + console.log({ es: event.sport, en: event.nocs, sport, noc, visible }) return visible; } @@ -251,7 +264,6 @@ export default function Home() { const getCompetitor = (competitorId: string) => { - console.log(competitorId); if (competitorId.startsWith("team:")) { const team = data.nocs.find(noc => noc.key === competitorId.replace("team:", "")); return { noc: team!.key, name: translate(team!.name) }; @@ -270,7 +282,7 @@ export default function Home() { const competitor = getCompetitor(competitorId); if (!competitor) return null; const noc = data.nocs.find(noc => noc.key === competitor.noc); - if (event.competitors.length === 2 || qs.get('noc') === competitor.noc) { + if (event.competitors.length === 2 || getParams().noc.toUpperCase() === competitor.noc) { return (
  • {competitor.name} @@ -329,7 +341,7 @@ export default function Home() { const header = (