From 8fe7b4eaf105b9a198681b8293163dc39be7d45c Mon Sep 17 00:00:00 2001
From: Struan Donald
Date: Tue, 10 Dec 2024 11:49:13 +0000
Subject: [PATCH] new alert display and create ui
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.
---
classes/AlertView/Standard.php | 369 +++++++++++++++++-
tests/AlertsPageTest.php | 83 +++-
tests/SearchTest.php | 6 +-
tests/_fixtures/alertspage.xml | 8 +
www/docs/js/main.js | 64 +++
www/docs/style/sass/_twfy-mixins.scss | 23 +-
www/docs/style/sass/app.scss | 59 +--
www/docs/style/sass/pages/_alert.scss | 5 +
www/docs/style/sass/parts/_accordion.scss | 280 +++++++++++++
www/includes/easyparliament/alert.php | 37 ++
.../templates/html/alert/_alert_form.php | 339 ++++++++++++++++
.../templates/html/alert/_list_accordian.php | 226 +++++++++++
.../templates/html/alert/_mp_alert_form.php | 76 ++++
.../templates/html/alert/_own_mp_alerts.php | 49 +++
.../templates/html/alert/index.php | 259 ++++++------
15 files changed, 1686 insertions(+), 197 deletions(-)
create mode 100644 www/docs/style/sass/parts/_accordion.scss
create mode 100644 www/includes/easyparliament/templates/html/alert/_alert_form.php
create mode 100644 www/includes/easyparliament/templates/html/alert/_list_accordian.php
create mode 100644 www/includes/easyparliament/templates/html/alert/_mp_alert_form.php
create mode 100644 www/includes/easyparliament/templates/html/alert/_own_mp_alerts.php
diff --git a/classes/AlertView/Standard.php b/classes/AlertView/Standard.php
index d55170d073..dcc4f7729c 100644
--- a/classes/AlertView/Standard.php
+++ b/classes/AlertView/Standard.php
@@ -25,7 +25,9 @@ public function display() {
$this->checkInput();
$this->searchForConstituenciesAndMembers();
- if (!sizeof($this->data['errors']) && ($this->data['keyword'] || $this->data['pid'])) {
+ if ($this->data['step'] || $this->data['addword']) {
+ $this->processStep();
+ } elseif (!$this->data['results'] == 'changes-abandoned' && !sizeof($this->data['errors']) && $this->data['submitted'] && ($this->data['keyword'] || $this->data['pid'])) {
$this->addAlert();
}
@@ -37,6 +39,7 @@ public function display() {
return $this->data;
}
+ # This only happens if we have an alert and want to do something to it.
private function processAction() {
$token = get_http_var('t');
$alert = $this->alert->check_token($token);
@@ -48,7 +51,8 @@ private function processAction() {
$success = $this->confirmAlert($token);
if ($success) {
$this->data['results'] = 'alert-confirmed';
- $this->data['criteria'] = \MySociety\TheyWorkForYou\Utility\Alert::prettifyCriteria($this->alert->criteria);
+ $this->data['criteria'] = $this->alert->criteria;
+ $this->data['display_criteria'] = \MySociety\TheyWorkForYou\Utility\Alert::prettifyCriteria($this->alert->criteria);
}
} elseif ($action == 'Suspend') {
$success = $this->suspendAlert($token);
@@ -70,6 +74,8 @@ private function processAction() {
if ($success) {
$this->data['results'] = 'all-alerts-deleted';
}
+ } elseif ($action == 'Abandon') {
+ $this->data['results'] = 'changes-abandoned';
}
if (!$success) {
$this->data['results'] = 'alert-fail';
@@ -79,6 +85,50 @@ private function processAction() {
$this->data['alert'] = $alert;
}
+ # Process a screen in the alert creation wizard
+ private function processStep() {
+ # fetch a list of suggested terms. Need this for the define screen so we can filter out the suggested terms
+ # and not show them if the user goes back
+ if (($this->data['step'] == 'review' || $this->data['step'] == 'define') && !$this->data['shown_related']) {
+ $suggestions = [];
+ foreach ($this->data['keywords'] as $word) {
+ $terms = $this->alert->get_related_terms($word);
+ $terms = array_diff($terms, $this->data['keywords']);
+ if ($terms && count($terms)) {
+ $suggestions = array_merge($suggestions, $terms);
+ }
+ }
+
+ if (count($suggestions) > 0) {
+ $this->data['step'] = 'add_vector_related';
+ $this->data['suggestions'] = $suggestions;
+ }
+ # confirm the alert. Handles both creating and editing alerts
+ } elseif ($this->data['step'] == 'confirm') {
+ $success = true;
+ # if there's already an alert assume we are editing it and user must be logged in
+ if ($this->data['alert']) {
+ $success = $this->updateAlert($this->data['alert']['id'], $this->data);
+ if ($success) {
+ # reset all the data to stop anything getting confused
+ $this->data['results'] = 'alert-confirmed';
+ $this->data['step'] = '';
+ $this->data['pid'] = '';
+ $this->data['alertsearch'] = '';
+ $this->data['pc'] = '';
+ $this->data['members'] = false;
+ $this->data['constituencies'] = [];
+ } else {
+ $this->data['results'] = 'alert-fail';
+ $this->data['step'] = 'review';
+ }
+ } else {
+ $success = $this->addAlert();
+ $this->data['step'] = '';
+ }
+ }
+ }
+
private function getBasicData() {
global $this_page;
@@ -93,12 +143,102 @@ private function getBasicData() {
$this->data["email"] = trim(get_http_var("email"));
$this->data['email_verified'] = false;
}
+
+ $this->data['token'] = get_http_var('t');
+ $this->data['step'] = trim(get_http_var("step"));
+ $this->data['mp_step'] = trim(get_http_var("mp_step"));
+ $this->data['addword'] = trim(get_http_var("addword"));
+ $this->data['this_step'] = trim(get_http_var("this_step"));
+ $this->data['shown_related'] = get_http_var('shown_related');
+ $this->data['match_all'] = get_http_var('match_all') == 'on';
$this->data['keyword'] = trim(get_http_var("keyword"));
- $this->data['pid'] = trim(get_http_var("pid"));
+ $this->data['search_section'] = '';
$this->data['alertsearch'] = trim(get_http_var("alertsearch"));
+ $this->data['mp_search'] = trim(get_http_var("mp_search"));
+ $this->data['pid'] = trim(get_http_var("pid"));
$this->data['pc'] = get_http_var('pc');
- $this->data['submitted'] = get_http_var('submitted') || $this->data['pid'] || $this->data['keyword'];
- $this->data['token'] = get_http_var('t');
+ $this->data['submitted'] = get_http_var('submitted') || $this->data['pid'] || $this->data['keyword'] || $this->data['step'];
+
+ if ($this->data['addword'] || $this->data['step']) {
+ $alert = $this->alert->check_token($this->data['token']);
+
+ $criteria = '';
+ if ($alert) {
+ $criteria = $alert['criteria'];
+ }
+
+ $this->data['alert'] = $alert;
+
+ $this->data['alert_parts'] = \MySociety\TheyWorkForYou\Utility\Alert::prettifyCriteria($criteria, true);
+
+ $existing_rep = '';
+ if (isset($this->data['alert_parts']['spokenby'])) {
+ $existing_rep = $this->data['alert_parts']['spokenby'][0];
+ }
+
+ $existing_section = '';
+ if (count($this->data['alert_parts']['sections'])) {
+ $existing_section = $this->data['alert_parts']['sections'][0];
+ }
+
+ if ($this->data['alert_parts']['match_all']) {
+ $this->data['match_all'] = true;
+ }
+
+ $words = get_http_var('words', $this->data['alert_parts']['words'], true);
+
+ $this->data['words'] = [];
+ $this->data['keywords'] = [];
+ foreach ($words as $word) {
+ if (trim($word) != '') {
+ $this->data['keywords'][] = $word;
+ $this->data['words'][] = $this->wrap_phrase_in_quotes($word);
+ }
+ }
+
+ $add_all_related = get_http_var('add_all_related');
+ $this->data['add_all_related'] = $add_all_related;
+ $this->data['skip_keyword_terms'] = [];
+
+ $selected_related_terms = get_http_var('selected_related_terms', [], true);
+ $this->data['selected_related_terms'] = $selected_related_terms;
+
+ if ($this->data['step'] !== 'define') {
+ if ($add_all_related) {
+ $this->data['selected_related_terms'] = [];
+ $related_terms = get_http_var('related_terms', [], true);
+ foreach ($related_terms as $term) {
+ $this->data['skip_keyword_terms'][] = $term;
+ $this->data['keywords'][] = $term;
+ $this->data['words'][] = $this->wrap_phrase_in_quotes($term);
+ }
+ } else {
+ $this->data['skip_keyword_terms'] = $selected_related_terms;
+ foreach ($selected_related_terms as $term) {
+ $this->data['keywords'][] = $term;
+ $this->data['words'][] = $this->wrap_phrase_in_quotes($term);
+ }
+ }
+ }
+ $this->data['exclusions'] = trim(get_http_var("exclusions", implode('', $this->data['alert_parts']['exclusions'])));
+ $this->data['representative'] = trim(get_http_var("representative", $existing_rep));
+
+ $this->data['search_section'] = trim(get_http_var("search_section", $existing_section));
+
+ $separator = ' OR ';
+ if ($this->data['match_all']) {
+ $separator = ' ';
+ }
+ $this->data['keyword'] = implode($separator, $this->data['words']);
+ if ($this->data['exclusions']) {
+ $this->data['keyword'] = '(' . $this->data['keyword'] . ') -' . $this->data["exclusions"];
+ }
+
+ $this->data['results'] = '';
+
+ $this->getSearchSections();
+ } # XXX probably should do something here if $alertsearch is set
+
$this->data['sign'] = get_http_var('sign');
$this->data['site'] = get_http_var('site');
$this->data['message'] = '';
@@ -106,6 +246,36 @@ private function getBasicData() {
$ACTIONURL = new \MySociety\TheyWorkForYou\Url($this_page);
$ACTIONURL->reset();
$this->data['actionurl'] = $ACTIONURL->generate();
+
+ }
+
+ private function wrap_phrase_in_quotes($phrase) {
+ if (strpos($phrase, ' ') > 0) {
+ $phrase = '"' . trim($phrase, '"') . '"';
+ }
+
+ return $phrase;
+ }
+
+ private function getRecentResults($text) {
+ global $SEARCHENGINE;
+ $se = new \SEARCHENGINE($text);
+ $this->data['search_result_count'] = $se->run_count(0, 10);
+ $se->run_search(0, 1, 'date');
+ }
+
+ private function getSearchSections() {
+ $this->data['sections'] = [];
+ if ($this->data['search_section']) {
+ foreach (explode(' ', $this->data['search_section']) as $section) {
+ $this->data['sections'][] = \MySociety\TheyWorkForYou\Utility\Alert::sectionToTitle($section);
+ }
+ }
+ }
+
+ private function updateAlert($token) {
+ $success = $this->alert->update($token, $this->data);
+ return $success;
}
private function checkInput() {
@@ -113,6 +283,12 @@ private function checkInput() {
$errors = [];
+ # these are the initial screens and so cannot have any errors as we've not submitted
+ if (!$this->data['submitted'] || $this->data['step'] == 'define' || $this->data['mp_step'] == 'mp_alert') {
+ $this->data['errors'] = $errors;
+ return;
+ }
+
// Check each of the things the user has input.
// If there is a problem with any of them, set an entry in the $errors array.
// This will then be used to (a) indicate there were errors and (b) display
@@ -131,6 +307,9 @@ private function checkInput() {
}
$text = $this->data['alertsearch'];
+ if ($this->data['mp_search']) {
+ $text = $this->data['mp_search'];
+ }
if (!$text) {
$text = $this->data['keyword'];
}
@@ -156,10 +335,48 @@ private function checkInput() {
}
private function searchForConstituenciesAndMembers() {
- // Do the search
- if ($this->data['alertsearch']) {
- $this->data['members'] = \MySociety\TheyWorkForYou\Utility\Search::searchMemberDbLookupWithNames($this->data['alertsearch'], true);
- [$this->data['constituencies'], $this->data['valid_postcode']] = \MySociety\TheyWorkForYou\Utility\Search::searchConstituenciesByQuery($this->data['alertsearch']);
+ if ($this->data['results'] == 'changes-abandoned') {
+ $this->data['members'] = false;
+ return;
+ }
+
+ $text = $this->data['alertsearch'];
+ if ($this->data['mp_search']) {
+ $text = $this->data['mp_search'];
+ }
+ $errors = [];
+ if ($text != '') {
+ //$members_from_pids = array_values(\MySociety\TheyWorkForYou\Utility\Search::membersForIDs($this->data['alertsearch']));
+ $members_from_names = [];
+ $names_from_pids = array_values(\MySociety\TheyWorkForYou\Utility\Search::speakerNamesForIDs($text));
+ foreach ($names_from_pids as $name) {
+ $members_from_names = array_merge($members_from_names,\MySociety\TheyWorkForYou\Utility\Search::searchMemberDbLookupWithNames($name));
+ }
+ $members_from_words = \MySociety\TheyWorkForYou\Utility\Search::searchMemberDbLookupWithNames($text, true);
+ $this->data['members'] = array_merge($members_from_words, $members_from_names);
+ [$this->data['constituencies'], $this->data['valid_postcode']] = \MySociety\TheyWorkForYou\Utility\Search::searchConstituenciesByQuery($text, false);
+ } elseif ($this->data['pid']) {
+ $MEMBER = new \MEMBER(['person_id' => $this->data['pid']]);
+ $this->data['members'] = [[
+ "person_id" => $MEMBER->person_id,
+ "given_name" => $MEMBER->given_name,
+ "family_name" => $MEMBER->family_name,
+ "house" => $MEMBER->house_disp,
+ "title" => $MEMBER->title,
+ "lordofname" => $MEMBER->lordofname,
+ "constituency" => $MEMBER->constituency,
+ ]];
+ } elseif (isset($this->data['representative']) && $this->data['representative'] != '') {
+ $this->data['members'] = \MySociety\TheyWorkForYou\Utility\Search::searchMemberDbLookupWithNames($this->data['representative'], true);
+
+ $member_count = count($this->data['members']);
+ if ($member_count == 0) {
+ $errors["representative"] = gettext("No matching representative found");
+ } elseif ($member_count > 1) {
+ $errors["representative"] = gettext("Multiple matching representatives found, please select one.");
+ } else {
+ $this->data['pid'] = $this->data['members'][0]['person_id'];
+ }
} else {
$this->data['members'] = [];
}
@@ -167,24 +384,42 @@ private function searchForConstituenciesAndMembers() {
# If the above search returned one result for constituency
# search by postcode, use it immediately
if (isset($this->data['constituencies']) && count($this->data['constituencies']) == 1 && $this->data['valid_postcode']) {
- $MEMBER = new \MEMBER(['constituency' => $this->data['constituencies'][0], 'house' => 1]);
+ $MEMBER = new \MEMBER(['constituency' => array_values($this->data['constituencies'])[0], 'house' => 1]);
$this->data['pid'] = $MEMBER->person_id();
- $this->data['pc'] = $this->data['alertsearch'];
+ $this->data['pc'] = $text;
unset($this->data['constituencies']);
- $this->data['alertsearch'] = '';
}
if (isset($this->data['constituencies'])) {
$cons = [];
foreach ($this->data['constituencies'] as $constituency) {
try {
- $MEMBER = new \MEMBER(['constituency' => $constituency, 'house' => 1]);
+ $MEMBER = new \MEMBER(['constituency' => $constituency]);
$cons[$constituency] = $MEMBER;
} catch (\MySociety\TheyWorkForYou\MemberException $e) {
// do nothing
}
}
$this->data['constituencies'] = $cons;
+ if (count($cons) == 1) {
+ $cons = array_values($cons);
+ $this->data['pid'] = $cons[0]->person_id();
+ }
+ }
+
+ if ($this->data['alertsearch'] && !$this->data['mp_step'] && ($this->data['pid'] || $this->data['members'] || $this->data['constituencies'])) {
+ if (count($this->data['members']) == 1) {
+ $this->data['pid'] = $this->data['members'][0]['person_id'];
+ }
+ $this->data['mp_step'] = 'mp_alert';
+ $this->data['mp_search'] = $this->data['alertsearch'];
+ $this->data['alertsearch'] = '';
+ }
+
+ if (count($this->data["errors"]) > 0) {
+ $this->data["errors"] = array_merge($this->data["errors"], $errors);
+ } else {
+ $this->data["errors"] = $errors;
}
}
@@ -203,8 +438,12 @@ private function addAlert() {
$success = $this->alert->add($this->data, $confirm);
if ($success > 0 && !$confirm) {
+ $this->data['step'] = '';
+ $this->data['mp_step'] = '';
$result = 'alert-added';
} elseif ($success > 0) {
+ $this->data['step'] = '';
+ $this->data['mp_step'] = '';
$result = 'alert-confirmation';
} elseif ($success == -2) {
// we need to make sure we know that the person attempting to sign up
@@ -230,7 +469,8 @@ private function addAlert() {
$this->data['pc'] = '';
$this->data['results'] = $result;
- $this->data['criteria'] = \MySociety\TheyWorkForYou\Utility\Alert::prettifyCriteria($this->alert->criteria);
+ $this->data['criteria'] = $this->alert->criteria;
+ $this->data['display_criteria'] = \MySociety\TheyWorkForYou\Utility\Alert::prettifyCriteria($this->alert->criteria);
}
@@ -303,13 +543,55 @@ private function formatSearchMemberData() {
}
private function setUserData() {
+ if (!isset($this->data['criteria'])) {
+ $criteria = $this->data['keyword'];
+ if (!$this->data['match_all']) {
+ $has_or = strpos($criteria, ' OR ') !== false;
+ $missing_braces = strpos($criteria, '(') === false;
+
+ if ($has_or && $missing_braces) {
+ $criteria = "($criteria)";
+ }
+ }
+ if ($this->data['search_section']) {
+ $criteria .= " section:" . $this->data['search_section'];
+ }
+ if ($this->data['pid']) {
+ $criteria .= " speaker:" . $this->data['pid'];
+ }
+ $this->getRecentResults($criteria);
+
+ $this->data['criteria'] = $criteria;
+ $this->data['display_criteria'] = \MySociety\TheyWorkForYou\Utility\Alert::prettifyCriteria($criteria);
+ }
+ if ($this->data['results'] == 'changes-abandoned') {
+ $this->data['members'] = false;
+ $this->data['alertsearch'] = '';
+ }
+
+ if ($this->data['alertsearch'] && !(isset($this->data['mistakes']['postcode_and']) || $this->data['members'] || $this->data['pid'])) {
+ $this->data['step'] = 'define';
+ $this->data['words'] = [$this->data['alertsearch']];
+ $this->data['keywords'] = [$this->data['alertsearch']];
+ $this->data['exclusions'] = '';
+ $this->data['representative'] = '';
+ } elseif ($this->data['alertsearch'] && ($this->data['members'] || $this->data['pid'])) {
+ $this->data['mp_step'] = 'mp_alert';
+ $this->data['mp_search'] = [$this->data['alertsearch']];
+ } elseif ($this->data['members'] && $this->data['mp_step'] == 'mp_search') {
+ $this->data['mp_step'] = '';
+ }
+
$this->data['current_mp'] = false;
$this->data['alerts'] = [];
$this->data['keyword_alerts'] = [];
$this->data['speaker_alerts'] = [];
+ $this->data['spoken_alerts'] = [];
$this->data['own_member_alerts'] = [];
$this->data['all_keywords'] = [];
+ $this->data['own_mp_criteria'] = '';
$own_mp_criteria = '';
+
if ($this->data['email_verified']) {
if ($this->user->postcode()) {
$current_mp = new \MEMBER(['postcode' => $this->user->postcode()]);
@@ -317,18 +599,65 @@ private function setUserData() {
$this->data['current_mp'] = $current_mp;
$own_mp_criteria = sprintf('speaker:%s', $current_mp->person_id());
}
+ $own_mp_criteria = $current_mp->full_name();
+ $this->data['own_mp_criteria'] = $own_mp_criteria;
}
$this->data['alerts'] = \MySociety\TheyWorkForYou\Utility\Alert::forUser($this->data['email']);
foreach ($this->data['alerts'] as $alert) {
- if (array_key_exists('words', $alert)) {
- $this->data['all_keywords'][] = implode(' ', $alert['words']);
- $this->data['keyword_alerts'][] = $alert;
- } elseif (array_key_exists('spokenby', $alert) and sizeof($alert['spokenby']) == 1 and $alert['spokenby'][0] == $own_mp_criteria) {
+ if (array_key_exists('spokenby', $alert) and sizeof($alert['spokenby']) == 1 and $alert['spokenby'][0] == $own_mp_criteria) {
$this->data['own_member_alerts'][] = $alert;
- } else {
- $this->data['spoken_alerts'][] = $alert;
+ } elseif (array_key_exists('spokenby', $alert)) {
+ if (!array_key_exists($alert['spokenby'][0], $this->data['spoken_alerts'])) {
+ $this->data['spoken_alerts'][$alert['spokenby'][0]] = [];
+ }
+ $this->data['spoken_alerts'][$alert['spokenby'][0]][] = $alert;
}
}
+ foreach ($this->data['alerts'] as $alert) {
+ $term = implode(' ', $alert['words']);
+ $add = true;
+ if (array_key_exists('spokenby', $alert)) {
+ $add = false;
+ } elseif (array_key_exists($term, $this->data['spoken_alerts'])) {
+ $add = false;
+ $this->data['all_keywords'][] = $term;
+ $this->data['spoken_alerts'][$term][] = $alert;
+ } elseif ($term == $own_mp_criteria) {
+ $add = false;
+ $this->data['all_keywords'][] = $term;
+ $this->data['own_member_alerts'][] = $alert;
+ } elseif (\MySociety\TheyWorkForYou\Utility\Search::searchMemberDbLookupWithNames($term, true)) {
+ if (!array_key_exists($term, $this->data['spoken_alerts'])) {
+ $this->data['spoken_alerts'][$term] = [];
+ }
+ $add = false;
+ # need to add this to make it consistent so the front end know where to get the name
+ $alert['spokenby'] = [$term];
+ $this->data['all_keywords'][] = $term;
+ $this->data['spoken_alerts'][$term][] = $alert;
+ }
+ if ($add) {
+ $this->data['all_keywords'][] = $term;
+ $this->data['keyword_alerts'][] = $alert;
+ }
+ }
+ } else {
+ if ($this->data['alertsearch'] && $this->data['pc']) {
+ $this->data['mp_step'] = 'mp_alert';
+ }
+ }
+ if (count($this->data['alerts'])) {
+ $this->data['delete_token'] = $this->data['alerts'][0]['token'];
+ }
+ if ($this->data['addword'] != '' || ($this->data['step'] && count($this->data['errors']) > 0)) {
+ $this->data["step"] = get_http_var('this_step');
+ } else {
+ $this->data['this_step'] = '';
+ }
+
+ $this->data["search_term"] = $this->data['alertsearch'];
+ if ($this->data['mp_search']) {
+ $this->data["search_term"] = $this->data['mp_search'];
}
}
}
diff --git a/tests/AlertsPageTest.php b/tests/AlertsPageTest.php
index 6d62a781a7..91a2b15f24 100644
--- a/tests/AlertsPageTest.php
+++ b/tests/AlertsPageTest.php
@@ -15,6 +15,10 @@ 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);
@@ -22,12 +26,18 @@ public function testFetchPage() {
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(' 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() {
@@ -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(' fetch_page([ 'step' => 'review', 'email' => 'test@example.org', 'words[]' => 'fish']);
+ $this->assertStringContainsString('Review Your Alert', $page);
+ $this->assertStringContainsString(' fetch_page([ 'step' => 'confirm', 'email' => 'test@example.org', '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(' fetch_page([ 'step' => 'review', 'email' => 'test@example.org', 'words[]' => ['fish', 'salmon']]);
+ $this->assertStringContainsString('Review Your Alert', $page);
+ $this->assertStringContainsString(' assertStringContainsString(' fetch_page([ 'step' => 'confirm', 'email' => 'test@example.org', '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(' get_page([ 'step' => 'review', 'words[]' => ['fish', 'salmon']]);
+ $this->assertStringContainsString('Review Your Alert', $page);
+ $this->assertStringContainsString(' assertStringContainsString(' 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(' get_page(['step' => 'review', 'words[]' => 'fish', 'search_section' => 'debates']);
+ $this->assertStringContainsString('Review Your Alert', $page);
+ $this->assertStringContainsString(' 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(' get_page(['step' => 'review', 'words[]' => 'fish', 'representative' => 'Mrs Test Current-MP']);
+ $this->assertStringContainsString('Review Your Alert', $page);
+ $this->assertStringContainsString(' assertStringContainsString(' 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);
+ }
}
diff --git a/tests/SearchTest.php b/tests/SearchTest.php
index a99e0a6db3..0bd2e38fa7 100644
--- a/tests/SearchTest.php
+++ b/tests/SearchTest.php
@@ -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);
}
/**
@@ -169,9 +169,9 @@ public function testSearchPageMultipleCons() {
$page = $this->fetch_page([ 'q' => 'Liverpool' ]);
$this->assertStringContainsString('MPs in constituencies matching Liverpool ', $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);
}
/**
diff --git a/tests/_fixtures/alertspage.xml b/tests/_fixtures/alertspage.xml
index e237dec30d..b1c65e678c 100644
--- a/tests/_fixtures/alertspage.xml
+++ b/tests/_fixtures/alertspage.xml
@@ -150,6 +150,14 @@
+
+ 1
+ Test
+ User
+ user@example.org
+ $2y$10$UNelQZqpPpO1jT.f7DLgeOdp.WBT81c5ECvOeTMFeQTBTyq3aCh8q
+ 1
+
diff --git a/www/docs/js/main.js b/www/docs/js/main.js
index 6dd194a9f0..9f319d38f9 100644
--- a/www/docs/js/main.js
+++ b/www/docs/js/main.js
@@ -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
@@ -423,6 +445,48 @@ function wrap_error($message){
return '';
}
+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() {
diff --git a/www/docs/style/sass/_twfy-mixins.scss b/www/docs/style/sass/_twfy-mixins.scss
index 05e5f4169c..5c7a50ce45 100644
--- a/www/docs/style/sass/_twfy-mixins.scss
+++ b/www/docs/style/sass/_twfy-mixins.scss
@@ -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;
@@ -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%);
diff --git a/www/docs/style/sass/app.scss b/www/docs/style/sass/app.scss
index d356a39cd9..511351cd8c 100644
--- a/www/docs/style/sass/app.scss
+++ b/www/docs/style/sass/app.scss
@@ -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,
@@ -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
@@ -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 {
@@ -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;
}
@@ -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;
}
@@ -198,7 +212,7 @@ a:focus {
// for .button elements!!
vertical-align: -0.4em;
}
-
+
&.tertiary {
@include button-style($bg: $links);
}
@@ -231,6 +245,7 @@ form {
@import "parts/panels";
@import "parts/promo-banner";
+@import "parts/accordion";
@import "pages/mp";
@import "pages/topics";
diff --git a/www/docs/style/sass/pages/_alert.scss b/www/docs/style/sass/pages/_alert.scss
index 23aeab8d98..ff0e5b90ea 100644
--- a/www/docs/style/sass/pages/_alert.scss
+++ b/www/docs/style/sass/pages/_alert.scss
@@ -283,6 +283,11 @@
}
}
+.alert-section--message {
+ background-color: #FFFCD9; // very light yellow
+ padding: 1rem;
+}
+
.alert-section--disambiguation {
li {
margin: 1em 0;
diff --git a/www/docs/style/sass/parts/_accordion.scss b/www/docs/style/sass/parts/_accordion.scss
new file mode 100644
index 0000000000..4c44111154
--- /dev/null
+++ b/www/docs/style/sass/parts/_accordion.scss
@@ -0,0 +1,280 @@
+.label {
+ background-color: #fff;
+ color: $primary-color;
+ padding: 0.25rem 0.5rem;
+ border-radius: 1rem;
+ font-size: 0.75rem;
+
+ &--primary-light {
+ background-color: $primary-color-200;
+ color: $body-font-color;
+ }
+
+ &--red {
+ background-color: lighten($color-red, 40%);
+ color: $body-font-color;
+ }
+}
+
+.alert-page-header {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+
+ button, h2 {
+ margin-bottom: 0;
+ margin-top: 0;
+ }
+
+ .alert-page-header__button-group {
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ input {
+ margin-bottom: 0;
+ }
+ }
+}
+
+.accordion {
+ margin-top: 2rem;
+}
+
+.accordion-button {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ text-align: left;
+ padding: 0.5rem;
+ font-size: 1rem;
+ font-weight: 400;
+ cursor: pointer;
+ border: none;
+ color: $body-font-color;
+ background-color: $primary-color-200;
+
+ &[aria-expanded="true"] {
+ background-color: lighten($primary-color-100, 6%);
+ color: $body-font-color;
+ border: 1px solid $primary-color;
+ & + .accordion-content{
+ max-height: 1000px;
+ transition: max-height 0.3s ease;
+ }
+
+ i {
+ transform: rotate(45deg);
+ }
+ }
+
+}
+
+.accordion-button--content {
+ display: flex;
+ flex-direction: row;
+ align-content: center;
+ align-items: center;
+ gap: 0.75rem;
+
+ .content-subtitle {
+ @extend .label;
+ }
+}
+
+.accordion-content {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.3s ease;
+ padding-left: 1rem;
+
+ .alert-controller-wrapper {
+ margin-bottom: 2rem;
+ form {
+ display: inline;
+ }
+
+ button {
+ margin-bottom: 0;
+ span {
+ margin-right: 0.2rem;
+ }
+ }
+
+ button.alert {
+ background-color: $color-red;
+ color: #fff;
+ }
+ }
+
+ .add-remove-tool {
+ display: flex;
+ flex-direction: row;
+
+ input {
+ margin: 0;
+ height: 40px;
+ }
+
+ button {
+ max-width: 100px;
+ height: 40px;
+ }
+ }
+
+ label {
+ font-size: inherit;
+ color: inherit;
+ }
+
+ select {
+ max-width: 350px;
+ }
+}
+
+.alert-page-alert-controls {
+ form {
+ display: inline;
+ }
+}
+
+.keyword-list {
+ ul {
+ list-style: none;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-left: 0;
+
+ li {
+ font-weight: bold;
+ i {
+ margin-left: 0.25rem;
+ }
+ }
+
+ }
+}
+
+.heading-with-bold-word {
+ font-weight: 400;
+
+ span {
+ font-weight: bold;
+ }
+}
+
+.alert-meta-info {
+
+ .alert-meta-info-results {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ column-gap: 1rem;
+ row-gap: 1rem;
+ align-items: center;
+ margin-bottom: 1rem;
+
+ .content-header-item {
+ border-radius: 0.5rem;
+ background-color: $primary-color-200;
+ padding: 1rem;
+
+ dt {
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ margin-bottom: 0;
+ }
+
+ dd {
+ margin-bottom: 0;
+ font-size: 1.1rem;
+ }
+ }
+ }
+
+}
+
+button {
+ i {
+ margin-right: 0.15rem;
+ }
+}
+
+.alert-page-section {
+ margin-bottom: 3rem;
+}
+
+.alert-page-subsection {
+ margin-bottom: 2.5rem;
+
+ .alert-page-subsection--subtitle {
+ margin-bottom: 0.5rem;
+ }
+
+ :last-child {
+ margin-bottom: 0;
+ }
+}
+
+.alert-page-option-label {
+ display: inline;
+ margin-left: 0.5em;
+}
+
+.button.red {
+ background-color: $color-red;
+ color: #fff;
+
+ &:hover {
+ background-color: darken($color-red, 15%);
+ }
+}
+
+#create-alert-form {
+ label {
+ color: $body-font-color;
+ font-size: 1.1rem;
+ line-height: 1.2;
+ margin-bottom: 0.75rem;
+ }
+
+ input[type="checkbox"], input[type="radio"] {
+ display: inline-block;
+ height: 1.5rem;
+ width: 1.5rem;
+ margin: 0 0.25rem 0 0;
+ vertical-align: middle;
+
+ + label {
+ display: inline-block;
+ margin-bottom: 0;
+ line-height: 1.5rem;
+ vertical-align: middle;
+ }
+ }
+
+ input[type="text"], select {
+ max-width: 400px;
+ height: 40px;
+ border-color: $body-font-color;
+ }
+
+ .checkbox-wrapper {
+ display: flex;
+ flex-direction: row;
+
+ input[type="checkbox"], input[type="radio"] {
+ flex-shrink: 0;
+ }
+ }
+
+ .checkbox-group {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 1rem;
+ }
+}
diff --git a/www/includes/easyparliament/alert.php b/www/includes/easyparliament/alert.php
index 66493d36e8..226b6991e6 100644
--- a/www/includes/easyparliament/alert.php
+++ b/www/includes/easyparliament/alert.php
@@ -104,6 +104,43 @@ public function fetch($confirmed, $deleted) {
return $data;
}
+ public function get_related_terms($term) {
+ $q = $this->db->query("SELECT
+ search_suggestion
+ FROM vector_search_suggestions
+ WHERE search_term = :term", [
+ ':term' => $term,
+ ]);
+
+ $data = $q->fetchAll();
+ $related = [];
+ foreach ($data as $d) {
+ $related[] = $d['search_suggestion'];
+ }
+ return $related;
+ }
+
+ public function update($id, $details) {
+ $criteria = \MySociety\TheyWorkForYou\Utility\Alert::detailsToCriteria($details);
+
+ $q = $this->db->query("SELECT * FROM alerts
+ WHERE alert_id = :id", [
+ ':id' => $id,
+ ])->first();
+ if ($q) {
+ $q = $this->db->query("UPDATE alerts SET deleted = 0, criteria = :criteria, confirmed = 1
+ WHERE alert_id = :id", [
+ ":criteria" => $criteria,
+ ":id" => $id,
+ ]);
+
+ if ($q->success()) {
+ return 1;
+ }
+ }
+ return -1;
+ }
+
public function add($details, $confirmation_email = false, $instantly_confirm = true) {
// Adds a new alert's info into the database.
diff --git a/www/includes/easyparliament/templates/html/alert/_alert_form.php b/www/includes/easyparliament/templates/html/alert/_alert_form.php
new file mode 100644
index 0000000000..91a39f82a6
--- /dev/null
+++ b/www/includes/easyparliament/templates/html/alert/_alert_form.php
@@ -0,0 +1,339 @@
+
+
+
+
+
+ = gettext('Edit Alert') ?>
+
+ = gettext('Create Alert') ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
= gettext('Search tips') ?>
+
+ = gettext('To be alerted on an exact phrase , be sure to put it in quotes. Also use quotes around a word to avoid stemming (where ‘horse’ would also match ‘horses’).') ?>
+
+
+ = gettext('You should only enter one term per alert – if you wish to receive alerts on more than one thing, or for more than one person, simply fill in this form as many times as you need, or use boolean OR.') ?>
+
+
+ = gettext('For example, if you wish to receive alerts whenever the words horse or pony are mentioned in Parliament, please fill in this form once with the word horse and then again with the word pony (or you can put horse OR pony with the OR in capitals). Do not put horse, pony as that will only sign you up for alerts where both horse and pony are mentioned.') ?>
+
+
+
+
+
+
= gettext('Step by step guides') ?>
+
+ = gettext('The mySociety blog has a number of posts on signing up for and managing alerts:') ?>
+
+
+
+
+
+
diff --git a/www/includes/easyparliament/templates/html/alert/_list_accordian.php b/www/includes/easyparliament/templates/html/alert/_list_accordian.php
new file mode 100644
index 0000000000..fb1065f292
--- /dev/null
+++ b/www/includes/easyparliament/templates/html/alert/_list_accordian.php
@@ -0,0 +1,226 @@
+
+ $alert) { ?>
+
+
+
+ = _htmlspecialchars($alert['criteria']) ?>
+
+ = sprintf(gettext('%d mentions this week'), $alert['mentions']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Keywords included in this alert:
+
+
+ = _htmlspecialchars($keyword) ?>
+
+
+
+
+
+
+
+
Keywords excluded in this alert:
+
+
+ = _htmlspecialchars($exclusion) ?>
+
+
+
+
+
+
+
+
Which section should this alert apply to:
+
+
+ = _htmlspecialchars($section) ?>
+
+
+
+
+
+
+
+
+
+
= gettext('This alert applies to the following representative ') ?>
+
+
+
+
+
+
+
+
+
+
+
+
= gettext('Your MP') ?>
+
+
+ = sprintf(gettext('You are not subscribed to an alert for your current MP, %s'), '' . htmlspecialchars($current_mp->full_name()) . ' ') ?>, speaks.
+
+
+
+ 0) { ?>
+
+
+ = gettext('You are subscribed to the following alerts about your MP.') ?>
+
+
+
+
+
Alert when = _htmlspecialchars($own_mp_criteria) ?> is mentioned
+
+
+
+ 0) { ?>
+
+
= gettext('Your MP') ?> ﹒ = $own_member_alerts[0]['spokenby'][0] ?>
+
+
+
+
+
+
+
+
+
= _htmlspecialchars(implode(', ', $person_alerts[0]['spokenby'])) ?>
+
+
+
= _htmlspecialchars($alert['criteria']) ?>
+
+
+
+
+
+
+
Alert when = _htmlspecialchars(implode(', ', $person_alerts[0]['spokenby'])) ?> is mentioned
+
+
+
+
+
diff --git a/www/includes/easyparliament/templates/html/alert/_mp_alert_form.php b/www/includes/easyparliament/templates/html/alert/_mp_alert_form.php
new file mode 100644
index 0000000000..5746c14aed
--- /dev/null
+++ b/www/includes/easyparliament/templates/html/alert/_mp_alert_form.php
@@ -0,0 +1,76 @@
+ 0) {
+ $member_options = true; ?>
+ = sprintf(gettext('Sign up for alerts when Representatives for constituencies matching %s speaks'), _htmlspecialchars($search_term)) ?>
+
+ $member) { ?>
+
+
+
+
+
+
+
+
diff --git a/www/includes/easyparliament/templates/html/alert/_own_mp_alerts.php b/www/includes/easyparliament/templates/html/alert/_own_mp_alerts.php
new file mode 100644
index 0000000000..d8d51e2fdb
--- /dev/null
+++ b/www/includes/easyparliament/templates/html/alert/_own_mp_alerts.php
@@ -0,0 +1,49 @@
+
+
+= _htmlspecialchars($alert['criteria']) ?>
+
+
+
+
+
+
+
+
+Alert when = _htmlspecialchars($own_mp_criteria) ?> is mentioned
+
+
diff --git a/www/includes/easyparliament/templates/html/alert/index.php b/www/includes/easyparliament/templates/html/alert/index.php
index 8f4deef191..12af929ee3 100644
--- a/www/includes/easyparliament/templates/html/alert/index.php
+++ b/www/includes/easyparliament/templates/html/alert/index.php
@@ -20,7 +20,7 @@
= gettext('You will now receive email alerts for the following criteria:') ?>
- = _htmlspecialchars($criteria) ?>
+ = _htmlspecialchars($display_criteria) ?>
= gettext('This is normally the day after, but could conceivably be later due to issues at our or the parliament’s end.') ?>
@@ -83,7 +83,7 @@
= gettext('Your alert has been added') ?>
- = sprintf(gettext('You will now receive email alerts on any day when %s in parliament.'), _htmlspecialchars($criteria)) ?>
+ = sprintf(gettext('You will now receive email alerts on any day when %s in parliament.'), _htmlspecialchars($display_criteria)) ?>
@@ -104,6 +104,11 @@
= gettext('You should receive an email shortly which will contain a link. You will need to follow that link to confirm your email address and receive future alerts. Thanks.') ?>
+
+ = gettext('Changes abandoned') ?>
+
+ = gettext('Those changes have been abandoned and your alerts are unchanged.') ?>
+
= gettext('Alert could not be created') ?>
@@ -115,11 +120,22 @@
-
+
+
+
= gettext("Create an MP Alert") ?>
+
+
+
+
+ 0) ||
- ($alertsearch)
+ !$results && (
+ $members ||
+ (isset($constituencies) && count($constituencies) > 0) ||
+ ($alertsearch)
+ )
) {
/* We need to disambiguate the user's instructions */
$member_options = false;
@@ -129,7 +145,7 @@
- = sprintf(gettext('Sign up for alerts when people matching %s speaks'), _htmlspecialchars($alertsearch)) ?>
+ = sprintf(gettext('Sign up for alerts when people matching %s speaks'), _htmlspecialchars($search_term)) ?>
0) {
$member_options = true; ?>
- = sprintf(gettext('Sign up for alerts when MPs for constituencies matching %s speaks'), _htmlspecialchars($alertsearch)) ?>
+ = sprintf(gettext('Sign up for alerts when MPs for constituencies matching %s speaks'), _htmlspecialchars($search_term)) ?>
$member) { ?>
@@ -172,30 +188,11 @@
- = gettext('Sign up for alerts for topics') ?>
-
- = gettext('Great! Can you just confirm what you mean?') ?>
-
+ if (!$member_options) { ?>
+ = gettext('That doesn’t match a person, postcode or constituency. Search again to refine your email alert.') ?>
+
-
-
- = gettext('
- You have used a comma in your search term –
- are you sure this is what you want? You cannot
- sign up to multiple search terms using a comma
- – either use OR, or create a separate alert
- for each individual term.') ?>
-
-
-
= gettext('
You have used a postcode and something else in your
search term – are you sure this is what you
@@ -205,17 +202,18 @@
printf(gettext('Did you mean to get alerts for when your representative mentions something instead? If so maybe you want to subscribe to…'));
} ?>
-
-
+
@@ -224,10 +222,12 @@
@@ -237,143 +237,106 @@
+
+ = gettext('Do you want alerts for a word or phrase?') ?>
+
+ = gettext('Not quite right? Search again to refine your email alert.') ?>
+
+
-
+
-
-
-
-
-
-
-
-
-
= gettext('Your MP alert') ?>
-
-
- = sprintf(gettext('You are not subscribed to an alert for your current MP, %s'), $current_mp->full_name()) ?>.
-
-
-
-
-
-
+
+
= sprintf(gettext('If you join or sign in , you can suspend, resume and delete your email alerts from your profile page.'), '/user/?pg=join', '/user/login/?ret=%2Falert%2F') ?>
= gettext('Plus, you won’t need to confirm your email address for every alert you set.') ?>
-
-
-
-
-
-
-
- full_name();
- if ($pid_member->constituency()) {
- $name .= ' (' . _htmlspecialchars($pid_member->constituency()) . ')';
- } ?>
- = sprintf(gettext('Sign up for an alert when %s speaks.'), $name) ?>
-
-
-
- = sprintf(gettext('Sign up for an alert when %s.'), _htmlspecialchars($display_keyword)) ?>
-
-
-
= gettext('Not quite right? Search again to refine your email alert.') ?>
-
-
= gettext('Request a new TheyWorkForYou email alert') ?>
-
-
-
-
+
+