diff --git a/newsletter/aprilnewsletter.html b/newsletter/aprilnewsletter.html new file mode 100644 index 00000000..636f3e0a --- /dev/null +++ b/newsletter/aprilnewsletter.html @@ -0,0 +1,235 @@ + + + + + + + + + April Newsletter 2024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+

View in browser +

+
+ + + + + +
+ + +

April 2024

+
+
+
+
+ + + + +
+

+
+
+

What's New with Connect

+
+ + +
+

Senior Scientist Mia Gaudet shares important announcements including activities participants should expect throughout the rest of the year.

+
+ + + + +
+ Read more +
+
+ + + + +
+ + + + + +
+ + + + +
+

Aleah Thomas is a research fellow at the NCI helping the Connect team engage populations that are underrepresented in research.

+

Through her work with Connect, Aleah Thomas hopes to help shape the future of cancer prevention for all people, with a special emphasis on those who are clinically underserved. +
Read more

+
+
+ + + + + +
+ + + + +
+ +
+
+ +
+
+

+
+ + + + +
+ + + + + +
+ + + + +
+

Did You Know?

+

The overall cancer death rate is declining in the U.S. However, certain groups continue to be at + greater risk of developing or dying from some cancers. Connect aims to help change that. +
Read more +

+
+
+ + + + +
+ + + + +
+ +
+
+
+
+

We want to hear from you! Which + topics would you like to see covered in future newsletters?
Are you interested in sharing why you joined Connect?
Send your feedback to ConnectSupport@norc.org +

+
+ + + + +
+

+
+
+ + + + +
+

Connect for Cancer Prevention Study

+

+ National Cancer Institute | National Institutes of Health | + U.S. Department of Health and Human Services | USA.gov

+
+ + + + +
+

Connect for Cancer Prevention Study, the Connect for Cancer Prevention Study logo, and “Connect today. Prevent cancer tomorrow.” + are trademarks of the U.S. Department of Health and Human Services (HHS).®

