Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 20 additions & 39 deletions src-gui/src/store/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { sortBy, sum, throttle } from "lodash";
import { sum, throttle } from "lodash";
import {
BobStateName,
GetSwapInfoResponseExt,
isBitcoinSyncProgress,
isPendingBackgroundProcess,
Expand All @@ -20,7 +19,6 @@ import {
} from "models/tauriModelExt";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { AppDispatch, RootState } from "renderer/store/storeRenderer";
import { parseDateString } from "utils/parseUtils";
import { useEffect, useMemo, useState } from "react";
import { isCliLogRelatedToSwap } from "models/cliModel";
import { SettingsState } from "./features/settingsSlice";
Expand All @@ -36,8 +34,12 @@ import { fnv1a } from "utils/hash";
import {
selectAllSwapInfos,
selectPendingApprovals,
selectResumableSwapsCount,
selectResumableSwapsCountExcludingPunished,
selectSaneSwapInfos,
selectSwapInfoWithTimelock,
selectSwapInfosRaw,
selectSwapInfosSortedByDate,
} from "./selectors";

export const useAppDispatch = () => useDispatch<AppDispatch>();
Expand All @@ -46,16 +48,19 @@ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export function useResumeableSwapsCount(
additionalFilter?: (s: GetSwapInfoResponseExt) => boolean,
) {
const saneSwapInfos = useSaneSwapInfos();
const defaultCount = useAppSelector(selectResumableSwapsCount);
const saneSwapInfos = useAppSelector(selectSaneSwapInfos);

return useAppSelector(
(state) =>
saneSwapInfos.filter(
(swapInfo: GetSwapInfoResponseExt) =>
!swapInfo.completed &&
(additionalFilter == null || additionalFilter(swapInfo)),
).length,
);
return useMemo(() => {
if (additionalFilter == null) {
return defaultCount;
}

return saneSwapInfos.filter(
(swapInfo: GetSwapInfoResponseExt) =>
!swapInfo.completed && additionalFilter(swapInfo),
).length;
}, [additionalFilter, defaultCount, saneSwapInfos]);
}

/**
Expand All @@ -64,11 +69,7 @@ export function useResumeableSwapsCount(
* - Swaps where the sanity check was not passed (e.g. they were aborted)
*/
export function useResumeableSwapsCountExcludingPunished() {
return useResumeableSwapsCount(
(s) =>
s.state_name !== BobStateName.BtcPunished &&
s.state_name !== BobStateName.SwapSetupCompleted,
);
return useAppSelector(selectResumableSwapsCountExcludingPunished);
}

/// Returns true if we have any swap that is running
Expand Down Expand Up @@ -155,32 +156,12 @@ export function useActiveSwapLogs() {
/// This hook returns the all swap infos, as an array
/// Excluding those who are in a state where it's better to hide them from the user
export function useSaneSwapInfos() {
const swapInfos = useAppSelector(selectAllSwapInfos);
return swapInfos.filter((swap) => {
// We hide swaps that are in the SwapSetupCompleted state
// This is because they are probably ones where:
// 1. The user force stopped the swap while we were waiting for their confirmation of the offer
// 2. We where therefore unable to transition to SafelyAborted
if (swap.state_name === BobStateName.SwapSetupCompleted) {
return false;
}

// We hide swaps that were safely aborted
// No funds were locked. Cannot be resumed.
// Wouldn't be beneficial to show them to the user
if (swap.state_name === BobStateName.SafelyAborted) {
return false;
}

return true;
});
return useAppSelector(selectSaneSwapInfos);
}

/// This hook returns the swap infos sorted by date
export function useSwapInfosSortedByDate() {
const swapInfos = useSaneSwapInfos();

return sortBy(swapInfos, (swap) => -parseDateString(swap.start_date));
return useAppSelector(selectSwapInfosSortedByDate);
}

/// Returns true if swapInfos has been loaded
Expand Down
37 changes: 36 additions & 1 deletion src-gui/src/store/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { createSelector } from "@reduxjs/toolkit";
import { RootState } from "renderer/store/storeRenderer";
import { GetSwapInfoResponseExt } from "models/tauriModelExt";
import { BobStateName, GetSwapInfoResponseExt } from "models/tauriModelExt";
import {
ConnectionStatus,
ExpiredTimelocks,
QuoteStatus,
} from "models/tauriModel";
import { parseDateString } from "utils/parseUtils";

const selectRpcState = (state: RootState) => state.rpc.state;
const selectP2pState = (state: RootState) => state.p2p;
Expand All @@ -24,6 +25,40 @@ export const selectAllSwapInfos = createSelector(
(rpcState) => (rpcState.swapInfos ? Object.values(rpcState.swapInfos) : []),
);

export const selectSaneSwapInfos = createSelector(
[selectAllSwapInfos],
(swapInfos) =>
swapInfos.filter(
(swap) =>
swap.state_name !== BobStateName.SwapSetupCompleted &&
swap.state_name !== BobStateName.SafelyAborted,
),
);

export const selectSwapInfosSortedByDate = createSelector(
[selectSaneSwapInfos],
(swapInfos) =>
[...swapInfos].sort(
(a, b) => parseDateString(b.start_date) - parseDateString(a.start_date),
),
);

export const selectResumableSwapsCount = createSelector(
[selectSaneSwapInfos],
(swapInfos) => swapInfos.filter((swapInfo) => !swapInfo.completed).length,
);

export const selectResumableSwapsCountExcludingPunished = createSelector(
[selectSaneSwapInfos],
(swapInfos) =>
swapInfos.filter(
(swapInfo) =>
!swapInfo.completed &&
swapInfo.state_name !== BobStateName.BtcPunished &&
swapInfo.state_name !== BobStateName.SwapSetupCompleted,
).length,
);

export const selectSwapTimelocks = createSelector(
[selectRpcState],
(rpcState) => rpcState.swapTimelocks,
Expand Down