refactor(sh-admin): improved error handling and dynamic user actions in admin dashboard (#4044)

* feat: new helper functions for better error management

* refactor: new i18n strings

* refactor: better error handling in invite modal and members component

* refactor: better user management

* refactor: better error handling in config handler

* refactor: updated logic of dynamic action row

* refactor: better naming for computed properties

* feat: new error message when an admin tries to invite himself

* refactor: updated error message when user is already invited

* refactor: reverted i18n string for user already invited back to the old string

* refactor: removed show prop from invite modal

* refactor: improved implementation for getting the compiled error messages

* feat: new error message when email inputted is of an invalid format

* refactor: minor optimization

---------

Co-authored-by: jamesgeorge007 <jamesgeorge998001@gmail.com>
This commit is contained in:
Joel Jacob Stephen
2024-06-03 17:17:46 +05:30
committed by GitHub
parent 5fd7c28894
commit 5805826994
8 changed files with 154 additions and 73 deletions

View File

@@ -174,18 +174,21 @@
class="py-4 border-divider rounded-r-none bg-emerald-800 text-secondaryDark"
/>
<HoppButtonSecondary
v-if="areNonAdminsSelected"
:icon="IconUserCheck"
:label="t('users.make_admin')"
class="py-4 border-divider border-r-1 rounded-none hover:bg-emerald-600"
@click="confirmUsersToAdmin = true"
/>
<HoppButtonSecondary
v-if="areAdminsSelected"
:icon="IconUserMinus"
:label="t('users.remove_admin_status')"
class="py-4 border-divider border-r-1 rounded-none hover:bg-orange-500"
@click="confirmAdminsToUsers = true"
/>
<HoppButtonSecondary
v-if="areNonAdminsSelected"
:icon="IconTrash"
:label="t('users.delete_users')"
class="py-4 border-divider rounded-none hover:bg-red-500"
@@ -203,7 +206,7 @@
</div>
<UsersInviteModal
:show="showInviteUserModal"
v-if="showInviteUserModal"
@hide-modal="showInviteUserModal = false"
@send-invite="sendInvite"
/>
@@ -258,10 +261,7 @@ import {
UsersListQuery,
UsersListV2Document,
} from '~/helpers/backend/graphql';
import {
ONLY_ONE_ADMIN_ACCOUNT_FOUND,
USER_ALREADY_INVITED,
} from '~/helpers/errors';
import { getCompiledErrorMessage } from '~/helpers/errors';
import { handleUserDeletion } from '~/helpers/userManagement';
import IconCheck from '~icons/lucide/check';
import IconLeft from '~icons/lucide/chevron-left';
@@ -291,6 +291,7 @@ const headings = [
// Get Paginated Results of all the users in the infra
const usersPerPage = 20;
const {
fetching,
error,
@@ -306,6 +307,19 @@ const {
// Selected Rows
const selectedRows = ref<UsersListQuery['infra']['allUsers']>([]);
const areAdminsSelected = computed(() =>
selectedRows.value.some((user) => user.isAdmin)
);
const areNonAdminsSelected = computed(() => {
// No Admins selected implicitly conveys that all the selected users are non-Admins assuming `selectedRows.length` > 0 (markup render condition)
if (!areAdminsSelected.value) {
return true;
}
return selectedRows.value.some((user) => !user.isAdmin);
});
// Ensure this variable is declared outside the debounce function
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
@@ -442,9 +456,12 @@ const sendInvite = async (email: string) => {
const variables = { inviteeEmail: email.trim() };
const result = await sendInvitation.executeMutation(variables);
if (result.error) {
if (result.error.message === USER_ALREADY_INVITED)
toast.error(t('state.user_already_invited'));
else toast.error(t('state.email_failure'));
const { message } = result.error;
const compiledErrorMessage = getCompiledErrorMessage(message);
compiledErrorMessage
? toast.error(t(compiledErrorMessage))
: toast.error(t('state.email_failure'));
} else {
toast.success(t('state.email_success'));
showInviteUserModal.value = false;
@@ -522,8 +539,10 @@ const makeAdminsToUsers = async (id: string | null) => {
const variables = { userUIDs };
const result = await adminsToUser.executeMutation(variables);
if (result.error) {
if (result.error.message === ONLY_ONE_ADMIN_ACCOUNT_FOUND) {
return toast.error(t('state.remove_admin_failure_only_one_admin'));
const compiledErrorMessage = getCompiledErrorMessage(result.error.message);
if (compiledErrorMessage) {
return toast.error(t(getCompiledErrorMessage(result.error.message)));
}
toast.error(