diff --git a/index.js b/index.js
index 1fd96fb7..14cfa52a 100644
--- a/index.js
+++ b/index.js
@@ -22,8 +22,9 @@ import { packageReceiptScreen } from "./src/pages/receipts/packageReceipt.js";
import { csvFileReceiptScreen } from "./src/pages/receipts/csvFileReceipt.js";
import { kitReportsScreen } from "./src/pages/reports/kitReports.js";
import { collectionIdSearchScreen } from "./src/pages/reports/collectionIdSearch.js";
+import { bptlShipReportsScreen } from "./src/pages/reports/shippingReport.js";
import { checkOutReportTemplate } from "./src/pages/checkOutReport.js";
-
+import { dailyReportTemplate } from "./src/pages/dailyReport.js";
let auth = '';
@@ -102,6 +103,8 @@ const manageRoutes = async () => {
else if (route === "#collectionidsearch") collectionIdSearchScreen(auth, route);
else if (route === "#reports") reportsQuery(auth, route);
else if (route === "#checkoutreport") checkOutReportTemplate(auth, route);
+ else if (route === "#dailyreport") dailyReportTemplate(auth, route);
+ else if (route === "#bptlshipreports") bptlShipReportsScreen(auth, route);
else if (route === "#manage_users") manageUsers(auth, route);
else if (route === "#sign_out") signOut();
else window.location.hash = "#welcome";
diff --git a/src/events.js b/src/events.js
index f861ce7a..10511b89 100644
--- a/src/events.js
+++ b/src/events.js
@@ -142,7 +142,7 @@ export const addEventsearchSpecimen = () => {
const biospecimen = await searchSpecimen(masterSpecimenId);
if (biospecimen.code !== 200 || Object.keys(biospecimen.data).length === 0) {
hideAnimation();
- showNotifications({ title: 'Not found', body: 'Specimen not found!' }, true)
+ showNotifications({ title: 'Not found', body: 'Specimen not found!' })
return
}
const biospecimenData = biospecimen.data;
@@ -150,14 +150,14 @@ export const addEventsearchSpecimen = () => {
if(getWorkflow() === 'research') {
if(biospecimenData[conceptIds.collection.collectionSetting] !== conceptIds.research) {
hideAnimation();
- showNotifications({ title: 'Incorrect Dashboard', body: 'Clinical Collections cannot be viewed on Research Dashboard' }, true);
+ showNotifications({ title: 'Incorrect Dashboard', body: 'Clinical Collections cannot be viewed on Research Dashboard' });
return;
}
}
else {
if(biospecimenData[conceptIds.collection.collectionSetting] === conceptIds.research) {
hideAnimation();
- showNotifications({ title: 'Incorrect Dashboard', body: 'Research Collections cannot be viewed on Clinical Dashboard' }, true);
+ showNotifications({ title: 'Incorrect Dashboard', body: 'Research Collections cannot be viewed on Clinical Dashboard' });
return;
}
}
@@ -183,11 +183,11 @@ export const addEventAddSpecimenToBox = () => {
const shippingLocationValue = document.getElementById('selectLocationList').value;
if(shippingLocationValue === 'none') {
- showNotifications({ title: 'Shipping Location Not Selected', body: 'Please select a shipping location from the dropdown.' }, true);
+ showNotifications({ title: 'Shipping Location Not Selected', body: 'Please select a shipping location from the dropdown.' });
return;
}
if (masterSpecimenId === '') {
- showNotifications({ title: 'Empty Entry or Scan', body: 'Please enter or scan a specimen bag ID or Full Specimen ID.' }, true);
+ showNotifications({ title: 'Empty Entry or Scan', body: 'Please enter or scan a specimen bag ID or Full Specimen ID.' });
return;
}
@@ -197,7 +197,7 @@ export const addEventAddSpecimenToBox = () => {
const isScannedIdInUnshippedBoxes = scannedIdInUnshippedBoxes['foundMatch'];
if (foundScannedIdShipped){
- showNotifications({ title:'Item reported as already shipped', body: 'Please enter or scan another specimen bag ID or Full Specimen ID.'}, true);
+ showNotifications({ title:'Item reported as already shipped', body: 'Please enter or scan another specimen bag ID or Full Specimen ID.'});
return;
}
@@ -206,7 +206,7 @@ export const addEventAddSpecimenToBox = () => {
const siteSpecificLocation = conceptIdToSiteSpecificLocation[scannedIdInUnshippedBoxes[conceptIds.shippingLocation]];
const siteSpecificLocationName = siteSpecificLocation || '';
const scannedInput = scannedIdInUnshippedBoxes['inputScanned'];
- showNotifications({ title:`${scannedInput} has already been recorded`, body: `${scannedInput} is recorded as being in ${boxNum} in ${siteSpecificLocationName}`}, true);
+ showNotifications({ title:`${scannedInput} has already been recorded`, body: `${scannedInput} is recorded as being in ${boxNum} in ${siteSpecificLocationName}`});
return;
}
@@ -214,7 +214,7 @@ export const addEventAddSpecimenToBox = () => {
const biospecimensList = specimenTablesResult.biospecimensList;
if (biospecimensList.length === 0) {
- showNotifications({ title: 'Item not found', body: `Item not reported as collected. Go to the Collection Dashboard to add specimen.` }, true);
+ showNotifications({ title: 'Item not found', body: `Item not reported as collected. Go to the Collection Dashboard to add specimen.` });
return;
} else {
document.getElementById('submitMasterSpecimenId').click();
@@ -237,7 +237,7 @@ const addEventSubmitSpecimenBuildModal = () => {
const tableIndex = specimenTablesResult.tableIndex;
if (biospecimensList.length == 0) {
- showNotifications({ title: 'Not found', body: 'The specimen with entered search criteria was not found!' }, true);
+ showNotifications({ title: 'Not found', body: 'The specimen with entered search criteria was not found!' });
hideAnimation();
const delay = ms => new Promise(res => setTimeout(res, ms));
await delay(500);
@@ -260,6 +260,7 @@ export const addEventAddSpecimensToListModalButton = (bagId, tableIndex, isOrpha
let boxIdAndBagsObj = {};
for (let i = 0; i < boxList.length; i++) {
const box = boxList[i];
+ if (!box['bags']) box['bags'] = {};
boxIdAndBagsObj[box[conceptIds.shippingBoxId]] = box['bags'];
locations[box[conceptIds.shippingBoxId]] = box[conceptIds.shippingLocation];
}
@@ -276,7 +277,7 @@ export const addEventAddSpecimensToListModalButton = (bagId, tableIndex, isOrpha
updateShippingStateAddBagToBox(currBoxId, bagId, boxToUpdate);
await startShipping(appState.getState().userName, true, currBoxId);
} else {
- showNotifications({ title: 'Error', body: 'Error updating box' }, true);
+ showNotifications({ title: 'Error', body: 'Error updating box' });
}
}
}, { once: true })
@@ -571,7 +572,7 @@ const addEventNewUserForm = (userEmail) => {
}
else if (response.code === 400 && response.message === 'User with this email already exists') {
hideAnimation();
- showNotifications({ title: 'User already exists!', body: `User with email: ${data.email} already exists` }, true);
+ showNotifications({ title: 'User already exists!', body: `User with email: ${data.email} already exists` });
}
})
}
@@ -917,7 +918,7 @@ const btnsClicked = async (connectId, formData) => {
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.' }, true)
+ showNotifications({ title: 'Collection ID Duplication', body: 'Entered Collection ID is already associated with a different Connect ID.' })
return;
}
@@ -928,7 +929,7 @@ const btnsClicked = async (connectId, formData) => {
const storeResponse = await storeSpecimen([formData]);
if (storeResponse.code === 400) {
hideAnimation();
- showNotifications({ title: 'Specimen already exists!', body: `Collection ID ${collectionID} is already associated with a different Connect ID` }, true);
+ showNotifications({ title: 'Specimen already exists!', body: `Collection ID ${collectionID} is already associated with a different Connect ID` });
return;
}
}
@@ -1999,7 +2000,7 @@ export const addEventSaveAndContinueButton = async (boxIdAndBagsObj, userName, b
const boxIdArray = Object.keys(boxIdAndBagsObj);
const trackingNumConfirmEls = Array.from(document.getElementsByClassName("invalid"));
if (trackingNumConfirmEls.length > 0) {
- showNotifications({ title: 'Invalid Fields', body: 'Please add valid inputs to fields.' }, true);
+ showNotifications({ title: 'Invalid Fields', body: 'Please add valid inputs to fields.' });
return;
}
@@ -2007,7 +2008,7 @@ export const addEventSaveAndContinueButton = async (boxIdAndBagsObj, userName, b
const trackingId = document.getElementById(boxId + "trackingId").value.toUpperCase();
const trackingIdConfirm = document.getElementById(boxId + "trackingIdConfirm").value.toUpperCase();
if (trackingId === '' || trackingIdConfirm === '') {
- showNotifications({ title: 'Missing Fields', body: 'Please enter in shipment tracking numbers'}, true);
+ showNotifications({ title: 'Missing Fields', body: 'Please enter in shipment tracking numbers'});
return;
}
@@ -2089,6 +2090,15 @@ export const addEventSaveButton = async (boxIdAndBagsObj) => {
})
}
+const validateShipperEmail = (email) => {
+ const finalizeSignInputEle = document.getElementById('finalizeSignInput');
+ if (finalizeSignInputEle.value.toUpperCase() !== email.toUpperCase()) {
+ showNotifications({ title: 'Error Shipping Box(es)', body: `Email mismatch. You entered: ${finalizeSignInputEle.value}, which does not match the email on record.` });
+ return false;
+ }
+ return true;
+}
+
/**
* Handle 'Sign' button click
* @param {object} boxIdAndTrackingObj eg: {Box1: {959708259: '123456789012', specimens:{'CXA001234 0008':{...}} }}
@@ -2097,62 +2107,55 @@ export const addEventSaveButton = async (boxIdAndBagsObj) => {
* @param {string} shipmentCourier name of shipment courier (eg: 'FedEx')
*/
export const addEventCompleteShippingButton = (boxIdAndTrackingObj, userName, boxWithTempMonitor, shipmentCourier) => {
- document.getElementById('finalizeModalSign').addEventListener('click', async () => {
- const finalizeSignInputEle = document.getElementById('finalizeSignInput');
- const [firstName, lastName] = userName.split(/\s+/);
- const firstNameShipper = firstName ?? "";
- const lastNameShipper = lastName ?? "";
- const errorMessageEle = document.getElementById('finalizeModalError');
+ const finalizeModalSignElement = document.getElementById('finalizeModalSign');
+ const finalizeModalCancelElement = document.getElementById('finalizeModalCancel');
- if (finalizeSignInputEle.value.toUpperCase() !== userName.toUpperCase()) {
- errorMessageEle.style.display = "block";
- return;
- }
-
- // Block subsequent requests before the first one is completed
- if (requestsBlocker.isBlocking()) return;
- requestsBlocker.block();
+ const finalizeAndShip = async () => {
+ if (!validateShipperEmail(userName)) return;
const commonShippingData = {
- 666553960: conceptIds[shipmentCourier],
- 948887825: firstNameShipper,
- 885486943: lastNameShipper,
- boxWithTempMonitor,
+ [conceptIds.shipmentCourier]: conceptIds[shipmentCourier],
+ [conceptIds.shippedByFirstName]: userName,
+ boxWithTempMonitor,
};
- let boxIdToTrackingNumberObj = {};
- for (const boxId in boxIdAndTrackingObj) {
- boxIdToTrackingNumberObj[boxId] = boxIdAndTrackingObj[boxId][conceptIds.shippingTrackingNumber];
- }
+ const boxIdToTrackingNumberObj = Object.fromEntries(
+ Object.entries(boxIdAndTrackingObj).map(
+ ([boxId, value]) => [boxId, value[conceptIds.shippingTrackingNumber]]
+ )
+ );
- const shipment = await ship(boxIdToTrackingNumberObj, commonShippingData);
-
- if (shipment.code === 200) {
- boxWithTempMonitor && (await updateNewTempDate());
- document.getElementById('finalizeModalCancel').click();
- alert('This shipment is now finalized; no other changes can be made');
- localforage.removeItem('shipData');
- startShipping(userName);
- } else {
- errorMessageEle.style.display = 'block';
- errorMessageEle.textContent =
- 'There was an error when saving the shipment data.';
+ try {
+ showAnimation();
+ const shipment = await ship(boxIdToTrackingNumberObj, commonShippingData);
+ hideAnimation();
- if (shipment.code === 500) {
- errorMessageEle.textContent =
- 'There was an error when saving the shipment data. Please sign again.';
- }
+ if (shipment.code === 200) {
+ boxWithTempMonitor && (await updateNewTempDate());
+ finalizeModalCancelElement.click();
+ localforage.removeItem('shipData');
+ showNotifications({ title: 'Success Shipping Box(es)', body: 'Box(es) Shipped Successfully! No other changes can be made to the boxes that were just shipped.' }, 10000);
+ startShipping(userName);
+ } else {
+ showNotifications({ title: 'Error Shipping Box(es)', body: `There was an error shipping the box(es). Please try again: ${shipment.message}` });
+ }
+ } catch (error) {
+ showNotifications({ title: 'Error Shipping Box(es)', body: `There was an error shipping the box(es). Please try again: ${error}` });
}
+ }
- requestsBlocker.unblock();
- });
-
- // Restore error message after closing the modal, in multiple clicks
- document.getElementById('finalizeModalCancel').addEventListener('click', () => {
+ const finalizeModalCancelClickHandler = () => {
const errorMessageEle = document.getElementById('finalizeModalError');
errorMessageEle.style.display = "none";
errorMessageEle.textContent = `*Please type in ${userName}`;
- });
+ };
+
+ // Remove event listeners, then add them (ensure no duplicates)
+ finalizeModalSignElement.removeEventListener('click', finalizeAndShip);
+ finalizeModalCancelElement.removeEventListener('click', finalizeModalCancelClickHandler);
+
+ finalizeModalSignElement.addEventListener('click', finalizeAndShip);
+ finalizeModalCancelElement.addEventListener('click', finalizeModalCancelClickHandler);
}
export const populateFinalCheck = (boxIdAndTrackingObj) => {
@@ -2271,9 +2274,9 @@ export const populateCourierBox = async () => {
}
-export const populateBoxTable = async (page, filter) => {
+export const populateBoxTable = async (page, filter, source) => {
showAnimation();
- let pageStuff = await getPage(page, 5, '656548982', filter)
+ let pageStuff = await getPage(page, 5, '656548982', filter, source)
let currTable = document.getElementById('boxTable')
currTable.innerHTML = ''
let rowCount = currTable.rows.length;
@@ -2302,43 +2305,29 @@ export const populateBoxTable = async (page, filter) => {
for (let j = 0; j < keys.length; j++) {
numTubes += currPage['bags'][keys[j]]['arrElements'].length;
}
- let shippedDate = ''
- let receivedDate = ''
- let packagedCondition = ''
-
- if (currPage.hasOwnProperty('656548982')) {
- const shippedDateStr = currPage['656548982'];
- shippedDate = retrieveDateFromIsoString(shippedDateStr)
- }
-
- if(currPage.hasOwnProperty('926457119')) {
- const receivedDateStr = currPage['926457119']
- receivedDate = retrieveDateFromIsoString(receivedDateStr)
- }
-
- if(currPage.hasOwnProperty('238268405')) {
- packagedCondition = currPage['238268405']
- }
+ const shippedDate = currPage['656548982'] ? retrieveDateFromIsoString(currPage['656548982']) : '';
+ const receivedDate = currPage['926457119'] ? retrieveDateFromIsoString(currPage['926457119']) : '';
+ const packagedCondition = currPage['238268405'] || '';
currRow.insertCell(0).innerHTML = currPage[conceptIds.shippingTrackingNumber] ?? '';
currRow.insertCell(1).innerHTML = shippedDate;
currRow.insertCell(2).innerHTML = conceptIdToSiteSpecificLocation[currPage['560975149']];
currRow.insertCell(3).innerHTML = currPage['132929440'];
currRow.insertCell(4).innerHTML = '';
- currRow.insertCell(5).innerHTML = currPage.hasOwnProperty('333524031') ? "Yes" : "No"
+ currRow.insertCell(5).innerHTML = currPage['333524031'] === 353358909 ? "Yes" : "No"
currRow.insertCell(6).innerHTML = receivedDate;
currRow.insertCell(7).innerHTML = convertConceptIdToPackageCondition(packagedCondition, packageConditonConversion);
- currRow.insertCell(8).innerHTML = currPage.hasOwnProperty('870456401') ? currPage['870456401'] : '' ;
- addEventViewManifestButton('reportsViewManifest' + i, currPage);
+ currRow.insertCell(8).innerHTML = currPage['870456401'] || '' ;
+ addEventViewManifestButton('reportsViewManifest' + i, currPage, source);
}
hideAnimation();
}
-export const addEventViewManifestButton = (buttonId, currPage) => {
+export const addEventViewManifestButton = (buttonId, currPage, source) => {
let button = document.getElementById(buttonId);
button.addEventListener('click', () => {
- showReportsManifest(currPage);
+ showReportsManifest(currPage, source);
});
}
@@ -2432,7 +2421,7 @@ export const populateReportManifestTable = (currPage, searchSpecimenInstituteArr
}
}
-export const addPaginationFunctionality = (lastPage, filter) => {
+export const addPaginationFunctionality = (lastPage, filter, source) => {
let paginationButtons = document.getElementById('paginationButtons');
paginationButtons.innterHTML = ""
paginationButtons.innerHTML = `
`;
}
diff --git a/src/pages/bptl.js b/src/pages/bptl.js
index 7ece08dc..708c428a 100644
--- a/src/pages/bptl.js
+++ b/src/pages/bptl.js
@@ -44,9 +44,9 @@ const bptlScreenTemplate = (name, data, auth, route) => {
Home Collection
-
-
-
+
+
+
Supplies
@@ -64,6 +64,7 @@ const bptlScreenTemplate = (name, data, auth, route) => {
Reports
+
@@ -105,4 +106,8 @@ const redirectPageToLocation = () => {
collectionIdSearchRedirection && collectionIdSearchRedirection.addEventListener("click", async () => {
location.hash = "#collectionidsearch";
});
+ const shippingReportRedirection = document.getElementById("bptlShipReports");
+ shippingReportRedirection && shippingReportRedirection.addEventListener("click", async () => {
+ location.hash = "#bptlshipreports";
+ });
};
\ No newline at end of file
diff --git a/src/pages/dailyReport.js b/src/pages/dailyReport.js
new file mode 100644
index 00000000..cc010c5c
--- /dev/null
+++ b/src/pages/dailyReport.js
@@ -0,0 +1,164 @@
+import { userAuthorization, removeActiveClass, hideAnimation, showAnimation, getDailyParticipant, convertISODateTime, restrictNonBiospecimenUser, getDataAttributes, appState } from "./../shared.js"
+import { homeNavBar, reportSideNavBar } from '../navbar.js';
+import fieldToConceptIdMapping from "../fieldToConceptIdMapping.js";
+
+
+export const dailyReportTemplate = (auth, route) => {
+ auth.onAuthStateChanged(async user => {
+ if(user){
+ const response = await userAuthorization(route, user.displayName ? user.displayName : user.email);
+ appState.setState({siteAcronym: response.siteAcronym});
+ if ( response.isBiospecimenUser === false ) {
+ restrictNonBiospecimenUser();
+ return;
+ }
+ if(!response.role) return;
+ renderDailyReport();
+ }
+ else {
+ document.getElementById('navbarNavAltMarkup').innerHTML = homeNavBar();
+ window.location.hash = '#';
+ }
+ });
+}
+
+
+export const renderDailyReport = async () => {
+ let template = `
+
+
+
+
Reports
+ ${reportSideNavBar()}
+
+
+
+ ${renderCollectionLocationList()}
+
+
+
+
+
`;
+ document.getElementById('contentBody').innerHTML = template;
+ removeActiveClass('nav-link', 'active');
+ const navBarBtn = document.getElementById('navBarDailyReport');
+ navBarBtn.classList.add('active');
+ initializeDailyReportTable();
+}
+
+const renderCollectionLocationList = () => {
+ let template = ``;
+ template += `
+
+
+
+
+ `
+ return template;
+}
+
+const initializeDailyReportTable = async () => {
+ showAnimation();
+ const dailyReportsData = await getDailyParticipant().then(res => res.data);
+ appState.setState({dailyReportsData: dailyReportsData}); // store inital daily reports data
+ populateDailyReportTable(`Filter by Collection Location`, dailyReportsData);
+}
+
+const populateDailyReportTable = (dropdownHeader, dailyReportsData) => {
+ const currTable = document.getElementById('populateDailyReportTable');
+ currTable.innerHTML = '';
+
+ const headerRow = currTable.insertRow();
+ headerRow.innerHTML = `
+ Collection Location |
+ Connect ID |
+ Last Name |
+ First Name |
+ Check-In Date/Time |
+ Collection ID |
+ Collection Finalized |
+ Check-Out Date/Time |
+ `;
+
+ for (const item of dailyReportsData) {
+ if (!item[fieldToConceptIdMapping.collection.selectedVisit]?.[fieldToConceptIdMapping.baseline.visitId]?.[fieldToConceptIdMapping.checkOutDateTime]) {
+ const newRow = currTable.insertRow();
+ newRow.innerHTML = `
+
+ ${fieldToConceptIdMapping.collectionLocationMapping[item[fieldToConceptIdMapping.collectionLocation]]} |
+ ${item['Connect_ID']} |
+ ${item[fieldToConceptIdMapping.lastName]} |
+ ${item[fieldToConceptIdMapping.firstName]} |
+ ${convertISODateTime(item[fieldToConceptIdMapping.checkInDateTime])} |
+ ${item[fieldToConceptIdMapping.collection.id]} |
+ ${item[fieldToConceptIdMapping.collection.finalizedTime] !== undefined ? convertISODateTime(item[fieldToConceptIdMapping.collection.finalizedTime]) : ``} |
+ ${item[fieldToConceptIdMapping.checkOutDateTime] !== undefined ? convertISODateTime(item[fieldToConceptIdMapping.checkOutDateTime]) : ``} |
+ `;
+ }
+ }
+ hideAnimation();
+ dropdownTrigger(dropdownHeader);
+}
+
+const reInitalizeDailyReportTable = async (dropdownText, siteKey, dailyData) => {
+ showAnimation();
+ let data = dailyData;
+ if (siteKey !== 'all') {
+ data = data.filter((dailyReportData) => dailyReportData[fieldToConceptIdMapping.collectionLocation] === fieldToConceptIdMapping.nameToKeyObj[siteKey]);
+ }
+ populateDailyReportTable(dropdownText, data)
+}
+
+
+const dropdownTrigger = (sitekeyName) => {
+ let a = document.getElementById('dropdownSites');
+ let dropdownMenuButton = document.getElementById('dropdownMenuButtonSites');
+ let tempSiteName = a.innerHTML = sitekeyName;
+ if (dropdownMenuButton) {
+ dropdownMenuButton.addEventListener('click', (e) => {
+ if (sitekeyName === `Filter by Collection Location` || sitekeyName === tempSiteName) {
+ a.innerHTML = e.target.textContent;
+ const sitekey = getDataAttributes(e.target)
+ const dailyReportsData = appState.getState().dailyReportsData;
+ reInitalizeDailyReportTable(e.target.textContent, sitekey, dailyReportsData);
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/pages/receipts/activeReceiptsNavbar.js b/src/pages/receipts/activeReceiptsNavbar.js
index 4cdedd25..1ade0e23 100644
--- a/src/pages/receipts/activeReceiptsNavbar.js
+++ b/src/pages/receipts/activeReceiptsNavbar.js
@@ -17,5 +17,5 @@ export const activeReceiptsNavbar = () => {
csvFileReceiptNavItem.classList.add("active");
csvFileReceiptNavItem.style.backgroundColor = "#bbcffc85";
csvFileReceiptNavItem.style.borderRadius = "4px 4px 0 0";
- } else return;
+ };
};
\ No newline at end of file
diff --git a/src/pages/receipts/csvFileReceipt.js b/src/pages/receipts/csvFileReceipt.js
index 17713553..30e1c703 100644
--- a/src/pages/receipts/csvFileReceipt.js
+++ b/src/pages/receipts/csvFileReceipt.js
@@ -1,4 +1,4 @@
-import { showAnimation, hideAnimation, getIdToken, nameToKeyObj, keyToLocationObj, baseAPI, keyToNameObj, convertISODateTime, formatISODateTime, getAllBoxes, getSiteAcronym, conceptIdToSiteSpecificLocation } from "../../shared.js";
+import { showAnimation, hideAnimation, getIdToken, keyToNameAbbreviationObj, keyToLocationObj, baseAPI, keyToNameObj, convertISODateTime, formatISODateTime, getAllBoxes, conceptIdToSiteSpecificLocation, showNotifications } from "../../shared.js";
import fieldToConceptIdMapping from "../../fieldToConceptIdMapping.js";
import { receiptsNavbar } from "./receiptsNavbar.js";
import { nonUserNavBar } from "../../navbar.js";
@@ -103,7 +103,7 @@ const confirmFileSelection = () => {
const radioVal = radio.value;
document.getElementById('modalShowMoreData').querySelector('#closeModal').click(); // closes modal
showAnimation();
- const response = await getAllBoxes(`bptl`);
+ const response = await getAllBoxes(`bptlPackagesInTransit`);
hideAnimation();
const allBoxesShippedBySiteAndNotReceived = getRecentBoxesShippedBySiteNotReceived(response.data);
let modifiedTransitResults = updateInTransitMapping(allBoxesShippedBySiteAndNotReceived);
@@ -113,55 +113,63 @@ const confirmFileSelection = () => {
}
const csvFileButtonSubmit = () => {
- document.getElementById("csvCreateFileButton").addEventListener("click", async (e)=> {
- e.preventDefault();
- let dateFilter = document.getElementById("csvDateInput").value
- dateFilter = dateFilter+'T00:00:00.000Z'
- showAnimation();
- const results = await getBSIQueryData(dateFilter);
- hideAnimation();
- document.getElementById("csvDateInput").value = ``;
- let modifiedResults = modifyBSIQueryResults(results.data);
- generateBSIqueryCSVData(modifiedResults);
- })
+ document.getElementById("csvCreateFileButton").addEventListener("click", async (e)=> {
+ e.preventDefault();
+ const dateFilter = document.getElementById("csvDateInput").value + 'T00:00:00.000Z';
+ showAnimation();
+
+ try {
+ const results = await getSpecimensByReceivedDate(dateFilter);
+ const modifiedResults = modifyBSIQueryResults(results.data);
+ generateBSIqueryCSVData(modifiedResults);
+ hideAnimation();
+ } catch (e) {
+ hideAnimation();
+ showNotifications({ title: 'Error', body: `Error fetching BSI Query Data -- ${e.message}` });
+ }
+ });
}
-const getCurrentDate = () => {
- const currentDate = new Date().toLocaleDateString('en-CA');
- return currentDate;
+const getSpecimensByReceivedDate = async (dateFilter) => {
+ try {
+ const idToken = await getIdToken();
+ const response = await fetch(`${baseAPI}api=getSpecimensByReceivedDate&receivedTimestamp=${dateFilter}`, {
+ method: "GET",
+ headers: {
+ Authorization: "Bearer " + idToken,
+ },
+ });
+
+ if (response.status !== 200) {
+ throw new Error(`Error fetching specimens by received date. ${response.status}`);
+ }
+
+ return await response.json();
+ } catch (e) {
+ console.error(e);
+ throw new Error(`Error fetching specimens by received date: ${e.message}`);
+ }
}
-const getBSIQueryData = async (filter) => {
- const idToken = await getIdToken();
- const response = await fetch(`${baseAPI}api=queryBsiData&type=${filter}`, {
- method: "GET",
- headers: {
- Authorization: "Bearer" + idToken,
- },
- });
-
- try {
- if (response.status === 200) {
- const bsiQueryData = await response.json();
- return bsiQueryData
- }
- } catch (e) { // if error return an empty array
- console.log(e);
- return [];
- }
-};
-
+const getCurrentDate = () => {
+ return new Date().toLocaleDateString('en-CA');
+}
const modifyBSIQueryResults = (results) => {
- let filteredResults = results.filter(result => result.length !== 0 && (result[0][fieldToConceptIdMapping.collectionId] !== undefined &&
- result[0][fieldToConceptIdMapping.collectionId].split(' ')[1] !== '0008' && result[0][fieldToConceptIdMapping.collectionId].split(' ')[1] !== '0009')
- && result[0][fieldToConceptIdMapping.discardFlag] !== fieldToConceptIdMapping.yes && result[0][fieldToConceptIdMapping.deviationNotFound] !== fieldToConceptIdMapping.yes)
- filteredResults = filteredResults.flat()
- filteredResults.forEach(filteredResult => {
- let vialMappings = getVialTypesMappings(filteredResult)
- updateResultMappings(filteredResult, vialMappings)
- })
- return filteredResults
+ const csvDataArray = [];
+ results.forEach(result => {
+ const collectionType = result[fieldToConceptIdMapping.collectionType];
+ const healthcareProvider = result[fieldToConceptIdMapping.healthcareProvider];
+ const specimenKeysArray = Object.keys(result.specimens);
+ for (const specimenKey of specimenKeysArray) {
+ const [collectionId, tubeId] = result.specimens[specimenKey][fieldToConceptIdMapping.collectionId].split(' ') ?? ['', ''];
+ const vialMappings = getVialTypesMappings(tubeId, collectionType, healthcareProvider);
+ const csvRowsFromSpecimen = updateResultMappings(result, vialMappings, collectionId, tubeId);
+ csvDataArray.push(csvRowsFromSpecimen);
+ }
+ });
+
+ return csvDataArray;
}
/**
@@ -214,149 +222,167 @@ const materialTypeMapping = (specimenId) => {
return materialTypeObject[tubeId] ?? '';
}
-/**
- * Maps specimen id to material type based on last 4 digits, collection type & health care provider
- * @param {object} filteredResult - Object containg essential information (health care provider, collection type, & more)
- * @returns {array} Returns an array containing all the vial mapping
-*/
-
-const getVialTypesMappings = (filteredResult) => {
- let vialMappingsHolder = []
- const tubeId = filteredResult[fieldToConceptIdMapping.collectionId].split(' ')[1]
- const collectionType = filteredResult[fieldToConceptIdMapping.collectionType]
- const healthCareProvider = filteredResult[fieldToConceptIdMapping.healthcareProvider]
-
- if (collectionType === fieldToConceptIdMapping.research && (tubeId === '0001' || tubeId === '0002' )) {
- vialMappingsHolder.push('8.5 mL Serum separator tube', 'SST', 'Serum', '8.5')
- } else if (collectionType === fieldToConceptIdMapping.research && tubeId === '0003') {
- vialMappingsHolder.push('10 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '10')
- } else if (collectionType === fieldToConceptIdMapping.research && tubeId === '0004') {
- vialMappingsHolder.push('10 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '10')
- } else if (collectionType === fieldToConceptIdMapping.research && tubeId === '0005') {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'WHOLE BL', '6')
- } else if (collectionType === fieldToConceptIdMapping.research && tubeId === '0006') {
- vialMappingsHolder.push('10 ml Vacutainer', 'No Additive', 'Urine', '10')
- } else if (collectionType === fieldToConceptIdMapping.research && tubeId === '0007') {
- vialMappingsHolder.push('15ml Nalgene jar', 'Crest Alcohol Free', 'Saliva', '15')
- } else if (collectionType === fieldToConceptIdMapping.clinical && (tubeId === '0001' || tubeId === '0002' || tubeId === '0011' || tubeId === '0012' || tubeId === '0021')) {
- vialMappingsHolder.push('5 mL Serum separator tube', 'SST', 'Serum', '5')
- } else if (collectionType === fieldToConceptIdMapping.clinical && (tubeId === '0003' || tubeId === '0013')) {
- vialMappingsHolder.push('4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && (tubeId === '0004' || tubeId === '0014' || tubeId === '0024')) {
- vialMappingsHolder.push('4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && tubeId === '0005') {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'WHOLE BL', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && tubeId === '0006') {
- vialMappingsHolder.push('6 ml Vacutainer', 'No Additive', 'Urine', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpCO"] && (tubeId === '0001' || tubeId === '0002' || tubeId === '0011'
- || tubeId === '0012' )) {
- vialMappingsHolder.push('5 mL Serum separator tube', 'SST', 'Serum', '5')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpCO"] && (tubeId === '0003' || tubeId === '0013' )) {
- vialMappingsHolder.push('4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpCO"] && (tubeId === '0004' || tubeId === '0014' )) {
- vialMappingsHolder.push('4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpCO"] && (tubeId === '0005')) {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'WHOLE BL', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpCO"] && (tubeId === '0001')) {
- vialMappingsHolder.push('6 ml Vacutainer', 'No Additive', 'Urine', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpNW"] && (tubeId === '0001' || tubeId === '0002'
- || tubeId === '0011' || tubeId === '0012' || tubeId === '0021' )) {
- vialMappingsHolder.push('3.5 mL Serum separator tube', 'SST', 'Serum', '3.5')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpNW"] && (tubeId === '0013' || tubeId === '0003')) {
- vialMappingsHolder.push('4 mL Serum separator tube', 'Lithium Heparin', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpNW"] && (tubeId === '0014' || tubeId === '0004')) {
- vialMappingsHolder.push('4 mL Serum separator tube', 'EDTA = K2', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpNW"] && (tubeId === '0005')) {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'WHOLE BL', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpNW"] && (tubeId === '0006')) {
- vialMappingsHolder.push('10 ml Vacutainer', 'No Additive', 'Urine', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpHI"] && (tubeId === '0001' || tubeId === '0002'
- || tubeId === '0011' || tubeId === '0012')) {
- vialMappingsHolder.push('5 ml Serum separator tube', 'SST', 'Serum', '5')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpHI"] && (tubeId === '0003' || tubeId === '0013')) {
- vialMappingsHolder.push('4 mL Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpHI"] && (tubeId === '0004' || tubeId === '0014'
- || tubeId === '0024')) {
- vialMappingsHolder.push('3 mL Vacutainer', 'EDTA = K2', 'WHOLE BL', '3')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpHI"] && (tubeId === '0005')) {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'WHOLE BL', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpHI"] && (tubeId === '0006')) {
- vialMappingsHolder.push('15 ml Nalgene jar', 'No Additive', 'Urine', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpGA"] && (tubeId === '0001' || tubeId === '0002'
- || tubeId === '0011' || tubeId === '0012' )) {
- vialMappingsHolder.push('5 ml Serum separator tube', 'SST', 'Serum', '5')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpGA"] && (tubeId === '0003' || tubeId === '0013')) {
- vialMappingsHolder.push('4.5 mL Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4.5')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpGA"] && (tubeId === '0004' || tubeId === '0014')) {
- vialMappingsHolder.push('4 mL Vacutainer', 'EDTA = K2', 'WHOLE BL', '4')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpGA"] && (tubeId === '0005')) {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'WHOLE BL', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["kpGA"] && (tubeId === '0006')) {
- vialMappingsHolder.push('15 ml Nalgene jar', 'No Additive', 'Urine', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["hfHealth"] && (tubeId === '0001' || tubeId === '0002')) {
- vialMappingsHolder.push('10 ml Serum separator tube', 'SST', 'Serum', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["hfHealth"] && (tubeId === '0003')) {
- vialMappingsHolder.push('10 ml Vacutainer', 'Lithium Heparin', 'Whole Blood', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["hfHealth"] && (tubeId === '0004')) {
- vialMappingsHolder.push('10 ml Vacutainer', 'EDTA', 'Whole Blood', '10')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["hfHealth"] && (tubeId === '0005')) {
- vialMappingsHolder.push('6 ml Vacutainer', 'ACD', 'Whole Blood', '6')
- } else if (collectionType === fieldToConceptIdMapping.clinical && healthCareProvider === nameToKeyObj["hfHealth"] && (tubeId === '0006')) {
- vialMappingsHolder.push('10 ml Vacutainer', 'No Additive', 'Urine', '6')
- } else {
- vialMappingsHolder.push('', '', '', '')
- }
+const vialMapping = {
+ research: {
+ default: {
+ '0001': ['10 mL Serum separator tube', 'SST', 'Serum', '10'],
+ '0002': ['10 mL Serum separator tube', 'SST', 'Serum', '10'],
+ '0003': ['10 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '10'],
+ '0004': ['10 ml Vacutainer', 'EDTA', 'WHOLE BL', '10'],
+ '0005': ['6 ml Vacutainer', 'ACD', 'WHOLE BL', '6'],
+ '0006': ['10 ml Vacutainer', 'No Additive', 'Urine', '10'],
+ '0007': ['15 ml Nalgene jar', 'Crest Alcohol Free', 'Saliva', '10'],
+ },
+ },
+ clinical: {
+ hfHealth: {
+ '0001': ['10 mL Serum separator tube', 'SST', 'Serum', '10'],
+ '0002': ['10 mL Serum separator tube', 'SST', 'Serum', '10'],
+ '0003': ['10 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '10'],
+ '0004': ['10 ml Vacutainer', 'EDTA', 'WHOLE BL', '10'],
+ '0005': ['6 ml Vacutainer', 'ACD', 'WHOLE BL', '6'],
+ '0006': ['10 ml Vacutainer', 'No Additive', 'Urine', '10'],
+ },
+ kpCO: {
+ '0001': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0002': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0011': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0012': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0003': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0013': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0004': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0014': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0005': ['6 ml Vacutainer', 'ACD', 'WHOLE BL', '6'],
+ '0006': ['6 ml Vacutainer', 'No Additive', 'Urine', '6'],
+ },
+ kpGA: {
+ '0001': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0002': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0011': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0012': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0003': ['4.5 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4.5'],
+ '0013': ['4.5 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4.5'],
+ '0004': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0014': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0005': ['6 ml Vacutainer', 'ACD', 'WHOLE BL', '6'],
+ '0006': ['15ml Nalgene jar', 'No Additive', 'Urine', '10'],
+ },
+ kpHI: {
+ '0001': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0002': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0011': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0012': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0003': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0013': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0004': ['3 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '3'],
+ '0014': ['3 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '3'],
+ '0024': ['3 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '3'],
+ '0005': ['10 ml Vacutainer', 'ACD', 'WHOLE BL', '10'],
+ '0006': ['15ml Nalgene jar', 'No Additive', 'Urine', '10'],
+ },
+ kpNW: {
+ '0001': ['3.5 mL Serum separator tube', 'SST', 'Serum', '3.5'],
+ '0002': ['3.5 mL Serum separator tube', 'SST', 'Serum', '3.5'],
+ '0011': ['3.5 mL Serum separator tube', 'SST', 'Serum', '3.5'],
+ '0012': ['3.5 mL Serum separator tube', 'SST', 'Serum', '3.5'],
+ '0021': ['3.5 mL Serum separator tube', 'SST', 'Serum', '3.5'],
+ '0003': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0013': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0004': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0014': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0005': ['6 ml Vacutainer', 'ACD', 'WHOLE BL', '6'],
+ '0006': ['10 ml Vacutainer', 'No Additive', 'Urine', '10'],
+ },
+ default: {
+ '0001': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0002': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0011': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0012': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0021': ['5 mL Serum separator tube', 'SST', 'Serum', '5'],
+ '0003': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0013': ['4 ml Vacutainer', 'Lithium Heparin', 'WHOLE BL', '4'],
+ '0004': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0014': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0024': ['4 ml Vacutainer', 'EDTA = K2', 'WHOLE BL', '4'],
+ '0005': ['6 ml Vacutainer', 'ACD', 'WHOLE BL', '6'],
+ '0006': ['10 ml Vacutainer', 'No Additive', 'Urine', '10'],
+ '0007': ['15ml Nalgene jar', 'Crest Alcohol Free', 'Saliva', '10'],
+ },
+ }
+};
- return vialMappingsHolder
-}
+const getVialTypesMappings = (tubeId, collectionType, healthcareProvider) => {
+ if (!collectionType || !tubeId) {
+ return ['', '', '', ''];
+ }
+
+ const collectionTypeString = collectionType === fieldToConceptIdMapping.research ? 'research' : 'clinical';
+ const healthCareProviderString = healthcareProvider ? keyToNameAbbreviationObj[healthcareProvider] : 'default';
+
+ if (collectionTypeString === 'research') {
+ return vialMapping[collectionTypeString].default[tubeId];
+ } else {
+ return vialMapping[collectionTypeString][healthCareProviderString]?.[tubeId] || vialMapping[collectionTypeString].default[tubeId];
+ }
+};
-const updateResultMappings = (filteredResult, vialMappings) => {
- filteredResult['Study ID'] = 'Connect Study';
- filteredResult['Sample Collection Center'] = (filteredResult[fieldToConceptIdMapping.collectionType] === fieldToConceptIdMapping.clinical)
- ? keyToNameObj[filteredResult[fieldToConceptIdMapping.healthcareProvider]] : keyToLocationObj[filteredResult[fieldToConceptIdMapping.collectionLocation]];
- filteredResult['Sample ID'] = filteredResult[fieldToConceptIdMapping.collectionId]?.split(' ')[0] || '';
- filteredResult['Sequence'] = filteredResult[fieldToConceptIdMapping.collectionId]?.split(' ')[1] || '';
- filteredResult['BSI ID'] = filteredResult[fieldToConceptIdMapping.collectionId] || '';
- filteredResult['Subject ID'] = filteredResult['Connect_ID'];
- filteredResult['Date Received'] = formatISODateTime(filteredResult[fieldToConceptIdMapping.dateReceived]) || '';
- filteredResult['Date Drawn'] = (filteredResult[fieldToConceptIdMapping.collectionType] === fieldToConceptIdMapping.clinical)
- ? convertISODateTime(filteredResult[fieldToConceptIdMapping.clinicalDateTimeDrawn]) || '' : convertISODateTime(filteredResult[fieldToConceptIdMapping.dateWithdrawn]) || '';
- filteredResult['Vial Type'] = vialMappings[0];
- filteredResult['Additive/Preservative'] = vialMappings[1];
- filteredResult['Material Type'] = vialMappings[2];
- filteredResult['Volume'] = vialMappings[3];
- filteredResult['Volume Estimate'] = 'Assumed';
- filteredResult['Voume Unit'] = 'ml (cc)';
- filteredResult['Vial Warnings'] = '';
- filteredResult['Hermolyzed'] = '';
- filteredResult['Label Status'] = 'Barcoded';
- filteredResult['Visit'] = 'BL';
-
- // Delete unwanted properties
- delete filteredResult[fieldToConceptIdMapping.healthcareProvider];
- delete filteredResult[fieldToConceptIdMapping.collectionLocation];
- delete filteredResult['Connect_ID'];
- delete filteredResult[fieldToConceptIdMapping.collectionId];
- delete filteredResult[fieldToConceptIdMapping.dateWithdrawn];
- delete filteredResult[fieldToConceptIdMapping.clinicalDateTimeDrawn];
- delete filteredResult[fieldToConceptIdMapping.dateReceived];
- delete filteredResult[fieldToConceptIdMapping.collectionType];
- delete filteredResult[fieldToConceptIdMapping.discardFlag];
- delete filteredResult[fieldToConceptIdMapping.deviationNotFound];
+const updateResultMappings = (filteredResult, vialMappings, collectionId, tubeId) => {
+ const collectionTypeValue = filteredResult[fieldToConceptIdMapping.collectionType];
+ const clinicalDateTime = filteredResult[fieldToConceptIdMapping.clinicalDateTimeDrawn];
+ const withdrawalDateTime = filteredResult[fieldToConceptIdMapping.dateWithdrawn];
+
+ return {
+ 'Study ID': 'Connect Study',
+ 'Sample Collection Center': (collectionTypeValue === fieldToConceptIdMapping.clinical)
+ ? keyToNameObj[filteredResult[fieldToConceptIdMapping.healthcareProvider]]
+ : keyToLocationObj[filteredResult[fieldToConceptIdMapping.collectionLocation]],
+ 'Sample ID': collectionId,
+ 'Sequence': tubeId,
+ 'BSI ID': `${collectionId} ${tubeId}`,
+ 'Subject ID': filteredResult['Connect_ID'],
+ 'Date Received': filteredResult[fieldToConceptIdMapping.dateReceived] ? formatISODateTime(filteredResult[fieldToConceptIdMapping.dateReceived]) : '',
+ 'Date Drawn': collectionTypeValue === fieldToConceptIdMapping.clinical
+ ? (clinicalDateTime ? convertISODateTime(clinicalDateTime) : '')
+ : (withdrawalDateTime ? convertISODateTime(withdrawalDateTime) : ''),
+ 'Vial Type': vialMappings[0],
+ 'Additive/Preservative': vialMappings[1],
+ 'Material Type': vialMappings[2],
+ 'Volume': vialMappings[3],
+ 'Volume Estimate': 'Assumed',
+ 'Volume Unit': 'ml (cc)',
+ 'Vial Warnings': '',
+ 'Hemolyzed': '',
+ 'Label Status': 'Barcoded',
+ 'Visit': 'BL'
+ }
}
const generateBSIqueryCSVData = (items) => {
- let csv = ``;
- csv += `Study ID, Sample Collection Center, Sample ID, Sequence, BSI ID, Subject ID, Date Received, Date Drawn, Vial Type, Additive/Preservative, Material Type, Volume, Volume Estimate, Volume Unit, Vial Warnings, Hemolyzed, Label Status, Visit\r\n`
- downloadCSVfile(items, csv, 'BSI-data-export')
+ const csv = 'Study ID, Sample Collection Center, Sample ID, Sequence, BSI ID, Subject ID, Date Received, Date Drawn, Vial Type, Additive/Preservative, Material Type, Volume, Volume Estimate, Volume Unit, Vial Warnings, Hemolyzed, Label Status, Visit\r\n';
+ downloadBSIQueryCSVFile(items, csv, 'BSI-data-export');
}
const generateInTransitCSVData = (items) => {
- let csv = ``;
- csv += `Ship Date, Tracking Number, Shipped from Site, Shipped from Location, Shipped Date & Time, Expected Number of Samples, Temperature Monitor, Box Number, Specimen Bag ID Type, Full Specimen IDs, Material Type\r\n`
- downloadCSVfile(items, csv, 'In-Transit-CSV-data-export')
+ const csv = `Ship Date, Tracking Number, Shipped from Site, Shipped from Location, Shipped Date & Time, Expected Number of Samples, Temperature Monitor, Box Number, Specimen Bag ID Type, Full Specimen IDs, Material Type\r\n`;
+ downloadCSVfile(items, csv, 'In-Transit-CSV-data-export');
+}
+
+// If value contains a comma, quote or newline, enclose it in double quotes and replace inner double quotes
+const downloadBSIQueryCSVFile = (items, csv, title) => {
+ const csvData = items.map(row =>
+ Object.values(row).map(value =>
+ typeof value === 'string' && (value.includes(',') || value.includes('"') || value.includes('\n') || value.includes('\r'))
+ ? `"${value.replace(/"/g, '""')}"`
+ : value
+ ).join(',')
+ ).join('\r\n');
+
+ csv += csvData;
+
+ generateFileToDownload(csv, title, 'csv');
}
+//TODO: refactor this to the downloadBSIQueryCSVFile format, then remove downloadBSIQueryCSVFile()
const downloadCSVfile = (items, csv, title) => {
for (let row = 0; row < (items.length); row++) {
let keysAmount = Object.keys(items[row]).length
diff --git a/src/pages/receipts/packagesInTransit.js b/src/pages/receipts/packagesInTransit.js
index b14b2d5d..7d25124b 100644
--- a/src/pages/receipts/packagesInTransit.js
+++ b/src/pages/receipts/packagesInTransit.js
@@ -1,4 +1,4 @@
-import { showAnimation, hideAnimation, getAllBoxes, conceptIdToSiteSpecificLocation, searchSpecimenByRequestedSite, appState } from "../../shared.js";
+import { showAnimation, hideAnimation, getAllBoxes, conceptIdToSiteSpecificLocation, searchSpecimenByRequestedSiteAndBoxId, appState } from "../../shared.js";
import fieldToConceptIdMapping from "../../fieldToConceptIdMapping.js";
import { receiptsNavbar } from "./receiptsNavbar.js";
import { nonUserNavBar, unAuthorizedUser } from "../../navbar.js";
@@ -15,7 +15,7 @@ export const packagesInTransitScreen = async (auth, route) => {
const packagesInTransitTemplate = async (username, auth, route) => {
showAnimation();
- const response = await getAllBoxes(`bptl`);
+ const response = await getAllBoxes(`bptlPackagesInTransit`);
hideAnimation();
const allBoxesShippedBySiteAndNotReceived = getRecentBoxesShippedBySiteNotReceived(response.data);
@@ -94,15 +94,7 @@ const packagesInTransitTemplate = async (username, auth, route) => {
export const getRecentBoxesShippedBySiteNotReceived = (boxes) => {
// boxes are from searchBoxes endpoint
if (boxes.length === 0) return [];
-
- const filteredBoxesBySubmitShipmentTimeAndNotReceived = boxes.filter(boxObj => {
- const hasShippingShipDate = boxObj[fieldToConceptIdMapping.shippingShipDate];
- const hasNoSiteShipmentDateReceivedKey = !boxObj[fieldToConceptIdMapping.siteShipmentDateReceived];
- const hasNotReceivedSiteShipment = boxObj[fieldToConceptIdMapping.siteShipmentReceived] === fieldToConceptIdMapping.no;
- return hasShippingShipDate && (hasNoSiteShipmentDateReceivedKey || hasNotReceivedSiteShipment);
- });
-
- return filteredBoxesBySubmitShipmentTimeAndNotReceived.sort((a,b) => {
+ return boxes.sort((a,b) => {
const shipDateA = a[fieldToConceptIdMapping.shippingShipDate];
const shipDateB = b[fieldToConceptIdMapping.shippingShipDate];
return (shipDateA < shipDateB) ? 1 : -1;
@@ -196,8 +188,8 @@ const manifestButton = (allBoxesShippedBySiteAndNotReceived, bagIdArr, manifestM
} = packagesInTransitModalData
manifestModalBodyEl.innerHTML = modalBody;
- showAnimation()
- const searchSpecimenByRequestedSiteResponse = await searchSpecimenByRequestedSite(loginSite);
+ showAnimation();
+ const searchSpecimenByRequestedSiteResponse = await searchSpecimenByRequestedSiteAndBoxId(loginSite, boxNumber);
const searchSpecimenInstituteArray = searchSpecimenByRequestedSiteResponse?.data ?? [];
modalBody =
diff --git a/src/pages/reports/activeReportsNavbar.js b/src/pages/reports/activeReportsNavbar.js
index 562030f0..5cef7ef2 100644
--- a/src/pages/reports/activeReportsNavbar.js
+++ b/src/pages/reports/activeReportsNavbar.js
@@ -14,5 +14,11 @@ export const activeReportsNavbar = () => {
reportsNavItem.classList.add("active");
reportsNavItem.style.backgroundColor = "#bbcffc85";
reportsNavItem.style.borderRadius = "4px 4px 0 0";
- } else return;
+ }
+ else if (location.hash === "#bptlshipreports") {
+ const reportsNavItem = document.getElementById("bptlShippingReportsNavItem");
+ reportsNavItem.classList.add("active");
+ reportsNavItem.style.backgroundColor = "#bbcffc85";
+ reportsNavItem.style.borderRadius = "4px 4px 0 0";
+ }
};
diff --git a/src/pages/reports/collectionIdSearch.js b/src/pages/reports/collectionIdSearch.js
index 6e632d28..4d3b7918 100644
--- a/src/pages/reports/collectionIdSearch.js
+++ b/src/pages/reports/collectionIdSearch.js
@@ -62,7 +62,7 @@ const searchSpecimenEvent = () => {
const biospecimen = await searchSpecimen(masterSpecimenId, true);
if (biospecimen.code !== 200 || Object.keys(biospecimen.data).length === 0) {
hideAnimation();
- showNotifications({ title: 'Not found', body: 'Specimen not found!' }, true)
+ showNotifications({ title: 'Not found', body: 'Specimen not found!' })
return
}
const biospecimenData = biospecimen.data;
@@ -75,7 +75,7 @@ const searchSpecimenEvent = () => {
finalizeTemplate(data, biospecimenData, true);
}
catch {
- showNotifications({ title: 'Not found', body: 'Participant not found!' }, true)
+ showNotifications({ title: 'Not found', body: 'Participant not found!' })
}
})
}
\ No newline at end of file
diff --git a/src/pages/reports/reportsNavbar.js b/src/pages/reports/reportsNavbar.js
index cfdcd756..23bb63d1 100644
--- a/src/pages/reports/reportsNavbar.js
+++ b/src/pages/reports/reportsNavbar.js
@@ -6,10 +6,13 @@ export const reportsNavbar = () => {
Home
- Reports
+ Reports
- Collection ID Search
+ Collection ID Search
+
+
+ Shipping Report
`;
diff --git a/src/pages/reports/shippingReport.js b/src/pages/reports/shippingReport.js
new file mode 100644
index 00000000..7828f341
--- /dev/null
+++ b/src/pages/reports/shippingReport.js
@@ -0,0 +1,29 @@
+import { reportsNavbar } from "./reportsNavbar.js";
+import { nonUserNavBar } from "../../navbar.js";
+import { activeReportsNavbar } from "./activeReportsNavbar.js";
+import { appState } from '../../shared.js';
+import { startReport } from "../reportsQuery.js";
+
+export const bptlShipReportsScreen = async (auth, route) => {
+ const user = auth.currentUser;
+ if (!user) return;
+ const username = user.displayName || user.email;
+ appState.setState({ username });
+ bptlShipReportsScreenTemplate(username);
+};
+
+export const bptlShipReportsScreenTemplate = async (username) => {
+ const template = ` ${reportsNavbar()}
+
+
Shipping Report Screen
+
+ ${startReport('bptlShippingReport')}
+
+
+ `;
+
+ document.getElementById("contentBody").innerHTML = template;
+ document.getElementById("navbarNavAltMarkup").innerHTML = nonUserNavBar(username);
+ activeReportsNavbar();
+};
+
diff --git a/src/pages/reportsQuery.js b/src/pages/reportsQuery.js
index 5f5e7569..98f37077 100644
--- a/src/pages/reportsQuery.js
+++ b/src/pages/reportsQuery.js
@@ -1,6 +1,7 @@
import { userAuthorization, removeActiveClass, restrictNonBiospecimenUser, hideAnimation, showAnimation, getNumPages, conceptIdToSiteSpecificLocation, searchSpecimenInstitute } from "./../shared.js";
import { populateBoxTable, populateReportManifestHeader, populateReportManifestTable, addPaginationFunctionality, addEventFilter } from "./../events.js";
import { homeNavBar, reportSideNavBar } from '../navbar.js';
+import { reportsNavbar } from "./reports/reportsNavbar.js";
import conceptIds from '../fieldToConceptIdMapping.js';
export const reportsQuery = (auth, route) => {
@@ -20,17 +21,21 @@ export const reportsQuery = (auth, route) => {
});
};
-export const startReport = async () => {
+export const startReport = async (source) => {
showAnimation();
- if (document.getElementById('navBarParticipantCheckIn')) document.getElementById('navBarParticipantCheckIn').classList.add('disabled');
-
+ if (document.getElementById('navBarParticipantCheckIn') && source !== `bptlShippingReport`) document.getElementById('navBarParticipantCheckIn').classList.add('disabled')
let template = `
-
-
-
-
Reports
- ${reportSideNavBar()}
-
+ ${ source !== `bptlShippingReport` ? `
+
+
+
+
Reports
+ ${reportSideNavBar()}
+ ` :
+ `${reportsNavbar()}
+
+
Shipping Report Screen
`
+ }
@@ -65,13 +71,14 @@ export const startReport = async () => {
let numPages = await getNumPages(5, {});
document.getElementById('contentBody').innerHTML = template;
removeActiveClass('navbar-btn', 'active');
- addEventFilter();
- populateBoxTable(0, {});
- addPaginationFunctionality(numPages, {});
+ addEventFilter(source);
+ populateBoxTable(0, {}, source);
+ addPaginationFunctionality(numPages, {}, source);
hideAnimation();
+ clearEventFilter(source);
};
-export const showReportsManifest = async (currPage) => {
+export const showReportsManifest = async (currPage, source) => {
showAnimation();
const searchSpecimenInstituteResponse = await searchSpecimenInstitute();
const searchSpecimenInstituteArray = searchSpecimenInstituteResponse?.data ?? [];
@@ -116,8 +123,16 @@ export const showReportsManifest = async (currPage) => {
window.print();
});
document.getElementById('returnToReports').addEventListener('click', e => {
- startReport();
+ startReport(source);
});
hideAnimation();
};
+
+const clearEventFilter = (source) => {
+
+ let clearFilterButton = document.getElementById('clearFilter');
+ clearFilterButton.addEventListener('click', async () => {
+ startReport(source);
+ });
+}
\ No newline at end of file
diff --git a/src/pages/shipping.js b/src/pages/shipping.js
index 5426a134..6213b700 100644
--- a/src/pages/shipping.js
+++ b/src/pages/shipping.js
@@ -1,4 +1,4 @@
-import { addBox, appState, conceptIdToSiteSpecificLocation, displayContactInformation, getAllBoxes, getBoxes, getLocationsInstitute, hideAnimation, locationConceptIDToLocationMap,
+import { addBoxAndUpdateSiteDetails, appState, conceptIdToSiteSpecificLocation, displayContactInformation, getAllBoxes, getBoxes, getLocationsInstitute, getSiteMostRecentBoxId, hideAnimation, locationConceptIDToLocationMap,
removeActiveClass, removeBag, removeMissingSpecimen, showAnimation, showNotifications, siteSpecificLocation, siteSpecificLocationToConceptId, sortBiospecimensList,
translateNumToType, userAuthorization } from "../shared.js"
import { addDeviationTypeCommentsContent, addEventAddSpecimenToBox, addEventBackToSearch, addEventBoxSelectListChanged, addEventCheckValidTrackInputs,
@@ -314,87 +314,119 @@ const handleRemoveBagButton = (currDeleteButton, currTubes, currBoxId) => {
});
}
-// Calculate the highest existing boxId and ++ for the new box.
+// Get the highest existing boxId and ++ for the new box.
// Create the box and add it to firestore. On success, add it to the relevant state objects (allBoxesList and boxesByLocationList, and detailedProviderBoxes).
-export const addNewBox = async () => {
- const siteLocation = document.getElementById('selectLocationList').value;
- const siteLocationConversion = siteSpecificLocationToConceptId[siteLocation];
- const siteCode = siteSpecificLocation[siteLocation]["siteCode"];
+// Important: 0 is a valid box number: only check for null and undefined boxId values, not falsy values.
+// Whether to create a new box is location specific (not site specific). Check whether location's most recent box is empty or populated.
+// Box numbering is based on site (not location), always increment highest site box number.
+// Create the new box and update the modal if the location's largest box is not empty or if the location has no current boxes.
+export const addNewBox = async () => {
+ try {
+ const siteLocation = document.getElementById('selectLocationList').value;
+ const siteLocationConversion = siteSpecificLocationToConceptId[siteLocation];
+ const siteCode = siteSpecificLocation[siteLocation]["siteCode"];
+ const boxList = appState.getState().allBoxesList;
+
+ const boxIdResponse = await getSiteMostRecentBoxId();
+ let docId = boxIdResponse.data.docId;
+ let largestBoxNum = boxIdResponse.data.mostRecentBoxId;
- const boxList = appState.getState().allBoxesList;
+ if (!docId) {
+ console.error('Error getting site details doc id');
+ return false;
+ }
- const { largestBoxIndex, largestBoxIndexAtLocation } = findLargestBoxData(boxList, siteLocation);
- const shouldUpdateBoxModal = largestBoxIndexAtLocation !== -1 && Object.keys(boxList[largestBoxIndexAtLocation]['bags']).length !== 0;
+ if (largestBoxNum == null) {
+ largestBoxNum = await getLargestBoxNumFromAllBoxes();
+ }
+
+ const largestLocationBoxNum = largestBoxNum === -1 ? -1 : getLargestLocationBoxId(boxList, siteLocationConversion);
+ const largestLocationBoxIndex = boxList.findIndex(box => box[conceptIds.shippingBoxId] === 'Box' + largestLocationBoxNum.toString());
+ const shouldCreateNewBox = Object.keys(boxList[largestLocationBoxIndex]?.['bags'] ?? {}).length !== 0 || largestLocationBoxIndex === -1;
+
+ if (shouldCreateNewBox) {
+ const boxToAdd = await createNewBox(boxList, siteLocationConversion, siteCode, largestBoxNum, docId);
+ if (!boxToAdd) {
+ showNotifications({ title: 'ERROR ADDING BOX - PLEASE REFRESH YOUR BROWSER', body: 'Error: This box already exists. A member of your team may have recently created this box. Please refresh your browser and try again.' });
+ return false;
+ }
- let largestBoxId;
- if (shouldUpdateBoxModal) largestBoxId = boxList[largestBoxIndex][conceptIds.shippingBoxId];
- else largestBoxId = largestBoxIndex !== -1 ? boxList[largestBoxIndex][conceptIds.shippingBoxId] : 'Box0';
-
- if (largestBoxIndexAtLocation == -1 || shouldUpdateBoxModal) {
- const boxToAdd = await createNewBox(boxList, siteLocationConversion, siteCode, largestBoxId, shouldUpdateBoxModal);
- if (!boxToAdd) {
- showNotifications({ title: 'ERROR ADDING BOX - PLEASE REFRESH YOUR BROWSER', body: 'Error: This box already exists. A member of your team may have recently created this box. Please refresh your browser and try again.' });
+ document.getElementById('shippingModalChooseBox').setAttribute('data-new-box', boxToAdd[conceptIds.shippingBoxId]);
+ updateShippingStateCreateBox(boxToAdd);
+ return true;
+ } else {
return false;
}
-
- updateShippingStateCreateBox(boxToAdd);
- return true;
- } else {
+ } catch (e) {
+ console.error('Error adding box', e);
+ showNotifications({
+ title: 'ERROR ADDING BOX',
+ body: 'An unexpected error occurred. Please try again later.'
+ });
return false;
}
}
-const createNewBox = async (boxList, pageLocationConversion, siteCode, largestBoxId, updateBoxModal) => {
- const newBoxNum = parseInt(largestBoxId.substring(3)) + 1;
- const newBoxId = 'Box' + newBoxNum.toString();
+// Create the new box and add it to firestore. If the box already exists, wait one second, increment the boxId, and try again up to 3 times.
+const createNewBox = async (boxList, pageLocationConversion, siteCode, largestBoxNum, docId) => {
+ let attempts = 0;
+ let maxAttempts = 3;
+
const boxToAdd = {
- 'bags': {},
- [conceptIds.shippingBoxId]: newBoxId,
[conceptIds.shippingLocation]: pageLocationConversion,
[conceptIds.siteCode]: siteCode,
[conceptIds.submitShipmentFlag]: conceptIds.no,
- [conceptIds.siteShipmentReceived]: conceptIds.no
+ [conceptIds.siteShipmentReceived]: conceptIds.no,
+ ['siteDetailsDocRef']: docId,
};
- try {
- const addBoxResponse = await addBox(boxToAdd);
- if (addBoxResponse.message !== 'Success!') {
+ while (attempts < maxAttempts) {
+ largestBoxNum++;
+ boxToAdd[conceptIds.shippingBoxId] = 'Box' + largestBoxNum.toString();
+
+ try {
+ const addBoxResponse = await addBoxAndUpdateSiteDetails(boxToAdd);
+ if (addBoxResponse.code === 200) {
+ boxList.push(boxToAdd);
+ return boxToAdd;
+ } else if (addBoxResponse.code === 409) {
+ attempts++;
+ await delayRetryAttempt(1000);
+ continue;
+ } else {
+ return null;
+ }
+ } catch (e) {
+ console.error('Error adding box', e);
return null;
}
- } catch (e) {
- console.error('Error adding box', e);
- return null;
}
-
- boxList.push(boxToAdd);
- if (updateBoxModal) document.getElementById('shippingModalChooseBox').setAttribute('data-new-box', newBoxId);
- return boxToAdd;
+ console.error('409 - Conflict! 3 Failed attempts creating new box.');
+ return null;
}
-// Find the largest box among all boxes and the largest box at the specified location.
-const findLargestBoxData = (boxList, siteLocation) => {
- let largestBoxId = 0;
- let largestBoxIndex = -1;
- let largestLocationBoxId = 0;
- let largestBoxIndexAtLocation = -1;
+// Delay retry attempt for 1 second when box creation fails.
+const delayRetryAttempt = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
- for (let i = 0; i < boxList.length; i++) {
- const currBoxNum = parseInt(boxList[i][conceptIds.shippingBoxId].substring(3));
- const currLocation = conceptIdToSiteSpecificLocation[boxList[i][conceptIds.shippingLocation]];
-
- if (currBoxNum > largestBoxId) {
- largestBoxId = currBoxNum;
- largestBoxIndex = i;
- }
+// Find the largest box among all boxes. This is a fallback for new sites that have no boxes.
+// It should only execute once per new site, and only if the siteDetails collection's 'mostRecentBoxId' field is null.
+// -1 fallback value is handled in the parent function.
+const getLargestBoxNumFromAllBoxes = async () => {
+ const getAllBoxesResponse = await getAllBoxes();
+ const boxList = getAllBoxesResponse.data;
- if (currLocation == siteLocation && currBoxNum > largestLocationBoxId) {
- largestLocationBoxId = currBoxNum;
- largestBoxIndexAtLocation = i;
- }
- }
+ return boxList.reduce((largestBoxNum, currentBox) => {
+ const currentBoxNum = parseInt(currentBox[conceptIds.shippingBoxId].substring(3));
+ return Math.max(largestBoxNum, currentBoxNum);
+ }, -1);
+}
- return { largestBoxIndex, largestBoxIndexAtLocation };
+// Find the largest shipping box id for the location
+// Return the highest numeric boxId or -1 if none exist
+const getLargestLocationBoxId = (boxesList, siteLocationId) => {
+ const boxIdsForLocation = boxesList.filter(box => box[conceptIds.shippingLocation] === siteLocationId).map(box => parseInt(box[conceptIds.shippingBoxId].substring(3)));
+ return boxIdsForLocation.length > 0 ? Math.max(...boxIdsForLocation) : -1;
}
export const generateBoxManifest = (currBox) => {
@@ -530,7 +562,7 @@ export const createShippingModalBody = (biospecimensList, masterBiospecimenId, i
populateModalSelect(boxIdAndBagsObj);
if (isBagEmpty) {
- showNotifications({ title: 'Not found', body: 'The participant with entered search criteria not found!' }, true);
+ showNotifications({ title: 'Not found', body: 'The participant with entered search criteria not found!' });
document.getElementById('shippingCloseButton').click();
hideAnimation();
}
@@ -768,7 +800,7 @@ export const generateShippingManifest = async (boxIdArray, userName, isTempMonit
e.stopPropagation();
const tempBoxElement = document.getElementById('tempBox');
if (isTempMonitorIncluded && tempBoxElement.value === '') {
- showNotifications({title: 'Missing field!', body: 'Please enter the box where the temperature monitor is being stored.'}, true);
+ showNotifications({title: 'Missing field!', body: 'Please enter the box where the temperature monitor is being stored.'});
return;
}
@@ -1104,7 +1136,7 @@ const renderSpecimenVerificationModal = () => {
Select Box or Create New Box
New box has been created
-
Please add a specimen or specimens to last box
+
Last created box is empty. Please add a specimen(s) to last box.
diff --git a/src/pages/welcome.js b/src/pages/welcome.js
index 76f30039..bb739079 100644
--- a/src/pages/welcome.js
+++ b/src/pages/welcome.js
@@ -21,12 +21,16 @@ export const welcomeScreen = async (auth, route) => {
}
const clinicalOnlySiteArray = ['KPNW', 'KPCO', 'KPHI', 'KPGA'];
-const researchOnlySiteArray = ['MFC', 'UCM', 'HP', 'SFH'];
+const researchOnlySiteArray = ['MFC', 'UCM', 'SFH'];
const welcomeScreenTemplate = (name, data, auth, route) => {
let template = '';
let dashboardSelectionStr = '';
+ if (location.host === urls.stage || location.host === urls.prod) {
+ researchOnlySiteArray.push('HP')
+ }
+
if (clinicalOnlySiteArray.includes(data.siteAcronym)) {
dashboardSelectionStr = `