Refactored the user callout class

Instead of the JS being in charge of the HTML, the HAML now handles it.
The HAML can then check the cookie & show it needed. It also allows the
HAML access to the paths so we don't have to pass that through.

Closes #29955
This commit is contained in:
Phil Hughes 2017-03-24 12:41:42 +00:00
parent 4a8e516c1f
commit 3eedb2aede
9 changed files with 87 additions and 77 deletions

View File

@ -1,57 +1,26 @@
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
const userCalloutElementName = '.user-callout';
const closeButton = '.close-user-callout';
const userCalloutBtn = '.user-callout-btn';
const userCalloutSvgAttrName = 'callout-svg';
const USER_CALLOUT_COOKIE = 'user_callout_dismissed'; const USER_CALLOUT_COOKIE = 'user_callout_dismissed';
const USER_CALLOUT_TEMPLATE = `
<div class="bordered-box landing content-block">
<button class="btn btn-default close close-user-callout" type="button">
<i class="fa fa-times dismiss-icon"></i>
</button>
<div class="row">
<div class="col-sm-3 col-xs-12 svg-container">
</div>
<div class="col-sm-8 col-xs-12 inner-content">
<h4>
Customize your experience
</h4>
<p>
Change syntax themes, default project pages, and more in preferences.
</p>
<a class="btn user-callout-btn" href="/profile/preferences">Check it out</a>
</div>
</div>
</div>`;
export default class UserCallout { export default class UserCallout {
constructor() { constructor() {
this.isCalloutDismissed = Cookies.get(USER_CALLOUT_COOKIE); this.isCalloutDismissed = Cookies.get(USER_CALLOUT_COOKIE);
this.userCalloutBody = $(userCalloutElementName); this.userCalloutBody = $('.user-callout');
this.userCalloutSvg = $(userCalloutElementName).attr(userCalloutSvgAttrName);
$(userCalloutElementName).removeAttr(userCalloutSvgAttrName);
this.init(); this.init();
} }
init() { init() {
const $template = $(USER_CALLOUT_TEMPLATE);
if (!this.isCalloutDismissed || this.isCalloutDismissed === 'false') { if (!this.isCalloutDismissed || this.isCalloutDismissed === 'false') {
$template.find('.svg-container').append(this.userCalloutSvg); $('.js-close-callout').on('click', e => this.dismissCallout(e));
this.userCalloutBody.append($template);
$template.find(closeButton).on('click', e => this.dismissCallout(e));
$template.find(userCalloutBtn).on('click', e => this.dismissCallout(e));
} else {
this.userCalloutBody.remove();
} }
} }
dismissCallout(e) { dismissCallout(e) {
Cookies.set(USER_CALLOUT_COOKIE, 'true');
const $currentTarget = $(e.currentTarget); const $currentTarget = $(e.currentTarget);
if ($currentTarget.hasClass('close-user-callout')) {
Cookies.set(USER_CALLOUT_COOKIE, 'true');
if ($currentTarget.hasClass('close')) {
this.userCalloutBody.remove(); this.userCalloutBody.remove();
} }
} }

View File

@ -306,4 +306,8 @@ module ApplicationHelper
def active_when(condition) def active_when(condition)
'active' if condition 'active' if condition
end end
def show_user_callout?
cookies[:user_callout_dismissed] == 'true'
end
end end

View File

@ -4,7 +4,9 @@
- page_title "Projects" - page_title "Projects"
- header_title "Projects", dashboard_projects_path - header_title "Projects", dashboard_projects_path
.user-callout{ 'callout-svg' => custom_icon('icon_customization') } - unless show_user_callout?
= render 'shared/user_callout'
- if @projects.any? || params[:name] - if @projects.any? || params[:name]
= render 'dashboard/projects_head' = render 'dashboard/projects_head'

View File

@ -0,0 +1,14 @@
.user-callout
.bordered-box.landing.content-block
%button.btn.btn-default.close.js-close-callout{ type: 'button',
'aria-label' => 'Dismiss customize experience box' }
= icon('times', class: 'dismiss-icon', 'aria-hidden' => 'true')
.row
.col-sm-3.col-xs-12.svg-container
= custom_icon('icon_customization')
.col-sm-8.col-xs-12.inner-content
%h4
Customize your experience
%p
Change syntax themes, default project pages, and more in preferences.
= link_to 'Check it out', profile_preferences_path, class: 'btn btn-default js-close-callout'

View File

@ -97,8 +97,8 @@
Snippets Snippets
%div{ class: container_class } %div{ class: container_class }
- if @user == current_user - if @user == current_user && !show_user_callout?
.user-callout{ 'callout-svg' => custom_icon('icon_customization') } = render 'shared/user_callout'
.tab-content .tab-content
#activity.tab-pane #activity.tab-pane
.row-content-block.calender-block.white.second-block.hidden-xs .row-content-block.calender-block.white.second-block.hidden-xs

View File

@ -7,15 +7,27 @@ describe 'User Callouts', js: true do
before do before do
login_as(user) login_as(user)
project.team << [user, :master] project.team << [user, :master]
end end
it 'takes you to the profile preferences when the link is clicked' do it 'takes you to the profile preferences when the link is clicked' do
visit dashboard_projects_path visit dashboard_projects_path
click_link 'Check it out' click_link 'Check it out'
expect(current_path).to eq profile_preferences_path expect(current_path).to eq profile_preferences_path
end end
it 'does not show when cookie is set' do
visit dashboard_projects_path
within('.user-callout') do
find('.close').click
end
visit dashboard_projects_path
expect(page).not_to have_selector('.user-callout')
end
describe 'user callout should appear in two routes' do describe 'user callout should appear in two routes' do
it 'shows up on the user profile' do it 'shows up on the user profile' do
visit user_path(user) visit user_path(user)
@ -31,7 +43,7 @@ describe 'User Callouts', js: true do
it 'hides the user callout when click on the dismiss icon' do it 'hides the user callout when click on the dismiss icon' do
visit user_path(user) visit user_path(user)
within('.user-callout') do within('.user-callout') do
find('.close-user-callout').click find('.close').click
end end
expect(page).not_to have_selector('.user-callout') expect(page).not_to have_selector('.user-callout')
end end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe Dashboard::ProjectsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project, namespace: namespace, path: 'builds-project') }
render_views
before(:all) do
clean_frontend_fixtures('dashboard/')
end
before(:each) do
sign_in(admin)
end
it 'dashboard/user-callout.html.raw' do |example|
rendered = render_template('shared/_user_callout')
store_frontend_fixture(rendered, example.description)
end
private
def render_template(template_file_name)
controller.prepend_view_path(JavaScriptFixturesHelpers::FIXTURE_PATH)
controller.render_to_string(template_file_name, layout: false)
end
end