+
+
+ + \ No newline at end of file diff --git a/siteManagerDashboard/assets/images/banner202404.png b/siteManagerDashboard/assets/images/banner202404.png new file mode 100644 index 00000000..461f2a16 Binary files /dev/null and b/siteManagerDashboard/assets/images/banner202404.png differ diff --git a/siteManagerDashboard/assets/images/didyouknow202404.png b/siteManagerDashboard/assets/images/didyouknow202404.png new file mode 100644 index 00000000..f43703e0 Binary files /dev/null and b/siteManagerDashboard/assets/images/didyouknow202404.png differ diff --git a/siteManagerDashboard/assets/images/headshotimg202404.jpeg b/siteManagerDashboard/assets/images/headshotimg202404.jpeg new file mode 100644 index 00000000..204d39a0 Binary files /dev/null and b/siteManagerDashboard/assets/images/headshotimg202404.jpeg differ diff --git a/siteManagerDashboard/dataCorrectionsTool.js b/siteManagerDashboard/dataCorrectionsTool.js index 3d9c7085..6a2f323e 100644 --- a/siteManagerDashboard/dataCorrectionsTool.js +++ b/siteManagerDashboard/dataCorrectionsTool.js @@ -248,9 +248,9 @@ const clickHandler = async (selectedOptions) => { if (response.status === 200) { const query = `token=${selectedOptions.token}`; - const reloadedParticpant = await findParticipant(query); - reloadVerificationToolPage(reloadedParticpant.data[0], 'Correction(s) updated.', 'success'); - localStorage.setItem("participant", JSON.stringify(reloadedParticpant.data[0])); + const reloadedParticipant = await findParticipant(query); + reloadVerificationToolPage(reloadedParticipant.data[0], 'Correction(s) updated.', 'success'); + localStorage.setItem("participant", JSON.stringify(reloadedParticipant.data[0])); } else { triggerNotificationBanner('Error: No corrections were made.', 'warning') diff --git a/siteManagerDashboard/fieldToConceptIdMapping.js b/siteManagerDashboard/fieldToConceptIdMapping.js index 0679d13b..050bedb7 100644 --- a/siteManagerDashboard/fieldToConceptIdMapping.js +++ b/siteManagerDashboard/fieldToConceptIdMapping.js @@ -126,6 +126,7 @@ export default "covidCompletedDate": 784810139, // "ssn": "D_716117818", + "ssnStatusFlag": 126331570, "ssnFullflag": 311580100, "ssnFulldate": 454067894, @@ -372,6 +373,7 @@ export default "requestedDataDestroySigned": 704529432, "dataHasBeenDestroyed": 861639549, "deceased": 618686157, + "dataDestroyed": 884452262, 'dateWithdrewConsentRequested': 659990606, 'dateDataDestroyRequested': 269050420, diff --git a/siteManagerDashboard/forms/Consent/KPGA_consent_V0.04.pdf b/siteManagerDashboard/forms/Consent/KPGA_consent_V0.04.pdf new file mode 100644 index 00000000..b4a7fc1e Binary files /dev/null and b/siteManagerDashboard/forms/Consent/KPGA_consent_V0.04.pdf differ diff --git a/siteManagerDashboard/forms/HIPAA/KPGA_HIPAA_V0.03.pdf b/siteManagerDashboard/forms/HIPAA/KPGA_HIPAA_V0.03.pdf new file mode 100644 index 00000000..879b63fe Binary files /dev/null and b/siteManagerDashboard/forms/HIPAA/KPGA_HIPAA_V0.03.pdf differ diff --git a/siteManagerDashboard/index.js b/siteManagerDashboard/index.js index aa4fe5cc..582c4466 100644 --- a/siteManagerDashboard/index.js +++ b/siteManagerDashboard/index.js @@ -7,7 +7,7 @@ import { renderParticipantMessages } from './participantMessages.js'; import { renderDataCorrectionsToolPage } from './dataCorrectionsTool.js'; import { renderSiteMessages } from './siteMessages.js'; import { renderParticipantWithdrawal } from './participantWithdrawal.js'; -import { renderStoreNotificationSchema, editSchema } from './notifications/storeNotifications.js'; +import { createNotificationSchema, editNotificationSchema } from './notifications/storeNotifications.js'; import { renderRetrieveNotificationSchema, showDraftSchemas } from './notifications/retrieveNotifications.js'; import { internalNavigatorHandler, getIdToken, userLoggedIn, baseAPI, urls } from './utils.js'; import fieldMapping from './fieldToConceptIdMapping.js'; @@ -52,7 +52,7 @@ window.onload = async () => { else { !firebase.apps.length ? firebase.initializeApp(devFirebaseConfig) : firebase.app(); !isLocalDev && window.DD_RUM && window.DD_RUM.init({ ...datadogConfig, env: 'dev' }); - } + } !isLocalDev && window.DD_RUM && window.DD_RUM.startSessionReplayRecording(); @@ -138,9 +138,9 @@ const router = async () => { renderParticipantWithdrawal(participant); } } - else if (route === '#notifications/createnotificationschema') renderStoreNotificationSchema(); + else if (route === '#notifications/createnotificationschema') createNotificationSchema(); else if (route === '#notifications/retrievenotificationschema') renderRetrieveNotificationSchema(); - else if (route === '#notifications/editSchema') editSchema(); + else if (route === '#notifications/editSchema') editNotificationSchema(); else if (route === '#notifications/showDraftSchemas') showDraftSchemas(); else if (route === '#logout') clearLocalStorage(); else window.location.hash = '#home'; diff --git a/siteManagerDashboard/notifications/retrieveNotifications.js b/siteManagerDashboard/notifications/retrieveNotifications.js index f0bc3f68..007237c4 100644 --- a/siteManagerDashboard/notifications/retrieveNotifications.js +++ b/siteManagerDashboard/notifications/retrieveNotifications.js @@ -1,6 +1,6 @@ import { dashboardNavBarLinks, removeActiveClass } from '../navigationBar.js'; import { getIdToken, showAnimation, hideAnimation, baseAPI } from '../utils.js'; -import { mapSchemaNotificaiton, addEventMoreCondition, getConcepts, conceptDropdown } from './storeNotifications.js'; +import { getSchemaHtmlStr, handleEmailPreview } from './storeNotifications.js'; import { appState } from '../stateManager.js'; export const renderRetrieveNotificationSchema = async (showDrafts = false) => { @@ -11,12 +11,11 @@ export const renderRetrieveNotificationSchema = async (showDrafts = false) => { notificationsAnchor && notificationsAnchor.classList.add("active"); showAnimation(); const idToken = await getIdToken(); - const response = await getNotificationSchema("all", idToken, showDrafts); + const response = await getNotificationSchemas("all", idToken, showDrafts); const schemaArray = response.data || []; document.getElementById("mainContent").innerHTML = render(schemaArray, showDrafts); const categoryArray = getNotificationSchemaCategories(schemaArray); - const concepts = await getConcepts(); - triggerSchemaEdit(categoryArray, "Filter by Category", concepts); + triggerSchemaEdit(categoryArray, "Filter by Category"); hideAnimation(); appState.setState({ notification: { showDrafts, schemaArray } }); }; @@ -25,9 +24,9 @@ export const showDraftSchemas = async () => { await renderRetrieveNotificationSchema(true); }; -const triggerSchemaEdit = (categoryArray, categoryName, concepts) => { - viewNotificationSchema(concepts); - editNotificationSchema(); +const triggerSchemaEdit = (categoryArray, categoryName) => { + handleViewNotificationSchema(); + handleEditNotificationSchema(); renderCategorydDropdown(categoryArray); triggerCategories(categoryArray, categoryName); }; @@ -59,7 +58,7 @@ const render = (schemaArray, showDrafts) => { `; }; -const getNotificationSchema = async (category, idToken, showDrafts) => { +const getNotificationSchemas = async (category, idToken, showDrafts) => { const catgStr = category !== undefined ? category : `all`; let apiStr = `${baseAPI}/dashboard?api=retrieveNotificationSchema&category=${catgStr}`; if (showDrafts) { @@ -100,113 +99,25 @@ const renderNotificationCards = (schemaArray) => { return template; }; -const viewNotificationSchema = (concepts) => { - const rows = Array.from(document.getElementsByClassName('detailedRow')); - if (rows.length > 0) { - rows.forEach(element => { - const viewButton = element.getElementsByClassName('viewSchema')[0]; - viewButton.addEventListener('click', () => { - const schema = appState.getState().notification.schemaArray[viewButton.dataset.schemaIdx]; - const header = document.getElementById('modalHeader'); - const body = document.getElementById('modalBody'); - header.innerHTML = `
View Schema
` - - let template = '
' - template += ` -
- - -
- -
- - -
- -
- - -
- -
- -   -   -   -
- -
-
-
- -
-
- -
- - -
-
-
-
- -
- -
- - -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- - - - -
-
` - - body.innerHTML = template; - addEventMoreCondition(concepts, true); - conceptDropdown(concepts, 'condition-key'); - conceptDropdown(concepts, 'condition-value'); - mapSchemaNotificaiton(schema, concepts, true); - document.getElementById('addConditions').disabled = true; - }) - }) - } -} +const handleViewNotificationSchema = () => { + const rows = Array.from(document.getElementsByClassName("detailedRow")); + if (rows.length > 0) { + rows.forEach((element) => { + const viewButton = element.getElementsByClassName("viewSchema")[0]; + viewButton && viewButton.addEventListener("click", () => { + const schemaData = appState.getState().notification.schemaArray[viewButton.dataset.schemaIdx]; + const header = document.getElementById("modalHeader"); + const body = document.getElementById("modalBody"); + header.innerHTML = `
View Schema
`; + + body.innerHTML = `
${getSchemaHtmlStr(schemaData, true)}
`; + handleEmailPreview(); + }); + }); + } +}; -const editNotificationSchema = () => { +const handleEditNotificationSchema = () => { const rows = Array.from(document.getElementsByClassName("detailedRow")); if (rows.length > 0) { rows.forEach((element) => { @@ -252,7 +163,6 @@ const renderCategorydDropdown = (categoriesHolder) => { }) } - const triggerCategories = (originalCategoriesHolder, categoryName) => { let a = document.getElementById('dropdownCategories'); let dropdownMenuButton = document.getElementById('dropdownMenuButtonCategories'); @@ -263,7 +173,7 @@ const triggerCategories = (originalCategoriesHolder, categoryName) => { a.innerHTML = e.target.textContent; const idToken = await getIdToken(); const showDrafts = appState.getState().notification?.showDrafts; - const response = await getNotificationSchema(e.target.textContent, idToken, showDrafts); + const response = await getNotificationSchemas(e.target.textContent, idToken, showDrafts); appState.setState({ notification: { showDrafts, schemaArray: response.data } }); document.getElementById("mainContent").innerHTML = render(response.data, showDrafts); triggerSchemaEdit(originalCategoriesHolder, e.target.textContent); diff --git a/siteManagerDashboard/notifications/storeNotifications.js b/siteManagerDashboard/notifications/storeNotifications.js index 6fdda92c..7e8f6ae0 100644 --- a/siteManagerDashboard/notifications/storeNotifications.js +++ b/siteManagerDashboard/notifications/storeNotifications.js @@ -2,7 +2,11 @@ import { dashboardNavBarLinks, removeActiveClass } from '../navigationBar.js'; import { showAnimation, hideAnimation, baseAPI, getIdToken, triggerNotificationBanner } from '../utils.js'; import { appState } from '../stateManager.js'; -export const editSchema = async () => { +const newsletterCategories = ["newsletter", "eNewsletter", "anniversaryNewsletter"]; +let conceptsOptionsStr = ""; +let concepts = null; + +export const editNotificationSchema = async () => { const notificationData = appState.getState().notification || {}; if (!notificationData.isEditing) { const createSchemaRoute = "#notifications/createnotificationschema"; @@ -10,261 +14,207 @@ export const editSchema = async () => { return; } - const concepts = await initializePage(); - mapSchemaNotificaiton(notificationData.savedSchema, concepts, true); + await renderSchemaPage(notificationData.savedSchema); }; -export const renderStoreNotificationSchema = async () => { +export const createNotificationSchema = async () => { appState.setState({ notification: { } }); - await initializePage(); + await renderSchemaPage(); }; -export const initializePage = async () => { +const renderSchemaPage = async (schemaData = null) => { const isParent = localStorage.getItem("isParent"); document.getElementById("navBarLinks").innerHTML = dashboardNavBarLinks(isParent); removeActiveClass("nav-link", "active"); document.getElementById("notifications").classList.add("active"); - mainContent.innerHTML = render(); - localStorage.setItem("emailCheck", false); - localStorage.setItem("smsCheck", false); - localStorage.setItem("pushNotificationCheck", false); - const concepts = await getConcepts(); - init(concepts); - - return concepts; -}; -const init = (concepts) => { - addEventMoreCondition(concepts); - conceptDropdown(concepts, 'condition-key'); - conceptDropdown(concepts, 'condition-value'); - conceptDropdown(concepts, 'email-concept'); - conceptDropdown(concepts, 'first-name-concept'); - conceptDropdown(concepts, 'preferred-name-concept'); - conceptDropdown(concepts, 'primary-field'); - conceptDropdown(concepts, 'phone-concept'); - addEventNotificationCheckbox(); - formSubmit(); - clearNotificationSchemaForm(); -}; + if (!concepts) { + concepts = await getConcepts(); + if (concepts) { + for (const key in concepts) { + conceptsOptionsStr += ``; + } + } + } -const render = () => { - const isEditing = appState.getState().notification?.isEditing; - const titleStr = isEditing ? "Edit Notification Schema" : "Create Notification Schema"; - let template = ` -
-
-
-
-

${titleStr}

-
-
- - -
- -
- - -
- -
- - -
- -
- -   -   -   -
- -
- -
- - -
-
- - -
-
-
-
-
-
-
- -
- - -
-
-
-
- -
- -
- - -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- - - - -
- -
- - - -
-
-
-
`; + const isEditing = appState.getState().notification?.isEditing; + const titleStr = isEditing ? "Edit Notification Schema" : "Create Notification Schema"; + + mainContent.innerHTML = ` +
+
+
+
+

${titleStr}

+
+ ${getSchemaHtmlStr(schemaData)} +
+ + + +
+ ${schemaData?.id ? getDryRunHtlmStr() : ""} +
+
+
`; - return template; + handleEmailPreview(); + handleDeleteExistingConditions(); + handleAddCondition(); + handleNotficationDivs(schemaData); + handleSMSCharacterCount(); + handleFormSubmit(); + handleExitForm(); + handleDryRun(); }; -export const mapSchemaNotificaiton = (updateSchemaNotification, concepts, flag) => { - document.getElementById("attempt").value = updateSchemaNotification.attempt; - document.getElementById("description").value = updateSchemaNotification.description; - document.getElementById("category").value = updateSchemaNotification.category; - const titleElement = document.getElementById("getCurrentTitle"); - if (titleElement) titleElement.innerText = "Edit Notification Schema"; - - (updateSchemaNotification.notificationType).forEach(i => { - if (i === "email") { - document.getElementById('emailCheckBox').checked = true - renderDivs("email", flag); - document.getElementById('emailSubject').value = updateSchemaNotification.email.subject - document.getElementById('emailBody').value = updateSchemaNotification.email.body - localStorage.setItem("emailCheck", true); - } - if (i === "sms") { - document.getElementById('smsCheckBox').checked = true; - renderDivs("sms", flag); - document.getElementById('smsBody').value = updateSchemaNotification.sms.body; - document.getElementById('characterCounts').innerText = `${updateSchemaNotification.sms.body.length}/160 characters`; - localStorage.setItem("smsCheck", true); - } - if (i === "push") { - document.getElementById('pushCheckBox').checked = true - renderDivs("push", flag); - document.getElementById('pushSubject').value = updateSchemaNotification.push.subject - document.getElementById('pushBody').value = updateSchemaNotification.push.body - localStorage.setItem("pushNotificationCheck", true); - } - }) - - const size = Object.keys(updateSchemaNotification.conditions).length; - let counter = 0; - const conditions = updateSchemaNotification.conditions; - for (let i in updateSchemaNotification.conditions) { - if (counter <= (size-1)) { - document.getElementById(`conditionkey${counter}`).value = i; - document.getElementById(`operatorkey${counter}`).value = getOperatorResponse(conditions[i]); - - if((conditions).hasOwnProperty(i)) { - - let storedValue = getConditionsResponse(conditions[i]); - document.getElementById(`conditionvalue${counter}`).value = storedValue; - - if(typeof storedValue == 'string') { - document.getElementById(`valuetype${counter}`).selectedIndex = 1; - } - } - - if(flag) { - document.getElementById(`conditionkey${counter}`).setAttribute('readonly', true); - document.getElementById(`operatorkey${counter}`).setAttribute('readonly', true); - document.getElementById(`valuetype${counter}`).setAttribute('readonly', true); - document.getElementById(`conditionvalue${counter}`).setAttribute('readonly', true); - } - - counter++; - if(counter != size) document.getElementById('addConditions').click(); - } +const getDryRunHtlmStr = () => ` +
+
+
+ +
+ +
`; + +export const getSchemaHtmlStr = (schemaData = null, isReadOnly = false) => { + let conditionHtmlStrAll = ""; + let index = 0; + if (schemaData) { + for (const [conditionKey, valObj] of Object.entries(schemaData.conditions)) { + const [conditionOperator, conditionValue] = Object.entries(valObj)[0]; + conditionHtmlStrAll += getConditionHtmlStr({ + index, + isReadOnly, + conditionKey, + conditionOperator, + conditionValue, + }); + index++; } + } else { + conditionHtmlStrAll = getConditionHtmlStr({ index, isReadOnly }); + } - - conceptDropdown(concepts, 'email-concept'); - const emailconcept = document.getElementById('emailconcept0'); - emailconcept.value = updateSchemaNotification.emailField; - - conceptDropdown(concepts, 'first-name-concept'); - const firstname = document.getElementById("firstnameconcept0"); - if (firstname) {firstname.value = updateSchemaNotification.firstNameField} - - conceptDropdown(concepts, 'preferred-name-concept'); - const preferredname = document.getElementById('preferrednameconcept0'); - if (updateSchemaNotification.preferredNameField && preferredname) { preferredname.value = updateSchemaNotification.preferredNameField; } - - - conceptDropdown(concepts, 'phone-concept'); - const phoneconcept = document.getElementById('phoneconcept0') - if (phoneconcept) {phoneconcept.value = updateSchemaNotification.phoneField} + return ` +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +   + +   + +   +
- conceptDropdown(concepts, 'primary-field'); - const primaryfield = document.getElementById('primaryfield0'); - if (primaryfield) {primaryfield.value = updateSchemaNotification.primaryField} - Array.from(document.getElementsByName('scheduleAt')).forEach(dt => { - if(dt.value === updateSchemaNotification.scheduleAt) dt.checked = true; - }); - document.getElementById('days').value = updateSchemaNotification.time['day']; - document.getElementById('hours').value = updateSchemaNotification.time['hour']; - document.getElementById('minutes').value = updateSchemaNotification.time['minute']; +
+ +
+ + +
+
+ + +
+
+
${schemaData?.email?.subject ? getEmailDivHtml(schemaData) : "" }
+
${schemaData?.sms?.body ? getSmsDivHtml(schemaData) : "" }
+
${schemaData?.push?.subject ? getPushDivHtml(schemaData) : "" }
+
+ ${conditionHtmlStrAll} +
+
+ +
+ +
+ +
+ + + ${conceptsOptionsStr} + +
+
+ +
+ +
+ + + ${conceptsOptionsStr} + +
+
+ +
+ +
+ + + ${conceptsOptionsStr} + +
+
+ +
+ +
+ + + ${conceptsOptionsStr} + +
+
+ +
+ +
+ + + ${conceptsOptionsStr} + +
+
+ +
+ + + + +
`; }; - -const formSubmit = () => { +const handleFormSubmit = () => { const form = document.getElementById("configForm"); form.addEventListener("submit", async (e) => { e.preventDefault(); let schema = {}; + schema.id = appState.getState().notification?.savedSchema?.id ?? ""; + const hasSchemaId = schema.id.length > 0; schema.isDraft = e.submitter.dataset.draft === "true"; schema["attempt"] = document.getElementById("attempt").value.trim(); schema["description"] = document.getElementById("description").value.trim(); @@ -272,15 +222,17 @@ const formSubmit = () => { schema["notificationType"] = Array.from(document.getElementsByName("notification-checkbox")) .filter((checkbox) => checkbox.checked) .map((checkbox) => checkbox.dataset.type); - schema["emailField"] = document.getElementById("emailconcept0").value; - schema["firstNameField"] = document.getElementById("firstnameconcept0").value; schema["scheduleAt"] = Array.from(document.getElementsByName("scheduleAt")).filter((dt) => dt.checked)[0].value; - if (document.getElementById("preferrednameconcept0").value) { - schema["preferredNameField"] = document.getElementById("preferrednameconcept0").value; + + schema["emailField"] = document.getElementById("emailConceptId").value; + schema["phoneField"] = document.getElementById("phoneConceptId").value; + schema["firstNameField"] = document.getElementById("firstNameConceptId").value; + const preferredNameValue = document.getElementById("preferredNameConceptId").value; + if (preferredNameValue) { + schema["preferredNameField"] = preferredNameValue; } - schema["phoneField"] = document.getElementById("phoneconcept0").value; - schema["primaryField"] = document.getElementById("primaryfield0").value; + schema["primaryField"] = document.getElementById("primaryFieldConceptId").value; schema["time"] = { day: parseInt(document.getElementById("days").value), hour: parseInt(document.getElementById("hours").value), @@ -290,9 +242,11 @@ const formSubmit = () => { const emailSubjectEle = document.getElementById("emailSubject"); if (emailSubjectEle) { schema["email"] = { subject: emailSubjectEle.value }; - schema["category"] === "newsletter" - ? (schema["email"]["body"] = document.getElementById("emailBody").value) - : (schema["email"]["body"] = document.getElementById("emailBody").value.replace(/\n/g, "
")); + if (newsletterCategories.includes(schema["category"])) { + schema["email"]["body"] = document.getElementById("emailBody").value; + } else { + schema["email"]["body"] = document.getElementById("emailBody").value.replace(/\n/g, "
"); + } } const smsBodyEle = document.getElementById("smsBody"); @@ -318,231 +272,204 @@ const formSubmit = () => { } }); - await storeNotificationSchema(schema); + const currSchemaId = await storeNotificationSchema(schema); + if (!hasSchemaId && currSchemaId.length > 0) { + const form = document.getElementById("configForm"); + const wrapperDiv = document.createElement("div"); + wrapperDiv.innerHTML = getDryRunHtlmStr(); + form && form.append(...wrapperDiv.children); + handleDryRun(); + } }); }; -export const addEventMoreCondition = (concepts, isReadonly = false) => { - const btn = document.getElementById('addConditions'); - btn.addEventListener('click', () => { - const conditionNo = parseInt(btn.dataset.condition); - const conditionDiv = document.getElementById('conditionsDiv'); - const div = document.createElement('div'); - div.classList = ['row form-group']; - div.innerHTML = ` - -
${getDataListTemplate(concepts, `conditionkey${conditionNo}`, 'condition-key', isReadonly)}
- - -
${getDataListTemplate(concepts, `conditionvalue${conditionNo}`, 'condition-value', isReadonly)}
- `; - conditionDiv.appendChild(div); - btn.dataset.condition = conditionNo + 1; - }); +const handleAddCondition = () => { + const conditionDiv = document.getElementById("conditionsDiv"); + const btn = document.getElementById("addConditions"); + + btn && btn.addEventListener("click", () => { + const index = parseInt(btn.dataset.condition); + const wrapperDiv = document.createElement("div"); + wrapperDiv.innerHTML = getConditionHtmlStr({ index }); + conditionDiv.appendChild(wrapperDiv.firstElementChild); + conditionDiv.querySelector(`button[data-btn-idx="${index}"]`).addEventListener("click", deleteConditionListener); + btn.dataset.condition = index + 1; + }); +}; + +const handleDeleteExistingConditions = () => { + const conditionDiv = document.getElementById("conditionsDiv"); + const btns = conditionDiv.querySelectorAll("button[data-btn-idx]"); + btns.forEach((btn) => { + if (!btn.hasClickListener) { + btn.addEventListener("click", deleteConditionListener); + btn.hasClickListener = true; + } + }); }; -export const getConcepts = async () => { - return await (await fetch('https://raw.githubusercontent.com/episphere/conceptGithubActions/master/jsons/varToConcept.json')).json() -} +const getConditionHtmlStr = ({ + index = 0, + isReadOnly = false, + conditionKey = null, + conditionOperator = null, + conditionValue = null, +}) => { + return ` +
+ +
+ + + ${conceptsOptionsStr} + +
+ + +
+ + + ${conceptsOptionsStr} + +
+ +
`; +}; -export const conceptDropdown = (concepts, name) => { - const elements = document.getElementsByClassName(name); - Array.from(elements).forEach((ele, i) => { - ele.innerHTML = getDataListTemplate(concepts, `${name.replace(/-/g, '')}${i}`, name); - }) -} +const deleteConditionListener = (event) => { + event.target.parentElement.remove(); +}; -const getDataListTemplate = (concepts, id, name, isReadonly = false) => { - let template = ``; +const getConcepts = async () => { + if (concepts) return concepts; - template += ``; - for (let key in concepts) { - template += ``; + try { + const response = await fetch("https://raw.githubusercontent.com/episphere/conceptGithubActions/master/jsons/varToConcept.json"); + if (!response.ok) { + return null; + } + return await response.json(); + } catch (error) { + console.error("Error in fetching concepts.", error); + return null; } - template += ``; - - return template; -}; - -const addEventNotificationCheckbox = () => { - const chkbs = document.getElementsByName('notification-checkbox'); - Array.from(chkbs).forEach(box => { - box.addEventListener('click', () => { - const checked = Array.from(chkbs).filter(cb => cb.checked).map(dt => dt.dataset.type); - renderDivs(checked); - }) - }) -} - -const getEmailNotificationTemplate = () => { +}; + +const getEmailDivHtml = (schemaData = null) => { return `
Email
- +
- +
`; }; -const getSmsNotificationTemplate = () => { +const getSmsDivHtml = (schemaData = null) => { return `
SMS
- - + +
`; }; -const getPushNotificationTemplate = () => { +const getPushDivHtml = (schemaData = null) => { return `
Push notification
- +
- +
`; }; -const renderDivs = (array, flag) => { +const handleNotficationDivs = (schemaData) => { + const emailCheckbox = document.getElementById("emailCheckBox"); + emailCheckbox.addEventListener("click", () => { + if (emailCheckbox.checked === true) { + document.getElementById("emailDiv").innerHTML = getEmailDivHtml(schemaData); + handleEmailPreview(); + } else { + document.getElementById("emailDiv").innerHTML = ""; + } + }); - if (flag === true) { - if(array.includes('email')){ - let template = getEmailNotificationTemplate(); - document.getElementById('emailDiv').innerHTML = template - } - - if(array.includes('sms')){ - let template = getSmsNotificationTemplate(); - document.getElementById('smsDiv').innerHTML = template - } - - if(array.includes('push')){ - let template = getPushNotificationTemplate(); - document.getElementById('pushDiv').innerHTML = template; - } + const smsCheckbox = document.getElementById("smsCheckBox"); + smsCheckbox.addEventListener("click", () => { + if (smsCheckbox.checked === true) { + document.getElementById("smsDiv").innerHTML = getSmsDivHtml(schemaData); + handleSMSCharacterCount(); + } else { + document.getElementById("smsDiv").innerHTML = ""; } + }); - else { - if(array.includes('email') && localStorage.getItem('emailCheck') === 'false'){ - let template = getEmailNotificationTemplate(); - document.getElementById('emailDiv').innerHTML = template - localStorage.setItem("emailCheck", true); - reRenderNotficationDivs(); - } - - if(array.includes('sms') && localStorage.getItem('smsCheck') === 'false'){ - let template = getSmsNotificationTemplate(); - document.getElementById('smsDiv').innerHTML = template - localStorage.setItem("smsCheck", true); - reRenderNotficationDivs(); - - } - - if(array.includes('push') && localStorage.getItem('pushNotificationCheck') === 'false'){ - let template = getPushNotificationTemplate(); - document.getElementById('pushDiv').innerHTML = template; - localStorage.setItem("pushNotificationCheck", true); - reRenderNotficationDivs(); - } + const pushCheckbox = document.getElementById("pushNotificationCheckBox"); + pushCheckbox.addEventListener("click", () => { + if (pushCheckbox.checked === true) { + document.getElementById("pushDiv").innerHTML = getPushDivHtml(schemaData); + } else { + document.getElementById("pushDiv").innerHTML = ""; } - const emailBody = document.getElementById('emailBody'); - if(emailBody) addEmailPreview(emailBody); - - addEventSMSCharacterCount(); -} - - -const reRenderNotficationDivs = () => { - const emailRecheck = document.getElementById('emailCheckBox'); - emailRecheck.addEventListener('click', () => { - if (emailRecheck.checked === false) document.getElementById('emailDiv').innerHTML = ''; - if (emailRecheck.checked === true) { - let template = getEmailNotificationTemplate(); - document.getElementById('emailDiv').innerHTML = template; - } - }) - const smsRecheck = document.getElementById('smsCheckBox'); - smsRecheck.addEventListener('click', () => { - if (smsRecheck.checked === false) document.getElementById('smsDiv').innerHTML = ''; - if (smsRecheck.checked === true) { - let template = getSmsNotificationTemplate(); - document.getElementById('smsDiv').innerHTML = template; - } - }) - const pushRecheck = document.getElementById('pushNotificationCheckBox'); - pushRecheck.addEventListener('click', () => { - if (pushRecheck.checked === false) document.getElementById('pushDiv').innerHTML = ''; - if (pushRecheck.checked === true) { - let template = getPushNotificationTemplate(); - document.getElementById('pushDiv').innerHTML = template; - } - }) -} - -const addEventSMSCharacterCount = () => { + }); +}; + +const handleSMSCharacterCount = () => { const characterCountEle = document.getElementById("characterCounts"); const smsBodyEle = document.getElementById("smsBody"); - if (characterCountEle && smsBodyEle) { + if (characterCountEle && smsBodyEle && !smsBodyEle.hasInputListener) { smsBodyEle.addEventListener("input", () => { characterCountEle.innerText = `${smsBodyEle.value.length}/160 characters`; }); + smsBodyEle.hasInputListener = true; } }; -const addEmailPreview = (emailBody) => { - const converter = new showdown.Converter() - emailBody.addEventListener('mouseenter', () => { - const text = emailBody.value; - const html = converter.makeHtml(text); - document.getElementById('emailBodyPreview').innerHTML = html; - }) -} - -const downloadObjectAsJson = (exportObj, exportName) => { - const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj)); - const downloadAnchorNode = document.createElement('a'); - downloadAnchorNode.setAttribute("href", dataStr); - downloadAnchorNode.setAttribute("download", exportName + ".json"); - document.body.appendChild(downloadAnchorNode); - downloadAnchorNode.click(); - downloadAnchorNode.remove(); -} +export const handleEmailPreview = () => { + const emailBody = document.getElementById("emailBody"); + if (!emailBody || emailBody?.hasMouseEnterListener) return; -const storeNotificationSchema = async (schema) => { - const notificationData = appState.getState().notification || {}; - schema.id = notificationData.savedSchema?.id || ""; + const converter = new showdown.Converter(); + emailBody.addEventListener("mouseenter", () => { + const text = emailBody.value; + const html = converter.makeHtml(text); + document.getElementById("emailBodyPreview").innerHTML = html; + }); + emailBody.hasMouseEnterListener = true; +}; +const storeNotificationSchema = async (schema) => { showAnimation(); const idToken = await getIdToken(); const schemaPayload = { data: schema }; @@ -559,42 +486,53 @@ const storeNotificationSchema = async (schema) => { const res = await response.json(); if (res.code === 200 && res.data?.length > 0) { schema.id = res.data[0].schemaId; - appState.setState({ notification: { savedSchema: schema, isEditing: notificationData.isEditing || false } }); + appState.setState((state) => ({ + notification: { savedSchema: schema, isEditing: state.notification?.isEditing ?? false }, + })); triggerNotificationBanner(`Notfication Schema Saved as ${schema.isDraft ? "Draft" : "Complete"}.`, "success"); - } else { - triggerNotificationBanner("Error in saving notification schema!", "danger"); + return res.data[0].schemaId; } + triggerNotificationBanner("Error in saving notification schema!", "danger"); + return ""; }; -const getOperatorResponse = (i) => { - return Object.keys(i)[0]; -} +const handleExitForm = () => { + const exitBtn = document.getElementById("exitForm"); + exitBtn.addEventListener("click", () => { + const loadDetailsPage = "#notifications/retrievenotificationschema"; + location.replace(window.location.origin + window.location.pathname + loadDetailsPage); + }); +}; -const getConditionsResponse = (i) => { - if (i['equals'] !== undefined) { - return i['equals']; - } else if (i['notequals'] !== undefined) { - return i['notequals']; - } - else if (i['greater'] !== undefined) { - return i['greater']; - } - else if (i['greaterequals'] !== undefined) { - return i['greaterequals']; - } - else if (i['less'] !== undefined) { - return i['less']; - } - else if (i['lessequals'] !== undefined) { - return i['lessequals']; +const handleDryRun = () => { + const resultEle = document.getElementById("dryRunResult"); + const dryRunBtn = document.getElementById("dryRunBtn"); + if (!dryRunBtn || dryRunBtn.hasClickListener) return; + + dryRunBtn.addEventListener("click", async () => { + showAnimation(); + const schemaId = appState.getState().notification.savedSchema.id; + const idToken = await getIdToken(); + const res = await fetch(`${baseAPI}/dashboard?api=dryRunNotificationSchema&schemaId=${schemaId}`, { + method: "GET", + headers: { + Authorization: "Bearer " + idToken, + }, + }); + + const resJson = await res.json(); + const dataObj = resJson.data[0] || { emailCount: 0, smsCount: 0 }; + + resultEle.textContent = `${"Emails count:".padEnd(25, " ")}${dataObj.emailCount}\n${"SMS messages count:".padEnd(25, " ")}${dataObj.smsCount}\n`; + if (resJson.code === 200) { + resultEle.textContent += "Everything looks good!"; + } else { + resultEle.textContent += `Error occurred in dry run:\n${resJson.message}`; } -} - -const clearNotificationSchemaForm = () => { - const a = document.getElementById('exitForm'); - a.addEventListener("click", () => { - const loadDetailsPage = '#notifications/retrievenotificationschema' - location.replace(window.location.origin + window.location.pathname + loadDetailsPage); - }) -} \ No newline at end of file + + hideAnimation(); + }); + + dryRunBtn.hasClickListener = true; +}; diff --git a/siteManagerDashboard/participantCommons.js b/siteManagerDashboard/participantCommons.js index 48ad16e3..3ae5af14 100644 --- a/siteManagerDashboard/participantCommons.js +++ b/siteManagerDashboard/participantCommons.js @@ -563,6 +563,8 @@ const tableTemplate = (data, showButtons) => { template += `${participant[x] ? 'Destroy Data Status' : ''}` : (participant[x] === fieldMapping.deceased) ? template += `${participant[x] ? 'Deceased' : ''}` + : (participant[x] === fieldMapping.dataDestroyed) ? + template += `${participant[x] ? 'Data Destroyed' : ''}` : template += ` ERROR ` ) : (x === (fieldMapping.bohStatusFlag1).toString() || x === (fieldMapping.mreStatusFlag1).toString() @@ -938,14 +940,14 @@ export const activeColumns = (data, showButtons) => { } if (appState.getState().filterHolder.type === "passive") { let passiveButton = document.getElementById('passiveFilter'); - if ([...passiveButton.classList].includes('btn-outline-info')) { + if (passiveButton && [...passiveButton.classList].includes('btn-outline-info')) { passiveButton.classList.remove('btn-outline-info'); passiveButton.classList.add('btn-info'); } } if (appState.getState().filterHolder.type === "active") { let activeButton = document.getElementById('activeFilter'); - if ([...activeButton.classList].includes('btn-outline-info')) { + if (activeButton && [...activeButton.classList].includes('btn-outline-info')) { activeButton.classList.remove('btn-outline-info'); activeButton.classList.add('btn-info'); } diff --git a/siteManagerDashboard/participantDetailsHelpers.js b/siteManagerDashboard/participantDetailsHelpers.js index 7f6216cf..3673acfa 100644 --- a/siteManagerDashboard/participantDetailsHelpers.js +++ b/siteManagerDashboard/participantDetailsHelpers.js @@ -402,9 +402,9 @@ export const hideUneditableButtons = (participant, changedOption) => { export const reloadParticipantData = async (token) => { showAnimation(); const query = `token=${token}` - const reloadedParticpant = await findParticipant(query); - mainContent.innerHTML = render(reloadedParticpant.data[0]); - renderParticipantDetails(reloadedParticpant.data[0], {}); + const reloadedParticipant = await findParticipant(query); + mainContent.innerHTML = render(reloadedParticipant.data[0]); + renderParticipantDetails(reloadedParticipant.data[0], {}); hideAnimation(); } @@ -790,7 +790,7 @@ export const saveResponses = (participant, changedOption, editedElement, concept changedOption[currentConceptId] = newValueElement.value; // if a changed field is a date of birth field then we need to update full date of birth if (fieldMapping.birthDay in changedOption || fieldMapping.birthMonth in changedOption || fieldMapping.birthYear in changedOption) { - const day = changedOption[fieldMapping.birthDay] || participant[fieldMapping.birthDay]; + const day = changedOption[fieldMapping.birthDay] || participant[fieldMapping.birthDay] || participant[fieldMapping.dateOfBirthComplete]?.slice(6,8) || "01"; const month = changedOption[fieldMapping.birthMonth] || participant[fieldMapping.birthMonth]; const year = changedOption[fieldMapping.birthYear] || participant[fieldMapping.birthYear]; const dateOfBirthComplete = fieldMapping.dateOfBirthComplete; diff --git a/siteManagerDashboard/participantHeader.js b/siteManagerDashboard/participantHeader.js index 313347d8..bd8abc95 100644 --- a/siteManagerDashboard/participantHeader.js +++ b/siteManagerDashboard/participantHeader.js @@ -2,82 +2,39 @@ import fieldMapping from './fieldToConceptIdMapping.js'; import { humanReadableMDY } from './utils.js'; import { keyToNameObj } from './idsToName.js'; -export const headerImportantColumns = [ - { field: 'Connect_ID' }, - { field: fieldMapping.fName }, - { field: fieldMapping.lName }, - { field: fieldMapping.birthYear }, - { field: fieldMapping.consentFlag }, - { field: fieldMapping.verifiedFlag }, - { field: 'Site' }, - { field: 'Year(s) in Connect' }, - { field: 'Participation Status'}, - { field: 'Suspended Contact'} -]; - - export const renderParticipantHeader = (participant) => { - - let conceptIdMapping = JSON.parse(localStorage.getItem('conceptIdMapping')); - let template = `' - - return template; -} + const readableVerificationDate = humanReadableMDY(participant[fieldMapping.verficationDate]); + let verificationHtmlStr = ""; + if (participant[fieldMapping.verifiedFlag] === fieldMapping.verified) { + verificationHtmlStr = `Verified: ${readableVerificationDate}`; + } else if (participant[fieldMapping.verifiedFlag] === fieldMapping.cannotBeVerified) { + verificationHtmlStr = `Can't Be Verified: ${readableVerificationDate}`; + } else if (participant[fieldMapping.verifiedFlag] === fieldMapping.notYetVerified) { + verificationHtmlStr = `Not Yet Verified: N/A`; + } else if (participant[fieldMapping.verifiedFlag] === fieldMapping.duplicate) { + verificationHtmlStr = `Duplicate: ${readableVerificationDate}`; + } else { + verificationHtmlStr = `Outreach Timed Out: ${readableVerificationDate}`; + } + + return ` + `; +}; // Year(s) in Connect : 1 const getYearsInConnect = (participant) => { @@ -92,22 +49,12 @@ const getYearsInConnect = (participant) => { totalYears <= 0 ? totalYears = '< 1' : totalYears; let yearsInConnect = totalYears; return typeof(yearsInConnect) !== 'string' && isNaN(yearsInConnect) ? 'N/A' : yearsInConnect; -} - - - -const concatDOB = (participant) => { - const participantBirthMonth = participant[fieldMapping.birthMonth]; - const participantBirthDate = participant[fieldMapping.birthDay]; - const participantBirthYear = participant[fieldMapping.birthYear]; - return participantBirthMonth && participantBirthDate && participantBirthYear ? participantBirthMonth + '/' + participantBirthDate + '/' + participantBirthYear : 'data deleted'; // 07/02/1966 or 'data deleted' - -} +}; const renderSiteLocation = (participant) => { const siteHealthcareProvider = participant[fieldMapping.healthcareProvider]; return keyToNameObj[siteHealthcareProvider]; -} +}; export const getParticipantStatus = (participant) => { if (typeof participant !== "string") { @@ -120,20 +67,12 @@ export const getParticipantStatus = (participant) => { } }; -const getEnrollmentStatus = (participant) => { - if (typeof participant !== "string") { - const statusValue = participant[fieldMapping.enrollmentStatus]; - if (statusValue !== undefined && statusValue !== `` ) return fieldMapping[statusValue]; - else return `Error`; - } -} - export const getParticipantSuspendedDate = (participant) => { if (participant[fieldMapping.suspendContact] !== "" && participant[fieldMapping.suspendContact] !== undefined ) { let suspendContactRequestedFrom = humanReadableMDY(participant[fieldMapping.startDateSuspendedContact]); - let suspendedDate = participant[fieldMapping.suspendContact] - return `Suspended Contact : From: ${suspendContactRequestedFrom} To: ${suspendedDate}` - } else { - return `` + let suspendedDate = participant[fieldMapping.suspendContact]; + return `Suspended Contact : From: ${suspendContactRequestedFrom} To: ${suspendedDate}`; } -} \ No newline at end of file + + return ""; +}; diff --git a/siteManagerDashboard/participantLookup.js b/siteManagerDashboard/participantLookup.js index 55af5eea..c682363b 100644 --- a/siteManagerDashboard/participantLookup.js +++ b/siteManagerDashboard/participantLookup.js @@ -46,7 +46,7 @@ export function renderParticipantSearch() {
- +
(OR)
@@ -143,15 +143,19 @@ const addEventSearch = () => { const email = document.getElementById('email').value; const phone = document.getElementById('phone').value; const sitePref = document.getElementById('dropdownSites').getAttribute('data-siteKey'); - if(!firstName && !lastName && !dob && !phone && !email && !sitePref) return; - let query = ''; - if(firstName) query += `firstName=${firstName}&`; - if(lastName) query += `lastName=${lastName}&`; - if(dob) query += `dob=${dob.replace(/-/g,'')}&`; - if(phone) query += `phone=${phone}&`; - if(email) query += `email=${email}&`; - if(sitePref) query += `sitePref=${sitePref}`; - performSearch(query, sitePref, "search-failed"); + + const params = new URLSearchParams(); + if (firstName) params.append('firstName', firstName); + if (lastName) params.append('lastName', lastName); + if (dob) params.append('dob', dob.replace(/-/g,'')); + if (phone) params.append('phone', phone.replace(/\D/g, '')); + if (email) params.append('email', email); + + if (params.size === 0) { + return alert('Please enter at least one field to search'); + }; + + performSearch(params.toString(), sitePref, "search-failed"); }) }; @@ -164,12 +168,17 @@ export const addEventSearchId = () => { const connectId = document.getElementById('connectId').value; const token = document.getElementById('token').value; const studyId = document.getElementById('studyId').value; - if(!connectId && !token && !studyId) return; - let query = ''; - if(connectId) query += `connectId=${connectId}`; - if(token) query += `token=${token}`; - if(studyId) query += `studyId=${studyId}`; - performSearch(query, "allResults", "search-connect-id-failed"); + + const params = new URLSearchParams(); + if (connectId) params.append('connectId', connectId); + if (token) params.append('token', token); + if (studyId) params.append('studyId', studyId); + + if (params.size === 0) { + return alert('Please enter at least one field to search'); + }; + + performSearch(params.toString(), "allResults", "search-connect-id-failed"); }) }; @@ -228,7 +237,7 @@ export const showNotifications = (data, error) => { export const findParticipant = async (query) => { const idToken = await getIdToken(); - const response = await fetch(`${baseAPI}/dashboard?api=getParticipants&type=filter&${query}`, { + const response = await fetch(`${baseAPI}/dashboard?api=getFilteredParticipants&${query}`, { method: "GET", headers: { Authorization:"Bearer " + idToken diff --git a/siteManagerDashboard/participantSummaryRow.js b/siteManagerDashboard/participantSummaryRow.js index cfebb621..70cbaa4f 100644 --- a/siteManagerDashboard/participantSummaryRow.js +++ b/siteManagerDashboard/participantSummaryRow.js @@ -42,14 +42,11 @@ export const verificationStatus = (participant) => { } export const baselineBloodSample = (participantModule) => { - const isDataDestroyed = participantModule[fieldMapping.dataHasBeenDestroyed] // TODO: should we use const instead of let for refusedBloodOption let refusedBloodOption = participantModule[fieldMapping.refusalOptions]?.[fieldMapping.refusedBlood]; let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Sample", "Blood", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (refusedBloodOption === fieldMapping.yes) { + if (refusedBloodOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Sample", "Blood", "Not Collected", "N/A", "N/A", "Y", "N/A"); } else if (!participantModule[fieldMapping.bloodFlag]) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Sample", "Blood", "Not Collected", "N/A", "N/A", "N", "N/A"); @@ -65,14 +62,11 @@ export const baselineBloodSample = (participantModule) => { } export const baselineUrineSample = (participantModule) => { - const isDataDestroyed = participantModule[fieldMapping.dataHasBeenDestroyed] let template = ``; let refusedUrineOption = participantModule[fieldMapping.refusalOptions]?.[fieldMapping.refusedUrine]; let urineFlag = participantModule[fieldMapping.urineFlag]; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Sample", "Urine", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (refusedUrineOption === fieldMapping.yes) { + if (refusedUrineOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Sample", "Urine", "Not Collected", "N/A", "N/A", "Y", "N/A"); } else if (!urineFlag) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Sample", "Urine", "Not Collected", "N/A", "N/A", "N", "N/A"); @@ -157,11 +151,6 @@ export const baselineMouthwashSample = (participantModule) => { displayedFields.refused = "Y"; } - const dataDestroyedOption = participantModule[fieldMapping.dataHasBeenDestroyed]; - if (dataDestroyedOption === fieldMapping.yes) { - displayedFields.status = "Data Destroyed"; - } - return getTemplateRow( displayedFields.icon.faIcon, displayedFields.icon.style, @@ -177,13 +166,10 @@ export const baselineMouthwashSample = (participantModule) => { }; export const baselineBOHSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let refusedSurveyOption = participant[fieldMapping.refusalOptions]?.[fieldMapping.refusedSurvey]; let template = ``; - if (isDataDestroyed === fieldMapping.yes){ - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "BOH", "Data Destroyed", "N/A", "N/A", "Y", "N/A"); - }else if (refusedSurveyOption === fieldMapping.yes) { + if (refusedSurveyOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "BOH", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (participant[fieldMapping.bohStatusFlag1] === fieldMapping.submitted1) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "BOH", "Submitted", @@ -201,13 +187,10 @@ export const baselineBOHSurvey = (participant) => { } export const baselineMRESurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let refusedSurveyOption = participant[fieldMapping.refusalOptions]?.[fieldMapping.refusedSurvey]; let template = ``; - if (isDataDestroyed === fieldMapping.yes){ - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "MRE", "Data Destroyed", "N/A", "N/A", "Y", "N/A"); - } else if (refusedSurveyOption === fieldMapping.yes) { + if (refusedSurveyOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "MRE", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (participant[fieldMapping.mreStatusFlag1] === fieldMapping.submitted1) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "MRE", "Submitted", @@ -225,13 +208,10 @@ export const baselineMRESurvey = (participant) => { } export const baselineSASSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let refusedSurveyOption = participant[fieldMapping.refusalOptions]?.[fieldMapping.refusedSurvey]; let template = ``; - if (isDataDestroyed === fieldMapping.yes){ - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "SAS", "Data Destroyed", "N/A", "N/A", "Y", "N/A"); - } else if (refusedSurveyOption === fieldMapping.yes) { + if (refusedSurveyOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "SAS", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (participant[fieldMapping.sasStatusFlag1] === fieldMapping.submitted1) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "SAS", "Submitted", @@ -249,13 +229,10 @@ export const baselineSASSurvey = (participant) => { } export const baselineLAWSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let refusedSurveyOption = participant[fieldMapping.refusalOptions]?.[fieldMapping.refusedSurvey]; let template = ``; - if (isDataDestroyed === fieldMapping.yes){ - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "LAW", "Data Destroyed", "N/A", "N/A", "Y", "N/A"); - } else if (refusedSurveyOption === fieldMapping.yes) { + if (refusedSurveyOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "LAW", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (participant[fieldMapping.lawStausFlag1] === fieldMapping.submitted1) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "LAW", "Submitted", @@ -273,31 +250,22 @@ export const baselineLAWSurvey = (participant) => { } export const baselineSSN = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] - let template = ``; + const { icon, color, itemStatus, date } = getSurveyStatus(participant, fieldMapping.ssnStatusFlag, fieldMapping.ssnPartialDate, fieldMapping.ssnFulldate); - if (isDataDestroyed === fieldMapping.yes){ - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "SSN", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (participant[fieldMapping.ssnFullflag] === fieldMapping.yes) { - template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "SSN", "All Digits", - (participant[fieldMapping.ssnFulldate] !== undefined ? humanReadableMDY(participant[fieldMapping.ssnFulldate]) : `N/A`), "N/A", "N", "N/A"); - } else if (participant[fieldMapping.ssnPartialFlag] === fieldMapping.yes) { - template += getTemplateRow("fa fa-hashtag fa-2x", "color: orange", "Baseline", "Survey", "SSN", "4 Digits", - (participant[fieldMapping.ssnPartialDate] !== undefined ? humanReadableMDY(participant[fieldMapping.ssnPartialDate]) : `N/A`), "N/A", "N", "N/A"); - } else { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "SSN", "None", "N/A", "N/A", "N", "N/A"); - } - - return template; + const timeline = "Baseline"; + const category = "Survey"; + const item = "SSN"; + const setting = "N/A"; + const refused = "N"; + const extra = "N/A"; + + return getTemplateRow(icon, color, timeline, category, item, itemStatus, date, setting, refused, extra); } export const baselineCOVIDSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "COVID", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (participant[fieldMapping.covidFlag] === fieldMapping.submitted1) { + if (participant[fieldMapping.covidFlag] === fieldMapping.submitted1) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "COVID", "Submitted", humanReadableMDY(participant[fieldMapping.covidCompletedDate]), "N/A", "N", "N/A"); } else if (participant[fieldMapping.covidFlag] === fieldMapping.started1) { @@ -313,14 +281,11 @@ export const baselineCOVIDSurvey = (participant) => { export const baselineBiospecSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let combinedBoodUrineMouthwashSurvey = participant[fieldMapping.combinedBoodUrineMouthwashSurvey] && participant[fieldMapping.combinedBoodUrineMouthwashSurvey]; let refusedSpecimenOption = participant[fieldMapping.refusalOptions] && participant[fieldMapping.refusalOptions][fieldMapping.refusedSpecimenSurveys]; let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Blood/Urine/Mouthwash", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (refusedSpecimenOption === fieldMapping.yes) { + if (refusedSpecimenOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Blood/Urine/Mouthwash", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (!combinedBoodUrineMouthwashSurvey) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Blood/Urine/Mouthwash", "N/A", "N/A", "N/A", "N", "N/A"); @@ -338,13 +303,10 @@ export const baselineBiospecSurvey = (participant) => { } export const baselineBloodUrineSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let refusedSpecimenOption = participant[fieldMapping.refusalOptions] && participant[fieldMapping.refusalOptions][fieldMapping.refusedSpecimenSurveys]; let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Clinical Blood/Urine", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (refusedSpecimenOption === fieldMapping.yes) { + if (refusedSpecimenOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Clinical Blood/Urine", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (!participant) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Clinical Blood/Urine", "N/A", "N/A", "N/A", "N", "N/A"); @@ -362,13 +324,10 @@ export const baselineBloodUrineSurvey = (participant) => { } export const baselineMouthwashSurvey = (participantModule) => { - const isDataDestroyed = participantModule[fieldMapping.dataHasBeenDestroyed]; let refusedSpecimenOption = participantModule[fieldMapping.refusalOptions] && participantModule[fieldMapping.refusalOptions][fieldMapping.refusedSpecimenSurveys]; let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Home Mouthwash", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (refusedSpecimenOption === fieldMapping.yes) { + if (refusedSpecimenOption === fieldMapping.yes) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Home Mouthwash", "N/A", "N/A", "N/A", "Y", "N/A"); } else if (!participantModule) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Home Mouthwash", "N/A", "N/A", "N/A", "N", "N/A"); @@ -387,12 +346,11 @@ export const baselineMouthwashSurvey = (participantModule) => { export const baselinePromisSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] === fieldMapping.yes; const refusedAllFutureSurveys = participant[fieldMapping.refusalOptions]?.[fieldMapping.refusedFutureSurveys]; const refusedAllFutureActivities = participant[fieldMapping.refusedAllFutureActivities]; const refusedQualityOfLifeSurvey = participant[fieldMapping.refusalOptions]?.[fieldMapping.refusedQualityOfLifeSurvey]; - const { icon, color, itemStatus, date } = getSurveyStatus(participant, isDataDestroyed, fieldMapping.promisSurveyFlag, fieldMapping.promisSurveyStartedDate, fieldMapping.promisSurveyCompletedDate); + const { icon, color, itemStatus, date } = getSurveyStatus(participant, fieldMapping.promisSurveyFlag, fieldMapping.promisSurveyStartedDate, fieldMapping.promisSurveyCompletedDate); const timeline = "Follow-Up 3-mo"; const category = "Survey"; @@ -405,12 +363,9 @@ export const baselinePromisSurvey = (participant) => { }; export const baselineMenstrualSurvey = (participant) => { - const isDataDestroyed = participant[fieldMapping.dataHasBeenDestroyed] let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Survey", "Menstrual Cycle", "Data Destroyed", "N/A", "N/A", "N", "N/A"); - } else if (participant[fieldMapping.menstrualFlag] === fieldMapping.submitted1) { + if (participant[fieldMapping.menstrualFlag] === fieldMapping.submitted1) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "Survey", "Menstrual Cycle", "Submitted", humanReadableMDY(participant[fieldMapping.menstrualDateTimeCompleted]), "N/A", "N", "N/A"); } else if (participant[fieldMapping.menstrualFlag] === fieldMapping.started1) { @@ -424,13 +379,10 @@ export const baselineMenstrualSurvey = (participant) => { } export const baselineEMR = (participantModule) => { - const isDataDestroyed = participantModule[fieldMapping.dataHasBeenDestroyed] const baselineEMR = participantModule[fieldMapping.baselineEMR] let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "EMR", "N/A", "Data Destroyed", "N/A", "N/A", "N/A", "N/A"); - } else if (!baselineEMR) { + if (!baselineEMR) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "EMR", "N/A", "Not Pushed", "N/A", "N/A", "N", "N/A"); } else if (baselineEMR[fieldMapping.baselineEMRflag] === fieldMapping.yes) { template += getTemplateRow("fa fa-check fa-2x", "color: green", "Baseline", "EMR", "N/A", "Pushed", @@ -443,12 +395,9 @@ export const baselineEMR = (participantModule) => { } export const baselinePayment = (participantModule) => { - const isDataDestroyed = participantModule[fieldMapping.dataHasBeenDestroyed] let template = ``; - if (isDataDestroyed === fieldMapping.yes) { - template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Payment", "N/A", "Data Destroyed", "N/A", "N/A", "N/A", "N/A") - } else if (!participantModule) { + if (!participantModule) { template += getTemplateRow("fa fa-times fa-2x", "color: red", "Baseline", "Payment", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"); } else if ( participantModule[fieldMapping.paymentRoundup] && @@ -466,49 +415,38 @@ export const baselinePayment = (participantModule) => { return template; } -const getSurveyStatus = (participant, dataDestroyed, surveyFlag, startDate, completeDate) => { - - if (dataDestroyed) { - return { - icon: "fa fa-times fa-2x", - color: "color: red", - itemStatus: "Data Destroyed", - date: "N/A" - }; - } - else { - switch (participant[surveyFlag]) { - case fieldMapping.submitted1: - return { - icon: "fa fa-check fa-2x", - color: "color: green", - itemStatus: "Submitted", - date: humanReadableMDY(participant[completeDate]) - }; - case fieldMapping.started1: - return { - icon: "fa fa-hashtag fa-2x", - color: "color: orange", - itemStatus: "Started", - date: humanReadableMDY(participant[startDate]) - }; - case fieldMapping.notYetEligible1: - return { - icon: "fa fa-times fa-2x", - color: "color: red", - itemStatus: "Not Yet Eligible", - date: "N/A" - }; - default: - return { - icon: "fa fa-times fa-2x", - color: "color: red", - itemStatus: "Not Started", - date: "N/A" - }; - } +const getSurveyStatus = (participant, surveyFlag, startDate, completeDate) => { + switch (participant[surveyFlag]) { + case fieldMapping.submitted1: + return { + icon: "fa fa-check fa-2x", + color: "color: green", + itemStatus: "Submitted", + date: humanReadableMDY(participant[completeDate]), + }; + case fieldMapping.started1: + return { + icon: "fa fa-hashtag fa-2x", + color: "color: orange", + itemStatus: "Started", + date: humanReadableMDY(participant[startDate]), + }; + case fieldMapping.notYetEligible1: + return { + icon: "fa fa-times fa-2x", + color: "color: red", + itemStatus: "Not Yet Eligible", + date: "N/A", + }; + default: + return { + icon: "fa fa-times fa-2x", + color: "color: red", + itemStatus: "Not Started", + date: "N/A", + }; } -} +}; const checkIncentiveIssued = (participantModule) => { return participantModule[fieldMapping.paymentRoundup] && diff --git a/siteManagerDashboard/participantWithdrawal.js b/siteManagerDashboard/participantWithdrawal.js index 6305f32c..1aabf9ae 100644 --- a/siteManagerDashboard/participantWithdrawal.js +++ b/siteManagerDashboard/participantWithdrawal.js @@ -68,25 +68,33 @@ const checkPreviousWithdrawalStatus = (participant) => { } const getParticipantSelectedRefusals = (participant) => { - let template = `` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedSurvey] === fieldMapping.yes ) template += `Initial Survey​, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedBlood] === fieldMapping.yes ) template += `Baseline Blood Donation, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedUrine] === fieldMapping.yes ) template += `Baseline Urine Donation, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedMouthwash] === fieldMapping.yes ) template += `Baseline Mouthwash (Saliva) Donation, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedSpecimenSurveys] === fieldMapping.yes ) template += `Baseline Specimen Surveys, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedFutureSamples] === fieldMapping.yes ) template += `All future specimens (willing to do surveys)​​, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedQualityOfLifeSurvey] === fieldMapping.yes ) template += `Refused QOL survey 3-mo (but willing to do other future surveys)​, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedAllFutureQualityOfLifeSurveys] === fieldMapping.yes ) template += `Refused all future QOL surveys (but willing to do other future surveys)​, ` - if (participant[fieldMapping.refusalOptions][fieldMapping.refusedFutureSurveys] === fieldMapping.yes ) template += `All future surveys (willing to do specimens)​, ` - if (participant[fieldMapping.refusedAllFutureActivities] === fieldMapping.yes ) template += `All Future Study Activities, ` - if (participant[fieldMapping.revokeHIPAA] === fieldMapping.yes ) template += `Revoke HIPAA Authorization, ` - if (participant[fieldMapping.withdrawConsent] === fieldMapping.yes ) template += `Withdraw Consent​, ` - if (participant[fieldMapping.destroyData] === fieldMapping.yes ) template += `Destroy Data​, ` - if (participant[fieldMapping.participantDeceased] === fieldMapping.yes ) template += `Participant Deceased, ` + let strArray = []; + const refusalOptions = participant[fieldMapping.refusalOptions]; - template = template.replace(/,\s*$/, "") // removes comma from the end + if (refusalOptions) { + if (refusalOptions[fieldMapping.refusedSurvey] === fieldMapping.yes) strArray.push("Initial Survey"); + if (refusalOptions[fieldMapping.refusedBlood] === fieldMapping.yes) strArray.push("Baseline Blood Donation"); + if (refusalOptions[fieldMapping.refusedUrine] === fieldMapping.yes) strArray.push("Baseline Urine Donation"); + if (refusalOptions[fieldMapping.refusedMouthwash] === fieldMapping.yes) + strArray.push("Baseline Mouthwash (Saliva) Donation"); + if (refusalOptions[fieldMapping.refusedSpecimenSurveys] === fieldMapping.yes) + strArray.push("Baseline Specimen Surveys"); + if (refusalOptions[fieldMapping.refusedFutureSamples] === fieldMapping.yes) + strArray.push("All future specimens (willing to do surveys)"); + if (refusalOptions[fieldMapping.refusedQualityOfLifeSurvey] === fieldMapping.yes) + strArray.push("Refused QOL survey 3-mo (but willing to do other future surveys)"); + if (refusalOptions[fieldMapping.refusedAllFutureQualityOfLifeSurveys] === fieldMapping.yes) + strArray.push("Refused all future QOL surveys (but willing to do other future surveys)"); + if (refusalOptions[fieldMapping.refusedFutureSurveys] === fieldMapping.yes) + strArray.push("All future surveys (willing to do specimens)"); + } - return template - -} + if (participant[fieldMapping.refusedAllFutureActivities] === fieldMapping.yes) + strArray.push("All Future Study Activities"); + if (participant[fieldMapping.revokeHIPAA] === fieldMapping.yes) strArray.push("Revoke HIPAA Authorization"); + if (participant[fieldMapping.withdrawConsent] === fieldMapping.yes) strArray.push("Withdraw Consent"); + if (participant[fieldMapping.destroyData] === fieldMapping.yes) strArray.push("Destroy Data"); + if (participant[fieldMapping.participantDeceased] === fieldMapping.yes) strArray.push("Participant Deceased"); + return strArray.join(", "); +}; diff --git a/siteManagerDashboard/participantWithdrawalForm.js b/siteManagerDashboard/participantWithdrawalForm.js index 8fdfa6f4..d34edfe3 100644 --- a/siteManagerDashboard/participantWithdrawalForm.js +++ b/siteManagerDashboard/participantWithdrawalForm.js @@ -565,7 +565,7 @@ const sendResponses = async (finalOptions, retainOptions, requestedHolder, sourc const token = localStorage.getItem("token"); sendRefusalData['token'] = token; const idToken = await getIdToken(); - clickHandler(sendRefusalData, idToken, token); + await sendResponsesClickHandler(sendRefusalData, idToken, token); } const updateWhoRequested = (sendRefusalData, updatedWhoRequested, updatedWhoRequestedOther) => { @@ -619,35 +619,46 @@ const combineResponses = (finalOptions, sendRefusalData, suspendDate) => { } } -async function clickHandler(sendRefusalData, idToken, token) { +async function sendResponsesClickHandler(sendRefusalData, idToken, token) { showAnimation(); - - const refusalPayload = { - "data": [sendRefusalData] - } - const response = await (await fetch(`${baseAPI}/dashboard?api=updateParticipantData`, { - method:'POST', - body: JSON.stringify(refusalPayload), - headers:{ - Authorization:"Bearer "+idToken, - "Content-Type": "application/json" + try { + const refusalPayload = { + "data": [sendRefusalData] + }; + const response = await fetch(`${baseAPI}/dashboard?api=updateParticipantData`, { + method: 'POST', + body: JSON.stringify(refusalPayload), + headers: { + Authorization: "Bearer " + idToken, + "Content-Type": "application/json" } - })) - hideAnimation(); - if (response.status === 200) { - const participantResponse = await (await fetch(`${baseAPI}/dashboard?api=getParticipants&type=filter&token=${token}`, { - method:'GET', - headers:{ - Authorization:"Bearer "+idToken, + }); + + if (response.status !== 200) { + throw new Error('Error updating participant data'); + } + + const participantResponse = await fetch(`${baseAPI}/dashboard?api=getFilteredParticipants&token=${token}`, { + method: 'GET', + headers: { + Authorization: "Bearer " + idToken, "Content-Type": "application/json" - } - })).json() - if (participantResponse.code === 200) { - const loadDetailsPage = '#participantSummary' - localStorage.setItem("participant", JSON.stringify(participantResponse.data[0])); - location.replace(window.location.origin + window.location.pathname + loadDetailsPage); // updates url to participantSummary - }} - else { - (alert('Error')) + } + }); + + const participantJSON = await participantResponse.json(); + + if (participantJSON.code !== 200) { + throw new Error('Error fetching participant data'); + } + + const loadDetailsPage = '#participantSummary'; + localStorage.setItem("participant", JSON.stringify(participantJSON.data[0])); + location.replace(window.location.origin + window.location.pathname + loadDetailsPage); // updates url to participantSummary + } catch (error) { + console.error(error); + alert('An error occurred. Please try again.'); + } finally { + hideAnimation(); } } \ No newline at end of file diff --git a/siteManagerDashboard/utils.js b/siteManagerDashboard/utils.js index 2faebcec..be75495d 100644 --- a/siteManagerDashboard/utils.js +++ b/siteManagerDashboard/utils.js @@ -167,6 +167,7 @@ export const pdfCoordinatesMap = { 'KPGA': { 'V0.02': [{x: 110, y: 400}, {x0: 110, y0: 360}, {x1: 110, y1: 320}], 'V0.03': [{x: 110, y: 375}, {x0: 110, y0: 335}, {x1: 110, y1: 295}], + 'V0.04': [{x: 110, y: 375}, {x0: 110, y0: 335}, {x1: 110, y1: 295}], 'V1.0': [{x: 110, y: 400}, {x0: 110, y0: 360}, {x1: 110, y1: 320}] }, 'KPHI': { @@ -217,6 +218,7 @@ export const pdfCoordinatesMap = { }, 'KPGA': { 'V0.02': [{x: 110, y: 345}, {x0: 110, y0: 305}, {x1: 110, y1: 385}], + 'V0.03': [{x: 110, y: 345}, {x0: 110, y0: 305}, {x1: 110, y1: 385}], 'V1.0': [{x: 110, y: 345}, {x0: 110, y0: 300}, {x1: 110, y1: 385}] }, 'KPHI': {