diff --git a/admin-spa/src/routes/Settings/Notifications/ChannelConfig.tsx b/admin-spa/src/routes/Settings/Notifications/ChannelConfig.tsx index cf382bd..2e24428 100644 --- a/admin-spa/src/routes/Settings/Notifications/ChannelConfig.tsx +++ b/admin-spa/src/routes/Settings/Notifications/ChannelConfig.tsx @@ -1,4 +1,6 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { api } from '@/lib/api'; import { Dialog, DialogContent, @@ -10,7 +12,8 @@ import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Switch } from '@/components/ui/switch'; -import { ExternalLink } from 'lucide-react'; +import { ExternalLink, Loader2 } from 'lucide-react'; +import { toast } from 'sonner'; import { __ } from '@/lib/i18n'; interface ChannelConfigProps { @@ -71,6 +74,45 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } // Push notification configuration if (channelId === 'push') { + const queryClient = useQueryClient(); + const [settings, setSettings] = useState({ + use_logo: true, + use_product_images: true, + use_gravatar: false, + click_action: '/wp-admin/admin.php?page=woonoow#/orders', + require_interaction: false, + silent: false, + }); + + // Fetch push settings + const { data: pushSettings, isLoading } = useQuery({ + queryKey: ['push-settings'], + queryFn: () => api.get('/notifications/push/settings'), + enabled: open, + }); + + // Update local state when data is fetched + useEffect(() => { + if (pushSettings) { + setSettings(pushSettings); + } + }, [pushSettings]); + + // Save settings mutation + const saveMutation = useMutation({ + mutationFn: async () => { + return api.post('/notifications/push/settings', settings); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['push-settings'] }); + toast.success(__('Push notification settings saved')); + onClose(); + }, + onError: (error: any) => { + toast.error(error?.message || __('Failed to save settings')); + }, + }); + return ( @@ -81,7 +123,12 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } -
+ {isLoading ? ( +
+ +
+ ) : ( +
{/* Branding */}
@@ -93,7 +140,11 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } {__('Display your store logo in push notifications')}

-
@@ -103,7 +154,11 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } {__('Show product images in order notifications')}

- + setSettings({...settings, use_product_images: checked})} + />
@@ -113,7 +168,11 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } {__('Display customer avatar when available')}

- + setSettings({...settings, use_gravatar: checked})} + /> @@ -127,7 +186,8 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } setSettings({...settings, click_action: e.target.value})} />

{__('Where users are redirected when clicking the notification')} @@ -141,7 +201,11 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } {__('Notification stays until user dismisses it')}

- + setSettings({...settings, require_interaction: checked})} + />
@@ -151,7 +215,11 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } {__('Disable notification sound')}

- + setSettings({...settings, silent: checked})} + /> @@ -161,14 +229,23 @@ export default function ChannelConfig({ open, onClose, channelId, channelLabel } 💡 {__('Note: These settings will be saved and applied to all push notifications. Individual templates can override the icon and image.')}

- + + ) + }
- -
diff --git a/includes/Api/NotificationsController.php b/includes/Api/NotificationsController.php index dbee244..e343c3f 100644 --- a/includes/Api/NotificationsController.php +++ b/includes/Api/NotificationsController.php @@ -120,6 +120,24 @@ class NotificationsController { 'permission_callback' => '__return_true', ], ]); + + // GET /woonoow/v1/notifications/push/settings + register_rest_route($this->namespace, '/' . $this->rest_base . '/push/settings', [ + [ + 'methods' => 'GET', + 'callback' => [$this, 'get_push_settings'], + 'permission_callback' => [$this, 'check_permission'], + ], + ]); + + // POST /woonoow/v1/notifications/push/settings + register_rest_route($this->namespace, '/' . $this->rest_base . '/push/settings', [ + [ + 'methods' => 'POST', + 'callback' => [$this, 'update_push_settings'], + 'permission_callback' => [$this, 'check_permission'], + ], + ]); } /** @@ -468,4 +486,50 @@ class NotificationsController { 'message' => __('Unsubscribed from push notifications', 'woonoow'), ], 200); } + + /** + * Get push notification settings + * + * @param WP_REST_Request $request Request object + * @return WP_REST_Response + */ + public function get_push_settings(WP_REST_Request $request) { + $settings = PushNotificationHandler::get_settings(); + + return new WP_REST_Response($settings, 200); + } + + /** + * Update push notification settings + * + * @param WP_REST_Request $request Request object + * @return WP_REST_Response + */ + public function update_push_settings(WP_REST_Request $request) { + $settings = $request->get_json_params(); + + if (empty($settings)) { + return new WP_Error( + 'invalid_settings', + __('Settings data is required', 'woonoow'), + ['status' => 400] + ); + } + + $success = PushNotificationHandler::update_settings($settings); + + if (!$success) { + return new WP_Error( + 'update_failed', + __('Failed to update push notification settings', 'woonoow'), + ['status' => 500] + ); + } + + return new WP_REST_Response([ + 'success' => true, + 'message' => __('Push notification settings updated', 'woonoow'), + 'settings' => PushNotificationHandler::get_settings(), + ], 200); + } } diff --git a/includes/Core/Notifications/PushNotificationHandler.php b/includes/Core/Notifications/PushNotificationHandler.php index f38ee89..967b18d 100644 --- a/includes/Core/Notifications/PushNotificationHandler.php +++ b/includes/Core/Notifications/PushNotificationHandler.php @@ -21,12 +21,80 @@ class PushNotificationHandler { */ const VAPID_KEYS_KEY = 'woonoow_push_vapid_keys'; + /** + * Option key for push settings + */ + const SETTINGS_KEY = 'woonoow_push_settings'; + /** * Initialize push notifications */ public static function init() { // Generate VAPID keys if not exists self::ensure_vapid_keys(); + + // Ensure default settings exist + self::ensure_default_settings(); + } + + /** + * Ensure default push settings exist + * + * @return array + */ + public static function ensure_default_settings() { + $settings = get_option(self::SETTINGS_KEY); + + if (!$settings) { + $settings = self::get_default_settings(); + update_option(self::SETTINGS_KEY, $settings); + } + + return $settings; + } + + /** + * Get default push settings + * + * @return array + */ + public static function get_default_settings() { + return [ + 'use_logo' => true, + 'use_product_images' => true, + 'use_gravatar' => false, + 'click_action' => '/wp-admin/admin.php?page=woonoow#/orders', + 'require_interaction' => false, + 'silent' => false, + ]; + } + + /** + * Get push settings + * + * @return array + */ + public static function get_settings() { + $settings = get_option(self::SETTINGS_KEY); + + if (!$settings) { + $settings = self::get_default_settings(); + } + + return $settings; + } + + /** + * Update push settings + * + * @param array $settings + * @return bool + */ + public static function update_settings($settings) { + $current = self::get_settings(); + $updated = array_merge($current, $settings); + + return update_option(self::SETTINGS_KEY, $updated); } /**