Skip to content

Commit

Permalink
feat: ✨ Implement multiple user creation flow
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rique223 committed Oct 9, 2023
1 parent 33b3ff6 commit a1f9183
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 33 deletions.
32 changes: 32 additions & 0 deletions apps/meteor/client/views/admin/users/AdminUserCreated.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<ContextualbarScrollableContent h='100%' fontScale='p1m'>
{t('You_have_created_one_user')}
</ContextualbarScrollableContent>
<ContextualbarFooter>
<ButtonGroup stretch>
<Button type='reset' w='50%' onClick={() => router.navigate(`/admin/users/new`)}>
{t('Add_more_users')}
</Button>
<Button primary w='50%' onClick={() => goToUser(uid)}>
{t('Done')}
</Button>
</ButtonGroup>
</ContextualbarFooter>
</>
);
};

export default AdminUserCreated;
59 changes: 27 additions & 32 deletions apps/meteor/client/views/admin/users/AdminUserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
Icon,
FieldGroup,
ContextualbarFooter,
ButtonGroup,
Button,
Callout,
} from '@rocket.chat/fuselage';
Expand All @@ -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';
Expand All @@ -54,10 +53,12 @@ const getInitialValue = ({
data,
defaultUserRoles,
isSmtpEnabled,
isNewUserPage,
}: {
data?: Serialized<IUser>;
defaultUserRoles?: IUser['roles'];
isSmtpEnabled?: boolean;
isNewUserPage?: boolean;
}): userFormProps => ({
roles: data?.roles ?? defaultUserRoles,
name: data?.name ?? '',
Expand All @@ -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 ?? '',
Expand All @@ -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 || '');
Expand All @@ -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) => {
Expand Down Expand Up @@ -194,7 +198,7 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => {
/>
</Field>
)}
<Field color='hint'>{t('Manually_created_users_briefing')}</Field>
{!userData?._id && <Box color='hint'>{t('Manually_created_users_briefing')}</Box>}
<Field>
<Field.Label htmlFor={emailId}>{t('Email')}</Field.Label>
<Field.Row>
Expand Down Expand Up @@ -520,18 +524,9 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => {
</FieldGroup>
</ContextualbarScrollableContent>
<ContextualbarFooter>
<ButtonGroup stretch>
{/* <Button
type='reset'
disabled={!isDirty}
onClick={() => reset(getInitialValue({ data: userData, defaultUserRoles, isSmtpEnabled }))}
>
{t('Reset')}
</Button> */}
<Button primary disabled={!isDirty} onClick={handleSubmit(handleSaveUser)}>
{t('Add_user')}
</Button>
</ButtonGroup>
<Button primary disabled={!isDirty} onClick={handleSubmit(handleSaveUser)} w='100%'>
{t('Add_user')}
</Button>
</ContextualbarFooter>
</>
);
Expand Down
4 changes: 3 additions & 1 deletion apps/meteor/client/views/admin/users/AdminUsersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -90,7 +91,7 @@ const UsersPage = (): ReactElement => {
<ContextualbarTitle>
{context === 'info' && t('User_Info')}
{context === 'edit' && t('Edit_User')}
{context === 'new' && (
{(context === 'new' || context === 'created') && (
<>
<Icon name='user-plus' size={20} /> {t('New_user')}
</>
Expand All @@ -102,6 +103,7 @@ const UsersPage = (): ReactElement => {
{context === 'info' && id && <AdminUserInfoWithData uid={id} onReload={handleReload} />}
{context === 'edit' && id && <AdminUserFormWithData uid={id} onReload={handleReload} />}
{context === 'new' && <AdminUserForm onReload={handleReload} />}
{context === 'created' && id && <AdminUserCreated uid={id} />}
{context === 'invite' && <AdminInviteUsers />}
</Contextualbar>
)}
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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.",
Expand Down

0 comments on commit a1f9183

Please sign in to comment.