From 2556fded1eb34ac5030f0c351ecb19853a04a40f Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 14 Jul 2020 14:24:25 +0100 Subject: [PATCH] Merge pull request #2998 from overleaf/as-beta-page-updates Update beta program page to include feedback survey link GitOrigin-RevId: 549cd2be01b8f64d952d0347c8c102d0d2efae24 --- .../BetaProgram/BetaProgramController.js | 47 +++++------- .../web/app/views/beta_program/opt_in.pug | 37 ++++++--- .../stylesheets/app/beta-program.less | 4 - .../BetaProgram/BetaProgramControllerTests.js | 75 ++++++------------- 4 files changed, 66 insertions(+), 97 deletions(-) diff --git a/services/web/app/src/Features/BetaProgram/BetaProgramController.js b/services/web/app/src/Features/BetaProgram/BetaProgramController.js index 69c1b66f1a..860edcc424 100644 --- a/services/web/app/src/Features/BetaProgram/BetaProgramController.js +++ b/services/web/app/src/Features/BetaProgram/BetaProgramController.js @@ -1,60 +1,47 @@ -/* eslint-disable - camelcase, - no-unused-vars, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -let BetaProgramController const BetaProgramHandler = require('./BetaProgramHandler') const UserGetter = require('../User/UserGetter') const Settings = require('settings-sharelatex') const logger = require('logger-sharelatex') const AuthenticationController = require('../Authentication/AuthenticationController') -module.exports = BetaProgramController = { +const BetaProgramController = { optIn(req, res, next) { - const user_id = AuthenticationController.getLoggedInUserId(req) - logger.log({ user_id }, 'user opting in to beta program') - if (user_id == null) { + const userId = AuthenticationController.getLoggedInUserId(req) + logger.log({ userId }, 'user opting in to beta program') + if (userId == null) { return next(new Error('no user id in session')) } - return BetaProgramHandler.optIn(user_id, function(err) { + BetaProgramHandler.optIn(userId, function(err) { if (err) { return next(err) } - return res.redirect('/beta/participate') + res.redirect('/beta/participate') }) }, optOut(req, res, next) { - const user_id = AuthenticationController.getLoggedInUserId(req) - logger.log({ user_id }, 'user opting out of beta program') - if (user_id == null) { + const userId = AuthenticationController.getLoggedInUserId(req) + logger.log({ userId }, 'user opting out of beta program') + if (userId == null) { return next(new Error('no user id in session')) } - return BetaProgramHandler.optOut(user_id, function(err) { + BetaProgramHandler.optOut(userId, function(err) { if (err) { return next(err) } - return res.redirect('/beta/participate') + res.redirect('/beta/participate') }) }, optInPage(req, res, next) { - const user_id = AuthenticationController.getLoggedInUserId(req) - logger.log({ user_id }, 'showing beta participation page for user') - return UserGetter.getUser(user_id, function(err, user) { + const userId = AuthenticationController.getLoggedInUserId(req) + logger.log({ user_id: userId }, 'showing beta participation page for user') + UserGetter.getUser(userId, function(err, user) { if (err) { - logger.warn({ err, user_id }, 'error fetching user') + logger.warn({ err, userId }, 'error fetching user') return next(err) } - return res.render('beta_program/opt_in', { + res.render('beta_program/opt_in', { title: 'sharelatex_beta_program', user, languages: Settings.languages @@ -62,3 +49,5 @@ module.exports = BetaProgramController = { }) } } + +module.exports = BetaProgramController diff --git a/services/web/app/views/beta_program/opt_in.pug b/services/web/app/views/beta_program/opt_in.pug index 778f16505d..a12fdc3bfc 100644 --- a/services/web/app/views/beta_program/opt_in.pug +++ b/services/web/app/views/beta_program/opt_in.pug @@ -1,7 +1,7 @@ extends ../layout block content - .content.content-alt + main.content.content-alt .container.beta-opt-in-wrapper .row .col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 @@ -13,29 +13,44 @@ block content .container-fluid .row .col-md-12 - p.text-centered #{translate("beta_program_benefits")} - p.text-centered - | #{translate("beta_program_badge_description")} - span.beta-feature-badge + if user.betaProgram + p #{translate("beta_program_already_participating")}. + p #{translate("thank_you_for_being_part_of_our_beta_program")}. + else + p #{translate("beta_program_benefits")} + + p #[strong How it works:] + ul + li #{translate("beta_program_badge_description")}#[span(aria-label=translate("beta_feature_badge") role="img").beta-feature-badge] + li #{translate("you_will_be_able_to_contact_us_any_time_to_share_your_feedback")}. + li #{translate("we_may_also_contact_you_from_time_to_time_by_email_with_a_survey")}. + li #{translate("you_can_opt_in_and_out_of_the_program_at_any_time_on_this_page")}. + .row.text-centered .col-md-12 if user.betaProgram - p #{translate("beta_program_already_participating")} form(id="beta-program-opt-out", method="post", action="/beta/opt-out", novalidate) + input(type="hidden", name="_csrf", value=csrfToken) .form-group - input(type="hidden", name="_csrf", value=csrfToken) - button.btn.btn-primary( + a( + href="https://forms.gle/CFEsmvZQTAwHCd3X9" + target="_blank" + rel="noopener noreferrer" + ).btn.btn-primary.btn-lg #{translate("give_feedback")} + .form-group + button.btn.btn-info.btn-sm( type="submit" ) span #{translate("beta_program_opt_out_action")} .form-group - a(href="/project").btn.btn-info #{translate("back_to_your_projects")} + a(href="/project").btn.btn-link.btn-sm #{translate("back_to_your_projects")} else form(id="beta-program-opt-in", method="post", action="/beta/opt-in", novalidate) + input(type="hidden", name="_csrf", value=csrfToken) .form-group - input(type="hidden", name="_csrf", value=csrfToken) button.btn.btn-primary( type="submit" ) span #{translate("beta_program_opt_in_action")} - + .form-group + a(href="/project").btn.btn-link.btn-sm #{translate("back_to_your_projects")} diff --git a/services/web/frontend/stylesheets/app/beta-program.less b/services/web/frontend/stylesheets/app/beta-program.less index 652eb6cdd7..209eac301d 100644 --- a/services/web/frontend/stylesheets/app/beta-program.less +++ b/services/web/frontend/stylesheets/app/beta-program.less @@ -1,7 +1,3 @@ -.beta-opt-in-wrapper { - min-height: 400px; -} - .beta-opt-in { .form-group { margin-top: 15px; diff --git a/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js b/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js index f660cf3c15..d6ad6a0a8e 100644 --- a/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js +++ b/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js @@ -1,26 +1,12 @@ -/* eslint-disable - max-len, - mocha/no-identical-title, - no-return-assign, - no-unused-vars, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const should = require('chai').should() +require('chai').should() const SandboxedModule = require('sandboxed-module') -const assert = require('assert') const path = require('path') const sinon = require('sinon') + const modulePath = path.join( __dirname, '../../../../app/src/Features/BetaProgram/BetaProgramController' ) -const { expect } = require('chai') describe('BetaProgramController', function() { beforeEach(function() { @@ -67,130 +53,113 @@ describe('BetaProgramController', function() { redirect: sinon.stub(), render: sinon.stub() } - return (this.next = sinon.stub()) + this.next = sinon.stub() }) describe('optIn', function() { beforeEach(function() { - return this.BetaProgramHandler.optIn.callsArgWith(1, null) + this.BetaProgramHandler.optIn.callsArgWith(1, null) }) it("should redirect to '/beta/participate'", function() { this.BetaProgramController.optIn(this.req, this.res, this.next) this.res.redirect.callCount.should.equal(1) - return this.res.redirect.firstCall.args[0].should.equal( - '/beta/participate' - ) + this.res.redirect.firstCall.args[0].should.equal('/beta/participate') }) it('should not call next with an error', function() { this.BetaProgramController.optIn(this.req, this.res, this.next) - return this.next.callCount.should.equal(0) - }) - - it('should not call next with an error', function() { - this.BetaProgramController.optIn(this.req, this.res, this.next) - return this.next.callCount.should.equal(0) + this.next.callCount.should.equal(0) }) it('should call BetaProgramHandler.optIn', function() { this.BetaProgramController.optIn(this.req, this.res, this.next) - return this.BetaProgramHandler.optIn.callCount.should.equal(1) + this.BetaProgramHandler.optIn.callCount.should.equal(1) }) describe('when BetaProgramHandler.opIn produces an error', function() { beforeEach(function() { - return this.BetaProgramHandler.optIn.callsArgWith(1, new Error('woops')) + this.BetaProgramHandler.optIn.callsArgWith(1, new Error('woops')) }) it("should not redirect to '/beta/participate'", function() { this.BetaProgramController.optIn(this.req, this.res, this.next) - return this.res.redirect.callCount.should.equal(0) + this.res.redirect.callCount.should.equal(0) }) it('should produce an error', function() { this.BetaProgramController.optIn(this.req, this.res, this.next) this.next.callCount.should.equal(1) - return this.next.firstCall.args[0].should.be.instanceof(Error) + this.next.firstCall.args[0].should.be.instanceof(Error) }) }) }) describe('optOut', function() { beforeEach(function() { - return this.BetaProgramHandler.optOut.callsArgWith(1, null) + this.BetaProgramHandler.optOut.callsArgWith(1, null) }) it("should redirect to '/beta/participate'", function() { this.BetaProgramController.optOut(this.req, this.res, this.next) this.res.redirect.callCount.should.equal(1) - return this.res.redirect.firstCall.args[0].should.equal( - '/beta/participate' - ) + this.res.redirect.firstCall.args[0].should.equal('/beta/participate') }) it('should not call next with an error', function() { this.BetaProgramController.optOut(this.req, this.res, this.next) - return this.next.callCount.should.equal(0) - }) - - it('should not call next with an error', function() { - this.BetaProgramController.optOut(this.req, this.res, this.next) - return this.next.callCount.should.equal(0) + this.next.callCount.should.equal(0) }) it('should call BetaProgramHandler.optOut', function() { this.BetaProgramController.optOut(this.req, this.res, this.next) - return this.BetaProgramHandler.optOut.callCount.should.equal(1) + this.BetaProgramHandler.optOut.callCount.should.equal(1) }) describe('when BetaProgramHandler.optOut produces an error', function() { beforeEach(function() { - return this.BetaProgramHandler.optOut.callsArgWith( - 1, - new Error('woops') - ) + this.BetaProgramHandler.optOut.callsArgWith(1, new Error('woops')) }) it("should not redirect to '/beta/participate'", function() { this.BetaProgramController.optOut(this.req, this.res, this.next) - return this.res.redirect.callCount.should.equal(0) + this.res.redirect.callCount.should.equal(0) }) it('should produce an error', function() { this.BetaProgramController.optOut(this.req, this.res, this.next) this.next.callCount.should.equal(1) - return this.next.firstCall.args[0].should.be.instanceof(Error) + this.next.firstCall.args[0].should.be.instanceof(Error) }) }) }) describe('optInPage', function() { beforeEach(function() { - return this.UserGetter.getUser.callsArgWith(1, null, this.user) + this.UserGetter.getUser.callsArgWith(1, null, this.user) }) it('should render the opt-in page', function() { this.BetaProgramController.optInPage(this.req, this.res, this.next) this.res.render.callCount.should.equal(1) const { args } = this.res.render.firstCall - return args[0].should.equal('beta_program/opt_in') + args[0].should.equal('beta_program/opt_in') }) describe('when UserGetter.getUser produces an error', function() { beforeEach(function() { - return this.UserGetter.getUser.callsArgWith(1, new Error('woops')) + this.UserGetter.getUser.callsArgWith(1, new Error('woops')) }) it('should not render the opt-in page', function() { this.BetaProgramController.optInPage(this.req, this.res, this.next) - return this.res.render.callCount.should.equal(0) + this.res.render.callCount.should.equal(0) }) it('should produce an error', function() { this.BetaProgramController.optInPage(this.req, this.res, this.next) this.next.callCount.should.equal(1) - return this.next.firstCall.args[0].should.be.instanceof(Error) + this.next.firstCall.args[0].should.be.instanceof(Error) }) }) })