diff --git a/acp/wpn_acp_module.php b/acp/wpn_acp_module.php index dbad44e..4015c4b 100644 --- a/acp/wpn_acp_module.php +++ b/acp/wpn_acp_module.php @@ -108,6 +108,7 @@ public function display_settings() 'WEBPUSH_VAPID_PRIVATE' => $this->config['wpn_webpush_vapid_private'] ? self::MASKED_PRIVATE_KEY : '', 'S_WEBPUSH_DROPDOWN_SUBSCRIBE' => $this->config['wpn_webpush_dropdown_subscribe'], 'S_WEBPUSH_METHOD_ENABLED' => $this->config['wpn_webpush_method_enabled'], + 'S_WEBPUSH_POPUP_PROMPT' => $this->config['wpn_webpush_popup_prompt'], 'U_ACTION' => $this->u_action, ]); @@ -133,6 +134,7 @@ public function save_settings() 'wpn_webpush_vapid_private'=> ['validate' => 'string:25:255', 'lang' => 'WEBPUSH_VAPID_PRIVATE'], 'wpn_webpush_dropdown_subscribe' => ['validate' => 'bool'], 'wpn_webpush_method_enabled' => ['validate' => 'bool'], + 'wpn_webpush_popup_prompt' => ['validate' => 'bool'], ]; // Do not validate and update private key field if the content is ******** and the key was already set diff --git a/adm/style/wpn_acp_settings.html b/adm/style/wpn_acp_settings.html index cdd3add..f1fa5af 100644 --- a/adm/style/wpn_acp_settings.html +++ b/adm/style/wpn_acp_settings.html @@ -39,6 +39,11 @@

{{ lang('WARNING') }}

+
+

{{ lang('WEBPUSH_POPUP_PROMPT_EXPLAIN') }}
+
+
+
  diff --git a/language/en/webpushnotifications_module_acp.php b/language/en/webpushnotifications_module_acp.php index 1da78c4..bf4edbe 100644 --- a/language/en/webpushnotifications_module_acp.php +++ b/language/en/webpushnotifications_module_acp.php @@ -50,5 +50,7 @@ 'WEBPUSH_METHOD_ENABLED_EXPLAIN'=> 'When this setting is enabled, users who have also enabled and allowed browser notifications will start receiving them automatically. They can visit the UCP Notification settings to disable any unwanted notifications.

If this setting is disabled, users will not receive any notifications, even if they have enabled push notifications, until they visit the UCP Notification settings to allow the specific notifications they wish to receive.', 'WEBPUSH_DROPDOWN_SUBSCRIBE' => 'Show web push settings in the notification dropdown', 'WEBPUSH_DROPDOWN_SUBSCRIBE_EXPLAIN'=> 'Show or hide the “Enable Web Push” toggle switch in the notification dropdown. This allows users to easily enable or disable push notifications from any page of the forum.', + 'WEBPUSH_POPUP_PROMPT' => 'Show popup prompt for unsubscribed members', + 'WEBPUSH_POPUP_PROMPT_EXPLAIN' => 'Display a popup message asking registered members if they want to receive push notifications. The popup will only appear to members who are not currently subscribed and have not previously declined.', 'WEBPUSH_INSECURE_SERVER_ERROR' => 'This board is not using a secure SSL/HTTPS protocol, which is required for enabling web push notifications. Alternatively, the server environment might be misconfigured. Ensure that the HTTPS and HEADER_CLIENT_PROTO server environment variables are correctly configured.', ]); diff --git a/language/en/webpushnotifications_module_ucp.php b/language/en/webpushnotifications_module_ucp.php index 9b7223f..31ed884 100644 --- a/language/en/webpushnotifications_module_ucp.php +++ b/language/en/webpushnotifications_module_ucp.php @@ -49,4 +49,8 @@ 'NOTIFY_WEBPUSH_DROPDOWN_TITLE' => 'Visit notifications settings to set your preferred push notifications.', 'NOTIFY_WEBPUSH_DENIED' => 'You have denied notifications from this site. To enable push notifications, allow notifications from this site in your browser settings.', 'NOTIFY_WEBPUSH_DISABLED' => 'Push notifications not supported', + 'NOTIFY_WEBPUSH_POPUP_TITLE' => 'Allow browser notifications?', + '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_DECLINE' => 'Decline', ]); diff --git a/language/ru/webpushnotifications_module_acp.php b/language/ru/webpushnotifications_module_acp.php index dd94ea6..5232e58 100644 --- a/language/ru/webpushnotifications_module_acp.php +++ b/language/ru/webpushnotifications_module_acp.php @@ -50,5 +50,7 @@ 'WEBPUSH_METHOD_ENABLED_EXPLAIN'=> 'Если включено, то пользователи, подписавшиеся на браузерные push—уведомления, будут автоматически получать все их типы. Если отключено, то пользователи не будут получать браузерные push—уведомления до тех пор, пока хотя бы один их тип не выбран.

