diff --git a/app/assets/stylesheets/article-show.scss b/app/assets/stylesheets/article-show.scss index f021ddf53..1d34436a8 100644 --- a/app/assets/stylesheets/article-show.scss +++ b/app/assets/stylesheets/article-show.scss @@ -898,6 +898,7 @@ article { flex: 1 0 24px; max-width: 24px; margin-left: 5px; + @include themeable(filter, theme-social-icon-invert, invert(0)); } input { cursor: pointer; @@ -974,6 +975,9 @@ article { .dropdown-content { left: 80px !important; bottom: 0px !important; + @media screen and (min-width: 1365px) { + bottom: -155px !important; + } a { background: transparent !important; padding-left: 10px !important; @@ -1159,7 +1163,11 @@ article { right: 0; left: 0; z-index: 100; - background: $tan; + @include themeable( + background, + theme-top-bar-background, + $tan + ); font-size: 1em; text-align: left; min-width: 300px; @@ -1208,37 +1216,109 @@ article { } } - a, label { + a { font-weight: bold; - color: $black; + @include themeable( + color, + theme-color, + $black + ); padding: 12px 18px; width: calc(100% - 36px); display: block; - + font-size: 0.8em; &:hover { - background: $light-gray; - } + @include themeable( + background, + theme-top-bar-background-hover, + $light-gray + ); + } } - label { - width: inherit; - @media screen and (min-width: 400px) { - padding-left: 18px; - font-size: 1em; - } + &.notification-subscriptions-area-row { + padding: 0px; + @include themeable( + border-bottom, + theme-container-border, + 1px solid $medium-gray + ); + } + .notification-subscriptions-area-header { + padding: 12px 6px; + padding-left: 12px; + font-size: 0.7em; + font-weight: bold; + margin-top: -5px; @media screen and (min-width: 500px) { - font-size: 0.92em; + border-top-right-radius: 3px; + border-top-left-radius: 3px; } - @media screen and (min-width: 1365px) { - padding-left: 10px; - font-size: 0.7em; + @include themeable-important( + background, + theme-container-background, + darken($tan, 3%) + ); + @include themeable-important( + border-bottom, + theme-subtle-border, + 1px solid $light-medium-gray + ); + button.notification-subscription-label { + display: inline-block; + width: 90px !important; + margin-left: 5px !important; + text-align: center !important; + float: right !important; + padding: 4px 0px !important; + @include themeable-important( + border, + theme-border, + 1px solid $light-medium-gray + ); + border-radius: 100px; + &.selected { + visibility: hidden !important; + } } } - label.enabled { - cursor: pointer; - } - label.disabled { - pointer-events: none; + button.notification-subscription-label { + width: 100% !important; + opacity: 1.0 !important; + text-align: left; + font-size: 0.8em; + box-sizing: border-box !important; + padding: 13px 4px !important; + padding-left: 13px !important; + margin: auto !important; + cursor: pointer !important; + @include themeable-important( + color, + theme-color, + $black + ); + &:hover { + @include themeable-important( + background, + theme-top-bar-background-hover, + $light-gray + ); + } + .selected-emoji { + visibility: hidden; + margin-left: 4px; + } + &.selected { + .selected-emoji { + display: inline-block; + visibility: visible; + } + @include themeable-important( + color, + theme-color, + $black + ); + } } } } diff --git a/app/controllers/notification_subscriptions_controller.rb b/app/controllers/notification_subscriptions_controller.rb index a263f52ea..6e7282fc8 100644 --- a/app/controllers/notification_subscriptions_controller.rb +++ b/app/controllers/notification_subscriptions_controller.rb @@ -1,9 +1,8 @@ class NotificationSubscriptionsController < ApplicationController def show result = if current_user - NotificationSubscription.exists?(user_id: current_user.id, notifiable_id: params[:notifiable_id], notifiable_type: params[:notifiable_type]) - else - false + NotificationSubscription.where(user_id: current_user.id, notifiable_id: params[:notifiable_id], notifiable_type: params[:notifiable_type]). + first&.to_json(only: %i[config]) || { config: "not_subscribed" } end respond_to do |format| format.json { render json: result } @@ -13,15 +12,17 @@ class NotificationSubscriptionsController < ApplicationController def upsert not_found unless current_user - @notification_subscription = NotificationSubscription.find_or_initialize_by(user_id: current_user.id, notifiable_id: params[:notifiable_id], notifiable_type: params[:notifiable_type].capitalize, config: "all_comments") - if params[:currently_subscribed] == "true" - @notification_subscription.notifiable.update(receive_notifications: false) if current_user_is_author? + @notification_subscription = NotificationSubscription.find_or_initialize_by(user_id: current_user.id, notifiable_id: params[:notifiable_id], notifiable_type: params[:notifiable_type].capitalize) + if params[:config] == "not_subscribed" @notification_subscription.delete - elsif params[:currently_subscribed] == "false" - @notification_subscription.notifiable.update(receive_notifications: true) if current_user_is_author? + @notification_subscription.notifiable.update(receive_notifications: false) if current_user_is_author? + else + @notification_subscription.config = params[:config] || "all_comments" + if params[:config] == "all_comments" && current_user_is_author? + @notification_subscription.notifiable.update(receive_notifications: true) + end @notification_subscription.save! end - result = @notification_subscription.persisted? respond_to do |format| format.json { render json: result } diff --git a/app/javascript/packs/notificationSubscriptionHandler.js b/app/javascript/packs/notificationSubscriptionHandler.js index adadbb4d3..a356ca3a9 100644 --- a/app/javascript/packs/notificationSubscriptionHandler.js +++ b/app/javascript/packs/notificationSubscriptionHandler.js @@ -1,14 +1,14 @@ -const label = document.getElementById('notification-subscription-label'); -const checkbox = document.getElementById('notification-subcription-checkbox'); const subscriptionStatusInput = document.getElementById( 'notification-subscription-status', ); -const notifiableId = document.getElementById( - 'notification-subscription-notifiable-id', -).value; -const notifiableType = document.getElementById( - 'notification-subscription-notifiable-type', -).value; +const {notifiableId} = document.getElementById( + 'notification-subscriptions-area', +).dataset; +const {notifiableType} = document.getElementById( + 'notification-subscriptions-area', +).dataset; + + const userStatus = document .getElementsByTagName('body')[0] .getAttribute('data-user-status'); @@ -24,8 +24,8 @@ if (userStatus === 'logged-in') { }) .then(response => response.json()) .then(result => { - subscriptionStatusInput.value = result; - checkbox.checked = result; + document.getElementById(`notification-subscription-label_${result.config}`).classList.add('selected'); + // checkbox.checked = result; }); } @@ -38,9 +38,12 @@ if (userStatus === 'logged-out') { showModal('notification-subscription'); }; } else { - updateStatus = () => { - checkbox.checked = !checkbox.checked; - + updateStatus = (target) => { + const allButtons = document.getElementsByClassName('notification-subscription-label'); + for(let i = 0; i < allButtons.length; i += 1) { + allButtons[i].classList.remove('selected') + } + target.classList.add('selected'); fetch(`/notification_subscriptions/${notifiableType}/${notifiableId}`, { method: 'POST', headers: { @@ -50,37 +53,29 @@ if (userStatus === 'logged-out') { }, credentials: 'same-origin', body: JSON.stringify({ - currently_subscribed: subscriptionStatusInput.value, + config: target.dataset.payload, // notifiable params are passed via URL }), }) .then(response => response.json()) .then(result => { - subscriptionStatusInput.value = result; - checkbox.checked = result; - - label.classList.remove('enabled'); - label.classList.add('disabled'); - - setTimeout(() => { - label.classList.remove('disabled'); - label.classList.add('enabled'); - }, 1500); }); }; } -label.addEventListener('click', e => { - e.preventDefault(); - updateStatus(); -}); -checkbox.addEventListener('click', e => { - e.preventDefault(); - updateStatus(); -}); +const subscriptionButtons = document.getElementsByClassName('notification-subscription-label'); -checkbox.addEventListener('keydown', e => { - if (e.key === 'Enter') { - updateStatus(); - } -}); +for(let i = 0; i < subscriptionButtons.length; i += 1) { + subscriptionButtons[i].addEventListener('click', e => { + e.preventDefault(); + updateStatus(e.target); + if (typeof sendHapticMessage !== "undefined") { + sendHapticMessage('medium'); + } + }); + subscriptionButtons[i].addEventListener('keydown', e => { + if (e.key === 'Enter') { + updateStatus(e.target); + } + }); +} diff --git a/app/models/notification_subscription.rb b/app/models/notification_subscription.rb index 202ce2a1a..acc39ae8f 100644 --- a/app/models/notification_subscription.rb +++ b/app/models/notification_subscription.rb @@ -3,5 +3,5 @@ class NotificationSubscription < ApplicationRecord belongs_to :notifiable, polymorphic: true validates :notifiable_type, inclusion: { in: %w[Comment Article] } validates :user_id, uniqueness: { scope: %i[notifiable_type notifiable_id] } - validates :config, inclusion: { in: %w[all_comments top_level_comments] } + validates :config, inclusion: { in: %w[all_comments top_level_comments only_author_comments] } end diff --git a/app/services/notifications/new_comment/send.rb b/app/services/notifications/new_comment/send.rb index c435434ab..6845aa93b 100644 --- a/app/services/notifications/new_comment/send.rb +++ b/app/services/notifications/new_comment/send.rb @@ -16,8 +16,10 @@ module Notifications comment_user_ids = comment.ancestors.where(receive_notifications: true).pluck(:user_id) subscribed_user_ids = NotificationSubscription.where(notifiable_id: comment.commentable_id, notifiable_type: "Article", config: "all_comments").pluck(:user_id) top_level_user_ids = NotificationSubscription.where(notifiable_id: comment.commentable_id, notifiable_type: "Article", config: "top_level_comments").pluck(:user_id) if comment.ancestry.blank? + author_subscriber_user_ids = NotificationSubscription.where(notifiable_id: comment.commentable_id, notifiable_type: "Article", config: "only_author_comments").pluck(:user_id) if comment.user_id == comment.commentable.user_id user_ids = (comment_user_ids + subscribed_user_ids).to_set user_ids += top_level_user_ids.to_set if top_level_user_ids + user_ids += author_subscriber_user_ids.to_set if author_subscriber_user_ids json_data = { user: user_data(comment.user), comment: comment_data(comment) @@ -31,7 +33,7 @@ module Notifications json_data: json_data, ) # Be careful with this basic first implementation of push notification. Has dependency of Pusher/iPhone sort of tough to test reliably. - send_push_notifications(user_id, "@#{comment.user.username} replied to you:", comment.title, "/notifications/comments") if User.find_by(id: user_id)&.mobile_comment_notifications + send_push_notifications(user_id, "@#{comment.user.username} re: #{comment.parent_or_root_article.title}", comment.title, "/notifications/comments") if User.find_by(id: user_id)&.mobile_comment_notifications end return unless comment.commentable.organization_id diff --git a/app/views/articles/_actions.html.erb b/app/views/articles/_actions.html.erb index 81a5f5e6d..4aa937735 100644 --- a/app/views/articles/_actions.html.erb +++ b/app/views/articles/_actions.html.erb @@ -30,23 +30,33 @@