mirror of
https://github.com/fabrice404/olympics-calendar.git
synced 2026-02-25 03:27:08 +00:00
Add medal events filter to UI and ICS generator
Co-authored-by: fabrice404 <12575390+fabrice404@users.noreply.github.com>
This commit is contained in:
@@ -33,18 +33,21 @@ export class ICSGenerator {
|
||||
private generateICSFile(
|
||||
sportKey: string | null,
|
||||
nocKey: string | null,
|
||||
medalOnly: boolean = false,
|
||||
): void {
|
||||
this.debug(
|
||||
"generateICSFile",
|
||||
sportKey || "all-sports",
|
||||
nocKey || "all-nocs",
|
||||
medalOnly ? "medal-only" : "all-events",
|
||||
);
|
||||
|
||||
for (const lang of this.calendar.languages) {
|
||||
const pathSportKey = sportKey ? sportKey : "all-sports";
|
||||
const pathNocKey = nocKey ? nocKey : "calendar";
|
||||
const medalPath = medalOnly ? "medal/" : "";
|
||||
|
||||
const filepath = `./output/${lang.code.toLowerCase()}/${pathSportKey.toLowerCase()}/${pathNocKey.toLowerCase()}.ics`;
|
||||
const filepath = `./output/${lang.code.toLowerCase()}/${pathSportKey.toLowerCase()}/${medalPath}${pathNocKey.toLowerCase()}.ics`;
|
||||
mkdirSync(filepath.split("/").slice(0, -1).join("/"), { recursive: true });
|
||||
|
||||
const titleComponents: string[] = [];
|
||||
@@ -56,6 +59,9 @@ export class ICSGenerator {
|
||||
if (sportKey) {
|
||||
titleComponents.push(this.calendar.sports.find((s) => s.key === sportKey)!.name[lang.code] || "");
|
||||
}
|
||||
if (medalOnly) {
|
||||
titleComponents.push("Medal Events");
|
||||
}
|
||||
titleComponents.push("Milano Cortina 2026");
|
||||
|
||||
const title = titleComponents.join(" - ");
|
||||
@@ -65,7 +71,7 @@ export class ICSGenerator {
|
||||
lines.push("BEGIN:VCALENDAR");
|
||||
lines.push("VERSION:2.0");
|
||||
lines.push(
|
||||
`PRODID:-//fabrice404//olympics-calendar//${lang.code}/${pathSportKey}/${pathNocKey}`,
|
||||
`PRODID:-//fabrice404//olympics-calendar//${lang.code}/${pathSportKey}/${medalPath}${pathNocKey}`,
|
||||
);
|
||||
lines.push(`X-WR-CALNAME:${title}`);
|
||||
lines.push(`NAME:${title}`);
|
||||
@@ -78,6 +84,9 @@ export class ICSGenerator {
|
||||
if (nocKey && !event.nocs.includes(nocKey)) {
|
||||
return false;
|
||||
}
|
||||
if (medalOnly && event.medal === "0") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.forEach((event) => {
|
||||
@@ -144,16 +153,20 @@ export class ICSGenerator {
|
||||
public generate(): void {
|
||||
this.debug("generate");
|
||||
this.generateICSFile(null, null);
|
||||
this.generateICSFile(null, null, true); // Generate medal-only calendar for all sports and all NOCs
|
||||
|
||||
this.calendar.sports.forEach((sport) => {
|
||||
this.generateICSFile(sport.key, null);
|
||||
this.generateICSFile(sport.key, null, true); // Generate medal-only calendar for this sport
|
||||
this.calendar.nocs.forEach((noc) => {
|
||||
this.generateICSFile(sport.key, noc.key);
|
||||
this.generateICSFile(sport.key, noc.key, true); // Generate medal-only calendar for this sport and NOC
|
||||
});
|
||||
});
|
||||
|
||||
this.calendar.nocs.forEach((noc) => {
|
||||
this.generateICSFile(null, noc.key);
|
||||
this.generateICSFile(null, noc.key, true); // Generate medal-only calendar for this NOC
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { loadSchedule } from "../lib/data";
|
||||
import { useEffect, useState } from "react";
|
||||
import Flag from "./flag";
|
||||
import { COPY, COPY_SUCCESS, FILTER_BY_COUNTRY, FILTER_BY_SPORT, MADE_BY_FABRICE, NOT_AFFILIATED, NO_EVENT_FOR_FILTERS } from "../lib/text";
|
||||
import { COPY, COPY_SUCCESS, FILTER_BY_COUNTRY, FILTER_BY_SPORT, MADE_BY_FABRICE, NOT_AFFILIATED, NO_EVENT_FOR_FILTERS, MEDAL_EVENTS_ONLY, ALL_EVENTS } from "../lib/text";
|
||||
import useLocalStorage from "@/lib/local-storage";
|
||||
import { GoogleAnalytics } from "@next/third-parties/google";
|
||||
|
||||
@@ -67,7 +67,7 @@ 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 generateLink = ({ noc, sport, lang, medal }: { noc?: string; sport?: string, lang?: string, medal?: string }) => {
|
||||
const currentParams = new URLSearchParams(qs.toString());
|
||||
if (noc !== undefined) {
|
||||
if (noc === "") {
|
||||
@@ -92,6 +92,14 @@ export default function Home() {
|
||||
currentParams.set('lang', lang);
|
||||
}
|
||||
}
|
||||
|
||||
if (medal !== undefined) {
|
||||
if (medal === "") {
|
||||
currentParams.delete('medal');
|
||||
} else {
|
||||
currentParams.set('medal', medal);
|
||||
}
|
||||
}
|
||||
const paramString = currentParams.toString();
|
||||
return paramString ? `./?${paramString}` : '.';
|
||||
}
|
||||
@@ -100,7 +108,11 @@ export default function Home() {
|
||||
const host = typeof window !== 'undefined' ? window.location.host : '';
|
||||
const noc = (qs.get('noc') || 'calendar').toLowerCase();
|
||||
const sport = (qs.get('sport') || 'all-sports').toLowerCase();
|
||||
const medal = qs.get('medal') === 'true' ? 'medal' : '';
|
||||
|
||||
if (medal) {
|
||||
return `http://${host}/api/data/${language}/${sport}/${medal}/${noc}.ics`;
|
||||
}
|
||||
return `http://${host}/api/data/${language}/${sport}/${noc}.ics`;
|
||||
};
|
||||
|
||||
@@ -133,6 +145,12 @@ export default function Home() {
|
||||
}
|
||||
}
|
||||
|
||||
const medal = qs.get('medal');
|
||||
if (medal === 'true') {
|
||||
if (event.medal === '0') {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return visible;
|
||||
}
|
||||
@@ -382,6 +400,31 @@ export default function Home() {
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li className="px-2">
|
||||
<div className="dropdown">
|
||||
<div tabIndex={0} role="button" className="select bg-transparent">
|
||||
{qs.get('medal') === 'true' ? (
|
||||
<>{translate(MEDAL_EVENTS_ONLY)}</>
|
||||
) : (
|
||||
<>{translate(ALL_EVENTS)}</>
|
||||
)}
|
||||
</div>
|
||||
<ul tabIndex={-1} className="dropdown-content menu bg-base-100 text-black rounded-box z-1 w-52 p-2 shadow-sm">
|
||||
<li>
|
||||
<a href={generateLink({ medal: "" })}>
|
||||
{qs.get('medal') !== 'true' && <div aria-label="success" className="status status-success"></div>}
|
||||
{translate(ALL_EVENTS)}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={generateLink({ medal: "true" })}>
|
||||
{qs.get('medal') === 'true' && <div aria-label="success" className="status status-success"></div>}
|
||||
{translate(MEDAL_EVENTS_ONLY)}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li className="px-2">
|
||||
<div className="dropdown dropdown-end">
|
||||
<div tabIndex={0} role="button" className="btn btn-ghost">
|
||||
|
||||
@@ -23,6 +23,30 @@ export const FILTER_BY_SPORT = {
|
||||
ru: "Фильтр по виду спорта"
|
||||
};
|
||||
|
||||
export const MEDAL_EVENTS_ONLY = {
|
||||
en: "Medal events only",
|
||||
fr: "Événements médaillés uniquement",
|
||||
es: "Solo eventos de medallas",
|
||||
de: "Nur Medaillen-Events",
|
||||
it: "Solo eventi con medaglie",
|
||||
pt: "Apenas eventos de medalhas",
|
||||
zh: "仅奖牌赛事",
|
||||
ja: "メダルイベントのみ",
|
||||
ru: "Только медальные события"
|
||||
};
|
||||
|
||||
export const ALL_EVENTS = {
|
||||
en: "All events",
|
||||
fr: "Tous les événements",
|
||||
es: "Todos los eventos",
|
||||
de: "Alle Veranstaltungen",
|
||||
it: "Tutti gli eventi",
|
||||
pt: "Todos os eventos",
|
||||
zh: "所有赛事",
|
||||
ja: "すべてのイベント",
|
||||
ru: "Все события"
|
||||
};
|
||||
|
||||
export const GET_CALENDAR = {
|
||||
en: "Get Calendar",
|
||||
fr: "Obtenir le calendrier",
|
||||
|
||||
Reference in New Issue
Block a user