Skip to content

Commit 389ffc4

Browse files
Improve address generation, show postcode on clinic list
1 parent cf7f316 commit 389ffc4

File tree

3 files changed

+147
-45
lines changed

3 files changed

+147
-45
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// app/lib/utils/address-generator.js
2+
3+
const { faker } = require('@faker-js/faker');
4+
5+
// Common UK street names
6+
const STREETS = [
7+
'High Street',
8+
'Church Road',
9+
'Station Road',
10+
'Victoria Road',
11+
'Manor Road',
12+
'The Green',
13+
'Queens Road',
14+
'Kings Road',
15+
'New Road',
16+
'School Lane',
17+
'Mill Lane',
18+
'The Avenue',
19+
'Park Road',
20+
'London Road',
21+
'York Road'
22+
];
23+
24+
/**
25+
* Extract postcode area (first 1-2 letters) from a full postcode
26+
* @param {string} postcode - Full UK postcode
27+
* @returns {string} Postcode area (e.g., 'OX' from 'OX3 7LE')
28+
*/
29+
const getPostcodeArea = (postcode) => {
30+
return postcode.match(/^[A-Z]{1,2}/)[0];
31+
};
32+
33+
/**
34+
* Get the postcode district (number after area) from a full postcode
35+
* @param {string} postcode - Full UK postcode
36+
* @returns {string} Postcode district number
37+
*/
38+
const getPostcodeDistrict = (postcode) => {
39+
return postcode.match(/^[A-Z]{1,2}(\d+)/)[1];
40+
};
41+
42+
/**
43+
* Generate a random postcode in the same area as the reference postcode
44+
* @param {string} referencePostcode - Postcode to base the new one on
45+
* @returns {string} New postcode in same area
46+
*/
47+
const generateNearbyPostcode = (referencePostcode) => {
48+
const area = getPostcodeArea(referencePostcode);
49+
const district = getPostcodeDistrict(referencePostcode);
50+
51+
// Generate nearby district number (±1 of reference, staying in valid range)
52+
const districtNum = parseInt(district);
53+
const nearbyDistrict = faker.helpers.arrayElement([
54+
districtNum,
55+
Math.max(1, districtNum - 1),
56+
districtNum + 1
57+
]);
58+
59+
// Generate random sector (0-9) and unit (two letters)
60+
const sector = faker.number.int({ min: 0, max: 9 });
61+
const unit = faker.helpers.arrayElement('ABCDEFGHJKLMNPQRSTUWXYZ') +
62+
faker.helpers.arrayElement('ABCDEFGHJKLMNPQRSTUWXYZ');
63+
64+
return `${area}${nearbyDistrict} ${sector}${unit}`;
65+
};
66+
67+
/**
68+
* Generate list of nearby towns/areas based on BSU location
69+
* @param {Object} bsu - Breast screening unit object
70+
* @returns {Array} List of nearby towns/areas
71+
*/
72+
const generateNearbyAreas = (bsu) => {
73+
// Start with the BSU's own city and any address parts that look like areas
74+
const areas = new Set([
75+
bsu.address.city,
76+
bsu.address.line4,
77+
...bsu.locations
78+
.filter(l => l.type === 'hospital')
79+
.map(l => l.address.city)
80+
.filter(Boolean)
81+
].filter(Boolean));
82+
83+
// Add some generated nearby areas
84+
for(let i = 0; i < 5; i++) {
85+
areas.add(faker.location.city());
86+
}
87+
88+
return Array.from(areas);
89+
};
90+
91+
/**
92+
* Generate an address appropriate for the BSU area
93+
* @param {Object} bsu - Breast screening unit object
94+
* @returns {Object} Generated address object
95+
*/
96+
const generateBSUAppropriateAddress = (bsu) => {
97+
const nearbyAreas = generateNearbyAreas(bsu);
98+
99+
return {
100+
line1: `${faker.number.int({ min: 1, max: 300 })} ${faker.helpers.arrayElement(STREETS)}`,
101+
line2: Math.random() < 0.3 ? `${faker.word.adjective()} House` : null,
102+
city: faker.helpers.arrayElement(nearbyAreas),
103+
postcode: generateNearbyPostcode(bsu.address.postcode)
104+
};
105+
};
106+
107+
module.exports = {
108+
generateBSUAppropriateAddress
109+
};