View File

@ -1,2 +0,0 @@
.user-callout{ 'callout-svg' => custom_icon('icon_customization') }

View File

@ -4,7 +4,7 @@ import UserCallout from '~/user_callout';
const USER_CALLOUT_COOKIE = 'user_callout_dismissed'; const USER_CALLOUT_COOKIE = 'user_callout_dismissed';
describe('UserCallout', function () { describe('UserCallout', function () {
const fixtureName = 'static/user_callout.html.raw'; const fixtureName = 'dashboard/user-callout.html.raw';
preloadFixtures(fixtureName); preloadFixtures(fixtureName);
beforeEach(() => { beforeEach(() => {
@ -12,26 +12,22 @@ describe('UserCallout', function () {
Cookies.remove(USER_CALLOUT_COOKIE); Cookies.remove(USER_CALLOUT_COOKIE);
this.userCallout = new UserCallout(); this.userCallout = new UserCallout();
this.closeButton = $('.close-user-callout'); this.closeButton = $('.js-close-callout.close');
this.userCalloutBtn = $('.user-callout-btn'); this.userCalloutBtn = $('.js-close-callout:not(.close)');
this.userCalloutContainer = $('.user-callout'); this.userCalloutContainer = $('.user-callout');
}); });
it('does not show when cookie is set not defined', () => { it('hides when user clicks on the dismiss-icon', (done) => {
expect(Cookies.get(USER_CALLOUT_COOKIE)).toBeUndefined();
expect(this.userCalloutContainer.is(':visible')).toBe(true);
});
it('shows when cookie is set to false', () => {
Cookies.set(USER_CALLOUT_COOKIE, 'false');
expect(Cookies.get(USER_CALLOUT_COOKIE)).toBeDefined();
expect(this.userCalloutContainer.is(':visible')).toBe(true);
});
it('hides when user clicks on the dismiss-icon', () => {
this.closeButton.click(); this.closeButton.click();
expect(Cookies.get(USER_CALLOUT_COOKIE)).toBe('true'); expect(Cookies.get(USER_CALLOUT_COOKIE)).toBe('true');
setTimeout(() => {
expect(
document.querySelector('.user-callout'),
).toBeNull();
done();
});
}); });
it('hides when user clicks on the "check it out" button', () => { it('hides when user clicks on the "check it out" button', () => {
@ -39,19 +35,3 @@ describe('UserCallout', function () {
expect(Cookies.get(USER_CALLOUT_COOKIE)).toBe('true'); expect(Cookies.get(USER_CALLOUT_COOKIE)).toBe('true');
}); });
}); });
describe('UserCallout when cookie is present', function () {
const fixtureName = 'static/user_callout.html.raw';
preloadFixtures(fixtureName);
beforeEach(() => {
loadFixtures(fixtureName);
Cookies.set(USER_CALLOUT_COOKIE, 'true');
this.userCallout = new UserCallout();
this.userCalloutContainer = $('.user-callout');
});
it('removes the DOM element', () => {
expect(this.userCalloutContainer.length).toBe(0);
});
});