From a1f91839787e6a62a1257cea504b416d5e85afda Mon Sep 17 00:00:00 2001 From: rique223 Date: Mon, 9 Oct 2023 18:40:32 -0300 Subject: [PATCH] feat: :sparkles: Implement multiple user creation flow Added a new screen to enhance the user creation experience. This screen appears immediately after you create a new user. On this page, you have two options: you can either complete the process and view the user you just created, or you can return to the form to create another user without exiting the contextual bar. Additionally, I've made some minor logic improvements and removed commented-out code. --- .../views/admin/users/AdminUserCreated.tsx | 32 ++++++++++ .../views/admin/users/AdminUserForm.tsx | 59 +++++++++---------- .../views/admin/users/AdminUsersPage.tsx | 4 +- .../rocketchat-i18n/i18n/en.i18n.json | 2 + 4 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 apps/meteor/client/views/admin/users/AdminUserCreated.tsx diff --git a/apps/meteor/client/views/admin/users/AdminUserCreated.tsx b/apps/meteor/client/views/admin/users/AdminUserCreated.tsx new file mode 100644 index 000000000000..f69a0911e0ac --- /dev/null +++ b/apps/meteor/client/views/admin/users/AdminUserCreated.tsx @@ -0,0 +1,32 @@ +import { Button, ButtonGroup, ContextualbarFooter } from '@rocket.chat/fuselage'; +import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; +import React, { useCallback } from 'react'; + +import { ContextualbarScrollableContent } from '../../../components/Contextualbar'; + +const AdminUserCreated = ({ uid }: { uid: string }) => { + const t = useTranslation(); + const router = useRouter(); + + const goToUser = useCallback((id) => router.navigate(`/admin/users/info/${id}`), [router]); + + return ( + <> + + {t('You_have_created_one_user')} + + + + + + + + + ); +}; + +export default AdminUserCreated; diff --git a/apps/meteor/client/views/admin/users/AdminUserForm.tsx b/apps/meteor/client/views/admin/users/AdminUserForm.tsx index beff65ba56a2..09386a093e59 100644 --- a/apps/meteor/client/views/admin/users/AdminUserForm.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserForm.tsx @@ -10,7 +10,6 @@ import { Icon, FieldGroup, ContextualbarFooter, - ButtonGroup, Button, Callout, } from '@rocket.chat/fuselage'; @@ -27,7 +26,7 @@ import { useTranslation, } from '@rocket.chat/ui-contexts'; import { useQuery, useMutation } from '@tanstack/react-query'; -import React, { useCallback, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { validateEmail } from '../../../../lib/emailValidator'; @@ -54,10 +53,12 @@ const getInitialValue = ({ data, defaultUserRoles, isSmtpEnabled, + isNewUserPage, }: { data?: Serialized; defaultUserRoles?: IUser['roles']; isSmtpEnabled?: boolean; + isNewUserPage?: boolean; }): userFormProps => ({ roles: data?.roles ?? defaultUserRoles, name: data?.name ?? '', @@ -67,8 +68,8 @@ const getInitialValue = ({ nickname: data?.nickname ?? '', email: (data?.emails?.length && data.emails[0].address) || '', verified: (data?.emails?.length && data.emails[0].verified) || false, - setRandomPassword: true, - setPasswordManually: false, + setRandomPassword: isNewUserPage, + setPasswordManually: !isNewUserPage, requirePasswordChange: data?.requirePasswordChange || false, customFields: data?.customFields ?? {}, statusText: data?.statusText ?? '', @@ -93,29 +94,32 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => { const { data } = useSmtpQuery(); const isSmtpEnabled = data?.isSMTPConfigured; - const eventStats = useEndpointAction('POST', '/v1/statistics.telemetry'); - const updateUserAction = useEndpoint('POST', '/v1/users.update'); - const createUserAction = useEndpoint('POST', '/v1/users.create'); - - const getRoles = useEndpoint('GET', '/v1/roles.list'); - const { data: roleData, error: roleError } = useQuery(['roles'], async () => getRoles()); - - const availableRoles: SelectOption[] = roleData?.roles.map(({ _id, name, description }) => [_id, description || name]) || []; - - const goToUser = useCallback((id) => router.navigate(`/admin/users/info/${id}`), [router]); - const { control, watch, handleSubmit, - // reset, formState: { errors, isDirty }, setValue, + resetField, } = useForm({ - defaultValues: getInitialValue({ data: userData, defaultUserRoles, isSmtpEnabled }), + defaultValues: getInitialValue({ data: userData, defaultUserRoles, isSmtpEnabled, isNewUserPage: !userData?._id }), mode: 'onBlur', }); + useEffect(() => { + resetField('sendWelcomeEmail', { defaultValue: isSmtpEnabled }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isSmtpEnabled]); + + const eventStats = useEndpointAction('POST', '/v1/statistics.telemetry'); + const updateUserAction = useEndpoint('POST', '/v1/users.update'); + const createUserAction = useEndpoint('POST', '/v1/users.create'); + + const getRoles = useEndpoint('GET', '/v1/roles.list'); + const { data: roleData, error: roleError } = useQuery(['roles'], async () => getRoles()); + + const availableRoles: SelectOption[] = roleData?.roles.map(({ _id, name, description }) => [_id, description || name]) || []; + const { avatar, username, setRandomPassword, password } = watch(); const updateAvatar = useUpdateAvatar(avatar, userData?._id || ''); @@ -135,12 +139,12 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => { const handleCreateUser = useMutation({ mutationFn: createUserAction, - onSuccess: async (data) => { + onSuccess: async ({ user: { _id } }) => { dispatchToastMessage({ type: 'success', message: t('User_created_successfully!') }); await eventStats({ params: [{ eventName: 'updateCounter', settingsId: 'Manual_Entry_User_Count' }], }); - goToUser(data.user._id); + router.navigate(`/admin/users/created/${_id}`); onReload(); }, onError: (error) => { @@ -194,7 +198,7 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => { /> )} - {t('Manually_created_users_briefing')} + {!userData?._id && {t('Manually_created_users_briefing')}} {t('Email')} @@ -520,18 +524,9 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => { - - {/* */} - - + ); diff --git a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx index 1829766aa5cc..284e31561f81 100644 --- a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx +++ b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx @@ -8,6 +8,7 @@ import { useSeatsCap } from '../../../../ee/client/views/admin/users/useSeatsCap import { Contextualbar, ContextualbarHeader, ContextualbarTitle, ContextualbarClose } from '../../../components/Contextualbar'; import Page from '../../../components/Page'; import AdminInviteUsers from './AdminInviteUsers'; +import AdminUserCreated from './AdminUserCreated'; import AdminUserForm from './AdminUserForm'; import AdminUserFormWithData from './AdminUserFormWithData'; import AdminUserInfoWithData from './AdminUserInfoWithData'; @@ -90,7 +91,7 @@ const UsersPage = (): ReactElement => { {context === 'info' && t('User_Info')} {context === 'edit' && t('Edit_User')} - {context === 'new' && ( + {(context === 'new' || context === 'created') && ( <> {t('New_user')} @@ -102,6 +103,7 @@ const UsersPage = (): ReactElement => { {context === 'info' && id && } {context === 'edit' && id && } {context === 'new' && } + {context === 'created' && id && } {context === 'invite' && } )} diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index b1135a97a849..7d7440bdec82 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -307,6 +307,7 @@ "Add_files_from": "Add files from", "Add_manager": "Add manager", "Add_monitor": "Add monitor", + "Add_more_users": "Add more users", "Add_Reaction": "Add reaction", "Add_Role": "Add Role", "Add_Sender_To_ReplyTo": "Add Sender to Reply-To", @@ -5769,6 +5770,7 @@ "You_have_a_new_message": "You have a new message", "You_have_been_muted": "You have been muted and cannot speak in this room", "You_have_been_removed_from__roomName_": "You've been removed from the room {{roomName}}", + "You_have_created_one_user": "You’ve created 1 user", "You_have_joined_a_new_call_with": "You have joined a new call with", "You_have_n_codes_remaining": "You have {{number}} codes remaining.", "You_have_not_verified_your_email": "You have not verified your email.",