diff options
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Dashboard.pm | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Reports.pm | 93 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/FixMyStreet.pm | 5 | ||||
-rw-r--r-- | t/cobrand/fixmystreet.t | 1 | ||||
-rwxr-xr-x | templates/web/base/reports/index.html | 54 | ||||
-rw-r--r-- | templates/web/fixmystreet.com/reports/summary.html | 173 |
6 files changed, 260 insertions, 74 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm index 5fe473c54..cff4c8dab 100644 --- a/perllib/FixMyStreet/App/Controller/Dashboard.pm +++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm @@ -175,15 +175,15 @@ sub generate_data { $state_map->{$_} = 'closed' foreach FixMyStreet::DB::Result::Problem->closed_states; $state_map->{$_} = 'fixed' foreach FixMyStreet::DB::Result::Problem->fixed_states; - $self->generate_grouped_data($c); + $c->forward('generate_grouped_data'); $self->generate_summary_figures($c); } -sub generate_grouped_data { +sub generate_grouped_data : Private { my ($self, $c) = @_; my $state_map = $c->stash->{state_map}; - my $group_by = $c->get_param('group_by') || ''; + my $group_by = $c->get_param('group_by') || $c->stash->{group_by_default} || ''; my (%grouped, @groups, %totals); if ($group_by eq 'category') { %grouped = map { $_->category => {} } @{$c->stash->{contacts}}; @@ -197,6 +197,8 @@ sub generate_grouped_data { ); } elsif ($group_by eq 'device+site') { @groups = qw/cobrand service/; + } elsif ($group_by eq 'device') { + @groups = qw/service/; } else { $group_by = 'category+state'; @groups = qw/category state/; diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index b6281f0ca..5ac3da197 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -69,19 +69,8 @@ sub index : Path : Args(0) { } } - my $dashboard = eval { - my $data = FixMyStreet->config('TEST_DASHBOARD_DATA'); - # uncoverable branch true - unless ($data) { - my $fn = '../data/all-reports-dashboard'; - if ($c->stash->{body}) { - $fn .= '-' . $c->stash->{body}->id; - } - $data = decode_json(path(FixMyStreet->path_to($fn . '.json'))->slurp_utf8); - } - $c->stash($data); - return 1; - }; + my $dashboard = $c->forward('load_dashboard_data'); + my $table = !$c->stash->{body} && eval { my $data = path(FixMyStreet->path_to('../data/all-reports.json'))->slurp_utf8; $c->stash(decode_json($data)); @@ -425,6 +414,65 @@ sub ward_check : Private { $c->detach( 'redirect_body' ); } +=head2 summary + +This is the summary page used on fixmystreet.com + +=cut + +sub summary : Private { + my ($self, $c) = @_; + my $dashboard = $c->forward('load_dashboard_data'); + + eval { + my $data = path(FixMyStreet->path_to('../data/all-reports-dashboard.json'))->slurp_utf8; + $data = decode_json($data); + $c->stash( + top_five_bodies => $data->{top_five_bodies}, + average => $data->{average}, + ); + }; + + my $dtf = $c->model('DB')->storage->datetime_parser; + my $period = $c->stash->{period} = $c->get_param('period') || ''; + my $start_date; + if ($period eq 'ever') { + $start_date = DateTime->new(year => 2007); + } elsif ($period eq 'year') { + $start_date = DateTime->now->subtract(years => 1); + } elsif ($period eq '3months') { + $start_date = DateTime->now->subtract(months => 3); + } elsif ($period eq 'week') { + $start_date = DateTime->now->subtract(weeks => 1); + } else { + $c->stash->{period} = 'month'; + $start_date = DateTime->now->subtract(months => 1); + } + + # required to stop errors in generate_grouped_data + $c->stash->{q_state} = ''; + $c->stash->{ward} = $c->get_param('ward'); + $c->stash->{start_date} = $dtf->format_date($start_date); + $c->stash->{end_date} = $c->get_param('end_date'); + + $c->stash->{group_by_default} = 'category'; + + my $area_id = $c->stash->{body}->body_areas->first->area_id; + my $children = mySociety::MaPit::call('area/children', $area_id, + type => $c->cobrand->area_types_children, + ); + $c->stash->{children} = $children; + + $c->forward('/admin/fetch_contacts'); + $c->stash->{contacts} = [ $c->stash->{contacts}->all ]; + + $c->forward('/dashboard/construct_rs_filter'); + + $c->forward('/dashboard/generate_grouped_data'); + + $c->stash->{template} = 'reports/summary.html'; +} + =head2 check_canonical_url Given an already found (case-insensitively) body, check what URL @@ -441,6 +489,25 @@ sub check_canonical_url : Private { $c->detach( 'redirect_body' ) unless $body_short eq $url_short; } +sub load_dashboard_data : Private { + my ($self, $c) = @_; + my $dashboard = eval { + my $data = FixMyStreet->config('TEST_DASHBOARD_DATA'); + # uncoverable branch true + unless ($data) { + my $fn = '../data/all-reports-dashboard'; + if ($c->stash->{body}) { + $fn .= '-' . $c->stash->{body}->id; + } + $data = decode_json(path(FixMyStreet->path_to($fn . '.json'))->slurp_utf8); + } + $c->stash($data); + return 1; + }; + + return $dashboard; +} + sub load_and_group_problems : Private { my ( $self, $c ) = @_; diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm index 2153ca33b..591234877 100644 --- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm +++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm @@ -81,14 +81,13 @@ sub council_dashboard_hook { } $c->forward('/admin/fetch_contacts'); - $c->stash->{display_contacts} = 1; - return if $c->user->is_superuser; + $c->detach('/reports/summary') if $c->user->is_superuser; my $body = $c->user->from_body || _user_to_body($c); if ($body) { # Matching URL and user's email body - return if $body->id eq $c->stash->{body}->id; + $c->detach('/reports/summary') if $body->id eq $c->stash->{body}->id; # Matched /a/ body, redirect to its summary page $c->stash->{body} = $body; diff --git a/t/cobrand/fixmystreet.t b/t/cobrand/fixmystreet.t index 4d76e43c6..b48593593 100644 --- a/t/cobrand/fixmystreet.t +++ b/t/cobrand/fixmystreet.t @@ -44,7 +44,6 @@ FixMyStreet::override_config { # Logged in, redirects $mech->get_ok('/about/council-dashboard'); is $mech->uri->path, '/reports/Birmingham/summary'; - $mech->content_contains('Top 5 wards'); $mech->content_contains('Where we send Birmingham'); $mech->content_contains('lights@example.com'); diff --git a/templates/web/base/reports/index.html b/templates/web/base/reports/index.html index ff812f113..70f4b3929 100755 --- a/templates/web/base/reports/index.html +++ b/templates/web/base/reports/index.html @@ -139,58 +139,4 @@ </div> </div> -[% IF display_contacts %] -<div class="dashboard-row"> - <div class="dashboard-item dashboard-item--12"> - <h2 class="dashboard-subheading">[% tprintf( loc('Where we send %s reports'), body.name ) %]</h2> - [% IF body.send_method == 'Refused' %] - <p> - [% tprintf( loc('%s currently does not accept reports from FixMyStreet.'), body.name) %] - </p> - - <p> - [% loc('If you’d like to discuss this then <a href="/contact">get in touch</a>.') %] - </p> - [% ELSIF body.send_method == 'Noop' %] - <p> - [% tprintf( loc('Reports are currently not being sent to %s.'), body.name ) %] - </p> - [% ELSIF body.send_method != 'Email' AND body.send_method != '' %] - <p> - [% tprintf( loc('Reports to %s are currently sent directly into backend services.'), body.name) %] - </p> - [% ELSE %] - <p> - [% loc('We currently send all reports to the email addresses below.') %] - </p> - - <p> - [% loc('Did you know that if you used the approved open standard Open311 you could send reports directly into your own backend services – and get much more control over what additional information you request?') %] - </p> - - <p> - [% loc('If that’s new to you, <a href="https://www.mysociety.org/2013/01/10/open311-introduced/">take a look at our simple Open311 primer</a> to see what you need to do to get up and running in a few days.') %] - </p> - - <p> - [% loc('If you would like to change either the categories or the contact emails below then <a href="/contact">get in touch</a>.') %] - <p> - <table class="dashboard-contacts-table"> - <tr> - <th>[% loc('Category') %]</th> - <th>[% loc('Contact') %]</th> - </tr> - [% WHILE ( cat = live_contacts.next ) %] - <tr> - <td class="contact-category"><a href="[% c.uri_for( 'body', body_id, cat.category ) %]">[% cat.category_display | html %]</a> - </td> - <td>[% cat.email | html %]</td> - </tr> - [% END %] - </table> - [% END %] - </div> -</div> -[% END %] - [% INCLUDE 'footer.html' pagefooter = 'yes' %] diff --git a/templates/web/fixmystreet.com/reports/summary.html b/templates/web/fixmystreet.com/reports/summary.html new file mode 100644 index 000000000..6ea664331 --- /dev/null +++ b/templates/web/fixmystreet.com/reports/summary.html @@ -0,0 +1,173 @@ +[% USE Number.Format -%] +[% + other_categories_formatted = other_categories | format_number; +-%] +[% extra_js = [ + version('/vendor/chart.min.js'), + version('/js/dashboard.js') +] -%] +[% INCLUDE 'header.html', title = loc('Dashboard'), bodyclass => 'dashboard fullwidthpage' %] + +<div class="dashboard-header"> + <h1>FMS [% loc('Dashboard') %] + [% IF body %] – [% body.name %] [% END %] + </h1> +</div> + +<form method="GET"> + <div class="filters"> + <p> + <label for="ward">[% loc('Problems reported in area:') %]</label> + <select class="form-control" id="ward" name="ward"> + <option value="">[% body.name %]</option> + [% FOR w IN children.values.sort('name') %] + <option value="[% w.id %]"[% ' selected' IF w.id == ward %]>[% w.name %]</option> + [% END %] + </select> + </p> + <p class="pro-feature"> + <label for="category">[% loc('Category:') %]</label> + <select class="form-control" id="category" disabled> + <option>[% loc('All categories') %]</option> + </select> + </p> + <p class="pro-feature"> + <label for="state">[% loc('Report state:') %]</label> + <select class="form-control" id="state" disabled> + <option>[% loc('All states') %]</option> + </select> + </p> + <p> + <label for="period">[% loc('Reported:') %]</label> + <select class="form-control" id="period" name="period"> + <option value="week"[% ' selected' IF period == 'week' %]>This past week</option> + <option value="month"[% ' selected' IF period == 'month' %]>This past month</option> + <option value="3months"[% ' selected' IF period == '3months' %]>In the past 3 months</option> + <option value="year"[% ' selected' IF period == 'year' %]>This past year</option> + <option value="ever"[% ' selected' IF period == 'ever' %]>Any time</option> + <option disabled>Custom date range (Pro)</option> + </select> + </p> + <p class="no-label"> + <input type="submit" class="btn" value="[% loc('Look up') %]"> + </p> + </div> + <input type="hidden" name="group_by" value="[% group_by %]"> + + [% BLOCK gb %] + [% IF group_by == new_gb %] + <strong title="Currently grouped by [% text %]">[% text %]</strong> + [% ELSE %] + <a href="[% c.uri_with({ group_by => new_gb }) %]" title="Group by [% text %]">[% text %]</a> + [% END %] + [% END %] + + <div class="dashboard-row"> + <div class="dashboard-item dashboard-item--12"> + <table class="dashboard-ranking-table js-make-bar-chart"> + [% FOR k IN rows %] + <tr> + [% IF group_by == 'state' %] + <th scope="row">[% prettify_state(k) %]</th> + [% ELSE %] + <th scope="row">[% k or loc('Website') %]</th> + [% END %] + <td>[% grouped.$k.total OR 0 %]</td> + </tr> + [% END %] + </table> + + <ul class="dashboard-options-tabs dashboard-options-tabs--below"> + <li role="presentation"><span>[% loc('Group by:') %]</span><li> + <li>[% INCLUDE gb new_gb='category' text='category' %]</li> + <li>[% INCLUDE gb new_gb='device' text='device' %]</li> + <li>[% INCLUDE gb new_gb='state' text='state' %]</li> + <li class="pull-right"><a href="[% c.uri_with({ csv => 1 }) %]">[% loc('Export as CSV') %]</a></li> + </ul> + </div> + </div> + +</form> + +<div class="dashboard-row"> + <div class="dashboard-item dashboard-item--6"> + <h2 class="dashboard-subheading">[% tprintf( loc('How responsive is %s?'), body.name ) %]</h2> + <p>[% loc('Average time between a problem being reported and being fixed, last 100 reports.') %]</p> + <table class="dashboard-ranking-table"> + <tbody> + [% FOR line IN top_five_bodies %] + <tr><td>[% line.name %]</td><td>[% tprintf(nget("%s day", "%s days", line.days), line.days) %]</td></tr> + [% END %] + </tbody> + <tfoot> + <tr><td>[% loc('Overall average') %]</td><td>[% tprintf(nget("%s day", "%s days", average), average) %]</td></tr> + </tfoot> + </table> + </div> + <div class="dashboard-item dashboard-item--6"> + <h2 class="dashboard-subheading">[% tprintf( loc('Most popular categories in %s'), body.name ) %]</h2> + <p>[% loc('Number of problems reported in each category, in the last 7 days.') %]</p> + <table class="dashboard-ranking-table"> + <tbody> + [% FOR line IN top_five_categories %] + [% line_count = line.count | format_number ~%] + <tr><td>[% line.category %]</td><td>[% tprintf(nget("%s report", "%s reports", line.count), decode(line_count)) %]</td></tr> + [% END %] + </tbody> + <tfoot> + <tr><td>[% loc('Other categories') %]</td><td>[% tprintf(nget("%s report", "%s reports", other_categories), decode(other_categories_formatted)) %]</td></tr> + </tfoot> + </table> + </div> +</div> + +<div class="dashboard-row"> + <div class="dashboard-item dashboard-item--12"> + <h2 class="dashboard-subheading">[% tprintf( loc('Where we send %s reports'), body.name ) %]</h2> + [% IF body.send_method == 'Refused' %] + <p> + [% tprintf( loc('%s currently does not accept reports from FixMyStreet.'), body.name) %] + </p> + + <p> + [% loc('If you’d like to discuss this then <a href="/contact">get in touch</a>.') %] + </p> + [% ELSIF body.send_method == 'Noop' %] + <p> + [% tprintf( loc('Reports are currently not being sent to %s.'), body.name ) %] + </p> + [% ELSIF body.send_method != 'Email' AND body.send_method != '' %] + <p> + [% tprintf( loc('Reports to %s are currently sent directly into backend services.'), body.name) %] + </p> + [% ELSE %] + <p> + [% loc('We currently send all reports to the email addresses below.') %] + </p> + <table class="dashboard-ranking-table" style="margin-bottom: 1em;"> + <tr> + <th>[% loc('Category') %]</th> + <th>[% loc('Contact') %]</th> + </tr> + [% WHILE ( cat = live_contacts.next ) %] + <tr> + <td class="contact-category"><a href="[% body_url %]?filter_category=[% cat.category | uri %]">[% cat.category_display | html %]</a> + </td> + <td>[% cat.email | html %]</td> + </tr> + [% END %] + </table> + <p> + [% loc('If you would like to change either the categories or the contact emails above then <a href="/contact">get in touch</a>.') %] + <p> + <p> + [% loc('Did you know that if you used the approved open standard Open311 you could send reports directly into your own backend services – and get much more control over what additional information you request?') %] + </p> + <p> + [% loc('If that’s new to you, <a href="https://www.mysociety.org/2013/01/10/open311-introduced/">take a look at our simple Open311 primer</a> to see what you need to do to get up and running in a few days.') %] + </p> + [% END %] + </div> +</div> + +[% INCLUDE 'footer.html' pagefooter = 'yes' %] |