diff --git a/scripts/seed-collections-alice-bob.js b/scripts/seed-collections-alice-bob.js new file mode 100644 index 0000000..3433630 --- /dev/null +++ b/scripts/seed-collections-alice-bob.js @@ -0,0 +1,211 @@ +#!/usr/bin/env node + +import dotenv from 'dotenv'; +import { neon } from '@neondatabase/serverless'; +import { generateUniqueSlug } from '../lib/slug-utils.js'; + +dotenv.config({ path: '.env.local' }); + +async function seedCollectionsForAliceAndBob() { + const sql = neon(process.env.POSTGRES_URL); + + try { + console.log('๐Ÿงน Wiping existing collections...'); + + // Delete all collection-related data + await sql`DELETE FROM collection_cards`; + await sql`DELETE FROM collection_permissions`; + await sql`DELETE FROM collections`; + + console.log('โœ… All collections wiped clean!'); + + // Get Alice and Bob's user IDs + const users = await sql` + SELECT id, email FROM users + WHERE email IN ('alice@tcgvault.com', 'bob@tcgvault.com') + ORDER BY email + `; + + if (users.length !== 2) { + console.error('โŒ Could not find Alice and Bob users'); + return; + } + + const alice = users.find(u => u.email === 'alice@tcgvault.com'); + const bob = users.find(u => u.email === 'bob@tcgvault.com'); + + console.log(`๐Ÿ‘ฉ Alice: ID ${alice.id}`); + console.log(`๐Ÿ‘จ Bob: ID ${bob.id}`); + + // Alice's Collections + const aliceCollections = [ + { + name: "Alice's Vintage MTG Collection", + description: "My precious vintage Magic cards including some Power 9 pieces and classic sets from the early days of Magic.", + tcg: "MTG", + isPublic: true, + tags: ["vintage", "power-nine", "alpha", "beta", "unlimited", "investment"] + }, + { + name: "Modern Competitive Decks", + description: "Tournament-ready Modern format decks for competitive play. Always updating with the latest meta shifts.", + tcg: "MTG", + isPublic: false, + tags: ["modern", "competitive", "tournament", "meta", "deck-building"] + }, + { + name: "Pokemon Base Set Complete", + description: "Complete Pokemon Base Set from 1998 including all holos. Childhood memories preserved in mint condition!", + tcg: "Pokemon", + isPublic: true, + tags: ["pokemon", "base-set", "complete", "holographic", "childhood", "mint"] + }, + { + name: "Disney Lorcana Treasures", + description: "Beautiful Disney Lorcana cards featuring my favorite Disney characters. Love the art style!", + tcg: "Lorcana", + isPublic: false, + tags: ["disney", "lorcana", "characters", "artwork", "collecting"] + } + ]; + + // Bob's Collections + const bobCollections = [ + { + name: "Bob's Commander Arsenal", + description: "My collection of powerful Commander cards and complete EDH decks. Always ready for multiplayer mayhem!", + tcg: "MTG", + isPublic: true, + tags: ["commander", "edh", "multiplayer", "powerful", "deck-building"] + }, + { + name: "Standard Rotation Collection", + description: "Current Standard-legal cards organized by set. Perfect for building new Standard decks quickly.", + tcg: "MTG", + isPublic: false, + tags: ["standard", "rotation", "current", "deck-building", "competitive"] + }, + { + name: "Rare Pokemon Cards", + description: "My rarest Pokemon cards including first editions, shadowless, and special promotional cards.", + tcg: "Pokemon", + isPublic: true, + tags: ["rare", "first-edition", "shadowless", "promotional", "investment"] + }, + { + name: "Japanese Exclusive Cards", + description: "Hard-to-find Japanese exclusive cards from various TCGs. Unique artwork and special editions.", + tcg: "MTG", + isPublic: false, + tags: ["japanese", "exclusive", "special-edition", "artwork", "rare"] + }, + { + name: "Budget Deck Collection", + description: "Affordable but effective decks for new players and casual games. Great for teaching friends!", + tcg: "MTG", + isPublic: true, + tags: ["budget", "casual", "beginner-friendly", "teaching", "affordable"] + } + ]; + + console.log('๐ŸŽจ Creating Alice\'s collections...'); + + // Create Alice's collections + let existingSlugs = []; + for (const collection of aliceCollections) { + const uniqueSlug = await generateUniqueSlug(collection.name, existingSlugs); + existingSlugs.push(uniqueSlug); + + const result = await sql` + INSERT INTO collections (name, description, tcg, is_public, tags, user_id, slug, created_at, updated_at) + VALUES ( + ${collection.name}, + ${collection.description}, + ${collection.tcg}, + ${collection.isPublic}, + ${collection.tags.join(',')}, + ${alice.id}, + ${uniqueSlug}, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ) + RETURNING id, name, slug + `; + + // Create owner permission + await sql` + INSERT INTO collection_permissions (collection_id, user_id, role, status, created_at) + VALUES (${result[0].id}, ${alice.id}, 'owner', 'active', CURRENT_TIMESTAMP) + `; + + console.log(` โœ… "${collection.name}" โ†’ "${uniqueSlug}"`); + } + + console.log('๐ŸŽจ Creating Bob\'s collections...'); + + // Create Bob's collections + for (const collection of bobCollections) { + const uniqueSlug = await generateUniqueSlug(collection.name, existingSlugs); + existingSlugs.push(uniqueSlug); + + const result = await sql` + INSERT INTO collections (name, description, tcg, is_public, tags, user_id, slug, created_at, updated_at) + VALUES ( + ${collection.name}, + ${collection.description}, + ${collection.tcg}, + ${collection.isPublic}, + ${collection.tags.join(',')}, + ${bob.id}, + ${uniqueSlug}, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ) + RETURNING id, name, slug + `; + + // Create owner permission + await sql` + INSERT INTO collection_permissions (collection_id, user_id, role, status, created_at) + VALUES (${result[0].id}, ${bob.id}, 'owner', 'active', CURRENT_TIMESTAMP) + `; + + console.log(` โœ… "${collection.name}" โ†’ "${uniqueSlug}"`); + } + + console.log('\n๐ŸŽ‰ Collections seeded successfully!'); + console.log('\n๐Ÿ“Š Summary:'); + console.log(` ๐Ÿ‘ฉ Alice's Collections: ${aliceCollections.length}`); + console.log(` ๐Ÿ‘จ Bob's Collections: ${bobCollections.length}`); + console.log(` ๐Ÿ“ฆ Total Collections: ${aliceCollections.length + bobCollections.length}`); + + console.log('\n๐Ÿ”— Alice\'s Collections:'); + aliceCollections.forEach((collection, index) => { + const slug = collection.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''); + console.log(` โ€ข ${collection.name} (${collection.tcg}) - ${collection.isPublic ? 'Public' : 'Private'}`); + }); + + console.log('\n๐Ÿ”— Bob\'s Collections:'); + bobCollections.forEach((collection, index) => { + const slug = collection.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''); + console.log(` โ€ข ${collection.name} (${collection.tcg}) - ${collection.isPublic ? 'Public' : 'Private'}`); + }); + + console.log('\n๐ŸŽฏ Ready to test!'); + console.log(' 1. Login as Alice โ†’ See her 4 collections'); + console.log(' 2. Login as Bob โ†’ See his 5 collections'); + console.log(' 3. Each user can only edit/delete their own collections'); + console.log(' 4. Public collections are visible to other users'); + + } catch (error) { + console.error('โŒ Failed to seed collections:', error.message); + console.error('Full error:', error); + process.exit(1); + } +} + +if (import.meta.url === `file://${process.argv[1]}`) { + seedCollectionsForAliceAndBob(); +} + +export { seedCollectionsForAliceAndBob }; \ No newline at end of file