Skip to content

Commit

Permalink
feat: added new api hooks and global states (#197)
Browse files Browse the repository at this point in the history
* feat: added new api hooks and global states

* fix: review issues

* fix: add new eslint rule for booleans

* fix: FAQ test

* fix: review feedback
  • Loading branch information
totraev authored Oct 4, 2024
1 parent 2b54b34 commit 6a00afc
Show file tree
Hide file tree
Showing 24 changed files with 466 additions and 498 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"pathGroupsExcludedImportTypes": ["builtin", "external"],
"newlines-between": "always"
}
]
],
"no-implicit-coercion": "error"
}
}
2 changes: 1 addition & 1 deletion src/app/components/Connect/ConnectSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export const ConnectSmall: React.FC<ConnectSmallProps> = ({
onClick={onConnect}
// Disable the button if the user is already connected
// or: API is not available, geo-blocked, or has an error
disabled={!!address || !isApiNormal}
disabled={Boolean(address) || !isApiNormal}
>
<PiWalletBold size={20} className="flex md:hidden" />
<span className="hidden md:flex">Connect to {networkName} network</span>
Expand Down
78 changes: 38 additions & 40 deletions src/app/components/Delegations/Delegations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ import { useEffect, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import { useLocalStorage } from "usehooks-ts";

import { SignPsbtTransaction } from "@/app/common/utils/psbt";
import {
signPsbtTransaction,
SignPsbtTransaction,
} from "@/app/common/utils/psbt";
import { LoadingTableList } from "@/app/components/Loading/Loading";
import { DelegationsPointsProvider } from "@/app/context/api/DelegationsPointsProvider";
import { useError } from "@/app/context/Error/ErrorContext";
import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useDelegations } from "@/app/hooks/useDelegations";
import { useHealthCheck } from "@/app/hooks/useHealthCheck";
import { QueryMeta } from "@/app/types/api";
import { useAppState } from "@/app/state";
import { useDelegationState } from "@/app/state/DelegationState";
import {
Delegation as DelegationInterface,
DelegationState,
Expand All @@ -32,43 +37,35 @@ import {

import { Delegation } from "./Delegation";

interface DelegationsProps {
delegationsAPI: DelegationInterface[];
delegationsLocalStorage: DelegationInterface[];
globalParamsVersion: GlobalParamsVersion;
signPsbtTx: SignPsbtTransaction;
pushTx: WalletProvider["pushTx"];
queryMeta: QueryMeta;
getNetworkFees: WalletProvider["getNetworkFees"];
}
export const Delegations = () => {
const { currentVersion } = useAppState();
const { data: delegationsAPI } = useDelegations();
const {
walletProvider: btcWallet,
address,
publicKeyNoCoord,
connected,
network,
} = useWallet();

export const Delegations: React.FC<DelegationsProps> = ({
delegationsAPI,
delegationsLocalStorage,
globalParamsVersion,
signPsbtTx,
pushTx,
queryMeta,
getNetworkFees,
}) => {
const { address, publicKeyNoCoord, connected, network } = useWallet();
if (!btcWallet || !delegationsAPI || !currentVersion || !network) {
return;
}

return (
network && (
<DelegationsPointsProvider
publicKeyNoCoord={publicKeyNoCoord}
delegationsAPI={delegationsAPI}
delegationsAPI={delegationsAPI.delegations}
isWalletConnected={connected}
address={address}
>
<DelegationsContent
delegationsAPI={delegationsAPI}
delegationsLocalStorage={delegationsLocalStorage}
globalParamsVersion={globalParamsVersion}
signPsbtTx={signPsbtTx}
pushTx={pushTx}
queryMeta={queryMeta}
getNetworkFees={getNetworkFees}
delegationsAPI={delegationsAPI.delegations}
globalParamsVersion={currentVersion}
signPsbtTx={signPsbtTransaction(btcWallet)}
pushTx={btcWallet.pushTx}
getNetworkFees={btcWallet.getNetworkFees}
address={address}
btcWalletNetwork={network}
publicKeyNoCoord={publicKeyNoCoord}
Expand All @@ -81,25 +78,21 @@ export const Delegations: React.FC<DelegationsProps> = ({

interface DelegationsContentProps {
delegationsAPI: DelegationInterface[];
delegationsLocalStorage: DelegationInterface[];
globalParamsVersion: GlobalParamsVersion;
publicKeyNoCoord: string;
btcWalletNetwork: networks.Network;
address: string;
signPsbtTx: SignPsbtTransaction;
pushTx: WalletProvider["pushTx"];
queryMeta: QueryMeta;
getNetworkFees: WalletProvider["getNetworkFees"];
isWalletConnected: boolean;
}

const DelegationsContent: React.FC<DelegationsContentProps> = ({
delegationsAPI,
delegationsLocalStorage,
globalParamsVersion,
signPsbtTx,
pushTx,
queryMeta,
getNetworkFees,
address,
btcWalletNetwork,
Expand All @@ -114,6 +107,12 @@ const DelegationsContent: React.FC<DelegationsContentProps> = ({
const [selectedDelegationHeight, setSelectedDelegationHeight] = useState<
number | undefined
>();
const {
delegations = [],
fetchMoreDelegations,
hasMoreDelegations,
isLoading,
} = useDelegationState();

const shouldShowPoints =
isApiNormal && !isGeoBlocked && shouldDisplayPoints();
Expand Down Expand Up @@ -288,9 +287,9 @@ const DelegationsContent: React.FC<DelegationsContentProps> = ({

// combine delegations from the API and local storage, prioritizing API data
const combinedDelegationsData = delegationsAPI
? [...delegationsLocalStorage, ...delegationsAPI]
? [...delegations, ...delegationsAPI]
: // if no API data, fallback to using only local storage delegations
delegationsLocalStorage;
delegations;

return (
<div className="card flex flex-col gap-2 bg-base-300 p-4 shadow-sm lg:flex-1">
Expand Down Expand Up @@ -318,9 +317,9 @@ const DelegationsContent: React.FC<DelegationsContentProps> = ({
<InfiniteScroll
className="flex flex-col gap-4 pt-3"
dataLength={combinedDelegationsData.length}
next={queryMeta.next}
hasMore={queryMeta.hasMore}
loader={queryMeta.isFetchingMore ? <LoadingTableList /> : null}
next={fetchMoreDelegations}
hasMore={hasMoreDelegations}
loader={isLoading ? <LoadingTableList /> : null}
scrollableTarget="staking-history"
>
{combinedDelegationsData?.map((delegation) => {
Expand Down Expand Up @@ -368,9 +367,8 @@ const DelegationsContent: React.FC<DelegationsContentProps> = ({
</div>
</>
)}
{modalMode && txID && selectedDelegationHeight !== undefined && (
{modalMode && txID && (
<UnbondWithdrawModal
delegationHeight={selectedDelegationHeight}
open={modalOpen}
onClose={() => setModalOpen(false)}
onProceed={() => {
Expand Down
6 changes: 3 additions & 3 deletions src/app/components/FAQ/FAQ.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useVersionInfo } from "@/app/context/api/VersionInfo";
import { useAppState } from "@/app/state";
import { getNetworkConfig } from "@/config/network.config";

import { questions } from "./data/questions";
Expand All @@ -7,8 +7,8 @@ import { Section } from "./Section";
interface FAQProps {}

export const FAQ: React.FC<FAQProps> = () => {
const { currentVersion } = useAppState();
const { coinName, networkName } = getNetworkConfig();
const versionInfo = useVersionInfo();

return (
<div className="container mx-auto flex flex-col gap-2 p-6">
Expand All @@ -17,7 +17,7 @@ export const FAQ: React.FC<FAQProps> = () => {
{questions(
coinName,
networkName,
versionInfo?.currentVersion?.confirmationDepth,
currentVersion?.confirmationDepth,
).map((question) => (
<Section
key={question.title}
Expand Down
16 changes: 5 additions & 11 deletions src/app/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useAppState } from "@/app/state";
import { shouldDisplayTestingMsg } from "@/config";

import { ConnectSmall } from "../Connect/ConnectSmall";
Expand All @@ -7,16 +8,9 @@ import { Logo } from "../Logo/Logo";
import { TestingInfo } from "../TestingInfo/TestingInfo";
import { ThemeToggle } from "../ThemeToggle/ThemeToggle";

interface HeaderProps {
loading?: boolean;
btcWalletBalanceSat?: number;
}

export const Header: React.FC<HeaderProps> = ({
loading,
btcWalletBalanceSat,
}) => {
export const Header = () => {
const { address, open, disconnect } = useWallet();
const { totalBalance, isLoading: loading } = useAppState();

return (
<nav>
Expand All @@ -34,7 +28,7 @@ export const Header: React.FC<HeaderProps> = ({
loading={loading}
onConnect={open}
address={address}
btcWalletBalanceSat={btcWalletBalanceSat}
btcWalletBalanceSat={totalBalance}
onDisconnect={disconnect}
/>
<ThemeToggle />
Expand All @@ -45,7 +39,7 @@ export const Header: React.FC<HeaderProps> = ({
<ConnectedSmall
loading={loading}
address={address}
btcWalletBalanceSat={btcWalletBalanceSat}
btcWalletBalanceSat={totalBalance}
onDisconnect={disconnect}
/>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Modals/ConnectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({
return null;
}

const isInjectable = !!window[BROWSER];
const isInjectable = Boolean(window[BROWSER]);
const { networkName } = getNetworkConfig();

const handleConnect = async () => {
Expand Down Expand Up @@ -225,7 +225,7 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({
return buildInjectableWallet(isInjectable, name);
}
const walletAvailable =
isQRWallet || !!window[provider as any];
isQRWallet || Boolean(window[provider as any]);

// If the wallet is integrated but does not support the current network, do not display it
if (
Expand Down
7 changes: 2 additions & 5 deletions src/app/components/Modals/UnbondWithdrawModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IoMdClose } from "react-icons/io";

import { useVersionInfo } from "@/app/context/api/VersionInfo";
import { useAppState } from "@/app/state";
import { getNetworkConfig } from "@/config/network.config";
import { blocksToDisplayTime } from "@/utils/blocksToDisplayTime";
import { satoshiToBtc } from "@/utils/btcConversions";
Expand All @@ -15,7 +15,6 @@ export const MODE_WITHDRAW = "withdraw";
export type MODE = typeof MODE_UNBOND | typeof MODE_WITHDRAW;

interface PreviewModalProps {
delegationHeight: number;
open: boolean;
onClose: (value: boolean) => void;
onProceed: () => void;
Expand All @@ -24,17 +23,15 @@ interface PreviewModalProps {
}

export const UnbondWithdrawModal: React.FC<PreviewModalProps> = ({
delegationHeight,
open,
onClose,
onProceed,
mode,
awaitingWalletResponse,
}) => {
const { coinName, networkName } = getNetworkConfig();
const versionInfo = useVersionInfo();
const { currentVersion: globalParams } = useAppState();

const globalParams = versionInfo?.currentVersion;
const unbondingFeeSat = globalParams?.unbondingFeeSat || 0;
const unbondingTimeBlocks = globalParams?.unbondingTime || 0;

Expand Down
18 changes: 10 additions & 8 deletions src/app/components/NetworkBadge/NetworkBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import Image from "next/image";
import { twJoin } from "tailwind-merge";

import { useWallet } from "@/app/context/wallet/WalletProvider";
import { network } from "@/config/network.config";
import { Network } from "@/utils/wallet/wallet_provider";

import testnetIcon from "./testnet-icon.png";

// This component can also be used rendering based on the network type
interface NetworkBadgeProps {
isWalletConnected: boolean;
}
export const NetworkBadge = () => {
const { walletProvider } = useWallet();

export const NetworkBadge: React.FC<NetworkBadgeProps> = ({
isWalletConnected,
}) => {
return (
<div
className={`absolute left-2 ${isWalletConnected ? "top-40 md:top-24 lg:top-32" : "top-24 md:top-24 lg:top-32"}`}
className={twJoin(
`absolute left-2`,
Boolean(walletProvider)
? "top-40 md:top-24 lg:top-32"
: "top-24 md:top-24 lg:top-32",
)}
>
{[Network.SIGNET, Network.TESTNET].includes(network) && (
<>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Points/StakerPoints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const StakerPoints: React.FC<StakerPointsProps> = ({
const { data: stakerPoints, isLoading } = useQuery({
queryKey: ["stakerPoints", publicKeyNoCoord],
queryFn: () => getStakersPoints([publicKeyNoCoord]),
enabled: !!publicKeyNoCoord,
enabled: Boolean(publicKeyNoCoord),
refetchInterval: 300000, // Refresh every 5 minutes
refetchOnWindowFocus: false,
retry: 1,
Expand Down
Loading

0 comments on commit 6a00afc

Please sign in to comment.