Skip to content

Commit

Permalink
Edit survey user extra properties from survey users list (#3630)
Browse files Browse the repository at this point in the history
* edit survey user extra props from list

* code cleanup

* fixed user update

* layout adjustments

* layout adjustments

---------

Co-authored-by: Stefano Ricci <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 31, 2024
1 parent 3a539ee commit fffb37b
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 74 deletions.
1 change: 1 addition & 0 deletions core/i18n/resources/en/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -41,26 +41,24 @@ export const UserAuthGroupExtraPropsEditor = (props) => {
const readOnly = !canEditSurvey

return (
<ExpansionPanel
buttonLabel="usersView.surveyExtraProp.label_other"
className="extra-props"
startClosed={Objects.isEmpty(extraOld)}
>
<div className="form">
{extraDefsArray.map(({ name, dataType }) => (
<FormItem label={name} key={name}>
<Input
value={User.getAuthGroupExtraProp(name)(userToUpdate)}
numberFormat={dataType === ExtraPropDef.dataTypes.number ? NumberFormats.decimal() : null}
readOnly={readOnly}
onChange={onInputFieldChange(name)}
readOnly={readOnly}
value={User.getAuthGroupExtraProp(name)(userToUpdate)}
/>
</FormItem>
))}
</ExpansionPanel>
{onSave && <ButtonSave onClick={onSave} />}
</div>
)
}

UserAuthGroupExtraPropsEditor.propTypes = {
onChange: PropTypes.func.isRequired,
onSave: PropTypes.func,
userToUpdate: PropTypes.object.isRequired,
}
24 changes: 16 additions & 8 deletions webapp/views/App/views/Users/UserEdit/UserEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -167,7 +169,13 @@ const UserEdit = () => {
</FormItem>
)}
{ProcessUtils.ENV.experimentalFeatures && (
<UserAuthGroupExtraPropsEditor onChange={onSurveyExtraPropsChange} userToUpdate={userToUpdate} />
<ExpansionPanel
buttonLabel="usersView.surveyExtraProp.label_other"
className="extra-props"
startClosed={Objects.isEmpty(User.getAuthGroupExtraProps(userToUpdate))}
>
<UserAuthGroupExtraPropsEditor onChange={onSurveyExtraPropsChange} userToUpdate={userToUpdate} />
</ExpansionPanel>
)}
</>
)}
Expand Down
15 changes: 12 additions & 3 deletions webapp/views/App/views/Users/UserEdit/UserEdit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const UserExtraPropEditor = (props) => {
}, [initialItem, newItem, onDelete, onEditChange])

