Skip to content

Commit

Permalink
refactor: leverage helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesgeorge007 committed Mar 27, 2024
1 parent 80b9941 commit 17db483
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 87 deletions.
121 changes: 121 additions & 0 deletions packages/hoppscotch-sh-admin/src/helpers/userManagement.ts
@@ -0,0 +1,121 @@
import { useToast } from '~/composables/toast';
import { getI18n } from '~/modules/i18n';
import { UserDeletionResult } from './backend/graphql';
import { ADMIN_CANNOT_BE_DELETED, USER_IS_OWNER } from './errors';

type IndividualActionInput = {
type: 'individual';
metadata: null;
};
type BulkActionInput = {
type: 'bulk';
metadata: {
areMultipleUsersSelected: boolean;
deletedIDs: string[];
};
};

type IndividualActionResult = {
data: null;
};
type BulkActionResult = {
data: { timeoutID: NodeJS.Timeout | null };
};

type HandleUserDeletion = {
(
deletedUsersList: UserDeletionResult[],
action: IndividualActionInput | BulkActionInput
): IndividualActionResult | BulkActionResult;
};

const t = getI18n();
const toast = useToast();

export const handleUserDeletion: HandleUserDeletion = (
deletedUsersList,
action
) => {
let timeoutID: NodeJS.Timeout | null = null;

const uniqueErrorMessages = new Set(
deletedUsersList.map(({ errorMessage }) => errorMessage).filter(Boolean)
) as Set<string>;

const { type, metadata } = action;

// Show the success toast based on the action type if there are no errors
if (uniqueErrorMessages.size === 0) {
if (type === 'bulk') {
toast.success(
metadata.areMultipleUsersSelected
? t('state.delete_user_success')
: t('state.delete_users_success')
);

return { type, data: { timeoutID } };
}

toast.success(t('state.delete_user_success'));
return { type, data: null };
}

const errMsgMap = {
[ADMIN_CANNOT_BE_DELETED]:
type === 'bulk'
? t('state.remove_admin_for_deletion')
: t('state.remove_admin_to_delete_user'),

[USER_IS_OWNER]:
type === 'bulk'
? t('state.remove_owner_for_deletion')
: t('state.remove_owner_to_delete_user'),
};
const errMsgMapKeys = Object.keys(errMsgMap);

if (type === 'bulk') {
const { areMultipleUsersSelected, deletedIDs } = metadata;

// Show toast messages with the count of users deleted only if multiple users are selected
if (areMultipleUsersSelected) {
toast.success(
t('state.delete_some_users_success', { count: deletedIDs.length })
);
toast.error(
t('state.delete_some_users_failure', {
count: deletedUsersList.length - deletedIDs.length,
})
);
}
}

uniqueErrorMessages.forEach((errorMessage) => {
if (errMsgMapKeys.includes(errorMessage)) {
if (type === 'bulk') {
timeoutID = setTimeout(
() => {
toast.error(errMsgMap[errorMessage as keyof typeof errMsgMap]);
},
metadata.areMultipleUsersSelected ? 2000 : 0
);

return;
}

toast.error(errMsgMap[errorMessage as keyof typeof errMsgMap]);
}
});

// Fallback for the case where the error message is not in the compiled list
if (
Array.from(uniqueErrorMessages).some(
(key) => !((key as string) in errMsgMap)
)
) {
type === 'bulk' && metadata.areMultipleUsersSelected
? t('state.delete_users_failure')
: t('state.delete_user_failure');
}

return { data: type === 'bulk' ? { timeoutID } : null };
};
21 changes: 20 additions & 1 deletion packages/hoppscotch-sh-admin/src/modules/i18n.ts
@@ -1,7 +1,23 @@
import { createI18n } from 'vue-i18n';
import { I18n, createI18n } from 'vue-i18n';
import { HoppModule } from '.';
import messages from '@intlify/unplugin-vue-i18n/messages';

// A reference to the i18n instance
let i18nInstance: I18n<
Record<string, unknown>,
Record<string, unknown>,
Record<string, unknown>,
string,
false
> | null = null;

/**
* Returns the i18n instance
*/
export function getI18n() {
return i18nInstance!.global.t;
}

