/* eslint-disable @next/next/no-html-link-for-pages */ "use client"; import { loadSchedule } from "../../lib/data"; import { use, useEffect, useState } from "react"; import Flag from "../flag"; import { ALL_EVENTS, COPY, COPY_SUCCESS, FILTER_BY_COUNTRY, FILTER_BY_EVENT_TYPE, FILTER_BY_SPORT, GOLD_MEDAL_EVENTS, LANGUAGE, MADE_BY_FABRICE, MEDAL_EVENTS, 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 { [key: string]: string; } export interface Language { code: string; name: string; code3: string; } export interface Sport { key: string; name: MultilingualString; order: number; } export interface NOC { key: string; name: MultilingualString; } export interface Competitor { noc: string; code: string; name: string; } export interface Event { key: string; start: string; end: string; sport: string; medal: "0" | "1" | "3"; name: MultilingualString; location: MultilingualString; nocs: string[]; competitors: string[]; } export interface Calendar { languages: Language[]; sports: Sport[]; nocs: NOC[]; competitors: Competitor[]; events: Event[]; } const COLORS = ['azzurro', 'giallo', 'rosa', 'rosso', 'verde', 'viola']; const EVENT_TYPE_ALL = "all"; const EVENT_TYPE_MEDAL = "medal-events"; const EVENT_TYPE_GOLD_MEDAL = "gold-medal-events"; const EVENT_TYPES = [{ key: EVENT_TYPE_ALL.toUpperCase(), name: ALL_EVENTS }, { key: EVENT_TYPE_MEDAL.toUpperCase(), name: MEDAL_EVENTS, }, { key: EVENT_TYPE_GOLD_MEDAL.toUpperCase(), name: GOLD_MEDAL_EVENTS, }] const DEFAULT_NOC = "world"; const DEFAULT_SPORT = "all-sports"; const DEFAULT_EVENT_TYPE = EVENT_TYPE_ALL; 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]); const [cookieConsent, setCookieConsent] = useLocalStorage('cookie-consent', 'null'); const translate = (text: MultilingualString) => { return text[`${language}`] || text['en'] || Object.values(text)[0] || ''; }; const getParams = () => ({ noc: slug?.length ? slug[0].toLowerCase() : DEFAULT_NOC, sport: slug?.length >= 2 ? slug[1].toLowerCase() : DEFAULT_SPORT, type: slug?.length >= 3 ? slug[2].toLowerCase() : DEFAULT_EVENT_TYPE, }) const generateLink = ({ noc, sport, type }: { noc?: string; sport?: string; type?: string }) => { const { noc: newNOC, sport: newSport, type: newType } = getParams(); if (type && type !== DEFAULT_EVENT_TYPE) { return `/${noc || newNOC}/${sport || newSport}/${type}`.toLowerCase(); } return `/${noc || newNOC}/${sport || newSport}`.toLowerCase(); } const generateCalendarLink = () => { const host = typeof window !== 'undefined' ? window.location.host : ''; const { noc, sport, type } = getParams(); if (type !== DEFAULT_EVENT_TYPE) { return `http://${host}/api/data/${language}/${sport}/${type}.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?.length >= 1) { selectedNOC = getParams().noc.toLowerCase(); } if (qs.get('sport')) { selectedSport = qs.get('sport')!.toLowerCase(); } else if (slug?.length >= 2) { selectedSport = getParams().sport.toLowerCase(); } let expectedUrl = `/${selectedNOC}/${selectedSport}`; if (getParams().type !== DEFAULT_EVENT_TYPE) { expectedUrl = `/${selectedNOC}/${selectedSport}/${getParams().type}`; } if (pathname !== expectedUrl) { permanentRedirect(expectedUrl); } if (data == null) { loadSchedule() .then(setData) .catch(console.log); } }, [data]); const filter = (event: Event) => { let visible = true; if (event.end < new Date().toISOString()) { return false; } const { noc, sport, type } = getParams(); if ( noc !== DEFAULT_NOC && !event.nocs.includes(noc.toUpperCase()) ) { visible = false; } if ( sport !== DEFAULT_SPORT && event.sport !== sport.toUpperCase() ) { visible = false; } if (type !== DEFAULT_EVENT_TYPE) { if ( (type === "medal-events" && event.medal === "0") || (type === "gold-medal-events" && event.medal !== "1") ) { visible = false; } } return visible; } const copyToClipboard = (text: string) => { if (typeof navigator !== 'undefined' && navigator.clipboard) { const button = document.getElementById('copy_button')!; navigator.clipboard.writeText(text).then(() => { button.textContent = translate(COPY_SUCCESS); button.classList.add('text-success'); button.classList.add('font-bold'); setTimeout(() => { button.textContent = translate(COPY); button.classList.remove('text-success'); button.classList.remove('font-bold'); }, 2000); }); } } const calendarLink = generateCalendarLink(); if (data) { let lastDay = ""; if (data.languages.find(lang => lang.code === language) === undefined) { setLanguage('en') } const events = data.events.filter(event => filter(event)); let main = (
{translate(NO_EVENT_FOR_FILTERS)}
) if (events.length) { main = (
Apple Calendar Google Calendar Office 365 Calendar Outlook Calendar Yahoo Calendar
{ events .sort((a, b) => a.start.localeCompare(b.start)) .map((event, i) => { const startDate = new Date(event.start); const endDate = new Date(event.end); const startHours = startDate.getHours().toString().padStart(2, '0'); const startMinutes = startDate.getMinutes().toString().padStart(2, '0'); const endHours = endDate.getHours().toString().padStart(2, '0'); const endMinutes = endDate.getMinutes().toString().padStart(2, '0'); let titleColor = "fg-main"; if (event.medal === '1') { titleColor = "bg-gold"; } else if (event.medal === '3') { titleColor = "bg-bronze"; } const day = event.start.split('T')[0]; let dayHeader = <>; if (lastDay !== day) { dayHeader = (

{new Date(event.start).toLocaleDateString(language, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}

); } // eslint-disable-next-line react-hooks/immutability lastDay = day; const getCompetitor = (competitorId: string) => { if (competitorId.startsWith("team:")) { const team = data.nocs.find(noc => noc.key === competitorId.replace("team:", "")); return { noc: team!.key, name: translate(team!.name) }; } const competitor = data.competitors.find(comp => comp.code === competitorId); return { noc: competitor!.noc, name: competitor!.name }; }; let competitors = <>; if (event.competitors.length > 0) { competitors = ( ); } let nocs = <>; if (event.nocs.length > 0 && event.competitors.length !== 2) { nocs = (
{ event.nocs.filter(Boolean).toSorted((a, b) => a.localeCompare(b)).map((nocKey) => { const noc = data.nocs.find(noc => noc.key === nocKey); if (!noc) return null; return ( ); }) }
); } return (
{dayHeader}
{startHours}:{startMinutes}
{endHours}:{endMinutes}
{translate(data.sports.find(sport => sport.key === event.sport)?.name || {})}
{translate(event.name)}
{competitors} {nocs}
) }) }
) } const header = (
Olympics Calendar
); const footer = ( ); let cookie = <>; if (cookieConsent === 'true') { cookie = ( ); } else if (cookieConsent === 'null') { cookie = (

This website uses cookies for statistics purposes and to enhance the user experience.

); } return (
{header} {main} {footer} {cookie}
{translate(FILTER_BY_COUNTRY)} {getParams().noc !== DEFAULT_NOC && ( )}
    {data.nocs.toSorted((a, b) => translate(a.name).localeCompare(translate(b.name))).map(noc => { if (noc.key === getParams().noc.toUpperCase()) { return (
  • {translate(noc.name)}
  • ) } return (
  • {translate(noc.name)}
  • ) })}
{translate(FILTER_BY_SPORT)} {getParams().sport !== DEFAULT_SPORT && ( )}
{translate(FILTER_BY_EVENT_TYPE)} {getParams().type !== DEFAULT_EVENT_TYPE && ( )}
{translate(LANGUAGE)}
); } return (
Loading
); }