+ {% block serviceNavigation %}
+ {% include "service_navigation.html" %}
+ {% endblock %}
+
+
+ {% if help %}
+
+ {% else %}
+
+ {% endif %}
+ {% block sideNavigation %}
+ {% include "main_nav.html" %}
+
+ {% endblock %}
+
+ {% if help %}
+
+ {% else %}
+
+ {% endif %}
+ {% block beforeContent %}
+ {% block backLink %}{% endblock %}
+ {% endblock %}
+
+ {% block content %}
+ {% include 'flash_messages.html' %}
+ {% block maincolumn_content %}{% endblock %}
+ {% endblock %}
+
+
+
+
+{% endblock %}
diff --git a/app/templates/new/templates_glossary.md b/app/templates/new/templates_glossary.md
new file mode 100644
index 000000000..81325e26c
--- /dev/null
+++ b/app/templates/new/templates_glossary.md
@@ -0,0 +1,37 @@
+
+# New Templates Glossary
+
+This document serves as a glossary for the templates directory structure of the project.
+
+## Directory Structure
+
+- `/templates`
+ - `base.html`: The main base template from which all other templates inherit. This template is a combination of `main_template`, `admin_template`, `withoutnav_template` and `content_template`.
+ - **/layouts**: Contains base templates and shared layouts used across the site. Simply put, it defines the overall structure or skeleton of the application (less frequently revised).
+ - `withnav_template.html`: A variation of the base layout that includes a sidebar.
+ - `org_template.html`: A variaton of the withnav_template
+ - **/components**: Houses reusable UI components that can be included in multiple templates and can be tailored with different content or links depending on the context.(more frequently revised or customized)
+ - `header.html`: Template for the site's header, included in `base.html`.
+ - `footer.html`: Template for the site's footer, included in `base.html`.
+ - **/views** (or **/pages**): Individual page templates that use the base layouts, components, and partials to present content.
+
+### Best Practices
+
+- Use **inheritance** (`{% extends %}`) to build on base layouts.
+- Employ **components** (`{% include %}`) for reusable UI elements to keep the code DRY and facilitate easier updates.
+
+### Observation Notes
+- The macro-options.json files in the header and footer component act as structural guides. They aren't directly used as data passed to the usaFooter function/macro. Instead, these files outline the expected properties and provide a description of their purpose. The `usaFooter` macro component is currently only invoked in the `admin_template`, which will eventually serve as the `base.html` template. This will simplify the approach when we change the footer macros to componenets by eliminating the need to dynamically pass this data from the base.html template.
+
+
+
+### Old Layout Templates We Don't Need
+- withoutnav_template.html Delete
+- main_template.html Delete
+- settings_templates.html `withnav_template` can be used to replace `settings_template`.
+- settings_nav.html (move to /new/navigation directory)
+- main_nav.html (move to /new/navigation directory)
+- service_navigation.html (move to /new/navigation directory)
+- org_template, could be under it's own directory called /layout/organization
+- org_nav.html (move to /new/navigation directory)
+- content_template.html Delete
diff --git a/app/templates/views/check/ok.html b/app/templates/views/check/ok.html
index b795a5971..015cb1ee1 100644
--- a/app/templates/views/check/ok.html
+++ b/app/templates/views/check/ok.html
@@ -1,6 +1,5 @@
{% extends "withnav_template.html" %}
{% from "components/banner.html" import banner_wrapper %}
-{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading %}
{% from "components/page-header.html" import page_header %}
{% from "components/components/button/macro.njk" import usaButton %}
{% from "components/components/skip-link/macro.njk" import usaSkipLink %}
@@ -9,7 +8,7 @@
{% set file_contents_header_id = 'file-preview' %}
{% block service_page_title %}
- {{ "Preview of {}".format(template.name) }}
+ {{ "Select delivery time" }}
{% endblock %}
@@ -19,11 +18,11 @@
{% block maincolumn_content %}
- {{ page_header('Preview of {}'.format(template.name)) }}
+ {{ page_header('Select delivery time') }}
{{ template|string }}
-
- {% if not request.args.from_test %}
-
-
{{ original_file_name }}
-
-
- {% call(item, row_number) list_table(
- recipients.displayed_rows,
- caption=original_file_name,
- caption_visible=False,
- field_headings=[
- '
Row in file1'|safe
- ] + recipients.column_headers
- ) %}
- {% call index_field() %}
-
- {% if (item.index + 2) == preview_row %}
- {{ item.index + 2 }}
- {% else %}
- {{ item.index + 2 }}
- {% endif %}
-
- {% endcall %}
- {% for column in recipients.column_headers %}
- {% if item[column].ignore %}
- {{ text_field(item[column].data or '', status='default') }}
- {% else %}
- {{ text_field(item[column].data or '') }}
- {% endif %}
- {% endfor %}
- {% if item[None].data %}
- {% for column in item[None].data %}
- {{ text_field(column, status='default') }}
- {% endfor %}
- {% endif %}
- {% endcall %}
-
-
- {% endif %}
-
- {% if count_of_displayed_recipients < count_of_recipients %}
-
- Only showing the first {{ count_of_displayed_recipients }} rows
-
- {% endif %}
{% endblock %}
diff --git a/app/templates/views/check/preview.html b/app/templates/views/check/preview.html
new file mode 100644
index 000000000..7398a7fd9
--- /dev/null
+++ b/app/templates/views/check/preview.html
@@ -0,0 +1,77 @@
+{% extends "withnav_template.html" %}
+{% from "components/banner.html" import banner_wrapper %}
+{% from "components/table.html" import list_table, field, text_field, hidden_field_heading %}
+{% from "components/page-header.html" import page_header %}
+{% from "components/components/button/macro.njk" import usaButton %}
+{% from "components/components/skip-link/macro.njk" import usaSkipLink %}
+{% from "components/components/back-link/macro.njk" import usaBackLink %}
+
+{% set file_contents_header_id = 'file-preview' %}
+
+{% block service_page_title %}
+ {{ "Preview of {}".format(template.name) }}
+{% endblock %}
+
+
+{% block backLink %}
+ {{ usaBackLink({ "href": back_link_from_preview }) }}
+{% endblock %}
+
+{% block maincolumn_content %}
+
+ {{ page_header('Preview') }}
+
+
Scheduled: {{ scheduled_for if scheduled_for else 'Now'}}
+
File: {{original_file_name}}
+
Template: {{template.name}}
+
From: {{ template.sender }}
+
+
+
+
{{ simplifed_template|string }}
+ {% if not request.args.from_test %}
+
Recipients list
+
+
+ {% call(item, row_number) list_table(
+ recipients.displayed_rows,
+ caption="Note: Only the first 5 rows are displayed here.",
+ caption_visible=True,
+ field_headings=recipients.column_headers
+ ) %}
+ {% for column in recipients.column_headers %}
+ {% if item[column].ignore %}
+ {{ text_field(item[column].data or '', status='default') }}
+ {% else %}
+ {{ text_field(item[column].data or '') }}
+ {% endif %}
+ {% endfor %}
+ {% if item[None].data %}
+ {% for column in item[None].data %}
+ {{ text_field(column, status='default') }}
+ {% endfor %}
+ {% endif %}
+ {% endcall %}
+
+ {% endif %}
+
+
+{% endblock %}
diff --git a/app/templates/views/notifications/check.html b/app/templates/views/notifications/check.html
index 5bc970f9b..8646d1b7f 100644
--- a/app/templates/views/notifications/check.html
+++ b/app/templates/views/notifications/check.html
@@ -5,7 +5,7 @@
{% from "components/components/button/macro.njk" import usaButton %}
{% block service_page_title %}
- {{ "Error" if error else "Preview of ‘{}’".format(template.name) }}
+ {{ "Error" if error else "Select delivery time" }}
{% endblock %}
{% block backLink %}
@@ -40,17 +40,16 @@
{% endcall %}
{% else %}
- {{ page_header('Preview of ‘{}’'.format(template.name)) }}
+ {{ page_header('Select delivery time') }}
{% endif %}
{{ template|string }}
diff --git a/app/templates/views/notifications/preview.html b/app/templates/views/notifications/preview.html
new file mode 100644
index 000000000..a22fda5bb
--- /dev/null
+++ b/app/templates/views/notifications/preview.html
@@ -0,0 +1,74 @@
+{% extends "withnav_template.html" %}
+{% from "components/banner.html" import banner_wrapper %}
+{% from "components/page-header.html" import page_header %}
+{% from "components/components/back-link/macro.njk" import usaBackLink %}
+{% from "components/components/button/macro.njk" import usaButton %}
+
+{% block service_page_title %}
+ {{ "Error" if error else "Preview" }}
+{% endblock %}
+
+{% block backLink %}
+ {{ usaBackLink({ "href": back_link_from_preview }) }}
+{% endblock %}
+
+{% block maincolumn_content %}
+ {% if error == 'not-allowed-to-send-to' %}
+
+ {% call banner_wrapper(type='dangerous') %}
+ {% with
+ count_of_recipients=1,
+ template_type_label=(
+ 'phone number' if template.template_type == 'sms' else 'email address'
+ )
+ %}
+ {% include "partials/check/not-allowed-to-send-to.html" %}
+ {% endwith %}
+ {% endcall %}
+
+ {% elif error == 'too-many-messages' %}
+
+ {% call banner_wrapper(type='dangerous') %}
+ {% include "partials/check/too-many-messages.html" %}
+ {% endcall %}
+
+ {% elif error == 'message-too-long' %}
+ {# the only row_errors we can get when sending one off messages is that the message is too long #}
+
+ {% call banner_wrapper(type='dangerous') %}
+ {% include "partials/check/message-too-long.html" %}
+ {% endcall %}
+
+ {% else %}
+ {{ page_header('Preview') }}
+ {% endif %}
+
+
Scheduled: {{ scheduled_for if scheduled_for else 'Now'}}
+
Template: {{template.name}}
+
From: {{ template.sender }}
+
To: {{ recipient }}
+
+
+
+
{{ simplifed_template|string }}
+
+
+
+
+
+{% endblock %}
diff --git a/tests/app/main/views/test_conversation.py b/tests/app/main/views/test_conversation.py
index 215a8e828..1139cd43f 100644
--- a/tests/app/main/views/test_conversation.py
+++ b/tests/app/main/views/test_conversation.py
@@ -391,7 +391,7 @@ def test_conversation_reply_redirects_with_phone_number_from_notification(
)
for element, expected_text in [
- ("h1", "Preview of ‘Two week reminder’"),
+ ("h1", "Select delivery time"),
(".sms-message-recipient", "To: 2021234567"),
(
".sms-message-wrapper",
diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py
index 7448c44cf..35309f57f 100644
--- a/tests/app/main/views/test_send.py
+++ b/tests/app/main/views/test_send.py
@@ -908,26 +908,22 @@ def test_upload_valid_csv_redirects_to_check_page(
(
"extra_args",
"expected_link_in_first_row",
- "expected_recipient",
"expected_message",
),
[
(
{},
None,
- "To: 2028675301",
"Test Service: A, Template
content with & entity",
),
(
{"row_index": 2},
None,
- "To: 2028675301",
"Test Service: A, Template
content with & entity",
),
(
{"row_index": 4},
True,
- "To: 2028675303",
"Test Service: C, Template
content with & entity",
),
],
@@ -946,7 +942,6 @@ def test_upload_valid_csv_shows_preview_and_table(
fake_uuid,
extra_args,
expected_link_in_first_row,
- expected_recipient,
expected_message,
):
with client_request.session_transaction() as session:
@@ -962,40 +957,20 @@ def test_upload_valid_csv_shows_preview_and_table(
""",
)
- page = client_request.get(
- "main.check_messages",
+ page = client_request.post(
+ "main.preview_job",
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
upload_id=fake_uuid,
**extra_args,
+ _expected_status=200,
)
- mock_s3_set_metadata.assert_called_once_with(
- SERVICE_ONE_ID,
- fake_uuid,
- notification_count=3,
- template_id=fake_uuid,
- valid=True,
- original_file_name="example.csv",
- )
-
- assert page.h1.text.strip() == "Preview of Two week reminder"
- assert page.select_one(".sms-message-recipient").text.strip() == expected_recipient
+ assert page.h1.text.strip() == "Preview"
+ assert page.select("h2")[1].text.strip() == "Recipients list"
+ assert page.h2.text.strip() == "Message"
assert page.select_one(".sms-message-wrapper").text.strip() == expected_message
-
- assert page.select_one(".table-field-index").text.strip() == "2"
-
- if expected_link_in_first_row:
- assert page.select_one(".table-field-index a")["href"] == url_for(
- "main.check_messages",
- service_id=SERVICE_ONE_ID,
- template_id=fake_uuid,
- upload_id=fake_uuid,
- row_index=2,
- original_file_name="example.csv",
- )
- else:
- assert not page.select_one(".table-field-index").select_one("a")
+ assert not page.select_one(".table-field-index")
for row_index, row in enumerate(
[
@@ -1043,7 +1018,7 @@ def test_upload_valid_csv_shows_preview_and_table(
for index, cell in enumerate(row):
row = page.select("table tbody tr")[row_index]
assert "id" not in row
- assert normalize_spaces(str(row.select("td")[index + 1])) == cell
+ assert normalize_spaces(str(row.select("td")[index])) == cell
def test_show_all_columns_if_there_are_duplicate_recipient_columns(
@@ -1674,7 +1649,7 @@ def test_send_one_off_email_to_self_without_placeholders_redirects_to_check_page
_follow_redirects=True,
)
- assert page.select("h1")[0].text.strip() == "Preview of ‘Two week reminder’"
+ assert page.select("h1")[0].text.strip() == "Select delivery time"
@pytest.mark.parametrize(
@@ -1901,10 +1876,9 @@ def test_upload_csvfile_with_valid_phone_shows_all_numbers(
original_file_name="example.csv",
)
- assert "202 867 0701" in page.text
- assert "202 867 0749" in page.text
+ assert "Select delivery time" in page.text
+ assert "202 867 0749" not in page.text
assert "202 867 0750" not in page.text
- assert "Only showing the first 50 rows" in page.text
mock_get_notification_count.assert_called_with(service_one["id"])
@@ -1988,7 +1962,7 @@ def test_test_message_can_only_be_sent_now(
assert 'name="scheduled_for"' not in content
-def test_send_button_is_correctly_labelled(
+def test_preview_button_is_correctly_labelled(
client_request,
mocker,
mock_get_live_service,
@@ -2013,9 +1987,7 @@ def test_send_button_is_correctly_labelled(
template_id=fake_uuid,
)
- assert normalize_spaces(page.select_one("main [type=submit]").text) == (
- "Send 1,000 text messages"
- )
+ assert normalize_spaces(page.select_one("main [type=submit]").text) == ("Preview")
@pytest.mark.parametrize("when", ["", "2016-08-25T13:04:21.767198"])
@@ -2043,6 +2015,8 @@ def test_create_job_should_call_api(
"valid": True,
}
}
+ with client_request.session_transaction() as session:
+ session["scheduled_for"] = when
page = client_request.post(
"main.start_job",
@@ -2593,7 +2567,7 @@ def test_check_notification_redirects_if_session_not_populated(
)
-def test_check_notification_shows_preview(
+def test_check_notification_shows_scheduler(
client_request, service_one, fake_uuid, mock_get_service_template
):
with client_request.session_transaction() as session:
@@ -2604,7 +2578,7 @@ def test_check_notification_shows_preview(
"main.check_notification", service_id=service_one["id"], template_id=fake_uuid
)
- assert page.h1.text.strip() == "Preview of ‘Two week reminder’"
+ assert page.h1.text.strip() == "Select delivery time"
assert (page.find_all("a", {"class": "usa-back-link"})[0]["href"]) == url_for(
"main.send_one_off_step",
service_id=service_one["id"],
@@ -2615,6 +2589,41 @@ def test_check_notification_shows_preview(
# assert tour not visible
assert not page.select(".banner-tour")
+ # post to send_notification with help=0 to ensure no back link is then shown
+ assert page.form.attrs["action"] == url_for(
+ "main.preview_notification",
+ service_id=service_one["id"],
+ template_id=fake_uuid,
+ )
+
+ assert normalize_spaces(page.select_one("main [type=submit]").text) == ("Preview")
+
+
+@pytest.mark.parametrize("when", ["", "2016-08-25T13:04:21.767198"])
+def test_preview_notification_shows_preview(
+ client_request,
+ service_one,
+ fake_uuid,
+ mock_get_service_template,
+ when,
+):
+ with client_request.session_transaction() as session:
+ session["recipient"] = "15555555555"
+ session["placeholders"] = {}
+
+ page = client_request.post(
+ "main.preview_notification", service_id=service_one["id"], template_id=fake_uuid,
+ _expected_status=200
+ )
+ assert page.h1.text.strip() == "Preview"
+ assert (page.find_all("a", {"class": "usa-back-link"})[0]["href"]) == url_for(
+ "main.check_notification",
+ service_id=service_one["id"],
+ template_id=fake_uuid,
+ )
+ # assert tour not visible
+ assert not page.select(".banner-tour")
+
# post to send_notification with help=0 to ensure no back link is then shown
assert page.form.attrs["action"] == url_for(
"main.send_notification",
@@ -2872,7 +2881,6 @@ def test_send_notification_shows_email_error_in_trial_mode(
@pytest.mark.parametrize(
("endpoint", "extra_args"),
[
- ("main.check_messages", {"template_id": uuid4(), "upload_id": uuid4()}),
("main.send_one_off_step", {"template_id": uuid4(), "step_index": 0}),
],
)
diff --git a/tests/app/main/views/test_tour.py b/tests/app/main/views/test_tour.py
index 1d34a9999..749a8097f 100644
--- a/tests/app/main/views/test_tour.py
+++ b/tests/app/main/views/test_tour.py
@@ -544,10 +544,9 @@ def test_should_200_for_check_tour_notification(
# post to send_notification keeps help argument
assert page.form.attrs["action"] == url_for(
- "main.send_notification",
+ "main.preview_notification",
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
- help="3",
)
diff --git a/tests/app/test_navigation.py b/tests/app/test_navigation.py
index 1f1da2915..5ee810f33 100644
--- a/tests/app/test_navigation.py
+++ b/tests/app/test_navigation.py
@@ -139,6 +139,8 @@ EXCLUDED_ENDPOINTS = tuple(
"platform_admin_list_complaints",
"platform_admin_reports",
"platform_admin_splash_page",
+ "preview_job",
+ "preview_notification",
"pricing",
"privacy",
"received_text_messages_callback",