export default <HoppModule>{
onVueAppInit(app) {
const i18n = createI18n({
Expand All @@ -11,6 +27,9 @@ export default <HoppModule>{
legacy: false,
allowComposition: true,
});

app.use(i18n);

i18nInstance = i18n;
},
};
35 changes: 5 additions & 30 deletions packages/hoppscotch-sh-admin/src/pages/users/_id.vue
Expand Up @@ -73,7 +73,7 @@ import {
RemoveUsersByAdminDocument,
UserInfoDocument,
} from '~/helpers/backend/graphql';
import { ADMIN_CANNOT_BE_DELETED, USER_IS_OWNER } from '~/helpers/errors';
import { handleUserDeletion } from '~/helpers/userManagement';
const t = useI18n();
const toast = useToast();
Expand Down Expand Up @@ -210,35 +210,10 @@ const deleteUserMutation = async (id: string | null) => {
} else {
const deletedUsers = result.data?.removeUsersByAdmin || [];
const uniqueErrorMessages = new Set(
deletedUsers.map(({ errorMessage }) => errorMessage).filter(Boolean)
) as Set<string>;
if (uniqueErrorMessages.size > 0) {
const errMsgMap = {
[ADMIN_CANNOT_BE_DELETED]: t('state.remove_admin_to_delete_user'),
[USER_IS_OWNER]: t('state.remove_owner_to_delete_user'),
};
const errMsgMapKeys = Object.keys(errMsgMap);
uniqueErrorMessages.forEach((errorMessage) => {
if (errMsgMapKeys.includes(errorMessage)) {
toast.error(errMsgMap[errorMessage as keyof typeof errMsgMap]);
}
});
// Fallback for the case where the error message is not in the compiled list
if (
Array.from(uniqueErrorMessages).some(
(key) => !((key as string) in errMsgMap)
)
) {
toast.error(t('state.delete_user_failure'));
}
} else {
toast.success(t('state.delete_user_success'));
}
handleUserDeletion(deletedUsers, {
type: 'individual',
metadata: null,
});
}
confirmDeletion.value = false;
deleteUserUID.value = null;
Expand Down
68 changes: 12 additions & 56 deletions packages/hoppscotch-sh-admin/src/pages/users/index.vue
Expand Up @@ -258,11 +258,8 @@ import {
UsersListQuery,
UsersListV2Document,
} from '~/helpers/backend/graphql';
import {
ADMIN_CANNOT_BE_DELETED,
USER_ALREADY_INVITED,
USER_IS_OWNER,
} from '~/helpers/errors';
import { USER_ALREADY_INVITED } from '~/helpers/errors';
import { handleUserDeletion } from '~/helpers/userManagement';
import IconCheck from '~icons/lucide/check';
import IconLeft from '~icons/lucide/chevron-left';
import IconRight from '~icons/lucide/chevron-right';
Expand Down Expand Up @@ -586,57 +583,16 @@ const deleteUsers = async (id: string | null) => {
.filter((user) => user.isDeleted)
.map((user) => user.userUID);

const uniqueErrorMessages = new Set(
deletedUsers.map(({ errorMessage }) => errorMessage).filter(Boolean)
) as Set<string>;

if (uniqueErrorMessages.size > 0) {
const errMsgMap = {
[ADMIN_CANNOT_BE_DELETED]: t('state.remove_admin_for_deletion'),
[USER_IS_OWNER]: t('state.remove_owner_for_deletion'),
};

const errMsgMapKeys = Object.keys(errMsgMap);

// Show toast messages with the count of users deleted only if multiple users are selected
if (areMultipleUsersSelected.value) {
toast.success(
t('state.delete_some_users_success', { count: deletedIDs.length })
);
toast.error(
t('state.delete_some_users_failure', {
count: deletedUsers.length - deletedIDs.length,
})
);
}

uniqueErrorMessages.forEach((errorMessage) => {
if (errMsgMapKeys.includes(errorMessage)) {
toastTimeout = setTimeout(
() => {
toast.error(errMsgMap[errorMessage as keyof typeof errMsgMap]);
},
areMultipleUsersSelected.value ? 2000 : 0
);
}
});

// Fallback for the case where the error message is not in the compiled list
if (
Array.from(uniqueErrorMessages).some(
(key) => !((key as string) in errMsgMap)
)
) {
areMultipleUsersSelected.value
? t('state.delete_users_failure')
: t('state.delete_user_failure');
}
} else {
toast.success(
areMultipleUsersSelected.value
? t('state.delete_users_success')
: t('state.delete_user_success')
);
const { data } = handleUserDeletion(deletedUsers, {
type: 'bulk',
metadata: {
areMultipleUsersSelected: areMultipleUsersSelected.value,
deletedIDs,
},
});

if (data?.timeoutID) {
toastTimeout = data.timeoutID;
}

usersList.value = usersList.value.filter(
Expand Down

0 comments on commit 17db483

Please sign in to comment.