From 06dbcf4d9faaaa781a9cd5c03bf82865ed513e58 Mon Sep 17 00:00:00 2001 From: danjohnstonUX <21033686+danjohnstonUX@users.noreply.github.com> Date: Fri, 11 Sep 2026 15:10:27 +0100 Subject: [PATCH] Add participant list and details pages and add participant database --- app/assets/sass/main.scss | 30 ++ app/data/participants.js | 328 +++++++++++--------- app/routes.js | 110 +++++++ app/views/_includes/primary-navigation.html | 2 +- app/views/index.html | 9 + app/views/participants/detail.html | 162 ++++++++++ app/views/participants/index.html | 115 +++++++ 7 files changed, 603 insertions(+), 153 deletions(-) create mode 100644 app/views/participants/detail.html create mode 100644 app/views/participants/index.html diff --git a/app/assets/sass/main.scss b/app/assets/sass/main.scss index b57d3ddb..c94cdc60 100755 --- a/app/assets/sass/main.scss +++ b/app/assets/sass/main.scss @@ -106,6 +106,36 @@ a { width: 100%; } +.app-participants-toolbar { + display: flex; + justify-content: space-between; + align-items: baseline; + gap: 24px; + margin-bottom: 24px; + + > p { + margin-bottom: 0; + } +} + +.app-participants-sort-form { + display: flex; + align-items: baseline; + gap: 8px; + margin-bottom: 0; + + .nhsuk-label { + margin-bottom: 0; + white-space: nowrap; + } +} + +@include nhsuk-media-query($from: tablet) { + .app-participants-sort-form { + flex-shrink: 0; + } +} + .nhsuk-grid-column-four-fifths { @include nhsuk-grid-column(four-fifths); diff --git a/app/data/participants.js b/app/data/participants.js index 64cf0904..e71e5398 100644 --- a/app/data/participants.js +++ b/app/data/participants.js @@ -1,152 +1,176 @@ -export default [ - { participantId: 'p0001', nhs_number: "999 054 3666", full_name: "Billie Joanne Marquardt", date_of_birth: "15 March 1960", status: "unstaged" }, - { participantId: 'p0002', nhs_number: "999 582 7164", full_name: "Alice Marie Gregory", date_of_birth: "8 November 1964", status: "unstaged" }, - { participantId: 'p0003', nhs_number: "999 374 0952", full_name: "Daphne Hart", date_of_birth: "22 July 1958", status: "unstaged" }, - { participantId: 'p0004', nhs_number: "999 195 4836", full_name: "Marta O'Neill", date_of_birth: "3 May 1971", status: "unstaged" }, - { participantId: 'p0005', nhs_number: "999 287 9305", full_name: "Susan Carter", date_of_birth: "19 September 1967", status: "unstaged" }, - { participantId: 'p0006', nhs_number: "999 463 1129", full_name: "Olivia Barnes", date_of_birth: "12 January 1975", status: "unstaged" }, - { participantId: 'p0007', nhs_number: "999 774 2201", full_name: "Rachel Price", date_of_birth: "27 April 1962", status: "unstaged" }, - { participantId: 'p0008', nhs_number: "999 546 8870", full_name: "Hannah Wallace", date_of_birth: "6 October 1959", status: "unstaged" }, - { participantId: 'p0009', nhs_number: "999 559 3322", full_name: "Fiona Lambert", date_of_birth: "14 December 1973", status: "unstaged" }, - { participantId: 'p0010', nhs_number: "999 804 7753", full_name: "Georgia Mills", date_of_birth: "30 June 1968", status: "unstaged" }, - { participantId: 'p0011', nhs_number: "999 290 4601", full_name: "Elaine Fox", date_of_birth: "11 February 1976", status: "unstaged" }, - { participantId: 'p0012', nhs_number: "999 613 2084", full_name: "Tessa King", date_of_birth: "25 August 1963", status: "unstaged" }, - { participantId: 'p0013', nhs_number: "999 118 9756", full_name: "Nadia Singh", date_of_birth: "7 April 1957", status: "unstaged" }, - { participantId: 'p0014', nhs_number: "999 039 6617", full_name: "Jane Reed", date_of_birth: "18 November 1970", status: "unstaged" }, - { participantId: 'p0015', nhs_number: "999 259 1148", full_name: "Laura White", date_of_birth: "29 May 1965", status: "unstaged" }, - { participantId: 'p0016', nhs_number: "999 880 3320", full_name: "Marissa Young", date_of_birth: "9 March 1961", status: "unstaged" }, - { participantId: 'p0017', nhs_number: "999 901 7732", full_name: "Naomi Bell", date_of_birth: "21 September 1974", status: "unstaged" }, - { participantId: 'p0018', nhs_number: "999 216 5087", full_name: "Paige Long", date_of_birth: "4 July 1969", status: "unstaged" }, - { participantId: 'p0019', nhs_number: "999 487 9901", full_name: "Catherine Wood", date_of_birth: "16 January 1956", status: "unstaged" }, - { participantId: 'p0020', nhs_number: "999 603 1774", full_name: "Victoria Hale", date_of_birth: "13 October 1966", status: "unstaged" }, - { participantId: 'p0021', nhs_number: "999 905 6423", full_name: "Imogen Frost", date_of_birth: "31 December 1972", status: "unstaged" }, - { participantId: 'p0022', nhs_number: "999 332 1108", full_name: "Dara Moss", date_of_birth: "24 June 1960", status: "unstaged" }, - { participantId: 'p0023', nhs_number: "999 427 5930", full_name: "Sophie Hartley", date_of_birth: "2 August 1962", status: "unstaged" }, - { participantId: 'p0024', nhs_number: "999 218 3446", full_name: "Emma Cole", date_of_birth: "17 April 1975", status: "unstaged" }, - { participantId: 'p0025', nhs_number: "999 109 8875", full_name: "Megan Price", date_of_birth: "5 February 1961", status: "unstaged" }, - { participantId: 'p0026', nhs_number: "999 678 2209", full_name: "Mia Ford", date_of_birth: "19 May 1972", status: "unstaged" }, - { participantId: 'p0027', nhs_number: "999 502 6683", full_name: "Zoe Grant", date_of_birth: "11 March 1965", status: "unstaged" }, - { participantId: 'p0028', nhs_number: "999 244 1196", full_name: "Ariana Miles", date_of_birth: "28 November 1959", status: "unstaged" }, - { participantId: 'p0029', nhs_number: "999 883 4455", full_name: "Bethany Cross", date_of_birth: "7 July 1975", status: "unstaged" }, - { participantId: 'p0030', nhs_number: "999 771 9002", full_name: "Callie Morris", date_of_birth: "14 September 1968", status: "unstaged" }, - { participantId: 'p0031', nhs_number: "999 439 3321", full_name: "Helena Rowe", date_of_birth: "2 April 1963", status: "unstaged" }, - { participantId: 'p0032', nhs_number: "999 210 5587", full_name: "Danielle Nash", date_of_birth: "23 June 1970", status: "unstaged" }, - { participantId: 'p0033', nhs_number: "999 619 4470", full_name: "Faye Turner", date_of_birth: "8 January 1957", status: "unstaged" }, - { participantId: 'p0034', nhs_number: "999 908 2233", full_name: "Leona Grant", date_of_birth: "15 October 1974", status: "unstaged" }, - { participantId: 'p0035', nhs_number: "999 776 9904", full_name: "Nora Blake", date_of_birth: "30 December 1966", status: "unstaged" }, - { participantId: 'p0036', nhs_number: "999 665 8805", full_name: "Olivia Lee", date_of_birth: "19 August 1960", status: "unstaged" }, - { participantId: 'p0037', nhs_number: "999 554 7706", full_name: "Priya Desai", date_of_birth: "10 May 1973", status: "unstaged" }, - { participantId: 'p0038', nhs_number: "999 443 6607", full_name: "Quinn Park", date_of_birth: "26 March 1964", status: "unstaged" }, - { participantId: 'p0039', nhs_number: "999 332 5508", full_name: "Rosa Kirk", date_of_birth: "13 July 1958", status: "unstaged" }, - { participantId: 'p0040', nhs_number: "999 221 4409", full_name: "Shannon Boyd", date_of_birth: "22 November 1971", status: "unstaged" }, - { participantId: 'p0041', nhs_number: "999 110 3310", full_name: "Tara Voss", date_of_birth: "9 February 1969", status: "unstaged" }, - { participantId: 'p0042', nhs_number: "999 009 2201", full_name: "Uma Jha", date_of_birth: "17 September 1962", status: "unstaged" }, - { participantId: 'p0043', nhs_number: "999 898 1192", full_name: "Victoria Dean", date_of_birth: "4 April 1976", status: "unstaged" }, - { participantId: 'p0044', nhs_number: "999 787 0083", full_name: "Wendy Fox", date_of_birth: "21 June 1967", status: "unstaged" }, - { participantId: 'p0045', nhs_number: "999 676 9974", full_name: "Xena Holt", date_of_birth: "11 December 1960", status: "unstaged" }, - { participantId: 'p0046', nhs_number: "999 565 8865", full_name: "Yasmin Noor", date_of_birth: "28 August 1961", status: "unstaged" }, - { participantId: 'p0047', nhs_number: "999 454 7756", full_name: "Zara Moon", date_of_birth: "6 May 1973", status: "unstaged" }, - { participantId: 'p0048', nhs_number: "999 343 6647", full_name: "Abigail Stone", date_of_birth: "14 October 1959", status: "unstaged" }, - { participantId: 'p0049', nhs_number: "999 000 0001", full_name: "Olivia Smith", date_of_birth: "12 March 1968", status: "unstaged" }, - { participantId: 'p0050', nhs_number: "999 000 0002", full_name: "Emily Johnson", date_of_birth: "5 June 1974", status: "unstaged" }, - { participantId: 'p0051', nhs_number: "999 000 0003", full_name: "Charlotte Taylor", date_of_birth: "23 September 1961", status: "unstaged" }, - { participantId: 'p0052', nhs_number: "999 000 0004", full_name: "Sophie Brown", date_of_birth: "18 January 1959", status: "unstaged" }, - { participantId: 'p0053', nhs_number: "999 000 0005", full_name: "Chloe Williams", date_of_birth: "7 July 1970", status: "unstaged" }, - { participantId: 'p0054', nhs_number: "999 000 0006", full_name: "Amelia Davies", date_of_birth: "30 November 1965", status: "unstaged" }, - { participantId: 'p0055', nhs_number: "999 000 0007", full_name: "Isla Evans", date_of_birth: "2 April 1963", status: "unstaged" }, - { participantId: 'p0056', nhs_number: "999 000 0008", full_name: "Mia Wilson", date_of_birth: "14 February 1967", status: "unstaged" }, - { participantId: 'p0057', nhs_number: "999 000 0009", full_name: "Ella Thomas", date_of_birth: "29 May 1976", status: "unstaged" }, - { participantId: 'p0058', nhs_number: "999 000 0010", full_name: "Grace Roberts", date_of_birth: "11 August 1962", status: "unstaged" }, - { participantId: 'p0059', nhs_number: "999 000 0011", full_name: "Lily Johnson", date_of_birth: "4 October 1958", status: "unstaged" }, - { participantId: 'p0060', nhs_number: "999 000 0012", full_name: "Hannah Lewis", date_of_birth: "25 March 1964", status: "unstaged" }, - { participantId: 'p0061', nhs_number: "999 000 0013", full_name: "Ruby Walker", date_of_birth: "9 December 1960", status: "unstaged" }, - { participantId: 'p0062', nhs_number: "999 000 0014", full_name: "Evie Wright", date_of_birth: "16 May 1969", status: "unstaged" }, - { participantId: 'p0063', nhs_number: "999 000 0015", full_name: "Isabelle Robinson", date_of_birth: "21 November 1957", status: "unstaged" }, - { participantId: 'p0064', nhs_number: "999 000 0016", full_name: "Alice Wood", date_of_birth: "6 July 1971", status: "unstaged" }, - { participantId: 'p0065', nhs_number: "999 000 0017", full_name: "Matilda Thompson", date_of_birth: "19 April 1966", status: "unstaged" }, - { participantId: 'p0066', nhs_number: "999 000 0018", full_name: "Poppy White", date_of_birth: "27 February 1963", status: "unstaged" }, - { participantId: 'p0067', nhs_number: "999 000 0019", full_name: "Jessica Watson", date_of_birth: "1 January 1957", status: "unstaged" }, - { participantId: 'p0068', nhs_number: "999 000 0020", full_name: "Sarah Jackson", date_of_birth: "8 September 1968", status: "unstaged" }, - { participantId: 'p0069', nhs_number: "999 000 0021", full_name: "Laura Clarke", date_of_birth: "13 June 1962", status: "unstaged" }, - { participantId: 'p0070', nhs_number: "999 000 0022", full_name: "Megan Harrison", date_of_birth: "22 August 1959", status: "unstaged" }, - { participantId: 'p0071', nhs_number: "999 000 0023", full_name: "Victoria Green", date_of_birth: "3 March 1973", status: "unstaged" }, - { participantId: 'p0072', nhs_number: "999 000 0024", full_name: "Natalie Hall", date_of_birth: "15 October 1965", status: "unstaged" }, - { participantId: 'p0073', nhs_number: "999 000 0025", full_name: "Lauren Cooper", date_of_birth: "28 November 1961", status: "unstaged" }, - { participantId: 'p0074', nhs_number: "999 000 0026", full_name: "Zoe Mitchell", date_of_birth: "10 May 1960", status: "unstaged" }, - { participantId: 'p0075', nhs_number: "999 000 0027", full_name: "Amber Morgan", date_of_birth: "17 July 1969", status: "unstaged" }, - { participantId: 'p0076', nhs_number: "999 000 0028", full_name: "Lydia Hill", date_of_birth: "2 December 1975", status: "unstaged" }, - { participantId: 'p0077', nhs_number: "999 000 0029", full_name: "Bethany Moore", date_of_birth: "24 April 1958", status: "unstaged" }, - { participantId: 'p0078', nhs_number: "999 000 0030", full_name: "Natalie Ward", date_of_birth: "30 September 1964", status: "unstaged" }, - { participantId: 'p0079', nhs_number: "999 000 0031", full_name: "Rebecca Edwards", date_of_birth: "5 February 1970", status: "unstaged" }, - { participantId: 'p0080', nhs_number: "999 000 0032", full_name: "Danielle Hughes", date_of_birth: "14 June 1967", status: "unstaged" }, - { participantId: 'p0081', nhs_number: "999 000 0033", full_name: "Fiona Turner", date_of_birth: "9 October 1963", status: "unstaged" }, - { participantId: 'p0082', nhs_number: "999 000 0034", full_name: "Rachel Parker", date_of_birth: "26 January 1956", status: "unstaged" }, - { participantId: 'p0083', nhs_number: "999 000 0035", full_name: "Nicola Collins", date_of_birth: "7 August 1966", status: "unstaged" }, - { participantId: 'p0084', nhs_number: "999 000 0036", full_name: "Claire Stewart", date_of_birth: "12 November 1971", status: "unstaged" }, - { participantId: 'p0085', nhs_number: "999 000 0037", full_name: "Joanne Morris", date_of_birth: "19 March 1962", status: "unstaged" }, - { participantId: 'p0086', nhs_number: "999 000 0038", full_name: "Lorraine Rogers", date_of_birth: "3 May 1974", status: "unstaged" }, - { participantId: 'p0087', nhs_number: "999 000 0039", full_name: "Angela Cook", date_of_birth: "22 July 1958", status: "unstaged" }, - { participantId: 'p0088', nhs_number: "999 000 0040", full_name: "Emma Murphy", date_of_birth: "27 September 1969", status: "unstaged" }, - { participantId: 'p0089', nhs_number: "999 000 0041", full_name: "Jill Richardson", date_of_birth: "6 April 1965", status: "unstaged" }, - { participantId: 'p0090', nhs_number: "999 000 0042", full_name: "Sandra Cox", date_of_birth: "15 December 1957", status: "unstaged" }, - { participantId: 'p0091', nhs_number: "999 000 0043", full_name: "Yasmin Baker", date_of_birth: "23 June 1961", status: "unstaged" }, - { participantId: 'p0092', nhs_number: "999 000 0044", full_name: "Paige Bell", date_of_birth: "11 October 1970", status: "unstaged" }, - { participantId: 'p0093', nhs_number: "999 000 0045", full_name: "Harriet Butler", date_of_birth: "2 February 1968", status: "unstaged" }, - { participantId: 'p0094', nhs_number: "999 000 0046", full_name: "Imogen Gray", date_of_birth: "29 May 1964", status: "unstaged" }, - { participantId: 'p0095', nhs_number: "999 000 0047", full_name: "Tessa Chapman", date_of_birth: "18 November 1962", status: "unstaged" }, - { participantId: 'p0096', nhs_number: "999 000 0048", full_name: "Darcey Ellis", date_of_birth: "4 July 1973", status: "unstaged" }, - { participantId: 'p0097', nhs_number: "999 000 0049", full_name: "Casey Kelly", date_of_birth: "30 March 1960", status: "unstaged" }, - { participantId: 'p0098', nhs_number: "999 000 0050", full_name: "Morgan Porter", date_of_birth: "21 August 1959", status: "unstaged" }, - { participantId: 'p0099', nhs_number: "999 000 0051", full_name: "Alex Pearson", date_of_birth: "8 January 1966", status: "unstaged" }, - { participantId: 'p0100', nhs_number: "999 000 0052", full_name: "Jamie Barker", date_of_birth: "14 October 1963", status: "unstaged" }, - { participantId: 'p0101', nhs_number: "999 000 0053", full_name: "Rowan Hudson", date_of_birth: "25 May 1967", status: "unstaged" }, - { participantId: 'p0102', nhs_number: "999 000 0054", full_name: "Riley Harvey", date_of_birth: "6 April 1958", status: "unstaged" }, - { participantId: 'p0103', nhs_number: "999 000 0055", full_name: "Avery Powell", date_of_birth: "13 September 1975", status: "unstaged" }, - { participantId: 'p0104', nhs_number: "999 000 0056", full_name: "Quinn Jenkins", date_of_birth: "28 February 1961", status: "unstaged" }, - { participantId: 'p0105', nhs_number: "999 000 0057", full_name: "Jordan Simpson", date_of_birth: "17 June 1969", status: "unstaged" }, - { participantId: 'p0106', nhs_number: "999 000 0058", full_name: "Taylor Matthews", date_of_birth: "3 November 1960", status: "unstaged" }, - { participantId: 'p0107', nhs_number: "999 000 0059", full_name: "Sam Davidson", date_of_birth: "12 July 1964", status: "unstaged" }, - { participantId: 'p0108', nhs_number: "999 000 0060", full_name: "Pat Palmer", date_of_birth: "20 March 1956", status: "unstaged" }, - { participantId: 'p0109', nhs_number: "999 000 0061", full_name: "Blair Grant", date_of_birth: "9 September 1968", status: "unstaged" }, - { participantId: 'p0110', nhs_number: "999 000 0062", full_name: "Darcy Price", date_of_birth: "1 December 1965", status: "unstaged" }, - { participantId: 'p0111', nhs_number: "999 000 0063", full_name: "Skylar Grant", date_of_birth: "14 August 1971", status: "unstaged" }, - { participantId: 'p0112', nhs_number: "999 000 0064", full_name: "Noel King", date_of_birth: "5 May 1959", status: "unstaged" }, - { participantId: 'p0113', nhs_number: "999 000 0065", full_name: "Ariel Lee", date_of_birth: "23 January 1962", status: "unstaged" }, - { participantId: 'p0114', nhs_number: "999 000 0066", full_name: "Shannon Baker", date_of_birth: "11 November 1967", status: "unstaged" }, - { participantId: 'p0115', nhs_number: "999 000 0067", full_name: "Kerry Webb", date_of_birth: "4 April 1963", status: "unstaged" }, - { participantId: 'p0116', nhs_number: "999 000 0068", full_name: "Shannon Reid", date_of_birth: "29 June 1974", status: "unstaged" }, - { participantId: 'p0117', nhs_number: "999 000 0069", full_name: "Kelly Fox", date_of_birth: "16 October 1969", status: "unstaged" }, - { participantId: 'p0118', nhs_number: "999 000 0070", full_name: "Casey Ward", date_of_birth: "7 March 1966", status: "unstaged" }, - { participantId: 'p0119', nhs_number: "999 000 0071", full_name: "Rowan Stone", date_of_birth: "30 August 1961", status: "unstaged" }, - { participantId: 'p0120', nhs_number: "999 000 0072", full_name: "Skye Doyle", date_of_birth: "19 May 1958", status: "unstaged" }, - { participantId: 'p0121', nhs_number: "999 000 0073", full_name: "Morgan Heath", date_of_birth: "2 September 1960", status: "unstaged" }, - { participantId: 'p0122', nhs_number: "999 000 0074", full_name: "Alex Murray", date_of_birth: "25 December 1964", status: "unstaged" }, - { participantId: 'p0123', nhs_number: "999 000 0075", full_name: "Taylor Hughes", date_of_birth: "10 February 1967", status: "unstaged" }, - { participantId: 'p0124', nhs_number: "999 000 0076", full_name: "Jamie Arnold", date_of_birth: "18 July 1972", status: "unstaged" }, - { participantId: 'p0125', nhs_number: "999 000 0077", full_name: "Riley Bates", date_of_birth: "6 November 1957", status: "unstaged" }, - { participantId: 'p0126', nhs_number: "999 000 0078", full_name: "Avery Gill", date_of_birth: "22 April 1965", status: "unstaged" }, - { participantId: 'p0127', nhs_number: "999 000 0079", full_name: "Quinn Ellis", date_of_birth: "13 June 1963", status: "unstaged" }, - { participantId: 'p0128', nhs_number: "999 000 0080", full_name: "Jordan Neal", date_of_birth: "27 September 1969", status: "unstaged" }, - { participantId: 'p0129', nhs_number: "999 000 0081", full_name: "Casey Walton", date_of_birth: "8 December 1958", status: "unstaged" }, - { participantId: 'p0130', nhs_number: "999 000 0082", full_name: "Sam Nash", date_of_birth: "15 January 1966", status: "unstaged" }, - { participantId: 'p0131', nhs_number: "999 000 0083", full_name: "Robin Blake", date_of_birth: "4 October 1970", status: "unstaged" }, - { participantId: 'p0132', nhs_number: "999 000 0084", full_name: "Frances Potter", date_of_birth: "21 March 1959", status: "unstaged" }, - { participantId: 'p0133', nhs_number: "999 000 0085", full_name: "Marlow Bishop", date_of_birth: "11 July 1968", status: "unstaged" }, - { participantId: 'p0134', nhs_number: "999 000 0086", full_name: "Ellis Finch", date_of_birth: "29 November 1962", status: "unstaged" }, - { participantId: 'p0135', nhs_number: "999 000 0087", full_name: "Darcy Lane", date_of_birth: "6 May 1961", status: "unstaged" }, - { participantId: 'p0136', nhs_number: "999 000 0088", full_name: "Sky Morgan", date_of_birth: "17 August 1964", status: "unstaged" }, - { participantId: 'p0137', nhs_number: "999 000 0089", full_name: "Rowan Finch", date_of_birth: "3 June 1971", status: "unstaged" }, - { participantId: 'p0138', nhs_number: "999 000 0090", full_name: "Taylor Fields", date_of_birth: "24 February 1967", status: "unstaged" }, - { participantId: 'p0139', nhs_number: "999 000 0091", full_name: "Alex Rivers", date_of_birth: "13 October 1956", status: "unstaged" }, - { participantId: 'p0140', nhs_number: "999 000 0092", full_name: "Morgan Heath", date_of_birth: "2 January 1963", status: "unstaged" }, - { participantId: 'p0141', nhs_number: "999 000 0093", full_name: "Jamie Park", date_of_birth: "30 April 1969", status: "unstaged" }, - { participantId: 'p0142', nhs_number: "999 000 0094", full_name: "Riley Fox", date_of_birth: "9 September 1965", status: "unstaged" }, - { participantId: 'p0143', nhs_number: "999 000 0095", full_name: "Avery Cross", date_of_birth: "5 June 1975", status: "unstaged" }, - { participantId: 'p0144', nhs_number: "999 000 0096", full_name: "Quinn Haynes", date_of_birth: "18 August 1958", status: "unstaged" }, - { participantId: 'p0145', nhs_number: "999 000 0097", full_name: "Jordan Vance", date_of_birth: "27 November 1966", status: "unstaged" }, - { participantId: 'p0146', nhs_number: "999 000 0098", full_name: "Taylor Webb", date_of_birth: "14 February 1970", status: "unstaged" }, - { participantId: 'p0147', nhs_number: "999 000 0099", full_name: "Sam Rector", date_of_birth: "1 October 1962", status: "unstaged" }, - { participantId: 'p0148', nhs_number: "999 000 0100", full_name: "Casey Milton", date_of_birth: "20 July 1968", status: "unstaged" }, - { participantId: 'p0149', nhs_number: "999 000 0101", full_name: "Alex Harper", date_of_birth: "11 March 1960", status: "unstaged" }, - { participantId: 'p0150', nhs_number: "999 000 0102", full_name: "Morgan Kane", date_of_birth: "22 December 1957", status: "unstaged" } -]; +const firstNames = [ + 'Amelia', 'Aisha', 'Alice', 'Angela', 'Anita', 'Charlotte', 'Claire', + 'Diane', 'Elizabeth', 'Emma', 'Fiona', 'Grace', 'Hannah', 'Helen', + 'Imogen', 'Janet', 'Joanne', 'Julia', 'Karen', 'Laura', 'Linda', + 'Louise', 'Maria', 'Megan', 'Michelle', 'Natalie', 'Nicola', 'Olivia', + 'Patricia', 'Rachel', 'Rebecca', 'Ruth', 'Sarah', 'Sharon', 'Sophie', + 'Susan', 'Teresa', 'Tracey', 'Victoria', 'Wendy', 'Yasmin' +] + +const middleNames = [ + 'Anne', 'Beatrice', 'Catherine', 'Dawn', 'Elaine', 'Jane', 'Jean', + 'Louise', 'Marie', 'May', 'Rose', 'Victoria' +] + +const surnames = [ + 'Adams', 'Baker', 'Bennett', 'Bishop', 'Brown', 'Campbell', 'Carter', + 'Chapman', 'Clarke', 'Collins', 'Cooper', 'Davies', 'Dawson', 'Dixon', + 'Edwards', 'Ellis', 'Evans', 'Fisher', 'Foster', 'Fox', 'Graham', + 'Grant', 'Green', 'Griffiths', 'Hall', 'Harris', 'Harrison', 'Hart', + 'Harvey', 'Henderson', 'Hill', 'Hughes', 'Jackson', 'James', 'Jenkins', + 'Johnson', 'Jones', 'Kelly', 'King', 'Knight', 'Lane', 'Lawrence', + 'Lee', 'Lewis', 'Lloyd', 'Marshall', 'Martin', 'Mason', 'Matthews', + 'Miller', 'Mills', 'Mitchell', 'Moore', 'Morgan', 'Morris', 'Moss', + 'Murphy', 'Murray', 'Nash', 'Nelson', 'Nicholson', 'Parker', 'Patel', + 'Pearson', 'Perry', 'Phillips', 'Price', 'Reed', 'Rees', 'Reid', + 'Richards', 'Roberts', 'Robinson', 'Rogers', 'Rose', 'Russell', 'Scott', + 'Shaw', 'Simpson', 'Smith', 'Stevens', 'Stewart', 'Stone', 'Taylor', + 'Thomas', 'Thompson', 'Turner', 'Walker', 'Wallace', 'Walsh', 'Ward', + 'Watson', 'Webb', 'West', 'White', 'Wilkinson', 'Williams', 'Wilson', + 'Wood', 'Wright', 'Young' +] + +const internationalNames = [ + { firstName: 'Amina', surname: 'Rahman' }, + { firstName: 'Ananya', surname: 'Sharma' }, + { firstName: 'Beatriz', surname: 'Gomes' }, + { firstName: 'Chiamaka', surname: 'Okafor' }, + { firstName: 'Fatima', surname: 'Khan' }, + { firstName: 'Hana', surname: 'Sato' }, + { firstName: 'Leila', surname: 'Haddad' }, + { firstName: 'Mei', surname: 'Wong' }, + { firstName: 'Nadia', surname: 'Petrova' }, + { firstName: 'Priyanka', surname: 'Patel' }, + { firstName: 'Samira', surname: 'Hassan' }, + { firstName: 'Thandiwe', surname: 'Ndlovu' }, + { firstName: 'Valentina', surname: 'Rossi' }, + { firstName: 'Wei', surname: 'Chen' }, + { firstName: 'Zeinab', surname: 'Ali' } +] + +const streets = [ + 'Ash Grove', 'Beech Avenue', 'Brook Lane', 'Cedar Road', 'Church Street', + 'Elm Close', 'Fairview Drive', 'Garden Way', 'Hawthorn Road', + 'Highfield Avenue', 'Meadow Lane', 'Oak Street', 'Orchard Close', + 'Park View', 'Station Road', 'The Crescent', 'Willow Drive' +] + +const towns = [ + { name: 'Brightmere', postcode: 'BM1 4AB' }, + { name: 'Cedarford', postcode: 'CF2 7CD' }, + { name: 'Fairwick', postcode: 'FW3 5EF' }, + { name: 'Greystone', postcode: 'GS4 8GH' }, + { name: 'Oakminster', postcode: 'OM5 2JK' }, + { name: 'Westcombe', postcode: 'WC6 9LM' } +] + +const months = [ + 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December' +] + +const pad = (value, width = 2) => String(value).padStart(width, '0') +const formatDate = (date) => `${pad(date.getDate())} ${months[date.getMonth()]} ${date.getFullYear()}` +const addDays = (date, days) => { + const result = new Date(date) + result.setDate(result.getDate() + days) + return result +} + +const formatRelativeDate = (date, today) => { + const days = Math.max(0, Math.round((date - today) / 86400000)) + + if (days < 7) { + return `In ${days} day${days === 1 ? '' : 's'}` + } + + const weeks = Math.round(days / 7) + if (weeks < 8) { + return `In ${weeks} week${weeks === 1 ? '' : 's'}` + } + + const months = Math.max(1, Math.round(days / 30)) + return `In ${months} month${months === 1 ? '' : 's'}` +} + +const calculateAge = (dateOfBirth, today) => { + let age = today.getFullYear() - dateOfBirth.getFullYear() + const birthdayThisYear = new Date(today.getFullYear(), dateOfBirth.getMonth(), dateOfBirth.getDate()) + + if (today < birthdayThisYear) { + age -= 1 + } + + return age +} + +const dateOfBirthFor = (index, today) => { + const age = 50 + (index % 22) + const date = new Date(today.getFullYear() - age, (index * 5) % 12, 1 + ((index * 7) % 27)) + + if (date > new Date(today.getFullYear() - 50, today.getMonth(), today.getDate())) { + date.setFullYear(date.getFullYear() - 1) + } + return date +} + +const createParticipant = (index, today) => { + const internationalName = index % 10 === 0 ? internationalNames[Math.floor(index / 10) % internationalNames.length] : null + const firstName = internationalName ? internationalName.firstName : firstNames[index % firstNames.length] + const surname = internationalName ? internationalName.surname : surnames[(index * 7) % surnames.length] + const middleName = index % 3 === 0 ? ` ${middleNames[(index * 3) % middleNames.length]}` : '' + const town = towns[index % towns.length] + const dateOfBirth = dateOfBirthFor(index, today) + const nextTestDueDays = 7 + ((index * 11) % 84) + const dueDate = addDays(today, nextTestDueDays) + const isBreaching = index === 7 || index === 83 + const hasScheduledAppointment = isBreaching || (index % 4 === 0 && index !== 4 && index !== 8) + const nextAppointmentDays = !hasScheduledAppointment + ? null + : isBreaching + ? nextTestDueDays + 5 + (index % 4) + : 3 + ((index * 9) % Math.max(4, nextTestDueDays - 2)) + const appointmentDate = nextAppointmentDays === null ? null : addDays(today, nextAppointmentDays) + const specialAppointmentRequired = index % 17 === 0 + const episodeStages = ['scheduled', 'scheduled', 'scheduled', 'scheduled', 'mammograms', 'reading', 'assessment', 'closed'] + const mobile = `07700 9${pad(index % 100)}${pad((index * 13) % 1000, 3)}` + const home = `01632 960${pad((index * 17) % 1000, 3)}` + + return { + participantId: `p${pad(index + 1)}`, + full_name: `${surname.toUpperCase()}, ${firstName}${middleName}`, + surname_sort_value: surname.toUpperCase(), + nhs_number: `999 ${pad((index * 37) % 1000, 3)} ${pad((index * 97 + 1) % 10000, 4)}`, + date_of_birth: formatDate(dateOfBirth), + age: calculateAge(dateOfBirth, today), + gender: 'Female', + ethnicity: 'Not recorded', + address: { + houseNumber: String(1 + ((index * 13) % 98)), + street: streets[index % streets.length], + town: town.name, + postcode: town.postcode + }, + phone_numbers: { mobile, home: index % 4 === 0 ? home : '' }, + email: `${firstName.toLowerCase()}.${surname.toLowerCase()}${index + 1}@example.com`, + sx_number: `ECX${String((index * 7919 + 104729) % 1000000).padStart(6, '0')}`, + next_test_due_days: nextTestDueDays, + next_test_due_date: formatDate(dueDate), + next_test_due_date_value: dueDate.getTime(), + next_test_due_date_relative: formatRelativeDate(dueDate, today), + episode_stage: episodeStages[index % episodeStages.length], + next_appointment_days: nextAppointmentDays, + next_appointment_date: appointmentDate ? formatDate(appointmentDate) : 'Not known', + next_appointment_date_value: appointmentDate ? appointmentDate.getTime() : null, + next_appointment_date_relative: appointmentDate ? formatRelativeDate(appointmentDate, today) : 'Not known', + special_appointment_required: specialAppointmentRequired ? 'Yes' : 'No', + special_appointment_information: '', + further_information: '', + status: 'unstaged', + is_breaching: isBreaching + } +} + +const today = new Date() + +export default Array.from({ length: 150 }, (_, index) => createParticipant(index, today)) diff --git a/app/routes.js b/app/routes.js index 562634cd..6764f7d6 100644 --- a/app/routes.js +++ b/app/routes.js @@ -3,6 +3,63 @@ const express = require('express') const router = express.Router() +const participantMonths = [ + 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December' +] + +const participantDateFromToday = (today, days) => { + const date = new Date(today) + date.setDate(date.getDate() + days) + return date +} + +const formatParticipantDate = (date) => `${String(date.getDate()).padStart(2, '0')} ${participantMonths[date.getMonth()]} ${date.getFullYear()}` + +const formatParticipantRelativeDate = (date, today) => { + const days = Math.max(0, Math.round((date - today) / 86400000)) + + if (days < 7) { + return `In ${days} day${days === 1 ? '' : 's'}` + } + + const weeks = Math.round(days / 7) + if (weeks < 8) { + return `In ${weeks} week${weeks === 1 ? '' : 's'}` + } + + const months = Math.max(1, Math.round(days / 30)) + return `In ${months} month${months === 1 ? '' : 's'}` +} + +const refreshParticipantDates = (participant, today) => { + const nextTestDueDate = participantDateFromToday(today, participant.next_test_due_days) + const nextAppointmentDate = participant.next_appointment_days === null + ? null + : participantDateFromToday(today, participant.next_appointment_days) + + return { + ...participant, + next_test_due_date: formatParticipantDate(nextTestDueDate), + next_test_due_date_value: nextTestDueDate.getTime(), + next_test_due_date_relative: formatParticipantRelativeDate(nextTestDueDate, today), + next_appointment_date: nextAppointmentDate ? formatParticipantDate(nextAppointmentDate) : 'Not known', + next_appointment_date_value: nextAppointmentDate ? nextAppointmentDate.getTime() : null, + next_appointment_date_relative: nextAppointmentDate ? formatParticipantRelativeDate(nextAppointmentDate, today) : 'Not known' + } +} + +const compareAppointmentDates = (a, b, direction) => { + const aUnknown = a.next_appointment_date_value === null + const bUnknown = b.next_appointment_date_value === null + + if (aUnknown && bUnknown) return 0 + if (aUnknown) return 1 + if (bUnknown) return -1 + + return direction * (a.next_appointment_date_value - b.next_appointment_date_value) +} + //======= September test specific for now // Utility function to generate calendar month data @@ -724,6 +781,59 @@ router.post('/sessions/02-organise-slots', function (req, res) { // Isolated September Test (Mission 1) routes router.use(require('./routes/mission-1')); +router.get('/participants', function (req, res) { + const sort = req.query.sort || 'due-soonest' + const today = new Date() + today.setHours(0, 0, 0, 0) + const allParticipants = ((req.session.data.participants && req.session.data.participants.default) || []) + .map(participant => refreshParticipantDates(participant, today)) + const sortComparators = { + 'name-asc': (a, b) => a.surname_sort_value.localeCompare(b.surname_sort_value), + 'name-desc': (a, b) => b.surname_sort_value.localeCompare(a.surname_sort_value), + 'due-soonest': (a, b) => a.next_test_due_date_value - b.next_test_due_date_value, + 'due-latest': (a, b) => b.next_test_due_date_value - a.next_test_due_date_value, + 'screening-soonest': (a, b) => compareAppointmentDates(a, b, 1), + 'screening-latest': (a, b) => compareAppointmentDates(a, b, -1), + 'age-oldest': (a, b) => b.age - a.age, + 'age-youngest': (a, b) => a.age - b.age + } + + allParticipants.sort(sortComparators[sort] || sortComparators['name-asc']) + + const pageSize = 100 + const totalParticipants = allParticipants.length + const totalPages = Math.max(1, Math.ceil(totalParticipants / pageSize)) + const requestedPage = parseInt(req.query.page, 10) || 1 + const currentPage = Math.min(Math.max(requestedPage, 1), totalPages) + const firstRecord = totalParticipants ? ((currentPage - 1) * pageSize) + 1 : 0 + const lastRecord = Math.min(currentPage * pageSize, totalParticipants) + const participants = allParticipants.slice(firstRecord - 1, lastRecord) + + res.render('participants/index', { + participants, + selectedSort: sort, + currentPage, + totalPages, + firstRecord, + lastRecord, + totalParticipants, + paginationPages: Array.from({ length: totalPages }, (_, index) => index + 1) + }) +}) + +router.get('/participants/:participantId', function (req, res) { + const participants = (req.session.data.participants && req.session.data.participants.default) || [] + const today = new Date() + today.setHours(0, 0, 0, 0) + const participant = participants.find(item => item.participantId === req.params.participantId) + + if (!participant) { + return res.status(404).send('Participant not found') + } + + res.render('participants/detail', { participant: refreshParticipantDates(participant, today) }) +}) + // Isolated create capacity from zero routes router.use(require('./routes/create-capacity-from-zero')); diff --git a/app/views/_includes/primary-navigation.html b/app/views/_includes/primary-navigation.html index f68669ec..210315ac 100644 --- a/app/views/_includes/primary-navigation.html +++ b/app/views/_includes/primary-navigation.html @@ -40,7 +40,7 @@ active: activeItem === "Clinics" }, { - href: "#", + href: "/participants/", text: "Participants", active: activeItem === "Participants" }, diff --git a/app/views/index.html b/app/views/index.html index 96e9174d..a9764cae 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -43,6 +43,15 @@
Participant view
+ +Clinics with schedules ideation
{{ participant.next_test_due_date }}
+{{ participant.next_test_due_date_relative }}
+{{ participant.next_appointment_date }}
+ {% endif %} +{{ participant.next_appointment_date_relative }}
+| + Name + | ++ NHS Number + | ++ Next test due date + | ++ Next screening + | +
|---|---|---|---|
|
+ {{ participant.full_name }} + {{ participant.age }} years old + |
+ {{ participant.nhs_number }} | +
+ {{ participant.next_test_due_date }} + {{ participant.next_test_due_date_relative }} + |
+
+ {% if participant.next_appointment_date != 'Not known' %}{{ participant.next_appointment_date }} {% endif %} + {{ participant.next_appointment_date_relative }} + |
+