From 6f67ee60779da4a563472d7aad022d6d0f60bd82 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 17 Jun 2026 21:08:24 -0400 Subject: [PATCH] fix update Section Block --- .codex/config.toml | 13 + .../page-builder/HeroArticleForm.tsx | 145 ++++++++++ .../page-builder/ProductCarouselForm.tsx | 110 ++++++++ .../page-builder/QuoteCalloutForm.tsx | 52 ++++ .../components/page-builder/RichTextForm.tsx | 44 +++ .../page-builder/ScentNotesBreakdownForm.tsx | 169 ++++++++++++ apps/admin/src/pages/PageBuilderPage.tsx | 111 +++++++- apps/backend/src/routes/pages.ts | 170 ++++++++++-- apps/mcp-server/README.md | 30 ++- apps/mcp-server/index.ts | 231 +++++++++++++++- apps/mcp-server/package.json | 5 + apps/mcp-server/run.sh | 8 +- .../src/components/DynamicPageRenderer.tsx | 8 +- apps/spa/src/components/DynamicProducts.tsx | 23 +- .../components/DynamicScentNotesBreakdown.tsx | 24 +- apps/spa/src/components/ProductCard.tsx | 14 +- .../components/sections/AccordionSection.tsx | 16 +- .../sections/ContactFormSection.tsx | 102 ++++++- .../sections/ContactInfoSection.tsx | 90 ++++--- apps/spa/src/locales/en/translation.json | 1 + apps/spa/src/locales/ja/translation.json | 1 + apps/spa/src/locales/ko/translation.json | 1 + apps/spa/src/locales/th/translation.json | 1 + apps/spa/src/locales/vi/translation.json | 1 + apps/spa/src/locales/zh/translation.json | 1 + apps/website/src/app/[slug]/page.tsx | 2 +- apps/website/src/app/category/[id]/page.tsx | 2 +- apps/website/src/app/checkout/page.tsx | 2 +- apps/website/src/app/coupons/page.tsx | 2 +- apps/website/src/app/layout.tsx | 70 ++++- apps/website/src/app/order/[id]/page.tsx | 2 +- apps/website/src/app/page.tsx | 2 +- apps/website/src/app/products/[id]/page.tsx | 2 +- apps/website/src/app/profile/page.tsx | 2 +- apps/website/src/app/scent-guide/page.tsx | 2 +- apps/website/src/app/search/page.tsx | 2 +- apps/website/src/app/shop/page.tsx | 2 +- apps/website/src/app/track/page.tsx | 2 +- apps/website/src/app/wishlist/page.tsx | 2 +- .../src/components/AddToCartSection.tsx | 10 +- apps/website/src/components/Footer.tsx | 162 +++++++++-- apps/website/src/components/Navbar.tsx | 39 +-- apps/website/src/components/ProductCard.tsx | 10 +- .../dynamic/DynamicPageRenderer.tsx | 10 +- apps/website/src/hooks/useLang.ts | 21 ++ apps/website/src/lib/cms.ts | 16 +- mcp_update.md | 254 ++++++++++++++++++ 47 files changed, 1792 insertions(+), 197 deletions(-) create mode 100644 .codex/config.toml create mode 100644 apps/admin/src/components/page-builder/HeroArticleForm.tsx create mode 100644 apps/admin/src/components/page-builder/ProductCarouselForm.tsx create mode 100644 apps/admin/src/components/page-builder/QuoteCalloutForm.tsx create mode 100644 apps/admin/src/components/page-builder/RichTextForm.tsx create mode 100644 apps/admin/src/components/page-builder/ScentNotesBreakdownForm.tsx create mode 100644 apps/website/src/hooks/useLang.ts create mode 100644 mcp_update.md diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 0000000..c46619e --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,13 @@ +[mcp_servers.homaroma_mcp] +command = "/home/ti/.bun/bin/bun" +args = ["index.ts"] +cwd = "/home/ti/git/homaroma/apps/mcp-server" +startup_timeout_sec = 20 +tool_timeout_sec = 60 +enabled = true +required = false +default_tools_approval_mode = "prompt" + +[mcp_servers.homaroma_mcp.env] +MCP_BACKEND_URL_LOCAL = "http://localhost:3051/api" +MCP_BACKEND_URL_PRODUCTION = "https://api.homaroma.shop/api" diff --git a/apps/admin/src/components/page-builder/HeroArticleForm.tsx b/apps/admin/src/components/page-builder/HeroArticleForm.tsx new file mode 100644 index 0000000..ecd1647 --- /dev/null +++ b/apps/admin/src/components/page-builder/HeroArticleForm.tsx @@ -0,0 +1,145 @@ +import React from 'react'; +import { UploadCloud, Image as ImageIcon } from 'lucide-react'; +import { type PageSection } from '@homaroma/types'; + +interface HeroArticleFormProps { + editingSection: Partial; + setEditingSection: React.Dispatch | null>>; + editingLang: string; + getLocalizedValue: (payload: any, field: string) => string; + updateLocalizedValue: (field: string, value: string) => void; + setUploadTarget: (target: { type: 'main' | 'slide'; index?: number } | null) => void; + setIsMediaModalOpen: (open: boolean) => void; +} + +export default function HeroArticleForm({ + editingSection, + setEditingSection, + getLocalizedValue, + updateLocalizedValue, + setUploadTarget, + setIsMediaModalOpen, +}: HeroArticleFormProps) { + return ( +
+
+ +
{ + setUploadTarget({ type: 'main' }); + setIsMediaModalOpen(true); + }} + > + {editingSection.payload?.imageUrl ? ( + <> + Hero Article +
+ +
+ + ) : ( +
+ +

Drop in an image URL first

+
+ )} +
+
+ +
+ + updateLocalizedValue('title', e.target.value)} + className="admin-input w-full" + placeholder="Editorial title" + /> +
+ +
+ + updateLocalizedValue('subtitle', e.target.value)} + className="admin-input w-full" + placeholder="Short supporting line" + /> +
+ +
+ + updateLocalizedValue('author', e.target.value)} + className="admin-input w-full" + placeholder="Author name" + /> +
+ +
+ + updateLocalizedValue('category', e.target.value)} + className="admin-input w-full" + placeholder="Story" + /> +
+ +
+ + + setEditingSection({ + ...editingSection, + payload: { ...(editingSection.payload || {}), publishDate: e.target.value } + }) + } + className="admin-input w-full" + placeholder="2026-01-01" + /> +
+ +
+ + + setEditingSection({ + ...editingSection, + payload: { ...(editingSection.payload || {}), overlayColor: e.target.value } + }) + } + className="admin-input w-full" + placeholder="#00000080" + /> +
+ +
+ + + setEditingSection({ + ...editingSection, + payload: { ...(editingSection.payload || {}), imageUrl: e.target.value } + }) + } + className="admin-input w-full" + placeholder="/images/hero.png or select from media library" + /> +
+
+ ); +} diff --git a/apps/admin/src/components/page-builder/ProductCarouselForm.tsx b/apps/admin/src/components/page-builder/ProductCarouselForm.tsx new file mode 100644 index 0000000..5cfe9f3 --- /dev/null +++ b/apps/admin/src/components/page-builder/ProductCarouselForm.tsx @@ -0,0 +1,110 @@ +import React from 'react'; +import { type PageSection } from '@homaroma/types'; + +interface ProductCarouselFormProps { + editingSection: Partial; + editingLang: string; + setEditingSection: React.Dispatch | null>>; + getLocalizedValue: (payload: any, field: string) => string; + updateLocalizedValue: (field: string, value: string) => void; +} + +export default function ProductCarouselForm({ + editingSection, + setEditingSection, + getLocalizedValue, + updateLocalizedValue, +}: ProductCarouselFormProps) { + const updateFlag = (field: 'showPrice' | 'showAddToCart', value: boolean) => { + setEditingSection({ + ...editingSection, + payload: { ...(editingSection.payload || {}), [field]: value } + }); + }; + + return ( +
+
+
+ + updateLocalizedValue('title', e.target.value)} + className="admin-input w-full" + placeholder="Carousel heading" + /> +
+ +
+ + updateLocalizedValue('description', e.target.value)} + className="admin-input w-full" + placeholder="Optional supporting line" + /> +
+ +
+ + + setEditingSection({ + ...editingSection, + payload: { ...(editingSection.payload || {}), collectionId: e.target.value } + }) + } + className="admin-input w-full" + placeholder="Optional collection identifier" + /> +
+ +
+ + + setEditingSection({ + ...editingSection, + payload: { ...(editingSection.payload || {}), limit: parseInt(e.target.value, 10) } + }) + } + className="admin-input w-full" + /> +
+
+ +
+ + + +
+ +

+ If your backend supports collection lookup by ID, place that value here. Otherwise leave it blank and use the default product list behavior. +

+
+ ); +} diff --git a/apps/admin/src/components/page-builder/QuoteCalloutForm.tsx b/apps/admin/src/components/page-builder/QuoteCalloutForm.tsx new file mode 100644 index 0000000..eb7f4c5 --- /dev/null +++ b/apps/admin/src/components/page-builder/QuoteCalloutForm.tsx @@ -0,0 +1,52 @@ +import { type PageSection } from '@homaroma/types'; + +interface QuoteCalloutFormProps { + editingSection: Partial; + editingLang: string; + getLocalizedValue: (payload: any, field: string) => string; + updateLocalizedValue: (field: string, value: string) => void; +} + +export default function QuoteCalloutForm({ + editingSection, + getLocalizedValue, + updateLocalizedValue, +}: QuoteCalloutFormProps) { + return ( +
+
+ +