extract well visit schedule data
This commit is contained in:
parent
03285532cb
commit
b4d7420f22
5 changed files with 4152 additions and 5 deletions
4003
public/data/well-visit/schedule.json
Normal file
4003
public/data/well-visit/schedule.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -475,7 +475,6 @@
|
|||
integrity="sha384-JUh163oCRItcbPme8pYnROHQMC6fNKTBWtRG3I3I0erJkzNgL7uxKlNwcrcFKeqF"
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer" defer></script>
|
||||
<script defer src="/js/milestonesData.js"></script>
|
||||
<script defer src="/js/pediatricScheduleData.js"></script>
|
||||
<script defer src="/js/audioBackup.js"></script>
|
||||
<script defer src="/js/browserWhisper.js"></script>
|
||||
<script defer src="/js/speechRecognition.js"></script>
|
||||
|
|
@ -498,7 +497,7 @@
|
|||
<script defer src="/js/diagrams.js"></script>
|
||||
<script type="module" src="/js/clinicalAssistant.js"></script>
|
||||
<script defer src="/js/nextcloud.js"></script>
|
||||
<script defer src="/js/wellVisit.js"></script>
|
||||
<script type="module" src="/js/wellVisit.js"></script>
|
||||
<script defer src="/js/shadess.js"></script>
|
||||
<script defer src="/js/sickVisit.js"></script>
|
||||
<script defer src="/js/ed-encounters.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { applyWellVisitScheduleGlobals, loadWellVisitScheduleData } from './wellVisit/scheduleData.js';
|
||||
|
||||
// ============================================================
|
||||
// WELL VISIT / PREVENTIVE CARE TAB
|
||||
// ============================================================
|
||||
|
|
@ -77,6 +79,25 @@
|
|||
// ─── Module-level state for visit statuses ────────────────────────────────
|
||||
// keyed by visitId + '.' + itemKey — persisted to localStorage
|
||||
var _visitStatuses = {};
|
||||
var _scheduleReady = null;
|
||||
|
||||
function ensureScheduleData() {
|
||||
if (typeof VISIT_AGES !== 'undefined' && typeof PERIODICITY !== 'undefined') return Promise.resolve();
|
||||
if (!_scheduleReady) {
|
||||
_scheduleReady = loadWellVisitScheduleData().then(function(data) {
|
||||
applyWellVisitScheduleGlobals(data, window);
|
||||
});
|
||||
}
|
||||
return _scheduleReady;
|
||||
}
|
||||
|
||||
function showScheduleLoadError(panelId, err) {
|
||||
var panel = document.getElementById(panelId);
|
||||
if (panel) {
|
||||
panel.innerHTML = '<div class="wv-empty">Unable to load well-visit schedule data. Please refresh and try again.</div>';
|
||||
}
|
||||
console.error('Failed to load well-visit schedule data', err);
|
||||
}
|
||||
|
||||
// SSHADESS is only relevant for 12+ year visits
|
||||
var SSHADESS_VISITS = ['12y','13y','14y','15y','16y','17y','18y','19y','20y','21y'];
|
||||
|
|
@ -721,9 +742,18 @@
|
|||
var _catchupInited = false;
|
||||
document.addEventListener('tabChanged', function(e) {
|
||||
var tab = e.detail.tab;
|
||||
if (tab === 'wellvisit' && !_inited) { _inited = true; init(); }
|
||||
if (tab === 'vaxschedule' && !_vaxInited) { _vaxInited = true; renderFullSchedule(); }
|
||||
if (tab === 'catchup' && !_catchupInited) { _catchupInited = true; renderCatchUp(); }
|
||||
if (tab === 'wellvisit' && !_inited) {
|
||||
_inited = true;
|
||||
ensureScheduleData().then(init).catch(function(err) { showScheduleLoadError('wv-visit-detail', err); });
|
||||
}
|
||||
if (tab === 'vaxschedule' && !_vaxInited) {
|
||||
_vaxInited = true;
|
||||
ensureScheduleData().then(renderFullSchedule).catch(function(err) { showScheduleLoadError('wv-full-schedule', err); });
|
||||
}
|
||||
if (tab === 'catchup' && !_catchupInited) {
|
||||
_catchupInited = true;
|
||||
ensureScheduleData().then(renderCatchUp).catch(function(err) { showScheduleLoadError('wv-catchup', err); });
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
|||
32
public/js/wellVisit/scheduleData.js
Normal file
32
public/js/wellVisit/scheduleData.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
var scheduleDataCache = null;
|
||||
|
||||
export function loadWellVisitScheduleData() {
|
||||
if (scheduleDataCache) return Promise.resolve(scheduleDataCache);
|
||||
|
||||
return fetch('/data/well-visit/schedule.json', { credentials: 'same-origin' })
|
||||
.then(function(response) {
|
||||
if (!response.ok) throw new Error('Failed to load well-visit schedule data');
|
||||
return response.json();
|
||||
})
|
||||
.then(function(data) {
|
||||
scheduleDataCache = data;
|
||||
return scheduleDataCache;
|
||||
});
|
||||
}
|
||||
|
||||
export function applyWellVisitScheduleGlobals(data, target) {
|
||||
var scope = target || globalThis;
|
||||
scope.VISIT_AGES = data.visitAges;
|
||||
scope.WELL_VISIT_CODES = data.wellVisitCodes;
|
||||
scope.VACCINES = data.vaccines;
|
||||
scope.PERIODICITY = data.periodicity;
|
||||
scope.CATCH_UP_SCHEDULE = data.catchUpSchedule;
|
||||
scope.ANTICIPATORY_GUIDANCE = data.anticipatoryGuidance;
|
||||
scope.AAP_FOOTNOTES = data.aapFootnotes;
|
||||
scope.DYSLIPIDEMIA_SCHEDULE = data.dyslipidemiaSchedule;
|
||||
scope.NEWBORN_SCREENING = data.newbornScreening;
|
||||
scope.GROWTH_REFERENCE = data.growthReference;
|
||||
scope.REFLEXES_REFERENCE = data.reflexesReference;
|
||||
scope.BMI_CLASSIFICATION = data.bmiClassification;
|
||||
return scope;
|
||||
}
|
||||
83
test/well-visit-data.test.js
Normal file
83
test/well-visit-data.test.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
function loadScheduleJson() {
|
||||
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'well-visit', 'schedule.json'), 'utf8');
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
|
||||
function loadLegacyScheduleData() {
|
||||
return require('../public/js/pediatricScheduleData.js');
|
||||
}
|
||||
|
||||
test('schedule.json exactly mirrors existing pediatric schedule constants', () => {
|
||||
const json = loadScheduleJson();
|
||||
const legacy = loadLegacyScheduleData();
|
||||
|
||||
assert.equal(json.version, '2025.1');
|
||||
assert.deepEqual(json.visitAges, legacy.VISIT_AGES);
|
||||
assert.deepEqual(json.wellVisitCodes, legacy.WELL_VISIT_CODES);
|
||||
assert.deepEqual(json.vaccines, legacy.VACCINES);
|
||||
assert.deepEqual(json.periodicity, legacy.PERIODICITY);
|
||||
assert.deepEqual(json.catchUpSchedule, legacy.CATCH_UP_SCHEDULE);
|
||||
assert.deepEqual(json.anticipatoryGuidance, legacy.ANTICIPATORY_GUIDANCE);
|
||||
assert.deepEqual(json.aapFootnotes, legacy.AAP_FOOTNOTES);
|
||||
assert.deepEqual(json.dyslipidemiaSchedule, legacy.DYSLIPIDEMIA_SCHEDULE);
|
||||
assert.deepEqual(json.newbornScreening, legacy.NEWBORN_SCREENING);
|
||||
assert.deepEqual(json.growthReference, legacy.GROWTH_REFERENCE);
|
||||
assert.deepEqual(json.reflexesReference, legacy.REFLEXES_REFERENCE);
|
||||
assert.deepEqual(json.bmiClassification, legacy.BMI_CLASSIFICATION);
|
||||
});
|
||||
|
||||
test('schedule.json preserves expected well-visit anchors', () => {
|
||||
const data = loadScheduleJson();
|
||||
|
||||
assert.equal(data.visitAges.length, 32);
|
||||
assert.deepEqual(data.visitAges[0], { id: 'prenatal', label: 'Prenatal', era: 'prenatal' });
|
||||
assert.deepEqual(data.visitAges[data.visitAges.length - 1], { id: '21y', label: '21 Years', era: 'adolescence' });
|
||||
assert.equal(data.wellVisitCodes['2mo'].cpt, '99391');
|
||||
assert.equal(data.periodicity['12mo'].procedures.lead, 'dot_or_risk');
|
||||
assert.equal(data.periodicity['11y'].developmental.depressionSuicideRisk, 'dot');
|
||||
assert.equal(data.catchUpSchedule.DTaP.series[4].minimumAge, '4 years');
|
||||
assert.equal(data.growthReference['2mo'].feeding.length, 4);
|
||||
assert.equal(data.reflexesReference.newborn.reflexes[2].name, 'Moro (startle)');
|
||||
assert.equal(data.bmiClassification.categories[3].label, 'Obesity (Class I)');
|
||||
});
|
||||
|
||||
test('well-visit schedule loader fetches JSON and can apply legacy globals', async () => {
|
||||
const data = loadScheduleJson();
|
||||
const previousFetch = globalThis.fetch;
|
||||
globalThis.fetch = async function(url, options) {
|
||||
assert.equal(url, '/data/well-visit/schedule.json');
|
||||
assert.deepEqual(options, { credentials: 'same-origin' });
|
||||
return {
|
||||
ok: true,
|
||||
async json() {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
try {
|
||||
const module = await import('../public/js/wellVisit/scheduleData.js');
|
||||
const loaded = await module.loadWellVisitScheduleData();
|
||||
assert.strictEqual(loaded, data);
|
||||
|
||||
const target = {};
|
||||
module.applyWellVisitScheduleGlobals(loaded, target);
|
||||
assert.strictEqual(target.VISIT_AGES, data.visitAges);
|
||||
assert.strictEqual(target.PERIODICITY, data.periodicity);
|
||||
assert.strictEqual(target.CATCH_UP_SCHEDULE, data.catchUpSchedule);
|
||||
assert.strictEqual(target.BMI_CLASSIFICATION, data.bmiClassification);
|
||||
} finally {
|
||||
globalThis.fetch = previousFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test('index loads wellVisit as a module without the legacy schedule data script', () => {
|
||||
const indexHtml = fs.readFileSync(path.join(__dirname, '..', 'public', 'index.html'), 'utf8');
|
||||
assert.match(indexHtml, /<script type="module" src="\/js\/wellVisit\.js"><\/script>/);
|
||||
assert.doesNotMatch(indexHtml, /src="\/js\/pediatricScheduleData\.js"/);
|
||||
});
|
||||
Loading…
Reference in a new issue