Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JN-1020] Admin form editing #894

Merged
merged 8 commits into from
May 22, 2024
Merged

[JN-1020] Admin form editing #894

merged 8 commits into from
May 22, 2024

Conversation

MatthewBemis
Copy link
Member

@MatthewBemis MatthewBemis commented May 16, 2024

DESCRIPTION (include screenshots, and mobile screenshots for participant UX)

Adds support for admin form editing. As a result, this brings a lot of survey-related infrastructure and types into ui-core.

OUT OF SCOPE: a refined admin UX. This PR is massive and challenging to review as-is, the focus here is just getting the survey infrastructure into core along with all of the related dependencies. Refined UX will come in follow-on PRs.

This needs some extra attention when testing the participant side to ensure that there weren't any regressions. This branch has also undergone several notable rebases during it's life, and accounting for newer changes during a rebase while also moving them ui-core is particularly vulnerable to dropping new functionality. Some areas worth calling out:

  • Confirm that address validation still works in surveys
  • Confirm that autosave behaves as expected
  • Confirm that all of the recently-added proxy survey functionality still works correctly

TO TEST: (simple manual steps for confirming core behavior -- used for pre-release checks)

More specific steps coming soon, but definitely focus on the above areas.

@MatthewBemis MatthewBemis marked this pull request as ready for review May 16, 2024 20:43
Copy link
Collaborator

@devonbush devonbush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on all the code rearranging! Overall, code looks good. Some minor suggestions. Only commenting for now because, as you said, I want to take a lot of time to test this code out

.surveyId(survey.getId())
.complete(responseDto.isComplete())
.resumeData(responseDto.getResumeData())
.build();
Optional.ofNullable(operator.getParticipantUser()).ifPresent(pUser -> newResponse.setCreatingParticipantUserId(pUser.getId()));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a standard if/else is more appropriate here -- we're not doing any chaining so the functional wrapper makes if harder to pinpoint the if logic--but maybe that's just me. Connor, what's your take? Better yet, add a "setResponsibleUser" method to SurveyResponse that takes a responsibleEntity and sets the ids appropriately. That method might then be reused via interface with Answer

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I like the setResponsibleUser on the survey response approach. That mirrors (iirc) the flow on the data audit info. I don't feel super strongly on if/else, but I agree it might make the logic clearer.

Store.addNotification(successNotification('Response saved'))
}}
onFailure={() => Store.addNotification(failureNotification('Response could not be saved'))}
updateProfile={() => {}} //eslint-disable-line @typescript-eslint/no-empty-function
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can avoid the typescript warning by having it return null or true, or some other simple value

Suggested change
updateProfile={() => {}} //eslint-disable-line @typescript-eslint/no-empty-function
updateProfile={() => null}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you an also have a commment on the inside

() => {
// todo
}


