diff --git a/src/client/src/components/PackCard.tsx b/src/client/src/components/PackCard.tsx
index 1d970dc..b2196ac 100644
--- a/src/client/src/components/PackCard.tsx
+++ b/src/client/src/components/PackCard.tsx
@@ -9,6 +9,8 @@ interface PackCardProps {
}
const ListItem: React.FC<{ card: DraftCard }> = ({ card }) => {
+ const isFoil = (card: DraftCard) => card.finish === 'foil';
+
const getRarityColorClass = (rarity: string) => {
switch (rarity) {
case 'common': return 'bg-black text-white border-slate-600';
@@ -22,15 +24,21 @@ const ListItem: React.FC<{ card: DraftCard }> = ({ card }) => {
return (
-
+
{card.name}
+ {isFoil(card) && (
+
+ FOIL
+
+ )}
{card.image && (
-
-

+
+ {isFoil(card) &&
}
+
)}
@@ -43,6 +51,7 @@ export const PackCard: React.FC
= ({ pack, viewMode }) => {
const rares = pack.cards.filter(c => c.rarity === 'rare');
const uncommons = pack.cards.filter(c => c.rarity === 'uncommon');
const commons = pack.cards.filter(c => c.rarity === 'common');
+ const isFoil = (card: DraftCard) => card.finish === 'foil';
const copyPackToClipboard = () => {
const text = pack.cards.map(c => c.name).join('\n');
@@ -95,7 +104,10 @@ export const PackCard: React.FC = ({ pack, viewMode }) => {
{viewMode === 'grid' && (
{pack.cards.map((card) => (
-
+
+ {isFoil(card) &&
}
+ {isFoil(card) &&
FOIL
}
+
{card.image ? (

) : (
diff --git a/src/client/src/modules/cube/CubeManager.tsx b/src/client/src/modules/cube/CubeManager.tsx
index b1f87f3..a6cde6b 100644
--- a/src/client/src/modules/cube/CubeManager.tsx
+++ b/src/client/src/modules/cube/CubeManager.tsx
@@ -129,7 +129,14 @@ export const CubeManager: React.FC
= ({ packs, setPacks, onGoT
identifiers.forEach(id => {
const card = scryfallService.getCachedCard(id.type === 'id' ? { id: id.value } : { name: id.value });
if (card) {
- for (let i = 0; i < id.quantity; i++) expandedCards.push(card);
+ for (let i = 0; i < id.quantity; i++) {
+ // Clone card to attach unique properties like finish
+ const expandedCard = { ...card };
+ if (id.finish) {
+ expandedCard.finish = id.finish;
+ }
+ expandedCards.push(expandedCard);
+ }
}
});
}
diff --git a/src/client/src/services/CardParserService.ts b/src/client/src/services/CardParserService.ts
index daeec41..4f73a1f 100644
--- a/src/client/src/services/CardParserService.ts
+++ b/src/client/src/services/CardParserService.ts
@@ -2,6 +2,7 @@ export interface CardIdentifier {
type: 'id' | 'name';
value: string;
quantity: number;
+ finish?: 'foil' | 'normal';
}
export class CardParserService {
@@ -11,13 +12,29 @@ export class CardParserService {
const uuidRegex = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
lines.forEach(line => {
- if (line.toLowerCase().startsWith('quantity') || line.toLowerCase().startsWith('count,name')) return;
+ // Skip header
+ if (line.toLowerCase().startsWith('quantity') && line.toLowerCase().includes('name')) return;
const idMatch = line.match(uuidRegex);
const cleanLineForQty = line.replace(/['"]/g, '');
const quantityMatch = cleanLineForQty.match(/^(\d+)[xX\s,;]/);
const quantity = quantityMatch ? parseInt(quantityMatch[1], 10) : 1;
+ // Detect Finish from CSV (Comma Separated)
+ let finish: 'foil' | 'normal' | undefined = undefined;
+ const parts = line.split(',');
+ if (parts.length >= 3) {
+ // Assuming format: Quantity,Name,Finish,...
+ // If the line started with a number, parts[0] is quantity. parts[1] is name. parts[2] is Finish.
+ // We should be careful about commas in names, but the user example shows a clean structure.
+ // If the name is quoted, split(',') might be naive, but valid for the provided example.
+ // Let's assume the user provided format: Quantity,Name,Finish,Edition Name,Scryfall ID
+
+ const possibleFinish = parts[2].trim().toLowerCase();
+ if (possibleFinish === 'foil' || possibleFinish === 'etched') finish = 'foil';
+ else if (possibleFinish === 'normal') finish = 'normal';
+ }
+
let identifier: { type: 'id' | 'name', value: string } | null = null;
if (idMatch) {
@@ -28,7 +45,6 @@ export class CardParserService {
let name = cleanLine.replace(/^(\d+)[xX\s,;]+/, '').trim();
// Remove set codes in parentheses/brackets e.g. (M20), [STA]
- // This regex looks for ( starts, anything inside, ) ends, or same for []
name = name.replace(/\s*[\(\[].*?[\)\]]/g, '');
// Remove trailing collector numbers (digits at the very end)
@@ -44,16 +60,11 @@ export class CardParserService {
}
if (identifier) {
- // Return one entry per quantity? Or aggregated?
- // The original code pushed multiple entries to an array.
- // For a parser service, returning the count is better, but to match logic:
- // "for (let i = 0; i < quantity; i++) rawCardList.push(identifier);"
- // I will return one object with Quantity property to be efficient.
-
rawCardList.push({
type: identifier.type,
value: identifier.value,
- quantity: quantity
+ quantity: quantity,
+ finish: finish
});
}
});
diff --git a/src/client/src/services/PackGeneratorService.ts b/src/client/src/services/PackGeneratorService.ts
index 8177991..d2a57cd 100644
--- a/src/client/src/services/PackGeneratorService.ts
+++ b/src/client/src/services/PackGeneratorService.ts
@@ -10,6 +10,7 @@ export interface DraftCard {
set: string;
setCode: string;
setType: string;
+ finish?: 'foil' | 'normal';
}
export interface Pack {
@@ -71,7 +72,8 @@ export class PackGeneratorService {
image: cardData.image_uris?.normal || cardData.card_faces?.[0]?.image_uris?.normal || '',
set: cardData.set_name,
setCode: cardData.set,
- setType: setType
+ setType: setType,
+ finish: cardData.finish
};
// Add to pools
diff --git a/src/client/src/services/ScryfallService.ts b/src/client/src/services/ScryfallService.ts
index d680af4..d99fd44 100644
--- a/src/client/src/services/ScryfallService.ts
+++ b/src/client/src/services/ScryfallService.ts
@@ -10,6 +10,7 @@ export interface ScryfallCard {
colors?: string[];
image_uris?: { normal: string };
card_faces?: { image_uris: { normal: string } }[];
+ finish?: 'foil' | 'normal'; // Manual override from import
}
export class ScryfallService {