Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show Google Form feedback modal on Area and Explore pages #576

Merged
merged 1 commit into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions hub/static/css/_feedback-modal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.feedback-modal {
--#{$prefix}modal-padding: 2rem;
--#{$prefix}modal-width: 550px;

@include media-breakpoint-up('lg') {
--#{$prefix}modal-padding: 2.5rem;
--#{$prefix}modal-width: 600px;
@include font-size(1.125rem);
}

.modal-header {
border-bottom: none;
align-items: center;
padding: var(--#{$prefix}modal-padding) var(--#{$prefix}modal-padding) 0 var(--#{$prefix}modal-padding);
}

.modal-body {
padding: 1rem var(--#{$prefix}modal-padding);
}

.modal-footer {
border-top: none;
justify-content: flex-start;
padding: 0 var(--#{$prefix}modal-padding) var(--#{$prefix}modal-padding) var(--#{$prefix}modal-padding);

& > * {
margin: 0;
}
}

.close {
padding: 1rem 1rem;
margin: -1rem -1rem -1rem auto;
background: transparent;
border: none;
color: $text-muted;
font-size: 1rem;
}

legend {
font-size: 1em; // match paragraphs
margin-bottom: 1em; // match paragraphs
}

.form-check {
margin-bottom: 0.25em;
}
}

.conditional-fields {
border-left: 4px solid $gray-400;
padding-left: 1rem;
margin-left: 0.4em;
margin-top: 1rem;
margin-bottom: 1rem;
}

.team-avatars {
display: flex;
margin: 0 -4px 1rem -4px;
}

.team-avatars__person {
display: flex;
align-items: center;
margin-right: -10px;

img {
width: 60px;
height: 60px;
border-radius: 30px;
border: 4px solid #fff;
}
}
3 changes: 3 additions & 0 deletions hub/static/css/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ $btn-font-weight: bold;

// Forms

$form-text-margin-top: 0.5rem;

$form-label-margin-bottom: 0.5rem;
$form-label-font-weight: bold;

// Form validation
Expand Down
1 change: 1 addition & 0 deletions hub/static/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@
@import "accounts";
@import "landing-page";
@import "print";
@import "feedback-modal";
Binary file added hub/static/img/avatar-alice.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added hub/static/img/avatar-julia.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added hub/static/img/avatar-struan.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added hub/static/img/avatar-zarino.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 56 additions & 1 deletion hub/static/js/area.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import $ from 'jquery/dist/jquery.slim'
import { Chart, BarController, BarElement, CategoryScale, LinearScale, Legend, Tooltip } from 'chart.js'
import trackEvent from './analytics.esm.js'
import Collapse from 'bootstrap/js/dist/collapse'
import setUpCollapsable from './collapsable.esm.js'
import Dropdown from 'bootstrap/js/dist/dropdown'

Chart.register( BarController, BarElement, CategoryScale, LinearScale, Legend, Tooltip);
Expand All @@ -16,6 +16,20 @@ Chart.defaults.responsive = true

import setUpAreaPage from './area.esm.js'

async function mailingListSignup($form) {
const response = await fetch($form.attr('action'), {
method: $form.attr('method') || 'GET',
mode: 'cors',
credentials: 'same-origin',
body: $form.serialize(),
headers: {
"Content-Type": 'application/x-www-form-urlencoded',
"Accept": 'application/json; charset=utf-8',
},
})
return response.json()
}

$(function(){
if( 'geolocation' in navigator ) {
$('.js-geolocate').removeClass('d-none');
Expand Down Expand Up @@ -95,6 +109,47 @@ $(function(){
window.location.href = href
})
})

$('.js-collapsable-mailing-list-form').each(function(){
setUpCollapsable(
$(this).find('.js-mailing-list-name, .js-mailing-list-extras'),
$(this).find('.js-mailing-list-email input#email'),
'keyup change',
function($targets, $triggers){
return $triggers.eq(0).val() !== '';
}
);
});

$('.js-mailing-list-signup').on('submit', function(e){
e.preventDefault();
var $form = $(this);
$('.invalid-feedback').remove()
mailingListSignup($form).then(function(response){
if (response['response'] == 'ok') {
$form.hide()
$('.js-mailing-list-success').removeClass('d-none')
} else {
console.log(response)
for (var k in response["errors"]) {
var id = '#' + k
var el = $(id)
el.addClass('is-invalid')
var error_el = $('<div>')
error_el.addClass('invalid-feedback d-block fs-6 mt-2')
error_el.html( '<p>' + response["errors"][k].join(", ") + '</p>' )
el.after(error_el)
}

if ("mailchimp" in response["errors"]) {
var error_el = $('<div>')
error_el.addClass('invalid-feedback d-block fs-6 mt-2')
error_el.html( '<p>There was a problem signing you up, please try again.</p>' )
$form.before(error_el)
}
}
});
})
})

var makeChart = function() {
Expand Down
27 changes: 27 additions & 0 deletions hub/static/js/collapsable.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import $ from 'jquery/dist/jquery.slim'
import Collapse from 'bootstrap/js/dist/collapse'

const setUpCollapsable = function(targets, triggers, triggerEvents, showTest) {
var instances = [];
var $targets = $(targets); // targets can either be a jQuery object or selector(s)
var $triggers = $(triggers); // triggers can either be a jQuery object or selector(s)

var updateUI = function() {
var show = showTest($targets, $triggers);
$.each(instances, function(i, instance){
show ? instance.show() : instance.hide();
});
};

$targets.addClass('collapse').each(function(){
instances.push(new Collapse(this, { toggle: false}));
});

$triggers.on(triggerEvents, function(){
updateUI();
});

updateUI();
}

export default setUpCollapsable
2 changes: 0 additions & 2 deletions hub/static/js/explore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
import Collapse from 'bootstrap/js/dist/collapse'

import exploreApp from './explore.esm.js'
exploreApp.mount('#exploreApp')
152 changes: 81 additions & 71 deletions hub/static/js/home.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,7 @@
import $ from 'jquery/dist/jquery.slim'
import Collapse from 'bootstrap/js/dist/collapse'
import Modal from 'bootstrap/js/dist/modal'
import trackEvent from './analytics.esm.js'

async function mailingListSignup($form) {
const response = await fetch($form.attr('action'), {
method: $form.attr('method') || 'GET',
mode: 'cors',
credentials: 'same-origin',
body: $form.serialize(),
headers: {
"Content-Type": 'application/x-www-form-urlencoded',
"Accept": 'application/json; charset=utf-8',
},
})
return response.json()
}

var setUpCollapsableMailingListForm = function() {
var $form = $(this);
var selectors = '.js-mailing-list-name, .js-mailing-list-extras';
var trigger = '.js-mailing-list-email input#email';
var instances = [];

var updateUI = function() {
var emailEntered = $(trigger).val() !== '';
$.each(instances, function(i, instance){
emailEntered ? instance.show() : instance.hide();
});
};

$(selectors, $form).addClass('collapse').each(function(){
instances.push(new Collapse(this, { toggle: false }));
});
$(trigger, $form).on('keyup change', function(){
updateUI();
});
updateUI();
};
import setUpCollapsable from './collapsable.esm.js'

$(function(){
if( 'geolocation' in navigator ) {
Expand Down Expand Up @@ -88,16 +53,6 @@ $(function(){
}
})

$('.js-email-your-mp').on('click', function(e){
e.preventDefault()
let href = $(this).attr('href')
trackEvent('email_your_mp', {
area_name: $('#area_name').text(),
area_mp_name: $('#mp_name').text()
}).always(function(){
window.location.href = href
})
})
$('.js-landingpage-search').on('submit', function(e){
var $form = $(this);
if ( ! $form.data('submitRecorded') ) {
Expand All @@ -122,35 +77,90 @@ $(function(){
});
})

$('.js-collapsable-mailing-list-form').each(setUpCollapsableMailingListForm);
$('.form-check + .conditional-fields').each(function(){
var $target = $(this); // the .conditional-fields element
var inputSetName = $target.prev().find('input').eq(0).attr('name');
var $triggers = $('input[name="' + inputSetName + '"]');

$('.js-mailing-list-signup').on('submit', function(e){
e.preventDefault();
var $form = $(this);
$('.invalid-feedback').remove()
mailingListSignup($form).then(function(response){
if (response['response'] == 'ok') {
$form.hide()
$('.js-mailing-list-success').removeClass('d-none')
} else {
console.log(response)
for (var k in response["errors"]) {
var id = '#' + k
var el = $(id)
el.addClass('is-invalid')
var error_el = $('<div>')
error_el.addClass('invalid-feedback d-block fs-6 mt-2')
error_el.html( '<p>' + response["errors"][k].join(", ") + '</p>' )
el.after(error_el)
// jQuery can't see custom bootstrap events, so use .addEventListener instead
$target[0].addEventListener('shown.bs.collapse', function(){
$target.find('input').eq(0).trigger('focus');
});

setUpCollapsable(
$target,
$triggers,
'change',
function($target, $triggers){
return $target.prev().find('input').eq(0).prop('checked');
}
);
});

$('.feedback-modal').each(function(){
var modal = new Modal(this);

var shouldShowModal = function() {
if ( ! window.localStorage ) {
// Can’t trigger modal, because no localStorage support.
return false;
}
if ( localStorage.getItem('submitted-feedback-modal-timestamp') ) {
// Browser has already submitted the feedback form.
return false;
}
if ( localStorage.getItem('skipped-feedback-modal-timestamp') ) {
// Respect skipped modals for 7 days.
var skippedTimestamp = localStorage.getItem('skipped-feedback-modal-timestamp');
var nowTimestamp = (new Date()).getTime() / 1000;
var coolingOffPeriod = 60 * 60 * 24 * 7;
if ( nowTimestamp - skippedTimestamp < coolingOffPeriod ) {
return false;
}
}
return true;
}

if ("mailchimp" in response["errors"]) {
var error_el = $('<div>')
error_el.addClass('invalid-feedback d-block fs-6 mt-2')
error_el.html( '<p>There was a problem signing you up, please try again.</p>' )
$form.before(error_el)
this.addEventListener('hide.bs.modal', event => {
if ( ! localStorage.getItem('submitted-feedback-modal-timestamp') ) {
var timestamp = (new Date()).getTime() / 1000;
localStorage.setItem('skipped-feedback-modal-timestamp', timestamp);
}
});

if ( shouldShowModal() ) {
localStorage.removeItem('skipped-feedback-modal-timestamp');
modal.show();
}

this.addEventListener('submit', function(e){
e.preventDefault();
let form = this.querySelector('form');
let hasMadeSelection = form.querySelectorAll('input[type="checkbox"]:checked').length > 0;
let params = new URLSearchParams(Array.from(new FormData(form))).toString()

if ( hasMadeSelection ) {
fetch(form.action + '?' + params, {
method: form.method,
mode: 'no-cors',
cache: 'no-cache',
credentials: 'omit',
headers: {
"Content-Type": 'application/x-www-form-urlencoded'
}
});

if ( window.localStorage ) {
var timestamp = (new Date()).getTime() / 1000;
if ( hasMadeSelection ) {
localStorage.setItem('submitted-feedback-modal-timestamp', timestamp);
} else {
localStorage.setItem('skipped-feedback-modal-timestamp', timestamp);
}
}
}

modal.hide();
});
})
})
3 changes: 3 additions & 0 deletions hub/templates/hub/area.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
{% block bodyclass %}js-area-page{% endblock %}

{% block script %}
<script type="module" src="{% static 'js/home-out-esm.js' %}"></script>
<script type="module" src="{% static 'js/area-out-esm.js' %}"></script>
{% endblock %}

Expand Down Expand Up @@ -693,4 +694,6 @@ <h2 class="h4">Climate Coalition member?</h2>
</div>
</aside>

{% include 'hub/includes/feedback-modal.html' %}

{% endblock %}
Loading
Loading