import { readFile } from 'node:fs/promises' import path from 'node:path' import { createClient } from '@supabase/supabase-js' // `src/data/products.ts` and `src/data/services.ts` now fetch live rows from Supabase // (see Tasks 2-3 of this plan) instead of exporting static arrays, so this seed script // owns its own copy of the seed data below rather than importing it from application code. // WARNING: re-running this after admin-panel edits will revert those rows to these seed // defaults (unconditional upsert keyed on id). Intended for initial setup / disaster // recovery only, not routine use. interface SeedProduct { id: string name: string category: 'hair-care' | 'extensions' | 'tools' | 'accessories' price: number image: string description: string inStock: boolean } interface SeedService { id: string name: string durationMinutes: number priceFrom: number description: string image: string } const products: SeedProduct[] = [ { id: 'edge-control', name: 'Gel Contour Soyeux', category: 'hair-care', price: 12, image: '/products/edge-control.jpg', description: 'Tenue longue durée avec un éclat naturel, sans effet blanc.', inStock: true }, { id: 'braid-oil', name: 'Huile Nourrissante pour Tresses', category: 'hair-care', price: 16, image: '/products/braid-oil.jpg', description: "Huile légère pour le cuir chevelu qui apaise et ajoute de l'éclat entre les lavages.", inStock: true }, { id: 'leave-in', name: 'Soin Démêlant Sans Rinçage', category: 'hair-care', price: 14, image: '/products/leave-in.jpg', description: 'Après-shampooing sans rinçage riche en glisse pour un démêlage tout en douceur.', inStock: true }, { id: 'kanekalon-black', name: 'Fibre à Tresser Kanekalon — Noir Jais', category: 'extensions', price: 8, image: '/products/kanekalon-black.jpg', description: 'Fibre synthétique haut de gamme pour tresses, texture douce, faible chute.', inStock: true }, { id: 'kanekalon-brown', name: 'Fibre à Tresser Kanekalon — Châtain', category: 'extensions', price: 8, image: '/products/kanekalon-brown.jpg', description: 'Teinte brune chaude qui se fond parfaitement pour un rendu naturel.', inStock: false }, { id: 'locs-extension', name: 'Extensions de Faux Locs', category: 'extensions', price: 22, image: '/products/locs-extension.jpg', description: 'Faux locs pré-bouclées pour une pose naturelle et légère.', inStock: true }, { id: 'rat-tail-comb', name: 'Peigne à Tige en Acier', category: 'tools', price: 6, image: '/products/rat-tail-comb.jpg', description: 'Peigne de précision pour les raies, avec une fine tige métallique.', inStock: true }, { id: 'edge-brush', name: 'Mini Brosse à Contours', category: 'tools', price: 5, image: '/products/edge-brush.jpg', description: 'Brosse double face pour lisser les contours et discipliner les cheveux follets.', inStock: true }, { id: 'gold-cuffs', name: 'Anneaux Dorés pour Cheveux (Lot de 6)', category: 'accessories', price: 10, image: '/products/gold-cuffs.jpg', description: 'Anneaux ajustables pour accessoiriser tresses et locs.', inStock: true }, { id: 'satin-bonnet', name: 'Bonnet de Nuit en Satin', category: 'accessories', price: 9, image: '/products/satin-bonnet.jpg', description: 'Protège tresses et locs pendant la nuit et réduit les frisottis.', inStock: true }, ] const services: SeedService[] = [ { id: 'knotless', name: 'Tresses sans nœuds', durationMinutes: 240, priceFrom: 150, description: 'Tresses sans tension avec une racine naturelle et invisible.', image: '/styles/knotless.jpg' }, { id: 'boho', name: 'Tresses Boho', durationMinutes: 270, priceFrom: 180, description: 'Tresses sans nœuds agrémentées de mèches bouclées pour un look doux et romantique.', image: '/styles/boho.jpg' }, { id: 'locs', name: 'Faux Locs', durationMinutes: 300, priceFrom: 200, description: "Locs légères à l'allure naturelle, installées avec soin.", image: '/styles/locs.jpg' }, { id: 'cornrows', name: 'Nattes Collées', durationMinutes: 120, priceFrom: 90, description: 'Nattes collées classiques et nettes, droites vers l\'arrière ou avec un motif personnalisé.', image: '/styles/cornrows.jpg' }, ] const supabaseUrl = process.env.SUPABASE_URL const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY if (!supabaseUrl || !serviceRoleKey) { console.error('Set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY environment variables before running this script.') process.exit(1) } const supabase = createClient(supabaseUrl, serviceRoleKey) function toStoragePath(image: string): string { return image.replace(/^\//, '') } async function uploadImages(imagePaths: string[]) { for (const imagePath of imagePaths) { const relativePath = toStoragePath(imagePath) const filePath = path.join(process.cwd(), 'public', relativePath) const fileBuffer = await readFile(filePath) const { error } = await supabase.storage.from('salon-images').upload(relativePath, fileBuffer, { upsert: true, contentType: 'image/jpeg', }) if (error) throw error } console.log(`Uploaded ${imagePaths.length} images to the salon-images bucket.`) } async function seed() { const productRows = products.map(({ id, name, category, price, image, description, inStock }) => ({ id, name, category, price, image: toStoragePath(image), description, in_stock: inStock, })) const { error: productsError } = await supabase.from('products').upsert(productRows) if (productsError) throw productsError const serviceRows = services.map(({ id, name, durationMinutes, priceFrom, description, image }) => ({ id, name, duration_minutes: durationMinutes, price_from: priceFrom, description, image: toStoragePath(image), })) const { error: servicesError } = await supabase.from('services').upsert(serviceRows) if (servicesError) throw servicesError const { error: scheduleError } = await supabase.from('schedule_template').upsert({ id: 'default', working_days: [2, 3, 4, 5, 6], start_time: '09:00', end_time: '18:00', slot_minutes: 120, }) if (scheduleError) throw scheduleError await uploadImages([ ...products.map((p) => p.image), ...services.map((s) => s.image), '/about/mira-portrait.jpg', '/testimonials/amara.jpg', '/testimonials/keisha.jpg', '/testimonials/nadia.jpg', ]) console.log(`Seeded ${products.length} products, ${services.length} services, and the default schedule.`) } seed().catch((err) => { console.error(err) process.exit(1) })