diff --git a/app/assets/javascripts/radioSlider.js b/app/assets/javascripts/radioSlider.js new file mode 100644 index 000000000..d0dffce99 --- /dev/null +++ b/app/assets/javascripts/radioSlider.js @@ -0,0 +1,28 @@ +(function(global) { + + "use strict"; + + global.GOVUK.Modules.RadioSlider = function() { + + this.start = function(component) { + + $(component) + .on('click', function() { + + valuesInLabel = $(this).find(':checked').next('label').text().split('/'); + + if (valuesInLabel.length === 2) { + leftValue = valuesInLabel[0]; + rightValue = valuesInLabel[1]; + $(this).find('.radio-slider-left-value').html(leftValue); + $(this).find('.radio-slider-right-value').html(rightValue); + } + + }) + .trigger('click'); + + }; + + }; + +})(window); diff --git a/app/assets/stylesheets/components/page-footer.scss b/app/assets/stylesheets/components/page-footer.scss index 8bc4ad4be..d39ee4579 100644 --- a/app/assets/stylesheets/components/page-footer.scss +++ b/app/assets/stylesheets/components/page-footer.scss @@ -65,6 +65,15 @@ margin: 0; } + &-centered-button { + + .button { + display: block; + margin: 0 auto; + } + + } + } .align-button-with-textbox { diff --git a/app/assets/stylesheets/components/radios.scss b/app/assets/stylesheets/components/radios.scss index 0b755e10f..52d72e93f 100644 --- a/app/assets/stylesheets/components/radios.scss +++ b/app/assets/stylesheets/components/radios.scss @@ -117,3 +117,56 @@ margin-right: 15px; } } + +.radio-slider { + + border-bottom: 2px solid $black; + height: 18px; + margin-bottom: 18px + 30px; + margin-right: -18px; + margin-left: -18px; + white-space: nowrap; + + legend { + display: none; + } + + .multiple-choice { + + display: inline-block; + margin-right: 0; + padding: 0; + width: 38px; + margin-right: calc((100% - (38px * 11)) / 10); + + &:last-child { + margin-right: 0; + } + + label { + + font-size: 0; + padding: 0; + + &:before { + background: $white; + } + + } + + } + + &-left-value { + position: absolute; + bottom: 30px; + left: 0; + } + + &-right-value { + position: absolute; + bottom: 30px; + right: 0; + text-align: right; + } + +} diff --git a/app/assets/stylesheets/views/history.scss b/app/assets/stylesheets/views/history.scss index b971a1726..b625c82e1 100644 --- a/app/assets/stylesheets/views/history.scss +++ b/app/assets/stylesheets/views/history.scss @@ -15,6 +15,10 @@ $item-top-padding: $gutter-half; border-bottom: 1px solid $border-colour; } + .page-footer { + margin-bottom: 5px; + } + } &-user { @@ -26,4 +30,66 @@ $item-top-padding: $gutter-half; color: $secondary-text-colour; } + &-percentage { + + $axis-thickness: 2px; + border-bottom: $axis-thickness solid $black; + position: relative; + margin-bottom: 35px; + height: 35px; + + &:before, + &:after { + content: ""; + position: absolute; + bottom: -6px; + left: 0; + height: 10px; + width: $axis-thickness; + background: $black; + } + + &:after { + left: auto; + right: 0; + } + + &-without-border { + position: relative; + padding-top: 35px; + } + + &-marker { + $size: 20px; + $border-thickness: 7px; + $text-width: 100px; + display: block; + width: $size; + height: $size; + position: absolute; + top: 35px - ($size / 2) - ($border-thickness - ($axis-thickness / 2)); + margin-left: 0 - ($size / 2) - $border-thickness; + background: $black; + border-radius: $size; + border: $border-thickness solid $white; + } + + &-left-label, + &-right-label { + width: 100%; + position: absolute; + top: 0; + } + + &-left-label { + left: 0; + } + + &-right-label { + right: 0; + text-align: right; + } + + } + } diff --git a/app/main/forms.py b/app/main/forms.py index 6c831a8fc..940f730e9 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -952,6 +952,22 @@ class ProviderForm(StripWhitespaceForm): priority = IntegerField('Priority', [validators.NumberRange(min=1, max=100, message="Must be between 1 and 100")]) +class ProviderRatioForm(StripWhitespaceForm): + + ratio = RadioField(choices=[ + (str(value), '{}% / {}%'.format(value, 100 - value)) + for value in range(100, -10, -10) + ]) + + @property + def percentage_left(self): + return int(self.ratio.data) + + @property + def percentage_right(self): + return 100 - self.percentage_left + + class ServiceContactDetailsForm(StripWhitespaceForm): contact_details_type = RadioField( 'Type of contact details', diff --git a/app/main/views/providers.py b/app/main/views/providers.py index 003f054ff..0484f4463 100644 --- a/app/main/views/providers.py +++ b/app/main/views/providers.py @@ -1,11 +1,17 @@ -from flask import render_template, url_for +from collections import defaultdict +from datetime import datetime +from operator import itemgetter + +from flask import abort, render_template, url_for from werkzeug.utils import redirect -from app import provider_client +from app import format_date_numeric, provider_client from app.main import main -from app.main.forms import ProviderForm +from app.main.forms import ProviderForm, ProviderRatioForm from app.utils import user_is_platform_admin +PROVIDER_PRIORITY_MEANING_SWITCHOVER = datetime(2019, 11, 29, 11, 0).isoformat() + @main.route("/providers") @user_is_platform_admin @@ -51,6 +57,65 @@ def edit_provider(provider_id): return render_template('views/providers/edit-provider.html', form=form, provider=provider) +@main.route("/provider/edit-sms-provider-ratio", methods=['GET', 'POST']) +@user_is_platform_admin +def edit_sms_provider_ratio(): + + providers = sorted([ + provider + for provider in provider_client.get_all_providers()['provider_details'] + if provider['notification_type'] == 'sms' + ], key=itemgetter('identifier'), reverse=True) + + form = ProviderRatioForm(ratio=providers[0]['priority']) + + if len(providers) < 2: + abort(400) + + primary_provider, secondary_provider = providers[0:2] + + if form.validate_on_submit(): + provider_client.update_provider(primary_provider['id'], form.percentage_left) + provider_client.update_provider(secondary_provider['id'], form.percentage_right) + return redirect(url_for('.edit_sms_provider_ratio')) + + return render_template( + 'views/providers/edit-sms-provider-ratio.html', + versions=_chunk_versions_by_day(_get_versions_since_switchover(primary_provider['id'])), + form=form, + primary_provider=providers[0]['display_name'], + secondary_provider=providers[1]['display_name'], + ) + + +def _get_versions_since_switchover(provider_id): + + for version in sorted( + provider_client.get_provider_versions(provider_id)['data'], + key=lambda version: version['updated_at'] or '' + ): + + if not version['updated_at']: + continue + + if version['updated_at'] < PROVIDER_PRIORITY_MEANING_SWITCHOVER: + continue + + yield version + + +def _chunk_versions_by_day(versions): + + days = defaultdict(list) + + for version in sorted(versions, key=lambda version: version['updated_at'] or '', reverse=True): + days[ + format_date_numeric(version['updated_at']) + ].append(version) + + return sorted(days.items(), reverse=True) + + @main.route("/provider/") @user_is_platform_admin def view_provider(provider_id): diff --git a/app/navigation.py b/app/navigation.py index 018c903e4..4e9cdef8c 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -89,6 +89,7 @@ class HeaderNavigation(Navigation): 'clear_cache', 'create_email_branding', 'create_letter_branding', + 'edit_sms_provider_ratio', 'email_branding', 'find_services_by_name', 'find_users_by_email', @@ -497,6 +498,7 @@ class MainNavigation(Navigation): 'edit_organisation_name', 'edit_organisation_type', 'edit_provider', + 'edit_sms_provider_ratio', 'edit_user_org_permissions', 'email_branding', 'email_not_received', @@ -717,6 +719,7 @@ class CaseworkNavigation(Navigation): 'edit_organisation_name', 'edit_organisation_type', 'edit_provider', + 'edit_sms_provider_ratio', 'edit_service_template', 'edit_template_postage', 'edit_user_email', @@ -1002,6 +1005,7 @@ class OrgNavigation(Navigation): 'edit_data_retention', 'edit_provider', 'edit_service_template', + 'edit_sms_provider_ratio', 'edit_template_postage', 'edit_user_email', 'edit_user_mobile_number', diff --git a/app/templates/components/page-footer.html b/app/templates/components/page-footer.html index 6bf8d32c1..b9bb4a0a0 100644 --- a/app/templates/components/page-footer.html +++ b/app/templates/components/page-footer.html @@ -6,9 +6,10 @@ secondary_link=False, secondary_link_text=None, delete_link=False, - delete_link_text="delete" + delete_link_text="delete", + centered_button=False ) %} -