Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
module.exports = {
extends: ['prettier'],
ignorePatterns: [
'**/app/**',
'**/public/**',

// Enable dotfile linting
Expand Down Expand Up @@ -44,6 +43,14 @@ module.exports = {
'jest-dom'
],
rules: {
// Allow unused variables via spread syntax
'@typescript-eslint/no-unused-vars': [
'error',
{
ignoreRestSiblings: true
}
],

// Always import Node.js packages from `node:*`
'import/enforce-node-protocol-usage': ['error', 'always'],

Expand All @@ -65,6 +72,14 @@ module.exports = {
}
],

// Allow extra nested properties in JSDoc
'jsdoc/check-param-names': [
'warn',
{
disableExtraPropertyReporting: true
}
],

// JSDoc blocks are optional by default
'jsdoc/require-jsdoc': 'off',

Expand All @@ -90,6 +105,13 @@ module.exports = {
{
startLines: 1
}
],

'promise/catch-or-return': [
'error',
{
allowFinally: true
}
]
},
settings: {
Expand Down
1 change: 1 addition & 0 deletions app/assets/javascript/custom-elements/is-sticky.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const IsStickyComponent = class extends HTMLElement {
let inThrottle
return function () {
const args = arguments
// eslint-disable-next-line @typescript-eslint/no-this-alias
const context = this
if (!inThrottle) {
callback.apply(context, args)
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascript/expanded-state-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
const path = window.location.pathname

// Clear if on main event page (not sub-pages)
if (path.match(/^\/clinics\/[^\/]+\/events\/[^\/]+\/?$/)) {
if (path.match(/^\/clinics\/[^/]+\/events\/[^/]+\/?$/)) {
clearAllExpandedStates()
}
}
Expand Down
12 changes: 8 additions & 4 deletions app/assets/javascript/mammogram-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const MammogramViewer = {
mammogramWindow = null
localStorage.removeItem(VIEWER_STORAGE_KEY)
}
} catch (e) {
} catch {
mammogramWindow = null
localStorage.removeItem(VIEWER_STORAGE_KEY)
}
Expand Down Expand Up @@ -207,7 +207,9 @@ const MammogramViewer = {
if (mammogramWindow) {
mammogramWindow.close()
}
} catch (err) {}
} catch {
// Ignore errors
}

localStorage.removeItem(VIEWER_STORAGE_KEY)
this.openNew(participantName)
Expand Down Expand Up @@ -273,7 +275,7 @@ const MammogramViewer = {
// Only check our direct reference, don't try to find windows
try {
return mammogramWindow && !mammogramWindow.closed
} catch (e) {
} catch {
// If there's an error accessing the window property, it's likely closed
return false
}
Expand Down Expand Up @@ -307,6 +309,8 @@ window.addEventListener('beforeunload', function () {
if (window.inReadingContext && mammogramWindow && !mammogramWindow.closed) {
try {
localStorage.setItem('wasInReadingContext', 'true')
} catch (e) {}
} catch {
// Ignore errors
}
}
})
4 changes: 3 additions & 1 deletion app/assets/javascript/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class AppModal {
this.handleAjax(actionElement)
break

default:
default: {
// Fire custom event for other action types
const customEvent = new CustomEvent('modal:action', {
detail: {
Expand All @@ -127,6 +127,7 @@ class AppModal {
}
})
this.modal.dispatchEvent(customEvent)
}
}
}

Expand Down Expand Up @@ -154,6 +155,7 @@ class AppModal {
body: method !== 'GET' ? JSON.stringify(modalData) : null
})
.then((response) => {
// eslint-disable-next-line promise/always-return
if (response.ok) {
if (closeOnSuccess) {
this.close()
Expand Down
2 changes: 1 addition & 1 deletion app/config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// app/config.js

// Use this file to change prototype configuration.
const path = require('path')
const path = require('node:path')

module.exports = {
// Service name
Expand Down
17 changes: 11 additions & 6 deletions app/data/session-data-defaults.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// app/data/session-data-defaults.js

const users = require('./users')
// Used to simulate in prototype
const breastScreeningUnits = require('./breast-screening-units')
// All breast screening units
const allBreastScreeningUnits = require('./all-breast-screening-units')
const path = require('path')
const fs = require('fs')
const { needsRegeneration } = require('../lib/utils/regenerate-data')
const fs = require('node:fs')
const path = require('node:path')

const config = require('../config')
const { needsRegeneration } = require('../lib/utils/regenerate-data')

const allBreastScreeningUnits = require('./all-breast-screening-units')
const breastScreeningUnits = require('./breast-screening-units')
const users = require('./users')

// Check if generated data folder exists and create if needed
const generatedDataPath = path.join(__dirname, 'generated')
Expand Down Expand Up @@ -48,8 +50,11 @@ if (needsRegeneration(generationInfo)) {

// Load generated data
try {
// eslint-disable-next-line n/no-unpublished-require
participants = require('./generated/participants.json').participants
// eslint-disable-next-line n/no-unpublished-require
clinics = require('./generated/clinics.json').clinics
// eslint-disable-next-line n/no-unpublished-require
events = require('./generated/events.json').events
} catch (err) {
console.warn('Error loading generated data:', err)
Expand Down
6 changes: 3 additions & 3 deletions app/filters.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// app/filters.js

const fs = require('fs')
const path = require('path')
const fs = require('node:fs')
const path = require('node:path')

module.exports = function (env) {
module.exports = function () {
/* eslint-disable-line func-names,no-unused-vars */
/**
* Instantiate object used to store the methods registered as a
Expand Down
5 changes: 3 additions & 2 deletions app/filters/tags.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// app/filters/tags.js

const { safe: nunjucksSafe } = require('nunjucks/src/filters')
const { formatWords, sentenceCase, snakeCase } = require('../lib/utils/strings')

const { getStatusTagColour, getStatusText } = require('../lib/utils/status')
const { formatWords, sentenceCase, snakeCase } = require('../lib/utils/strings')

/**
* Convert a status string into an NHS tag
Expand Down Expand Up @@ -38,7 +39,7 @@ const toTag = (status, options = {}) => {
.join(' ')

// Generate tag HTML
const idAttr = options.id ? ` id=\"${options.id}\"` : ''
const idAttr = options.id ? ` id="${options.id}"` : ''
return nunjucksSafe(`<strong${idAttr} class="${classes}">${text}</strong>`)
}

Expand Down
26 changes: 11 additions & 15 deletions app/lib/generate-seed-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,26 @@
// to run: node app/lib/generate-seed-data.js
// can also be run from ui at localhost:3000/settings

const fs = require('node:fs')
const path = require('node:path')

const dayjs = require('dayjs')
const fs = require('fs')
const path = require('path')
const config = require('../config')
const weighted = require('weighted')

const { generateParticipant } = require('./generators/participant-generator')
const { generateClinicsForBSU } = require('./generators/clinic-generator')
const { generateEvent } = require('./generators/event-generator')
const { getCurrentRiskLevel } = require('./utils/participants')
const { generateReadingData } = require('./generators/reading-generator')

const riskLevels = require('../data/risk-levels')

const config = require('../config')
// Load existing data
const breastScreeningUnits = require('../data/breast-screening-units')
const ethnicities = require('../data/ethnicities')

const riskLevels = require('../data/risk-levels')
// Hardcoded scenarios for user research
const testScenarios = require('../data/test-scenarios')

const { generateClinicsForBSU } = require('./generators/clinic-generator')
const { generateEvent } = require('./generators/event-generator')
const { generateParticipant } = require('./generators/participant-generator')
const { generateReadingData } = require('./generators/reading-generator')
const { getCurrentRiskLevel } = require('./utils/participants')

// Create an index of participants by risk level for efficient lookup
// Create an index of participants by risk level for efficient lookup
const createParticipantIndices = (participants, clinicDate, events = []) => {
Expand Down Expand Up @@ -129,9 +128,6 @@ const generateClinicsForDay = (
})
: []

// Pre-filter eligible participants once
const clinicDate = dayjs(date)

// Generate clinics for this day
const newClinics = generateClinicsForBSU({
date: date.toDate(),
Expand Down
5 changes: 3 additions & 2 deletions app/lib/generators/clinic-generator.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// app/lib/generators/clinic-generator.js

const { faker } = require('@faker-js/faker')
const generateId = require('../utils/id-generator')
const dayjs = require('dayjs')
const weighted = require('weighted')

const config = require('../../config')
const generateId = require('../utils/id-generator')

const determineClinicType = (location, breastScreeningUnit) => {
// First check location-specific service types
Expand Down Expand Up @@ -246,7 +247,7 @@ const generateClinicsForBSU = ({ date, breastScreeningUnit }) => {
return [clinic]
} else {
// For paired sessions, create two clinics
return selectedPattern.sessions.map((sessionTimes, sessionIndex) => {
return selectedPattern.sessions.map(() => {
const clinic = generateClinic(
date,
location,
Expand Down
50 changes: 7 additions & 43 deletions app/lib/generators/event-generator.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// app/lib/generators/event-generator.js

const generateId = require('../utils/id-generator')
const { faker } = require('@faker-js/faker')
const weighted = require('weighted')
const dayjs = require('dayjs')
const weighted = require('weighted')

const config = require('../../config')
const { STATUS_GROUPS, isCompleted, isFinal } = require('../utils/status')
const users = require('../../data/users')
const generateId = require('../utils/id-generator')
const { STATUS_GROUPS, isCompleted } = require('../utils/status')

const { generateMammogramImages } = require('./mammogram-generator')
const { generateSymptoms } = require('./symptoms-generator')
const {
generateSpecialAppointment
} = require('./special-appointment-generator')
const users = require('../../data/users')
const { generateSymptoms } = require('./symptoms-generator')

const NOT_SCREENED_REASONS = [
'Recent mammogram at different facility',
Expand Down Expand Up @@ -71,7 +73,6 @@ const generateEvent = ({
slot,
participant,
clinic,
outcomeWeights,
forceStatus = null,
id = null,
specialAppointmentOverride = null,
Expand Down Expand Up @@ -266,43 +267,6 @@ const generateEvent = ({
return eventBase
}

const generateStatusHistory = (finalStatus, dateTime) => {
const history = []
const baseDate = new Date(dateTime)

// Always starts with scheduled status
history.push({
status: 'event_scheduled',
timestamp: new Date(baseDate.getTime() - 24 * 60 * 60 * 1000).toISOString() // Day before
})

// Add intermediate statuses based on final status
if (isCompleted(finalStatus)) {
history.push(
{
status: 'checked_in',
timestamp: new Date(baseDate.getTime() - 10 * 60 * 1000).toISOString() // 10 mins before
},
// {
// status: 'in_progress',
// timestamp: new Date(baseDate).toISOString()
// },
{
status: finalStatus,
timestamp: new Date(baseDate.getTime() + 15 * 60 * 1000).toISOString() // 15 mins after
}
)
} else {
// For did_not_attend and attended_not_screened, just add the final status
history.push({
status: finalStatus,
timestamp: new Date(baseDate.getTime() + 15 * 60 * 1000).toISOString()
})
}

return history
}

module.exports = {
generateEvent
}
2 changes: 0 additions & 2 deletions app/lib/generators/mammogram-generator.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// app/lib/generators/mammogram-generator.js

const { faker } = require('@faker-js/faker')
const generateId = require('../utils/id-generator')
const dayjs = require('dayjs')
const weighted = require('weighted')

const STANDARD_VIEWS = [
{ side: 'right', view: 'mediolateral oblique' },
Expand Down
10 changes: 6 additions & 4 deletions app/lib/generators/participant-generator.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// app/lib/generators/participant-generator.js

const { faker } = require('@faker-js/faker')
const generateId = require('../utils/id-generator')
const weighted = require('weighted')
const { generateBSUAppropriateAddress } = require('./address-generator')
const dayjs = require('dayjs')
const _ = require('lodash')
const weighted = require('weighted')

const riskLevels = require('../../data/risk-levels')
const dayjs = require('dayjs')
const generateId = require('../utils/id-generator')

const { generateBSUAppropriateAddress } = require('./address-generator')

/**
* Generate a precise date of birth within the specified age range
Expand Down
Loading