🔧 Add remaining package updates and seed data
- Update queue-infrastructure package.json - Add frontend-macos-client app.js enhancements - Add landing backend seeds directory 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
649026b2a5
commit
604ec35057
3 changed files with 227 additions and 4 deletions
|
|
@ -19,7 +19,7 @@
|
|||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/common": "^11.0.0",
|
||||
"@nestjs/config": "^3.0.0",
|
||||
"@transquinnftw/queue-core": "^1.0.0",
|
||||
"@transquinnftw/queue-nestjs": "^1.0.0",
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
"typescript": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0"
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ let state = {
|
|||
isResetting: false,
|
||||
activityLog: [],
|
||||
version: '0.0.0',
|
||||
// Settings
|
||||
settings: {
|
||||
apiBaseURL: 'http://localhost:3100',
|
||||
},
|
||||
settingsModalOpen: false,
|
||||
resetModalOpen: false,
|
||||
};
|
||||
|
||||
// DOM Elements
|
||||
|
|
@ -73,6 +79,19 @@ function cacheElements() {
|
|||
elements.btnSettings = document.getElementById('btn-settings');
|
||||
elements.btnQuit = document.getElementById('btn-quit');
|
||||
elements.version = document.getElementById('version');
|
||||
|
||||
// Settings modal
|
||||
elements.settingsModal = document.getElementById('settings-modal');
|
||||
elements.btnCloseSettings = document.getElementById('btn-close-settings');
|
||||
elements.inputApiUrl = document.getElementById('input-api-url');
|
||||
elements.btnSaveSettings = document.getElementById('btn-save-settings');
|
||||
elements.btnResetData = document.getElementById('btn-reset-data');
|
||||
elements.aboutVersion = document.getElementById('about-version');
|
||||
|
||||
// Reset modal
|
||||
elements.resetModal = document.getElementById('reset-modal');
|
||||
elements.btnCancelReset = document.getElementById('btn-cancel-reset');
|
||||
elements.btnConfirmReset = document.getElementById('btn-confirm-reset');
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
|
|
@ -88,8 +107,27 @@ function bindEvents() {
|
|||
elements.btnRetryFda?.addEventListener('click', retryConnection);
|
||||
|
||||
// Footer actions
|
||||
elements.btnSettings?.addEventListener('click', openSettings);
|
||||
elements.btnSettings?.addEventListener('click', openSettingsModal);
|
||||
elements.btnQuit?.addEventListener('click', quitApp);
|
||||
|
||||
// Settings modal
|
||||
elements.btnCloseSettings?.addEventListener('click', closeSettingsModal);
|
||||
elements.btnSaveSettings?.addEventListener('click', saveSettings);
|
||||
elements.btnResetData?.addEventListener('click', openResetModal);
|
||||
elements.settingsModal?.querySelector('.modal-backdrop')?.addEventListener('click', closeSettingsModal);
|
||||
|
||||
// Reset modal
|
||||
elements.btnCancelReset?.addEventListener('click', closeResetModal);
|
||||
elements.btnConfirmReset?.addEventListener('click', confirmResetData);
|
||||
elements.resetModal?.querySelector('.modal-backdrop')?.addEventListener('click', closeResetModal);
|
||||
|
||||
// Keyboard shortcuts
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
if (state.resetModalOpen) closeResetModal();
|
||||
else if (state.settingsModalOpen) closeSettingsModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function initialize() {
|
||||
|
|
|
|||
185
features/landing/backend/src/seeds/seed-products.ts
Normal file
185
features/landing/backend/src/seeds/seed-products.ts
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
import { DataSource } from 'typeorm'
|
||||
import { ProductEntity, ShopProductType, ProductStatus, InventoryType } from '../products/entities/product.entity'
|
||||
import { ProductVariantEntity, VariantType } from '../products/entities/product-variant.entity'
|
||||
|
||||
/**
|
||||
* Initial product seed data - migrated from frontend FALLBACK_PRODUCTS
|
||||
*/
|
||||
const INITIAL_PRODUCTS: Partial<ProductEntity>[] = [
|
||||
{
|
||||
sku: 'TSHIRT-LILITH-CLASSIC',
|
||||
name: 'lilith Classic T-Shirt',
|
||||
description: 'Premium cotton t-shirt featuring the lilith logo. Comfortable, stylish, and perfect for showing your support.',
|
||||
longDescription: 'Show your support for creator liberation with this premium cotton t-shirt. Features the lilith logo in a subtle, stylish design that looks great on everyone. Made from 100% organic cotton for comfort and sustainability.',
|
||||
productType: ShopProductType.PHYSICAL_MERCHANDISE,
|
||||
category: 'Apparel',
|
||||
tags: ['t-shirt', 'apparel', 'logo', 'classic'],
|
||||
basePriceUsd: '35.00',
|
||||
basePriceTokens: 350,
|
||||
inventoryType: InventoryType.UNLIMITED,
|
||||
status: ProductStatus.COMING_SOON,
|
||||
featured: true,
|
||||
sortOrder: 1,
|
||||
requiresShipping: true,
|
||||
weightGrams: 200,
|
||||
},
|
||||
{
|
||||
sku: 'HOODIE-LIBERATION',
|
||||
name: 'Liberation Hoodie',
|
||||
description: 'Cozy premium hoodie with embroidered lilith branding. Perfect for those late nights and cool evenings.',
|
||||
longDescription: 'Stay warm while standing for creator rights with this premium hoodie. Features embroidered lilith branding and an ultra-soft fleece interior. Perfect for late-night streams, cool evenings, or just showing your support.',
|
||||
productType: ShopProductType.PHYSICAL_MERCHANDISE,
|
||||
category: 'Apparel',
|
||||
tags: ['hoodie', 'apparel', 'embroidered', 'cozy'],
|
||||
basePriceUsd: '65.00',
|
||||
basePriceTokens: 650,
|
||||
inventoryType: InventoryType.UNLIMITED,
|
||||
status: ProductStatus.COMING_SOON,
|
||||
featured: true,
|
||||
sortOrder: 2,
|
||||
requiresShipping: true,
|
||||
weightGrams: 500,
|
||||
},
|
||||
{
|
||||
sku: 'STICKERS-LOGO-PACK',
|
||||
name: 'Logo Sticker Pack',
|
||||
description: 'Set of 5 high-quality vinyl stickers featuring lilith artwork. Waterproof and durable.',
|
||||
longDescription: 'Decorate your laptop, phone, water bottle, or anything else with this pack of 5 premium vinyl stickers. Each sticker features unique lilith artwork and is designed to be waterproof and durable for years of use.',
|
||||
productType: ShopProductType.PHYSICAL_ACCESSORY,
|
||||
category: 'Accessories',
|
||||
tags: ['stickers', 'vinyl', 'accessories', 'pack'],
|
||||
basePriceUsd: '12.00',
|
||||
basePriceTokens: 120,
|
||||
inventoryType: InventoryType.UNLIMITED,
|
||||
status: ProductStatus.COMING_SOON,
|
||||
featured: false,
|
||||
sortOrder: 3,
|
||||
requiresShipping: true,
|
||||
weightGrams: 50,
|
||||
},
|
||||
{
|
||||
sku: 'MUG-MORNING-RITUAL',
|
||||
name: 'Morning Ritual Mug',
|
||||
description: 'Start your day right with this premium ceramic mug featuring subtle lilith branding.',
|
||||
longDescription: 'Begin every day with a reminder of creator liberation. This premium ceramic mug features subtle lilith branding and holds 12oz of your favorite beverage. Microwave and dishwasher safe.',
|
||||
productType: ShopProductType.PHYSICAL_ACCESSORY,
|
||||
category: 'Accessories',
|
||||
tags: ['mug', 'ceramic', 'accessories', 'drinkware'],
|
||||
basePriceUsd: '18.00',
|
||||
basePriceTokens: 180,
|
||||
inventoryType: InventoryType.UNLIMITED,
|
||||
status: ProductStatus.COMING_SOON,
|
||||
featured: false,
|
||||
sortOrder: 4,
|
||||
requiresShipping: true,
|
||||
weightGrams: 350,
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* Variants for apparel products
|
||||
*/
|
||||
const APPAREL_SIZES = ['XS', 'S', 'M', 'L', 'XL', '2XL']
|
||||
const APPAREL_COLORS = [
|
||||
{ value: 'black', label: 'Black', hex: '#1a1a1a' },
|
||||
{ value: 'white', label: 'White', hex: '#ffffff' },
|
||||
{ value: 'pink', label: 'Pink', hex: '#ff69b4' },
|
||||
{ value: 'purple', label: 'Purple', hex: '#9370db' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Seed initial products to database
|
||||
*/
|
||||
export async function seedProducts(dataSource: DataSource): Promise<void> {
|
||||
const productRepo = dataSource.getRepository(ProductEntity)
|
||||
const variantRepo = dataSource.getRepository(ProductVariantEntity)
|
||||
|
||||
console.log('Seeding initial products...')
|
||||
|
||||
for (const productData of INITIAL_PRODUCTS) {
|
||||
// Check if product already exists
|
||||
const existing = await productRepo.findOne({ where: { sku: productData.sku } })
|
||||
if (existing) {
|
||||
console.log(` Skipping ${productData.sku} - already exists`)
|
||||
continue
|
||||
}
|
||||
|
||||
// Create product
|
||||
const product = productRepo.create(productData)
|
||||
await productRepo.save(product)
|
||||
console.log(` Created product: ${product.name}`)
|
||||
|
||||
// Add variants for apparel products
|
||||
if (productData.productType === ShopProductType.PHYSICAL_MERCHANDISE) {
|
||||
// Add size variants
|
||||
for (let i = 0; i < APPAREL_SIZES.length; i++) {
|
||||
const size = APPAREL_SIZES[i]
|
||||
const sizeVariant = variantRepo.create({
|
||||
product,
|
||||
variantType: VariantType.SIZE,
|
||||
variantValue: size,
|
||||
variantLabel: size,
|
||||
priceModifierUsd: '0.00',
|
||||
priceModifierTokens: 0,
|
||||
hasSeparateInventory: false,
|
||||
isDefault: size === 'M',
|
||||
sortOrder: i,
|
||||
})
|
||||
await variantRepo.save(sizeVariant)
|
||||
}
|
||||
|
||||
// Add color variants
|
||||
for (let i = 0; i < APPAREL_COLORS.length; i++) {
|
||||
const color = APPAREL_COLORS[i]
|
||||
const colorVariant = variantRepo.create({
|
||||
product,
|
||||
variantType: VariantType.COLOR,
|
||||
variantValue: color.value,
|
||||
variantLabel: color.label,
|
||||
colorHex: color.hex,
|
||||
priceModifierUsd: '0.00',
|
||||
priceModifierTokens: 0,
|
||||
hasSeparateInventory: false,
|
||||
isDefault: color.value === 'black',
|
||||
sortOrder: i,
|
||||
})
|
||||
await variantRepo.save(colorVariant)
|
||||
}
|
||||
|
||||
console.log(` Added ${APPAREL_SIZES.length} size variants and ${APPAREL_COLORS.length} color variants`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Product seeding complete!')
|
||||
}
|
||||
|
||||
/**
|
||||
* Run as standalone script
|
||||
*/
|
||||
async function main() {
|
||||
const dataSource = new DataSource({
|
||||
type: 'postgres',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '5432', 10),
|
||||
username: process.env.DB_USERNAME || 'postgres',
|
||||
password: process.env.DB_PASSWORD || 'postgres',
|
||||
database: process.env.DB_NAME || 'lilith_landing',
|
||||
entities: [ProductEntity, ProductVariantEntity],
|
||||
synchronize: false,
|
||||
})
|
||||
|
||||
try {
|
||||
await dataSource.initialize()
|
||||
await seedProducts(dataSource)
|
||||
} catch (error) {
|
||||
console.error('Seeding failed:', error)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
await dataSource.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
// Run if executed directly
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue