diff --git a/src/app/api/getHealthCheck.ts b/src/app/api/getHealthCheck.ts new file mode 100644 index 00000000..ae91a1ef --- /dev/null +++ b/src/app/api/getHealthCheck.ts @@ -0,0 +1,50 @@ +import axios, { isAxiosError } from "axios"; + +import { + API_ERROR_MESSAGE, + GEO_BLOCK_MESSAGE, + HealthCheckResult, + HealthCheckStatus, +} from "../types/healthCheck"; + +interface HealthCheckResponse { + data: string; +} + +export const getHealthCheck = async (): Promise => { + try { + const response = await axios.get( + `${process.env.NEXT_PUBLIC_API_URL}/healthcheck`, + ); + const healthCheckAPIResponse: HealthCheckResponse = response.data; + // If the response has a data field, it's a normal response + if (healthCheckAPIResponse.data) { + return { + status: HealthCheckStatus.Normal, + message: healthCheckAPIResponse.data, + }; + } else { + // Something went wrong + throw new Error(API_ERROR_MESSAGE); + } + } catch (error: Error | any) { + // Geo-blocking is a custom status code + if ( + isAxiosError(error) && + (error.response?.status === 451 || error.request.status === 451) + ) { + return { + status: HealthCheckStatus.GeoBlocked, + message: error.request?.response?.message || GEO_BLOCK_MESSAGE, + }; + } else { + return { + status: HealthCheckStatus.Error, + message: + error.request?.response?.message || + error?.message || + API_ERROR_MESSAGE, + }; + } + } +}; diff --git a/src/app/components/Connect/ConnectSmall.tsx b/src/app/components/Connect/ConnectSmall.tsx index e0a5deae..a7b41520 100644 --- a/src/app/components/Connect/ConnectSmall.tsx +++ b/src/app/components/Connect/ConnectSmall.tsx @@ -1,9 +1,17 @@ import { useRef, useState } from "react"; +import { AiOutlineInfoCircle } from "react-icons/ai"; import { FaBitcoin } from "react-icons/fa"; import { IoMdClose } from "react-icons/io"; import { PiWalletBold } from "react-icons/pi"; +import { Tooltip } from "react-tooltip"; import { useOnClickOutside } from "usehooks-ts"; +import { + API_ERROR_MESSAGE, + GEO_BLOCK_MESSAGE, + HealthCheckResult, + HealthCheckStatus, +} from "@/app/types/healthCheck"; import { getNetworkConfig } from "@/config/network.config"; import { satoshiToBtc } from "@/utils/btcConversions"; import { maxDecimals } from "@/utils/maxDecimals"; @@ -17,6 +25,7 @@ interface ConnectSmallProps { address: string; btcWalletBalanceSat?: number; onDisconnect: () => void; + apiAvailable?: HealthCheckResult; } export const ConnectSmall: React.FC = ({ @@ -24,6 +33,7 @@ export const ConnectSmall: React.FC = ({ address, btcWalletBalanceSat, onDisconnect, + apiAvailable, }) => { const [showMenu, setShowMenu] = useState(false); const handleClickOutside = () => { @@ -35,6 +45,33 @@ export const ConnectSmall: React.FC = ({ const { coinName, networkName } = getNetworkConfig(); + // Renders the Tooltip describing the reason + // why the user might not be able to connect the wallet + const renderApiNotAvailableTooltip = () => { + if (!apiAvailable) return null; + + const message = + apiAvailable.status === HealthCheckStatus.GeoBlocked + ? GEO_BLOCK_MESSAGE + : API_ERROR_MESSAGE; + + return ( + <> + + + + + + ); + }; + + const isApiNormal = apiAvailable?.status === HealthCheckStatus.Normal; + return address ? (
) : ( - +
+ + {!isApiNormal && renderApiNotAvailableTooltip()} +
); }; diff --git a/src/app/components/Header/Header.tsx b/src/app/components/Header/Header.tsx index 88317c04..4fbd9b42 100644 --- a/src/app/components/Header/Header.tsx +++ b/src/app/components/Header/Header.tsx @@ -1,3 +1,5 @@ +import { HealthCheckResult } from "@/app/types/healthCheck"; + import { ConnectSmall } from "../Connect/ConnectSmall"; import { ConnectedSmall } from "../Connect/ConnectedSmall"; import { TestingInfo } from "../TestingInfo/TestingInfo"; @@ -10,6 +12,7 @@ interface HeaderProps { address: string; btcWalletBalanceSat?: number; onDisconnect: () => void; + apiAvailable?: HealthCheckResult; } export const Header: React.FC = ({ @@ -17,6 +20,7 @@ export const Header: React.FC = ({ address, btcWalletBalanceSat, onDisconnect, + apiAvailable, }) => { return (