/** allows editing of a survey response */
export default function SurveyEditView({ response, survey }: {response: SurveyResponse, survey: Survey}) {
console.log(`not implemented ${response.surveyId} ${survey.stableId}`)
export default function SurveyEditView({ studyEnvContext, response, survey, enrollee, adminUserId, onUpdate }: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's rename this to SurveyResponseEditor to avoid confusion with the form editor


/** Show responses for a survey based on url param */
export default function EnrolleeSurveyView({ enrollee, responseMap, studyEnvContext }:
{enrollee: Enrollee, responseMap: ResponseMapT, studyEnvContext: StudyEnvContextT}) {
export default function EnrolleeSurveyView({ enrollee, responseMap, studyEnvContext, onUpdate }:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SurveyResponseView might be a better name for this component

@devonbush
Copy link
Collaborator

Initial testing seems solid -- I had tabs open to admin and participant view of the same survey and was taking turns editing both, and it always saved the answers, which were then available to the other side upon refresh. (which is desired behavior -- CMI confirmed earlier they do not want a google-docs-like shared editing experience. They'd rather risk accidental overwrites than have a patient jarred by seeing their data change in front of them

Copy link
Collaborator

@connorlbark connorlbark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worked great! a really impressive lift, excited to see the final product. also commenting for now, ran into some bugs. i'll be gone all next week, though, so if devon gives it a thumb then consider it worthy 😄


export * from './test-utils/asMockedFn'
export * from './test-utils/router-testing-utils'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that we already had some testing stuff in core's index file, but I wonder if we should break this out into something like @ui-core/testing: it seems weird (to me) to have testing utils interspersed with the core app functionality. That is probably out of the scope of this PR, though.

import { Enrollee } from 'src/types/user'
import { Profile } from 'src/types/address'

const AUTO_SAVE_INTERVAL = 3 * 1000 // auto-save every 3 seconds if there are changes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still wary of relying on autosave for editing participant data, since it seems like a "thing we should not do often", but CMI folks seemed to not mind, so 🤷 . It definitely makes sense in regards to admin-only forms, though.

Comment on lines +277 to +279
envName: EnvironmentName,
profile?: Profile,
proxyProfile?: Profile,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sad that we have to move these to the parameters :( these are so easy to forget, as evidenced by the preenroll breaking. it would be so cool if there was some way to allow useUser/useActiveUser to still function in core.

It feels like more and more things are moving to core as we start to allow the admins to do more of the participant experience in the admin side. As such, I suspect we might start running into more cases like this where we have to awkwardly pass down user information to things in core. it would be cool if these hooks worked in the admin app but returned nothing except for the cases that you are looking at an enrollee's page, then it would return the appropriate user.

potentially, we could rename them to useParticipantUser and useActiveParticipantUser so that it's more clear in the admin side that they are only available when you're viewing a specific participant? dunno just spitballing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100% agree that the parameter list on this is way too burdensome. hooks are an interesting idea here, let me see what I can do to clean it up (but i may defer that work to a followup PR though since this branch is super vulnerable to merge conflicts)

@@ -17,3 +17,17 @@ export type AddressValidationResult = {
hasInferredComponents?: boolean,
vacant?: boolean
}

export type Profile = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be in user.ts?

creatingAdminUserId: string
}

export type Enrollee = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's goooooooooo

import { SurveyResponse } from 'src/types/forms'
import { StudyEnvParams } from 'src/types/study'
import { HubResponse } from 'src/types/user'
import { AddressValidationResult, MailingAddress } from 'src/types/address'

export type ImageUrlFunc = (cleanFileName: string, version: number) => string
export type SubmitMailingListContactFunc = (name: string, email: string) => Promise<object>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried the e2e tests (and then tried it myself) and found that, oddly, I couldn't add myself to the mailing list. It wouldn't error in the participant side, but it didn't show up on the admin side. I tried on dev and it worked.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unable to reproduce this locally or with the e2e tests.

Devon, do you see this as well?

onChange={e => updateWorkingForm({
...workingForm, allowAdminEdit: e.target.checked
})}
/> Allow admin completion
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word completion feels weird to me, especially when half of the time we really mean admins can edit this participant's responses, but should only edit one small thing not complete it on behalf of them - Imo, this would make more sense to me as a radio group

opt 1 - Participant-only form (e.g., consent form) 
opt 2 - Admin-editable participant survey (e.g., demographics)
opt 3 - Admin-only survey (e.g., medical records)

This also eliminates the weird possibility of a form being editable by no one haha

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed- this will definitely be touched up in a followup UX PR

}
}>
{isEditing ?
<div><FontAwesomeIcon icon={faX}/> Cancel</div> :
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me this feels more like Complete or Finish button since the changes are already saved - but that's probably more of a UX concern.

Comment on lines 33 to 34
undefined,
undefined,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we actually do need to pass these in, if they exist - they are used to prefill proxy/governed user name in the case of adding a new proxy or signing yourself up as a governed user.

Copy link
Collaborator

@devonbush devonbush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, let's get this merged so we have time to poke at it!

@devonbush devonbush requested a review from wluken May 21, 2024 19:59
Copy link

sonarcloud bot commented May 21, 2024

Copy link
Collaborator

@wluken wluken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admin survey editing good to merge.

@MatthewBemis MatthewBemis added this pull request to the merge queue May 22, 2024
Merged via the queue into development with commit dced393 May 22, 2024
12 checks passed
@MatthewBemis MatthewBemis deleted the mb-jn-1020 branch May 22, 2024 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants