From 5a87e7f77d5f8c61befcb7982c842f2a72bb5cc9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 29 Jun 2026 19:24:57 -0400 Subject: [PATCH] x --- apps/admin/src/App.tsx | 11 +- apps/admin/src/components/Sidebar.tsx | 59 +++++- apps/admin/src/pages/ContentSettingsPage.tsx | 127 ++++++++++++ apps/admin/src/pages/MediaLibraryPage.tsx | 107 +++++++++- apps/admin/src/pages/PaymentSettingsPage.tsx | 121 +++++++++++ apps/admin/src/pages/StoreSettingsPage.tsx | 128 ++++++++++++ .../admin/src/pages/SystemMaintenancePage.tsx | 89 ++++++++ apps/admin/src/pages/SystemSettingsPage.tsx | 100 ++++++++- apps/admin/src/pages/ThemeSettingsPage.tsx | 192 ++++++++++++++++++ .../migration.sql | 4 + apps/backend/prisma/schema.prisma | 3 + .../48bee660-d52a-4613-bb7d-0e046812381e.png | Bin 0 -> 2157577 bytes .../9d735eb4-03e7-4549-95fc-3c131a2318d6.jpeg | Bin 0 -> 523154 bytes apps/backend/src/routes/settings.ts | 17 +- apps/spa/src/components/DynamicHero.tsx | 4 +- .../src/components/DynamicPageRenderer.tsx | 56 ++--- apps/spa/src/components/ScrollReveal.tsx | 52 +++++ apps/spa/src/components/ThemeInjector.tsx | 45 ++-- apps/spa/src/hooks/useScrollReveal.ts | 37 ++++ apps/spa/src/index.css | 16 -- packages/types/index.ts | 3 + 21 files changed, 1083 insertions(+), 88 deletions(-) create mode 100644 apps/admin/src/pages/ContentSettingsPage.tsx create mode 100644 apps/admin/src/pages/PaymentSettingsPage.tsx create mode 100644 apps/admin/src/pages/StoreSettingsPage.tsx create mode 100644 apps/admin/src/pages/SystemMaintenancePage.tsx create mode 100644 apps/admin/src/pages/ThemeSettingsPage.tsx create mode 100644 apps/backend/prisma/migrations/20260629230554_add_scroll_reveal_settings/migration.sql create mode 100644 apps/backend/public/uploads/48bee660-d52a-4613-bb7d-0e046812381e.png create mode 100644 apps/backend/public/uploads/9d735eb4-03e7-4549-95fc-3c131a2318d6.jpeg create mode 100644 apps/spa/src/components/ScrollReveal.tsx create mode 100644 apps/spa/src/hooks/useScrollReveal.ts diff --git a/apps/admin/src/App.tsx b/apps/admin/src/App.tsx index d87c1e0..9236ed2 100644 --- a/apps/admin/src/App.tsx +++ b/apps/admin/src/App.tsx @@ -13,6 +13,11 @@ import ProtectedRoute from './components/ProtectedRoute' import OrdersPage from './pages/OrdersPage' import OrderDetailPage from './pages/OrderDetailPage' import SystemSettingsPage from './pages/SystemSettingsPage' +import StoreSettingsPage from './pages/StoreSettingsPage' +import PaymentSettingsPage from './pages/PaymentSettingsPage' +import ThemeSettingsPage from './pages/ThemeSettingsPage' +import ContentSettingsPage from './pages/ContentSettingsPage' +import SystemMaintenancePage from './pages/SystemMaintenancePage' import MenuManagerPage from './pages/MenuManagerPage' import NewsletterSubscribersPage from './pages/NewsletterSubscribersPage' import ArticlesPage from './pages/ArticlesPage' @@ -61,7 +66,11 @@ function App() { } /> } /> } /> - } /> + } /> + } /> + } /> + } /> + } /> } /> } /> } /> diff --git a/apps/admin/src/components/Sidebar.tsx b/apps/admin/src/components/Sidebar.tsx index f549d7e..1bd83a5 100644 --- a/apps/admin/src/components/Sidebar.tsx +++ b/apps/admin/src/components/Sidebar.tsx @@ -1,4 +1,5 @@ -import { NavLink, useNavigate } from 'react-router-dom' +import { useState } from 'react' +import { NavLink, useNavigate, useLocation } from 'react-router-dom' import { LayoutDashboard, Package, @@ -18,10 +19,16 @@ import { Globe2, Users, Image as ImageIcon, - MessageSquare + MessageSquare, + Store, + CreditCard, + Palette, + FileText, + Wrench, + ChevronDown, } from 'lucide-react' -const MENU_ITEMS = [ +const MAIN_MENU = [ { icon: LayoutDashboard, label: 'Dashboard', to: '/' }, { icon: Tags, label: 'Categories', to: '/categories' }, { icon: Package, label: 'Products', to: '/products' }, @@ -49,11 +56,21 @@ const MENU_ITEMS = [ { icon: Layers, label: 'Menu Manager', to: '/menu-manager' }, { icon: Users, label: 'Subscribers', to: '/subscribers' }, { icon: MessageSquare, label: 'Contact Messages', to: '/contacts' }, - { icon: Settings, label: 'Settings', to: '/settings' }, +] + +const SETTINGS_MENU = [ + { icon: Store, label: 'Store Settings', to: '/settings' }, + { icon: CreditCard, label: 'Payment & Shipping',to: '/settings/payments' }, + { icon: Palette, label: 'Theme & Design', to: '/settings/theme' }, + { icon: FileText, label: 'Content', to: '/settings/content' }, + { icon: Wrench, label: 'System', to: '/settings/system' }, ] export default function Sidebar() { const navigate = useNavigate() + const location = useLocation() + const isInSettings = location.pathname.startsWith('/settings') + const [settingsOpen, setSettingsOpen] = useState(isInSettings) const handleLogout = () => { localStorage.removeItem('homaroma_admin_token') @@ -72,12 +89,12 @@ export default function Sidebar() { {/* Navigation — scrollable */} {/* User / Bottom */} diff --git a/apps/admin/src/pages/ContentSettingsPage.tsx b/apps/admin/src/pages/ContentSettingsPage.tsx new file mode 100644 index 0000000..19367f8 --- /dev/null +++ b/apps/admin/src/pages/ContentSettingsPage.tsx @@ -0,0 +1,127 @@ +import { useState, useEffect } from 'react' +import { API_BASE, type StoreSettings } from '@homaroma/types' +import { Save, Loader2 } from 'lucide-react' + +export default function ContentSettingsPage() { + const [loading, setLoading] = useState(true) + const [saving, setSaving] = useState(false) + + const [footerDescription, setFooterDescription] = useState('') + const [footerSupportHeading, setFooterSupportHeading] = useState('') + const [footerCopyrightText, setFooterCopyrightText] = useState('') + const [newsletterTitle, setNewsletterTitle] = useState('') + const [newsletterDescription, setNewsletterDescription] = useState('') + const [newsletterPlaceholder, setNewsletterPlaceholder] = useState('') + const [newsletterButtonText, setNewsletterButtonText] = useState('') + + useEffect(() => { + fetch(`${API_BASE}/settings`) + .then(r => r.json()) + .then((data: StoreSettings) => { + setFooterDescription(data.footerDescription || '') + setFooterSupportHeading(data.footerSupportHeading || '') + setFooterCopyrightText(data.footerCopyrightText || '') + setNewsletterTitle(data.newsletterTitle || '') + setNewsletterDescription(data.newsletterDescription || '') + setNewsletterPlaceholder(data.newsletterPlaceholder || '') + setNewsletterButtonText(data.newsletterButtonText || '') + }) + .catch(console.error) + .finally(() => setLoading(false)) + }, []) + + const handleSave = async (e: React.FormEvent) => { + e.preventDefault() + setSaving(true) + try { + const res = await fetch(`${API_BASE}/settings`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + footerDescription, footerSupportHeading, footerCopyrightText, + newsletterTitle, newsletterDescription, newsletterPlaceholder, newsletterButtonText, + }), + }) + if (res.ok) alert('Saved successfully!') + } catch { alert('Failed to save') } finally { setSaving(false) } + } + + if (loading) return
+ + return ( +
+
+

Content Settings

+

Newsletter copy and footer text displayed across the website.

+
+ +
+ {/* Footer Content */} +
+
+
📄
+

Footer Content

+
+ +
+
+ +