Extract collection CSV export helper (Brief 1). (#80)
Moves download logic from pages/collection/[identifier].js into lib/collection-cards-csv.js. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6a5c46ab1e
commit
91b481ffa4
2 changed files with 68 additions and 62 deletions
66
lib/collection-cards-csv.js
Normal file
66
lib/collection-cards-csv.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ import { ManaCost, ColorFilterSymbol } from '../../components/ManaSymbols';
|
||||||
import ManaSymbolSettings from '../../components/ManaSymbolSettings';
|
import ManaSymbolSettings from '../../components/ManaSymbolSettings';
|
||||||
import { useAuth } from '../../lib/use-auth';
|
import { useAuth } from '../../lib/use-auth';
|
||||||
import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
|
import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
|
||||||
|
import { downloadCollectionCardsCsv } from '../../lib/collection-cards-csv.js';
|
||||||
|
|
||||||
export default function CollectionView() {
|
export default function CollectionView() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -424,68 +425,7 @@ export default function CollectionView() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDownloadCSV = () => {
|
const handleDownloadCSV = () => {
|
||||||
if (cards.length === 0) {
|
downloadCollectionCardsCsv(cards, collection?.name);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Group cards by game
|
// Group cards by game
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue