mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-11 09:28:27 -04:00
Merge pull request #3527 from alphagov/broadcast-end-time
Let users choose when to end a broadcast
This commit is contained in:
@@ -7,12 +7,14 @@
|
||||
|
||||
let states = {
|
||||
'initial': Hogan.compile(`
|
||||
<div class="radio-select__column">
|
||||
<div class="multiple-choice js-multiple-choice">
|
||||
<input checked="checked" id="{{name}}-0" name="{{name}}" type="radio" value="">
|
||||
<label class="block-label js-block-label" for="{{name}}-0">Now</label>
|
||||
{{#showNowAsDefault}}
|
||||
<div class="radio-select__column">
|
||||
<div class="multiple-choice js-multiple-choice">
|
||||
<input checked="checked" id="{{name}}-0" name="{{name}}" type="radio" value="">
|
||||
<label class="block-label js-block-label" for="{{name}}-0">Now</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/showNowAsDefault}}
|
||||
<div class="radio-select__column">
|
||||
{{#categories}}
|
||||
<input type='button' class='govuk-button govuk-button--secondary radio-select__button--category' value='{{.}}' />
|
||||
@@ -20,12 +22,14 @@
|
||||
</div>
|
||||
`),
|
||||
'choose': Hogan.compile(`
|
||||
<div class="radio-select__column">
|
||||
<div class="multiple-choice js-multiple-choice js-initial-option">
|
||||
<input checked="checked" id="{{name}}-0" name="{{name}}" type="radio" value="">
|
||||
<label for="{{name}}-0">Now</label>
|
||||
{{#showNowAsDefault}}
|
||||
<div class="radio-select__column">
|
||||
<div class="multiple-choice js-multiple-choice js-initial-option">
|
||||
<input checked="checked" id="{{name}}-0" name="{{name}}" type="radio" value="">
|
||||
<label for="{{name}}-0">Now</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/showNowAsDefault}}
|
||||
<div class="radio-select__column">
|
||||
{{#choices}}
|
||||
<div class="multiple-choice js-multiple-choice js-option">
|
||||
@@ -37,12 +41,14 @@
|
||||
</div>
|
||||
`),
|
||||
'chosen': Hogan.compile(`
|
||||
<div class="radio-select__column">
|
||||
<div class="multiple-choice js-multiple-choice js-initial-option">
|
||||
<input id="{{name}}-0" name="{{name}}" type="radio" value="">
|
||||
<label for="{{name}}-0">Now</label>
|
||||
{{#showNowAsDefault}}
|
||||
<div class="radio-select__column">
|
||||
<div class="multiple-choice js-multiple-choice js-initial-option">
|
||||
<input id="{{name}}-0" name="{{name}}" type="radio" value="">
|
||||
<label for="{{name}}-0">Now</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/showNowAsDefault}}
|
||||
<div class="radio-select__column">
|
||||
{{#choices}}
|
||||
<div class="multiple-choice js-multiple-choice">
|
||||
@@ -80,10 +86,15 @@
|
||||
let categories = $component.data('categories').split(',');
|
||||
let name = $component.find('input').eq(0).attr('name');
|
||||
let mousedownOption = null;
|
||||
let showNowAsDefault = (
|
||||
$component.data('show-now-as-default').toString() === 'true' ?
|
||||
{'name': name} : false
|
||||
);
|
||||
const reset = () => {
|
||||
render('initial', {
|
||||
'categories': categories,
|
||||
'name': name
|
||||
'name': name,
|
||||
'showNowAsDefault': showNowAsDefault
|
||||
});
|
||||
};
|
||||
const selectOption = (value) => {
|
||||
@@ -91,7 +102,8 @@
|
||||
'choices': choices.filter(
|
||||
element => element.value == value
|
||||
),
|
||||
'name': name
|
||||
'name': name,
|
||||
'showNowAsDefault': showNowAsDefault
|
||||
});
|
||||
focusSelected(component);
|
||||
};
|
||||
@@ -119,7 +131,8 @@
|
||||
'choices': choices.filter(
|
||||
element => element.label.toLowerCase().indexOf(day) > -1
|
||||
),
|
||||
'name': name
|
||||
'name': name,
|
||||
'showNowAsDefault': showNowAsDefault
|
||||
});
|
||||
focusSelected(component);
|
||||
|
||||
@@ -153,7 +166,8 @@
|
||||
'choices': choices.filter(
|
||||
element => element.value == $selection.eq(0).attr('value')
|
||||
),
|
||||
'name': name
|
||||
'name': name,
|
||||
'showNowAsDefault': showNowAsDefault
|
||||
});
|
||||
|
||||
} else {
|
||||
@@ -174,7 +188,8 @@
|
||||
|
||||
render('initial', {
|
||||
'categories': categories,
|
||||
'name': name
|
||||
'name': name,
|
||||
'showNowAsDefault': showNowAsDefault
|
||||
});
|
||||
|
||||
$component.css({'height': 'auto'});
|
||||
|
||||
@@ -100,7 +100,7 @@ def get_next_hours_until(until):
|
||||
now = datetime.utcnow()
|
||||
hours = int((until - now).total_seconds() / (60 * 60))
|
||||
return [
|
||||
(now + timedelta(hours=i)).replace(minute=0, second=0).replace(tzinfo=pytz.utc)
|
||||
(now + timedelta(hours=i)).replace(minute=0, second=0, microsecond=0).replace(tzinfo=pytz.utc)
|
||||
for i in range(1, hours + 1)
|
||||
]
|
||||
|
||||
@@ -979,6 +979,24 @@ class ChooseTimeForm(StripWhitespaceForm):
|
||||
)
|
||||
|
||||
|
||||
class ChooseBroadcastDurationForm(StripWhitespaceForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.finishes_at.choices = [
|
||||
get_time_value_and_label(hour) for hour in get_next_hours_until(
|
||||
get_furthest_possible_scheduled_time()
|
||||
)
|
||||
]
|
||||
self.finishes_at.categories = get_next_days_until(
|
||||
get_furthest_possible_scheduled_time()
|
||||
)
|
||||
|
||||
finishes_at = RadioField(
|
||||
'When should this broadcast end?',
|
||||
)
|
||||
|
||||
|
||||
class CreateKeyForm(StripWhitespaceForm):
|
||||
def __init__(self, existing_keys, *args, **kwargs):
|
||||
self.existing_key_names = [
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from flask import abort, jsonify, redirect, render_template, request, url_for
|
||||
from flask import abort, jsonify, redirect, render_template, url_for
|
||||
|
||||
from app import current_service
|
||||
from app.main import main
|
||||
from app.main.forms import BroadcastAreaForm, SearchByNameForm
|
||||
from app.main.forms import (
|
||||
BroadcastAreaForm,
|
||||
ChooseBroadcastDurationForm,
|
||||
SearchByNameForm,
|
||||
)
|
||||
from app.models.broadcast_message import BroadcastMessage, BroadcastMessages
|
||||
from app.utils import service_has_permission, user_has_permissions
|
||||
|
||||
@@ -141,15 +145,19 @@ def preview_broadcast_message(service_id, broadcast_message_id):
|
||||
broadcast_message_id,
|
||||
service_id=current_service.id,
|
||||
)
|
||||
if request.method == 'POST':
|
||||
broadcast_message.request_approval()
|
||||
form = ChooseBroadcastDurationForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
broadcast_message.request_approval(until=form.finishes_at.data)
|
||||
return redirect(url_for(
|
||||
'.broadcast_dashboard',
|
||||
service_id=current_service.id,
|
||||
))
|
||||
|
||||
return render_template(
|
||||
'views/broadcast/preview-message.html',
|
||||
broadcast_message=broadcast_message,
|
||||
form=form,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
|
||||
from notifications_utils.broadcast_areas import broadcast_area_libraries
|
||||
from notifications_utils.template import BroadcastPreviewTemplate
|
||||
@@ -33,7 +33,6 @@ class BroadcastMessage(JSONModel):
|
||||
'approved_by_id',
|
||||
'cancelled_by_id',
|
||||
}
|
||||
DEFAULT_TTL = timedelta(hours=72)
|
||||
|
||||
libraries = broadcast_area_libraries
|
||||
|
||||
@@ -132,9 +131,9 @@ class BroadcastMessage(JSONModel):
|
||||
data=kwargs,
|
||||
)
|
||||
|
||||
def request_approval(self):
|
||||
def request_approval(self, until):
|
||||
self._update(
|
||||
finishes_at=(datetime.utcnow() + self.DEFAULT_TTL).isoformat(),
|
||||
finishes_at=until,
|
||||
)
|
||||
self._set_status_to('pending-approval')
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
{% macro radio_select(
|
||||
field,
|
||||
hint=None,
|
||||
wrapping_class='form-group'
|
||||
wrapping_class='form-group',
|
||||
show_now_as_default=True
|
||||
) %}
|
||||
<div class="{{ wrapping_class }} {% if field.errors %} form-group-error{% endif %}">
|
||||
<fieldset>
|
||||
@@ -35,7 +36,7 @@
|
||||
</span>
|
||||
{% endif %}
|
||||
</legend>
|
||||
<div class="radio-select" data-module="radio-select" data-categories="{{ field.categories|join(',') }}">
|
||||
<div class="radio-select" data-module="radio-select" data-categories="{{ field.categories|join(',') }}" data-show-now-as-default="{{ show_now_as_default|string|lower }}">
|
||||
<div class="radio-select-column">
|
||||
{% for option in field %}
|
||||
<div class="multiple-choice">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{% from "components/button/macro.njk" import govukButton %}
|
||||
{% from "components/form.html" import form_wrapper %}
|
||||
{% from "components/page-header.html" import page_header %}
|
||||
{% from "components/page-footer.html" import sticky_page_footer %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/radios.html" import radio_select %}
|
||||
|
||||
{% extends "withnav_template.html" %}
|
||||
|
||||
@@ -28,7 +29,11 @@
|
||||
{{ broadcast_message.template|string }}
|
||||
|
||||
{% call form_wrapper() %}
|
||||
{{ sticky_page_footer('Submit for approval') }}
|
||||
{{ radio_select(
|
||||
form.finishes_at,
|
||||
show_now_as_default=False
|
||||
) }}
|
||||
{{ page_footer('Submit for approval') }}
|
||||
{% endcall %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user