🔧 Fix System Collections & Database Schema Issues

🐛 Database Schema Fixes:
- Removed non-existent 'updated_at' column from collection_cards operations
- Fixed SQL queries in card ownership API and seeding scripts
- Resolved column does not exist errors

🚫 Hide System Collections from Selection:
- Added 'excludeSystem' parameter to /api/collections endpoint
- Updated CollectionSelectionModal to exclude system collections
- 'All My Cards' no longer appears in card addition modals

 Enhanced System Collection Styling:
- Upgraded system collection badge with gradient styling
- Added 🔒 SYSTEM badge with blue-purple gradient
- Added informative tooltip: 'Automatically syncs with your owned cards'
- Made system collections visually distinct and educational

🎯 User Experience Improvements:
- System collections are now clearly identified as special
- Users understand they can't manually add cards to system collections
- Better visual hierarchy and information architecture
- Automatic sync behavior is now clearly communicated

Card ownership should now work without errors! 🚀
This commit is contained in:
Randall Stillwell 2025-07-27 19:17:55 -05:00
parent 9d7278f8f5
commit 4689424f3a
5 changed files with 24 additions and 13 deletions

View file

@ -23,7 +23,7 @@ export default function CollectionSelectionModal({
const fetchCollections = async () => { const fetchCollections = async () => {
setLoading(true); setLoading(true);
try { try {
const response = await fetch('/api/collections'); const response = await fetch('/api/collections?excludeSystem=true');
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();

View file

@ -73,12 +73,11 @@ export default async function handler(req, res) {
// Sync with "All My Cards" collection // Sync with "All My Cards" collection
const collectionCardResult = await sql` const collectionCardResult = await sql`
INSERT INTO collection_cards (collection_id, card_id, quantity, created_at, updated_at) INSERT INTO collection_cards (collection_id, card_id, quantity, created_at)
VALUES (${collectionId}, ${cardId}, ${cardQuantity}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) VALUES (${collectionId}, ${cardId}, ${cardQuantity}, CURRENT_TIMESTAMP)
ON CONFLICT (collection_id, card_id) ON CONFLICT (collection_id, card_id)
DO UPDATE SET DO UPDATE SET
quantity = ${cardQuantity}, quantity = ${cardQuantity}
updated_at = CURRENT_TIMESTAMP
RETURNING * RETURNING *
`; `;

View file

@ -23,6 +23,7 @@ export default async function handler(req, res) {
} }
const currentUserId = user.userId; const currentUserId = user.userId;
const { excludeSystem } = req.query; // New parameter to exclude system collections
// Get collections based on ownership, collaboration, or shared access (no public discovery) // Get collections based on ownership, collaboration, or shared access (no public discovery)
const result = await sql` const result = await sql`
@ -43,8 +44,8 @@ export default async function handler(req, res) {
LEFT JOIN cards ON cc.card_id = cards.id LEFT JOIN cards ON cc.card_id = cards.id
LEFT JOIN collection_permissions cp ON c.id = cp.collection_id AND cp.user_id = ${currentUserId} AND cp.status = 'active' LEFT JOIN collection_permissions cp ON c.id = cp.collection_id AND cp.user_id = ${currentUserId} AND cp.status = 'active'
WHERE WHERE
c.user_id = ${currentUserId} OR (c.user_id = ${currentUserId} OR cp.id IS NOT NULL)
cp.id IS NOT NULL ${excludeSystem === 'true' ? sql`AND (c.is_system_collection IS NULL OR c.is_system_collection = false)` : sql``}
GROUP BY c.id, u.email, cp.role GROUP BY c.id, u.email, cp.role
ORDER BY c.updated_at DESC ORDER BY c.updated_at DESC
`; `;

View file

@ -497,9 +497,20 @@ export default function Collections() {
</h3> </h3>
{/* System collection indicator */} {/* System collection indicator */}
{collection.isSystemCollection && ( {collection.isSystemCollection && (
<span className="px-2 py-0.5 text-xs font-medium rounded-full bg-blue-50 text-blue-700 border border-blue-200"> <div className="flex items-center space-x-1">
🔒 System <span className="px-2.5 py-1 text-xs font-bold rounded-full bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-sm border-2 border-blue-200">
</span> 🔒 SYSTEM
</span>
<div className="group relative">
<svg className="h-4 w-4 text-blue-500 cursor-help" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-2 text-xs bg-gray-900 text-white rounded-lg shadow-lg opacity-0 group-hover:opacity-100 transition-opacity z-10 whitespace-nowrap">
Automatically syncs with your owned cards
<div className="absolute top-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-t-gray-900"></div>
</div>
</div>
</div>
)} )}
</div> </div>
{/* Edit/Delete buttons - hidden for system collections */} {/* Edit/Delete buttons - hidden for system collections */}

View file

@ -129,14 +129,14 @@ async function fixUserCardsConstraints() {
// Update existing entry // Update existing entry
await sql` await sql`
UPDATE collection_cards UPDATE collection_cards
SET quantity = ${ownedCard.quantity}, updated_at = CURRENT_TIMESTAMP SET quantity = ${ownedCard.quantity}
WHERE collection_id = ${collectionId} AND card_id = ${ownedCard.card_id} WHERE collection_id = ${collectionId} AND card_id = ${ownedCard.card_id}
`; `;
} else { } else {
// Insert new entry // Insert new entry
await sql` await sql`
INSERT INTO collection_cards (collection_id, card_id, quantity, created_at, updated_at) INSERT INTO collection_cards (collection_id, card_id, quantity, created_at)
VALUES (${collectionId}, ${ownedCard.card_id}, ${ownedCard.quantity}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) VALUES (${collectionId}, ${ownedCard.card_id}, ${ownedCard.quantity}, CURRENT_TIMESTAMP)
`; `;
} }
} }