Skip to content

Commit 50a5f0d

Browse files
authored
Merge pull request #1382 from NHSDigital/12697-tech-recall-page
Add initial technical recall page
2 parents 02d167b + 4781175 commit 50a5f0d

6 files changed

Lines changed: 176 additions & 49 deletions

File tree

manage_breast_screening/participants/models/appointment.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ def filter_counts_for_clinic(cls, clinic):
111111
counts[filter] = clinic.appointments.for_filter(filter).count()
112112
return counts
113113

114+
@classmethod
115+
def with_study(cls):
116+
return cls.objects.filter(study__isnull=False)
117+
114118
@property
115119
def provider(self):
116120
return self.clinic_slot.provider

manage_breast_screening/reading/apps.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33

44
class ReadingConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
56
name = "manage_breast_screening.reading"

manage_breast_screening/reading/jinja2/read_image.jinja

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{% extends "layout-app.jinja" %}
2-
{% from "django_form_helpers.jinja" import form_error_summary %}
32
{% from "nhsuk/components/button/macro.jinja" import button %}
43
{% from "nhsuk/components/inset-text/macro.jinja" import insetText %}
54
{% from "nhsuk/components/summary-list/macro.jinja" import summaryList %}
@@ -26,8 +25,6 @@
2625
{% block page_content %}
2726
<div class="nhsuk-grid-row">
2827
<div class="nhsuk-grid-column-full">
29-
{{ form_error_summary(form) }}
30-
3128
<div class="nhsuk-grid-row app-header">
3229
<div class="nhsuk-grid-column-two-thirds app-header">
3330
<h1 class="nhsuk-heading-l">
@@ -59,51 +56,50 @@
5956
</div>
6057
</div>
6158

62-
<form method="post" novalidate>
63-
{{ csrf_input }}
64-
65-
<div class="nhsuk-grid-row">
66-
<div class="nhsuk-grid-column-one-third nhsuk-u-margin-bottom-4">
67-
<h2 class="nhsuk-heading-s">Image thumbnails ({{ images | length }})</h2>
68-
<div class="app-mammogram-thumbnails">
69-
{% for image in images %}
70-
<div class="app-mammogram-thumbnail {{ image.class }}">
71-
<div class="app-mammogram-thumbnail__image-wrapper">
72-
<span class="app-mammogram-thumbnail__label">{{ image.name }}</span>
73-
<img class="app-mammogram-thumbnail__image app-mammogram-thumbnail__image--diagram"
74-
src="{{ image.url }}" alt="{{ image.name }} view">
75-
</div>
59+
<div class="nhsuk-grid-row">
60+
<div class="nhsuk-grid-column-one-third nhsuk-u-margin-bottom-4">
61+
<h2 class="nhsuk-heading-s">Image thumbnails ({{ images | length }})</h2>
62+
<div class="app-mammogram-thumbnails">
63+
{% for image in images %}
64+
<div class="app-mammogram-thumbnail {{ image.class }}">
65+
<div class="app-mammogram-thumbnail__image-wrapper">
66+
<span class="app-mammogram-thumbnail__label">{{ image.name }}</span>
67+
<img class="app-mammogram-thumbnail__image app-mammogram-thumbnail__image--diagram"
68+
src="{{ image.url }}" alt="{{ image.name }} view">
7669
</div>
77-
{% endfor %}
78-
</div>
70+
</div>
71+
{% endfor %}
7972
</div>
73+
</div>
8074

81-
<div class="nhsuk-grid-column-two-thirds">
82-
<h2 class="nhsuk-heading-m">What is your opinion of these images?</h2>
75+
<div class="nhsuk-grid-column-two-thirds">
76+
<h2 class="nhsuk-heading-m">What is your opinion of these images?</h2>
8377

84-
<div class="nhsuk-u-margin-bottom-4">
85-
<button class="nhsuk-button nhsuk-u-width-full nhsuk-u-margin-bottom-3">
86-
Normal <span class="app-shortcut-hint">(N)</span>
87-
</button>
88-
<p class="nhsuk-u-margin-bottom-4">
89-
<a class="nhsuk-link nhsuk-link--no-visited-state" href="#">Normal, but add details</a>
90-
</p>
91-
</div>
78+
<div class="nhsuk-u-margin-bottom-4">
79+
<button class="nhsuk-button nhsuk-u-width-full nhsuk-u-margin-bottom-3">
80+
Normal <span class="app-shortcut-hint">(N)</span>
81+
</button>
82+
<p class="nhsuk-u-margin-bottom-4">
83+
<a class="nhsuk-link nhsuk-link--no-visited-state" href="#">Normal, but add details</a>
84+
</p>
85+
</div>
9286

