From cd4b89a0fc51091bbdba73712b44bd2c9825cc51 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 22 Jun 2026 19:11:43 -0400 Subject: [PATCH] x --- apps/admin/src/pages/PageBuilderPage.tsx | 588 +++++++++++++---------- 1 file changed, 328 insertions(+), 260 deletions(-) diff --git a/apps/admin/src/pages/PageBuilderPage.tsx b/apps/admin/src/pages/PageBuilderPage.tsx index 0c996a8..b270f93 100644 --- a/apps/admin/src/pages/PageBuilderPage.tsx +++ b/apps/admin/src/pages/PageBuilderPage.tsx @@ -57,11 +57,11 @@ export default function PageBuilderPage() { const [categories, setCategories] = useState([]); const [scents, setScents] = useState([]); const [loading, setLoading] = useState(true); - const [isModalOpen, setIsModalOpen] = useState(false); const [editingSection, setEditingSection] = useState | null>(null); const [uploadTarget, setUploadTarget] = useState<{ type: 'main' | 'slide'; index?: number } | null>(null); const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle'); const [isSavingPageSettings, setIsSavingPageSettings] = useState(false); + const [isReorderModalOpen, setIsReorderModalOpen] = useState(false); const [isMediaModalOpen, setIsMediaModalOpen] = useState(false); @@ -440,6 +440,7 @@ export default function PageBuilderPage() { if (res.ok) { setSaveStatus('saved'); + setIsReorderModalOpen(false); setTimeout(() => setSaveStatus('idle'), 3000); } else { setSaveStatus('error'); @@ -497,12 +498,12 @@ export default function PageBuilderPage() { buttonLink: '/shop' } }); - setIsModalOpen(true); + window.scrollTo({ top: 0, behavior: 'smooth' }); }; const openEditModal = (section: PageSection) => { setEditingSection(JSON.parse(JSON.stringify(section))); // deep copy - setIsModalOpen(true); + window.scrollTo({ top: 0, behavior: 'smooth' }); }; const handleTypeChange = (type: string) => { @@ -705,7 +706,7 @@ export default function PageBuilderPage() { }); if (res.ok) { - setIsModalOpen(false); + setEditingSection(null); if (selectedPageId) fetchPageDetails(selectedPageId); } else { const errData = await res.json(); @@ -718,157 +719,33 @@ export default function PageBuilderPage() { return (
+ {/* Global Header */}
-
+

Page Builder (CMS)

+
- Select Page: - - {page && ( - <> - - - Open Live - - - - )} - - - {page && page.slug !== 'home' && ( - - )}
- - {page && ( -
- - - {page.isPublished ? 'Published' : 'Draft'} - -
- )} -
-
- - {sections.length > 0 && ( - - )}
- {pages.length > 0 && ( -
-
-
-

Quick Page Links

-

Open any page directly in the storefront.

-
-
-
- {pages.map((p) => ( -
- - / {p.slug} - - - -
- ))} -
-
- )} {saveStatus === 'saved' && (
@@ -890,149 +767,196 @@ export default function PageBuilderPage() { ))}
) : ( -
-
-

Homepage Blocks list

-
- -
- {sections.length === 0 ? ( -
- -

No content sections in this page yet. Start by adding one!

-
- ) : ( - sections.map((section, idx) => ( -
-
- {/* Index & Order controls */} -
- - - {idx + 1} - - +
+
+ {/* Page Configuration Card */} + {page && ( +
+
+
+
+ + setPage({ ...page, title: e.target.value })} + className="bg-slate-900/50 border border-white/10 text-white rounded-xl px-4 py-2 text-sm focus:outline-none focus:border-cyan-glow/50 transition-colors w-full" + placeholder="Enter page title..." + />
- {/* Section Description */} -
-
- - {section.type} +
+
-

- {getAdminDisplayString( - section.payload?.title - || section.payload?.tagline - || section.payload?.quote - || (section.type?.toUpperCase() === 'ANNOUNCEMENT_BAR' ? section.payload?.slides?.[0] : undefined) - ) || `Block #${section.id}`} -

- {section.type?.toUpperCase() === 'PRODUCTS' && ( -

- Type: {section.payload?.type} • Limit: {section.payload?.limit || 3} products -

- )} - {section.type?.toUpperCase() === 'ANNOUNCEMENT_BAR' && ( -

- Slides: {section.payload?.slides?.length || 0} messages -

- )} + + + {page.isPublished ? 'Published' : 'Draft'} +
- {/* Actions */} -
+
- - + + Preview Live +
+ {page.slug !== 'home' && ( + + )}
- )) +
)} -
-
- )} - {/* Editor Modal */} - {isModalOpen && editingSection && ( -
-
-
-

- - {editingSection.id ? `Edit ${editingSection.type} Block` : 'Create Layout Block'} -

- + +
+
+ + {/* Block Selection Dropdown */} +
+ + +
+
+ +
+ {editingSection ? ( +
+
+
+

+ + {editingSection.id ? 'Edit Block Settings' : 'Create Layout Block'} +

+ {editingSection.id && ( +
+ + Type: {editingSection.type} + + + Block ID: {editingSection.id} + +
+ + Page: {page?.slug || 'Unknown'} + + + Page ID: {page?.id || '-'} + +
+ )} +
+
- {/* Sub-header for Language Tabs */} -
- {['th', 'en', 'ja', 'zh', 'vi', 'ko'].map((lang) => ( - - ))} + {/* Premium Sub-header for Language Tabs */} +
+
+ {['th', 'en', 'ja', 'zh', 'vi', 'ko'].map((lang) => ( + + ))} +
@@ -1264,7 +1188,7 @@ export default function PageBuilderPage() {
+ ) : ( +
+ +

Select a block from the left to edit its content

+
+ )} +
+
+ )} + + {/* Reorder Layout Modal */} + {isReorderModalOpen && ( +
+
+
+

+ + Reorder Layout +

+ +
+ +
+ {sections.length === 0 ? ( +
+ +

No content sections in this page yet.

+
+ ) : ( + sections.map((section, idx) => ( +
+
+ {/* Index & Order controls */} +
+ {idx + 1} +
+ + +
+
+ + {/* Section Description */} +
+ + {section.type} + + {!section.isActive && ( + + Hidden + + )} +

+ {getAdminDisplayString( + section.payload?.title + || section.payload?.tagline + || section.payload?.quote + || (section.type?.toUpperCase() === 'ANNOUNCEMENT_BAR' ? section.payload?.slides?.[0] : undefined) + ) || `Block #${section.id}`} +

+
+
+ + {/* Actions */} +
+ + + +
+
+ )) + )} +
+ +
+ {sections.length > 0 && ( + + )} + +
+
)}