diff --git a/src/api/tenants/index.ts b/src/api/tenants/index.ts index d464228f..f586225f 100644 --- a/src/api/tenants/index.ts +++ b/src/api/tenants/index.ts @@ -32,7 +32,6 @@ export const useTenantCreateService = () => { status: "INVALID_TENANT_ID_ERROR"; message: string; } - | undefined > => { const response = await fetchData({ url: getApiUrl("/api/tenant"), @@ -49,7 +48,7 @@ export const useTenantCreateService = () => { return body; } - return undefined; + throw new Error("Unknown error"); }; return createOrUpdateTenant; @@ -68,7 +67,6 @@ export const useTenantGetService = () => { | { status: "UNKNOWN_TENANT_ERROR"; } - | undefined > => { const response = await fetchData({ url: getApiUrl("/api/tenant", tenantId), diff --git a/src/ui/components/tenants/creatNewTenant/CreateNewTenant.tsx b/src/ui/components/tenants/creatNewTenant/CreateNewTenant.tsx index 127dbc7e..9398f8f1 100644 --- a/src/ui/components/tenants/creatNewTenant/CreateNewTenant.tsx +++ b/src/ui/components/tenants/creatNewTenant/CreateNewTenant.tsx @@ -24,7 +24,7 @@ import { useTenantCreateService } from "../../../../api/tenants"; import "./createNewTenant.scss"; export const CreateNewTenantDialog = ({ onCloseDialog }: { onCloseDialog: () => void }) => { - const createOrUpdateTenant = useTenantCreateService(); + const createTenant = useTenantCreateService(); const navigate = useNavigate(); const [tenantCreationError, setTenantCreationError] = useState(undefined); const [isCreatingTenant, setIsCreatingTenant] = useState(false); @@ -38,19 +38,19 @@ export const CreateNewTenantDialog = ({ onCloseDialog }: { onCloseDialog: () => } try { setIsCreatingTenant(true); - const resp = await createOrUpdateTenant(tenantId); - if (resp?.status === "OK") { + const resp = await createTenant(tenantId); + if (resp.status === "OK") { if (resp.createdNew) { navigate(`?tenantId=${tenantId.toLowerCase()}`); onCloseDialog(); } else { setTenantCreationError("Tenant already exists"); } - } else if (resp?.status === "MULTITENANCY_NOT_ENABLED_IN_CORE_ERROR") { + } else if (resp.status === "MULTITENANCY_NOT_ENABLED_IN_CORE_ERROR") { setTenantCreationError( "Multitenancy is not enabled for your SuperTokens instance. Please add a license key to enable it." ); - } else if (resp?.status === "INVALID_TENANT_ID_ERROR") { + } else if (resp.status === "INVALID_TENANT_ID_ERROR") { setTenantCreationError(resp.message); } else { throw new Error("Failed to create tenant"); diff --git a/src/ui/components/tenants/tenantDetail/CoreConfigSection.tsx b/src/ui/components/tenants/tenantDetail/CoreConfigSection.tsx index 6e53917a..34acc916 100644 --- a/src/ui/components/tenants/tenantDetail/CoreConfigSection.tsx +++ b/src/ui/components/tenants/tenantDetail/CoreConfigSection.tsx @@ -18,10 +18,6 @@ import { ReactComponent as InfoIcon } from "../../../../assets/info-icon.svg"; import { ReactComponent as QuestionMarkIcon } from "../../../../assets/question-mark.svg"; import { PUBLIC_TENANT_ID } from "../../../../constants"; import { getConnectionUri } from "../../../../utils"; -// import { Checkbox } from "../../checkbox/Checkbox"; -// import InputField from "../../inputField/InputField"; -// import { NativeSelect } from "../../nativeSelect/NativeSelect"; -// import { Toggle } from "../../toggle/Toggle"; import TooltipContainer from "../../tooltip/tooltip"; import { EditCoreConfigPropertyDialog } from "./editCoreConfigPropertyDialog/EditCoreConfigPropertyDialog"; import { EditPluginPropertyDialog } from "./editPluginPropertyDialog/EditPluginPropertyDialog"; @@ -159,7 +155,8 @@ type CoreConfigTableRowProps = { isPluginPropertyEditable: boolean; }; -const isUsingSaaS = localStorage.getItem("isUsingSaaS") === "true"; +// TODO: Use the connectionURI to determine if the user is using SaaS +const isUsingSaaS = false; const isUsingNonPublicApp = /appid-.*$/.test(getConnectionUri()); const CoreConfigTableRow = ({ @@ -200,7 +197,7 @@ const CoreConfigTableRow = ({ if ((isPublicTenant && !isUsingNonPublicApp) || isModifyableOnlyViaConfigYaml) { return isUsingSaaS ? "To modify this property, please visit the dashboard on supertokens.com and click on the edit configuration button." - : "This property is modifyable only via the config.yaml file or via Docker env variables."; + : "This property is modifiable only via the config.yaml file or via Docker env variables."; } if (isUsingNonPublicApp && isPublicTenant) { diff --git a/src/ui/components/tenants/tenantDetail/LoginMethodsSection.tsx b/src/ui/components/tenants/tenantDetail/LoginMethodsSection.tsx index 77be2d28..7bec109e 100644 --- a/src/ui/components/tenants/tenantDetail/LoginMethodsSection.tsx +++ b/src/ui/components/tenants/tenantDetail/LoginMethodsSection.tsx @@ -33,8 +33,7 @@ export const LoginMethodsSection = () => { const doesTenantHasEmailPasswordAndPasswordlessEnabled = tenantInfo.firstFactors?.includes(FactorIds.EMAILPASSWORD) && - doesTenantHasPasswordlessEnabled(tenantInfo.firstFactors) && - !tenantInfo.firstFactors?.includes(FactorIds.THIRDPARTY); + doesTenantHasPasswordlessEnabled(tenantInfo.firstFactors); return ( <> @@ -68,7 +67,6 @@ export const LoginMethodsSection = () => { label={method.label} description={method.description} checked={tenantInfo?.firstFactors.includes(method.id)} - setMfaError={setMfaError} /> ))} @@ -136,7 +134,7 @@ const LoginFactor = ({ checked: boolean; fixedGap?: boolean; type: "first-factor" | "secondary-factor"; - setMfaError: (error: null | "MFA_NOT_INITIALIZED" | "MFA_REQUIREMENTS_FOR_AUTH_OVERRIDDEN") => void; + setMfaError?: (error: null | "MFA_NOT_INITIALIZED" | "MFA_REQUIREMENTS_FOR_AUTH_OVERRIDDEN") => void; }) => { const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -168,7 +166,7 @@ const LoginFactor = ({ if (res.status === "RECIPE_NOT_CONFIGURED_ON_BACKEND_SDK_ERROR") { setError(res.message); } else if (res.status === "MFA_NOT_INITIALIZED_ERROR") { - setMfaError("MFA_NOT_INITIALIZED"); + setMfaError?.("MFA_NOT_INITIALIZED"); } else { throw new Error(res.status); } @@ -177,7 +175,7 @@ const LoginFactor = ({ } if (res.status === "OK" && res.isMFARequirementsForAuthOverridden) { - setMfaError("MFA_REQUIREMENTS_FOR_AUTH_OVERRIDDEN"); + setMfaError?.("MFA_REQUIREMENTS_FOR_AUTH_OVERRIDDEN"); } // If this is not a MFA related error then clear the error @@ -185,7 +183,7 @@ const LoginFactor = ({ (res.status === "OK" && !res.isMFARequirementsForAuthOverridden) || res.status === "RECIPE_NOT_CONFIGURED_ON_BACKEND_SDK_ERROR" ) { - setMfaError(null); + setMfaError?.(null); } } } catch (error) { diff --git a/src/ui/components/tenants/tenantDetail/TenantDetail.tsx b/src/ui/components/tenants/tenantDetail/TenantDetail.tsx index eb68159a..b833d3e3 100644 --- a/src/ui/components/tenants/tenantDetail/TenantDetail.tsx +++ b/src/ui/components/tenants/tenantDetail/TenantDetail.tsx @@ -12,12 +12,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { useEffect, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { useTenantGetService } from "../../../../api/tenants"; import { TenantDashboardView, TenantInfo } from "../../../../api/tenants/types"; import { ReactComponent as NoTenantFound } from "../../../../assets/no-tenants.svg"; import { FactorIds, PUBLIC_TENANT_ID } from "../../../../constants"; import { getImageUrl, usePrevious } from "../../../../utils"; +import { PopupContentContext } from "../../../contexts/PopupContentContext"; import Button from "../../button"; import { Loader } from "../../loader/Loader"; import { AddNewProviderDialog } from "./addNewProviderDialog/AddNewProviderDialog"; @@ -47,13 +48,14 @@ export const TenantDetail = ({ const [viewObj, setViewObj] = useState({ view: "tenant-detail", }); + const { showToast } = useContext(PopupContentContext); const tenantHasThirdPartyEnabled = tenant?.firstFactors?.includes(FactorIds.THIRDPARTY); const prevTenantHasThirdPartyEnabled = usePrevious(tenantHasThirdPartyEnabled); const getTenant = async () => { const response = await getTenantInfo(tenantId); - if (response?.status === "OK") { + if (response.status === "OK") { setTenant(response.tenant); } }; @@ -63,7 +65,12 @@ export const TenantDetail = ({ try { setIsLoading(true); await getTenant(); - } catch (_) { + } catch (error) { + showToast({ + iconImage: getImageUrl("form-field-error-icon.svg"), + toastType: "error", + children: <>Something went wrong please try refreshing the page, + }); } finally { setIsLoading(false); } @@ -120,8 +127,9 @@ export const TenantDetail = ({ if (viewObj.view === "add-or-edit-third-party-provider") { return ( setViewObj({ view: "tenant-detail" })} /> ); } @@ -196,7 +204,6 @@ export const TenantDetail = ({ return ( {renderView()} {isNoProviderAddedDialogVisible && ( diff --git a/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx b/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx index 66f9e39c..9c03272e 100644 --- a/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx +++ b/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx @@ -13,13 +13,12 @@ * under the License. */ -import { createContext, Dispatch, SetStateAction, useContext } from "react"; +import { createContext, useContext } from "react"; import { TenantInfo } from "../../../../api/tenants/types"; type TenantDetailContextType = { tenantInfo: TenantInfo; refetchTenant: () => Promise; - setTenantInfo: Dispatch>; }; const TenantDetailContext = createContext(undefined); @@ -28,19 +27,16 @@ export const TenantDetailContextProvider = ({ children, tenantInfo, refetchTenant, - setTenantInfo, }: { children: React.ReactNode; tenantInfo: TenantInfo; refetchTenant: () => Promise; - setTenantInfo: Dispatch>; }) => { return ( {children} diff --git a/src/ui/components/tenants/tenantDetail/thirdPartyPage/ThirdPartyPage.tsx b/src/ui/components/tenants/tenantDetail/thirdPartyPage/ThirdPartyPage.tsx index 498970db..63d70389 100644 --- a/src/ui/components/tenants/tenantDetail/thirdPartyPage/ThirdPartyPage.tsx +++ b/src/ui/components/tenants/tenantDetail/thirdPartyPage/ThirdPartyPage.tsx @@ -12,10 +12,11 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { useGetThirdPartyProviderInfo } from "../../../../../api/tenants"; -import { ProviderConfigResponse, TenantDashboardView } from "../../../../../api/tenants/types"; +import { ProviderConfigResponse } from "../../../../../api/tenants/types"; import { getImageUrl, isValidHttpUrl } from "../../../../../utils"; +import { PopupContentContext } from "../../../../contexts/PopupContentContext"; import Button from "../../../button"; import { Loader } from "../../../loader/Loader"; import { useTenantDetailContext } from "../TenantDetailContext"; @@ -26,20 +27,19 @@ import { ThirdPartyProviderInput } from "../thirdPartyProviderInput/ThirdPartyPr import "./thirdPartyPage.scss"; export const ThirdPartyPage = ({ - viewObj, - setViewObj, + providerId, + isAddingNewProvider, + handleGoBack, }: { - viewObj: TenantDashboardView; - setViewObj: Dispatch>; + providerId?: string; + isAddingNewProvider: boolean; + handleGoBack: () => void; }) => { - const handleProviderInfoBack = () => { - setViewObj({ view: "tenant-detail" }); - }; return (
); @@ -78,6 +76,7 @@ const ProviderInfo = ({ const [providerConfigResponse, setProviderConfigResponse] = useState(undefined); const providerHasCustomFields = typeof providerId === "string" && PROVIDERS_WITH_ADDITIONAL_CONFIG.includes(providerId); + const { showToast } = useContext(PopupContentContext); const fetchProviderInfo = async (id: string, additionalConfig?: Record) => { setHasFilledCustomFieldsForProvider(true); @@ -88,6 +87,11 @@ const ProviderInfo = ({ setProviderConfigResponse(response.providerConfig); } } catch (error) { + showToast({ + iconImage: getImageUrl("form-field-error-icon.svg"), + toastType: "error", + children: <>Something went wrong please try refreshing the page, + }); } finally { setIsProviderInfoLoading(false); }