diff --git a/apps/admin/src/pages/PageBuilderPage.tsx b/apps/admin/src/pages/PageBuilderPage.tsx index 45950fb..9c94452 100644 --- a/apps/admin/src/pages/PageBuilderPage.tsx +++ b/apps/admin/src/pages/PageBuilderPage.tsx @@ -18,6 +18,7 @@ import { ExternalLink } from 'lucide-react'; import { API_BASE, type Page, type PageSection, type Category } from '@homaroma/types'; +import { getAdminDisplayString } from '../utils/localization'; interface Scent { id: number; @@ -37,6 +38,103 @@ export default function PageBuilderPage() { const [uploadTarget, setUploadTarget] = useState<{ type: 'main' | 'slide'; index?: number } | null>(null); const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle'); + const [editingLang, setEditingLang] = useState('th'); + + // Helper to read localized string safely + const getLocalizedValue = (payload: any, field: string) => { + if (!payload || payload[field] === undefined) return ''; + const val = payload[field]; + if (typeof val === 'string') { + return editingLang === 'th' ? val : ''; + } + return val[editingLang] || ''; + }; + + // Helper to update localized string + const updateLocalizedValue = (field: string, value: string) => { + setEditingSection(prev => { + if (!prev) return null; + const payload = prev.payload || {}; + const currentVal = payload[field]; + + let newVal; + if (typeof currentVal === 'string') { + newVal = { th: currentVal, [editingLang]: value }; + } else { + newVal = { ...(currentVal || {}), [editingLang]: value }; + } + + return { + ...prev, + payload: { + ...payload, + [field]: newVal + } + }; + }); + }; + + const getLocalizedSlideValue = (slide: any, field: string) => { + if (!slide || slide[field] === undefined) return ''; + const val = slide[field]; + if (typeof val === 'string') { + return editingLang === 'th' ? val : ''; + } + return val[editingLang] || ''; + }; + + const updateLocalizedSlideValue = (idx: number, field: string, value: string) => { + setEditingSection(prev => { + if (!prev) return null; + const currentSlides = [...(prev.payload?.slides || [])]; + const slide = currentSlides[idx]; + const currentVal = slide[field]; + + let newVal; + if (typeof currentVal === 'string') { + newVal = { th: currentVal, [editingLang]: value }; + } else { + newVal = { ...(currentVal || {}), [editingLang]: value }; + } + + currentSlides[idx] = { ...slide, [field]: newVal }; + + return { + ...prev, + payload: { ...(prev.payload || {}), slides: currentSlides } + }; + }); + }; + + const getLocalizedAnnouncementSlide = (slide: any) => { + if (typeof slide === 'string') { + return editingLang === 'th' ? slide : ''; + } + return slide?.[editingLang] || ''; + }; + + const updateLocalizedAnnouncementSlide = (idx: number, value: string) => { + setEditingSection(prev => { + if (!prev) return null; + const currentSlides = [...(prev.payload?.slides || [])]; + const currentVal = currentSlides[idx]; + + let newVal; + if (typeof currentVal === 'string') { + newVal = { th: currentVal, [editingLang]: value }; + } else { + newVal = { ...(currentVal || {}), [editingLang]: value }; + } + + currentSlides[idx] = newVal; + return { + ...prev, + payload: { ...(prev.payload || {}), slides: currentSlides } + }; + }); + }; + + const [pages, setPages] = useState([]); const [selectedPageId, setSelectedPageId] = useState(null); const [isPageModalOpen, setIsPageModalOpen] = useState(false); @@ -640,7 +738,7 @@ export default function PageBuilderPage() { )}

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

{section.type === 'PRODUCTS' && (

@@ -693,13 +791,14 @@ export default function PageBuilderPage() { {/* Editor Modal */} {isModalOpen && editingSection && (

-
+

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

+ {/* Sub-header for Language Tabs */} +
+ {['th', 'en', 'ja', 'zh', 'vi', 'ko'].map((lang) => ( + + ))} +
+
{!editingSection.id && (
@@ -769,13 +886,8 @@ export default function PageBuilderPage() { - setEditingSection({ - ...editingSection, - payload: { ...(editingSection.payload || {}), title: e.target.value } - }) - } + value={getLocalizedValue(editingSection.payload, 'title')} + onChange={(e) => updateLocalizedValue('title', e.target.value)} className="admin-input w-full" />

Use [brackets] for golden accent serif text.

@@ -828,13 +940,8 @@ export default function PageBuilderPage() { - setEditingSection({ - ...editingSection, - payload: { ...(editingSection.payload || {}), buttonText: e.target.value } - }) - } + value={getLocalizedValue(editingSection.payload, 'buttonText')} + onChange={(e) => updateLocalizedValue('buttonText', e.target.value)} className="admin-input w-full" />
@@ -842,13 +949,8 @@ export default function PageBuilderPage() { - setEditingSection({ - ...editingSection, - payload: { ...(editingSection.payload || {}), buttonLink: e.target.value } - }) - } + value={getLocalizedValue(editingSection.payload, 'buttonLink')} + onChange={(e) => updateLocalizedValue('buttonLink', e.target.value)} className="admin-input w-full" />
@@ -859,13 +961,8 @@ export default function PageBuilderPage() {