Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 8b005ec

Browse files
authored
feat: use expansion visibility service (#1537)
* feat: use expansion visibility service * chore: return usecallback * chore: resolve comments
1 parent f7c3fa5 commit 8b005ec

File tree

2 files changed

+158
-2
lines changed

2 files changed

+158
-2
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { useCallback } from "react";
2+
3+
import { useDelegationStorage } from "@/ui/common/hooks/storage/useDelegationStorage";
4+
import { useStakingExpansionState } from "@/ui/common/state/StakingExpansionState";
5+
import {
6+
DelegationV2,
7+
DelegationV2StakingState,
8+
} from "@/ui/common/types/delegationsV2";
9+
import { getExpansionsLocalStorageKey } from "@/ui/common/utils/local_storage/getExpansionsLocalStorageKey";
10+
11+
/**
12+
* Hook providing expansion visibility services.
13+
* Centralizes complex logic for determining which delegations should be visible
14+
* in different UI parts (Activity tab vs Verified Expansion Modal).
15+
*/
16+
export function useExpansionVisibilityService(
17+
publicKeyNoCoord: string | undefined,
18+
) {
19+
const { expansions } = useStakingExpansionState();
20+
21+
// Access expansion localStorage for broadcast status detection
22+
const expansionStorageKey = getExpansionsLocalStorageKey(publicKeyNoCoord);
23+
24+
// Get pending delegations from localStorage to check broadcast status
25+
const { delegations: expansionStorageDelegations } = useDelegationStorage(
26+
expansionStorageKey,
27+
expansions ?? [],
28+
);
29+
30+
/**
31+
* Checks if a delegation is a broadcasted expansion.
32+
* A broadcasted expansion must meet both criteria:
33+
* 1. Has VERIFIED status in the API data (delegation.state)
34+
* 2. Has INTERMEDIATE_PENDING_VERIFICATION status in localStorage (user broadcasted it)
35+
*/
36+
const isBroadcastedExpansion = useCallback(
37+
(delegation: DelegationV2): boolean => {
38+
// First, verify this is actually VERIFIED in the API data
39+
if (delegation.state !== DelegationV2StakingState.VERIFIED) {
40+
return false;
41+
}
42+
43+
// Then check if this delegation exists in localStorage with INTERMEDIATE_PENDING_VERIFICATION status
44+
const storedDelegation = (expansionStorageDelegations ?? []).find(
45+
(stored) =>
46+
stored.stakingTxHashHex.toLowerCase() ===
47+
delegation.stakingTxHashHex.toLowerCase(),
48+
);
49+
50+
return (
51+
storedDelegation?.state ===
52+
DelegationV2StakingState.INTERMEDIATE_PENDING_VERIFICATION
53+
);
54+
},
55+
[expansionStorageDelegations],
56+
);
57+
58+
/**
59+
* Checks if an original staking transaction should be hidden.
60+
* Original staking transactions are hidden when they have broadcasted expansions.
61+
*/
62+
const isOriginalTransactionHidden = useCallback(
63+
(stakeHashHex: string, delegations: DelegationV2[]): boolean => {
64+
// Find any expansion that references this original transaction
65+
const relatedExpansions = delegations.filter(
66+
(delegation) =>
67+
delegation.previousStakingTxHashHex === stakeHashHex &&
68+
isBroadcastedExpansion(delegation),
69+
);
70+
71+
return relatedExpansions.length > 0;
72+
},
73+
[isBroadcastedExpansion],
74+
);
75+
76+
/**
77+
* Returns delegations that should be visible in the Activity tab.
78+
* Applies the following rules:
79+
* 1. Exclude VERIFIED expansions that are not broadcasted (show in modal only)
80+
* 2. Include VERIFIED expansions that are broadcasted (INTERMEDIATE_PENDING_VERIFICATION)
81+
* 3. Exclude original transactions that have broadcasted expansions
82+
* 4. Include all other regular transactions
83+
*/
84+
const getActivityTabDelegations = useCallback(
85+
(delegations: DelegationV2[]): DelegationV2[] => {
86+
// Performance optimization: Pre-compute hidden transaction IDs to avoid O^2 complexity
87+
const hiddenOriginalTxIds = new Set<string>();
88+
89+
// First pass: identify all original transactions that should be hidden
90+
delegations.forEach((delegation) => {
91+
if (
92+
delegation.previousStakingTxHashHex &&
93+
isBroadcastedExpansion(delegation)
94+
) {
95+
hiddenOriginalTxIds.add(
96+
delegation.previousStakingTxHashHex.toLowerCase(),
97+
);
98+
}
99+
});
100+
101+
// Second pass: filter delegations using O(1) Set lookups
102+
return delegations.filter((delegation) => {
103+
// Always exclude EXPANDED state delegations (existing logic)
104+
if (delegation.state === DelegationV2StakingState.EXPANDED) {
105+
return false;
106+
}
107+
108+
// Handle VERIFIED expansions
109+
if (
110+
delegation.state === DelegationV2StakingState.VERIFIED &&
111+
delegation.previousStakingTxHashHex
112+
) {
113+
// Only include if it's been broadcasted by the user
114+
return isBroadcastedExpansion(delegation);
115+
}
116+
117+
// Check if this is an original transaction that should be hidden (O(1) lookup)
118+
if (
119+
hiddenOriginalTxIds.has(delegation.stakingTxHashHex.toLowerCase())
120+
) {
121+
return false;
122+
}
123+
124+
// Include all other transactions
125+
return true;
126+
});
127+
},
128+
[isBroadcastedExpansion],
129+
);
130+
131+
/**
132+
* Returns delegations that should be visible in the Verified Expansion Modal.
133+
* These are VERIFIED expansions with previousStakingTxHashHex that haven't been broadcasted yet.
134+
*/
135+
const getVerifiedExpansionModalDelegations = useCallback(
136+
(delegations: DelegationV2[]): DelegationV2[] => {
137+
return delegations.filter(
138+
(delegation) =>
139+
delegation.state === DelegationV2StakingState.VERIFIED &&
140+
delegation.previousStakingTxHashHex &&
141+
!isBroadcastedExpansion(delegation),
142+
);
143+
},
144+
[isBroadcastedExpansion],
145+
);
146+
147+
return {
148+
getActivityTabDelegations,
149+
getVerifiedExpansionModalDelegations,
150+
isOriginalTransactionHidden,
151+
isBroadcastedExpansion,
152+
};
153+
}

src/ui/common/utils/local_storage/getExpansionsLocalStorageKey.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { network } from "@/ui/common/config/network/btc";
22

33
const EXPANSIONS_KEY = "bbn-staking-expansions";
44

5+
// Safe no-op key to prevent potential issues with empty string
6+
const NO_KEY = "__NO_KEY__";
7+
58
// Get the local storage key for staking expansions
6-
export const getExpansionsLocalStorageKey = (pk: string) => {
7-
return pk ? `${EXPANSIONS_KEY}-${network}-${pk}` : "";
9+
export const getExpansionsLocalStorageKey = (pk: string | undefined) => {
10+
return pk ? `${EXPANSIONS_KEY}-${network}-${pk}` : NO_KEY;
811
};

0 commit comments

Comments
 (0)