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

Edit survey user extra properties from survey users list #3630

Merged
merged 8 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2,7 +2,6 @@ import React, { useCallback } from 'react'
import PropTypes from 'prop-types'

import * as ObjectUtils from '@core/objectUtils'
import * as ProcessUtils from '@core/processUtils'
import * as Survey from '@core/survey/survey'
import { ExtraPropDef } from '@core/survey/extraPropDef'

Expand Down Expand Up @@ -53,13 +52,11 @@ export const SurveyListUserExtraPropsEditor = (props) => {
onClose={onClose}
width="55rem"
>
{ProcessUtils.ENV.experimentalFeatures && (
<SurveyUserExtraPropDefsEditor
extraPropDefs={Survey.getUserExtraPropDefs(surveyInfo)}
onExtraPropDefDelete={onSurveyExtraPropDefDelete}
onExtraPropDefUpdate={onSurveyExtraPropDefUpdate}
/>
)}
<SurveyUserExtraPropDefsEditor
extraPropDefs={Survey.getUserExtraPropDefs(surveyInfo)}
onExtraPropDefDelete={onSurveyExtraPropDefDelete}
onExtraPropDefUpdate={onSurveyExtraPropDefUpdate}
/>
</PanelRight>
)
}
Expand Down
3 changes: 2 additions & 1 deletion webapp/components/survey/Surveys/Surveys.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useDispatch } from 'react-redux'
import { useNavigate } from 'react-router'

import * as DateUtils from '@core/dateUtils'
import * as ProcessUtils from '@core/processUtils'
import * as Survey from '@core/survey/survey'
import * as Authorizer from '@core/auth/authorizer'
import { appModuleUri, homeModules } from '@webapp/app/appModules'
Expand Down Expand Up @@ -179,7 +180,7 @@ const Surveys = (props) => {
}
)
}
if (isSystemAdmin) {
if (ProcessUtils.ENV.experimentalFeatures && isSystemAdmin) {
cols.push({
key: 'edit_user_props',
header: '',
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
Loading
Loading