Skip to content

Commit e8f3899

Browse files
Add search feature for Manage users (#130)
This adds a search feature to enable users to search for active users rather than having to browse for them. It matches on either name or email address, and partial matches work based on the start of names, for example "ali" will return "Alissa Wells" and "lee" will return "Hayley Lee" but does not return "Jayleen Robertson". "amber.roth@" returns Amber Roth based on email matching. All searches are case-insensitive. After the search term has been entered and the "Search" button pressed, the table updates to show matching results, and the table `<caption>` (which looks like a heading) includes the count of users and the search term, eg: > Showing 2 active users matching “hay” If the search is empty or on the initial page load, the table caption is "All active users". There is no minimum number of characters to search on, so no need to display any error messages. If there are no matching results, then the table is completely removed and replaced with a paragraph saying: > No users matching “jason”. Search results are displayed in alphabetical order by first name then last name. The search results should be paginated if there are more than the per-page limit. 🗂️ [Jira card](https://nhsd-jira.digital.nhs.uk/browse/RAVS-959) ## Screenshots ![Screenshot 2024-11-01 at 13 06 43](https://github.com/user-attachments/assets/7386d570-63c3-4b9a-a766-2d2873087d0e) ![Screenshot 2024-11-01 at 13 09 37](https://github.com/user-attachments/assets/73f82947-1317-4ed4-bacc-85270aa17e8c)
1 parent bffe237 commit e8f3899

File tree

7 files changed

+119
-14
lines changed

7 files changed

+119
-14
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Short button variant
2+
//
3+
// This button is slightly shorter than the usual one,
4+
// so that when it sits to the right of a text input
5+
// (eg a search box) it is the same height.
6+
.app-button--small {
7+
@include nhsuk-typography-responsive(16);
8+
padding: nhsuk-spacing(1) 12px;
9+
10+
&.app-button--secondary,
11+
&.app-button--secondary-warning {
12+
// Adjust padding to account for removal of 2px bottom border
13+
padding-bottom: #{nhsuk-spacing(1) + 1px};
14+
padding-top: #{nhsuk-spacing(1) + 1px};
15+
16+
&:active {
17+
margin-bottom: -1px;
18+
// Revert padding to account for reintroduction of 2px bottom border
19+
padding-bottom: nhsuk-spacing(1);
20+
padding-top: nhsuk-spacing(1);
21+
}
22+
}
23+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// This component is used for filtering a list, eg using search
2+
.app-filters {
3+
padding: nhsuk-spacing(3) nhsuk-spacing(3) nhsuk-spacing(4) nhsuk-spacing(3);
4+
background-color: $color_nhsuk-grey-4;
5+
}

app/assets/sass/components/_table.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
11

2+
table {
3+
max-width: 100%;
4+
}
5+
6+
table td {
7+
word-break: break-all;
8+
}
9+
10+
11+
.app-table__header--min-width-100 {
12+
min-width: 100px;
13+
}
14+
15+
.app-table__header--min-width-200 {
16+
min-width: 100px;
17+
@include mq($from: desktop) {
18+
min-width: 200px;
19+
}
20+
}
221

322
.app-table__cell--border-right,
423
.app-table__header--border-right {

app/assets/sass/main.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ $govuk-brand-colour: $nhsuk-link-color;
2626
@import 'components/header';
2727
@import 'components/summary-list';
2828
@import 'components/table';
29+
@import 'components/button';
30+
@import 'components/filters';
2931

3032

3133
@import '../../components/pagination/_pagination';

app/data/session-data-defaults.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,15 @@ module.exports = {
424424
status: "Active",
425425
clinician: "no"
426426
},
427+
{
428+
id: "34643643",
429+
430+
firstName: "Sam",
431+
lastName: "Jones",
432+
role: "Recorder",
433+
status: "Active",
434+
clinician: "no"
435+
},
427436
{
428437
id: "1006456",
429438
@@ -547,7 +556,7 @@ module.exports = {
547556
firstName: "Jaelynn",
548557
lastName: "Chase",
549558
role: "Recorder",
550-
status: "Active",
559+
status: "Deactivated",
551560
clinician: "no"
552561
},
553562
{
@@ -930,7 +939,7 @@ module.exports = {
930939
},
931940
{
932941
id: "7199138",
933-
email: "aaden[email protected]",
942+
email: "aadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaadenaaden[email protected]",
934943
firstName: "Aaden",
935944
lastName: "Shah",
936945
role: "Recorder",

app/routes/user-admin.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ module.exports = (router) => {
55
const perPage = 20; // Max number of users to show per page
66
const page = parseInt(req.query.page) || 1 ; // Current page, default to 1
77

8+
const q = req.query.q;
89
const data = req.session.data;
910
const statusesToInclude = ['Invited', 'Active'];
10-
const allUsers = data.users
11+
let allUsers = data.users
1112
.filter((user) => statusesToInclude.includes(user.status))
1213
.sort((a, b) => {
1314
const nameA = a.firstName.toUpperCase(); // ignore upper and lowercase
@@ -21,6 +22,17 @@ module.exports = (router) => {
2122
return 0;
2223
})
2324

25+
if (q) {
26+
allUsers = allUsers.filter(function(user) {
27+
return (
28+
user.firstName.toLowerCase().startsWith(q.toLowerCase()) ||
29+
user.lastName.toLowerCase().startsWith(q.toLowerCase()) ||
30+
(user.firstName + " " + user.lastName).toLowerCase().startsWith(q.toLowerCase()) ||
31+
user.email.toLowerCase().startsWith(q.toLowerCase())
32+
)
33+
})
34+
}
35+
2436

2537
const totalUsers = allUsers.length
2638

@@ -37,7 +49,8 @@ module.exports = (router) => {
3749
totalPages,
3850
page,
3951
users,
40-
deactivatedUsers
52+
deactivatedUsers,
53+
q
4154
})
4255
})
4356

app/views/user-admin/index.html

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,37 @@ <h1 class="nhsuk-heading-xl">Manage users</h1>
1919
"href": "/user-admin/add-user"
2020
}) }}
2121

22-
<table class="nhsuk-table">
23-
<caption class="nhsuk-table__caption nhsuk-table__caption--m">Users</caption>
22+
23+
<div class="app-filters nhsuk-u-margin-top-5">
24+
<form action="/user-admin" method="get" novalidate>
25+
<div class="nhsuk-form-group nhsuk-u-margin-bottom-0">
26+
<label class="nhsuk-label" for="q">
27+
Search active users by name or email
28+
</label>
29+
<input class="nhsuk-input nhsuk-input--width-20" id="q" name="q" type="search" value="{{ q }}">
30+
31+
{{ button({
32+
text: "Search",
33+
classes: "nhsuk-button--secondary nhsuk-u-margin-left-2 app-button--small nhsuk-u-margin-bottom-0"
34+
})}}
35+
</div>
36+
</form>
37+
</div>
38+
39+
40+
{% if totalUsers > 0 %}
41+
42+
<table class="nhsuk-table nhsuk-u-margin-top-4">
43+
<caption class="nhsuk-table__caption nhsuk-table__caption--m">
44+
{% if q %}
45+
Showing {{ totalUsers | plural("active user") }} matching {{ q }}
46+
{% else %}
47+
All active users
48+
{% endif %}
49+
</caption>
2450
<thead role="rowgroup" class="nhsuk-table__head">
2551
<tr role="row">
26-
<th role="columnheader" class="" scope="col">
52+
<th role="columnheader" class="app-table__header--min-width-200" scope="col">
2753
Name
2854
</th>
2955
<th role="columnheader" class="" scope="col">
@@ -35,7 +61,7 @@ <h1 class="nhsuk-heading-xl">Manage users</h1>
3561
<th role="columnheader" class="" scope="col">
3662
Status
3763
</th>
38-
<th role="columnheader" class="" scope="col">
64+
<th role="columnheader" class="app-table__header--min-width-100" scope="col">
3965

4066
</th>
4167
</tr>
@@ -53,35 +79,43 @@ <h1 class="nhsuk-heading-xl">Manage users</h1>
5379
<td class="nhsuk-table__cell ">{{ user.email }}</td>
5480
<td class="nhsuk-table__cell ">{{ user.role }}</td>
5581
<td class="nhsuk-table__cell ">{{ user.status }}</td>
56-
<td class="nhsuk-table__cell">
82+
<td class="nhsuk-table__cell app-table__cell--right-aligned">
5783
<a href="/user-admin/users/{{ user.id }}/change-role" class="nhsuk-link">Change <span class="nhsuk-u-visually-hidden">details for {{ user.firstName }} </span></a>
5884
</td>
5985
</tr>
6086
{% endfor %}
6187
</tbody>
6288
</table>
6389

90+
{% else %}
91+
92+
<div class="nhsuk-u-margin-top-6 nhsuk-u-margin-bottom-6">
93+
<p>No users matching {{ q }}.</p>
94+
</div>
95+
96+
{% endif %}
97+
6498
{% set items = [] %}
6599

66100
{% for i in range(1, totalPages + 1) -%}
67101
{% set items = (items.push({
68102
number: i,
69-
href: "/user-admin?page=" + i,
103+
href: "/user-admin?page=" + i + "&q=" + (q if q else ""),
70104
current: (i === page)
71105
}), items) %}
72106
{%- endfor %}
73107

74108

75-
{% if totalPages > 0 %}
109+
{% if totalPages > 1 %}
76110
{{ appPagination({
77-
previousUrl: "/user-admin?page=" + (page - 1) if page != 1,
78-
nextUrl: "/user-admin?page=" + (page + 1) if page != totalPages,
111+
previousUrl: "/user-admin?page=" + (page - 1) + "&q=" + (q if q else "") if page != 1,
112+
nextUrl: "/user-admin?page=" + (page + 1) + "&q=" + (q if q else "") if page != totalPages,
79113
items: items
80114
}) }}
81115
{% endif %}
82116

83117

84-
{% if deactivatedUsers | length > 0 %}
118+
{% if (not q and q != "") and (deactivatedUsers | length > 0) %}
85119
<p><a href="/user-admin/deactivated">View {{ deactivatedUsers | length | plural ("deactivated user") }}</a> </p>
86120
{% endif %}
87121

0 commit comments

Comments
 (0)