93-
<div class="nhsuk-u-margin-bottom-4">
94-
<button class="nhsuk-button nhsuk-button--secondary nhsuk-u-width-full nhsuk-u-margin-bottom-3">
95-
Technical recall <span class="app-shortcut-hint">(T)</span>
96-
</button>
97-
</div>
87+
<div class="nhsuk-u-margin-bottom-4">
88+
<a href="{{ url('reading:add_technical_recall', kwargs={'session_pk': view.kwargs.session_pk, 'read_pk': view.kwargs.pk}) }}"
89+
role="button"
90+
draggable="false"
91+
class="nhsuk-button nhsuk-button--secondary nhsuk-u-width-full nhsuk-u-margin-bottom-3">
92+
Technical recall <span class="app-shortcut-hint">(T)</span>
93+
</a>
94+
</div>
9895

99-
<div class="nhsuk-u-margin-bottom-4">
100-
<button class="nhsuk-button nhsuk-button--warning nhsuk-u-width-full">
101-
Recall for assessment <span class="app-shortcut-hint">(R)</span>
102-
</button>
103-
</div>
96+
<div class="nhsuk-u-margin-bottom-4">
97+
<button class="nhsuk-button nhsuk-button--warning nhsuk-u-width-full">
98+
Recall for assessment <span class="app-shortcut-hint">(R)</span>
99+
</button>
104100
</div>
105101
</div>
106-
</form>
102+
</div>
107103

108104
{% if notes_for_reader %}
109105
{% set inset_html %}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
{% extends "layout-app.jinja" %}
2+
{% from "nhsuk/components/button/macro.jinja" import button %}
3+
{% from "nhsuk/components/checkboxes/macro.jinja" import checkboxes %}
4+
5+
{% macro recall_fields(prefix) %}
6+
<div class="nhsuk-form-group">
7+
<label class="nhsuk-label" for="{{ prefix }}_reason">Reason for recall</label>
8+
<select class="nhsuk-select" id="{{ prefix }}_reason" name="{{ prefix }}_reason">
9+
<option value="" selected disabled>Select a reason</option>
10+
<option value="breast_positioning">Breast positioning</option>
11+
<option value="incorrect_exposure">Incorrect exposure</option>
12+
<option value="image_obscured">Image obscured</option>
13+
<option value="image_blurred">Image blurred</option>
14+
<option value="image_missing">Image missing</option>
15+
<option value="other_reason">Other reason</option>
16+
</select>
17+
</div>
18+
<div class="nhsuk-form-group">
19+
<label class="nhsuk-label nhsuk-label--s" for="{{ prefix }}_details">Additional details (optional)</label>
20+
<input class="nhsuk-input" id="{{ prefix }}_details" name="{{ prefix }}_details" type="text">
21+
</div>
22+
{% endmacro %}
23+
24+
{% block page_content %}
25+
<div class="nhsuk-grid-row">
26+
<div class="nhsuk-grid-column-full">
27+
<span class="nhsuk-caption-l">Erin Sauer</span>
28+
<h1 class="nhsuk-heading-l">Technical recall</h1>
29+
30+
<form action="{{ request.path }}" method="post" novalidate>
31+
{{ csrf_input }}
32+
33+
<h2 class="nhsuk-heading-m">Which views need to be retaken?</h2>
34+
35+
<div class="nhsuk-grid-row">
36+
<div class="nhsuk-grid-column-one-half">
37+
<h3 class="nhsuk-heading-s">Right breast</h3>
38+
39+
{% set rcc_conditional = recall_fields("rcc") %}
40+
{{ checkboxes({
41+
"idPrefix": "rcc",
42+
"name": "rcc",
43+
"items": [
44+
{
45+
"value": "rcc",
46+
"text": "RCC",
47+
"conditional": {"html": rcc_conditional}
48+
}
49+
]
50+
}) }}
51+
52+
{% set rmlo_conditional = recall_fields("rmlo") %}
53+
{{ checkboxes({
54+
"idPrefix": "rmlo",
55+
"name": "rmlo",
56+
"items": [
57+
{
58+
"value": "rmlo",
59+
"text": "RMLO",
60+
"conditional": {"html": rmlo_conditional}
61+
}
62+
]
63+
}) }}
64+
</div>
65+
66+
<div class="nhsuk-grid-column-one-half">
67+
<h3 class="nhsuk-heading-s">Left breast</h3>
68+
69+
{% set lcc_conditional = recall_fields("lcc") %}
70+
{{ checkboxes({
71+
"idPrefix": "lcc",
72+
"name": "lcc",
73+
"items": [
74+
{
75+
"value": "lcc",
76+
"text": "LCC",
77+
"conditional": {"html": lcc_conditional}
78+
}
79+
]
80+
}) }}
81+
82+
{% set lmlo_conditional = recall_fields("lmlo") %}
83+
{{ checkboxes({
84+
"idPrefix": "lmlo",
85+
"name": "lmlo",
86+
"items": [
87+
{
88+
"value": "lmlo",
89+
"text": "LMLO",
90+
"conditional": {"html": lmlo_conditional}
91+
}
92+
]
93+
}) }}
94+
</div>
95+
</div>
96+
97+
{{ button({"text": "Continue"}) }}
98+
</form>
99+
</div>
100+
</div>
101+
{% endblock %}

