[deploy] UserSubscription liquid tag update & re-enable JS (#9082)

This commit is contained in:
Alex 2020-07-06 09:26:40 -04:00 committed by GitHub
parent 9af9a489e5
commit f86b8a55a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 243 additions and 57 deletions

View file

@ -13,73 +13,117 @@ class UserSubscriptionTag < LiquidTagBase
// Hiding/showing elements
// ***************************************
const subscriptionSignedIn = document.getElementById('subscription-signed-in');
const subscriptionSignedOut = document.getElementById('subscription-signed-out');
const responseMessage = document.getElementById('response-message');
const subscriberAppleAuth = document.getElementById('subscriber-apple-auth');
const confirmationModal = document.getElementById('user-subscription-confirmation-modal');
const profileImageContainer = document.getElementById('profile-images');
const subscriberImageContainer = document.querySelector('.ltag__user-subscription-tag__subscriber-profile-image');
function clearSubscriptionArea() {
subscriptionSignedIn.classList.add("hidden");
subscriptionSignedOut.classList.add("hidden");
responseMessage.classList.add("hidden");
subscriberAppleAuth.classList.add("hidden");
const subscriptionSignedIn = document.getElementById('subscription-signed-in');
if (subscriptionSignedIn) {
subscriptionSignedIn.classList.add("hidden");
}
const subscriptionSignedOut = document.getElementById('subscription-signed-out');
if (subscriptionSignedOut) {
subscriptionSignedOut.classList.add("hidden");
}
const responseMessage = document.getElementById('response-message');
if (responseMessage) {
responseMessage.classList.add("hidden");
}
const subscriberAppleAuth = document.getElementById('subscriber-apple-auth');
if (subscriberAppleAuth) {
subscriberAppleAuth.classList.add("hidden");
}
hideConfirmationModal();
}
function showSignedIn() {
clearSubscriptionArea();
const subscriptionSignedIn = document.getElementById('subscription-signed-in');
if (subscriptionSignedIn) {
subscriptionSignedIn.classList.remove("hidden");
}
subscriptionSignedIn.classList.remove("hidden");
profileImageContainer.classList.remove("signed-out");
const profileImages = document.getElementById('profile-images');
if (profileImages) {
profileImages.classList.remove("signed-out");
profileImages.classList.add("signed-in");
}
}
function showSignedOut() {
clearSubscriptionArea();
subscriptionSignedOut.classList.remove("hidden");
const subscriptionSignedOut = document.getElementById('subscription-signed-out');
if (subscriptionSignedOut) {
subscriptionSignedOut.classList.remove("hidden");
}
const profileImages = document.getElementById('profile-images');
if (profileImages) {
profileImages.classList.remove("signed-in");
profileImages.classList.add("signed-out");
}
const subscriberProfileImage = document.querySelector('.ltag__user-subscription-tag__subscriber-profile-image');
if (subscriberProfileImage) {
subscriberProfileImage.classList.add("hidden");
}
}
function showResponseMessage(noticeType, msg) {
clearSubscriptionArea();
responseMessage.classList.remove("hidden");
responseMessage.classList.add(`crayons-notice--${noticeType}`);
responseMessage.textContent = msg;
const responseMessage = document.getElementById('response-message');
if (responseMessage) {
responseMessage.classList.remove("hidden");
responseMessage.classList.add(`crayons-notice--${noticeType}`);
responseMessage.textContent = msg;
}
}
function showAppleAuthMessage() {
clearSubscriptionArea();
subscriberAppleAuth.classList.remove("hidden");
const subscriber = userData();
if (subscriber) {
updateProfileImages('.ltag__user-subscription-tag__subscriber-profile-image', subscriber);
}
const subscriberAppleAuth = document.getElementById('subscriber-apple-auth');
if (subscriberAppleAuth) {
subscriberAppleAuth.classList.remove("hidden");
}
}
function showSubscribed() {
updateSubscriberData();
const authorUsername = document.getElementById('user-subscription-tag').dataset.authorUsername;
const authorUsername = document.getElementById('user-subscription-tag')?.dataset.authorUsername;
const alreadySubscribedMsg = `You are already subscribed.`;
showResponseMessage('success', alreadySubscribedMsg);
}
function showConfirmationModal() {
confirmationModal.classList.remove("hidden");
const confirmationModal = document.getElementById('user-subscription-confirmation-modal');
if (confirmationModal) {
confirmationModal.classList.remove("hidden");
}
}
function hideConfirmationModal() {
confirmationModal.classList.add("hidden");
const confirmationModal = document.getElementById('user-subscription-confirmation-modal');
if (confirmationModal) {
confirmationModal.classList.add("hidden");
}
}
// Updating DOM elements
// ***************************************
function updateSubscriberData() {
const subscriber = userData();
if (subscriber) {
if (subscriber.email) {
updateElementsTextContent('.ltag__user-subscription-tag__subscriber-email', subscriber.email);
updateProfileImages('.ltag__user-subscription-tag__subscriber-profile-image', subscriber);
}
updateProfileImages('.ltag__user-subscription-tag__subscriber-profile-image', subscriber);
}
function updateElementsTextContent(identifier, value) {
@ -102,29 +146,42 @@ class UserSubscriptionTag < LiquidTagBase
// Adding event listeners for 'click'
// ***************************************
function addSignInClickHandler() {
document.getElementById('sign-in-btn').addEventListener('click', function(e) {
if (typeof showModal !== 'undefined') {
const signInBtn = document.getElementById('sign-in-btn');
if (signInBtn && typeof showModal !== 'undefined') {
signInBtn.addEventListener('click', function(e) {
showModal('email_signup');
}
});
});
}
}
function addConfirmationModalClickHandlers() {
document.getElementById('subscribe-btn').addEventListener('click', function(e) {
showConfirmationModal();
});
const subscribeBtn = document.getElementById('subscribe-btn');
if (subscribeBtn) {
subscribeBtn.addEventListener('click', function(e) {
showConfirmationModal();
});
}
document.getElementById('cancel-btn').addEventListener('click', function(e) {
hideConfirmationModal();
});
const cancelBtn = document.getElementById('cancel-btn');
if (cancelBtn) {
cancelBtn.addEventListener('click', function(e) {
hideConfirmationModal();
});
}
document.getElementById('close-confirmation-modal').addEventListener('click', function(e) {
hideConfirmationModal();
});
const closeConfirmationModal = document.getElementById('close-confirmation-modal');
if (closeConfirmationModal) {
closeConfirmationModal.addEventListener('click', function(e) {
hideConfirmationModal();
});
}
document.getElementById('confirmation-btn').addEventListener('click', function(e) {
handleSubscription();
});
const confirmationModal = document.getElementById('confirmation-btn')
if (confirmationModal) {
confirmationModal.addEventListener('click', function(e) {
handleSubscription();
});
}
}
// API calls
@ -136,7 +193,9 @@ class UserSubscriptionTag < LiquidTagBase
'Content-Type': 'application/json',
}
const articleId = document.getElementById('article-body').dataset.articleId;
const articleBody = document.getElementById('article-body');
const articleId = (articleBody ? articleBody.dataset.articleId : null);
const subscriber = userData();
const body = JSON.stringify(
{
@ -159,7 +218,8 @@ class UserSubscriptionTag < LiquidTagBase
}
function fetchIsSubscribed() {
const articleId = document.getElementById('article-body').dataset.articleId;
const articleBody = document.getElementById('article-body');
const articleId = (articleBody ? articleBody.dataset.articleId : null);
const params = new URLSearchParams({
source_type: 'Article',
@ -190,7 +250,8 @@ class UserSubscriptionTag < LiquidTagBase
function handleSubscription() {
submitSubscription().then(function(response) {
if (response.success) {
const authorUsername = document.getElementById('user-subscription-tag').dataset.authorUsername;
const userSubscriptionTag = document.getElementById('user-subscription-tag');
const authorUsername = (userSubscriptionTag ? userSubscriptionTag.dataset.authorUsername : null);
const successMsg = `You are now subscribed and may receive emails from ${authorUsername}`;
showResponseMessage('success', successMsg);
} else {
@ -202,7 +263,7 @@ class UserSubscriptionTag < LiquidTagBase
function checkIfSubscribed() {
fetchIsSubscribed().then(function(response) {
const subscriber = userData();
const isSubscriberAuthedWithApple = subscriber.email.endsWith('@privaterelay.appleid.com');
const isSubscriberAuthedWithApple = (subscriber.email ? subscriber.email.endsWith('@privaterelay.appleid.com') : false);
if (response.is_subscribed) {
showSubscribed();
@ -218,8 +279,6 @@ class UserSubscriptionTag < LiquidTagBase
if (isUserSignedIn()) {
showSignedIn();
addConfirmationModalClickHandlers();
profileImageContainer.classList.remove("signed-out");
profileImageContainer.classList.add("signed-in");
// We need access to some DOM elements (i.e. csrf token, article id, userData, etc.)
document.addEventListener('DOMContentLoaded', function() {
@ -228,9 +287,6 @@ class UserSubscriptionTag < LiquidTagBase
} else {
showSignedOut();
addSignInClickHandler();
profileImageContainer.classList.remove("signed-in");
profileImageContainer.classList.add("signed-out");
subscriberImageContainer.classList.add("hidden");
}
JAVASCRIPT

View file

@ -254,6 +254,6 @@
<%== PollTag.script %>
<%== RunkitTag.script %>
<%== TweetTag.script %>
<%#== UserSubscriptionTag.script %>
<%== UserSubscriptionTag.script %>
</script>
<% end %>

View file

@ -43,7 +43,7 @@
</div>
<div class="ltag__user-subscription-tag__apple-auth fs-s hidden" id="subscriber-apple-auth">
<button disabled class="crayons-btn" id="subscribe-btn">Subscribe</button>
<button disabled class="crayons-btn" id="apple-subscribe-btn">Subscribe</button>
<div class="fs-s" id="apple-auth-message">
Hey, there! It looks like when you created your DEV account you signed
up with Apple using a private relay email address. If you'd like to
@ -71,9 +71,8 @@
</header>
<div class="crayons-modal__box__body">
<p id="confirmation-text" class="fs-base mb-4 mt-0">
You'll share your email address
<span class="ltag__user-subscription-tag__subscriber-email"></span>
with
You'll share your email address<span class="ltag__user-subscription-tag__subscriber-email"></span>,
username, name, and DEV profile URL with
<span class="ltag__user-subscription-tag__author-username fw-medium"><%= author_username %></span>.
Once you do this, you cannot undo this.
<p>

View file

@ -0,0 +1,131 @@
require "rails_helper"
RSpec.describe UserSubscriptionTag, type: :liquid_tag do
setup { Liquid::Template.register_tag("user_subscription", described_class) }
let(:subscriber) { create(:user) }
let(:author) { create(:user, :super_admin) } # TODO: (Alex Smith) - update roles before release
let(:article_with_user_subscription_tag) { create(:article, :with_user_subscription_tag_role_user, with_user_subscription_tag: true) }
context "when rendering" do
it "renders default data correctly" do
source = create(:article, user: author)
liquid_tag_options = { source: source, user: source.user }
cta_text = "Some sweet CTA text"
liquid_tag = Liquid::Template.parse("{% user_subscription #{cta_text} %}", liquid_tag_options).render
expect(liquid_tag).to include(CGI.escapeHTML(cta_text))
expect(liquid_tag).to include(CGI.escapeHTML(author.username))
expect(liquid_tag).to include(CGI.escapeHTML(author.profile_image_90))
end
it "displays signed out view by default", type: :system, js: true do
sign_in author
visit "/new" # Preview behaves differently - we don't load liquid tag scripts
fill_in "article_body_markdown", with: "{% user_subscription Some sweet CTA text %}"
page.execute_script("window.scrollTo(0, -100000)")
find("button", text: /\APreview\z/).click
expect(page).to have_css("#subscription-signed-in", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :hidden)
expect(page).to have_css("#response-message", visible: :hidden)
expect(page).to have_css("#subscription-signed-out", visible: :visible)
expect(page).to have_css("img.ltag__user-subscription-tag__author-profile-image[src='#{author.profile_image_90}']")
end
end
context "when signed in", type: :system, js: true do
before do
sign_in subscriber
visit article_with_user_subscription_tag.path
end
it "shows the signed in UX" do
expect(page).to have_css("#subscription-signed-out", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :hidden)
expect(page).to have_css("#response-message", visible: :hidden)
expect(page).to have_css("#subscription-signed-in", visible: :visible)
expect(page).to have_css("img.ltag__user-subscription-tag__subscriber-profile-image[src='#{subscriber.profile_image_90}']")
end
it "asks the user to confirm their subscription" do
expect(page).to have_css("#user-subscription-confirmation-modal", visible: :hidden)
click_button("Subscribe", id: "subscribe-btn")
expect(page).to have_css("#user-subscription-confirmation-modal", visible: :visible)
end
it "displays a sucess mesage when a subscription is created" do
expect(page).to have_css("#subscription-signed-out", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :hidden)
expect(page).to have_css("#response-message", visible: :hidden)
expect(page).to have_css("#subscription-signed-in", visible: :visible)
click_button("Subscribe", id: "subscribe-btn")
click_button("Confirm subscription", id: "confirmation-btn")
expect(page).to have_css("#subscription-signed-in", visible: :hidden)
expect(page).to have_css("#response-message.crayons-notice--success", visible: :visible)
within "#response-message" do
expect(page).to have_text("You are now subscribed")
end
end
it "displays errors when there's an error creating a subscription" do
# Create a subscription so it causes an error by already being subscribed
create(:user_subscription, subscriber_id: subscriber.id, subscriber_email: subscriber.email, author_id: article_with_user_subscription_tag.user_id, user_subscription_sourceable: article_with_user_subscription_tag)
expect(page).to have_css("#subscription-signed-out", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :hidden)
expect(page).to have_css("#response-message", visible: :hidden)
expect(page).to have_css("#subscription-signed-in", visible: :visible)
click_button("Subscribe", id: "subscribe-btn")
click_button("Confirm subscription", id: "confirmation-btn")
expect(page).to have_css("#subscription-signed-in", visible: :hidden)
expect(page).to have_css("#response-message.crayons-notice--danger", visible: :visible)
within "#response-message" do
expect(page).to have_text("Subscriber has already been taken")
end
end
it "tells the user they're already subscribed by default if they're already subscribed" do
create(:user_subscription, subscriber_id: subscriber.id, subscriber_email: subscriber.email, author_id: article_with_user_subscription_tag.user_id, user_subscription_sourceable: article_with_user_subscription_tag)
visit article_with_user_subscription_tag.path
expect(page).to have_css("#subscription-signed-out", visible: :hidden)
expect(page).to have_css("#subscription-signed-in", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :hidden)
expect(page).to have_css("#response-message.crayons-notice--success", visible: :visible)
within "#response-message" do
expect(page).to have_text("You are already subscribed.")
end
end
end
context "when signed out", type: :sytem, js: true do
before { visit article_with_user_subscription_tag.path }
it "prompts a user to sign in when they're signed out", type: :system, js: true do
expect(page).to have_css("#subscription-signed-in", visible: :hidden)
expect(page).to have_css("#response-message", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :hidden)
expect(page).to have_css("#subscription-signed-out", visible: :visible)
end
end
# TODO: [@thepracticaldev/delightful]: re-enable this once email confirmation
# is re-enabled and confirm it isn't flaky.
xcontext "when a user has an Apple private relay email address", type: :system, js: true do
it "prompts the user to update their email address" do
allow(subscriber).to receive(:email).and_return("test@privaterelay.appleid.com")
sign_in subscriber
visit article_with_user_subscription_tag.path
expect(page).to have_css("#subscription-signed-out", visible: :hidden)
expect(page).to have_css("#subscription-signed-in", visible: :hidden)
expect(page).to have_css("#response-message", visible: :hidden)
expect(page).to have_css("#subscriber-apple-auth", visible: :visible)
within "#subscriber-apple-auth" do
expect(page).to have_button("Subscribe", disabled: true, visible: :visible)
end
end
end
end