diff --git a/config/wpn_ucp.yml b/config/wpn_ucp.yml index f340196..eb39d21 100644 --- a/config/wpn_ucp.yml +++ b/config/wpn_ucp.yml @@ -13,3 +13,7 @@ phpbb_webpushnotifications_ucp_push_subscribe_controller: phpbb_webpushnotifications_ucp_push_unsubscribe_controller: path: /push/unsubscribe defaults: { _controller: phpbb.wpn.ucp.controller.webpush:unsubscribe } + +phpbb_webpushnotifications_ucp_push_toggle_popup_controller: + path: /push/toggle-popup + defaults: { _controller: phpbb.wpn.ucp.controller.webpush:toggle_popup } diff --git a/language/en/webpushnotifications_module_ucp.php b/language/en/webpushnotifications_module_ucp.php index 8a481e3..709f0ea 100644 --- a/language/en/webpushnotifications_module_ucp.php +++ b/language/en/webpushnotifications_module_ucp.php @@ -53,4 +53,6 @@ 'NOTIFY_WEBPUSH_POPUP_MESSAGE' => 'We would like to send you browser notifications for replies, private messages, and relevant forum activity. Optional — you can manage these settings at any time.', 'NOTIFY_WEBPUSH_POPUP_ALLOW' => 'Allow', 'NOTIFY_WEBPUSH_POPUP_DENY' => 'Deny', + 'NOTIFY_WEBPUSH_POPUP_DISABLE' => 'Disable web push notification prompts', + 'NOTIFY_WEBPUSH_POPUP_DISABLE_EXPLAIN' => 'Turn this on to stop us from asking you to enable web push notifications on any of your devices. If you disable web push notification prompts, we won’t be able to alert you if you ever become unsubscribed.', ]); diff --git a/language/ru/webpushnotifications_module_ucp.php b/language/ru/webpushnotifications_module_ucp.php index c670739..e9c9b3b 100644 --- a/language/ru/webpushnotifications_module_ucp.php +++ b/language/ru/webpushnotifications_module_ucp.php @@ -53,4 +53,6 @@ 'NOTIFY_WEBPUSH_POPUP_MESSAGE' => 'Браузерные уведомления позволяют быстро получать информацию о новых ответах, личных сообщениях и других активностях на данной конференции. Функцию можно отключить или включить в любое время в настройках уведомлений в Личном разделе.', 'NOTIFY_WEBPUSH_POPUP_ALLOW' => 'Включить', 'NOTIFY_WEBPUSH_POPUP_DENY' => 'Отклонить', + 'NOTIFY_WEBPUSH_POPUP_DISABLE' => 'Disable web push notification prompts', + 'NOTIFY_WEBPUSH_POPUP_DISABLE_EXPLAIN' => 'Turn this on to stop us from asking you to enable web push notifications on any of your devices. If you disable web push notification prompts, we won’t be able to alert you if you ever become unsubscribed.', ]); diff --git a/migrations/add_user_popup_preference.php b/migrations/add_user_popup_preference.php new file mode 100644 index 0000000..d6649d1 --- /dev/null +++ b/migrations/add_user_popup_preference.php @@ -0,0 +1,48 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + */ + +namespace phpbb\webpushnotifications\migrations; + +use phpbb\db\migration\migration; + +class add_user_popup_preference extends migration +{ + public function effectively_installed() + { + return $this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_wpn_popup_disabled'); + } + + public static function depends_on() + { + return ['\phpbb\webpushnotifications\migrations\add_popup_prompt']; + } + + public function update_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'users' => [ + 'user_wpn_popup_disabled' => ['BOOL', 0], + ], + ], + ]; + } + + public function revert_schema() + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'users' => [ + 'user_wpn_popup_disabled', + ], + ], + ]; + } +} diff --git a/notification/method/webpush.php b/notification/method/webpush.php index b8eee4f..162c637 100644 --- a/notification/method/webpush.php +++ b/notification/method/webpush.php @@ -390,11 +390,13 @@ public function get_ucp_template_data(helper $controller_helper, form_helper $fo 'NOTIFICATIONS_WEBPUSH_ENABLE' => ($this->config['load_notifications'] && $this->config['allow_board_notifications'] && $this->config['wpn_webpush_dropdown_subscribe']) || stripos($this->user->page['page'], 'notification_options'), 'U_WEBPUSH_SUBSCRIBE' => $controller_helper->route('phpbb_webpushnotifications_ucp_push_subscribe_controller'), 'U_WEBPUSH_UNSUBSCRIBE' => $controller_helper->route('phpbb_webpushnotifications_ucp_push_unsubscribe_controller'), + 'U_WEBPUSH_TOGGLE_POPUP' => $controller_helper->route('phpbb_webpushnotifications_ucp_push_toggle_popup_controller'), 'VAPID_PUBLIC_KEY' => $this->config['wpn_webpush_vapid_public'], 'U_WEBPUSH_WORKER_URL' => $controller_helper->route('phpbb_webpushnotifications_ucp_push_worker_controller'), 'SUBSCRIPTIONS' => $subscriptions, 'WEBPUSH_FORM_TOKENS' => $form_helper->get_form_tokens(\phpbb\webpushnotifications\ucp\controller\webpush::FORM_TOKEN_UCP), - 'S_WEBPUSH_POPUP_PROMPT' => $this->config['wpn_webpush_popup_prompt'] && $this->user->id() != ANONYMOUS && $this->user->data['user_type'] != USER_IGNORE, + 'S_WEBPUSH_POPUP_PROMPT' => $this->config['wpn_webpush_popup_prompt'] && $this->user->id() != ANONYMOUS && $this->user->data['user_type'] != USER_IGNORE && !($this->user->data['user_wpn_popup_disabled'] ?? 0), + 'S_WEBPUSH_POPUP_DISABLED' => $this->user->data['user_wpn_popup_disabled'] ?? 0, ]; } diff --git a/styles/all/template/ucp_notifications_webpush.html b/styles/all/template/ucp_notifications_webpush.html index 35a0298..2967f1f 100644 --- a/styles/all/template/ucp_notifications_webpush.html +++ b/styles/all/template/ucp_notifications_webpush.html @@ -3,6 +3,7 @@ serviceWorkerUrl: '{{ U_WEBPUSH_WORKER_URL }}', subscribeUrl: '{{ U_WEBPUSH_SUBSCRIBE }}', unsubscribeUrl: '{{ U_WEBPUSH_UNSUBSCRIBE }}', + togglePopupUrl: '{{ U_WEBPUSH_TOGGLE_POPUP }}', ajaxErrorTitle: '{{ lang_js('AJAX_ERROR_TITLE') }}', vapidPublicKey: '{{ VAPID_PUBLIC_KEY }}', formTokens: { diff --git a/styles/all/template/webpush.js b/styles/all/template/webpush.js index 3481bb9..440406c 100644 --- a/styles/all/template/webpush.js +++ b/styles/all/template/webpush.js @@ -33,6 +33,15 @@ function PhpbbWebpush() { /** @type {HTMLElement} Unsubscribe button */ let unsubscribeButton; + /** @type {HTMLElement} Toggle popup button */ + let togglePopupButton; + + /** @type {string} URL to toggle popup prompt preference */ + let togglePopupUrl = ''; + + /** @type {function} Escape key handler for popup */ + let popupEscapeHandler; + /** * Init function for phpBB Web Push * @type {array} options @@ -41,6 +50,7 @@ function PhpbbWebpush() { serviceWorkerUrl = options.serviceWorkerUrl; subscribeUrl = options.subscribeUrl; unsubscribeUrl = options.unsubscribeUrl; + togglePopupUrl = options.togglePopupUrl; this.formTokens = options.formTokens; subscriptions = options.subscriptions; ajaxErrorTitle = options.ajaxErrorTitle; @@ -48,6 +58,12 @@ function PhpbbWebpush() { subscribeButton = document.querySelector('#subscribe_webpush'); unsubscribeButton = document.querySelector('#unsubscribe_webpush'); + togglePopupButton = document.querySelector('#toggle_popup_prompt'); + + // Set up toggle popup button handler if it exists (on UCP settings page) + if (togglePopupButton) { + togglePopupButton.addEventListener('click', togglePopupHandler); + } // Service workers are only supported in secure context if (window.isSecureContext !== true) { @@ -163,7 +179,7 @@ function PhpbbWebpush() { if (allowBtn) { allowBtn.addEventListener('click', (event) => { event.stopPropagation(); - popup.style.display = 'none'; + hidePopup(popup); subscribeButtonHandler(event).catch(error => { console.error('Subscription handler error:', error); }); @@ -173,7 +189,7 @@ function PhpbbWebpush() { if (denyBtn) { denyBtn.addEventListener('click', (event) => { event.stopPropagation(); - popup.style.display = 'none'; + hidePopup(popup); promptDenied.set(); }); } @@ -181,11 +197,32 @@ function PhpbbWebpush() { if (overlay) { overlay.addEventListener('click', (event) => { if (event.target === overlay) { - popup.style.display = 'none'; + hidePopup(popup); promptDenied.set(); } }); + + popupEscapeHandler = (event) => { + if (event.key === 'Escape') { + hidePopup(popup); + promptDenied.set(); + } + }; + + document.addEventListener('keydown', popupEscapeHandler); + } + } + + /** + * Hide popup + * @param popup + */ + function hidePopup(popup) { + if (popup) { + popup.style.display = 'none'; } + document.removeEventListener('keydown', popupEscapeHandler); + popupEscapeHandler = null; } /** @@ -282,10 +319,7 @@ function PhpbbWebpush() { }); } catch (error) { promptDenied.set(); // deny the prompt on error to prevent repeated prompting - const popup = document.getElementById('wpn_popup_prompt'); - if (popup) { - popup.style.display = 'none'; - } + hidePopup(document.getElementById('wpn_popup_prompt')); console.error('Push subscription error:', error); phpbb.alert(subscribeButton.getAttribute('data-l-err'), error.message || subscribeButton.getAttribute('data-l-unsupported')); } finally { @@ -331,6 +365,55 @@ function PhpbbWebpush() { }); } + /** + * Handler for toggle popup prompt button + * + * @param {Object} event Toggle button push event + */ + function togglePopupHandler(event) { + event.preventDefault(); + + const loadingIndicator = phpbb.loadingIndicator(); + const formData = new FormData(); + formData.append('form_token', phpbb.webpush.formTokens.formToken); + formData.append('creation_time', phpbb.webpush.formTokens.creationTime.toString()); + + fetch(togglePopupUrl, { + method: 'POST', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + }, + body: formData, + }) + .then(response => response.json()) + .then(data => { + loadingIndicator.fadeOut(phpbb.alertTime); + if (data.success) { + // Update toggle icon based on new state + const button = document.getElementById('toggle_popup_prompt'); + if (button) { + const icon = button.querySelector('i'); + if (icon) { + if (data.disabled) { + icon.classList.remove('fa-toggle-off'); + icon.classList.add('fa-toggle-on'); + } else { + icon.classList.remove('fa-toggle-on'); + icon.classList.add('fa-toggle-off'); + } + } + } + if ('form_tokens' in data) { + updateFormTokens(data.form_tokens); + } + } + }) + .catch(error => { + loadingIndicator.fadeOut(phpbb.alertTime); + phpbb.alert(ajaxErrorTitle, error); + }); + } + /** * Handle subscribe response * @@ -343,10 +426,7 @@ function PhpbbWebpush() { updateFormTokens(response.form_tokens); } promptDenied.remove(); - const popup = document.getElementById('wpn_popup_prompt'); - if (popup) { - popup.style.display = 'none'; - } + hidePopup(document.getElementById('wpn_popup_prompt')); } } diff --git a/styles/all/template/webpush_popup.html b/styles/all/template/webpush_popup.html index deb9133..cff48bd 100644 --- a/styles/all/template/webpush_popup.html +++ b/styles/all/template/webpush_popup.html @@ -1,15 +1,15 @@ {% if S_WEBPUSH_POPUP_PROMPT %} -