Skip to content

Commit

Permalink
new alert display and create ui
Browse files Browse the repository at this point in the history
Alert list splits alerts into keyword and representative alerts.

New alert creation wizard which makes complicated alerts easier to
create and also suggests related terms if we have any. Also allows
editing alerts.

Retains existing form for adding MP/postcode alerts.
  • Loading branch information
struan committed Dec 17, 2024
1 parent a644038 commit 9d9f22e
Show file tree
Hide file tree
Showing 15 changed files with 1,686 additions and 197 deletions.
369 changes: 349 additions & 20 deletions classes/AlertView/Standard.php

Large diffs are not rendered by default.

83 changes: 81 additions & 2 deletions tests/AlertsPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,29 @@ private function fetch_page($vars) {
return $this->base_fetch_page($vars, 'alert');
}

private function get_page($vars = []) {
return $this->base_fetch_page_user($vars, '1.fbb689a0c092f5534b929d302db2c8a9', 'alert');
}

public function testFetchPage() {
$page = $this->fetch_page([]);
$this->assertStringContainsString('TheyWorkForYou Email Alerts', $page);
}

public function testKeywordOnly() {
$page = $this->fetch_page([ 'alertsearch' => 'elephant']);
$this->assertStringContainsString('Receive alerts when [elephant] is mentioned', $page);
$this->assertStringContainsString('What word or phrase would you like to recieve alerts about', $page);
$this->assertStringContainsString('<input type="text" id="words0" name="words[]" aria-required="true" value="elephant"', $page);
}

public function testSpeakerId() {
$page = $this->fetch_page([ 'alertsearch' => 'speaker:2']);
$this->assertStringContainsString('Mrs Test Current-MP', $page);
}

public function testPostCodeOnly() {
$page = $this->fetch_page([ 'alertsearch' => 'SE17 3HE']);
$this->assertStringContainsString('when Mrs Test Current-MP', $page);
$this->assertStringContainsString('Mrs Test Current-MP', $page);
}

