diff --git a/.cypress/cypress/integration/category_tests.js b/.cypress/cypress/integration/category_tests.js
index 8cd72b50db..bcb543a3cd 100644
--- a/.cypress/cypress/integration/category_tests.js
+++ b/.cypress/cypress/integration/category_tests.js
@@ -13,7 +13,7 @@ describe('Basic categories', function() {
'Footpath/bridleway away from road',
'Graffiti',
'Offensive graffiti',
- 'Licensing',
+ 'G|Licensing',
'Parks/landscapes',
'Pavements',
'Potholes',
@@ -75,7 +75,7 @@ describe('Basic categories', function() {
cy.get('[value="Abandoned vehicles"]').should('not.be.visible');
cy.get('[value="Bus stops"]').should('not.be.visible');
cy.get('[value="Flyposting"]').should('not.be.visible');
- cy.get('[value="Licensing"]').should('be.visible');
+ cy.get('[value="G|Licensing"]').should('be.visible');
cy.get('[value="Dropped Kerbs"]').should('be.visible');
cy.get('[value="Skips"]').should('be.visible');
cy.get('[value="Street lighting"]').should('be.visible');
@@ -84,7 +84,7 @@ describe('Basic categories', function() {
cy.get('[value="Abandoned vehicles"]').should('not.be.visible');
cy.get('[value="Bus stops"]').should('be.visible');
cy.get('[value="Flyposting"]').should('not.be.visible');
- cy.get('[value="Licensing"]').should('be.visible');
+ cy.get('[value="G|Licensing"]').should('be.visible');
cy.get('[value="Dropped Kerbs"]').should('not.be.visible');
cy.get('[value="Skips"]').should('be.visible');
cy.get('[value="Road traffic signs"]').should('be.visible');
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 1971087777..785c4708d1 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -843,6 +843,7 @@ sub stash_category_groups : Private {
(my $id = $_) =~ s/[^a-zA-Z]+//g;
if (@{$category_groups{$_}} == 1) {
my $contact = $category_groups{$_}[0];
+ $contact->set_extra_metadata(hoisted => $_);
push @list, [ $contact->category_display, $contact ];
} else {
my $cats = $category_groups{$_};
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 400548923f..ad1b1731ae 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -1823,19 +1823,22 @@ sub generate_map : Private {
sub check_for_category : Private {
my ( $self, $c, $opts ) = @_;
- my $category;
- if (!$opts->{with_group}) {
- $category = $c->get_param('category') || '';
- } else {
- # Group is either an actual group, or a category that wasn't in a group
- my $group = $c->get_param('category') || $c->get_param('filter_group') || '';
- if (any { $_->{name} && $group eq $_->{name} } @{$c->stash->{category_groups}}) {
+ my $category = $c->get_param('category') || '';
+ if ($opts->{with_group}) {
+ if (my ($group) = $category =~ /^G\|(.*)/) {
+ # A top-level group
$c->stash->{group} = $c->stash->{filter_group} = $group;
(my $group_id = $group) =~ s/[^a-zA-Z]+//g;
my $cat_param = "category.$group_id";
$category = $c->get_param($cat_param);
- } else {
- $category = $group;
+ } elsif ($category =~ /^H\|(.*?)\|(.*)/) {
+ # A hoisted to top-level category
+ ($group, $category) = ($1, $2);
+ $c->stash->{group} = $c->stash->{filter_group} = $group;
+ } elsif (!$category && ($group = $c->get_param('filter_group'))) {
+ if (any { $_->{name} && $group eq $_->{name} } @{$c->stash->{category_groups}}) {
+ $c->stash->{group} = $c->stash->{filter_group} = $group;
+ }
}
}
$category ||= $c->stash->{report}->category || '';
diff --git a/t/app/controller/auth_social.t b/t/app/controller/auth_social.t
index 4211e56054..6a4fc89972 100644
--- a/t/app/controller/auth_social.t
+++ b/t/app/controller/auth_social.t
@@ -129,7 +129,7 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) {
$mech->submit_form_ok( { with_fields => { pc => $test->{pc} || 'SW1A1AA' } }, "submit location" );
$mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" );
$mech->submit_form(with_fields => {
- category => 'Bins',
+ category => 'G|Bins',
'category.Bins' => 'Damaged bin',
title => 'Test title',
detail => 'Test detail',
@@ -173,7 +173,7 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) {
if ($page eq 'report') {
$mech->content_contains('/report/new');
$mech->content_contains('Salt bin');
- $mech->content_contains('name="category" value="Bins" data-subcategory="Bins" checked');
+ $mech->content_like(qr{value="G|Bins"\s+data-subcategory="Bins" checked});
$mech->content_contains('name="category.Bins" data-category_display="Damaged bin" value=\'Damaged bin\' checked');
} elsif ($page eq 'update') {
$mech->content_contains('/report/update');
@@ -319,7 +319,7 @@ for my $tw_state ( 'refused', 'existing UID', 'no email' ) {
$mech->submit_form_ok( { with_fields => { pc => 'SW1A1AA' } }, "submit location" );
$mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" );
$mech->submit_form(with_fields => {
- category => 'Bins',
+ category => 'G|Bins',
'category.Bins' =>'Damaged bin',
title => 'Test title',
detail => 'Test detail',
diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t
index 08c0496bb0..624b0abb63 100644
--- a/t/app/controller/report_new.t
+++ b/t/app/controller/report_new.t
@@ -680,9 +680,9 @@ subtest "category groups" => sub {
my $div = '
]*>\s*';
my $div_end = '
\s*';
my $pavements_label = '\s*' . $div_end;
- my $pavements_input = ']* value="Pavements" data-subcategory="Pavements">\s*';
- my $pavements_input_checked = ']* value="Pavements" data-subcategory="Pavements" checked>\s*';
- my $roads = $div . ']* value="Roads" data-subcategory="Roads">\s*\s*' . $div_end;
+ my $pavements_input = ']* value="G|Pavements"\s+data-subcategory="Pavements">\s*';
+ my $pavements_input_checked = ']* value="G|Pavements"\s+data-subcategory="Pavements" checked>\s*';
+ my $roads = $div . ']* value="G|Roads"\s+data-subcategory="Roads">\s*\s*' . $div_end;
my $trees_label = '\s*' . $div_end;
my $trees_input = $div . ']* value=\'Trees\'>\s*';
my $trees_input_checked = $div . ']* value=\'Trees\' checked>\s*';
@@ -708,18 +708,28 @@ subtest "category groups" => sub {
$mech->content_like(qr{$fieldset_pavements$options});
$mech->content_like(qr{$fieldset_roads$options});
# Server submission of pavement subcategory
- $mech->get_ok("/report/new?lat=$saved_lat&lon=$saved_lon&category=Pavements&category.Pavements=Potholes");
+ $mech->get_ok("/report/new?lat=$saved_lat&lon=$saved_lon&category=G|Pavements&category.Pavements=Potholes");
$mech->content_like(qr{$pavements_input_checked$pavements_label$roads$trees_input$trees_label});
$mech->content_like(qr{$fieldset_pavements$optionsS});
$mech->content_like(qr{$fieldset_roads$options});
$contact9->update( { extra => { group => 'Lights' } } );
$mech->get_ok("/report/new?lat=$saved_lat&lon=$saved_lon");
- $streetlighting = $div . ']*value=\'Street lighting\'>\s*\s*' . $div_end;
+ $streetlighting = $div . ']*value=\'H|Lights\|Street lighting\'>\s*\s*' . $div_end;
+ $potholes_input = $div . ']* value=\'H|Pavements\|Potholes\'>\s*';
$potholes_label = '\s*' . $div_end;
$mech->content_like(qr{$potholes_input$potholes_label$roads$streetlighting$trees_input$trees_label});
$mech->content_unlike(qr{$fieldset_pavements});
$mech->content_like(qr{$fieldset_roads$options});
+
+ $mech->submit_form_ok({ with_fields => {
+ category => 'H|Lights|Street lighting',
+ title => 'Test Report',
+ detail => 'Test report details',
+ username_register => 'jo@example.org',
+ name => 'Jo Bloggs',
+ } });
+ $mech->content_contains('Now check your email');
};
};
diff --git a/t/cobrand/brent.t b/t/cobrand/brent.t
index f3b93eb03d..799a829424 100644
--- a/t/cobrand/brent.t
+++ b/t/cobrand/brent.t
@@ -927,7 +927,7 @@ FixMyStreet::override_config {
with_fields => {
title => "Test Report",
detail => 'Test report details.',
- category => 'Parks and open spaces',
+ category => 'G|Parks and open spaces',
'category.Parksandopenspaces' => 'Overgrown grass',
}
}, "submit details");
@@ -951,7 +951,7 @@ FixMyStreet::override_config {
with_fields => {
title => "Test Report",
detail => 'Test report details.',
- category => 'Parks and open spaces',
+ category => 'G|Parks and open spaces',
'category.Parksandopenspaces' => 'Overgrown grass',
}
}, "submit details");
@@ -970,7 +970,7 @@ FixMyStreet::override_config {
with_fields => {
title => "Test Report",
detail => 'Test report details.',
- category => 'Parks and open spaces',
+ category => 'G|Parks and open spaces',
'category.Parksandopenspaces' => 'Overgrown grass',
}
}, "submit details");
@@ -994,7 +994,7 @@ FixMyStreet::override_config {
with_fields => {
title => "Test Report",
detail => 'Test report details.',
- category => 'Parks and open spaces',
+ category => 'G|Parks and open spaces',
'category.Parksandopenspaces' => 'Ponds',
}
}, "submit details");
diff --git a/t/cobrand/northumberland.t b/t/cobrand/northumberland.t
index 0e5d51c38f..7764597bcd 100644
--- a/t/cobrand/northumberland.t
+++ b/t/cobrand/northumberland.t
@@ -87,7 +87,7 @@ FixMyStreet::override_config {
$mech->content_contains('Main Carriageway');
$mech->content_contains('Potholes');
$mech->content_contains("Trees'>");
- $mech->content_contains('value=\'Flytipping\' data-nh="1"');
+ $mech->content_contains('value=\'H|Staff Only - Out Of Hours|Flytipping\' data-nh="1"');
# A-road where NH responsible for litter, council categories will also be present
mock_road("A5103", 1);
@@ -97,7 +97,7 @@ FixMyStreet::override_config {
$mech->content_contains('Main Carriageway');
$mech->content_contains('Potholes');
$mech->content_contains('Trees\'>');
- $mech->content_contains('value=\'Flytipping\' data-nh="1"');
+ $mech->content_contains('value=\'H|Staff Only - Out Of Hours|Flytipping\' data-nh="1"');
# A-road where NH not responsible for litter, no NH litter categories
mock_road("A34", 0);
@@ -107,7 +107,7 @@ FixMyStreet::override_config {
$mech->content_lacks('Main Carriageway');
$mech->content_contains('Potholes');
$mech->content_contains('Trees\'>');
- $mech->content_contains('value=\'Flytipping\' data-nh="1"');
+ $mech->content_contains('value=\'H|Staff Only - Out Of Hours|Flytipping\' data-nh="1"');
};
};
diff --git a/templates/web/base/report/new/category.html b/templates/web/base/report/new/category.html
index e83a73a3b8..7efcd900eb 100644
--- a/templates/web/base/report/new/category.html
+++ b/templates/web/base/report/new/category.html
@@ -24,7 +24,12 @@
[%~ FOREACH group_or_cat IN category_groups ~%]
[% IF group_or_cat.name %]
-
+
[% group_hint = group_or_cat.categories.first.get_extra_metadata('group_hint') %]
[%~ IF group_hint %]
@@ -32,9 +37,15 @@
[% group_hint | safe %]
[% END ~%]
- [% ELSE # A category not in a group %]
- [% cat_lc = group_or_cat.category | lower =%]
-
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index de09f6df3d..0e7716e2f4 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -1848,11 +1848,11 @@ function re_select(group, category) {
var group_id = group.replace(/[^a-z]+/gi, '');
var cat_in_group = $("#subcategory_" + group_id + " input[value=\"" + category + "\"]");
if (cat_in_group.length) {
- $('#form_category_fieldset input[value="' + group + '"]')[0].checked = true;
+ $('#form_category_fieldset input[data-valuealone="' + group + '"]')[0].checked = true;
cat_in_group[0].checked = true;
} else {
var top_level = group || category;
- var top_level_match = $("#form_category_fieldset input[value=\"" + top_level + "\"]");
+ var top_level_match = $("#form_category_fieldset input[data-valuealone=\"" + top_level + "\"]");
if (top_level && top_level_match.length) {
top_level_match[0].checked = true;
}
@@ -1976,7 +1976,7 @@ fixmystreet.fetch_reporting_data = function() {
fixmystreet.reporting = {};
fixmystreet.reporting.selectedCategory = function() {
var $group_or_cat_input = $('#form_category_fieldset input:checked'),
- group_or_cat = $group_or_cat_input.val() || '',
+ group_or_cat = $group_or_cat_input.data('valuealone') || '',
group_id = group_or_cat.replace(/[^a-z]+/gi, ''),
$subcategory = $("#subcategory_" + group_id),
$subcategory_input = $subcategory.find('input:checked'),