app/lib/generators/participant-generator.js

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,25 @@
22
const { faker } = require('@faker-js/faker');
33
const generateId = require('../utils/id-generator');
44
const weighted = require('weighted');
5+
const { generateBSUAppropriateAddress } = require('./address-generator');
56

67
// Generate a UK phone number
78
const generateUKPhoneNumber = () => {
89
// 80% mobile, 20% landline
910
if (Math.random() < 0.8) {
10-
// Mobile number in range 07700900000 to 07700900999
11-
const suffix = faker.number.int({ min: 0, max: 999 }).toString().padStart(3, '0');
12-
return `07700900${suffix}`;
11+
// Mobile number formats
12+
const formats = [
13+
'07### ######', // Standard UK mobile
14+
'07#########', // No spaces
15+
'+447### ######' // International format
16+
];
17+
return faker.phone.number(faker.helpers.arrayElement(formats));
1318
} else {
14-
// 50/50 split between London and Sheffield landlines
15-
if (Math.random() < 0.5) {
16-
// London: 02079460000 to 02079460999
17-
const suffix = faker.number.int({ min: 0, max: 999 }).toString().padStart(3, '0');
18-
return `02079460${suffix}`;
19-
} else {
20-
// Sheffield: 01144960000 to 01144960999
21-
const suffix = faker.number.int({ min: 0, max: 999 }).toString().padStart(3, '0');
22-
return `01144960${suffix}`;
23-
}
19+
// Get the BSU's area code from their phone number
20+
// Fallback to standard area codes if not available
21+
const areaCodes = ['0118', '01865', '0114', '020'];
22+
const areaCode = faker.helpers.arrayElement(areaCodes);
23+
return faker.phone.number(areaCode + ' ### ####');
2424
}
2525
};
2626

@@ -94,14 +94,9 @@ const generateParticipant = ({ ethnicities, breastScreeningUnits }) => {
9494
max: 70,
9595
mode: 'age'
9696
}).toISOString(),
97-
address: {
98-
line1: faker.location.streetAddress(),
99-
line2: faker.location.secondaryAddress(),
100-
city: faker.location.city(),
101-
postcode: faker.location.zipCode('??# #??')
102-
},
97+
address: generateBSUAppropriateAddress(assignedBSU),
10398
phone: generateUKPhoneNumber(),
104-
email: `${faker.internet.username().toLowerCase()}@example.com`,
99+
email: `${faker.internet.userName().toLowerCase()}@example.com`,
105100
ethnicGroup,
106101
ethnicBackground
107102
},
@@ -121,6 +116,7 @@ const generateParticipant = ({ ethnicities, breastScreeningUnits }) => {
121116
};
122117
};
123118

