Compare commits
1 commit
main
...
fix/scanne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5088155016 |
2 changed files with 56 additions and 30 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { sql } from '@vercel/postgres';
|
import { sql } from '@vercel/postgres';
|
||||||
import { getUserFromRequest } from '../../../../lib/permission-middleware';
|
import { getUserFromRequest, logCollectionActivity } from '../../../../lib/permission-middleware';
|
||||||
import { isValidSlug } from '../../../../lib/slug-utils';
|
import { isValidSlug } from '../../../../lib/slug-utils';
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
|
|
@ -107,18 +107,20 @@ export default async function handler(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if card exists
|
// Check if card exists
|
||||||
const cardCheck = await sql`SELECT id FROM cards WHERE id = ${cardId}`;
|
const cardCheck = await sql`SELECT id, name FROM cards WHERE id = ${cardId}`;
|
||||||
if (cardCheck.length === 0) {
|
if (cardCheck.rows.length === 0) {
|
||||||
return res.status(404).json({ error: 'Card not found' });
|
return res.status(404).json({ error: 'Card not found' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cardRecord = cardCheck.rows[0];
|
||||||
|
|
||||||
// Check if card already exists in collection
|
// Check if card already exists in collection
|
||||||
const existingResult = await sql`
|
const existingResult = await sql`
|
||||||
SELECT * FROM collection_cards
|
SELECT * FROM collection_cards
|
||||||
WHERE collection_id = ${collection.id} AND card_id = ${cardId}
|
WHERE collection_id = ${collection.id} AND card_id = ${cardId}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (existingResult.length > 0) {
|
if (existingResult.rows.length > 0) {
|
||||||
// Update quantity if card already exists
|
// Update quantity if card already exists
|
||||||
const result = await sql`
|
const result = await sql`
|
||||||
UPDATE collection_cards
|
UPDATE collection_cards
|
||||||
|
|
@ -127,9 +129,16 @@ export default async function handler(req, res) {
|
||||||
RETURNING *
|
RETURNING *
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
await logCollectionActivity(collection.id, user.userId, 'card_added', {
|
||||||
|
cardId,
|
||||||
|
cardName: cardRecord.name,
|
||||||
|
quantityAdded: quantity,
|
||||||
|
newQuantity: result.rows[0]?.quantity,
|
||||||
|
});
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
message: 'Card quantity updated in collection',
|
message: 'Card quantity updated in collection',
|
||||||
card: result[0]
|
card: result.rows[0]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Add new card to collection
|
// Add new card to collection
|
||||||
|
|
@ -139,9 +148,15 @@ export default async function handler(req, res) {
|
||||||
RETURNING *
|
RETURNING *
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
await logCollectionActivity(collection.id, user.userId, 'card_added', {
|
||||||
|
cardId,
|
||||||
|
cardName: cardRecord.name,
|
||||||
|
quantityAdded: quantity,
|
||||||
|
});
|
||||||
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
message: 'Card added to collection',
|
message: 'Card added to collection',
|
||||||
card: result[0]
|
card: result.rows[0]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import Layout from '../components/Layout';
|
import Layout from '../components/Layout';
|
||||||
import CameraScanner from '../components/CameraScanner';
|
import CameraScanner from '../components/CameraScanner';
|
||||||
|
|
@ -22,6 +22,7 @@ export default function Scanner() {
|
||||||
const [bulkAction, setBulkAction] = useState(''); // 'owned', 'collection', 'deck'
|
const [bulkAction, setBulkAction] = useState(''); // 'owned', 'collection', 'deck'
|
||||||
const [bulkTarget, setBulkTarget] = useState('');
|
const [bulkTarget, setBulkTarget] = useState('');
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
|
const addingInFlightRef = useRef(new Set());
|
||||||
|
|
||||||
// Mana symbol settings
|
// Mana symbol settings
|
||||||
const [manaSymbolSettings, setManaSymbolSettings] = useState({ useSVG: false });
|
const [manaSymbolSettings, setManaSymbolSettings] = useState({ useSVG: false });
|
||||||
|
|
@ -140,11 +141,15 @@ export default function Scanner() {
|
||||||
|
|
||||||
// Individual card actions
|
// Individual card actions
|
||||||
const addSingleCardToOwned = async (card) => {
|
const addSingleCardToOwned = async (card) => {
|
||||||
|
if (addingInFlightRef.current.has(card.id)) return;
|
||||||
|
addingInFlightRef.current.add(card.id);
|
||||||
try {
|
try {
|
||||||
await addToOwnedCards(card);
|
await addToOwnedCards(card);
|
||||||
markCardAsProcessed(card.id, 'owned');
|
markCardAsProcessed(card.id, 'owned');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error adding card to owned:', error);
|
console.error('Error adding card to owned:', error);
|
||||||
|
} finally {
|
||||||
|
addingInFlightRef.current.delete(card.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -167,25 +172,34 @@ export default function Scanner() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bulk actions
|
// Bulk actions
|
||||||
const handleBulkAction = async () => {
|
const handleBulkAction = async (actionOverride, targetOverride) => {
|
||||||
if (!bulkAction || selectedCards.size === 0) return;
|
const action = actionOverride ?? bulkAction;
|
||||||
|
const target = targetOverride ?? bulkTarget;
|
||||||
|
if (!action || selectedCards.size === 0) return;
|
||||||
|
|
||||||
setIsProcessing(true);
|
setIsProcessing(true);
|
||||||
try {
|
try {
|
||||||
const cardsToProcess = scannedCards.filter(card => selectedCards.has(card.id));
|
const cardsToProcess = scannedCards.filter(card => selectedCards.has(card.id));
|
||||||
|
|
||||||
for (const card of cardsToProcess) {
|
for (const card of cardsToProcess) {
|
||||||
if (bulkAction === 'owned') {
|
if (action === 'owned') {
|
||||||
await addToOwnedCards(card);
|
if (addingInFlightRef.current.has(card.id)) continue;
|
||||||
} else if (bulkAction === 'collection' && bulkTarget) {
|
addingInFlightRef.current.add(card.id);
|
||||||
await addToCollection(card, bulkTarget);
|
try {
|
||||||
} else if (bulkAction === 'deck' && bulkTarget) {
|
await addToOwnedCards(card);
|
||||||
await addToDeck(card, bulkTarget);
|
} finally {
|
||||||
|
addingInFlightRef.current.delete(card.id);
|
||||||
|
}
|
||||||
|
} else if (action === 'collection' && target) {
|
||||||
|
await addToCollection(card, target);
|
||||||
|
} else if (action === 'deck' && target) {
|
||||||
|
await addToDeck(card, target);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
markCardAsProcessed(card.id, bulkAction);
|
markCardAsProcessed(card.id, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear selections and reset bulk action state
|
|
||||||
setSelectedCards(new Set());
|
setSelectedCards(new Set());
|
||||||
setBulkAction('');
|
setBulkAction('');
|
||||||
setBulkTarget('');
|
setBulkTarget('');
|
||||||
|
|
@ -655,10 +669,7 @@ export default function Scanner() {
|
||||||
{/* Quick Actions */}
|
{/* Quick Actions */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => handleBulkAction('owned')}
|
||||||
setBulkAction('owned');
|
|
||||||
handleBulkAction();
|
|
||||||
}}
|
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
className="px-4 py-2 rounded-lg font-medium hover:opacity-80 disabled:opacity-50 flex items-center gap-2"
|
className="px-4 py-2 rounded-lg font-medium hover:opacity-80 disabled:opacity-50 flex items-center gap-2"
|
||||||
style={{ backgroundColor: 'var(--accent-gold)', color: 'white' }}
|
style={{ backgroundColor: 'var(--accent-gold)', color: 'white' }}
|
||||||
|
|
@ -669,10 +680,10 @@ export default function Scanner() {
|
||||||
{collections.length > 0 && (
|
{collections.length > 0 && (
|
||||||
<select
|
<select
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (e.target.value) {
|
const collectionId = e.target.value;
|
||||||
setBulkAction('collection');
|
e.target.value = '';
|
||||||
setBulkTarget(e.target.value);
|
if (collectionId) {
|
||||||
setTimeout(() => handleBulkAction(), 100);
|
handleBulkAction('collection', collectionId);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
|
|
@ -691,10 +702,10 @@ export default function Scanner() {
|
||||||
{decks.length > 0 && (
|
{decks.length > 0 && (
|
||||||
<select
|
<select
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (e.target.value) {
|
const deckId = e.target.value;
|
||||||
setBulkAction('deck');
|
e.target.value = '';
|
||||||
setBulkTarget(e.target.value);
|
if (deckId) {
|
||||||
setTimeout(() => handleBulkAction(), 100);
|
handleBulkAction('deck', deckId);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue