diff --git a/.gitignore b/.gitignore index 8fd3f19..7cca5d1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ dist dist-ssr *.tgz *.local +demo # Editor directories and files .vscode/* diff --git a/package.json b/package.json index b63fb71..037336d 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ }, "peerDependencies": { "@bluxcc/core": "^0.1.16", + "@tanstack/react-query": "^5.90.11", "react": ">=17.0.0", "react-dom": ">=17.0.0" }, diff --git a/src/useStellar/index.ts b/src/useStellar/index.ts index b3fd011..ec54adf 100644 --- a/src/useStellar/index.ts +++ b/src/useStellar/index.ts @@ -1,13 +1,13 @@ export { networks } from '@bluxcc/core'; export * from './useAccount'; export * from './useNetwork'; -// import useAccounts from './useAccounts'; -// import useAssets from './useAssets'; -// import useBalances from './useBalances'; -// import useClaimableBalances from './useClaimableBalances'; -// import useEffects from './useEffects'; -// import useLedgers from './useLedgers'; -// import useLiquidityPools from './useLiquidityPools'; +export * from './useAccounts'; +// export * from './useAssets'; +export * from './useBalances'; +export * from './useClaimableBalances'; +export * from './useEffects'; +export * from './useLedgers'; +export * from './useLiquidityPools'; // import useNetwork from './useNetwork'; // import useOffers from './useOffers'; // import useOperations from './useOperations'; @@ -17,5 +17,5 @@ export * from './useNetwork'; // import useStrictSendPaths from './useStrictSendPaths'; // import useTradeAggregation from './useTradeAggregation'; // import useTrades from './useTrades'; -// import useTransactions from './useTransactions'; +// export * from './useTransactions'; export { useSwitchNetwork } from './useSwitchNetwork'; diff --git a/src/useStellar/useAccount.ts b/src/useStellar/useAccount.ts index 142b9ab..6ebd90e 100644 --- a/src/useStellar/useAccount.ts +++ b/src/useStellar/useAccount.ts @@ -12,9 +12,6 @@ export type UseAccountResult = { }; export function useAccount(options: GetAccountOptions): UseAccountResult { - // TODO: we need the same exact function as the core function here. - // Take the options.address, options.network, pass it to it, and wait for changes - // In useEffect. const [result, setResult] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); diff --git a/src/useStellar/useAccounts.ts b/src/useStellar/useAccounts.ts index e69de29..002ae04 100644 --- a/src/useStellar/useAccounts.ts +++ b/src/useStellar/useAccounts.ts @@ -0,0 +1,51 @@ +import { useState, useEffect } from "react"; +import { getAccounts } from "@bluxcc/core"; // or your local path +import { + GetAccountsOptions, + GetAccountsResult, +} from "@bluxcc/core/dist/exports/core/getAccounts"; + +export type UseAccountsResult = { + loading: boolean; + error: Error | null; + result: GetAccountsResult | null; +}; + +export function useAccounts(options: GetAccountsOptions): UseAccountsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!options.network) return; + + const fetchAccounts = async () => { + setLoading(true); + setError(null); + + try { + const accounts = await getAccounts(options); + setResult(accounts); + } catch (e) { + setError(e instanceof Error ? e : new Error(String(e))); + setResult(null); + } finally { + setLoading(false); + } + }; + + fetchAccounts(); + }, [ + options.network, + options.forSigner, + options.forAsset?.code, + options.forAsset?.issuer, + options.forLiquidityPool, + options.sponsor, + options.cursor, + options.limit, + options.order, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useAssets.ts b/src/useStellar/useAssets.ts index e69de29..cd0f7e1 100644 --- a/src/useStellar/useAssets.ts +++ b/src/useStellar/useAssets.ts @@ -0,0 +1,55 @@ +// Upon testing, it either gives "Bad Request" or "Custom network has no transports." + +import { useEffect, useState } from "react"; +import { getAssets } from "@bluxcc/core"; + +import { + GetAssetsOptions, + GetAssetsResult, +} from "@bluxcc/core/dist/exports/core/getAssets"; + +export type UseAssetsResult = { + loading: boolean; + error: Error | null; + result: GetAssetsResult | null; +}; + +export function useAssets(options: GetAssetsOptions): UseAssetsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + + getAssets(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + options.forCode, + options.forIssuer, + ]); + + return { loading, error, result }; +} \ No newline at end of file diff --git a/src/useStellar/useBalances.ts b/src/useStellar/useBalances.ts index e69de29..e4ce8e6 100644 --- a/src/useStellar/useBalances.ts +++ b/src/useStellar/useBalances.ts @@ -0,0 +1,53 @@ +import { useMemo } from "react"; +import { useQuery, UseQueryOptions, UseQueryResult } from "@tanstack/react-query"; +import { getBalances } from "@bluxcc/core"; +import type { + GetBalancesOptions, + GetBalancesResult, +} from "@bluxcc/core/dist/exports/core/getBalances"; +import { getAddress, getNetwork } from "../utils"; + +export function useBalances( + options?: GetBalancesOptions, + queryOptions?: UseQueryOptions +): UseQueryResult { + + const address = getAddress(options?.address); + const network = getNetwork(options?.network); + + const enabled = !!address && (queryOptions?.enabled ?? true); + + const queryKey = useMemo( + () => [ + "blux", + "balances", + address ?? null, + network ?? null, + Boolean(options?.includeZeroBalances), + ], + [address, network, options?.includeZeroBalances] + ); + + const queryFn = useMemo( + () => async () => { + const opts: GetBalancesOptions = { + address: options?.address, + network: options?.network, + includeZeroBalances: options?.includeZeroBalances, + }; + return getBalances(opts); + }, + [options?.address, options?.network, options?.includeZeroBalances] + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} + +export default useBalances; diff --git a/src/useStellar/useClaimableBalances.ts b/src/useStellar/useClaimableBalances.ts index e69de29..ef6892d 100644 --- a/src/useStellar/useClaimableBalances.ts +++ b/src/useStellar/useClaimableBalances.ts @@ -0,0 +1,60 @@ +// Gives "Issuer is invalid" + +import { useEffect, useState } from "react"; +import { getClaimableBalances } from "@bluxcc/core"; + +import { + GetClaimableBalancesOptions, + GetClaimableBalancesResult, +} from "@bluxcc/core/dist/exports/core/getClaimableBalances"; + +export type UseClaimableBalancesResult = { + loading: boolean; + error: Error | null; + result: GetClaimableBalancesResult | null; +}; + +export function useClaimableBalances( + options: GetClaimableBalancesOptions +): UseClaimableBalancesResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getClaimableBalances(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + + options.asset, + options.claimant, + options.sponsor, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useEffects.ts b/src/useStellar/useEffects.ts index e69de29..b6cb0ed 100644 --- a/src/useStellar/useEffects.ts +++ b/src/useStellar/useEffects.ts @@ -0,0 +1,57 @@ +import { useEffect, useState } from "react"; +import { getEffects } from "@bluxcc/core"; + +import { + GetEffectsOptions, + GetEffectsResult, +} from "@bluxcc/core/dist/exports/core/getEffects"; + +export type UseEffectsResult = { + loading: boolean; + error: Error | null; + result: GetEffectsResult | null; +}; + +export function useEffects(options: GetEffectsOptions): UseEffectsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getEffects(options) + .then((res) => { + if (!cancelled) { + setResult(res); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + options.forAccount, + options.forLedger, + options.forTransaction, + options.forOperation, + options.forLiquidityPool, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useLedgers.ts b/src/useStellar/useLedgers.ts index e69de29..3ee25e0 100644 --- a/src/useStellar/useLedgers.ts +++ b/src/useStellar/useLedgers.ts @@ -0,0 +1,47 @@ +import { useEffect, useState } from "react"; +import { getLedgers } from "@bluxcc/core"; + +import { + GetLedgersOptions, + GetLedgersResult, +} from "@bluxcc/core/dist/exports/core/getLedgers"; + +export type UseLedgersResult = { + loading: boolean; + error: Error | null; + result: GetLedgersResult | null; +}; + +export function useLedgers(options: GetLedgersOptions): UseLedgersResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getLedgers(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [options.network, options.cursor, options.limit, options.order, options.ledger]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useLiquidityPools.ts b/src/useStellar/useLiquidityPools.ts index e69de29..3fd2c4b 100644 --- a/src/useStellar/useLiquidityPools.ts +++ b/src/useStellar/useLiquidityPools.ts @@ -0,0 +1,58 @@ +// Gives "Issuer is invalid" + +import { useEffect, useState } from "react"; +import { getLiquidityPools } from "@bluxcc/core"; + +import { + GetLiquidityPoolsOptions, + GetLiquidityPoolsResult, +} from "@bluxcc/core/dist/exports/core/getLiquidityPools"; + +export type UseLiquidityPoolsResult = { + loading: boolean; + error: Error | null; + result: GetLiquidityPoolsResult | null; +}; + +export function useLiquidityPools( + options: GetLiquidityPoolsOptions +): UseLiquidityPoolsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getLiquidityPools(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + options.forAccount, + options.forAssets, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useTransactions.ts b/src/useStellar/useTransactions.ts index e69de29..3a41cc8 100644 --- a/src/useStellar/useTransactions.ts +++ b/src/useStellar/useTransactions.ts @@ -0,0 +1,573 @@ +// import { useCallback, useEffect, useRef, useState } from "react"; +// import { getTransactions as coreGetTransactions } from "@bluxcc/core"; + +// import type { +// GetTransactionsOptions as CoreGetTransactionsOptions, +// GetTransactionsResult as CoreGetTransactionsResult, +// } from "@bluxcc/core/dist/exports/core/getTransactions"; + +// export type QueryOptions = { +// enabled?: boolean; +// retry?: boolean | number | ((failureCount: number, error: Error) => boolean); +// retryDelay?: number | ((retryAttempt: number, error: Error) => number); +// initialData?: CoreGetTransactionsResult | (() => CoreGetTransactionsResult); +// initialDataUpdatedAt?: number | (() => number | undefined); +// placeholderData?: +// | CoreGetTransactionsResult +// | (( +// previousValue: CoreGetTransactionsResult | undefined, +// previousQuery: UseTransactionsBaseResult | undefined +// ) => CoreGetTransactionsResult); +// notifyOnChangeProps?: string[] | "all" | (() => string[] | "all"); +// refetchInterval?: +// | number +// | false +// | ((data: CoreGetTransactionsResult | undefined, query: UseTransactionsBaseResult) => number | false | undefined); +// refetchIntervalInBackground?: boolean; +// staleTime?: number | typeof Infinity | undefined; +// refetchOnMount?: boolean; +// refetchOnWindowFocus?: boolean; +// refetchOnReconnect?: boolean; +// select?: (data: CoreGetTransactionsResult) => TSelect; +// }; + +// export type Status = "error" | "pending" | "success"; +// export type FetchStatus = "fetching" | "idle" | "paused"; + +// export type UseTransactionsBaseResult = { +// data: TSelect | null; +// result: CoreGetTransactionsResult | null; + +// loading: boolean; +// isFetching: boolean; +// fetchStatus: FetchStatus; +// status: Status; +// error: Error | null; + +// updatedAt: number | null; +// dataUpdatedAt: number | null; +// errorUpdatedAt: number | null; +// failureCount: number; + +// refetch: () => Promise; +// cancel: () => void; + +// isStale: boolean; + +// isError: boolean; +// isPending: boolean; +// isSuccess: boolean; +// isPaused: boolean; +// isFetched: boolean; +// isLoading: boolean; +// isLoadingError: boolean; +// isRefetchError: boolean; +// isRefetching: boolean; +// isFetchedAfterMount: boolean; +// isPlaceholderData: boolean; +// }; + +// export function useTransactions( +// options: CoreGetTransactionsOptions, +// queryOptions?: QueryOptions +// ): UseTransactionsBaseResult { +// const enabled = queryOptions?.enabled !== false; + +// const hasInitialized = useRef(false); +// const prevStateRef = useRef | null>(null); +// const cancelledRef = useRef(false); + +// const retryTimerRef = useRef | null>(null); +// const failureCountRef = useRef(0); + +// const mountedRef = useRef(false); + +// const runSelect = useCallback( +// (res: CoreGetTransactionsResult): TSelect | null => { +// if (!queryOptions?.select) { +// return (res as unknown) as TSelect; +// } +// try { +// return queryOptions.select(res); +// } catch (e) { +// console.error("select() threw an error:", e); +// return null; +// } +// }, +// [queryOptions?.select] +// ); + +// const [result, setResult] = useState(() => { +// if (queryOptions?.initialData) { +// hasInitialized.current = true; +// return typeof queryOptions.initialData === "function" +// ? (queryOptions.initialData as () => CoreGetTransactionsResult)() +// : queryOptions.initialData; +// } +// if (queryOptions?.placeholderData) { +// return typeof queryOptions.placeholderData === "function" +// ? queryOptions.placeholderData(undefined, undefined) +// : queryOptions.placeholderData; +// } +// return null; +// }); + +// const [data, setData] = useState(() => { +// const initial = queryOptions?.initialData +// ? typeof queryOptions.initialData === "function" +// ? (queryOptions.initialData as () => CoreGetTransactionsResult)() +// : queryOptions.initialData +// : queryOptions?.placeholderData +// ? typeof queryOptions.placeholderData === "function" +// ? queryOptions.placeholderData(undefined, undefined) +// : queryOptions.placeholderData +// : null; + +// if (!initial) return null; +// return runSelect(initial); +// }); + +// const [updatedAt, setUpdatedAt] = useState(() => { +// return queryOptions?.initialData ? Date.now() : null; +// }); + +// const [dataUpdatedAt, setDataUpdatedAt] = useState(() => { +// if (queryOptions?.initialData && queryOptions?.initialDataUpdatedAt) { +// const val = +// typeof queryOptions.initialDataUpdatedAt === "function" +// ? queryOptions.initialDataUpdatedAt() +// : queryOptions.initialDataUpdatedAt; +// return typeof val === "number" ? val : null; +// } +// return null; +// }); + +// const [errorUpdatedAt, setErrorUpdatedAt] = useState(null); + +// const [failureCount, setFailureCount] = useState(0); +// const [error, setError] = useState(null); +// const [loading, setLoading] = useState(false); + +// const [fetchStatus, setFetchStatus] = useState(() => +// enabled ? "idle" : "paused" +// ); + +// const [isFetched, setIsFetched] = useState(false); + +// const [isLoading, setIsLoading] = useState(false); + +// const [isLoadingError, setIsLoadingError] = useState(false); + +// const [isRefetchError, setIsRefetchError] = useState(false); + +// const [isPlaceholderData, setIsPlaceholderData] = useState(() => { +// if (queryOptions?.initialData) return false; +// if (queryOptions?.placeholderData) return true; +// return false; +// }); + +// const shouldNotifyChange = useCallback( +// (nextState: UseTransactionsBaseResult) => { +// const rule = queryOptions?.notifyOnChangeProps; +// if (!rule) return true; + +// const prev = prevStateRef.current; +// if (!prev) return true; + +// const keys = typeof rule === "function" ? rule() : rule; +// if (keys === "all") return true; + +// for (const key of keys) { +// if (prev[key as keyof UseTransactionsBaseResult] !== nextState[key as keyof UseTransactionsBaseResult]) { +// return true; +// } +// } +// return false; +// }, +// [queryOptions?.notifyOnChangeProps] +// ); + +// const clearRetryTimer = () => { +// if (retryTimerRef.current) { +// clearTimeout(retryTimerRef.current); +// retryTimerRef.current = null; +// } +// }; + +// const computeShouldRetry = (count: number, err: Error): boolean => { +// const opt = queryOptions?.retry; +// if (opt === undefined) { +// return count < 3; +// } +// if (typeof opt === "boolean") { +// return opt === true; +// } +// if (typeof opt === "number") { +// return count < opt; +// } +// if (typeof opt === "function") { +// try { +// return Boolean(opt(count, err)); +// } catch (e) { +// console.warn("retry function threw", e); +// return false; +// } +// } +// return false; +// }; + +// const computeRetryDelayMs = (attempt: number, err?: Error): number => { +// const opt = queryOptions?.retryDelay; + +// const defaultDelay = Math.min(1000 * 2 ** (attempt - 1), 30000); + +// if (opt === undefined) return defaultDelay; +// if (typeof opt === "number") { +// return Math.max(0, Math.floor(opt)); +// } +// if (typeof opt === "function") { +// try { +// const val = opt(attempt, err as Error); +// return typeof val === "number" && !Number.isNaN(val) ? Math.max(0, Math.floor(val)) : defaultDelay; +// } catch (e) { +// console.warn("retryDelay function threw", e); +// return defaultDelay; +// } +// } +// return defaultDelay; +// }; + +// const isStale = useCallback((): boolean => { +// const staleTimeVal = queryOptions?.staleTime ?? 0; +// if (staleTimeVal === Infinity) return false; +// if (dataUpdatedAt === null) return true; +// return Date.now() - dataUpdatedAt >= (staleTimeVal || 0); +// }, [queryOptions?.staleTime, dataUpdatedAt]); + +// const [isFetchedAfterMount, setIsFetchedAfterMount] = useState(false); + +// useEffect(() => { +// mountedRef.current = true; +// return () => { +// mountedRef.current = false; +// }; +// }, []); + +// const runFetch = useCallback(async (): Promise => { +// if (!enabled) { +// setFetchStatus("paused"); +// return; +// } + +// clearRetryTimer(); + +// setError(null); +// setLoading(true); +// setFetchStatus("fetching"); +// setIsLoadingError(false); +// setIsRefetchError(false); +// cancelledRef.current = false; + +// try { +// const res = await coreGetTransactions(options); +// if (cancelledRef.current) return; + +// failureCountRef.current = 0; +// setFailureCount(0); +// clearRetryTimer(); + +// const selected = runSelect(res); + +// const now = Date.now(); + +// const nextState: UseTransactionsBaseResult = { +// data: selected, +// result: res, +// loading: false, +// isFetching: false, +// fetchStatus: "idle", +// isPaused: false, +// status: "success", +// error: null, +// updatedAt: now, +// dataUpdatedAt: now, +// errorUpdatedAt: prevStateRef.current?.errorUpdatedAt ?? null, +// failureCount: 0, +// refetch: async () => res, +// cancel: () => {}, +// isStale: false, +// isError: false, +// isPending: false, +// isSuccess: true, +// isFetched: true, +// isLoading: false, +// isLoadingError: false, +// isRefetchError: false, +// isRefetching: false, +// isFetchedAfterMount: mountedRef.current ? true : false, +// isPlaceholderData: false, +// }; + +// nextState.refetch = refetch as any; +// nextState.cancel = cancel as any; + +// hasInitialized.current = true; + +// setIsFetched(true); +// setIsLoadingError(false); +// setIsRefetchError(false); +// setIsPlaceholderData(false); +// if (mountedRef.current) { +// setIsFetchedAfterMount(true); +// } + +// if (shouldNotifyChange(nextState)) { +// setResult(res); +// setData(selected); +// setError(null); +// setUpdatedAt(now); +// setDataUpdatedAt(now); +// setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); +// setFetchStatus("idle"); +// setLoading(false); +// } else { +// setResult(res); +// setData(selected); +// setError(null); +// setUpdatedAt(now); +// setDataUpdatedAt(now); +// setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); +// setFetchStatus("idle"); +// setLoading(false); +// } + +// prevStateRef.current = nextState; +// return res; +// } catch (err: any) { +// if (cancelledRef.current) return; +// const e = err instanceof Error ? err : new Error(String(err)); + +// failureCountRef.current = (failureCountRef.current || 0) + 1; +// setFailureCount(failureCountRef.current); + +// const now = Date.now(); + +// const firstFetchFailed = !hasInitialized.current; +// const refetchFailed = !firstFetchFailed; + +// const nextState: UseTransactionsBaseResult = { +// data: null, +// result: null, +// loading: false, +// isFetching: false, +// fetchStatus: "idle", +// isPaused: false, +// status: "error", +// error: e, +// updatedAt: now, +// dataUpdatedAt: dataUpdatedAt, +// errorUpdatedAt: now, +// failureCount: failureCountRef.current, +// refetch: async () => undefined, +// cancel: () => {}, +// isStale: isStale(), +// isError: true, +// isPending: false, +// isSuccess: false, +// isFetched: true, +// isLoading: false, +// isLoadingError: firstFetchFailed, +// isRefetchError: refetchFailed, +// isRefetching: false, +// isFetchedAfterMount: mountedRef.current ? true : false, +// isPlaceholderData: false, +// }; + +// nextState.refetch = refetch as any; +// nextState.cancel = cancel as any; + +// setIsFetched(true); +// if (firstFetchFailed) { +// setIsLoadingError(true); +// } +// if (refetchFailed) { +// setIsRefetchError(true); +// } +// setIsPlaceholderData(false); +// if (mountedRef.current) { +// setIsFetchedAfterMount(true); +// } + +// if (shouldNotifyChange(nextState)) { +// setResult(null); +// setData(null); +// setError(e); +// setUpdatedAt(now); +// setErrorUpdatedAt(now); +// setFetchStatus("idle"); +// setLoading(false); +// } else { +// setError(e); +// setUpdatedAt(now); +// setErrorUpdatedAt(now); +// setFetchStatus("idle"); +// setLoading(false); +// } + +// prevStateRef.current = nextState; + +// const shouldRetry = computeShouldRetry(failureCountRef.current, e); + +// if (shouldRetry) { +// const delay = computeRetryDelayMs(failureCountRef.current, e); +// clearRetryTimer(); +// retryTimerRef.current = setTimeout(() => { +// if (cancelledRef.current) return; +// runFetch().catch(() => {}); +// }, delay); +// } + +// return undefined; +// } +// }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay, dataUpdatedAt]); + +// const refetch = useCallback(async () => { +// clearRetryTimer(); +// failureCountRef.current = 0; +// setFailureCount(0); +// cancelledRef.current = false; +// setIsLoadingError(false); +// setIsRefetchError(false); +// return runFetch(); +// }, [runFetch]); + +// const cancel = useCallback(() => { +// cancelledRef.current = true; +// clearRetryTimer(); +// setLoading(false); +// }, []); + +// const status: Status = error ? "error" : !hasInitialized.current ? "pending" : "success"; + +// const isError = status === "error"; +// const isPending = status === "pending"; +// const isSuccess = status === "success"; + +// const derivedIsFetching = fetchStatus === "fetching"; +// const derivedIsPaused = fetchStatus === "paused"; + +// const derivedIsLoading = derivedIsFetching && isPending; +// const derivedIsRefetching = derivedIsFetching && !isPending; + +// useEffect(() => { +// setIsLoading(derivedIsLoading); +// }, [derivedIsLoading]); + +// const currentState: UseTransactionsBaseResult = { +// data, +// result, +// loading, +// isFetching: derivedIsFetching, +// fetchStatus, +// isPaused: derivedIsPaused, +// status, +// error, +// updatedAt, +// dataUpdatedAt, +// errorUpdatedAt, +// failureCount, +// refetch, +// cancel, +// isStale: isStale(), + +// isError, +// isPending, +// isSuccess, + +// isFetched, +// isLoading, +// isLoadingError, +// isRefetchError, +// isRefetching: derivedIsRefetching, +// isFetchedAfterMount, +// isPlaceholderData, +// }; + +// prevStateRef.current = currentState; + +// useEffect(() => { +// if (!enabled) { +// setFetchStatus("paused"); +// } else { +// setFetchStatus((s) => (s === "fetching" ? s : "idle")); +// } +// }, [enabled]); + +// useEffect(() => { +// if (!enabled) return; + +// cancelledRef.current = false; + +// const shouldInitialFetch = !hasInitialized.current || (hasInitialized.current && queryOptions?.refetchOnMount && isStale()); + +// if (shouldInitialFetch) { +// runFetch().catch(() => {}); +// } + +// return () => { +// cancelledRef.current = true; +// clearRetryTimer(); +// }; +// }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, dataUpdatedAt]); + +// useEffect(() => { +// if (!enabled) return; + +// const onFocus = () => { +// if (queryOptions?.refetchOnWindowFocus && isStale()) { +// runFetch().catch(() => {}); +// } +// }; + +// const onOnline = () => { +// if (queryOptions?.refetchOnReconnect && isStale()) { +// runFetch().catch(() => {}); +// } +// }; + +// if (queryOptions?.refetchOnWindowFocus) { +// window.addEventListener("focus", onFocus); +// } +// if (queryOptions?.refetchOnReconnect) { +// window.addEventListener("online", onOnline); +// } + +// return () => { +// if (queryOptions?.refetchOnWindowFocus) { +// window.removeEventListener("focus", onFocus); +// } +// if (queryOptions?.refetchOnReconnect) { +// window.removeEventListener("online", onOnline); +// } +// }; +// }, [ +// enabled, +// queryOptions?.refetchOnWindowFocus, +// queryOptions?.refetchOnReconnect, +// queryOptions?.staleTime, +// dataUpdatedAt, +// isStale, +// runFetch, +// ]); + +// useEffect(() => { +// return () => { +// clearRetryTimer(); +// cancelledRef.current = true; +// }; +// }, []); + +// return currentState; +// } + +// export default useTransactions; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..408579d --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,34 @@ +import { getState } from '@bluxcc/core'; + +export type CallBuilderOptions = { + cursor?: string; + limit?: number; + network?: string; + order?: 'asc' | 'desc'; +}; + +export const checkConfigCreated = () => { + const { stellar } = getState(); + + return !!stellar; +}; + +export const getAddress = (address?: string) => { + const { user } = getState(); + + if (address) { + return address; + } + + return user?.address as string; +}; + +export const getNetwork = (network?: string) => { + const { stellar } = getState(); + + if (!network && stellar) { + return stellar.activeNetwork; + } + + return network; +}; \ No newline at end of file