From d9c79aa90060fcc5a81223f06be619f775353b63 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 3 Jun 2026 11:01:01 +0700 Subject: [PATCH] Mass replace irelax with homaroma across project --- PROJECT_DETAILS.md | 22 +++++++++---------- apps/admin/src/components/ProtectedRoute.tsx | 2 +- apps/admin/src/components/Sidebar.tsx | 6 ++--- apps/admin/src/index.css | 2 +- apps/admin/src/pages/DashboardPage.tsx | 2 +- apps/admin/src/pages/GlobalAnalyticsPage.tsx | 2 +- apps/admin/src/pages/LazadaAnalyticsPage.tsx | 2 +- apps/admin/src/pages/LazadaOrderPage.tsx | 4 ++-- apps/admin/src/pages/LazadaOverviewPage.tsx | 4 ++-- apps/admin/src/pages/LoginPage.tsx | 8 +++---- apps/admin/src/pages/ShopeeAnalyticsPage.tsx | 2 +- .../admin/src/pages/ShopeeOrderDetailPage.tsx | 2 +- apps/admin/src/pages/ShopeeOverviewPage.tsx | 2 +- apps/admin/src/pages/ShopeePage.tsx | 4 ++-- apps/admin/src/pages/TiktokAnalysisPage.tsx | 2 +- apps/admin/src/pages/TiktokAnalyticsPage.tsx | 2 +- apps/admin/src/pages/TiktokOrderPage.tsx | 2 +- apps/admin/src/pages/TiktokOverviewPage.tsx | 2 +- apps/admin/src/pages/TiktokPage.tsx | 2 +- apps/backend/package.json | 2 +- apps/backend/prisma/schema.prisma | 2 +- apps/backend/prisma/seed.cjs | 4 ++-- apps/backend/src/routes/auth.ts | 2 +- apps/spa/src/components/CartDrawer.tsx | 4 ++-- apps/spa/src/components/Footer.tsx | 4 ++-- apps/spa/src/components/Navbar.tsx | 6 ++--- apps/spa/src/i18n.ts | 2 +- apps/spa/src/pages/AboutPage.tsx | 6 ++--- apps/spa/src/pages/CheckoutPage.tsx | 12 +++++----- apps/spa/src/pages/ContactPage.tsx | 6 ++--- apps/spa/src/pages/CouponsPage.tsx | 2 +- apps/spa/src/pages/FaqPage.tsx | 6 ++--- apps/spa/src/pages/ShopPage.tsx | 2 +- apps/spa/src/pages/TrackOrderPage.tsx | 4 ++-- apps/spa/src/store/authStore.ts | 2 +- apps/spa/src/store/cartStore.ts | 2 +- apps/website/src/app/about/page.tsx | 10 ++++----- apps/website/src/app/article/[slug]/page.tsx | 4 ++-- apps/website/src/app/contact/layout.tsx | 4 ++-- apps/website/src/app/contact/page.tsx | 6 ++--- apps/website/src/app/coupons/page.tsx | 8 +++---- apps/website/src/app/faq/layout.tsx | 4 ++-- apps/website/src/app/faq/page.tsx | 4 ++-- apps/website/src/app/layout.tsx | 2 +- apps/website/src/app/products/[id]/page.tsx | 6 ++--- apps/website/src/app/scent-guide/page.tsx | 2 +- apps/website/src/app/search/layout.tsx | 2 +- apps/website/src/app/shop/layout.tsx | 2 +- apps/website/src/components/Footer.tsx | 4 ++-- apps/website/src/components/Navbar.tsx | 6 ++--- apps/website/src/lib/api.ts | 2 +- apps/website/src/lib/i18n.ts | 2 +- apps/website/src/store/cartStore.ts | 2 +- cf.js | 2 +- deploy-hook.sh | 2 +- frontend-comparison.md | 14 ++++++------ serverinfo/post-receive | 4 ++-- 57 files changed, 117 insertions(+), 117 deletions(-) diff --git a/PROJECT_DETAILS.md b/PROJECT_DETAILS.md index 28686fd..8031465 100644 --- a/PROJECT_DETAILS.md +++ b/PROJECT_DETAILS.md @@ -1,4 +1,4 @@ -# รายละเอียดโปรเจกต์ iRelax Aroma +# รายละเอียดโปรเจกต์ HomAroma โปรเจกต์นี้เป็นระบบ E-commerce สำหรับผลิตภัณฑ์เครื่องหอมและน้ำมันหอมระเหย (Aroma & Essential Oils) โดยมีการออกแบบสถาปัตยกรรมแบบ Monorepo ที่แบ่งส่วนการทำงานออกเป็น 4 ส่วนหลักในโฟลเดอร์ `apps/` ดังนี้: @@ -78,7 +78,7 @@ graph TD git push server master ``` * **Remote Name:** `server` -* **Remote URL:** `ti@kitizone.com:/home/ti/git/irelax.git` +* **Remote URL:** `ti@kitizone.com:/home/ti/git/homaroma.git` ### ขั้นตอนการทำงานของสคริปต์ Deployment (`post-receive`) เมื่อมีการ Push โค้ด สคริปต์จะทำงานโดยอัตโนมัติดังนี้: @@ -86,21 +86,21 @@ git push server master 1. **Checkout & Build**: ดึงโค้ดล่าสุดมายังโฟลเดอร์ชั่วคราวและรัน `bun install` 2. **Frontend Deployment**: * Build `website` และ `admin` (Vite) - * Deploy ไฟล์ `dist` ไปยัง Nginx paths (`/home/ti/projects/MyNginxMain/nginx/html/irelaxaroma.shop/`) + * Deploy ไฟล์ `dist` ไปยัง Nginx paths (`/home/ti/projects/MyNginxMain/nginx/html/homaroma.shop/`) 3. **Backend Deployment**: - * Sync โค้ดไปยัง `/home/ti/projects/irelax-api` + * Sync โค้ดไปยัง `/home/ti/projects/homaroma-api` * รัน `prisma generate` และ `prisma migrate deploy` เพื่ออัปเดตฐานข้อมูล - * Restart บริการด้วย **PM2** (ชื่อ process: `irelax-backend`) + * Restart บริการด้วย **PM2** (ชื่อ process: `homaroma-backend`) 4. **SSR Deployment**: - * Build Next.js app และ Sync ไปยัง `/home/ti/projects/irelax-ssr` - * Restart บริการด้วย **PM2** (ชื่อ process: `irelax-ssr`) บนพอร์ต `3001` + * Build Next.js app และ Sync ไปยัง `/home/ti/projects/homaroma-ssr` + * Restart บริการด้วย **PM2** (ชื่อ process: `homaroma-ssr`) บนพอร์ต `3001` 5. **Cleanup**: ลบไฟล์ชั่วคราวที่ใช้ในการ Build ออก ### สรุป URL การเข้าใช้งาน (Production) -* **Website (SPA):** [https://irelaxaroma.shop](https://irelaxaroma.shop) -* **Admin Panel:** [https://admin.irelaxaroma.shop](https://admin.irelaxaroma.shop) -* **API Backend:** [https://api.irelaxaroma.shop](https://api.irelaxaroma.shop) -* **SSR Next.js:** [https://ssr.irelaxaroma.shop](https://ssr.irelaxaroma.shop) +* **Website (SPA):** [https://homaroma.shop](https://homaroma.shop) +* **Admin Panel:** [https://admin.homaroma.shop](https://admin.homaroma.shop) +* **API Backend:** [https://api.homaroma.shop](https://api.homaroma.shop) +* **SSR Next.js:** [https://ssr.homaroma.shop](https://ssr.homaroma.shop) --- diff --git a/apps/admin/src/components/ProtectedRoute.tsx b/apps/admin/src/components/ProtectedRoute.tsx index d6e00e6..600b80d 100644 --- a/apps/admin/src/components/ProtectedRoute.tsx +++ b/apps/admin/src/components/ProtectedRoute.tsx @@ -1,7 +1,7 @@ import { Navigate, Outlet } from 'react-router-dom' export default function ProtectedRoute() { - const token = localStorage.getItem('irelax_admin_token') + const token = localStorage.getItem('homaroma_admin_token') if (!token) { // If no token, redirect to login page diff --git a/apps/admin/src/components/Sidebar.tsx b/apps/admin/src/components/Sidebar.tsx index 1193983..fe807d1 100644 --- a/apps/admin/src/components/Sidebar.tsx +++ b/apps/admin/src/components/Sidebar.tsx @@ -48,8 +48,8 @@ export default function Sidebar() { const navigate = useNavigate() const handleLogout = () => { - localStorage.removeItem('irelax_admin_token') - localStorage.removeItem('irelax_admin_user') + localStorage.removeItem('homaroma_admin_token') + localStorage.removeItem('homaroma_admin_user') navigate('/login') } @@ -58,7 +58,7 @@ export default function Sidebar() { {/* Brand */}
- iRelax Admin + HomAroma Admin
diff --git a/apps/admin/src/index.css b/apps/admin/src/index.css index fcd258c..1fcfc94 100644 --- a/apps/admin/src/index.css +++ b/apps/admin/src/index.css @@ -1,7 +1,7 @@ @import "tailwindcss"; @theme { - /* iRelax Admin - Professional Dark Palette */ + /* HomAroma Admin - Professional Dark Palette */ --color-night-950: #050608; --color-night-900: #0B0C10; --color-night-800: #1F2833; diff --git a/apps/admin/src/pages/DashboardPage.tsx b/apps/admin/src/pages/DashboardPage.tsx index 79ef517..4d61b69 100644 --- a/apps/admin/src/pages/DashboardPage.tsx +++ b/apps/admin/src/pages/DashboardPage.tsx @@ -52,7 +52,7 @@ export default function DashboardPage() {

System Overview

-

Real-time stats from the iRelax platform.

+

Real-time stats from the HomAroma platform.

Last updated

diff --git a/apps/admin/src/pages/GlobalAnalyticsPage.tsx b/apps/admin/src/pages/GlobalAnalyticsPage.tsx index 97a1dd4..d506237 100644 --- a/apps/admin/src/pages/GlobalAnalyticsPage.tsx +++ b/apps/admin/src/pages/GlobalAnalyticsPage.tsx @@ -45,7 +45,7 @@ const PRESETS: { key: Preset; label: string }[] = [ ]; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, dec = 0) { return new Intl.NumberFormat('th-TH', { minimumFractionDigits: dec, maximumFractionDigits: dec }).format(val); diff --git a/apps/admin/src/pages/LazadaAnalyticsPage.tsx b/apps/admin/src/pages/LazadaAnalyticsPage.tsx index 4711e3d..572b94f 100644 --- a/apps/admin/src/pages/LazadaAnalyticsPage.tsx +++ b/apps/admin/src/pages/LazadaAnalyticsPage.tsx @@ -16,7 +16,7 @@ const API_URL = (import.meta.env.VITE_API_URL || 'http://localhost:3000').replac const COLORS = ['#3b82f6', '#8b5cf6', '#ec4899', '#eab308', '#f97316', '#22d3ee', '#10b981']; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, decimals = 0) { diff --git a/apps/admin/src/pages/LazadaOrderPage.tsx b/apps/admin/src/pages/LazadaOrderPage.tsx index 5d1f6e1..8897328 100644 --- a/apps/admin/src/pages/LazadaOrderPage.tsx +++ b/apps/admin/src/pages/LazadaOrderPage.tsx @@ -8,7 +8,7 @@ export const LAZADA_SHOPS = [ { id: 'hom-aroma', label: 'Hom Aroma', color: 'text-blue-500', activeBg: 'bg-blue-500/15', activeBorder: 'border-blue-500/40' }, { id: 'shop-01', label: 'Annlina', color: 'text-indigo-400', activeBg: 'bg-indigo-500/15', activeBorder: 'border-indigo-500/40' }, { id: 'pakasai', label: 'Pakasai', color: 'text-pink-400', activeBg: 'bg-pink-500/15', activeBorder: 'border-pink-500/40' }, - { id: 'irelaxshop', label: 'Relax', color: 'text-yellow-400', activeBg: 'bg-yellow-500/15', activeBorder: 'border-yellow-500/40' }, + { id: 'homaromashop', label: 'Relax', color: 'text-yellow-400', activeBg: 'bg-yellow-500/15', activeBorder: 'border-yellow-500/40' }, { id: 'conner', label: 'Conner', color: 'text-white', activeBg: 'bg-white/15', activeBorder: 'border-white/40' }, { id: 'december', label: 'December', color: 'text-white', activeBg: 'bg-white/15', activeBorder: 'border-white/40' }, @@ -18,7 +18,7 @@ export const LAZADA_SHOPS = [ function getShop(id: string) { return LAZADA_SHOPS.find(s => s.id === id) || LAZADA_SHOPS[0]; } function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } // ── Summary Cards ───────────────────────────────────────────────────────────── diff --git a/apps/admin/src/pages/LazadaOverviewPage.tsx b/apps/admin/src/pages/LazadaOverviewPage.tsx index 1b80a9e..39e4289 100644 --- a/apps/admin/src/pages/LazadaOverviewPage.tsx +++ b/apps/admin/src/pages/LazadaOverviewPage.tsx @@ -17,7 +17,7 @@ const SHOP_HEX: Record = { 'hom-aroma': '#3b82f6', // blue-500 'shop-01': '#818cf8', // indigo-400 'pakasai': '#f472b6', // pink-400 - 'irelaxshop':'#facc15', // yellow-400 + 'homaromashop':'#facc15', // yellow-400 'conner': '#94a3b8', // slate-400 'december': '#cbd5e1', // slate-300 }; @@ -59,7 +59,7 @@ const PRESETS: { key: Preset; label: string }[] = [ ]; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, dec = 0) { return new Intl.NumberFormat('th-TH', { minimumFractionDigits: dec, maximumFractionDigits: dec }).format(val); diff --git a/apps/admin/src/pages/LoginPage.tsx b/apps/admin/src/pages/LoginPage.tsx index 8648e56..ad56c88 100644 --- a/apps/admin/src/pages/LoginPage.tsx +++ b/apps/admin/src/pages/LoginPage.tsx @@ -29,8 +29,8 @@ export default function LoginPage() { } // Store token - localStorage.setItem('irelax_admin_token', data.token) - localStorage.setItem('irelax_admin_user', JSON.stringify(data.user)) + localStorage.setItem('homaroma_admin_token', data.token) + localStorage.setItem('homaroma_admin_user', JSON.stringify(data.user)) // Redirect to dashboard navigate('/') @@ -53,7 +53,7 @@ export default function LoginPage() { Authorized Access Only

- iRelax Admin + HomAroma Admin

Welcome back to the sensory command center.

@@ -115,7 +115,7 @@ export default function LoginPage() {

- © 2026 iRelax Aroma & Essential Oils + © 2026 HomAroma & Essential Oils

diff --git a/apps/admin/src/pages/ShopeeAnalyticsPage.tsx b/apps/admin/src/pages/ShopeeAnalyticsPage.tsx index 662fbcc..137e459 100644 --- a/apps/admin/src/pages/ShopeeAnalyticsPage.tsx +++ b/apps/admin/src/pages/ShopeeAnalyticsPage.tsx @@ -16,7 +16,7 @@ const API_URL = (import.meta.env.VITE_API_URL || 'http://localhost:3000').replac const COLORS = ['#22d3ee', '#4ade80', '#f97316', '#818cf8', '#f472b6', '#facc15', '#fb923c']; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, decimals = 0) { diff --git a/apps/admin/src/pages/ShopeeOrderDetailPage.tsx b/apps/admin/src/pages/ShopeeOrderDetailPage.tsx index 21f2413..4b99285 100644 --- a/apps/admin/src/pages/ShopeeOrderDetailPage.tsx +++ b/apps/admin/src/pages/ShopeeOrderDetailPage.tsx @@ -21,7 +21,7 @@ const API_URL = (import.meta.env.VITE_API_URL || 'http://localhost:3000').replac function authHeaders() { return { 'Content-Type': 'application/json', - Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}`, + Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}`, } } diff --git a/apps/admin/src/pages/ShopeeOverviewPage.tsx b/apps/admin/src/pages/ShopeeOverviewPage.tsx index c579efa..4c8b467 100644 --- a/apps/admin/src/pages/ShopeeOverviewPage.tsx +++ b/apps/admin/src/pages/ShopeeOverviewPage.tsx @@ -56,7 +56,7 @@ const PRESETS: { key: Preset; label: string }[] = [ ]; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, dec = 0) { return new Intl.NumberFormat('th-TH', { minimumFractionDigits: dec, maximumFractionDigits: dec }).format(val); diff --git a/apps/admin/src/pages/ShopeePage.tsx b/apps/admin/src/pages/ShopeePage.tsx index 907cf8f..ce8525c 100644 --- a/apps/admin/src/pages/ShopeePage.tsx +++ b/apps/admin/src/pages/ShopeePage.tsx @@ -8,7 +8,7 @@ const API_URL = (import.meta.env.VITE_API_URL || 'http://localhost:3000').replac // ── Shop Config ─────────────────────────────────────────────────────────────── export const SHOPEE_SHOPS = [ { id: 'hom-aroma', label: 'Hom Aroma', color: 'text-orange-400', bg: 'bg-orange-500/15', border: 'border-orange-500/20', activeBg: 'bg-orange-500/20', activeBorder: 'border-orange-500/30' }, - { id: 'shop-01', label: 'iRelax', color: 'text-violet-400', bg: 'bg-violet-500/15', border: 'border-violet-500/20', activeBg: 'bg-violet-500/20', activeBorder: 'border-violet-500/30' }, + { id: 'shop-01', label: 'HomAroma', color: 'text-violet-400', bg: 'bg-violet-500/15', border: 'border-violet-500/20', activeBg: 'bg-violet-500/20', activeBorder: 'border-violet-500/30' }, { id: 'shop-02', label: 'Shop-02', color: 'text-sky-400', bg: 'bg-sky-500/15', border: 'border-sky-500/20', activeBg: 'bg-sky-500/20', activeBorder: 'border-sky-500/30' }, ]; @@ -17,7 +17,7 @@ function getShop(id: string) { return SHOPEE_SHOPS.find(s => s.id === id) ?? SHO function authHeaders() { return { 'Content-Type': 'application/json', - Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}`, + Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}`, }; } diff --git a/apps/admin/src/pages/TiktokAnalysisPage.tsx b/apps/admin/src/pages/TiktokAnalysisPage.tsx index 1f6f391..1829177 100644 --- a/apps/admin/src/pages/TiktokAnalysisPage.tsx +++ b/apps/admin/src/pages/TiktokAnalysisPage.tsx @@ -12,7 +12,7 @@ function formatCurrency(val: number) { } function authHeaders() { - return { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } const COLORS = ['#22d3ee', '#818cf8', '#c084fc', '#f472b6', '#fb923c', '#facc15', '#4ade80']; diff --git a/apps/admin/src/pages/TiktokAnalyticsPage.tsx b/apps/admin/src/pages/TiktokAnalyticsPage.tsx index bc96dc8..889cd8a 100644 --- a/apps/admin/src/pages/TiktokAnalyticsPage.tsx +++ b/apps/admin/src/pages/TiktokAnalyticsPage.tsx @@ -16,7 +16,7 @@ const API_URL = (import.meta.env.VITE_API_URL || 'http://localhost:3000').replac const COLORS = ['#22d3ee', '#4ade80', '#f97316', '#818cf8', '#f472b6', '#facc15', '#fb923c']; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, decimals = 0) { diff --git a/apps/admin/src/pages/TiktokOrderPage.tsx b/apps/admin/src/pages/TiktokOrderPage.tsx index ec0a77d..3957c79 100644 --- a/apps/admin/src/pages/TiktokOrderPage.tsx +++ b/apps/admin/src/pages/TiktokOrderPage.tsx @@ -17,7 +17,7 @@ export const TIKTOK_SHOPS = [ function getShop(id: string) { return TIKTOK_SHOPS.find(s => s.id === id) ?? TIKTOK_SHOPS[0]; } function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number) { return new Intl.NumberFormat('th-TH', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(val); diff --git a/apps/admin/src/pages/TiktokOverviewPage.tsx b/apps/admin/src/pages/TiktokOverviewPage.tsx index 58a782b..7cfb9c9 100644 --- a/apps/admin/src/pages/TiktokOverviewPage.tsx +++ b/apps/admin/src/pages/TiktokOverviewPage.tsx @@ -55,7 +55,7 @@ const PRESETS: { key: Preset; label: string }[] = [ ]; function authHeaders() { - return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } function fmt(val: number, dec = 0) { return new Intl.NumberFormat('th-TH', { minimumFractionDigits: dec, maximumFractionDigits: dec }).format(val); diff --git a/apps/admin/src/pages/TiktokPage.tsx b/apps/admin/src/pages/TiktokPage.tsx index be249a6..2874cc9 100644 --- a/apps/admin/src/pages/TiktokPage.tsx +++ b/apps/admin/src/pages/TiktokPage.tsx @@ -12,7 +12,7 @@ function formatCurrency(val: number) { } function authHeaders() { - return { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('irelax_admin_token')}` }; + return { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('homaroma_admin_token')}` }; } // ─── TSV parser: handles quoted fields (embedded tabs/newlines) + skip rows ──── diff --git a/apps/backend/package.json b/apps/backend/package.json index 2c179ff..d6aa78a 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -1,7 +1,7 @@ { "name": "backend", "version": "1.0.0", - "description": "iRelax API — Elysia.js + Prisma 7", + "description": "HomAroma API — Elysia.js + Prisma 7", "module": "src/index.ts", "type": "module", "scripts": { diff --git a/apps/backend/prisma/schema.prisma b/apps/backend/prisma/schema.prisma index 41d3415..f822a09 100644 --- a/apps/backend/prisma/schema.prisma +++ b/apps/backend/prisma/schema.prisma @@ -118,7 +118,7 @@ model StoreSettings { id Int @id @default(1) shippingFee Float @default(35) bankName String @default("KASIKORNBANK (KBANK)") - bankAccountName String @default("iRelax Aroma Co., Ltd.") + bankAccountName String @default("HomAroma Co., Ltd.") bankAccountNumber String @default("012-3-45678-9") updatedAt DateTime @updatedAt } diff --git a/apps/backend/prisma/seed.cjs b/apps/backend/prisma/seed.cjs index e82dff2..03a2b9c 100644 --- a/apps/backend/prisma/seed.cjs +++ b/apps/backend/prisma/seed.cjs @@ -86,7 +86,7 @@ async function main() { } // 0. Seed Admin User - const adminPassword = await bcrypt.hash('irelax123', 10); + const adminPassword = await bcrypt.hash('homaroma123', 10); await prisma.user.upsert({ where: { username: 'admin' }, update: { password: adminPassword }, @@ -96,7 +96,7 @@ async function main() { role: 'ADMIN' } }); - process.stdout.write('✅ Seeded Admin User (admin / irelax123).\n'); + process.stdout.write('✅ Seeded Admin User (admin / homaroma123).\n'); // 1. Seed Scents & Categories const scents = []; diff --git a/apps/backend/src/routes/auth.ts b/apps/backend/src/routes/auth.ts index b2eec73..ea28ebf 100644 --- a/apps/backend/src/routes/auth.ts +++ b/apps/backend/src/routes/auth.ts @@ -7,7 +7,7 @@ export const authRoute = new Elysia({ prefix: "/auth" }) .use( jwt({ name: "jwt", - secret: process.env.JWT_SECRET || "irelax_secret_2026_scent", + secret: process.env.JWT_SECRET || "homaroma_secret_2026_scent", exp: "24h", }) ) diff --git a/apps/spa/src/components/CartDrawer.tsx b/apps/spa/src/components/CartDrawer.tsx index 831221a..67b3754 100644 --- a/apps/spa/src/components/CartDrawer.tsx +++ b/apps/spa/src/components/CartDrawer.tsx @@ -126,7 +126,7 @@ function CartDrawerFooter({ subtotal, onClose }: { subtotal: number; onClose: () const [couponValid, setCouponValid] = React.useState(false) React.useEffect(() => { - const code = localStorage.getItem('irelax_active_coupon') + const code = localStorage.getItem('homaroma_active_coupon') setSavedCoupon(code) if (code && subtotal > 0) { fetch(`${API_BASE}/coupons/validate`, { @@ -149,7 +149,7 @@ function CartDrawerFooter({ subtotal, onClose }: { subtotal: number; onClose: () }, [subtotal]) const removeCoupon = () => { - localStorage.removeItem('irelax_active_coupon') + localStorage.removeItem('homaroma_active_coupon') setSavedCoupon(null) setDiscountAmount(0) setIsFreeShipping(false) diff --git a/apps/spa/src/components/Footer.tsx b/apps/spa/src/components/Footer.tsx index e6b957f..d063715 100644 --- a/apps/spa/src/components/Footer.tsx +++ b/apps/spa/src/components/Footer.tsx @@ -13,7 +13,7 @@ export default function Footer({ categories = [] }: FooterProps) {
- iRelax Essential + HomAroma Essential

{t('footer.catchphrase')} @@ -64,7 +64,7 @@ export default function Footer({ categories = [] }: FooterProps) {

- © {new Date().getFullYear()} iRelax Essential. {t('footer.rights')} + © {new Date().getFullYear()} HomAroma. {t('footer.rights')}

diff --git a/apps/spa/src/components/Navbar.tsx b/apps/spa/src/components/Navbar.tsx index 8eb8800..f8d3fd0 100644 --- a/apps/spa/src/components/Navbar.tsx +++ b/apps/spa/src/components/Navbar.tsx @@ -27,7 +27,7 @@ export default function Navbar({ categories = [] }: NavbarProps) { const toggleLanguage = () => { const newLang = i18n.language.startsWith('en') ? 'th' : 'en' i18n.changeLanguage(newLang) - localStorage.setItem('irelax_lang', newLang) + localStorage.setItem('homaroma_lang', newLang) } // Detect scroll for navbar bg change @@ -36,7 +36,7 @@ export default function Navbar({ categories = [] }: NavbarProps) { window.addEventListener('scroll', onScroll, { passive: true }) // Check local orders periodically (or just on mount) - const stored = localStorage.getItem('irelax_local_orders') + const stored = localStorage.getItem('homaroma_local_orders') if (stored) { try { setLocalOrdersCount(JSON.parse(stored).length) } catch (e) {} } @@ -75,7 +75,7 @@ export default function Navbar({ categories = [] }: NavbarProps) { > {/* Logo */} setMobileOpen(false)} className="text-xl md:text-2xl font-bold tracking-widest text-white uppercase italic shrink-0"> - iRelax Essential + HomAroma Essential {/* ── DESKTOP NAV ── */} diff --git a/apps/spa/src/i18n.ts b/apps/spa/src/i18n.ts index 5659e40..7e17176 100644 --- a/apps/spa/src/i18n.ts +++ b/apps/spa/src/i18n.ts @@ -5,7 +5,7 @@ import enTranslation from './locales/en/translation.json' import thTranslation from './locales/th/translation.json' // Retrieve default lang from localStorage if set -const savedLang = localStorage.getItem('irelax_lang') || 'th' +const savedLang = localStorage.getItem('homaroma_lang') || 'th' i18n .use(initReactI18next) diff --git a/apps/spa/src/pages/AboutPage.tsx b/apps/spa/src/pages/AboutPage.tsx index 66e6556..31bba4e 100644 --- a/apps/spa/src/pages/AboutPage.tsx +++ b/apps/spa/src/pages/AboutPage.tsx @@ -52,7 +52,7 @@ export default function AboutPage() { Born from a passion for stillness

- iRelax began in 2019 as a one-person studio in Bangkok, crafting small batches of botanical aroma blends for friends and family. What started as a personal journey toward calm became a philosophy — that our environment shapes how we feel, think, and rest. + HomAroma began in 2019 as a one-person studio in Bangkok, crafting small batches of botanical aroma blends for friends and family. What started as a personal journey toward calm became a philosophy — that our environment shapes how we feel, think, and rest.

@@ -81,7 +81,7 @@ export default function AboutPage() { We believe that scent is the fastest pathway to emotional transformation. A single breath of the right blend can dissolve anxiety, sharpen focus, or unlock creativity. Our mission is to make that transformation accessible — through products that are as beautiful as they are effective.

- Every iRelax product is designed with intention: the glass bottles are reusable, the packaging is recycled, and the formulas are written to be understood by anyone — not hidden behind chemical jargon. + Every HomAroma product is designed with intention: the glass bottles are reusable, the packaging is recycled, and the formulas are written to be understood by anyone — not hidden behind chemical jargon.

@@ -89,7 +89,7 @@ export default function AboutPage() {
🌿
-

iRelax Studio, Bangkok

+

HomAroma Studio, Bangkok

diff --git a/apps/spa/src/pages/CheckoutPage.tsx b/apps/spa/src/pages/CheckoutPage.tsx index 7270165..7162105 100644 --- a/apps/spa/src/pages/CheckoutPage.tsx +++ b/apps/spa/src/pages/CheckoutPage.tsx @@ -58,7 +58,7 @@ export default function CheckoutPage() { .then(setCategories) // Check if there's an active coupon saved in localStorage - const savedCoupon = localStorage.getItem('irelax_active_coupon') + const savedCoupon = localStorage.getItem('homaroma_active_coupon') if (savedCoupon) { setCouponCode(savedCoupon) // We will trigger handleApplyCoupon but we need to wait for items/subtotal to be ready. @@ -80,7 +80,7 @@ export default function CheckoutPage() { // Auto-apply saved coupon if subtotal is ready useEffect(() => { - const savedCoupon = localStorage.getItem('irelax_active_coupon') + const savedCoupon = localStorage.getItem('homaroma_active_coupon') if (savedCoupon && subtotal > 0 && !appliedCoupon && !couponError && !couponLoading) { setCouponCode(savedCoupon) // trigger fetch to validate @@ -96,7 +96,7 @@ export default function CheckoutPage() { setDiscountAmount(data.discountAmount) setIsFreeShipping(data.isFreeShipping) } else { - localStorage.removeItem('irelax_active_coupon') // Remove invalid + localStorage.removeItem('homaroma_active_coupon') // Remove invalid } }) .catch(console.error) @@ -160,7 +160,7 @@ export default function CheckoutPage() { setDiscountAmount(0) setIsFreeShipping(false) setCouponError('') - localStorage.removeItem('irelax_active_coupon') + localStorage.removeItem('homaroma_active_coupon') } const handleSubmit = async (e: React.FormEvent) => { @@ -200,10 +200,10 @@ export default function CheckoutPage() { if (res.ok) { clearCart() - const existingStr = localStorage.getItem('irelax_local_orders') + const existingStr = localStorage.getItem('homaroma_local_orders') const existing = existingStr ? JSON.parse(existingStr) : [] if (!existing.includes(responseData.id)) { - localStorage.setItem('irelax_local_orders', JSON.stringify([responseData.id, ...existing])) + localStorage.setItem('homaroma_local_orders', JSON.stringify([responseData.id, ...existing])) } navigate(`/order/${responseData.id}`) diff --git a/apps/spa/src/pages/ContactPage.tsx b/apps/spa/src/pages/ContactPage.tsx index 2cce39c..9d06bb4 100644 --- a/apps/spa/src/pages/ContactPage.tsx +++ b/apps/spa/src/pages/ContactPage.tsx @@ -50,9 +50,9 @@ export default function ContactPage() {

Reach Us Directly

{[ - { icon: '📧', label: 'Email', value: 'hello@irelax.co.th', href: 'mailto:hello@irelax.co.th' }, - { icon: '📱', label: 'LINE Official', value: '@irelaxessential', href: '#' }, - { icon: '📸', label: 'Instagram', value: '@irelax.essential', href: '#' }, + { icon: '📧', label: 'Email', value: 'hello@homaroma.shop', href: 'mailto:hello@homaroma.shop' }, + { icon: '📱', label: 'LINE Official', value: '@homaroma', href: '#' }, + { icon: '📸', label: 'Instagram', value: '@homaroma', href: '#' }, { icon: '📍', label: 'Studio', value: 'Bangkok, Thailand', href: '#' }, ].map(item => ( diff --git a/apps/spa/src/pages/CouponsPage.tsx b/apps/spa/src/pages/CouponsPage.tsx index 06d7a79..d4a6bfb 100644 --- a/apps/spa/src/pages/CouponsPage.tsx +++ b/apps/spa/src/pages/CouponsPage.tsx @@ -56,7 +56,7 @@ export default function CouponsPage() { } const handleUseNow = (code: string) => { - localStorage.setItem('irelax_active_coupon', code) + localStorage.setItem('homaroma_active_coupon', code) navigate('/shop') } diff --git a/apps/spa/src/pages/FaqPage.tsx b/apps/spa/src/pages/FaqPage.tsx index cb6ab34..7a130a6 100644 --- a/apps/spa/src/pages/FaqPage.tsx +++ b/apps/spa/src/pages/FaqPage.tsx @@ -8,7 +8,7 @@ const FAQS = [ category: 'Products', icon: '🌿', items: [ - { q: 'What are the ingredients in your aroma products?', a: 'All iRelax products are crafted from 100% natural botanical extracts, pure essential oils, and pharmaceutical-grade carrier bases. We never use synthetic fragrances, parabens, or harmful chemicals. Each product label lists full ingredient transparency.' }, + { q: 'What are the ingredients in your aroma products?', a: 'All HomAroma products are crafted from 100% natural botanical extracts, pure essential oils, and pharmaceutical-grade carrier bases. We never use synthetic fragrances, parabens, or harmful chemicals. Each product label lists full ingredient transparency.' }, { q: 'How long does each product last?', a: 'Our Reed Diffusers last 4–8 weeks depending on room size and airflow. Aroma Oils (30ml) last approximately 3–4 months with normal use. Room Sprays (100ml) provide 60–80 uses. Car Diffusers cartridges last up to 45 days.' }, { q: 'Are your products suitable for sensitive skin or allergies?', a: 'We recommend patch testing before topical use. Our Aroma Oils are formulated for diffuser use primarily. If you have known fragrance allergies, consult our scent guide or contact us with your specific concerns — we are happy to help identify suitable options.' }, { q: 'What is the difference between Aroma Oil and Oil Ozone?', a: 'Aroma Oils are pure essential oil blends designed for aromatherapy diffusers and therapeutic use. Oil Ozone is our premium line featuring ozone-infused botanical extracts — designed for air purification and deeper space transformation, ideal for large rooms and commercial spaces.' }, @@ -29,7 +29,7 @@ const FAQS = [ items: [ { q: 'How long does shipping take?', a: 'Standard delivery within Bangkok takes 1–2 business days. Provincial orders take 2–4 business days. Express same-day delivery is available in Bangkok for orders placed before 12:00 PM.' }, { q: 'Do you ship internationally?', a: 'Currently we ship within Thailand only. International shipping is planned for late 2025. Sign up for our newsletter to be notified when we expand to your region.' }, - { q: 'What is your return policy?', a: 'We accept returns within 14 days of purchase for unopened, undamaged products in original packaging. For defective or damaged products, we offer full replacement at no cost. Contact us at hello@irelax.co.th with your order number.' }, + { q: 'What is your return policy?', a: 'We accept returns within 14 days of purchase for unopened, undamaged products in original packaging. For defective or damaged products, we offer full replacement at no cost. Contact us at hello@homaroma.shop with your order number.' }, ], }, { @@ -64,7 +64,7 @@ export default function FaqPage() {

Support

Frequently Asked Questions

- Everything you need to know about iRelax products, shipping, and care. + Everything you need to know about HomAroma products, shipping, and care.

diff --git a/apps/spa/src/pages/ShopPage.tsx b/apps/spa/src/pages/ShopPage.tsx index dc851e4..566cc58 100644 --- a/apps/spa/src/pages/ShopPage.tsx +++ b/apps/spa/src/pages/ShopPage.tsx @@ -27,7 +27,7 @@ export default function ShopPage() { const params = new URLSearchParams(location.search) const coupon = params.get('coupon') if (coupon) { - localStorage.setItem('irelax_active_coupon', coupon) + localStorage.setItem('homaroma_active_coupon', coupon) // Optionally clean URL window.history.replaceState({}, document.title, window.location.pathname) } diff --git a/apps/spa/src/pages/TrackOrderPage.tsx b/apps/spa/src/pages/TrackOrderPage.tsx index 3655ea6..63f7bb7 100644 --- a/apps/spa/src/pages/TrackOrderPage.tsx +++ b/apps/spa/src/pages/TrackOrderPage.tsx @@ -22,7 +22,7 @@ export default function TrackOrderPage() { .catch(console.error) // Load local orders - const storedStr = localStorage.getItem('irelax_local_orders') + const storedStr = localStorage.getItem('homaroma_local_orders') if (storedStr) { setLocalOrders(JSON.parse(storedStr)) } @@ -49,7 +49,7 @@ export default function TrackOrderPage() { if (!localOrders.includes(data.orderId)) { const newOrders = [data.orderId, ...localOrders] setLocalOrders(newOrders) - localStorage.setItem('irelax_local_orders', JSON.stringify(newOrders)) + localStorage.setItem('homaroma_local_orders', JSON.stringify(newOrders)) } navigate(`/order/${data.orderId}`) } else { diff --git a/apps/spa/src/store/authStore.ts b/apps/spa/src/store/authStore.ts index 624b657..c0cec90 100644 --- a/apps/spa/src/store/authStore.ts +++ b/apps/spa/src/store/authStore.ts @@ -30,7 +30,7 @@ export const useAuthStore = create()( logout: () => set({ token: null, customer: null }), }), { - name: "irelax-auth-storage", + name: "homaroma-auth-storage", partialize: (state) => ({ token: state.token, customer: state.customer }), // don't persist isLiffInitialized } ) diff --git a/apps/spa/src/store/cartStore.ts b/apps/spa/src/store/cartStore.ts index 133e686..fdb98ef 100644 --- a/apps/spa/src/store/cartStore.ts +++ b/apps/spa/src/store/cartStore.ts @@ -71,7 +71,7 @@ export const useCartStore = create()( } }), { - name: 'irelax-cart-storage', + name: 'homaroma-cart-storage', partialize: (state) => ({ items: state.items }), // Only persist items, not UI state } ) diff --git a/apps/website/src/app/about/page.tsx b/apps/website/src/app/about/page.tsx index 55d1883..819391c 100644 --- a/apps/website/src/app/about/page.tsx +++ b/apps/website/src/app/about/page.tsx @@ -26,8 +26,8 @@ const STATS = [ ] export const metadata = { - title: 'About Us | iRelax Aroma', - description: 'Born from a passion for stillness. iRelax began in 2019 as a Bangkok studio crafting botanical aroma blends.', + title: 'About Us | HomAroma', + description: 'Born from a passion for stillness. HomAroma began in 2019 as a Bangkok studio crafting botanical aroma blends.', } export default function AboutPage() { @@ -46,7 +46,7 @@ export default function AboutPage() { Born from a passion for stillness

- iRelax began in 2019 as a one-person studio in Bangkok, crafting small batches of botanical aroma blends for friends and family. What started as a personal journey toward calm became a philosophy — that our environment shapes how we feel, think, and rest. + HomAroma began in 2019 as a one-person studio in Bangkok, crafting small batches of botanical aroma blends for friends and family. What started as a personal journey toward calm became a philosophy — that our environment shapes how we feel, think, and rest.

@@ -73,7 +73,7 @@ export default function AboutPage() { We believe that scent is the fastest pathway to emotional transformation. A single breath of the right blend can dissolve anxiety, sharpen focus, or unlock creativity. Our mission is to make that transformation accessible — through products that are as beautiful as they are effective.

- Every iRelax product is designed with intention: the glass bottles are reusable, the packaging is recycled, and the formulas are written to be understood by anyone — not hidden behind chemical jargon. + Every HomAroma product is designed with intention: the glass bottles are reusable, the packaging is recycled, and the formulas are written to be understood by anyone — not hidden behind chemical jargon.

@@ -81,7 +81,7 @@ export default function AboutPage() {
🌿
-

iRelax Studio, Bangkok

+

HomAroma Studio, Bangkok

diff --git a/apps/website/src/app/article/[slug]/page.tsx b/apps/website/src/app/article/[slug]/page.tsx index 2b9deec..97c6efe 100644 --- a/apps/website/src/app/article/[slug]/page.tsx +++ b/apps/website/src/app/article/[slug]/page.tsx @@ -16,9 +16,9 @@ async function getArticle(slug: string): Promise
{ export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise { const { slug } = await params const article = await getArticle(slug) - if (!article) return { title: 'Article Not Found | iRelax' } + if (!article) return { title: 'Article Not Found | HomAroma' } return { - title: `${article.title} | iRelax Scent Guide`, + title: `${article.title} | HomAroma Scent Guide`, description: article.content.replace(/<[^>]+>/g, '').slice(0, 160), openGraph: { title: article.title, diff --git a/apps/website/src/app/contact/layout.tsx b/apps/website/src/app/contact/layout.tsx index bf73dbf..8b8d01d 100644 --- a/apps/website/src/app/contact/layout.tsx +++ b/apps/website/src/app/contact/layout.tsx @@ -1,8 +1,8 @@ import type { Metadata } from 'next' export const metadata: Metadata = { - title: 'Contact Us | iRelax Aroma', - description: 'Get in touch with iRelax. We respond to all inquiries within 2 hours.', + title: 'Contact Us | HomAroma', + description: 'Get in touch with HomAroma. We respond to all inquiries within 2 hours.', } export default function ContactLayout({ children }: { children: React.ReactNode }) { diff --git a/apps/website/src/app/contact/page.tsx b/apps/website/src/app/contact/page.tsx index a004ef2..4de3021 100644 --- a/apps/website/src/app/contact/page.tsx +++ b/apps/website/src/app/contact/page.tsx @@ -39,9 +39,9 @@ export default function ContactPage() {

Reach Us Directly

{[ - { icon: '📧', label: 'Email', value: 'hello@irelax.co.th', href: 'mailto:hello@irelax.co.th' }, - { icon: '📱', label: 'LINE Official', value: '@irelaxessential', href: '#' }, - { icon: '📸', label: 'Instagram', value: '@irelax.essential', href: '#' }, + { icon: '📧', label: 'Email', value: 'hello@homaroma.shop', href: 'mailto:hello@homaroma.shop' }, + { icon: '📱', label: 'LINE Official', value: '@homaroma', href: '#' }, + { icon: '📸', label: 'Instagram', value: '@homaroma', href: '#' }, { icon: '📍', label: 'Studio', value: 'Bangkok, Thailand', href: '#' }, ].map(item => ( diff --git a/apps/website/src/app/coupons/page.tsx b/apps/website/src/app/coupons/page.tsx index a3ca938..2ae02da 100644 --- a/apps/website/src/app/coupons/page.tsx +++ b/apps/website/src/app/coupons/page.tsx @@ -24,8 +24,8 @@ function formatDiscount(type: string, value: number) { } export const metadata = { - title: 'โปรโมชั่นและคูปองส่วนลด | iRelax', - description: 'รวมรหัสส่วนลดและโปรโมชั่นพิเศษจาก iRelax สำหรับการสั่งซื้อน้ำหอมและผลิตภัณฑ์อโรม่าที่คุณชื่นชอบ', + title: 'โปรโมชั่นและคูปองส่วนลด | HomAroma', + description: 'รวมรหัสส่วนลดและโปรโมชั่นพิเศษจาก HomAroma สำหรับการสั่งซื้อน้ำหอมและผลิตภัณฑ์อโรม่าที่คุณชื่นชอบ', } export default async function CouponsPage() { @@ -48,7 +48,7 @@ export default async function CouponsPage() {

ยังไม่มีคูปองส่วนลดในขณะนี้

กรุณากลับมาตรวจสอบโปรโมชั่นใหม่ในภายหลัง

ไปช้อปปิ้งกันก่อน @@ -92,7 +92,7 @@ export default async function CouponsPage() {
ช้อปพร้อมใช้คูปองเลย diff --git a/apps/website/src/app/faq/layout.tsx b/apps/website/src/app/faq/layout.tsx index 076337b..144e17d 100644 --- a/apps/website/src/app/faq/layout.tsx +++ b/apps/website/src/app/faq/layout.tsx @@ -1,8 +1,8 @@ import type { Metadata } from 'next' export const metadata: Metadata = { - title: 'FAQ | iRelax Aroma', - description: 'Everything you need to know about iRelax products, shipping, and care.', + title: 'FAQ | HomAroma', + description: 'Everything you need to know about HomAroma products, shipping, and care.', } export default function FaqLayout({ children }: { children: React.ReactNode }) { diff --git a/apps/website/src/app/faq/page.tsx b/apps/website/src/app/faq/page.tsx index f6b7af8..46ca900 100644 --- a/apps/website/src/app/faq/page.tsx +++ b/apps/website/src/app/faq/page.tsx @@ -5,7 +5,7 @@ const FAQS = [ { category: 'Products', icon: '🌿', items: [ - { q: 'What are the ingredients in your aroma products?', a: 'All iRelax products are crafted from 100% natural botanical extracts, pure essential oils, and pharmaceutical-grade carrier bases. We never use synthetic fragrances, parabens, or harmful chemicals. Each product label lists full ingredient transparency.' }, + { q: 'What are the ingredients in your aroma products?', a: 'All HomAroma products are crafted from 100% natural botanical extracts, pure essential oils, and pharmaceutical-grade carrier bases. We never use synthetic fragrances, parabens, or harmful chemicals. Each product label lists full ingredient transparency.' }, { q: 'How long does each product last?', a: 'Our Reed Diffusers last 4–8 weeks depending on room size and airflow. Aroma Oils (30ml) last approximately 3–4 months with normal use. Room Sprays (100ml) provide 60–80 uses. Car Diffusers cartridges last up to 45 days.' }, { q: 'Are your products suitable for sensitive skin or allergies?', a: 'We recommend patch testing before topical use. Our Aroma Oils are formulated for diffuser use primarily. If you have known fragrance allergies, consult our scent guide or contact us with your specific concerns.' }, { q: 'What is the difference between Aroma Oil and Oil Ozone?', a: 'Aroma Oils are pure essential oil blends designed for aromatherapy diffusers and therapeutic use. Oil Ozone is our premium line featuring ozone-infused botanical extracts — designed for air purification and deeper space transformation.' }, @@ -48,7 +48,7 @@ export default function FaqPage() {

Support

Frequently Asked Questions

-

Everything you need to know about iRelax products, shipping, and care.

+

Everything you need to know about HomAroma products, shipping, and care.

diff --git a/apps/website/src/app/layout.tsx b/apps/website/src/app/layout.tsx index 2504a09..249fa48 100644 --- a/apps/website/src/app/layout.tsx +++ b/apps/website/src/app/layout.tsx @@ -6,7 +6,7 @@ import ClientProviders from '../components/ClientProviders'; import { API_BASE } from '../lib/api'; export const metadata: Metadata = { - title: 'iRelax Aroma', + title: 'HomAroma', description: 'Pure Origins, Artisan Craft, Zero Compromise', }; diff --git a/apps/website/src/app/products/[id]/page.tsx b/apps/website/src/app/products/[id]/page.tsx index 8c69566..e29f879 100644 --- a/apps/website/src/app/products/[id]/page.tsx +++ b/apps/website/src/app/products/[id]/page.tsx @@ -26,10 +26,10 @@ async function getRelated(categoryId: number, excludeId: number): Promise }): Promise { const { id } = await params const product = await getProduct(id) - if (!product) return { title: 'Product Not Found | iRelax' } + if (!product) return { title: 'Product Not Found | HomAroma' } return { - title: `${product.scent.name} ${product.category.name} | iRelax Aroma`, - description: product.description ?? `Premium ${product.category.name} — ${product.scent.name}. Shop iRelax Aroma for high-quality botanical scents.`, + title: `${product.scent.name} ${product.category.name} | HomAroma`, + description: product.description ?? `Premium ${product.category.name} — ${product.scent.name}. Shop HomAroma for high-quality botanical scents.`, openGraph: { title: product.scent.name, description: product.description ?? '', diff --git a/apps/website/src/app/scent-guide/page.tsx b/apps/website/src/app/scent-guide/page.tsx index 703e0f5..9c67be0 100644 --- a/apps/website/src/app/scent-guide/page.tsx +++ b/apps/website/src/app/scent-guide/page.tsx @@ -3,7 +3,7 @@ import type { Article } from '@homaroma/types' import { API_BASE } from '../../lib/api' export const metadata = { - title: 'Scent Guide | iRelax Aroma', + title: 'Scent Guide | HomAroma', description: 'Explore our collection of aroma articles, guides, and sensory knowledge to find your perfect scent.', } diff --git a/apps/website/src/app/search/layout.tsx b/apps/website/src/app/search/layout.tsx index 994db2a..63b804a 100644 --- a/apps/website/src/app/search/layout.tsx +++ b/apps/website/src/app/search/layout.tsx @@ -1,7 +1,7 @@ import type { Metadata } from 'next' export const metadata: Metadata = { - title: 'Search Products | iRelax Aroma', + title: 'Search Products | HomAroma', description: 'Search our collection of premium aroma products by scent or product name.', } diff --git a/apps/website/src/app/shop/layout.tsx b/apps/website/src/app/shop/layout.tsx index f3952fa..e6d47ec 100644 --- a/apps/website/src/app/shop/layout.tsx +++ b/apps/website/src/app/shop/layout.tsx @@ -1,7 +1,7 @@ import type { Metadata } from 'next' export const metadata: Metadata = { - title: 'Shop All Products | iRelax Aroma', + title: 'Shop All Products | HomAroma', description: 'Browse our full range of premium aroma products — crafted to elevate every space.', } diff --git a/apps/website/src/components/Footer.tsx b/apps/website/src/components/Footer.tsx index 808d723..a824342 100644 --- a/apps/website/src/components/Footer.tsx +++ b/apps/website/src/components/Footer.tsx @@ -14,7 +14,7 @@ export default function Footer({ categories = [] }: FooterProps) {
- iRelax Essential + HomAroma Essential

{t('footer.catchphrase')} @@ -65,7 +65,7 @@ export default function Footer({ categories = [] }: FooterProps) {

- © {new Date().getFullYear()} iRelax Essential. {t('footer.rights')} + © {new Date().getFullYear()} HomAroma. {t('footer.rights')}

diff --git a/apps/website/src/components/Navbar.tsx b/apps/website/src/components/Navbar.tsx index a1cd190..a9fce88 100644 --- a/apps/website/src/components/Navbar.tsx +++ b/apps/website/src/components/Navbar.tsx @@ -27,7 +27,7 @@ export default function Navbar({ categories = [] }: NavbarProps) { const toggleLanguage = () => { const newLang = i18n.language.startsWith('en') ? 'th' : 'en' i18n.changeLanguage(newLang) - localStorage.setItem('irelax_lang', newLang) + localStorage.setItem('homaroma_lang', newLang) } // Detect scroll for navbar bg change @@ -36,7 +36,7 @@ export default function Navbar({ categories = [] }: NavbarProps) { window.addEventListener('scroll', onScroll, { passive: true }) // Check local orders periodically (or just on mount) - const stored = localStorage.getItem('irelax_local_orders') + const stored = localStorage.getItem('homaroma_local_orders') if (stored) { try { setLocalOrdersCount(JSON.parse(stored).length) } catch (e) {} } @@ -75,7 +75,7 @@ export default function Navbar({ categories = [] }: NavbarProps) { > {/* Logo */} setMobileOpen(false)} className="text-xl md:text-2xl font-bold tracking-widest text-white uppercase italic shrink-0"> - iRelax Essential + HomAroma Essential {/* ── DESKTOP NAV ── */} diff --git a/apps/website/src/lib/api.ts b/apps/website/src/lib/api.ts index d3c6374..24c5563 100644 --- a/apps/website/src/lib/api.ts +++ b/apps/website/src/lib/api.ts @@ -8,7 +8,7 @@ * 3. Fallback dev — http://localhost:3000/api * * Dev: NEXT_PUBLIC_API_URL=http://localhost:3000/api - * Production: NEXT_PUBLIC_API_URL=https://api.irelaxaroma.shop/api + * Production: NEXT_PUBLIC_API_URL=https://api.homaroma.shop/api */ export const API_BASE = process.env.NEXT_PUBLIC_API_URL || diff --git a/apps/website/src/lib/i18n.ts b/apps/website/src/lib/i18n.ts index 234de9f..70fcf07 100644 --- a/apps/website/src/lib/i18n.ts +++ b/apps/website/src/lib/i18n.ts @@ -5,7 +5,7 @@ import enTranslation from '../locales/en/translation.json' import thTranslation from '../locales/th/translation.json' // Ensure we only access localStorage on the client side -const savedLang = typeof window !== 'undefined' ? (localStorage.getItem('irelax_lang') || 'th') : 'th' +const savedLang = typeof window !== 'undefined' ? (localStorage.getItem('homaroma_lang') || 'th') : 'th' // Check if it's already initialized to prevent re-initialization on HMR if (!i18n.isInitialized) { diff --git a/apps/website/src/store/cartStore.ts b/apps/website/src/store/cartStore.ts index 133e686..fdb98ef 100644 --- a/apps/website/src/store/cartStore.ts +++ b/apps/website/src/store/cartStore.ts @@ -71,7 +71,7 @@ export const useCartStore = create()( } }), { - name: 'irelax-cart-storage', + name: 'homaroma-cart-storage', partialize: (state) => ({ items: state.items }), // Only persist items, not UI state } ) diff --git a/cf.js b/cf.js index 948d46e..288a72f 100644 --- a/cf.js +++ b/cf.js @@ -2,7 +2,7 @@ const CONFIG = { email: 'ti.ddc.2026@gmail.com', // อีเมลที่ใช้สมัคร Cloudflare apiKey: 'cfut_fZ4ct5szqJbJxpdEfPT0Q5790SqjKZuU4DlbTukn769a34d8', zoneId: '82a3c279a9f53ab8a5531848031c7629', - recordName: 'irelaxaroma.shop', + recordName: 'homaroma.shop', proxied: false }; diff --git a/deploy-hook.sh b/deploy-hook.sh index 75c1831..cde36c3 100755 --- a/deploy-hook.sh +++ b/deploy-hook.sh @@ -8,7 +8,7 @@ # --- ตั้งค่าตรงนี้ --- SERVER_USER="ti" SERVER_HOST="192.168.1.167" # <-- เปลี่ยนเป็น IP หรือ Domain ของ server -REMOTE_HOOK_PATH="/home/ti/git/irelax.git/hooks/post-receive" +REMOTE_HOOK_PATH="/home/ti/git/homaroma.git/hooks/post-receive" # --------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" diff --git a/frontend-comparison.md b/frontend-comparison.md index 4398d1b..f8a21d1 100644 --- a/frontend-comparison.md +++ b/frontend-comparison.md @@ -1,6 +1,6 @@ # สรุปความแตกต่างและเป้าหมายการใช้งาน: `apps/ssr` vs `apps/website` -เอกสารนี้สรุปความแตกต่างเชิงสถาปัตยกรรม (Architecture) และจุดประสงค์การใช้งานระหว่าง Frontend ทั้งสองระบบในโปรเจกต์ iRelax เพื่อให้ทีมพัฒนาเข้าใจว่าควรเลือกใช้หรือพัฒนาต่อยอดที่โปรเจกต์ใด +เอกสารนี้สรุปความแตกต่างเชิงสถาปัตยกรรม (Architecture) และจุดประสงค์การใช้งานระหว่าง Frontend ทั้งสองระบบในโปรเจกต์ HomAroma เพื่อให้ทีมพัฒนาเข้าใจว่าควรเลือกใช้หรือพัฒนาต่อยอดที่โปรเจกต์ใด ## ตารางเปรียบเทียบ (Comparison Table) @@ -13,9 +13,9 @@ | **จุดเด่น** | ทำงานลื่นไหลเหมือนแอปมือถือ (ไม่กระตุกตอนเปลี่ยนหน้า), เหมาะกับ Webview ในแอปพลิเคชัน | ทำ SEO ได้ดีมาก Bot สามารถอ่านข้อมูลสินค้าได้ทันที, โหลดหน้าแรกได้ไว | | **จุดด้อย** | ทำ SEO ได้ยาก (Bot ของ Google อาจจะอ่านข้อมูลไม่ครบเพราะต้องรอ JavaScript ทำงาน) | ต้องใช้ทรัพยากรฝั่ง Server ในการรัน (Node.js Process), ซับซ้อนกว่าในการตั้งค่า | | **รูปแบบการ Deploy** | **Static Files** (HTML/CSS/JS) เสิร์ฟผ่าน Nginx โดยตรง ไม่ต้องมี Node.js รันเป็นพื้นหลัง | **Node.js Server** ต้องใช้ PM2 รัน `next start` และใช้ Nginx ทำ Reverse Proxy | -| **ตำแหน่งไฟล์บน Server**| `/home/ti/projects/MyNginxMain/nginx/html/irelaxaroma.shop/website` | `/home/ti/projects/irelax-ssr` | +| **ตำแหน่งไฟล์บน Server**| `/home/ti/projects/MyNginxMain/nginx/html/homaroma.shop/website` | `/home/ti/projects/homaroma-ssr` | | **คำสั่ง Build** | `bun run build` (ได้โฟลเดอร์ `dist`) | `bun run build` (ได้โฟลเดอร์ `.next`) | -| **Service ที่ทำงาน**| ไม่มี (Nginx จัดการทั้งหมด) | **PM2** ชื่อ process: `irelax-ssr` รันบนพอร์ต `3001` | +| **Service ที่ทำงาน**| ไม่มี (Nginx จัดการทั้งหมด) | **PM2** ชื่อ process: `homaroma-ssr` รันบนพอร์ต `3001` | | **การจัดการ Routing** | `react-router-dom` (ประมวลผลที่ฝั่ง Client ทั้งหมด) | Next.js App Router (มีระบบ File-based routing) | | **การจัดการ State** | Zustand | React Context / Zustand / Server Components | | **ความเหมาะสมของระบบ Login**| เหมาะสมกับ **LINE LIFF Login** และ Token-based auth เพราะมี Context แบบ SPA | เหมาะกับ Cookie-based Auth (NextAuth/Auth.js) หรือ Session | @@ -44,13 +44,13 @@ - **คำสั่ง Build:** `cd apps/website && bun run build` - **สิ่งที่ได้จากการ Build:** โฟลเดอร์ `dist/` - **ตำแหน่งไฟล์ปลายทาง (Target Directory):** - `/home/ti/projects/MyNginxMain/nginx/html/irelaxaroma.shop/website` + `/home/ti/projects/MyNginxMain/nginx/html/homaroma.shop/website` - **การจัดการ Environment:** ต้องประกาศตัวแปรแวดล้อมก่อนสั่ง Build เสมอ (เช่น `export VITE_LIFF_ID=...`) เพื่อให้ Vite ฝังค่าเข้าไปในไฟล์โค้ด - **การตั้งค่า Nginx ที่จำเป็น (Routing Configuration):** เพื่อให้ระบบ React Router ทำงานได้โดยไม่เกิด 404 Error Nginx ต้องถูกตั้งค่าให้โยน Path ที่ไม่รู้จักกลับไปหา `index.html` เสมอ ```nginx location / { - root /usr/share/nginx/html/irelaxaroma.shop/website; + root /usr/share/nginx/html/homaroma.shop/website; index index.html; try_files $uri $uri/ /index.html; # <--- บังคับให้ SPA จัดการ Route เอง } @@ -61,11 +61,11 @@ - **คำสั่ง Build:** `cd apps/ssr && bun run build` - **สิ่งที่ได้จากการ Build:** โฟลเดอร์ `.next/` และไฟล์ Source Code - **ตำแหน่งไฟล์ปลายทาง (Target Directory):** - `/home/ti/projects/irelax-ssr` + `/home/ti/projects/homaroma-ssr` - **การจัดการ Service (PM2):** ต้องสั่งรันให้แอปทำงานอยู่เบื้องหลังเสมอด้วยคำสั่ง: ```bash - pm2 start /home/ti/projects/irelax-ssr/node_modules/.bin/next --name irelax-ssr -- start -p 3001 + pm2 start /home/ti/projects/homaroma-ssr/node_modules/.bin/next --name homaroma-ssr -- start -p 3001 ``` - **การตั้งค่า Nginx ที่จำเป็น (Reverse Proxy):** Nginx จะไม่ได้เสิร์ฟไฟล์ตรงๆ เหมือน SPA แต่ทำหน้าที่เป็นประตูส่ง Request ต่อไปให้ PM2 (ที่พอร์ต 3001) diff --git a/serverinfo/post-receive b/serverinfo/post-receive index 9f46031..82267c8 100644 --- a/serverinfo/post-receive +++ b/serverinfo/post-receive @@ -1,7 +1,7 @@ #!/bin/bash # ============================================================================== -# iRelax Project - Integrated Deployment Script (post-receive hook) +# HomAroma Project - Integrated Deployment Script (post-receive hook) # ============================================================================== # 1. TARGET PATHS (Nginx & PM2) @@ -34,7 +34,7 @@ SSR_PORT=3002 # START DEPLOYMENT # ------------------------------------------------------------------------------ set -e -echo "------- 🚀 Starting Full Deployment: iRelax Platform -------" +echo "------- 🚀 Starting Full Deployment: HomAroma Platform -------" # A. Prepare Temp Source from Checkout echo "Cloning branch $BRANCH to temporary directory: $TEMP_DIR"