diff --git a/admin-spa/src/routes/Appearance/General.tsx b/admin-spa/src/routes/Appearance/General.tsx index 7f5a154..1bfb7bf 100644 --- a/admin-spa/src/routes/Appearance/General.tsx +++ b/admin-spa/src/routes/Appearance/General.tsx @@ -15,6 +15,7 @@ import { api } from '@/lib/api'; export default function AppearanceGeneral() { const [loading, setLoading] = useState(true); const [spaMode, setSpaMode] = useState<'disabled' | 'checkout_only' | 'full'>('full'); + const [toastPosition, setToastPosition] = useState('top-right'); const [typographyMode, setTypographyMode] = useState<'predefined' | 'custom_google'>('predefined'); const [predefinedPair, setPredefinedPair] = useState('modern'); const [customHeading, setCustomHeading] = useState(''); @@ -44,6 +45,7 @@ export default function AppearanceGeneral() { if (general) { if (general.spa_mode) setSpaMode(general.spa_mode); + if (general.toast_position) setToastPosition(general.toast_position); if (general.typography) { setTypographyMode(general.typography.mode || 'predefined'); setPredefinedPair(general.typography.predefined_pair || 'modern'); @@ -75,6 +77,7 @@ export default function AppearanceGeneral() { try { await api.post('/appearance/general', { spa_mode: spaMode, + toastPosition, typography: { mode: typographyMode, predefined_pair: typographyMode === 'predefined' ? predefinedPair : undefined, @@ -141,6 +144,31 @@ export default function AppearanceGeneral() { + {/* Toast Notifications */} + + + +

+ Choose where toast notifications appear on the screen +

+
+
+ {/* Typography */} {editingAttribute ? __('Edit Attribute') : __('Add Attribute')} + + {editingAttribute ? __('Update attribute information') : __('Create a new product attribute')} +
diff --git a/admin-spa/src/routes/Products/Categories.tsx b/admin-spa/src/routes/Products/Categories.tsx index a5d3650..7df087b 100644 --- a/admin-spa/src/routes/Products/Categories.tsx +++ b/admin-spa/src/routes/Products/Categories.tsx @@ -3,7 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Plus, Pencil, Trash2, Search } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { api } from '@/lib/api'; @@ -194,6 +194,9 @@ export default function ProductCategories() { {editingCategory ? __('Edit Category') : __('Add Category')} + + {editingCategory ? __('Update category information') : __('Create a new product category')} +
diff --git a/admin-spa/src/routes/Products/Tags.tsx b/admin-spa/src/routes/Products/Tags.tsx index 014c125..f576c66 100644 --- a/admin-spa/src/routes/Products/Tags.tsx +++ b/admin-spa/src/routes/Products/Tags.tsx @@ -3,7 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Plus, Pencil, Trash2, Search } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { api } from '@/lib/api'; @@ -192,6 +192,9 @@ export default function ProductTags() { {editingTag ? __('Edit Tag') : __('Add Tag')} + + {editingTag ? __('Update tag information') : __('Create a new product tag')} +
diff --git a/customer-spa/src/App.tsx b/customer-spa/src/App.tsx index bff2b40..f9bb995 100644 --- a/customer-spa/src/App.tsx +++ b/customer-spa/src/App.tsx @@ -46,8 +46,15 @@ const getThemeConfig = () => { }; }; +// 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 ( @@ -77,8 +84,8 @@ function App() { - {/* Toast notifications */} - + {/* Toast notifications - position from settings */} + ); diff --git a/customer-spa/src/pages/Wishlist.tsx b/customer-spa/src/pages/Wishlist.tsx index 6d3ff1d..fe24050 100644 --- a/customer-spa/src/pages/Wishlist.tsx +++ b/customer-spa/src/pages/Wishlist.tsx @@ -6,7 +6,7 @@ import { useCartStore } from '@/lib/cart/store'; import { Button } from '@/components/ui/button'; import { toast } from 'sonner'; import { apiClient } from '@/lib/api/client'; -import { formatPrice } from '@/lib/utils'; +import { formatPrice } from '@/lib/currency'; interface ProductData { id: number; diff --git a/includes/Admin/AppearanceController.php b/includes/Admin/AppearanceController.php index f0ea9c3..87a56b0 100644 --- a/includes/Admin/AppearanceController.php +++ b/includes/Admin/AppearanceController.php @@ -82,6 +82,7 @@ class AppearanceController { $general_data = [ 'spa_mode' => sanitize_text_field($request->get_param('spaMode')), + 'toast_position' => sanitize_text_field($request->get_param('toastPosition') ?? 'top-right'), 'typography' => [ 'mode' => sanitize_text_field($request->get_param('typography')['mode'] ?? 'predefined'), 'predefined_pair' => sanitize_text_field($request->get_param('typography')['predefined_pair'] ?? 'modern'), @@ -377,6 +378,7 @@ class AppearanceController { return [ 'general' => [ 'spa_mode' => 'full', + 'toast_position' => 'top-right', 'typography' => [ 'mode' => 'predefined', 'predefined_pair' => 'modern',