119+
124120
const generateRiskFactors = () => {
125121
const factors = [];
126122
const possibleFactors = {

app/views/clinics/show.html

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
21
{% extends 'layout-app.html' %}
3-
4-
{% set pageHeading = "Today’s clinics" %}
5-
2+
{% set pageHeading = "Today's clinics" %}
63

74
{% block pageContent %}
85
{% set unit = data.breastScreeningUnits | findById(clinic.breastScreeningUnitId) %}
@@ -14,36 +11,33 @@ <h1 class="nhsuk-heading-l">
1411
</h1>
1512

1613
{% if events.length === 0 %}
17-
<p class="nhsuk-body">No participants scheduled for this clinic.</p>
14+
<p>No participants scheduled for this clinic.</p>
1815
{% else %}
16+
<p>{{ events.length }} scheduled participants</p>
17+
1918
<table class="nhsuk-table">
20-
<caption class="nhsuk-table__caption">
21-
{{ events.length }} scheduled participants
22-
</caption>
2319
<thead class="nhsuk-table__head">
2420
<tr>
25-
<th scope="col" class="nhsuk-table__header">Time</th>
26-
<th scope="col" class="nhsuk-table__header">Name</th>
27-
<th scope="col" class="nhsuk-table__header">SX number</th>
28-
<th scope="col" class="nhsuk-table__header">Status</th>
29-
<th scope="col" class="nhsuk-table__header">Actions</th>
21+
<th class="nhsuk-table__header">Time</th>
22+
<th class="nhsuk-table__header">Name</th>
23+
<th class="nhsuk-table__header">Postcode</th>
24+
<th class="nhsuk-table__header">SX number</th>
25+
<th class="nhsuk-table__header">Status</th>
26+
<th class="nhsuk-table__header">Actions</th>
3027
</tr>
3128
</thead>
3229
<tbody class="nhsuk-table__body">
3330
{% for event in events %}
3431
{% set participant = data.participants | findById(event.participantId) %}
35-
<tr class="nhsuk-table__row">
36-
<td class="nhsuk-table__cell">
37-
{{ event.statusHistory[0].timestamp | formatTime }}
38-
</td>
32+
<tr>
33+
<td class="nhsuk-table__cell">{{ event.statusHistory[0].timestamp | formatTime }}</td>
3934
<td class="nhsuk-table__cell">
4035
<a href="/clinics/{{ clinicId }}/participants/{{ participant.id }}" class="nhsuk-link">
4136
{{ participant | getFullName }}
4237
</a>
4338
</td>
44-
<td class="nhsuk-table__cell">
45-
{{ participant.sxNumber }}
46-
</td>
39+
<td class="nhsuk-table__cell">{{ participant.demographicInformation.address.postcode | noWrap }}</td>
40+
<td class="nhsuk-table__cell">{{ participant.sxNumber }}</td>
4741
<td class="nhsuk-table__cell">
4842
{{ tag({
4943
text: event.status | formatWords | sentenceCase,
@@ -52,7 +46,9 @@ <h1 class="nhsuk-heading-l">
5246
</td>
5347
<td class="nhsuk-table__cell">
5448
{% if event.status === 'scheduled' %}
55-
<a href="/clinics/{{ clinicId }}/check-in/{{ event.id }}" class="nhsuk-link">{{ "Check in" | noWrap }}</a>
49+
<a href="#/clinics/{{ clinicId }}/check-in/{{ event.id }}" class="nhsuk-link">
50+
{{ "Check in" | noWrap }}
51+
</a>
5652
{% endif %}
5753
</td>
5854
</tr>
@@ -62,6 +58,7 @@ <h1 class="nhsuk-heading-l">
6258
{% endif %}
6359

6460
<h2 class="nhsuk-heading-m">Details</h2>
61+
6562
<dl class="nhsuk-summary-list">
6663
<div class="nhsuk-summary-list__row">
6764
<dt class="nhsuk-summary-list__key">Location</dt>
@@ -70,22 +67,22 @@ <h2 class="nhsuk-heading-m">Details</h2>
7067
{{ unit.address | replace("\n", "<br>") | safe }}
7168
</dd>
7269
</div>
70+
7371
<div class="nhsuk-summary-list__row">
7472
<dt class="nhsuk-summary-list__key">Phone</dt>
7573
<dd class="nhsuk-summary-list__value">{{ unit.phoneNumber }}</dd>
7674
</div>
75+
7776
<div class="nhsuk-summary-list__row">
7877
<dt class="nhsuk-summary-list__key">Date</dt>
7978
<dd class="nhsuk-summary-list__value">{{ clinic.date | formatDate }}</dd>
8079
</div>
80+
8181
<div class="nhsuk-summary-list__row">
8282
<dt class="nhsuk-summary-list__key">Type</dt>
83-
<dd class="nhsuk-summary-list__value">
84-
{{ clinic.clinicType | replace("_", " ") | capitalize }}
85-
</dd>
83+
<dd class="nhsuk-summary-list__value">{{ clinic.clinicType | replace("_", " ") | capitalize }}</dd>
8684
</div>
8785
</dl>
8886

8987
<a href="/clinics" class="nhsuk-back-link">Back to today's clinics</a>
90-
9188
{% endblock %}

0 commit comments

Comments
 (0)