From 19e69ef51ec7b7dca93951d08753e366da4a86da Mon Sep 17 00:00:00 2001 From: Chakravarthy7102 Date: Tue, 29 Aug 2023 12:42:26 +0530 Subject: [PATCH 1/5] fix: email popup --- src/api/user/index.ts | 9 ++++++++- src/api/user/password/reset/index.ts | 10 +++++++++- src/ui/components/userDetail/userDetailForm.tsx | 4 ++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/api/user/index.ts b/src/api/user/index.ts index 0b0fe333..7c8c36ad 100644 --- a/src/api/user/index.ts +++ b/src/api/user/index.ts @@ -13,6 +13,7 @@ * under the License. */ +import { HTTPStatusCodes } from "../../constants"; import { UserWithRecipeId } from "../../ui/pages/usersList/types"; import { getApiUrl, useFetchData } from "../../utils"; @@ -45,7 +46,7 @@ export type GetUserInfoResult = export type UpdateUserInformationResponse = | { - status: "OK" | "EMAIL_ALREADY_EXISTS_ERROR" | "PHONE_ALREADY_EXISTS_ERROR"; + status: "OK" | "EMAIL_ALREADY_EXISTS_ERROR" | "PHONE_ALREADY_EXISTS_ERROR" | "EMAIL_UPDATE_FORBIDDEN"; } | { status: "INVALID_EMAIL_ERROR" | "INVALID_PHONE_ERROR"; @@ -124,6 +125,12 @@ export const useUserService = (): IUseUserService => { }, }); + if (response.status === HTTPStatusCodes.FORBIDDEN) { + return { + status: "EMAIL_UPDATE_FORBIDDEN", + }; + } + return await response.json(); }; diff --git a/src/api/user/password/reset/index.ts b/src/api/user/password/reset/index.ts index d1b142ad..b3dee479 100644 --- a/src/api/user/password/reset/index.ts +++ b/src/api/user/password/reset/index.ts @@ -1,3 +1,4 @@ +import { HTTPStatusCodes } from "../../../../constants"; import { getApiUrl, useFetchData } from "../../../../utils"; interface IUsePasswordResetService { @@ -10,7 +11,7 @@ interface IUsePasswordResetService { type UpdatePasswordResponse = | { - status: "OK"; + status: "OK" | "PASSWORD_UPDATE_FORBIDDEN"; } | { status: "INVALID_PASSWORD_ERROR"; @@ -36,6 +37,13 @@ const usePasswordResetService = (): IUsePasswordResetService => { }), }, }); + + if (response.status === HTTPStatusCodes.FORBIDDEN) { + return { + status: "PASSWORD_UPDATE_FORBIDDEN", + }; + } + return await response.json(); }; diff --git a/src/ui/components/userDetail/userDetailForm.tsx b/src/ui/components/userDetail/userDetailForm.tsx index 61d1e664..8ef1864e 100644 --- a/src/ui/components/userDetail/userDetailForm.tsx +++ b/src/ui/components/userDetail/userDetailForm.tsx @@ -300,6 +300,8 @@ export const UserDetailChangeEmailForm: FC = ( setApiError(response.error); } else if (response.status === "EMAIL_ALREADY_EXISTS_ERROR") { setApiError("A user with this email already exists"); + } else if (response.status === "EMAIL_UPDATE_FORBIDDEN") { + void onCancel(); } else { showToast(getUpdateEmailToast(true)); await onEmailChange(true); @@ -391,6 +393,8 @@ export const UserDetailChangePasswordForm: FC if (response.status === "INVALID_PASSWORD_ERROR") { setApiError(response.error); + } else if (response.status === "PASSWORD_UPDATE_FORBIDDEN") { + void onCancel(); } else { showToast(getUpdatePasswordToast(true)); await onPasswordChange(); From bba49fd0027af93224e5bbca30d736b4fd76bb9b Mon Sep 17 00:00:00 2001 From: Chakravarthy7102 Date: Tue, 29 Aug 2023 13:04:16 +0530 Subject: [PATCH 2/5] fix: dropdown flicker --- src/ui/components/usersListTable/UsersListTable.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/components/usersListTable/UsersListTable.scss b/src/ui/components/usersListTable/UsersListTable.scss index dce55336..524de0da 100644 --- a/src/ui/components/usersListTable/UsersListTable.scss +++ b/src/ui/components/usersListTable/UsersListTable.scss @@ -208,7 +208,7 @@ $container-padding-v: 24px; &:last-of-type { // put popup on the left because the popup could be cropped by the paper's bottom .user-row-select-popup { - top: 0px; + top: -50%; padding: 0px 40px 0px; } } From 979adb7447991058e10900d50735ddb851591e1f Mon Sep 17 00:00:00 2001 From: Chakravarthy7102 Date: Thu, 31 Aug 2023 11:00:03 +0530 Subject: [PATCH 3/5] fix: remove verbose code --- src/api/user/index.ts | 9 +-------- src/api/user/password/reset/index.ts | 9 +-------- src/ui/components/userDetail/userDetailForm.tsx | 8 ++------ 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/api/user/index.ts b/src/api/user/index.ts index 7c8c36ad..0b0fe333 100644 --- a/src/api/user/index.ts +++ b/src/api/user/index.ts @@ -13,7 +13,6 @@ * under the License. */ -import { HTTPStatusCodes } from "../../constants"; import { UserWithRecipeId } from "../../ui/pages/usersList/types"; import { getApiUrl, useFetchData } from "../../utils"; @@ -46,7 +45,7 @@ export type GetUserInfoResult = export type UpdateUserInformationResponse = | { - status: "OK" | "EMAIL_ALREADY_EXISTS_ERROR" | "PHONE_ALREADY_EXISTS_ERROR" | "EMAIL_UPDATE_FORBIDDEN"; + status: "OK" | "EMAIL_ALREADY_EXISTS_ERROR" | "PHONE_ALREADY_EXISTS_ERROR"; } | { status: "INVALID_EMAIL_ERROR" | "INVALID_PHONE_ERROR"; @@ -125,12 +124,6 @@ export const useUserService = (): IUseUserService => { }, }); - if (response.status === HTTPStatusCodes.FORBIDDEN) { - return { - status: "EMAIL_UPDATE_FORBIDDEN", - }; - } - return await response.json(); }; diff --git a/src/api/user/password/reset/index.ts b/src/api/user/password/reset/index.ts index b3dee479..a650c106 100644 --- a/src/api/user/password/reset/index.ts +++ b/src/api/user/password/reset/index.ts @@ -1,4 +1,3 @@ -import { HTTPStatusCodes } from "../../../../constants"; import { getApiUrl, useFetchData } from "../../../../utils"; interface IUsePasswordResetService { @@ -11,7 +10,7 @@ interface IUsePasswordResetService { type UpdatePasswordResponse = | { - status: "OK" | "PASSWORD_UPDATE_FORBIDDEN"; + status: "OK"; } | { status: "INVALID_PASSWORD_ERROR"; @@ -38,12 +37,6 @@ const usePasswordResetService = (): IUsePasswordResetService => { }, }); - if (response.status === HTTPStatusCodes.FORBIDDEN) { - return { - status: "PASSWORD_UPDATE_FORBIDDEN", - }; - } - return await response.json(); }; diff --git a/src/ui/components/userDetail/userDetailForm.tsx b/src/ui/components/userDetail/userDetailForm.tsx index 8ef1864e..493a60f9 100644 --- a/src/ui/components/userDetail/userDetailForm.tsx +++ b/src/ui/components/userDetail/userDetailForm.tsx @@ -300,9 +300,7 @@ export const UserDetailChangeEmailForm: FC = ( setApiError(response.error); } else if (response.status === "EMAIL_ALREADY_EXISTS_ERROR") { setApiError("A user with this email already exists"); - } else if (response.status === "EMAIL_UPDATE_FORBIDDEN") { - void onCancel(); - } else { + } else if (response.status === "OK") { showToast(getUpdateEmailToast(true)); await onEmailChange(true); } @@ -393,9 +391,7 @@ export const UserDetailChangePasswordForm: FC if (response.status === "INVALID_PASSWORD_ERROR") { setApiError(response.error); - } else if (response.status === "PASSWORD_UPDATE_FORBIDDEN") { - void onCancel(); - } else { + } else if (response.status === "OK") { showToast(getUpdatePasswordToast(true)); await onPasswordChange(); } From 0b1e818afb02d25a2c82a951a9b84083c4cf7ba1 Mon Sep 17 00:00:00 2001 From: Chakravarthy7102 Date: Fri, 1 Sep 2023 11:18:44 +0530 Subject: [PATCH 4/5] fix: add custome error class --- src/api/user/password/reset/index.ts | 1 - .../components/userDetail/userDetailForm.tsx | 49 +++++++++++++------ src/utils/customErrors.ts | 11 +++++ src/utils/index.ts | 11 +++-- 4 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 src/utils/customErrors.ts diff --git a/src/api/user/password/reset/index.ts b/src/api/user/password/reset/index.ts index a650c106..d1b142ad 100644 --- a/src/api/user/password/reset/index.ts +++ b/src/api/user/password/reset/index.ts @@ -36,7 +36,6 @@ const usePasswordResetService = (): IUsePasswordResetService => { }), }, }); - return await response.json(); }; diff --git a/src/ui/components/userDetail/userDetailForm.tsx b/src/ui/components/userDetail/userDetailForm.tsx index 493a60f9..c36ea006 100644 --- a/src/ui/components/userDetail/userDetailForm.tsx +++ b/src/ui/components/userDetail/userDetailForm.tsx @@ -18,6 +18,7 @@ import { Tenant } from "../../../api/tenants/list"; import { useUserService } from "../../../api/user"; import usePasswordResetService from "../../../api/user/password/reset"; import { getImageUrl } from "../../../utils"; +import { ForbiddenError } from "../../../utils/customErrors"; import { getTenantsObjectsForIds } from "../../../utils/user"; import { PopupContentContext } from "../../contexts/PopupContentContext"; import { useTenantsListContext } from "../../contexts/TenantsListContext"; @@ -289,18 +290,26 @@ export const UserDetailChangeEmailForm: FC = ( return; } - const response = await updateUserInformation({ - userId, - email, - recipeId, - tenantId, - }); + let response; + + try { + response = await updateUserInformation({ + userId, + email, + recipeId, + tenantId, + }); + } catch (error) { + if (ForbiddenError.isThisError(error)) { + void onCancel(); + } + } - if (response.status === "INVALID_EMAIL_ERROR") { + if (response?.status === "INVALID_EMAIL_ERROR") { setApiError(response.error); - } else if (response.status === "EMAIL_ALREADY_EXISTS_ERROR") { + } else if (response?.status === "EMAIL_ALREADY_EXISTS_ERROR") { setApiError("A user with this email already exists"); - } else if (response.status === "OK") { + } else if (response?.status === "OK") { showToast(getUpdateEmailToast(true)); await onEmailChange(true); } @@ -383,15 +392,23 @@ export const UserDetailChangePasswordForm: FC return; } - const response = await updatePassword( - userId, - password, - matchingTenantIds.length > 0 ? matchingTenantIds[0].tenantId : undefined - ); + let response; + + try { + response = await updatePassword( + userId, + password, + matchingTenantIds.length > 0 ? matchingTenantIds[0].tenantId : undefined + ); + } catch (error) { + if (ForbiddenError.isThisError(error)) { + void onCancel(); + } + } - if (response.status === "INVALID_PASSWORD_ERROR") { + if (response?.status === "INVALID_PASSWORD_ERROR") { setApiError(response.error); - } else if (response.status === "OK") { + } else if (response?.status === "OK") { showToast(getUpdatePasswordToast(true)); await onPasswordChange(); } diff --git a/src/utils/customErrors.ts b/src/utils/customErrors.ts new file mode 100644 index 00000000..f41ed17a --- /dev/null +++ b/src/utils/customErrors.ts @@ -0,0 +1,11 @@ +export class ForbiddenError extends Error { + statusCode = 403; + status = "FORBIDDEN_REQUEST"; + constructor(message: string) { + super(message); + } + + static isThisError(err: any): boolean { + return err.status === "FORBIDDEN_REQUEST"; + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 4520f9bd..1de92625 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -20,6 +20,7 @@ import NetworkManager from "../services/network"; import { localStorageHandler } from "../services/storage"; import { HttpMethod } from "../types"; import { UserRecipeType } from "../ui/pages/usersList/types"; +import { ForbiddenError } from "./customErrors"; export function getStaticBasePath(): string { return (window as any).staticBasePath; @@ -124,11 +125,13 @@ export const useFetchData = () => { } if (response.status === HTTPStatusCodes.FORBIDDEN) { - const message = (await response.clone().json())?.message; + let message = (await response.clone().json())?.message; + if (message === undefined) { + message = "You do not have access to this page"; + } + window.dispatchEvent(getAccessDeniedEvent(message)); - window.dispatchEvent( - getAccessDeniedEvent(message === undefined ? "You do not have access to this page" : message) - ); + throw new ForbiddenError(message); } const logoutAndRedirect = shouldRedirectOnUnauthorised && HTTPStatusCodes.UNAUTHORIZED === response.status; From e7f26378646db672485858d76ed7926919ce463e Mon Sep 17 00:00:00 2001 From: Chakravarthy7102 Date: Fri, 1 Sep 2023 16:04:55 +0530 Subject: [PATCH 5/5] fix: add comment and fix stuff --- .../components/userDetail/userDetailForm.tsx | 40 +++++++++---------- src/utils/index.ts | 4 ++ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ui/components/userDetail/userDetailForm.tsx b/src/ui/components/userDetail/userDetailForm.tsx index c36ea006..d4ecabc3 100644 --- a/src/ui/components/userDetail/userDetailForm.tsx +++ b/src/ui/components/userDetail/userDetailForm.tsx @@ -290,29 +290,27 @@ export const UserDetailChangeEmailForm: FC = ( return; } - let response; - try { - response = await updateUserInformation({ + const response = await updateUserInformation({ userId, email, recipeId, tenantId, }); + + if (response.status === "INVALID_EMAIL_ERROR") { + setApiError(response.error); + } else if (response.status === "EMAIL_ALREADY_EXISTS_ERROR") { + setApiError("A user with this email already exists"); + } else if (response.status === "OK") { + showToast(getUpdateEmailToast(true)); + await onEmailChange(true); + } } catch (error) { if (ForbiddenError.isThisError(error)) { void onCancel(); } } - - if (response?.status === "INVALID_EMAIL_ERROR") { - setApiError(response.error); - } else if (response?.status === "EMAIL_ALREADY_EXISTS_ERROR") { - setApiError("A user with this email already exists"); - } else if (response?.status === "OK") { - showToast(getUpdateEmailToast(true)); - await onEmailChange(true); - } }; const onCancel = async () => { @@ -392,26 +390,24 @@ export const UserDetailChangePasswordForm: FC return; } - let response; - try { - response = await updatePassword( + const response = await updatePassword( userId, password, matchingTenantIds.length > 0 ? matchingTenantIds[0].tenantId : undefined ); + + if (response?.status === "INVALID_PASSWORD_ERROR") { + setApiError(response.error); + } else if (response?.status === "OK") { + showToast(getUpdatePasswordToast(true)); + await onPasswordChange(); + } } catch (error) { if (ForbiddenError.isThisError(error)) { void onCancel(); } } - - if (response?.status === "INVALID_PASSWORD_ERROR") { - setApiError(response.error); - } else if (response?.status === "OK") { - showToast(getUpdatePasswordToast(true)); - await onPasswordChange(); - } }; const onCancel = async () => { diff --git a/src/utils/index.ts b/src/utils/index.ts index 1de92625..14be0994 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -131,6 +131,10 @@ export const useFetchData = () => { } window.dispatchEvent(getAccessDeniedEvent(message)); + /* throwing this error just to make sure that this case is handled in some places in the application. + global search for ForbiddenError.isThisError to see those places + */ + throw new ForbiddenError(message); }