diff --git a/index.html b/index.html index 232a9e61..f330edcf 100644 --- a/index.html +++ b/index.html @@ -95,22 +95,11 @@ +

- diff --git a/index.js b/index.js index 018903b1..ee9d8a4c 100644 --- a/index.js +++ b/index.js @@ -30,6 +30,25 @@ import { bptlShipReportsScreen } from "./src/pages/reports/shippingReport.js"; import { checkOutReportTemplate } from "./src/pages/checkOutReport.js"; import { dailyReportTemplate } from "./src/pages/dailyReport.js"; +if ("serviceWorker" in navigator) { + navigator.serviceWorker.register("./serviceWorker.js").catch((error) => { + console.error("Service worker registration failed.", error); + return; + }); + + navigator.serviceWorker.ready.then(() => { + if (navigator.serviceWorker.controller) { + navigator.serviceWorker.controller.postMessage({ action: "getAppVersion" }); + } + }); + + navigator.serviceWorker.addEventListener("message", (event) => { + if (event.data.action === "sendAppVersion") { + document.getElementById("appVersion").textContent = event.data.payload; + } + }); +} + let auth = ''; const datadogConfig = { @@ -48,14 +67,6 @@ const datadogConfig = { const isLocalDev = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; window.onload = () => { - if ("serviceWorker" in navigator) { - try { - navigator.serviceWorker.register("./serviceWorker.js"); - } catch (error) { - console.log(error); - } - } - if(location.host === urls.prod) { !firebase.apps.length ? firebase.initializeApp(prodFirebaseConfig()) : firebase.app(); window.DD_RUM && window.DD_RUM.init({ ...datadogConfig, env: 'prod' }); @@ -101,7 +112,6 @@ const manageRoutes = async () => { else if (route === "#allParticipants") allParticipantsScreen(auth, route); else if (route === "#addressPrinted") addressesPrintedScreen(auth, route); else if (route === "#assigned") assignedScreen(auth, route); - else if (route === "#status_shipped") kitStatusReportsShipped(auth, route); else if (route === "#received") receivedKitsScreen(auth,route); else if (route === "#kitshipment") kitShipmentScreen(auth, route); else if (route === "#packagesintransit") packagesInTransitScreen(auth, route); diff --git a/serviceWorker.js b/serviceWorker.js index 21c7856e..24166c83 100644 --- a/serviceWorker.js +++ b/serviceWorker.js @@ -1,17 +1,22 @@ importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js'); + +const appVersion = "v24.7.0"; workbox.setConfig({debug: false}); const { registerRoute } = workbox.routing; -const { CacheFirst, NetworkFirst, StaleWhileRevalidate, NetworkOnly } = workbox.strategies; -const { CacheableResponse, CacheableResponsePlugin } = workbox.cacheableResponse; +const { CacheFirst, NetworkFirst } = workbox.strategies; const { ExpirationPlugin } = workbox.expiration; -const { BackgroundSyncPlugin } = workbox.backgroundSync const googleAnalytics = workbox.googleAnalytics; +const cacheNameMapper = { + "static-cache": `static-cache-${appVersion}`, + "images-cache": `images-cache-${appVersion}`, +}; +const currCacheNameArray = Object.values(cacheNameMapper); googleAnalytics.initialize(); -registerRoute(/\.(?:js|css)$/, new NetworkFirst({cacheName: 'static-cache'})); +registerRoute(/\.(?:js|css|html)$/, new NetworkFirst({ cacheName: cacheNameMapper["static-cache"] })); registerRoute(/\.(?:png|jpg|jpeg|svg|gif|ico)$/, new CacheFirst({ - cacheName: 'images-cache', + cacheName: cacheNameMapper["images-cache"], plugins: [ new ExpirationPlugin({ maxEntries: 30, @@ -21,41 +26,26 @@ registerRoute(/\.(?:png|jpg|jpeg|svg|gif|ico)$/, }) ); -registerRoute( - new RegExp('https://us-central1-nih-nci-dceg-connect-dev.cloudfunctions.net/.+'), - new NetworkFirst({ - cacheName: 'api-cache', - plugins: [ - new CacheableResponsePlugin({ - statuses: [200], - }) - ] - }), - 'GET' -); - - -const bgSyncPlugin = new BackgroundSyncPlugin('connectBiospecimen', { - maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes) +self.addEventListener("install", () => { + self.skipWaiting(); }); -registerRoute( - new RegExp('https://us-central1-nih-nci-dceg-connect-dev.cloudfunctions.net/.+'), - new NetworkOnly({ - plugins: [bgSyncPlugin] - }), - 'POST' -); +self.addEventListener("activate", (event) => { + event.waitUntil( + caches.keys().then((cacheNames) => { + return Promise.all( + cacheNames.map((cacheName) => { + if (!currCacheNameArray.includes(cacheName)) { + return caches.delete(cacheName); + } + }) + ); + }) + ); +}); -registerRoute( - /index\.html$/, - new NetworkFirst({ - cacheName: 'index-html-cache', - networkTimeoutSeconds: 3, - plugins: [ - new CacheableResponsePlugin({ - statuses: [0, 200], - }), - ], - }) -); \ No newline at end of file +self.addEventListener("message", (event) => { + if (event.data.action === "getAppVersion") { + event.source.postMessage({ action: "sendAppVersion", payload: appVersion }); + } +}); diff --git a/src/events.js b/src/events.js index 3e5ebb2a..86fdc065 100644 --- a/src/events.js +++ b/src/events.js @@ -6,7 +6,8 @@ import { convertConceptIdToPackageCondition, checkFedexShipDuplicate, shippingDuplicateMessage, checkInParticipant, checkOutParticipant, getCheckedInVisit, participantCanCheckIn, shippingPrintManifestReminder, checkNonAlphanumericStr, shippingNonAlphaNumericStrMessage, visitType, getParticipantCollections, updateBaselineData, siteSpecificLocationToConceptId, conceptIdToSiteSpecificLocation, locationConceptIDToLocationMap, updateCollectionSettingData, convertToOldBox, translateNumToType, - getCollectionsByVisit, getSpecimenAndParticipant, getUserProfile, checkDuplicateTrackingIdFromDb, checkAccessionId, checkSurveyEmailTrigger, checkDerivedVariables, isDeviceMobile, replaceDateInputWithMaskedInput, bagConceptIdList, showModalNotification, showTimedNotifications, showNotificationsCancelOrContinue, validateSpecimenAndParticipantResponse, findReplacementTubeLabels, + getCollectionsByVisit, getSpecimenAndParticipant, getUserProfile, checkDuplicateTrackingIdFromDb, checkAccessionId, checkSurveyEmailTrigger, checkDerivedVariables, isDeviceMobile, replaceDateInputWithMaskedInput, bagConceptIdList, showModalNotification, showTimedNotifications, showNotificationsCancelOrContinue, validateSpecimenAndParticipantResponse, findReplacementTubeLabels, + showConfirmationModal, dismissBiospecimenModal } from './shared.js'; import { searchTemplate, searchBiospecimenTemplate } from './pages/dashboard.js'; import { showReportsManifest } from './pages/reportsQuery.js'; @@ -557,30 +558,30 @@ export const addEventCheckInCompleteForm = (isCheckedIn, checkOutFlag) => { e.preventDefault(); try { const btnCheckIn = document.getElementById('checkInComplete'); - btnCheckIn.disabled = true; let query = `connectId=${parseInt(form.dataset.connectId)}`; const response = await findParticipant(query); const data = response.data[0]; + if (isCheckedIn) { showAnimation(); await checkOutParticipant(data); hideAnimation(); showTimedNotifications({ title: 'Success', body: 'Participant is checked out.' }, 100000, 1500); setTimeout(() => { - const closeButton = document.querySelector('#biospecimenModal .btn[data-dismiss="modal"]'); - if (closeButton) { - closeButton.click(); - } checkOutFlag === true ? location.reload() : goToParticipantSearch(); }, 1500); } else { const visitConcept = document.getElementById('visit-select').value; + const isClinicalUrineOrBloodCollected = checkClinicalBloodOrUrineCollected(data); + + if (isClinicalUrineOrBloodCollected) return; + for (const visit of visitType) { if (data[conceptIds.collection.selectedVisit] && data[conceptIds.collection.selectedVisit][visit.concept]) { const visitTime = new Date(data[conceptIds.collection.selectedVisit][visit.concept][conceptIds.checkInDateTime]); - const now = new Date(); + const now = new Date(); if (now.getYear() == visitTime.getYear() && now.getMonth() == visitTime.getMonth() && now.getDate() == visitTime.getDate()) { const response = await getParticipantCollections(data.token); let collection = response.data.filter(res => res[conceptIds.collection.selectedVisit] == visit.concept); @@ -592,6 +593,7 @@ export const addEventCheckInCompleteForm = (isCheckedIn, checkOutFlag) => { } await handleCheckInModal(data, visitConcept, query); + btnCheckIn.disabled = true; } } catch (error) { const bodyMessage = isCheckedIn ? 'There was an error checking out the participant. Please try again.' : 'There was an error checking in the participant. Please try again.'; @@ -600,6 +602,34 @@ export const addEventCheckInCompleteForm = (isCheckedIn, checkOutFlag) => { }); }; +/** + * Checks if the participant has any specimen collected (clinical blood or clinical urine) under baseline from the dashboard or collected clinical blood or urine derivations from the site EMR API. If participant has either a clinical blood or urine dashboard variable or other blood/urine derived variables from the site EMR API, show a notification and return true. + * @param {Object} participantData - participant document data from find participant query + * @returns {Boolean} - true if participant has any clinical blood or urine collected derivations, false otherwise +*/ +const checkClinicalBloodOrUrineCollected = (participantData) => { + const collectionDetailsBaseline = participantData?.[conceptIds.collectionDetails]?.[conceptIds.baseline.visitId]; + + if (!collectionDetailsBaseline) return false; + + const collectedBaselineStatuses = [ + collectionDetailsBaseline?.[conceptIds.anySpecimenCollected], + collectionDetailsBaseline?.[conceptIds.clinicalSiteBloodCollected], + collectionDetailsBaseline?.[conceptIds.clinicalSiteUrineCollected], + collectionDetailsBaseline?.[conceptIds.clinicalSiteBloodRRLReceived], + collectionDetailsBaseline?.[conceptIds.clinicalSiteUrineRRLReceived] + ]; + + if (collectedBaselineStatuses.includes(conceptIds.yes)) { + const modalIcon = `` + const bodyMessage = `Check In not allowed, participant already has clinical collection for this timepoint. If you have questions, contact the Connect Biospeicmen Team: connectbioteam@nih.gov.` + + showNotifications({ title: `${modalIcon} WARNING`, body: bodyMessage }); + return true; + } + return false; +} + const handleCheckInWarning = async (visit, data, collection) => { const message = { title: "Warning - Participant Previously Checked In", @@ -630,12 +660,15 @@ const handleCheckInModal = async (data, visitConcept, query) => { continueButtonText: "Continue to Specimen Link", }; - const checkInOnCancel = () => { }; + const checkInOnCancel = () => { + dismissBiospecimenModal(); + }; const checkInOnContinue = async () => { try { const updatedResponse = await findParticipant(query); const updatedData = updatedResponse.data[0]; - + + dismissBiospecimenModal(); specimenTemplate(updatedData); } catch (error) { showNotifications({ title: 'Error', body: 'There was an error checking in the participant. Please try again.' }); @@ -680,6 +713,7 @@ export const addEventSpecimenLinkForm = (formData) => { form.addEventListener('click', async (e) => { e.preventDefault(); const collections = await getCollectionsByVisit(formData); + if (collections.length) { existingCollectionAlert(collections, connectId, formData); } else { @@ -731,7 +765,7 @@ const existingCollectionAlert = async (collections, connectId, formData) => { * @param {string} connectId * @param {*} formData */ -const btnsClicked = async (connectId, formData) => { +const btnsClicked = async (connectId, formData) => { removeAllErrors(); let scanSpecimenID = document.getElementById('scanSpecimenID')?.value && document.getElementById('scanSpecimenID')?.value.toUpperCase(); @@ -749,18 +783,17 @@ const btnsClicked = async (connectId, formData) => { errorMessage('scanSpecimenID', 'Please Scan Collection ID or Type in Manually', focus, true); focus = false; errorMessage('scanSpecimenID2', 'Please Scan Collection ID or Type in Manually', focus, true); - } - else if (scanSpecimenID !== scanSpecimenID2 && !formData?.collectionId) { + } else if (scanSpecimenID !== scanSpecimenID2 && !formData?.collectionId) { hasError = true; errorMessage('scanSpecimenID2', 'Entered Collection ID doesn\'t match.', focus, true); - } - else if (scanSpecimenID && scanSpecimenID2) { + } else if (scanSpecimenID && scanSpecimenID2) { if (!masterSpecimenIDRequirement.regExp.test(scanSpecimenID) || scanSpecimenID.length !== masterSpecimenIDRequirement.length) { hasError = true; errorMessage('scanSpecimenID', `Collection ID must be ${masterSpecimenIDRequirement.length} characters long and in CXA123456 format.`, focus, true); focus = false; } } + if (collectionLocation && collectionLocation.value === 'none') { hasError = true; errorMessage('collectionLocation', `Please Select Collection Location.`, focus, true); @@ -776,60 +809,10 @@ const btnsClicked = async (connectId, formData) => { const firstName = document.getElementById(firstNameCidString).innerText || "" -const showConfirmationModal = async (collectionID, firstName) => { - return new Promise((resolve) => { - const modalContainer = document.createElement('div'); - modalContainer.classList.add('modal', 'fade'); - modalContainer.id = 'confirmationModal'; - modalContainer.tabIndex = '-1'; - modalContainer.role = 'dialog'; - modalContainer.setAttribute('aria-labelledby', 'exampleModalCenterTitle'); - modalContainer.setAttribute('aria-hidden', 'true'); - const modalContent = document.createElement('div'); - modalContent.classList.add('modal-dialog', 'modal-dialog-centered'); - modalContent.setAttribute('role', 'document'); - - const modalBody = ` - - `; + const confirmVal = await showConfirmationModal(collectionID, firstName); - modalContent.innerHTML = modalBody; - modalContainer.appendChild(modalContent); - document.body.appendChild(modalContainer); - - modalContainer.classList.add('show'); - modalContainer.style.display = 'block'; - modalContainer.addEventListener('click', (event) => { - const result = event.target.getAttribute('data-result'); - if (result) - { - document.body.removeChild(modalContainer); - resolve(result); - } - }); - }); -}; + if (confirmVal === "cancel") return; -const confirmVal = await showConfirmationModal(collectionID, firstName); -if (confirmVal === "cancel") { - return; -} formData[conceptIds.collection.id] = collectionID; formData[conceptIds.collection.collectionSetting] = getWorkflow() === 'research' ? conceptIds.research : conceptIds.clinical; formData['Connect_ID'] = parseInt(document.getElementById('specimenLinkForm').dataset.connectId); @@ -844,15 +827,16 @@ if (confirmVal === "cancel") { if (!formData?.collectionId) { specimenData = (await searchSpecimen(formData[conceptIds.collection.id])).data; + } hideAnimation(); - if (specimenData?.Connect_ID && parseInt(specimenData.Connect_ID) !== particpantData.Connect_ID) { showNotifications({ title: 'Collection ID Duplication', body: 'Entered Collection ID is already associated with a different Connect ID.' }) return; } showAnimation(); + formData[conceptIds.collection.selectedVisit] = formData?.[conceptIds.collection.selectedVisit] || parseInt(getCheckedInVisit(particpantData)); if (!formData?.collectionId) { @@ -881,6 +865,7 @@ if (confirmVal === "cancel") { } } + /** * Check accession number inputs after clicking 'Submit' button * @param {*} formData @@ -2768,4 +2753,4 @@ const searchAvailableCollectionsForSpecimen = (specimenId) => { } } return false; -} +} \ No newline at end of file diff --git a/src/fieldToConceptIdMapping.js b/src/fieldToConceptIdMapping.js index 7714d1e1..9c6aa4a3 100644 --- a/src/fieldToConceptIdMapping.js +++ b/src/fieldToConceptIdMapping.js @@ -140,6 +140,13 @@ export const conceptIds = { checkOutDateTime: 343048998, checkInDateTime: 840048338, checkInComplete: 135591601, + clinicalBloodOrUrineCollected: 156605577, + + // Site EMR API Clinical baseline derivations + clinicalSiteBloodCollected: 693370086, + clinicalSiteUrineCollected: 786930107, + clinicalSiteBloodRRLReceived: 728696253, + clinicalSiteUrineRRLReceived: 453452655, // not shipped specimen deviation id brokenSpecimenDeviation: 472864016, @@ -299,6 +306,7 @@ export const conceptIds = { 807835037: 'Other', 723351427: 'BCC- HWC', 807443231: 'FW All Saints', + 288564244: 'BCC- Fort Worth', 475614532: 'BCC- Plano', 809370237: 'BCC- Worth St', 856158129: 'BCC- Irving', @@ -335,6 +343,7 @@ export const conceptIds = { "mfPopUp": 567969985, 'bccHwc': 723351427, 'bccAllSaints': 807443231, + 'bccFortWorth': 288564244, 'bccPlano': 475614532, 'bccWorthSt': 809370237, 'bccIrving': 856158129, diff --git a/src/pages/checkIn.js b/src/pages/checkIn.js index 0c7d06b1..123f374e 100644 --- a/src/pages/checkIn.js +++ b/src/pages/checkIn.js @@ -75,7 +75,7 @@ export const checkInTemplate = async (data, checkOutFlag) => {
`; - + template += await participantStatus(data, collections); @@ -134,6 +134,7 @@ const participantStatus = (data, collections) => { const urineTubes = siteTubesList?.filter(tube => tube.tubeType === "Urine"); const mouthwashTubes = siteTubesList?.filter(tube => tube.tubeType === "Mouthwash"); + collections = collections.filter(collection => collection[conceptIds.collection.selectedVisit] == conceptIds.baseline.visitId); collections.forEach(collection => { diff --git a/src/pages/homeCollection/kitAssembly.js b/src/pages/homeCollection/kitAssembly.js index 30a602c6..e9df7cbf 100644 --- a/src/pages/homeCollection/kitAssembly.js +++ b/src/pages/homeCollection/kitAssembly.js @@ -204,7 +204,7 @@ const renderSidePane = () => { Return Kit ID = ${ kitObject[conceptIds.returnKitId] } | Cup Id = ${ kitObject[conceptIds.collectionCupId] } | Card Id = ${ kitObject[conceptIds.collectionCardId] } - + ` }) editAssembledKits(); @@ -217,7 +217,8 @@ const editAssembledKits = () => { if (detailedRow) { Array.from(detailedRow).forEach(function(editKitBtn) { editKitBtn.addEventListener('click', () => { - const editKitObj = JSON.parse(editKitBtn.getAttribute('data-kitObject')); + let data = decodeURIComponent(editKitBtn.getAttribute('data-kitObject')); + const editKitObj = JSON.parse(data); document.getElementById('scannedBarcode').value = editKitObj[conceptIds.returnKitTrackingNum] document.getElementById('supplyKitId').value = editKitObj[conceptIds.supplyKitId] document.getElementById('returnKitId').value = editKitObj[conceptIds.returnKitId] @@ -228,9 +229,9 @@ const editAssembledKits = () => { }); // state to indicate if its an edit & also pass the uniqueKitID }} -const checkUniqueness = async (supplyKitId, collectionId) => { +const checkUniqueness = async (supplyKitId, collectionId, returnKitTrackingNumber) => { const idToken = await getIdToken(); - const response = await fetch(`${baseAPI}api=collectionUniqueness&supplyKitId=${supplyKitId}&collectionId=${collectionId}`, { + const response = await fetch(`${baseAPI}api=collectionUniqueness&supplyKitId=${supplyKitId}&collectionId=${collectionId}&returnKitTrackingNumber=${returnKitTrackingNumber}`, { method: "GET", headers: { Authorization:"Bearer "+idToken @@ -244,7 +245,7 @@ const storeAssembledKit = async (kitData) => { showAnimation(); const collectionUnique = appState.getState().uniqueKitID !== '' ? { data: true } - : await checkUniqueness(kitData[conceptIds.supplyKitId], kitData?.[conceptIds.collectionCupId].replace(/\s/g, "\n")); + : await checkUniqueness(kitData[conceptIds.supplyKitId], kitData?.[conceptIds.collectionCupId].replace(/\s/g, "\n"), kitData[conceptIds.returnKitTrackingNum]); hideAnimation(); if (collectionUnique.data === true) { @@ -312,6 +313,14 @@ const storeAssembledKit = async (kitData) => { alertTemplate('The collection card and cup ID are already in use.'); return false } + else if (collectionUnique.data === 'duplicate return kit tracking number'){ + alertTemplate('This tracking number has already been used.'); + return false + } + else if (collectionUnique.data === 'return kit tracking number is for supply kit'){ + alertTemplate('This tracking number has already been used.'); + return false + } else { alertTemplate('Error'); return false diff --git a/src/pages/homeCollection/kitsReceipt.js b/src/pages/homeCollection/kitsReceipt.js index c10fb183..3412a042 100644 --- a/src/pages/homeCollection/kitsReceipt.js +++ b/src/pages/homeCollection/kitsReceipt.js @@ -202,7 +202,7 @@ const storePackageReceipt = async (data) => { document.getElementById("receivePackageComments").value = ""; document.getElementById("dateReceived").value = getCurrentDate(); document.getElementById("collectionComments").value = ""; - document.getElementById("collectionId").value = ""; + enableCollectionCardFields(); enableCollectionCheckBox(); document.getElementById("packageCondition").setAttribute("data-selected", "[]"); diff --git a/src/shared.js b/src/shared.js index d482cc3d..0949d5d3 100644 --- a/src/shared.js +++ b/src/shared.js @@ -489,10 +489,66 @@ export const showNotificationsSelectableList = (message, items, onCancel, onCont errorMessageDiv.style.display = 'block'; } }); - document.getElementById('root').removeChild(button); }; +/** + * Display confirmation modal to the user and returns a promise with the user's choice. + * + * @param {string} collectionID - the collection ID to display in the modal. + * @param {string} firstName - the participant's first name to display in the modal. + * @returns {Promise} - the user's choice on button click: 'cancel', 'back', or 'confirmed'. +*/ +export const showConfirmationModal = (collectionID, firstName) => { + return new Promise((resolve) => { + const modalContainer = document.createElement('div'); + modalContainer.classList.add('modal', 'fade'); + modalContainer.id = 'confirmationModal'; + modalContainer.tabIndex = '-1'; + modalContainer.role = 'dialog'; + modalContainer.setAttribute('aria-labelledby', 'exampleModalCenterTitle'); + modalContainer.setAttribute('aria-hidden', 'true'); + const modalContent = document.createElement('div'); + modalContent.classList.add('modal-dialog', 'modal-dialog-centered'); + modalContent.setAttribute('role', 'document'); + + const modalBody = ` + + `; + + modalContent.innerHTML = modalBody; + modalContainer.appendChild(modalContent); + document.body.appendChild(modalContainer); + + modalContainer.classList.add('show'); + modalContainer.style.display = 'block'; + modalContainer.addEventListener('click', (event) => { + const result = event.target.getAttribute('data-result'); + if (result) + { + document.body.removeChild(modalContainer); + resolve(result); + } + }); + }); +}; + export const showTimedNotifications = (data, zIndex, timeInMilliseconds = 2600) => { const button = document.createElement('button'); button.dataset.target = '#biospecimenModal'; @@ -522,10 +578,7 @@ export const showTimedNotifications = (data, zIndex, timeInMilliseconds = 2600) // Programmatically close the modal on a timer. setTimeout(() => { - const closeButton = document.querySelector('#biospecimenModal .btn[data-dismiss="modal"]'); - if (closeButton) { - closeButton.click(); - } + dismissBiospecimenModal() }, timeInMilliseconds); }; @@ -547,6 +600,15 @@ const closeBiospecimenModal = () => { document.body.classList.remove('modal-open'); }; +/** + * Targets close button on biospecimen bootstrap modal and closes it. Can be used to close and dismiss modal for other buttons on the modal. + * */ +export const dismissBiospecimenModal = () => { + const closeButton = document.querySelector('#biospecimenModal .btn[data-dismiss="modal"]'); + + if (closeButton) closeButton.click(); +} + export const errorMessage = (id, msg, focus, offset, icon) => { const currentElement = document.getElementById(id); const parentElement = currentElement.parentNode; @@ -2010,6 +2072,7 @@ export const siteSpecificLocation = { "Orland Park": {"siteAcronym":"UCM", "siteCode": healthProviderAbbrToConceptIdObj.uOfChicagoMed, "loginSiteName": "University of Chicago Medicine"}, "BCC- HWC": {"SiteAcronym":"BSWH", "siteCode": healthProviderAbbrToConceptIdObj.BSWH, "loginSiteName": "Baylor Scott & White Health"}, "FW All Saints": {"SiteAcronym":"BSWH", "siteCode": healthProviderAbbrToConceptIdObj.BSWH, "loginSiteName": "Baylor Scott & White Health"}, + "BCC- Fort Worth": {"SiteAcronym":"BSWH", "siteCode": healthProviderAbbrToConceptIdObj.BSWH, "loginSiteName": "Baylor Scott & White Health"}, "BCC- Plano": {"SiteAcronym":"BSWH", "siteCode": healthProviderAbbrToConceptIdObj.BSWH, "loginSiteName": "Baylor Scott & White Health"}, "BCC- Worth St": {"SiteAcronym":"BSWH", "siteCode": healthProviderAbbrToConceptIdObj.BSWH, "loginSiteName": "Baylor Scott & White Health"}, "BCC- Irving": {"SiteAcronym":"BSWH", "siteCode": healthProviderAbbrToConceptIdObj.BSWH, "loginSiteName": "Baylor Scott & White Health"}, @@ -2269,6 +2332,14 @@ export const locationConceptIDToLocationMap = { loginSiteName: 'Baylor Scott & White Health', email: 'connectbiospecimen@BSWHealth.org', }, + 288564244: { + siteSpecificLocation: 'BCC- Fort Worth', + siteAcronym: 'BSWH', + siteCode: '472940358', + siteTeam: 'BSWH Connect Study Team', + loginSiteName: 'Baylor Scott & White Health', + email: 'connectbiospecimen@BSWHealth.org', + }, 475614532: { siteSpecificLocation: 'BCC- Plano', siteAcronym: 'BSWH', @@ -2353,6 +2424,7 @@ export const conceptIdToSiteSpecificLocation = { [conceptIds.nameToKeyObj.sfSC]: "Sioux Falls Sanford Center", 723351427: "BCC- HWC", 807443231: "FW All Saints", + 288564244: "BCC- Fort Worth", 475614532: "BCC- Plano", 809370237: "BCC- Worth St", 856158129: "BCC- Irving", @@ -2393,6 +2465,7 @@ export const siteSpecificLocationToConceptId = { "Sioux Falls Sanford Center": conceptIds.nameToKeyObj.sfSC, "BCC- HWC": 723351427, "FW All Saints": 807443231, + "BCC- Fort Worth": 288564244, "BCC- Plano": 475614532, "BCC- Worth St": 809370237, "BCC- Irving": 856158129, @@ -2471,14 +2544,15 @@ export const keyToLocationObj = 589224449: "Sioux Falls Imagenetics", [conceptIds.nameToKeyObj.sfBM] : "Bismarck Medical Center", [conceptIds.nameToKeyObj.sfSC] : "Sioux Falls Sanford Center", - 723351427:'BCC- HWC', - 807443231:'FW All Saints', - 475614532:'BCC- Plano', - 809370237:'BCC- Worth St', - 856158129:'BCC- Irving', - 436956777:'NTX Biorepository', + 723351427: 'BCC- HWC', + 807443231: 'FW All Saints', + 288564244: 'BCC- Fort Worth', + 475614532: 'BCC- Plano', + 809370237: 'BCC- Worth St', + 856158129: 'BCC- Irving', + 436956777: 'NTX Biorepository', 111111111: "NIH", - 13:"NCI" + 13: "NCI" } @@ -2690,6 +2764,7 @@ export const siteLocations = { 'BSWH': [{location: 'BCC- HWC', concept: 723351427}, {location: 'FW All Saints', concept: 807443231}, + {location: 'BCC- Fort Worth', concept: 288564244}, {location: 'BCC- Plano', concept: 475614532}, {location: 'BCC- Worth St', concept: 809370237}, {location: 'BCC- Irving', concept: 856158129}, @@ -2801,9 +2876,8 @@ export const checkInParticipant = async (data, visitConcept) => { const uid = data.state.uid; let shouldSendBioEmail = false; - if (data[conceptIds.selectedVisit]) { - visits = data[conceptIds.selectedVisit]; - + if (data[conceptIds.collection.selectedVisit]) { + visits = data[conceptIds.collection.selectedVisit]; if (!visits[visitConcept]) { if (visitConcept === conceptIds.baseline.visitId.toString()) shouldSendBioEmail = true; diff --git a/static/css/style.css b/static/css/style.css index 1b68e3c4..5bccda21 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -467,4 +467,13 @@ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); height: auto; max-height: 200px; overflow-x: hidden; +} + +#checkInComplete:disabled { + cursor: not-allowed; + background-color: #e0e0e0; +} + +#appVersion { + font-size: 0.8rem; } \ No newline at end of file