From fffb37ba6a28045305dcd0a90352acc611fe1344 Mon Sep 17 00:00:00 2001 From: Stefano Ricci <1219739+SteRiccio@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:48:26 +0100 Subject: [PATCH] Edit survey user extra properties from survey users list (#3630) * edit survey user extra props from list * code cleanup * fixed user update * layout adjustments * layout adjustments --------- Co-authored-by: Stefano Ricci Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- core/i18n/resources/en/common.js | 1 + .../UserAuthGroupExtraPropsEditor.js | 18 +++--- .../App/views/Users/UserEdit/UserEdit.js | 24 +++++--- .../App/views/Users/UserEdit/UserEdit.scss | 15 ++++- .../UserExtraPropEditor.js | 2 +- .../UserExtraPropsEditor.js | 42 +++++++------- .../Users/UserEdit/store/actions/useOnSave.js | 12 ++-- .../views/Users/UserEdit/store/useEditUser.js | 29 ++++++---- .../views/Users/UsersListSurvey/Row/Row.js | 17 +++++- .../SurveyUserExtraPropsEditor.js | 55 +++++++++++++++++++ .../SurveyUserExtraPropsEditor/index.js | 1 + .../Users/UsersListSurvey/UsersList.scss | 9 +++ .../Users/UsersListSurvey/UsersListSurvey.js | 42 ++++++++++---- 13 files changed, 193 insertions(+), 74 deletions(-) create mode 100644 webapp/views/App/views/Users/UsersListSurvey/SurveyUserExtraPropsEditor/SurveyUserExtraPropsEditor.js create mode 100644 webapp/views/App/views/Users/UsersListSurvey/SurveyUserExtraPropsEditor/index.js diff --git a/core/i18n/resources/en/common.js b/core/i18n/resources/en/common.js index ede3fe7107..0427538e88 100644 --- a/core/i18n/resources/en/common.js +++ b/core/i18n/resources/en/common.js @@ -898,6 +898,7 @@ Copy the invitation link to the clipboard?`, }, surveysDraft: 'Surveys (draft)', surveysPublished: 'Surveys (published)', + editSurveyUserExtraPropsForUser: 'Edit survey user extra properties for user "{{userName}}"', }, usersAccessRequestView: { diff --git a/webapp/views/App/views/Users/UserEdit/UserAuthGroupExtraPropsEditor/UserAuthGroupExtraPropsEditor.js b/webapp/views/App/views/Users/UserEdit/UserAuthGroupExtraPropsEditor/UserAuthGroupExtraPropsEditor.js index a5e20af328..7cbe47d575 100644 --- a/webapp/views/App/views/Users/UserEdit/UserAuthGroupExtraPropsEditor/UserAuthGroupExtraPropsEditor.js +++ b/webapp/views/App/views/Users/UserEdit/UserAuthGroupExtraPropsEditor/UserAuthGroupExtraPropsEditor.js @@ -7,14 +7,14 @@ import * as Survey from '@core/survey/survey' import { ExtraPropDef } from '@core/survey/extraPropDef' import * as User from '@core/user/user' -import { ExpansionPanel } from '@webapp/components' import { FormItem, Input, NumberFormats } from '@webapp/components/form/Input' import { useSurveyInfo } from '@webapp/store/survey' import { useAuthCanEditSurvey } from '@webapp/store/user' +import { ButtonSave } from '@webapp/components' export const UserAuthGroupExtraPropsEditor = (props) => { - const { onChange, userToUpdate } = props + const { onChange, onSave, userToUpdate } = props const canEditSurvey = useAuthCanEditSurvey() const surveyInfo = useSurveyInfo() @@ -41,26 +41,24 @@ export const UserAuthGroupExtraPropsEditor = (props) => { const readOnly = !canEditSurvey return ( - +
{extraDefsArray.map(({ name, dataType }) => ( ))} - + {onSave && } +
) } UserAuthGroupExtraPropsEditor.propTypes = { onChange: PropTypes.func.isRequired, + onSave: PropTypes.func, userToUpdate: PropTypes.object.isRequired, } diff --git a/webapp/views/App/views/Users/UserEdit/UserEdit.js b/webapp/views/App/views/Users/UserEdit/UserEdit.js index 1bb4d65288..381554dfca 100644 --- a/webapp/views/App/views/Users/UserEdit/UserEdit.js +++ b/webapp/views/App/views/Users/UserEdit/UserEdit.js @@ -3,28 +3,30 @@ import './UserEdit.scss' import React from 'react' import { useNavigate, useParams } from 'react-router' +import { Objects } from '@openforis/arena-core' + +import * as AuthGroup from '@core/auth/authGroup' +import * as ProcessUtils from '@core/processUtils' import * as Survey from '@core/survey/survey' import * as User from '@core/user/user' import * as Validation from '@core/validation/validation' -import * as AuthGroup from '@core/auth/authGroup' -import * as ProcessUtils from '@core/processUtils' -import ProfilePicture from '@webapp/components/profilePicture' -import { FormItem, Input, NumberFormats } from '@webapp/components/form/Input' +import { Button, ButtonDelete, ButtonInvite, ButtonSave, ExpansionPanel } from '@webapp/components' import Checkbox from '@webapp/components/form/checkbox' import DropdownUserTitle from '@webapp/components/form/DropdownUserTitle' -import { ButtonSave, ButtonDelete, ButtonInvite, Button } from '@webapp/components' +import { FormItem, Input, NumberFormats } from '@webapp/components/form/Input' +import ProfilePicture from '@webapp/components/profilePicture' import { appModuleUri, userModules } from '@webapp/app/appModules' import { useSurveyInfo } from '@webapp/store/survey' import { useI18n } from '@webapp/store/system' import { useAuthCanUseMap } from '@webapp/store/user/hooks' -import { useEditUser } from './store' import DropdownUserGroup from '../DropdownUserGroup' import ProfilePictureEditor from './ProfilePictureEditor' -import { UserExtraPropsEditor } from './UserExtraPropsEditor' +import { useEditUser } from './store' import { UserAuthGroupExtraPropsEditor } from './UserAuthGroupExtraPropsEditor/UserAuthGroupExtraPropsEditor' +import { UserExtraPropsEditor } from './UserExtraPropsEditor' const UserEdit = () => { const { userUuid } = useParams() @@ -167,7 +169,13 @@ const UserEdit = () => { )} {ProcessUtils.ENV.experimentalFeatures && ( - + + + )} )} diff --git a/webapp/views/App/views/Users/UserEdit/UserEdit.scss b/webapp/views/App/views/Users/UserEdit/UserEdit.scss index cabecc84f6..e38c5644e8 100644 --- a/webapp/views/App/views/Users/UserEdit/UserEdit.scss +++ b/webapp/views/App/views/Users/UserEdit/UserEdit.scss @@ -32,9 +32,18 @@ } .extra-props { - .form-item { - display: flex; - white-space: nowrap; + .form { + height: auto; + grid-row-gap: 0; + + .form-item { + width: 20rem; + white-space: nowrap; + + .form-input-container { + width: 12rem; + } + } } .btn-add { justify-self: center; diff --git a/webapp/views/App/views/Users/UserEdit/UserExtraPropsEditor/UserExtraPropEditor.js b/webapp/views/App/views/Users/UserEdit/UserExtraPropsEditor/UserExtraPropEditor.js index 0999da5e3d..34d34479e4 100644 --- a/webapp/views/App/views/Users/UserEdit/UserExtraPropsEditor/UserExtraPropEditor.js +++ b/webapp/views/App/views/Users/UserEdit/UserExtraPropsEditor/UserExtraPropEditor.js @@ -101,7 +101,7 @@ export const UserExtraPropEditor = (props) => { }, [initialItem, newItem, onDelete, onEditChange]) return ( -
+
{ return ( - {items.map(({ name, newItem, uuid, value }, index) => ( - + {items.map(({ name, newItem, uuid, value }, index) => ( + + ))} + item.newItem)} + label="extraProp.addExtraProp" + onClick={onAdd} /> - ))} - item.newItem)} - label="extraProp.addExtraProp" - onClick={onAdd} - /> +
) } diff --git a/webapp/views/App/views/Users/UserEdit/store/actions/useOnSave.js b/webapp/views/App/views/Users/UserEdit/store/actions/useOnSave.js index 2de42234cc..55340b40ce 100644 --- a/webapp/views/App/views/Users/UserEdit/store/actions/useOnSave.js +++ b/webapp/views/App/views/Users/UserEdit/store/actions/useOnSave.js @@ -14,13 +14,13 @@ import { useSurveyId } from '@webapp/store/survey' import { validateUserEdit } from './validate' -export const useOnSave = ({ userToUpdate, userToUpdateOriginal, setUserToUpdateOriginal }) => { +export const useOnSave = ({ userToUpdate, userToUpdateOriginal = null, setUserToUpdateOriginal = null }) => { const dispatch = useDispatch() const { hideSurveyGroup } = useQuery() const user = useUser() const surveyId = useSurveyId() - const saveUser = async () => { + const saveUser = useCallback(async () => { const editingSelf = User.isEqual(user)(userToUpdate) const userToUpdateUuid = User.getUuid(userToUpdate) const profilePicture = User.getProfilePicture(userToUpdate) @@ -61,17 +61,17 @@ export const useOnSave = ({ userToUpdate, userToUpdateOriginal, setUserToUpdateO params: { name: User.getName(userToUpdate) }, }) ) - setUserToUpdateOriginal(userToUpdate) + setUserToUpdateOriginal?.(userToUpdate) } finally { dispatch(LoaderActions.hideLoader()) } - } + }, [dispatch, hideSurveyGroup, setUserToUpdateOriginal, surveyId, user, userToUpdate]) return useCallback(async () => { const userUpdatedValidated = await validateUserEdit(userToUpdate) if (Validation.isObjValid(userUpdatedValidated)) { - if (User.isSystemAdmin(userToUpdate) && !User.isSystemAdmin(userToUpdateOriginal)) { + if (userToUpdateOriginal && User.isSystemAdmin(userToUpdate) && !User.isSystemAdmin(userToUpdateOriginal)) { dispatch( DialogConfirmActions.showDialogConfirm({ key: 'usersView.confirmUserWillBeSystemAdmin', @@ -82,5 +82,5 @@ export const useOnSave = ({ userToUpdate, userToUpdateOriginal, setUserToUpdateO await saveUser() } } - }, [userToUpdate, userToUpdateOriginal]) + }, [dispatch, saveUser, userToUpdate, userToUpdateOriginal]) } diff --git a/webapp/views/App/views/Users/UserEdit/store/useEditUser.js b/webapp/views/App/views/Users/UserEdit/store/useEditUser.js index 5cc3405700..fd6222a5b4 100644 --- a/webapp/views/App/views/Users/UserEdit/store/useEditUser.js +++ b/webapp/views/App/views/Users/UserEdit/store/useEditUser.js @@ -87,14 +87,17 @@ export const useEditUser = ({ userUuid }) => { onUpdate(userUpdated) } - const onMapApiKeyTest = useCallback(async ({ provider, apiKey }) => { - const success = await API.testMapApiKey({ provider, apiKey }) - if (success) { - dispatch(NotificationActions.notifyInfo({ key: 'user.mapApiKeys.keyIsCorrect' })) - } else { - dispatch(NotificationActions.notifyError({ key: 'user.mapApiKeys.keyIsNotCorrect' })) - } - }, []) + const onMapApiKeyTest = useCallback( + async ({ provider, apiKey }) => { + const success = await API.testMapApiKey({ provider, apiKey }) + if (success) { + dispatch(NotificationActions.notifyInfo({ key: 'user.mapApiKeys.keyIsCorrect' })) + } else { + dispatch(NotificationActions.notifyError({ key: 'user.mapApiKeys.keyIsNotCorrect' })) + } + }, + [dispatch] + ) const onExtraChange = useCallback( (extra) => { @@ -103,10 +106,12 @@ export const useEditUser = ({ userUuid }) => { [onUpdate, userToUpdate] ) - const onSurveyExtraPropsChange = (extraPropsNew) => { - const userUpdated = User.assocAuthGroupExtraProps(extraPropsNew)(userToUpdate) - onUpdate(userUpdated) - } + const onSurveyExtraPropsChange = useCallback( + (extraPropsNew) => { + onUpdate(User.assocAuthGroupExtraProps(extraPropsNew)(userToUpdate)) + }, + [onUpdate, userToUpdate] + ) return { hideSurveyGroup, diff --git a/webapp/views/App/views/Users/UsersListSurvey/Row/Row.js b/webapp/views/App/views/Users/UsersListSurvey/Row/Row.js index 2287739978..63a80652dc 100644 --- a/webapp/views/App/views/Users/UsersListSurvey/Row/Row.js +++ b/webapp/views/App/views/Users/UsersListSurvey/Row/Row.js @@ -5,6 +5,7 @@ import * as AuthGroup from '@core/auth/authGroup' import * as Survey from '@core/survey/survey' import * as User from '@core/user/user' import * as DateUtils from '@core/dateUtils' +import * as ProcessUtils from '@core/processUtils' import { TestId } from '@webapp/utils/testId' import { useI18n } from '@webapp/store/system' @@ -17,13 +18,15 @@ import ProfilePicture from '@webapp/components/profilePicture' import { CopyInvitationLinkButton } from './CopyInvitationLinkButton' const Row = (props) => { - const { row: userListItem } = props + const { onEditSurveyUserExtraProps, row: userListItem } = props const surveyInfo = useSurveyInfo() const surveyUuid = Survey.getUuid(surveyInfo) const i18n = useI18n() const canEditUser = useAuthCanEditUser(userListItem) const emailVisible = useAuthCanViewOtherUsersEmail() + const handleResendInvitation = useOnInviteRepeat({ userToInvite: userListItem, hasToNavigate: false }) + const authGroup = User.getAuthGroupBySurveyUuid({ surveyUuid, defaultToMainGroup: true })(userListItem) const authGroupName = AuthGroup.getName(authGroup) const userUuid = User.getUuid(userListItem) @@ -34,8 +37,6 @@ const Row = (props) => { const lastLoginTime = User.getLastLoginTime(userListItem) const lastLoginTimeFormatted = DateUtils.convertDateTimeFromISOToDisplay(lastLoginTime) ?? '' - const handleResendInvitation = useOnInviteRepeat({ userToInvite: userListItem, hasToNavigate: false }) - return ( <>
@@ -86,11 +87,21 @@ const Row = (props) => {
+ {canEditUser && ProcessUtils.ENV.experimentalFeatures && ( +