Skip to content

Commit 224fa7a

Browse files
Clean up clinic statuses and other work
1 parent 39c1e6c commit 224fa7a

File tree

11 files changed

+98
-61
lines changed

11 files changed

+98
-61
lines changed

app/assets/sass/_utils.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.app-nowrap {
2+
white-space: nowrap;
3+
}

app/assets/sass/main.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
@import 'components/list-border';
66
@import 'components/related-nav';
77

8+
@import 'utils';
9+
810
///////////////////////////////////////////
911
// Add your custom CSS/Sass styles below...
1012
///////////////////////////////////////////
11-
13+

app/config.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// Use this file to change prototype configuration.
2+
const path = require('path');
3+
24

35
module.exports = {
46
// Service name
@@ -16,4 +18,43 @@ module.exports = {
1618

1719
// Enable or disable built-in docs and examples.
1820
useDocumentation: true,
21+
22+
paths: {
23+
generatedData: path.join(__dirname, 'data/generated')
24+
},
25+
26+
// Clinic settings
27+
clinics: {
28+
// Timing
29+
startTime: '09:00',
30+
endTime: '17:00',
31+
slotDurationMinutes: 8,
32+
slotsPerDay: 32,
33+
34+
// Capacity
35+
targetBookings: 60,
36+
targetAttendance: 40,
37+
38+
// Date range for generating data
39+
daysToGenerate: 7,
40+
daysBeforeToday: 3
41+
},
42+
43+
screening: {
44+
// Outcomes and their probabilities
45+
outcomes: {
46+
clear: 0.95,
47+
needs_further_tests: 0.04,
48+
cancer_detected: 0.01
49+
},
50+
51+
// Standard images taken during screening
52+
standardImages: ['RCC', 'LCC', 'RMLO', 'LMLO']
53+
},
54+
55+
// Data generation settings
56+
generation: {
57+
numberOfParticipants: 1000,
58+
bookingProbability: 0.8 // 80% of slots are booked
59+
}
1960
};

app/data/breast-screening-units.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module.exports = [
1717
abbreviation: "OXF",
1818
locations: [
1919
{
20-
id: generateId(),
20+
id: "duif1ywp", // Must be hardcoded so it matches generated data
2121
name: "Churchill Hospital breast unit",
2222
type: "hospital",
2323
isMainSite: true,
@@ -43,14 +43,14 @@ module.exports = [
4343
// }
4444
// },
4545
{
46-
id: generateId(),
46+
id: "2yt5dukk", // Must be hardcoded so it matches generated data
4747
name: "Mobile Unit WX71 HCP",
4848
type: "mobile_unit",
4949
isMainSite: false,
5050
registration: "WX71 HCP"
5151
},
5252
{
53-
id: generateId(),
53+
id: "acxcdcnj", // Must be hardcoded so it matches generated data
5454
name: "Mobile Unit WX71 HCR",
5555
type: "mobile_unit",
5656
isMainSite: false,

app/lib/generate-seed-data.js

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { faker } = require('@faker-js/faker');
44
const weighted = require('weighted');
55
const fs = require('fs');
66
const path = require('path');
7+
const config = require('../config');
78

89
const { generateParticipant } = require('./generators/participant-generator');
910
const { generateClinicsForBSU } = require('./generators/clinic-generator');
@@ -13,33 +14,17 @@ const { generateEvent } = require('./generators/event-generator');
1314
const breastScreeningUnits = require('../data/breast-screening-units');
1415
const ethnicities = require('../data/ethnicities');
1516

16-
const CONFIG = {
17-
numberOfParticipants: 1000,
18-
outputPath: path.join(__dirname, '../data/generated'),
19-
clinicDefaults: {
20-
slotsPerDay: 32,
21-
daysToGenerate: 5,
22-
startTime: '09:00',
23-
endTime: '17:00',
24-
slotDurationMinutes: 8
25-
},
26-
eventOutcomes: {
27-
'clear': 0.95,
28-
'needs_further_tests': 0.04,
29-
'cancer_detected': 0.01
30-
}
31-
};
32-
3317
const generateData = async () => {
3418
// Create output directory if it doesn't exist
35-
if (!fs.existsSync(CONFIG.outputPath)) {
36-
fs.mkdirSync(CONFIG.outputPath, { recursive: true });
19+
if (!fs.existsSync(config.paths.generatedData)) {
20+
fs.mkdirSync(config.paths.generatedData, { recursive: true });
3721
}
3822

3923
// Generate base data
4024
console.log('Generating participants...');
41-
const participants = Array.from({ length: CONFIG.numberOfParticipants }, () =>
42-
generateParticipant({ ethnicities, breastScreeningUnits })
25+
const participants = Array.from(
26+
{ length: config.generation.numberOfParticipants },
27+
() => generateParticipant({ ethnicities, breastScreeningUnits })
4328
);
4429

4530
console.log('Generating clinics and events...');
@@ -48,31 +33,31 @@ const generateData = async () => {
4833

4934
// Calculate date range
5035
const startDate = new Date();
51-
startDate.setDate(startDate.getDate() - 3);
36+
startDate.setDate(startDate.getDate() - config.clinics.daysBeforeToday);
5237

53-
for (let i = 0; i < CONFIG.clinicDefaults.daysToGenerate; i++) {
38+
for (let i = 0; i < config.clinics.daysToGenerate; i++) {
5439
const clinicDate = new Date(startDate);
5540
clinicDate.setDate(clinicDate.getDate() + i);
5641

57-
// Generate clinics for each BSU (currently just Oxford)
42+
// Generate clinics for each BSU
5843
breastScreeningUnits.forEach(unit => {
5944
const newClinics = generateClinicsForBSU({
6045
date: clinicDate,
6146
breastScreeningUnit: unit,
62-
config: CONFIG.clinicDefaults
47+
config: config.clinics
6348
});
6449

6550
// Generate events for each clinic
6651
newClinics.forEach(clinic => {
6752
const clinicEvents = clinic.slots
68-
.filter(slot => Math.random() > 0.2)
53+
.filter(() => Math.random() < config.generation.bookingProbability)
6954
.map(slot => {
7055
const participant = faker.helpers.arrayElement(participants);
7156
return generateEvent({
7257
slot,
7358
participant,
7459
clinic,
75-
outcomeWeights: CONFIG.eventOutcomes
60+
outcomeWeights: config.screening.outcomes
7661
});
7762
});
7863

@@ -86,7 +71,7 @@ const generateData = async () => {
8671
// Write generated data to files
8772
const writeData = (filename, data) => {
8873
fs.writeFileSync(
89-
path.join(CONFIG.outputPath, filename),
74+
path.join(config.paths.generatedData, filename),
9075
JSON.stringify(data, null, 2)
9176
);
9277
};

app/lib/generators/clinic-generator.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const { faker } = require('@faker-js/faker');
44
const generateId = require('../utils/id-generator');
55
const dayjs = require('dayjs');
6+
const config = require('../../config');
67

78
const generateTimeSlots = (date, config) => {
89
const slots = [];
@@ -26,24 +27,16 @@ const generateTimeSlots = (date, config) => {
2627

2728
const determineClinicStatus = (date) => {
2829
const now = dayjs();
29-
const clinicDate = dayjs(date);
30-
const clinicStart = clinicDate.hour(8); // Assume clinic starts at 8am
31-
const clinicEnd = clinicDate.hour(17); // Assume clinic ends at 5pm
30+
const clinicDate = dayjs(date).startOf('day');
31+
const today = now.startOf('day');
3232

33-
if (clinicDate.isBefore(now, 'day')) {
33+
if (clinicDate.isBefore(today)) {
3434
return 'closed';
35-
} else if (clinicDate.isAfter(now, 'day')) {
35+
}
36+
if (clinicDate.isAfter(today)) {
3637
return 'scheduled';
37-
} else {
38-
// Today - check time
39-
if (now.isBefore(clinicStart)) {
40-
return 'scheduled';
41-
} else if (now.isAfter(clinicEnd)) {
42-
return 'closed';
43-
} else {
44-
return 'in_progress';
45-
}
4638
}
39+
return 'in_progress'; // it's today
4740
};
4841

4942
const generateMobileSiteName = () => {
@@ -64,7 +57,7 @@ const generateMobileSiteName = () => {
6457
};
6558

6659
// Generate multiple clinics for a BSU on a given day
67-
const generateClinicsForBSU = ({ date, breastScreeningUnit, config }) => {
60+
const generateClinicsForBSU = ({ date, breastScreeningUnit, config: clinicConfig }) => {
6861
// Determine number of clinics for this BSU today (1-2)
6962
const numberOfClinics = Math.random() < 0.3 ? 2 : 1;
7063

@@ -82,15 +75,15 @@ const generateClinicsForBSU = ({ date, breastScreeningUnit, config }) => {
8275
clinicType: location.type,
8376
locationId: location.id,
8477
siteName: location.type === 'mobile_unit' ? generateMobileSiteName() : null,
85-
slots: generateTimeSlots(date, config),
78+
slots: generateTimeSlots(date, clinicConfig),
8679
status: determineClinicStatus(date),
8780
staffing: {
8881
mamographers: [],
8982
radiologists: [],
9083
support: []
9184
},
92-
targetBookings: 60,
93-
targetAttendance: 40,
85+
targetBookings: clinicConfig.targetBookings,
86+
targetAttendance: clinicConfig.targetAttendance,
9487
notes: null
9588
};
9689
});

app/lib/utils/clinics.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// app/lib/utils/clinics.js
22

3+
4+
const config = require('../../config');
5+
6+
37
/**
48
* Get today's clinics
59
* @param {Array} clinics - Array of all clinics
@@ -37,12 +41,11 @@ const formatTimeSlot = (dateTime) => {
3741
/**
3842
* Calculate the end time of a slot
3943
* @param {string} slotDateTime - ISO date string
40-
* @param {number} durationMinutes - Duration of slot in minutes
4144
* @returns {Date} End time of slot
4245
*/
43-
const getSlotEndTime = (slotDateTime, durationMinutes = 8) => {
46+
const getSlotEndTime = (slotDateTime) => {
4447
const date = new Date(slotDateTime);
45-
date.setMinutes(date.getMinutes() + durationMinutes);
48+
date.setMinutes(date.getMinutes() + config.clinics.slotDurationMinutes);
4649
return date;
4750
};
4851

app/views/clinics/index.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
{% set pageHeading = "All clinics" %}
55

6-
6+
{% set back = {
7+
href: "/"
8+
} %}
79
{% block pageContent %}
810
<h1 class="nhsuk-heading-l">{{pageHeading}}</h1>
911

@@ -21,6 +23,7 @@ <h1 class="nhsuk-heading-l">{{pageHeading}}</h1>
2123
</thead>
2224
<tbody class="nhsuk-table__body">
2325
{% for clinic in data.clinics | sort(false, false, 'date') %}
26+
{{ clinic | log }}
2427
{% set unit = data.breastScreeningUnits | findById(clinic.breastScreeningUnitId) %}
2528
{% set location = unit.locations | findById(clinic.locationId) %}
2629
{% set events = data.events | getClinicEvents(clinic.id) %}

app/views/clinics/show.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ <h1 class="nhsuk-heading-l">
4545
{{ participant.sxNumber }}
4646
</td>
4747
<td class="nhsuk-table__cell">
48-
{{ event.status | replace("_", " ") | capitalize }}
48+
{{ tag({
49+
text: event.status | formatWords | sentenceCase,
50+
classes: "nhsuk-tag--" + event.status | getStatusTagColour
51+
})}}
4952
</td>
5053
<td class="nhsuk-table__cell">
5154
{% if event.status === 'scheduled' %}
52-
<a href="/clinics/{{ clinicId }}/check-in/{{ event.id }}" class="nhsuk-link">Check in</a>
55+
<a href="/clinics/{{ clinicId }}/check-in/{{ event.id }}" class="nhsuk-link">{{ "Check in" | nowrap | safe }}</a>
5356
{% endif %}
5457
</td>
5558
</tr>

app/views/clinics/today.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
{% extends 'layout-app.html' %}
22

3-
{% set pageHeading = "Today's clinics" %}
3+
{% set pageHeading = "Today’s clinics" %}
4+
5+
{% set back = {
6+
href: "/clinics",
7+
text: "All clinics"
8+
} %}
9+
410

511
{% block pageContent %}
612
{% set todaysClinics = data.clinics | getTodaysClinics %}

0 commit comments

Comments
 (0)