return (
<div className="extra-props display-flex">
<div className="extra-prop display-flex">
<FormItem label="extraProp.name" labelParams={{ position: index + 1 }}>
<Input
disabled={!editing}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,29 @@ export const UserExtraPropsEditor = (props) => {

return (
<ExpansionPanel buttonLabel="extraProp.label_plural" className="extra-props" startClosed={items.length === 0}>
{items.map(({ name, newItem, uuid, value }, index) => (
<UserExtraPropEditor
key={uuid}
editingItems={editing}
index={index}
items={items}
name={name}
newItem={newItem}
onDelete={onItemDelete}
onEditChange={onItemEditChange}
onSave={onItemSave}
uuid={uuid}
value={value}
<div className="form">
{items.map(({ name, newItem, uuid, value }, index) => (
<UserExtraPropEditor
key={uuid}
editingItems={editing}
index={index}
items={items}
name={name}
newItem={newItem}
onDelete={onItemDelete}
onEditChange={onItemEditChange}
onSave={onItemSave}
uuid={uuid}
value={value}
/>
))}
<ButtonAdd
className="btn-add"
disabled={editing || items.some((item) => item.newItem)}
label="extraProp.addExtraProp"
onClick={onAdd}
/>
))}
<ButtonAdd
className="btn-add"
disabled={editing || items.some((item) => item.newItem)}
label="extraProp.addExtraProp"
onClick={onAdd}
/>
</div>
</ExpansionPanel>
)
}
Expand Down
12 changes: 6 additions & 6 deletions webapp/views/App/views/Users/UserEdit/store/actions/useOnSave.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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',
Expand All @@ -82,5 +82,5 @@ export const useOnSave = ({ userToUpdate, userToUpdateOriginal, setUserToUpdateO
await saveUser()
}
}
}, [userToUpdate, userToUpdateOriginal])
}, [dispatch, saveUser, userToUpdate, userToUpdateOriginal])
}
29 changes: 17 additions & 12 deletions webapp/views/App/views/Users/UserEdit/store/useEditUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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,
Expand Down
17 changes: 14 additions & 3 deletions webapp/views/App/views/Users/UsersListSurvey/Row/Row.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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)
Expand All @@ -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 (
<>
<div data-testid={TestId.userList.profilePicture} className="users-list__cell-profile-picture">
Expand Down Expand Up @@ -86,11 +87,21 @@ const Row = (props) => {
<div data-testid={TestId.userList.edit}>
<span className={`icon icon-12px icon-action ${canEditUser ? 'icon-pencil2' : 'icon-eye'}`} />
</div>
{canEditUser && ProcessUtils.ENV.experimentalFeatures && (
<Button
iconClassName="icon-cog"
title="usersView.editSurveyUserExtraPropsForUser"
titleParams={{ userName: User.getName(userListItem) ?? User.getEmail(userListItem) }}
onClick={(event) => onEditSurveyUserExtraProps({ event, userListItem })}
variant="text"
/>
)}
</>
)
}

Row.propTypes = {
onEditSurveyUserExtraProps: PropTypes.func.isRequired,
row: PropTypes.object.isRequired,
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { useCallback, useEffect, useState } from 'react'
import PropTypes from 'prop-types'

import * as User from '@core/user/user'

import { PanelRight } from '@webapp/components'

import { useSurveyUuid } from '@webapp/store/survey/hooks'

import { UserAuthGroupExtraPropsEditor } from '../../UserEdit/UserAuthGroupExtraPropsEditor'
import { useOnSave } from '../../UserEdit/store/actions/useOnSave'

export const SurveyUserExtraPropsEditor = (props) => {
const { onClose, onUserUpdate, userToUpdate } = props

const surveyUuid = useSurveyUuid()
const [userUpdated, setUserUpdated] = useState(userToUpdate)
const saveUser = useOnSave({ userToUpdate: userUpdated })

useEffect(() => {
const groupInCurrentSurvey = User.getAuthGroupBySurveyUuid({ surveyUuid })(userToUpdate)
const groupExtraProps = groupInCurrentSurvey?.props?.extra
setUserUpdated(User.assocAuthGroupExtraProps(groupExtraProps)(userToUpdate))
}, [surveyUuid, userToUpdate])

const onSurveyExtraPropsChange = useCallback(
(extraPropsNew) => {
setUserUpdated(User.assocAuthGroupExtraProps(extraPropsNew)(userUpdated))
},
[userUpdated]
)

const onSave = useCallback(async () => {
await saveUser()
onUserUpdate(userUpdated)
}, [onUserUpdate, saveUser, userUpdated])

return (
<PanelRight
className="survey-user-extra-props"
header="usersView.editSurveyUserExtraPropsForUser"
headerParams={{ userName: User.getName(userToUpdate) ?? User.getEmail(userToUpdate) }}
onClose={onClose}
width="55rem"
>
<UserAuthGroupExtraPropsEditor onChange={onSurveyExtraPropsChange} onSave={onSave} userToUpdate={userUpdated} />
</PanelRight>
)
}

SurveyUserExtraPropsEditor.propTypes = {
onClose: PropTypes.func.isRequired,
onUserUpdate: PropTypes.func.isRequired,
userToUpdate: PropTypes.object.isRequired,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { SurveyUserExtraPropsEditor } from './SurveyUserExtraPropsEditor'
Loading

0 comments on commit fffb37b

Please sign in to comment.