refactor(collection): extract CSV export lib (Brief 1) #80

Merged
varutasu merged 1 commit from refactor/collection-identifier-split-brief-1 into main 2026-06-03 17:53:01 -04:00
2 changed files with 68 additions and 62 deletions

View file

@ -0,0 +1,66 @@
/**
* Build and trigger a browser download of collection cards as CSV.
*/
export function downloadCollectionCardsCsv(cards, collectionName) {
if (cards.length === 0) {
alert('No cards to download');
return;
}
const headers = [
'Name',
'Set Name',
'Set Code',
'Card Number',
'Rarity',
'Game',
'Mana Cost',
'CMC',
'Type',
'Colors',
'Oracle Text',
'Power',
'Toughness',
'Market Price',
'Quantity',
'Added Date',
];
const csvRows = [
headers.join(','),
...cards.map((card) =>
[
`"${(card.name || '').replace(/"/g, '""')}"`,
`"${(card.set_name || '').replace(/"/g, '""')}"`,
`"${card.set_code || ''}"`,
`"${card.card_number || ''}"`,
`"${card.rarity || ''}"`,
`"${card.game || ''}"`,
`"${card.mana_cost || ''}"`,
`"${card.cmc || ''}"`,
`"${card.card_type || ''}"`,
`"${Array.isArray(card.colors) ? card.colors.join(', ') : card.colors || ''}"`,
`"${(card.oracle_text || '').replace(/"/g, '""')}"`,
`"${card.power || ''}"`,
`"${card.toughness || ''}"`,
`"${card.market_price || ''}"`,
`"${card.quantity || 1}"`,
`"${card.created_at ? new Date(card.created_at).toLocaleDateString() : ''}"`,
].join(',')
),
];
const csvContent = csvRows.join('\n');
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', `${collectionName || 'collection'}_cards.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}

View file

@ -12,6 +12,7 @@ import { ManaCost, ColorFilterSymbol } from '../../components/ManaSymbols';
import ManaSymbolSettings from '../../components/ManaSymbolSettings';
import { useAuth } from '../../lib/use-auth';
import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
import { downloadCollectionCardsCsv } from '../../lib/collection-cards-csv.js';
export default function CollectionView() {
const router = useRouter();
@ -424,68 +425,7 @@ export default function CollectionView() {
};
const handleDownloadCSV = () => {
if (cards.length === 0) {
alert('No cards to download');
return;
}
// Create CSV headers
const headers = [
'Name',
'Set Name',
'Set Code',
'Card Number',
'Rarity',
'Game',
'Mana Cost',
'CMC',
'Type',
'Colors',
'Oracle Text',
'Power',
'Toughness',
'Market Price',
'Quantity',
'Added Date'
];
// Create CSV rows
const csvRows = [
headers.join(','), // Header row
...cards.map(card => [
`"${(card.name || '').replace(/"/g, '""')}"`,
`"${(card.set_name || '').replace(/"/g, '""')}"`,
`"${card.set_code || ''}"`,
`"${card.card_number || ''}"`,
`"${card.rarity || ''}"`,
`"${card.game || ''}"`,
`"${card.mana_cost || ''}"`,
`"${card.cmc || ''}"`,
`"${card.card_type || ''}"`,
`"${Array.isArray(card.colors) ? card.colors.join(', ') : (card.colors || '')}"`,
`"${(card.oracle_text || '').replace(/"/g, '""')}"`,
`"${card.power || ''}"`,
`"${card.toughness || ''}"`,
`"${card.market_price || ''}"`,
`"${card.quantity || 1}"`,
`"${card.created_at ? new Date(card.created_at).toLocaleDateString() : ''}"`
].join(','))
];
// Create and download the CSV file
const csvContent = csvRows.join('\n');
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', `${collection.name || 'collection'}_cards.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
downloadCollectionCardsCsv(cards, collection?.name);
};
// Group cards by game