/** * Export utilities for match data * Provides CSV and JSON export functionality for match listings */ import type { MatchListItem } from '$lib/types'; import { formatDuration } from './formatters'; /** * Format date to readable string (YYYY-MM-DD HH:MM) * @param dateString - ISO date string * @returns Formatted date string */ function formatDateForExport(dateString: string): string { const date = new Date(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}`; } /** * Convert matches array to CSV format * @param matches - Array of match items to export * @returns CSV string */ function matchesToCSV(matches: MatchListItem[]): string { // CSV Headers const headers = [ 'Match ID', 'Date', 'Map', 'Score Team A', 'Score Team B', 'Duration', 'Demo Parsed', 'Player Count' ]; // CSV rows const rows = matches.map((match) => { return [ match.match_id, formatDateForExport(match.date), match.map, match.score_team_a.toString(), match.score_team_b.toString(), formatDuration(match.duration), match.demo_parsed ? 'Yes' : 'No', match.player_count?.toString() || '-' ]; }); // Combine headers and rows const csvContent = [ headers.join(','), ...rows.map((row) => row .map((cell) => { // Escape cells containing commas or quotes if (cell.includes(',') || cell.includes('"')) { return `"${cell.replace(/"/g, '""')}"`; } return cell; }) .join(',') ) ].join('\n'); return csvContent; } /** * Convert matches array to formatted JSON * @param matches - Array of match items to export * @returns Formatted JSON string */ function matchesToJSON(matches: MatchListItem[]): string { // Create clean export format const exportData = { export_date: new Date().toISOString(), total_matches: matches.length, matches: matches.map((match) => ({ match_id: match.match_id, date: formatDateForExport(match.date), map: match.map, score: `${match.score_team_a} - ${match.score_team_b}`, score_team_a: match.score_team_a, score_team_b: match.score_team_b, duration: formatDuration(match.duration), duration_seconds: match.duration, demo_parsed: match.demo_parsed, player_count: match.player_count })) }; return JSON.stringify(exportData, null, 2); } /** * Trigger browser download for a file * @param content - File content * @param filename - Name of file to download * @param mimeType - MIME type of file */ function triggerDownload(content: string, filename: string, mimeType: string): void { const blob = new Blob([content], { type: mimeType }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } /** * Export matches to CSV file * Generates and downloads a CSV file with match data * @param matches - Array of match items to export * @throws Error if matches array is empty */ export function exportMatchesToCSV(matches: MatchListItem[]): void { if (!matches || matches.length === 0) { throw new Error('No matches to export'); } const csvContent = matchesToCSV(matches); const timestamp = new Date().toISOString().split('T')[0]; const filename = `cs2wtf-matches-${timestamp}.csv`; triggerDownload(csvContent, filename, 'text/csv;charset=utf-8;'); } /** * Export matches to JSON file * Generates and downloads a JSON file with match data * @param matches - Array of match items to export * @throws Error if matches array is empty */ export function exportMatchesToJSON(matches: MatchListItem[]): void { if (!matches || matches.length === 0) { throw new Error('No matches to export'); } const jsonContent = matchesToJSON(matches); const timestamp = new Date().toISOString().split('T')[0]; const filename = `cs2wtf-matches-${timestamp}.json`; triggerDownload(jsonContent, filename, 'application/json;charset=utf-8;'); }