From 1d9820a59b055fcb39fd476ec53631072ac871e5 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Tue, 19 May 2020 23:42:17 -0300 Subject: [PATCH] [NEW] Added custom fields to Add/Edit user (#17681) Co-authored-by: Guilherme Gazzo --- client/admin/users/AddUser.js | 161 +++++--------------- client/admin/users/CustomFieldsForm.js | 80 ++++++++++ client/admin/users/EditUser.js | 159 ++++++------------- client/admin/users/UserForm.js | 125 +++++++++++++++ client/helpers/capitalize.js | 4 + client/hooks/useEndpointDataExperimental.js | 7 +- client/hooks/useForm.js | 11 +- 7 files changed, 303 insertions(+), 244 deletions(-) create mode 100644 client/admin/users/CustomFieldsForm.js create mode 100644 client/admin/users/UserForm.js create mode 100644 client/helpers/capitalize.js diff --git a/client/admin/users/AddUser.js b/client/admin/users/AddUser.js index 3b1076655daf..6547c9d8e00a 100644 --- a/client/admin/users/AddUser.js +++ b/client/admin/users/AddUser.js @@ -1,147 +1,68 @@ -import React, { useMemo, useState, useCallback } from 'react'; -import { Field, TextInput, Box, ToggleSwitch, Icon, TextAreaInput, MultiSelectFiltered, Margins, Button } from '@rocket.chat/fuselage'; +import React, { useMemo, useCallback } from 'react'; +import { Field, Box, Button } from '@rocket.chat/fuselage'; import { useTranslation } from '../../contexts/TranslationContext'; import { useEndpointData } from '../../hooks/useEndpointData'; import { useEndpointAction } from '../../hooks/useEndpointAction'; -import { isEmail } from '../../../app/utils/lib/isEmail.js'; import { useRoute } from '../../contexts/RouterContext'; -import VerticalBar from '../../components/basic/VerticalBar'; +import { useForm } from '../../hooks/useForm'; +import UserForm from './UserForm'; export function AddUser({ roles, ...props }) { const t = useTranslation(); - const [newData, setNewData] = useState({}); - const router = useRoute('admin-users'); const roleData = useEndpointData('roles.list', '') || {}; + const { + values, + handlers, + reset, + hasUnsavedChanges, + } = useForm({ + roles: [], + name: '', + username: '', + statusText: '', + bio: '', + email: '', + password: '', + verified: false, + requirePasswordChange: false, + setRandomPassword: false, + sendWelcomeEmail: true, + joinDefaultChannels: true, + customFields: {}, + }); + const goToUser = (id) => router.push({ context: 'info', id, }); - const saveQuery = useMemo(() => ({ - ...Object.fromEntries(Object.entries(newData).filter(([, value]) => value !== null)), - }), [JSON.stringify(newData)]); + const saveQuery = useMemo(() => values, [JSON.stringify(values)]); const saveAction = useEndpointAction('POST', 'users.create', saveQuery, t('User_created_successfully')); - const handleSave = async () => { - if (Object.keys(newData).length) { - const result = await saveAction(); - if (result.success) { - goToUser(result.user._id); - } + const handleSave = useCallback(async () => { + const result = await saveAction(); + if (result.success) { + goToUser(result.user._id); } - }; - - const handleChange = (field, getValue = (e) => e.currentTarget.value) => (e) => setNewData({ ...newData, [field]: getValue(e) }); + }, [saveAction]); - const { - roles: selectedRoles = [], - name = '', - username = '', - statusText = '', - bio = '', - email = '', - password = '', - verified = false, - requirePasswordChange = false, - setRandomPassword = false, - sendWelcomeEmail = true, - joinDefaultChannels = true, - } = newData; + const availableRoles = useMemo(() => (roleData && roleData.roles ? roleData.roles.map(({ _id, description }) => [_id, description || _id]) : []), [JSON.stringify(roleData)]); - const availableRoles = roleData && roleData.roles ? roleData.roles.map(({ _id, description }) => [_id, description || _id]) : []; + const append = useMemo(() => + + + + + + + , [reset, handleSave]); - return e.preventDefault(), [])} { ...props }> - - {t('Name')} - - - - - - {t('Username')} - - }/> - - - - {t('Email')} - - 0 ? 'error' : undefined} onChange={handleChange('email')} addon={}/> - - - - {t('Verified')} !verified)} /> - - - - - {t('StatusMessage')} - - }/> - - - - {t('Bio')} - - }/> - - - - {t('Password')} - - }/> - - - - - - {t('Require_password_change')} !requirePasswordChange)} /> - - - - - - - {t('Set_random_password_and_send_by_email')} !setRandomPassword)} /> - - - - - {t('Roles')} - - value)} placeholder={t('Select_role')} /> - - - - - - {t('Join_default_channels')} !joinDefaultChannels)} /> - - - - - - - {t('Send_welcome_email')} !sendWelcomeEmail)} /> - - - - - - - - - - - - - - ; + return ; } diff --git a/client/admin/users/CustomFieldsForm.js b/client/admin/users/CustomFieldsForm.js new file mode 100644 index 000000000000..e6ee3074fa5b --- /dev/null +++ b/client/admin/users/CustomFieldsForm.js @@ -0,0 +1,80 @@ +import React, { useMemo, useEffect } from 'react'; +import { TextInput, Select, Field, Divider, Box } from '@rocket.chat/fuselage'; + +import { useSetting } from '../../contexts/SettingsContext'; +import { useForm } from '../../hooks/useForm'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { capitalize } from '../../helpers/capitalize'; + +const CustomTextInput = (props) => { + const t = useTranslation(); + const { name, required, minLength, maxLength, setState, state } = props; + const verify = useMemo(() => { + const error = []; + if (!state && required) { error.push(t('Field_required')); } + if (state.length < minLength) { error.push(t('Min_length_is', minLength)); } + return error.join(', '); + }, [required, minLength, maxLength, state]); + + return useMemo(() => + {name} + + setState(e.currentTarget.value)}/> + + {verify} + , [name, verify, state, required]); +}; + +const CustomSelect = (props) => { + const t = useTranslation(); + const { name, required, options, setState, state } = props; + const mappedOptions = useMemo(() => Object.values(options).map((value) => [value, value]), [...options]); + const verify = useMemo(() => (!state.length && required ? t('Field_required') : ''), [required, state]); + + return useMemo(() => + {name} + +