From 2067d8ccfc5cc16b67b4e8637d30f89a71148cd2 Mon Sep 17 00:00:00 2001 From: amber-emmes Date: Tue, 3 Sep 2024 09:28:50 -0400 Subject: [PATCH 1/5] Participant reset work WIP --- index.html | 2 ++ index.js | 2 ++ src/participantDetails.js | 13 ++++++++++- src/participantDetailsHelpers.js | 39 ++++++++++++++++++++++++++++++++ src/utils.js | 1 + 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 76289d5..95385fb 100644 --- a/index.html +++ b/index.html @@ -98,6 +98,8 @@ + + diff --git a/index.js b/index.js index 8f4d732..dca7f32 100644 --- a/index.js +++ b/index.js @@ -71,6 +71,8 @@ window.onload = async () => { else { !firebase.apps.length ? firebase.initializeApp(devFirebaseConfig) : firebase.app(); !isLocalDev && window.DD_RUM && window.DD_RUM.init({ ...datadogConfig, env: 'dev' }); + // TODO: Remove this line + if (location.host.startsWith('localhost')) firebase.functions().useFunctionsEmulator('http://localhost:5001'); } !isLocalDev && window.DD_RUM && window.DD_RUM.startSessionReplayRecording(); diff --git a/src/participantDetails.js b/src/participantDetails.js index be1de91..b150057 100644 --- a/src/participantDetails.js +++ b/src/participantDetails.js @@ -1,5 +1,5 @@ import { dashboardNavBarLinks, removeActiveClass } from './navigationBar.js'; -import { attachUpdateLoginMethodListeners, allStates, closeModal, getFieldValues, getImportantRows, getModalLabel, hideUneditableButtons, renderReturnSearchResults, resetChanges, saveResponses, showSaveNoteInModal, submitClickHandler, suffixList, languageList, viewParticipantSummary, } from './participantDetailsHelpers.js'; +import { attachUpdateLoginMethodListeners, allStates, closeModal, getFieldValues, getImportantRows, getModalLabel, hideUneditableButtons, renderReturnSearchResults, resetChanges, saveResponses, showSaveNoteInModal, submitClickHandler, resetClickHandlers, suffixList, languageList, viewParticipantSummary, } from './participantDetailsHelpers.js'; import fieldMapping from './fieldToConceptIdMapping.js'; import { renderParticipantHeader } from './participantHeader.js'; import { getDataAttributes } from './utils.js'; @@ -43,6 +43,7 @@ export const renderParticipantDetails = (participant, changedOption) => { renderReturnSearchResults(); attachUpdateLoginMethodListeners(participant[fieldMapping.accountEmail], participant[fieldMapping.accountPhone], participant.token, participant.state.uid); submitClickHandler(participant, changedOption); + resetClickHandlers(participant); } export const render = (participant, changedOption) => { @@ -63,6 +64,7 @@ export const render = (participant, changedOption) => { ${renderParticipantHeader(participant)} ${renderBackToSearchDivAndButton()} ${renderCancelChangesAndSaveChangesButtons()} + ${renderResetUserButton()} ${renderDetailsTableHeader()} `; @@ -282,6 +284,15 @@ const renderBackToSearchDivAndButton = () => { `; }; +const renderResetUserButton = () => { + // @TODO: Make this dev environment only + return ` +
+ +
+ ` +} + const renderDetailsTableHeader = () => { return `

Participant Details

diff --git a/src/participantDetailsHelpers.js b/src/participantDetailsHelpers.js index cd64675..3980ba1 100644 --- a/src/participantDetailsHelpers.js +++ b/src/participantDetailsHelpers.js @@ -1206,6 +1206,15 @@ export const submitClickHandler = async (participant, changedOption) => { } }; +export const resetClickHandlers = async (participant) => { + console.log('participant', participant); + const participantUid = participant?.state?.uid; + const resetButton = document.getElementById('resetUserBtn'); + resetButton.addEventListener('click', async (e) => { + + }); +} + /** * Handle the query.frstName and query.lastName fields. * Check changedUserDataForProfile the participant profile for all name types. If a name is in changedUserDataForProfile, Add it to the queryNameArray. @@ -1387,6 +1396,10 @@ const processUserDataUpdate = async (changedUserDataForProfile, changedUserDataF }); return true; }; + +const processUserDataReset = async() => { + +} /** * Update the user's history based on new data entered by the user. This only triggers if the user's profile is verified. @@ -1490,3 +1503,29 @@ export const postUserDataUpdate = async (changedUserData) => { throw error; } } + +export const getResetUserData = async (uid) => { + try { + const idToken = await getIdToken(); + const response = await fetch(`${baseAPI}/dashboard?api=resetUser`, { + method: "GET", + headers:{ + Authorization: "Bearer " + idToken, + "Content-Type": "application/json" + }, + body: JSON.stringify({uid}) + }); + + console.log('response', response); + + if (!response.ok) { + const error = (response.status + ": " + (await response.json()).message); + throw new Error(error); + } + + return await response.json(); + } catch (error) { + console.error('Error in getResetUserData:', error); + throw error; + } +} \ No newline at end of file diff --git a/src/utils.js b/src/utils.js index 16f22d5..bc5064f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -115,6 +115,7 @@ export const urls = { let api = ``; if(location.host === urls.prod) api = 'https://api-myconnect.cancer.gov'; else if(location.host === urls.stage) api = 'https://api-myconnect-stage.cancer.gov'; +else if(location.host.startsWith('localhost')) api = 'http://localhost:5001/nih-nci-dceg-connect-dev/us-central1'; else api = 'https://us-central1-nih-nci-dceg-connect-dev.cloudfunctions.net'; export const baseAPI = api; From 0f52d84b119ccdf11943611259c19ab84c1ccdd0 Mon Sep 17 00:00:00 2001 From: amber-emmes Date: Thu, 5 Sep 2024 14:23:00 -0400 Subject: [PATCH 2/5] WIP --- src/participantDetailsHelpers.js | 8 ++++---- src/participantLookup.js | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/participantDetailsHelpers.js b/src/participantDetailsHelpers.js index 3980ba1..951d7fb 100644 --- a/src/participantDetailsHelpers.js +++ b/src/participantDetailsHelpers.js @@ -1211,7 +1211,7 @@ export const resetClickHandlers = async (participant) => { const participantUid = participant?.state?.uid; const resetButton = document.getElementById('resetUserBtn'); resetButton.addEventListener('click', async (e) => { - + await postResetUserData(participantUid); }); } @@ -1504,11 +1504,11 @@ export const postUserDataUpdate = async (changedUserData) => { } } -export const getResetUserData = async (uid) => { +export const postResetUserData = async (uid) => { try { const idToken = await getIdToken(); const response = await fetch(`${baseAPI}/dashboard?api=resetUser`, { - method: "GET", + method: "POST", headers:{ Authorization: "Bearer " + idToken, "Content-Type": "application/json" @@ -1525,7 +1525,7 @@ export const getResetUserData = async (uid) => { return await response.json(); } catch (error) { - console.error('Error in getResetUserData:', error); + console.error('Error in postResetUserData:', error); throw error; } } \ No newline at end of file diff --git a/src/participantLookup.js b/src/participantLookup.js index e590cd0..10d40da 100644 --- a/src/participantLookup.js +++ b/src/participantLookup.js @@ -204,6 +204,7 @@ export const performSearch = async (query, sitePref, failedElem) => { if(response.code === 200 && response.data.length > 0) { const mainContent = document.getElementById('mainContent') let filterRawData = filterdata(response.data); + console.log('filterRawData', filterRawData); if (sitePref !== undefined && sitePref != null && sitePref !== 'allResults') { const sitePrefId = nameToKeyObj[sitePref]; From 8ef38bad2019d2f67b077ae30ce854b0876bac17 Mon Sep 17 00:00:00 2001 From: amber-emmes Date: Mon, 9 Sep 2024 09:10:56 -0400 Subject: [PATCH 3/5] Reset user button limited to dev; commit parameter now passed along Reset also has confirm dialog now. --- src/participantDetails.js | 53 ++++++++++++++++++++++------ src/participantDetailsHelpers.js | 59 +++++++++++++++++++++++++++----- 2 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/participantDetails.js b/src/participantDetails.js index b150057..341c5a1 100644 --- a/src/participantDetails.js +++ b/src/participantDetails.js @@ -2,7 +2,7 @@ import { dashboardNavBarLinks, removeActiveClass } from './navigationBar.js'; import { attachUpdateLoginMethodListeners, allStates, closeModal, getFieldValues, getImportantRows, getModalLabel, hideUneditableButtons, renderReturnSearchResults, resetChanges, saveResponses, showSaveNoteInModal, submitClickHandler, resetClickHandlers, suffixList, languageList, viewParticipantSummary, } from './participantDetailsHelpers.js'; import fieldMapping from './fieldToConceptIdMapping.js'; import { renderParticipantHeader } from './participantHeader.js'; -import { getDataAttributes } from './utils.js'; +import { getDataAttributes, urls } from './utils.js'; import { appState } from './stateManager.js'; appState.setState({unsavedChangesTrack:{saveFlag: false, counter: 0}}); @@ -38,12 +38,12 @@ export const renderParticipantDetails = (participant, changedOption) => { hideUneditableButtons(participant, changedOption); localStorage.setItem("participant", JSON.stringify(participant)); changeParticipantDetail(participant, changedOption, originalHTML); + resetParticipantConfirm(originalHTML); editAltContact(participant); viewParticipantSummary(participant); renderReturnSearchResults(); attachUpdateLoginMethodListeners(participant[fieldMapping.accountEmail], participant[fieldMapping.accountPhone], participant.token, participant.state.uid); submitClickHandler(participant, changedOption); - resetClickHandlers(participant); } export const render = (participant, changedOption) => { @@ -64,7 +64,7 @@ export const render = (participant, changedOption) => { ${renderParticipantHeader(participant)} ${renderBackToSearchDivAndButton()} ${renderCancelChangesAndSaveChangesButtons()} - ${renderResetUserButton()} + ${renderResetUserButton(participant?.state?.uid)} ${renderDetailsTableHeader()} `; @@ -109,6 +109,30 @@ export const render = (participant, changedOption) => { return template; } +const resetParticipantConfirm = (originalHTML) => { + const openResetDialogBtn = document.getElementById('openResetDialog'); + if(openResetDialogBtn) { + let data = getDataAttributes(openResetDialogBtn); + openResetDialogBtn.addEventListener('click', () => { + const header = document.getElementById('modalHeader'); + const body = document.getElementById('modalBody'); + const uid = data.participantuid; + header.innerHTML = ` +
Confirm Participant Reset
+ ` + body.innerHTML = `
+ Are you sure you want to reset this participant to a just-verified state? This cannot be undone. +
+ +   + +
+
` + resetClickHandlers(uid); + }); + } +} + const changeParticipantDetail = (participant, changedOption, originalHTML) => { const detailedRow = Array.from(document.getElementsByClassName('detailedRow')); if (detailedRow) { @@ -284,13 +308,22 @@ const renderBackToSearchDivAndButton = () => { `; }; -const renderResetUserButton = () => { - // @TODO: Make this dev environment only - return ` -
- -
- ` +const renderResetUserButton = (participantUid) => { + if(location.hostname === 'localhost' || location.hostname === '127.0.0.1' || location.host === urls.stage) { + return ` + + + + ` + } else { + return ''; + } } const renderDetailsTableHeader = () => { diff --git a/src/participantDetailsHelpers.js b/src/participantDetailsHelpers.js index 951d7fb..93b519c 100644 --- a/src/participantDetailsHelpers.js +++ b/src/participantDetailsHelpers.js @@ -760,6 +760,37 @@ const showAuthUpdateAPIError = (bodyId, message) => { return false; } +export const refreshParticipantAfterReset = async (participant) => { + showAnimation(); + localStorage.setItem('participant', JSON.stringify(participant)); + renderParticipantDetails(participant, {}); + appState.setState({unsavedChangesTrack:{saveFlag: false, counter: 0}}) + let alertList = document.getElementById('alert_placeholder'); + let template = ''; + template += `` + hideAnimation(); + alertList.innerHTML = template; +} + +export const participantRefreshError = async (errorMsg) => { + showAnimation(); + let alertList = document.getElementById('alert_placeholder'); + let template = ''; + template += `` + hideAnimation(); + alertList.innerHTML = template; +} + export const refreshParticipantAfterUpdate = async (participant) => { showAnimation(); localStorage.setItem('participant', JSON.stringify(participant)); @@ -1206,12 +1237,26 @@ export const submitClickHandler = async (participant, changedOption) => { } }; -export const resetClickHandlers = async (participant) => { - console.log('participant', participant); - const participantUid = participant?.state?.uid; +export const resetClickHandlers = async (participantUid) => { const resetButton = document.getElementById('resetUserBtn'); - resetButton.addEventListener('click', async (e) => { - await postResetUserData(participantUid); + if(!resetButton) { + return; + } + resetButton.addEventListener('click', async () => { + try { + const json = await postResetUserData(participantUid); + closeModal(); + if(json.code === 200) { + refreshParticipantAfterReset(json.data.data); + } else if (json.code === 404) { + participantRefreshError('Unable to find participant.'); + } else { + participantRefreshError(json.data); + } + } catch(error) { + console.error('error', error); + participantRefreshError('Unknown error.'); + } }); } @@ -1513,11 +1558,9 @@ export const postResetUserData = async (uid) => { Authorization: "Bearer " + idToken, "Content-Type": "application/json" }, - body: JSON.stringify({uid}) + body: JSON.stringify({uid, saveToDb: 'true'}) }); - console.log('response', response); - if (!response.ok) { const error = (response.status + ": " + (await response.json()).message); throw new Error(error); From 0a4f40eba27213885ac3d14dc0152621fe44e71c Mon Sep 17 00:00:00 2001 From: amber-emmes Date: Mon, 9 Sep 2024 09:14:49 -0400 Subject: [PATCH 4/5] Removed erroneously included lines for local API usage + console log --- index.html | 2 -- index.js | 2 -- src/participantLookup.js | 1 - src/utils.js | 1 - 4 files changed, 6 deletions(-) diff --git a/index.html b/index.html index 95385fb..76289d5 100644 --- a/index.html +++ b/index.html @@ -98,8 +98,6 @@ - - diff --git a/index.js b/index.js index dca7f32..8f4d732 100644 --- a/index.js +++ b/index.js @@ -71,8 +71,6 @@ window.onload = async () => { else { !firebase.apps.length ? firebase.initializeApp(devFirebaseConfig) : firebase.app(); !isLocalDev && window.DD_RUM && window.DD_RUM.init({ ...datadogConfig, env: 'dev' }); - // TODO: Remove this line - if (location.host.startsWith('localhost')) firebase.functions().useFunctionsEmulator('http://localhost:5001'); } !isLocalDev && window.DD_RUM && window.DD_RUM.startSessionReplayRecording(); diff --git a/src/participantLookup.js b/src/participantLookup.js index 10d40da..e590cd0 100644 --- a/src/participantLookup.js +++ b/src/participantLookup.js @@ -204,7 +204,6 @@ export const performSearch = async (query, sitePref, failedElem) => { if(response.code === 200 && response.data.length > 0) { const mainContent = document.getElementById('mainContent') let filterRawData = filterdata(response.data); - console.log('filterRawData', filterRawData); if (sitePref !== undefined && sitePref != null && sitePref !== 'allResults') { const sitePrefId = nameToKeyObj[sitePref]; diff --git a/src/utils.js b/src/utils.js index bc5064f..16f22d5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -115,7 +115,6 @@ export const urls = { let api = ``; if(location.host === urls.prod) api = 'https://api-myconnect.cancer.gov'; else if(location.host === urls.stage) api = 'https://api-myconnect-stage.cancer.gov'; -else if(location.host.startsWith('localhost')) api = 'http://localhost:5001/nih-nci-dceg-connect-dev/us-central1'; else api = 'https://us-central1-nih-nci-dceg-connect-dev.cloudfunctions.net'; export const baseAPI = api; From 842a024d65695fe0fe0b1fdb0450e5530feed1fc Mon Sep 17 00:00:00 2001 From: amber-emmes Date: Mon, 9 Sep 2024 11:23:53 -0400 Subject: [PATCH 5/5] Addressed PR comments --- src/participantDetails.js | 6 +++--- src/participantDetailsHelpers.js | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/participantDetails.js b/src/participantDetails.js index 341c5a1..95a7025 100644 --- a/src/participantDetails.js +++ b/src/participantDetails.js @@ -38,7 +38,7 @@ export const renderParticipantDetails = (participant, changedOption) => { hideUneditableButtons(participant, changedOption); localStorage.setItem("participant", JSON.stringify(participant)); changeParticipantDetail(participant, changedOption, originalHTML); - resetParticipantConfirm(originalHTML); + resetParticipantConfirm(); editAltContact(participant); viewParticipantSummary(participant); renderReturnSearchResults(); @@ -109,7 +109,7 @@ export const render = (participant, changedOption) => { return template; } -const resetParticipantConfirm = (originalHTML) => { +const resetParticipantConfirm = () => { const openResetDialogBtn = document.getElementById('openResetDialog'); if(openResetDialogBtn) { let data = getDataAttributes(openResetDialogBtn); @@ -309,7 +309,7 @@ const renderBackToSearchDivAndButton = () => { }; const renderResetUserButton = (participantUid) => { - if(location.hostname === 'localhost' || location.hostname === '127.0.0.1' || location.host === urls.stage) { + if(location.hostname === 'localhost' || location.hostname === '127.0.0.1' || location.host === urls.dev) { return ` { - -} /** * Update the user's history based on new data entered by the user. This only triggers if the user's profile is verified.