diff --git a/admin-spa/src/routes/Appearance/General.tsx b/admin-spa/src/routes/Appearance/General.tsx index 1bfb7bf..8752f26 100644 --- a/admin-spa/src/routes/Appearance/General.tsx +++ b/admin-spa/src/routes/Appearance/General.tsx @@ -12,9 +12,22 @@ 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 [spaPages, setSpaPages] = useState({ + shop: 0, + cart: 0, + checkout: 0, + account: 0, + }); + const [availablePages, setAvailablePages] = useState([]); const [toastPosition, setToastPosition] = useState('top-right'); const [typographyMode, setTypographyMode] = useState<'predefined' | 'custom_google'>('predefined'); const [predefinedPair, setPredefinedPair] = useState('modern'); @@ -40,11 +53,20 @@ export default function AppearanceGeneral() { 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_pages) { + setSpaPages({ + shop: general.spa_pages.shop || 0, + cart: general.spa_pages.cart || 0, + checkout: general.spa_pages.checkout || 0, + account: general.spa_pages.account || 0, + }); + } if (general.toast_position) setToastPosition(general.toast_position); if (general.typography) { setTypographyMode(general.typography.mode || 'predefined'); @@ -63,6 +85,12 @@ export default function AppearanceGeneral() { }); } } + + // Load available pages + const pagesResponse = await api.get('/pages/list'); + if (pagesResponse.data?.data) { + setAvailablePages(pagesResponse.data.data); + } } catch (error) { console.error('Failed to load settings:', error); } finally { @@ -76,7 +104,8 @@ export default function AppearanceGeneral() { const handleSave = async () => { try { await api.post('/appearance/general', { - spa_mode: spaMode, + spaMode, + spaPages, toastPosition, typography: { mode: typographyMode, @@ -144,6 +173,98 @@ export default function AppearanceGeneral() { + {/* SPA Pages */} + +
+ + + + These pages will render directly to the body element with no theme interference. + This is the recommended approach for a clean SPA experience. + + + + + + + + + + + + + + + + + + +
+
+ {/* Toast Notifications */} 'GET', + 'callback' => [__CLASS__, 'get_pages_list'], + 'permission_callback' => [__CLASS__, 'check_permission'], + ]); } public static function check_permission() { @@ -377,6 +384,30 @@ class AppearanceController { return $sanitized; } + /** + * Get list of WordPress pages for page selector + */ + public static function get_pages_list(WP_REST_Request $request) { + $pages = get_pages([ + 'post_status' => 'publish', + 'sort_column' => 'post_title', + 'sort_order' => 'ASC', + ]); + + $pages_list = array_map(function($page) { + return [ + 'id' => $page->ID, + 'title' => $page->post_title, + 'slug' => $page->post_name, + ]; + }, $pages); + + return new WP_REST_Response([ + 'success' => true, + 'data' => $pages_list, + ], 200); + } + /** * Get default settings structure */