61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import type { Race } from "../api";
|
|
|
|
function escapeCsvCell(value: string | number | null): string {
|
|
const text = value == null ? "" : String(value);
|
|
return /[",\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
|
|
}
|
|
|
|
function escapeIcsText(value: string): string {
|
|
return value.replace(/[\\;,\n]/g, (character) => ({ "\\": "\\\\", ";": "\\;", ",": "\\,", "\n": "\\n" })[character]!);
|
|
}
|
|
|
|
function toIcsDate(date: string): string {
|
|
return date.slice(0, 10).replace(/-/g, "");
|
|
}
|
|
|
|
function addOneDay(date: string): string {
|
|
const next = new Date(`${date.slice(0, 10)}T00:00:00Z`);
|
|
next.setUTCDate(next.getUTCDate() + 1);
|
|
return next.toISOString().slice(0, 10);
|
|
}
|
|
|
|
export function racesToCsv(races: Race[]): string {
|
|
const headers = ["Дата", "Название", "Дистанция (км)", "Статус", "Время", "Место", "Официальная страница"];
|
|
const rows = races.map((race) => [
|
|
race.date,
|
|
race.title,
|
|
race.distanceKm,
|
|
race.status,
|
|
race.finishTime,
|
|
race.finishPlace,
|
|
race.officialUrl,
|
|
]);
|
|
return `\uFEFF${[headers, ...rows].map((row) => row.map(escapeCsvCell).join(",")).join("\r\n")}\r\n`;
|
|
}
|
|
|
|
export function racesToIcs(races: Race[]): string {
|
|
const events = races.map((race) => {
|
|
const start = race.date.slice(0, 10);
|
|
const end = addOneDay(start);
|
|
return [
|
|
"BEGIN:VEVENT",
|
|
`UID:${race.id}@calendar-run`,
|
|
`DTSTART;VALUE=DATE:${toIcsDate(start)}`,
|
|
`DTEND;VALUE=DATE:${toIcsDate(end)}`,
|
|
`SUMMARY:${escapeIcsText(race.title)}`,
|
|
`DESCRIPTION:${escapeIcsText(`${race.distanceKm} км${race.officialUrl ? `\n${race.officialUrl}` : ""}`)}`,
|
|
"END:VEVENT",
|
|
].join("\r\n");
|
|
});
|
|
return ["BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//Calendar Run//Races//RU", ...events, "END:VCALENDAR", ""].join("\r\n");
|
|
}
|
|
|
|
export function downloadTextFile(filename: string, content: string, type: string): void {
|
|
const url = URL.createObjectURL(new Blob([content], { type }));
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.download = filename;
|
|
link.click();
|
|
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
}
|