diff --git a/apps/backend/src/routes/settings.ts b/apps/backend/src/routes/settings.ts index a661c8b..550d6e0 100644 --- a/apps/backend/src/routes/settings.ts +++ b/apps/backend/src/routes/settings.ts @@ -117,48 +117,166 @@ export const settingsRoute = new Elysia({ prefix: "/settings" }) } }) .post("/seed-pages", async ({ set }) => { + type SectionInput = { type: string; order: number; isActive: boolean; payload: object }; + type PageDef = { slug: string; title: string; sections: SectionInput[] }; + + const ANNOUNCEMENT = (slides: string[]) => ({ + type: "ANNOUNCEMENT_BAR", order: 1, isActive: true, + payload: { slides, backgroundColor: "#1F3D2D", textColor: "#FDFDF9", speed: 3500 } + }); + const NEWSLETTER = (title: string, description: string, order = 2) => ({ + type: "NEWSLETTER", order, isActive: true, + payload: { title, description, buttonText: "Subscribe", placeholderText: "Enter your email address", showPrivacyCheckbox: true, privacyText: "I agree to the privacy policy." } + }); + const EDITORIAL = (title: string, description: string, imagePosition: string, buttonText: string, buttonLink: string, order = 2) => ({ + type: "EDITORIAL_TILE", order, isActive: true, + payload: { title, description, imageUrl: "/images/oil_ozone.png", imagePosition, buttonText, buttonLink, backgroundColor: "#FDFDF9", textColor: "#1F3D2D" } + }); + + const PAGES: PageDef[] = [ + { + slug: "home", title: "Home Page", + sections: [ + { type: "HERO", order: 1, isActive: true, payload: { tagline: "VIBRANT ELEGANCE COLLECTION", title: "Inhale [Serenity]", description: "Crafting premium sensory experiences that transform your space into a sanctuary of peace.", imageUrl: "/images/hero.png", buttonText: "Explore Collection", buttonLink: "/shop" } }, + { type: "CATEGORIES", order: 2, isActive: true, payload: { title: "Our Collections", subtitle: "Discover the perfect scent for every moment" } }, + { type: "PRODUCTS", order: 3, isActive: true, payload: { title: "Featured Picks", subtitle: "Hand-picked fragrances recommended just for you", type: "featured", limit: 3 } }, + { type: "BANNER", order: 4, isActive: true, payload: { imageUrl: "/images/oil_ozone.png", linkUrl: "/category/1", title: "Special Offer", description: "Get 10% off on your first purchase of Oil Ozone collection", buttonText: "Shop Now" } }, + { type: "TEXT", order: 5, isActive: true, payload: { title: "About HomAroma", content: "HomAroma is dedicated to sourcing the finest raw materials to formulate high-quality essential oils, reed diffusers, and room sprays.", textAlign: "center" } }, + ] + }, + { + slug: "shop-layout", title: "Shop Page Layout", + sections: [ + ANNOUNCEMENT(["[FREE SHIPPING] on orders over ฿1,500", "New Premium Collection is out now!"]), + { type: "HERO", order: 2, isActive: true, payload: { tagline: "CURATED BOTANICALS", title: "The [Shop] Collection", description: "Transform your daily space into a luxury escape with our natural aroma range.", imageUrl: "/images/hero.png", buttonText: "Learn More", buttonLink: "/about" } }, + EDITORIAL("Crafted with [Sensory Passion]", "Every formulation at HomAroma is a tribute to pure botanical essences, hand-blended to capture nature's quiet intelligence.", "right", "Read Our Story", "/about", 3), + NEWSLETTER("Begin Your Wellness Journey", "Subscribe to receive 10% off your first purchase and exclusive updates.", 4), + ] + }, + { + slug: "scent-guide-layout", title: "Scent Guide Layout", + sections: [ + ANNOUNCEMENT(["Explore our Scent Guide to find your signature fragrance", "Read wellness articles crafted by experts"]), + { type: "HERO", order: 2, isActive: true, payload: { tagline: "JOURNAL & INSIGHTS", title: "The [Scent] Guide", description: "Welcome to the sensory archive of HomAroma. Explore the art and science of botanical aromatherapy.", imageUrl: "/images/hero.png", buttonText: "Read Story", buttonLink: "/about" } }, + NEWSLETTER("Stay Inspired", "Subscribe to our journal and get regular wellness guides, blending tips, and exclusive offers.", 3), + ] + }, + { + slug: "category-layout", title: "Category Page Layout", + sections: [ + ANNOUNCEMENT(["Explore our specialized collections for your sanctuary", "Free premium shipping on orders over ฿1,500"]), + NEWSLETTER("Join [HomAroma] Circle", "Subscribe to receive announcements of new single-origin botanical releases."), + ] + }, + { + slug: "product-detail-layout", title: "Product Detail Layout", + sections: [ + ANNOUNCEMENT(["Special Offer: Get 10% off your first purchase of single-origin oils", "Hand-formulated with pure botanical extracts"]), + EDITORIAL("The [Botanical] Sourcing", "All our raw materials are sustainably harvested at peak potency from verified organic micro-farms worldwide.", "left", "Sourcing Map", "/about"), + ] + }, + { + slug: "faq-layout", title: "FAQ Page Layout", + sections: [ + ANNOUNCEMENT(["Need instant help? Reach out on LINE @homaroma", "FAQ updated for Summer 2026 delivery guidelines"]), + NEWSLETTER("Stay informed with [HomAroma]", "Sign up to receive shipping updates, care guides, and exclusive collection invites."), + ] + }, + { + slug: "wishlist-layout", title: "Wishlist Page Layout", + sections: [ + ANNOUNCEMENT(["Sign up to HomAroma Circle to get 10% off your wishlist items", "Hand-crafted botanicals shipped directly to you"]), + NEWSLETTER("Don't lose your favorites", "Subscribe to receive price drops, back-in-stock alerts, and exclusive discounts on items in your wishlist."), + ] + }, + { + slug: "search-layout", title: "Search Page Layout", + sections: [ + ANNOUNCEMENT(["Need help finding something? Live Chat with our scent experts on LINE @homaroma"]), + EDITORIAL("Find Your [Signature Scent]", "Aromatherapy is the art of tuning your environment. Discover our curation of room sprays, reed diffusers, and essential oils designed for modern sanctuaries.", "right", "Explore Guide", "/scent-guide"), + ] + }, + { + slug: "coupons-layout", title: "Coupons Page Layout", + sections: [ + ANNOUNCEMENT(["Enjoy limited-time discount codes for your sensory sanctuary"]), + NEWSLETTER("Get Exclusive Secret Codes", "Become a subscriber to get weekly private discount codes and early access to new collections."), + ] + }, + { + slug: "contact-layout", title: "Contact Page Layout", + sections: [ + ANNOUNCEMENT(["Customer support is available Mon-Sat, 9:00 - 18:00 on LINE @homaroma"]), + EDITORIAL("Our [Bangkok Studio]", "Visit our flagship boutique to experience custom blending sessions and smell our full botanical library in person.", "left", "Book Session", "/about"), + ] + }, + { + slug: "order-success-layout", title: "Order Success Page Layout", + sections: [ + ANNOUNCEMENT(["Thank you for shopping with HomAroma! Your package is preparing.", "Your order tracking status will be updated here."]), + EDITORIAL("Crafting Your [Sanctuary]", "Every order is carefully packaged by hand using sustainable, biodegradable materials. We ensure your botanicals arrive fresh and ready to enrich your space.", "right", "Our Sustainability Commitments", "/about"), + ] + }, + { + slug: "track-order-layout", title: "Track Order Page Layout", + sections: [ + ANNOUNCEMENT(["Check shipping status live. For any delivery queries, reach LINE @homaroma"]), + EDITORIAL("Scenting Your [Daily Rituals]", "While waiting for your order, explore how different botanical notes impact focus, sleep, and emotional balance in our Scent Guide.", "left", "Read Scent Guide", "/scent-guide"), + ] + }, + { + slug: "checkout-layout", title: "Checkout Page Layout", + sections: [ + ANNOUNCEMENT(["Secure checkout — all payments are encrypted and protected", "Free shipping on orders over ฿1,500"]), + EDITORIAL("Crafted for Your [Sanctuary]", "Every HomAroma order is hand-packed with care using eco-conscious materials, so your botanicals arrive in perfect condition.", "right", "Our Sustainability Promise", "/about"), + ] + }, + { + slug: "profile-layout", title: "Profile Page Layout", + sections: [ + ANNOUNCEMENT(["Welcome back to HomAroma — manage your orders and wishlist from your profile", "Earn points with every purchase"]), + NEWSLETTER("Exclusive Member Benefits", "Subscribe to receive early access to new collections, member-only discounts, and scent guides curated just for you."), + ] + }, + ]; + try { - const REQUIRED_PAGES = [ - { slug: "home", title: "Home Page" }, - { slug: "shop-layout", title: "Shop Page Layout" }, - { slug: "scent-guide-layout", title: "Scent Guide Layout" }, - { slug: "category-layout", title: "Category Page Layout" }, - { slug: "product-detail-layout", title: "Product Detail Layout" }, - { slug: "faq-layout", title: "FAQ Page Layout" }, - { slug: "wishlist-layout", title: "Wishlist Page Layout" }, - { slug: "search-layout", title: "Search Page Layout" }, - { slug: "coupons-layout", title: "Coupons Page Layout" }, - { slug: "contact-layout", title: "Contact Page Layout" }, - { slug: "order-success-layout", title: "Order Success Page Layout" }, - { slug: "track-order-layout", title: "Track Order Page Layout" }, - { slug: "checkout-layout", title: "Checkout Page Layout" }, - { slug: "profile-layout", title: "Profile Page Layout" }, - ]; + const results: { slug: string; status: "created" | "exists"; sectionsCreated: number }[] = []; - const results: { slug: string; status: "created" | "exists" }[] = []; + for (const pageDef of PAGES) { + let page = await prisma.page.findUnique({ where: { slug: pageDef.slug } }); + let sectionsCreated = 0; - for (const page of REQUIRED_PAGES) { - const existing = await prisma.page.findUnique({ where: { slug: page.slug } }); - if (!existing) { - await prisma.page.create({ - data: { - slug: page.slug, - title: page.title, - isPublished: true, - } + if (!page) { + page = await prisma.page.create({ + data: { slug: pageDef.slug, title: pageDef.title, isPublished: true } }); - results.push({ slug: page.slug, status: "created" }); + // New page — create all sections + for (const section of pageDef.sections) { + await prisma.pageSection.create({ data: { pageId: page.id, ...section } }); + sectionsCreated++; + } + results.push({ slug: pageDef.slug, status: "created", sectionsCreated }); } else { - results.push({ slug: page.slug, status: "exists" }); + // Existing page — only fill sections if completely empty + const existingCount = await prisma.pageSection.count({ where: { pageId: page.id } }); + if (existingCount === 0) { + for (const section of pageDef.sections) { + await prisma.pageSection.create({ data: { pageId: page.id, ...section } }); + sectionsCreated++; + } + } + results.push({ slug: pageDef.slug, status: "exists", sectionsCreated }); } } const created = results.filter(r => r.status === "created").length; const existed = results.filter(r => r.status === "exists").length; + const totalSections = results.reduce((sum, r) => sum + r.sectionsCreated, 0); return { success: true, - message: `Seed complete: ${created} pages created, ${existed} pages already existed.`, + message: `Seed complete: ${created} pages created, ${existed} pages already existed, ${totalSections} sections created.`, results }; } catch (err) { @@ -167,3 +285,4 @@ export const settingsRoute = new Elysia({ prefix: "/settings" }) return { error: "Failed to seed pages" }; } }); +