Отключить нежелательные или выбрать нужные типы браузерных push—уведомлений можно в настройках уведомлений в Личном разделе.', 'WEBPUSH_DROPDOWN_SUBSCRIBE' => 'Показать кнопку «Подписаться» в выпадающем меню уведомлений', 'WEBPUSH_DROPDOWN_SUBSCRIBE_EXPLAIN'=> 'Включить или отключить отображение кнопки «Подписаться» в выпадающем списке уведомлений. Если включено, то пользователи смогут подписываться на браузерные push-уведомления с любой страницы конференции.', + 'WEBPUSH_POPUP_PROMPT' => 'Показывать всплывающее приглашение', + 'WEBPUSH_POPUP_PROMPT_EXPLAIN' => 'Показывать всплывающее сообщение зарегистрированным пользователям с приглашением подписаться на браузерные уведомления данной конференции. Сообщение будет показано только тем зарегистрированным пользователям, которые не подписаны на браузерные уведомления и ранее не отклоняли такое приглашение.', 'WEBPUSH_INSECURE_SERVER_ERROR' => 'На данной конференции не применяется защищённый протокол SSL/HTTPS, без которого использование браузерных push—уведомлений невозможно, либо соответствующие переменные серверного окружения неверно сконфигурированы. Убедитесь, что значения переменных серверного окружения HTTPS и/или HEADER_CLIENT_PROTO заданы верно.', ]); diff --git a/language/ru/webpushnotifications_module_ucp.php b/language/ru/webpushnotifications_module_ucp.php index b0fe007..6b08e2b 100644 --- a/language/ru/webpushnotifications_module_ucp.php +++ b/language/ru/webpushnotifications_module_ucp.php @@ -49,4 +49,8 @@ 'NOTIFY_WEBPUSH_DROPDOWN_TITLE' => 'Посетите настройки уведомлений, чтобы установить предпочтительные типы браузерных уведомлений.', 'NOTIFY_WEBPUSH_DENIED' => 'Вы запретили браузерные уведомления для даного сайта. Для того, чтобы подписаться, необходимо их разрешить в настройках браузера.', 'NOTIFY_WEBPUSH_DISABLED' => 'Не поддерживается', + 'NOTIFY_WEBPUSH_POPUP_TITLE' => 'Включить браузерные уведомления?', + 'NOTIFY_WEBPUSH_POPUP_MESSAGE' => 'Браузерные уведомления позволяют быстро получать информацию о новых ответах, личных сообщениях и других активностях на данной конференции. Функцию можно отключить или включить в любое время в настройках уведомлений в Личном разделе.', + 'NOTIFY_WEBPUSH_POPUP_ALLOW' => 'Включить', + 'NOTIFY_WEBPUSH_POPUP_DECLINE' => 'Отклонить', ]); diff --git a/migrations/add_popup_prompt.php b/migrations/add_popup_prompt.php new file mode 100644 index 0000000..98ba3cd --- /dev/null +++ b/migrations/add_popup_prompt.php @@ -0,0 +1,33 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + */ + +namespace phpbb\webpushnotifications\migrations; + +use phpbb\db\migration\migration; + +class add_popup_prompt extends migration +{ + public function effectively_installed() + { + return $this->config->offsetExists('wpn_webpush_popup_prompt'); + } + + public static function depends_on() + { + return ['\phpbb\webpushnotifications\migrations\add_acp_configs']; + } + + public function update_data() + { + return [ + ['config.add', ['wpn_webpush_popup_prompt', 0]], + ]; + } +} diff --git a/notification/method/webpush.php b/notification/method/webpush.php index c1756c4..8f371ed 100644 --- a/notification/method/webpush.php +++ b/notification/method/webpush.php @@ -400,6 +400,7 @@ public function get_ucp_template_data(helper $controller_helper, form_helper $fo '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, ]; } diff --git a/styles/all/template/event/overall_header_head_append.html b/styles/all/template/event/overall_header_head_append.html index 00c8172..5e26b0b 100644 --- a/styles/all/template/event/overall_header_head_append.html +++ b/styles/all/template/event/overall_header_head_append.html @@ -7,4 +7,5 @@ {% if NOTIFICATIONS_WEBPUSH_ENABLE %} {% include '@phpbb_webpushnotifications/ucp_notifications_webpush.html' %} + {% include '@phpbb_webpushnotifications/webpush_popup.html' %} {% endif %} diff --git a/styles/all/template/webpush.js b/styles/all/template/webpush.js index 685f066..0968dff 100644 --- a/styles/all/template/webpush.js +++ b/styles/all/template/webpush.js @@ -62,6 +62,7 @@ function PhpbbWebpush() { unsubscribeButton.addEventListener('click', unsubscribeButtonHandler); updateButtonState(); + initPopupPrompt(); }) .catch(error => { console.info(error); @@ -116,6 +117,75 @@ function PhpbbWebpush() { } } + /** + * Initialize popup prompt + */ + function initPopupPrompt() { + const popup = document.getElementById('wpn_popup_prompt'); + if (!popup || Notification.permission === 'denied') { + return; + } + + // Check if user declined on this browser + if (getDeclined() === 'true') { + return; + } + + // Check if this browser already has a subscription + navigator.serviceWorker.getRegistration(serviceWorkerUrl) + .then(registration => { + if (typeof registration === 'undefined') { + showPopup(popup); + return; + } + + registration.pushManager.getSubscription() + .then(subscription => { + if (!isValidSubscription(subscription)) { + showPopup(popup); + } + }); + }); + } + + /** + * Show popup with event handlers + */ + function showPopup(popup) { + setTimeout(() => { + popup.style.display = 'flex'; + }, 1000); + + const allowBtn = document.getElementById('wpn_popup_allow'); + const declineBtn = document.getElementById('wpn_popup_decline'); + const overlay = document.getElementById('wpn_popup_prompt'); + + if (allowBtn) { + allowBtn.addEventListener('click', (event) => { + event.stopPropagation(); + popup.style.display = 'none'; + subscribeButtonHandler({ preventDefault: () => {} }); + }); + } + + if (declineBtn) { + declineBtn.addEventListener('click', (event) => { + event.stopPropagation(); + popup.style.display = 'none'; + setDeclined(); + }); + } + + if (overlay) { + overlay.addEventListener('click', (event) => { + if (event.target === overlay) { + popup.style.display = 'none'; + setDeclined(); + } + }); + } + } + /** * Check whether subscription is valid * @@ -258,6 +328,11 @@ function PhpbbWebpush() { if ('form_tokens' in response) { updateFormTokens(response.form_tokens); } + resetDeclined(); + const popup = document.getElementById('wpn_popup_prompt'); + if (popup) { + popup.style.display = 'none'; + } } } @@ -303,6 +378,16 @@ function PhpbbWebpush() { return outputArray; } + + function setDeclined() { + localStorage.setItem('wpn_popup_declined', 'true'); + } + function getDeclined() { + return localStorage.getItem('wpn_popup_declined'); + } + function resetDeclined() { + localStorage.removeItem('wpn_popup_declined'); + } } function domReady(callBack) { diff --git a/styles/all/template/webpush_popup.html b/styles/all/template/webpush_popup.html new file mode 100644 index 0000000..ef893c6 --- /dev/null +++ b/styles/all/template/webpush_popup.html @@ -0,0 +1,14 @@ +{% if S_WEBPUSH_POPUP_PROMPT %} + +{% endif %} diff --git a/styles/all/theme/phpbb_wpn.css b/styles/all/theme/phpbb_wpn.css index 415d0b2..53d8913 100644 --- a/styles/all/theme/phpbb_wpn.css +++ b/styles/all/theme/phpbb_wpn.css @@ -51,3 +51,100 @@ margin-top: 8px; } } + +.wpn-popup-overlay { + background: rgba(0, 0, 0, 0.5); + position: fixed; + z-index: 9999; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: flex-start; + width: 100%; + height: 100%; + padding-top: 20px; +} + +.wpn-popup-container { + background: #ffffff; + border-radius: 8px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); + width: 90%; + max-width: 500px; + animation: wpnSlideDown 0.3s ease-out; +} + +@keyframes wpnSlideDown { + from { + opacity: 0; + transform: translateY(-50px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.wpn-popup-content { + padding: 24px; +} + +.wpn-popup-title { + font-size: 18px; + font-weight: 600; + color: #333333; + margin: 0 0 12px; +} + +.wpn-popup-message { + font-size: 14px; + line-height: 1.5; + color: #666666; + margin: 0 0 20px; +} + +.wpn-popup-buttons { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.wpn-popup-btn { + font-size: 14px; + font-weight: 500; + border: none; + border-radius: 4px; + padding: 10px 20px; + cursor: pointer; + transition: all 0.2s; +} + +.wpn-popup-btn-allow { + background: #0066cc; + color: #ffffff; +} + +.wpn-popup-btn-allow:hover { + background: #0052a3; +} + +.wpn-popup-btn-decline { + background: #f0f0f0; + color: #666666; +} + +.wpn-popup-btn-decline:hover { + background: #e0e0e0; +} + +@media (max-width: 500px) { + .wpn-popup-buttons { + flex-direction: column-reverse; + } + + .wpn-popup-btn { + width: 100%; + } +} diff --git a/tests/functional/functional_test.php b/tests/functional/functional_test.php index 6527126..76b08aa 100644 --- a/tests/functional/functional_test.php +++ b/tests/functional/functional_test.php @@ -140,6 +140,28 @@ public function test_manifest() $this->assertEquals(json_encode($expected), self::get_content()); } + public function test_popup_prompt() + { + $this->login(); + $this->admin_login(); + + $this->add_lang_ext('phpbb/webpushnotifications', 'webpushnotifications_module_ucp'); + + // Assert popup is not present by default + $crawler = self::request('GET', 'index.php'); + $this->assertCount(0, $crawler->filter('#wpn_popup_prompt')); + + $this->set_acp_option('wpn_webpush_popup_prompt', 1); + + // Assert popup is present when enabled + $crawler = self::request('GET', 'index.php'); + $this->assertCount(1, $crawler->filter('#wpn_popup_prompt')); + $this->assertContainsLang('NOTIFY_WEBPUSH_POPUP_TITLE', $crawler->filter('.wpn-popup-title')->text()); + $this->assertContainsLang('NOTIFY_WEBPUSH_POPUP_MESSAGE', $crawler->filter('.wpn-popup-message')->text()); + $this->assertContainsLang('NOTIFY_WEBPUSH_POPUP_ALLOW', $crawler->filter('#wpn_popup_allow')->text()); + $this->assertContainsLang('NOTIFY_WEBPUSH_POPUP_DECLINE', $crawler->filter('#wpn_popup_decline')->text()); + } + protected function set_acp_option($option, $value) { $crawler = self::request('GET', 'adm/index.php?i=-phpbb-webpushnotifications-acp-wpn_acp_module&mode=webpush&sid=' . $this->sid);