manage_breast_screening/reading/urls.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
path("", views.show_reading_dashboard_view, name="show_reading_dashboard"),
99
path(
1010
"sessions/<uuid:session_pk>/reads/<uuid:pk>/",
11-
views.ReadImageView.as_view(),
11+
views.ShowImageReadView.as_view(),
1212
name="image_read",
1313
),
14+
path(
15+
"sessions/<uuid:session_pk>/reads/<uuid:read_pk>/technical-recall/",
16+
views.AddTechnicalRecallView.as_view(),
17+
name="add_technical_recall",
18+
),
1419
]

manage_breast_screening/reading/views.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
from logging import getLogger
2+
13
from django.contrib.auth.decorators import permission_required
2-
from django.forms import Form
34
from django.shortcuts import render
45
from django.views.decorators.http import require_http_methods
5-
from django.views.generic import FormView
6+
from django.views.generic import TemplateView
67
from rules.contrib.views import PermissionRequiredMixin
78

89
from manage_breast_screening.auth.models import Permission
910
from manage_breast_screening.mammograms.presenters.medical_history.check_medical_information_presenter import (
1011
CheckMedicalInformationPresenter,
1112
)
12-
from manage_breast_screening.mammograms.views.mixins import AppointmentMixin
13+
from manage_breast_screening.participants.models import Appointment
14+
15+
logger = getLogger(__name__)
1316

1417

1518
@require_http_methods(["GET"])
@@ -18,25 +21,28 @@ def show_reading_dashboard_view(request):
1821
return render(request, "show_readings.jinja")
1922

2023

21-
class ReadImageView(PermissionRequiredMixin, AppointmentMixin, FormView):
22-
form_class = Form
24+
class ShowImageReadView(PermissionRequiredMixin, TemplateView):
2325
template_name = "read_image.jinja"
2426
permission_required = Permission.READ_IMAGES
2527

2628
def get_context_data(self, **kwargs):
2729
context = super().get_context_data(**kwargs)
2830

31+
# TODO: dummy data — replace once retrieval of the appropriate Reading object is implemented.
32+
appointment = Appointment.with_study().first()
33+
participant = appointment.participant
34+
2935
images = []
3036

3137
context.update(
3238
{
33-
"heading": self.participant.full_name,
39+
"heading": participant.full_name,
3440
"caption": "Review images",
3541
"images": images,
3642
"presented_medical_information": CheckMedicalInformationPresenter(
37-
self.appointment
43+
appointment
3844
),
39-
"notes_for_reader": self.appointment.study.additional_details,
45+
"notes_for_reader": appointment.study.additional_details,
4046
"is_urgent": True,
4147
"is_second_read": True,
4248
"is_previously_skipped": True,
@@ -61,3 +67,17 @@ def _get_images(self, study):
6167
)
6268

6369
return images
70+
71+
72+
class AddTechnicalRecallView(TemplateView):
73+
template_name = "reading/technical_recall.jinja"
74+
75+
def get_context_data(self, **kwargs):
76+
context = super().get_context_data(**kwargs)
77+
context.update(
78+
{
79+
"page_title": "Technical recall",
80+
"back_link_params": {"href": "#"},
81+
}
82+
)
83+
return context

0 commit comments

Comments
 (0)