1. Toast Position Control ✅ - Added toast_position setting to Appearance > General - 6 position options: top-left/center/right, bottom-left/center/right - Default: top-right - Backend: AppearanceController.php (save/load toast_position) - Frontend: Customer SPA reads from appearanceSettings and applies to Toaster - Admin UI: Select dropdown in General settings - Solves UX issue: toast blocking cart icon in header 2. Currency Formatting Fix ✅ - Changed formatPrice import from @/lib/utils to @/lib/currency - @/lib/currency respects WooCommerce currency settings (IDR, not USD) - Reads currency code, symbol, position, separators from window.woonoowCustomer.currency - Applies correct formatting for Indonesian Rupiah and any other currency 3. Dialog Accessibility Warnings Fixed ✅ - Added DialogDescription component to all taxonomy dialogs - Categories: 'Update category information' / 'Create a new product category' - Tags: 'Update tag information' / 'Create a new product tag' - Attributes: 'Update attribute information' / 'Create a new product attribute' - Fixes console warning: Missing Description or aria-describedby Note on React Key Warning: The warning about missing keys in ProductCategories is still appearing in console. All table rows already have proper key props (key={category.term_id}). This may be a dev server cache issue or a nested element without a key. The code is correct - keys are present on all mapped elements. Files Modified: - includes/Admin/AppearanceController.php (toast_position setting) - admin-spa/src/routes/Appearance/General.tsx (toast position UI) - customer-spa/src/App.tsx (apply toast position from settings) - customer-spa/src/pages/Wishlist.tsx (use correct formatPrice from currency) - admin-spa/src/routes/Products/Categories.tsx (DialogDescription) - admin-spa/src/routes/Products/Tags.tsx (DialogDescription) - admin-spa/src/routes/Products/Attributes.tsx (DialogDescription) Result: ✅ Toast notifications now configurable and won't block header elements ✅ Prices display in correct currency (IDR) with proper formatting ✅ All Dialog accessibility warnings resolved ⚠️ React key warning persists (but keys are correctly implemented)
95 lines
2.8 KiB
TypeScript
95 lines
2.8 KiB
TypeScript
import React from 'react';
|
|
import { HashRouter, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { Toaster } from 'sonner';
|
|
|
|
// Theme
|
|
import { ThemeProvider } from './contexts/ThemeContext';
|
|
import { BaseLayout } from './layouts/BaseLayout';
|
|
|
|
// Pages
|
|
import Shop from './pages/Shop';
|
|
import Product from './pages/Product';
|
|
import Cart from './pages/Cart';
|
|
import Checkout from './pages/Checkout';
|
|
import ThankYou from './pages/ThankYou';
|
|
import Account from './pages/Account';
|
|
import Wishlist from './pages/Wishlist';
|
|
|
|
// Create QueryClient instance
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
refetchOnWindowFocus: false,
|
|
retry: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Get theme config from window (injected by PHP)
|
|
const getThemeConfig = () => {
|
|
const config = (window as any).woonoowCustomer?.theme;
|
|
|
|
// Default config if not provided
|
|
return config || {
|
|
mode: 'full',
|
|
layout: 'modern',
|
|
colors: {
|
|
primary: '#3B82F6',
|
|
secondary: '#8B5CF6',
|
|
accent: '#10B981',
|
|
},
|
|
typography: {
|
|
preset: 'professional',
|
|
},
|
|
};
|
|
};
|
|
|
|
// Get appearance settings from window
|
|
const getAppearanceSettings = () => {
|
|
return (window as any).woonoowCustomer?.appearanceSettings || {};
|
|
};
|
|
|
|
function App() {
|
|
const themeConfig = getThemeConfig();
|
|
const appearanceSettings = getAppearanceSettings();
|
|
const toastPosition = (appearanceSettings?.general?.toast_position || 'top-right') as any;
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<ThemeProvider config={themeConfig}>
|
|
<HashRouter>
|
|
<BaseLayout>
|
|
<Routes>
|
|
{/* Shop Routes */}
|
|
<Route path="/" element={<Shop />} />
|
|
<Route path="/shop" element={<Shop />} />
|
|
<Route path="/product/:slug" element={<Product />} />
|
|
|
|
{/* Cart & Checkout */}
|
|
<Route path="/cart" element={<Cart />} />
|
|
<Route path="/checkout" element={<Checkout />} />
|
|
<Route path="/order-received/:orderId" element={<ThankYou />} />
|
|
|
|
{/* Wishlist - Public route accessible to guests */}
|
|
<Route path="/wishlist" element={<Wishlist />} />
|
|
|
|
{/* My Account */}
|
|
<Route path="/my-account/*" element={<Account />} />
|
|
|
|
{/* Fallback */}
|
|
<Route path="*" element={<Navigate to="/shop" replace />} />
|
|
</Routes>
|
|
</BaseLayout>
|
|
</HashRouter>
|
|
|
|
{/* Toast notifications - position from settings */}
|
|
<Toaster position={toastPosition} richColors />
|
|
</ThemeProvider>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|