public function testPostCodeWithKeyWord() {
Expand All @@ -49,4 +59,73 @@ public function testPostcodeAndKeywordWithNoSittingMP() {
$this->assertStringContainsString('You have used a postcode and something else', $page);
$this->assertStringNotContainsString('Did you mean to get alerts for when your MP', $page);
}

public function testBasicKeyWordAlertsCreation() {
$page = $this->fetch_page([ 'step' => 'define']);
$this->assertStringContainsString('What word or phrase would you like to recieve alerts about', $page);
$this->assertStringContainsString('<input type="text" id="words0" name="words[]" aria-required="true" value=""', $page);

$page = $this->fetch_page([ 'step' => 'review', 'email' => '[email protected]', 'words[]' => 'fish']);
$this->assertStringContainsString('Review Your Alert', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="fish"', $page);

$page = $this->fetch_page([ 'step' => 'confirm', 'email' => '[email protected]', 'words[]' => 'fish']);
$this->assertStringContainsString('We’re nearly done', $page);
$this->assertStringContainsString('You should receive an email shortly', $page);
}

public function testMultipleKeyWordAlertsCreation() {
$page = $this->fetch_page([ 'step' => 'define']);
$this->assertStringContainsString('What word or phrase would you like to recieve alerts about', $page);
$this->assertStringContainsString('<input type="text" id="words0" name="words[]" aria-required="true" value=""', $page);

$page = $this->fetch_page([ 'step' => 'review', 'email' => '[email protected]', 'words[]' => ['fish', 'salmon']]);
$this->assertStringContainsString('Review Your Alert', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="fish"', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="salmon"', $page);

$page = $this->fetch_page([ 'step' => 'confirm', 'email' => '[email protected]', 'words[]' => ['fish', 'salmon']]);
$this->assertStringContainsString('You should receive an email shortly', $page);
}

public function testMultipleKeyWordAlertsCreationLoggedIn() {
$page = $this->get_page(['step' => 'define']);
$this->assertStringContainsString('What word or phrase would you like to recieve alerts about', $page);
$this->assertStringContainsString('<input type="text" id="words0" name="words[]" aria-required="true" value=""', $page);

$page = $this->get_page([ 'step' => 'review', 'words[]' => ['fish', 'salmon']]);
$this->assertStringContainsString('Review Your Alert', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="fish"', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="salmon"', $page);

$page = $this->get_page([ 'step' => 'confirm', 'words[]' => ['fish', 'salmon']]);
$this->assertStringContainsString('You will now receive email alerts on any day when [fish salmon] is mentioned in parliament', $page);
}

public function testKeyWordAndSectionAlertsCreationLoggedIn() {
$page = $this->get_page(['step' => 'define']);
$this->assertStringContainsString('What word or phrase would you like to recieve alerts about', $page);
$this->assertStringContainsString('<input type="text" id="words0" name="words[]" aria-required="true" value=""', $page);

$page = $this->get_page(['step' => 'review', 'words[]' => 'fish', 'search_section' => 'debates']);
$this->assertStringContainsString('Review Your Alert', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="fish"', $page);

$page = $this->get_page(['step' => 'confirm', 'words[]' => 'fish', 'search_section' => 'debates']);
$this->assertStringContainsString('You will now receive email alerts on any day when [fish] is mentioned in House of Commons debates', $page);
}

public function testKeyWordAndSpeakerAlertsCreationLoggedIn() {
$page = $this->get_page(['step' => 'define']);
$this->assertStringContainsString('What word or phrase would you like to recieve alerts about', $page);
$this->assertStringContainsString('<input type="text" id="words0" name="words[]" aria-required="true" value=""', $page);

$page = $this->get_page(['step' => 'review', 'words[]' => 'fish', 'representative' => 'Mrs Test Current-MP']);
$this->assertStringContainsString('Review Your Alert', $page);
$this->assertStringContainsString('<input type="hidden" name="words[]" value="fish"', $page);
$this->assertStringContainsString('<input type="hidden" name="representative" value="Mrs Test Current-MP"', $page);

$page = $this->get_page([ 'step' => 'confirm', 'words[]' => 'fish', 'representative' => 'Mrs Test Current-MP']);
$this->assertStringContainsString('You will now receive email alerts on any day when Mrs Test Current-MP mentions [fish] in parliament', $page);
}
}
6 changes: 3 additions & 3 deletions tests/SearchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function testSearchPage() {
public function testSearchPageMP() {
$page = $this->fetch_page([ 'q' => 'Mary Smith' ]);
$this->assertStringContainsString('Mary Smith', $page);
$this->assertStringContainsString('MP, Amber Valley', $page);
$this->assertMatchesRegularExpression('/MP *for Amber Valley/', $page);
}

/**
Expand Down Expand Up @@ -169,9 +169,9 @@ public function testSearchPageMultipleCons() {
$page = $this->fetch_page([ 'q' => 'Liverpool' ]);
$this->assertStringContainsString('MPs in constituencies matching <em class="current-search-term">Liverpool</em>', $page);
$this->assertStringContainsString('Susan Brown', $page);
$this->assertStringContainsString('MP, Liverpool, Riverside', $page);
$this->assertMatchesRegularExpression('/MP *for Liverpool, Riverside/', $page);
$this->assertStringContainsString('Andrew Jones', $page);
$this->assertStringContainsString('MP, Liverpool, Walton', $page);
$this->assertMatchesRegularExpression('/MP *for Liverpool, Walton/', $page);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/_fixtures/alertspage.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@
<table_data name="titles_ignored">
</table_data>
<table_data name="users">
<row>
<field name="user_id">1</field>
<field name="firstname">Test</field>
<field name="lastname">User</field>
<field name="email">[email protected]</field>
<field name="password">$2y$10$UNelQZqpPpO1jT.f7DLgeOdp.WBT81c5ECvOeTMFeQTBTyq3aCh8q</field>
<field name="confirmed">1</field>
</row>
</table_data>
<table_data name="uservotes">
</table_data>
Expand Down
64 changes: 64 additions & 0 deletions www/docs/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,28 @@ $(function(){
if (!$('#options').data('advanced')) {
$("#options").find(":input").attr("disabled", "disabled");
}

$('#add-all').on('click', function(e) {
var $add_all = e.currentTarget;
var $selected_related = document.querySelectorAll('input[name="selected_related_terms[]"]');
if ($add_all.checked) {
$selected_related.forEach(function(input) {
if (input.checked) {
input.setAttribute('data:was_checked', true);
}
input.checked = true;
input.setAttribute('disabled', true);
});
} else {
$selected_related.forEach(function(input) {
if (!input.getAttribute('data:was_checked')) {
input.checked = false;
}
input.removeAttribute('data:was_checked');
input.removeAttribute('disabled');
});
}
});
});

// Backwards-compatible functions for the click/submit trackers on MP pages
Expand Down Expand Up @@ -423,6 +445,48 @@ function wrap_error($message){
return '<div class="donate-form__error-wrapper"><p class="donate-form__error">' + $message + '</p></div>';
}

function createAccordion(triggerSelector, contentSelector) {
var triggers = document.querySelectorAll(triggerSelector);

triggers.forEach(function(trigger) {
var content = document.querySelector(trigger.getAttribute('href'));

var openAccordion = function() {
content.style.maxHeight = content.scrollHeight + "px"; // Dynamically calculate height
content.setAttribute('aria-hidden', 'false');
trigger.setAttribute('aria-expanded', 'true');
};

var closeAccordion = function() {
content.style.maxHeight = null; // Collapse
content.setAttribute('aria-hidden', 'true');
trigger.setAttribute('aria-expanded', 'false');
};

trigger.addEventListener('click', function(e) {
e.preventDefault();

if (content.style.maxHeight) {
closeAccordion();
} else {
openAccordion();
}
});

// Accessibility
trigger.setAttribute('aria-controls', content.getAttribute('id'));
trigger.setAttribute('aria-expanded', 'false');
content.setAttribute('aria-hidden', 'true');
content.style.maxHeight = null;
});
}

// Initialize accordion when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
createAccordion('.accordion-button', '.accordion-content');
});


$(function() {

$('#how-often-annually').click(function() {
Expand Down
23 changes: 21 additions & 2 deletions www/docs/style/sass/_twfy-mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -246,22 +246,29 @@ $weight_bold: 700;
.button {
background-color: $colour_primary;
font-weight: $weight_semibold;
border: 0;
border: 1px solid $colour_primary;
@include border-radius(3px);
&:hover {
background-color: $primary-color-700;
}

&:focus {
&:focus-visible {
background-color: $color-yellow;
color: $body-font-color;
}
}


button {
@extend .button;
}

.button--outline {
border: 1px solid $colour_primary;
background-color: $white-text;
color: $colour_primary;
}

.secondary-button,
.button--secondary {
background-color: $colour_off_white;
Expand All @@ -276,11 +283,23 @@ button {

.button--red, .button--negative {
background-color: $color_red;
border: 1px solid $color_red;
&:hover {
background-color: darken($color_red, 10%);
}
}

.button--outline-red {
color: $color_red;
border: 1px solid $color_red;
background-color: $white-text;

&:hover {
color: $white-text;
background-color: $color_red;
}
}

.button--disabled,
.button--disabled:hover {
background-color: lighten($colour_off_white, 3%);
Expand Down
59 changes: 37 additions & 22 deletions www/docs/style/sass/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@
@import url(https://fonts.googleapis.com/css2?family=Manrope:wght@700&family=Merriweather:wght@400;700&display=swap);
/* Foundation Icons v 3.0 MIT License */
@font-face {
font-family: "foundation-icons";
src: url("/style/foundation-icons/foundation-icons.woff") format("woff");
font-weight: normal;
font-style: normal;
font-family: "foundation-icons";
src: url("/style/foundation-icons/foundation-icons.woff") format("woff");
font-weight: normal;
font-style: normal;
}

.fi-social-facebook:before,
Expand All @@ -75,17 +75,24 @@
.fi-megaphone:before,
.fi-pound:before,
.fi-magnifying-glass:before,
.fi-heart:before
.fi-heart:before,
.fi-plus:before,
.fi-play:before,
.fi-pause:before,
.fi-trash:before,
.fi-page-edit:before,
.fi-x:before,
.fi-save:before
{
font-family: "foundation-icons";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
display: inline-block;
text-decoration: inherit;
font-family: "foundation-icons";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
display: inline-block;
text-decoration: inherit;
}

// https://github.com/zurb/foundation-icon-fonts/blob/master/_foundation-icons.scss
Expand All @@ -97,6 +104,13 @@
.fi-pound:before {content: "\f19a"}
.fi-magnifying-glass:before {content: "\f16c"}
.fi-heart:before { content: "\f159"; }
.fi-plus:before { content: "\f199"; }
.fi-play:before { content: "\f198"; }
.fi-pause:before { content: "\f191"; }
.fi-trash:before { content: "\f204"; }
.fi-page-edit:before { content: "\f184"; }
.fi-x:before { content: "\f217"; }
.fi-save:before { content: "\f1ac"; }

html,
body {
Expand Down Expand Up @@ -129,13 +143,13 @@ h3 {
}

.pull-right {
@media (min-width: $medium-screen) {
@media (min-width: $medium-screen) {
float: right;
margin-left: 1em;
}
}
.pull-left {
@media (min-width: $medium-screen) {
@media (min-width: $medium-screen) {
float: left;
margin-left: 1em;
}
Expand Down Expand Up @@ -166,12 +180,12 @@ ul {
a {
overflow-wrap: break-word;
word-wrap: break-word;

-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;

-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
color: $links;
}

Expand All @@ -198,7 +212,7 @@ a:focus {
// for .button elements!!
vertical-align: -0.4em;
}

&.tertiary {
@include button-style($bg: $links);
}
Expand Down Expand Up @@ -231,6 +245,7 @@ form {

@import "parts/panels";
@import "parts/promo-banner";
@import "parts/accordion";

@import "pages/mp";
@import "pages/topics";
Expand Down
Loading

0 comments on commit 9d9f22e

Please sign in to comment.