import React, { useState, useEffect } from 'react'; import { SettingsLayout } from '@/routes/Settings/components/SettingsLayout'; import { SettingsCard } from '@/routes/Settings/components/SettingsCard'; import { SettingsSection } from '@/routes/Settings/components/SettingsSection'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Slider } from '@/components/ui/slider'; import { Input } from '@/components/ui/input'; import { AlertCircle } from 'lucide-react'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { toast } from 'sonner'; import { api } from '@/lib/api'; interface WordPressPage { id: number; title: string; slug: string; } export default function AppearanceGeneral() { const [loading, setLoading] = useState(true); const [spaMode, setSpaMode] = useState<'disabled' | 'checkout_only' | 'full'>('full'); const [spaPage, setSpaPage] = useState(0); const [availablePages, setAvailablePages] = useState([]); const [toastPosition, setToastPosition] = useState('top-right'); const [typographyMode, setTypographyMode] = useState<'predefined' | 'custom_google'>('predefined'); const [predefinedPair, setPredefinedPair] = useState('modern'); const [customHeading, setCustomHeading] = useState(''); const [customBody, setCustomBody] = useState(''); const [fontScale, setFontScale] = useState([1.0]); const [containerWidth, setContainerWidth] = useState<'boxed' | 'fullwidth'>('boxed'); const fontPairs = { modern: { name: 'Modern & Clean', fonts: 'Inter' }, editorial: { name: 'Editorial', fonts: 'Playfair Display + Source Sans' }, friendly: { name: 'Friendly', fonts: 'Poppins + Open Sans' }, elegant: { name: 'Elegant', fonts: 'Cormorant + Lato' }, }; const [colors, setColors] = useState({ primary: '#1a1a1a', secondary: '#6b7280', accent: '#3b82f6', text: '#111827', background: '#ffffff', gradientStart: '#9333ea', // purple-600 defaults gradientEnd: '#3b82f6', // blue-500 defaults }); useEffect(() => { const loadSettings = async () => { try { // Load appearance settings const response = await api.get('/appearance/settings'); const general = response.data?.general; if (general) { if (general.spa_mode) setSpaMode(general.spa_mode); if (general.spa_page) setSpaPage(general.spa_page || 0); if (general.toast_position) setToastPosition(general.toast_position); if (general.typography) { setTypographyMode(general.typography.mode || 'predefined'); setPredefinedPair(general.typography.predefined_pair || 'modern'); setCustomHeading(general.typography.custom?.heading || ''); setCustomBody(general.typography.custom?.body || ''); setFontScale([general.typography.scale || 1.0]); } if (general.container_width) { setContainerWidth(general.container_width); } if (general.colors) { setColors({ primary: general.colors.primary || '#1a1a1a', secondary: general.colors.secondary || '#6b7280', accent: general.colors.accent || '#3b82f6', text: general.colors.text || '#111827', background: general.colors.background || '#ffffff', gradientStart: general.colors.gradientStart || '#9333ea', gradientEnd: general.colors.gradientEnd || '#3b82f6', }); } } // Load available pages const pagesResponse = await api.get('/pages/list'); console.log('Pages API response:', pagesResponse); if (pagesResponse.data) { console.log('Pages loaded:', pagesResponse.data); setAvailablePages(pagesResponse.data); } else { console.warn('No pages data in response:', pagesResponse); } } catch (error) { console.error('Failed to load settings:', error); console.error('Error details:', error); } finally { setLoading(false); } }; loadSettings(); }, []); const handleSave = async () => { try { await api.post('/appearance/general', { spaMode, spaPage, toastPosition, typography: { mode: typographyMode, predefined_pair: typographyMode === 'predefined' ? predefinedPair : undefined, custom: typographyMode === 'custom_google' ? { heading: customHeading, body: customBody } : undefined, scale: fontScale[0], }, containerWidth, colors, }); toast.success('General settings saved successfully'); } catch (error) { console.error('Save error:', error); toast.error('Failed to save settings'); } }; return ( {/* SPA Mode */} setSpaMode(value)}>

SPA never loads (use WordPress default pages)

SPA starts at cart page (cart → checkout → thank you → account)

SPA starts at shop page (shop → product → cart → checkout → account)

{/* SPA Page */}
This page will render the full SPA to the body element with no theme interference. The SPA Mode above determines the initial route (shop or cart). React Router handles navigation via /#/ routing.

Full SPA: Loads shop page initially
Checkout Only: Loads cart page initially
Tip: You can set this page as your homepage in Settings → Reading

setContainerWidth(value)}>

Content centered with max-width (recommended)

Content fills entire screen width

Default width for all pages (can be overridden per page)

{/* Toast Notifications */}

Choose where toast notifications appear on the screen

{/* Typography */} setTypographyMode(value)}>

Self-hosted fonts, no external requests

{typographyMode === 'predefined' && ( )}
Using Google Fonts may not be GDPR compliant {typographyMode === 'custom_google' && (
setCustomHeading(e.target.value)} /> setCustomBody(e.target.value)} />
)}

Adjust the overall size of all text (0.8x - 1.2x)

{/* Colors */}
{Object.entries(colors).map(([key, value]) => (
setColors({ ...colors, [key]: e.target.value })} className="w-20 h-10 cursor-pointer" /> setColors({ ...colors, [key]: e.target.value })} className="flex-1 font-mono" />
))}
); }