@rango-dev/widget-embedded 0.20.1-next.22 → 0.20.1-next.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/QueueManager.d.ts.map +1 -1
- package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts +3 -3
- package/dist/components/ConfirmWalletsModal/WalletList.d.ts.map +1 -1
- package/dist/components/Layout/Layout.d.ts.map +1 -1
- package/dist/components/Quote/Quote.styles.d.ts +2 -2
- package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts +1 -0
- package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts +1 -0
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts +1 -0
- package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts +1 -0
- package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts.map +1 -1
- package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
- package/dist/components/SwapDetailsModal/SwapDetailsModal.WalletState.d.ts.map +1 -1
- package/dist/components/SwapDetailsModal/SwapDetailsModal.d.ts.map +1 -1
- package/dist/components/SwapDetailsModal/SwapDetailsModal.types.d.ts +2 -0
- package/dist/components/SwapDetailsModal/SwapDetailsModal.types.d.ts.map +1 -1
- package/dist/components/common/ActivateTabAlert/ActivateTabAlert.d.ts +4 -0
- package/dist/components/common/ActivateTabAlert/ActivateTabAlert.d.ts.map +1 -0
- package/dist/components/common/ActivateTabAlert/ActivateTabAlert.types.d.ts +4 -0
- package/dist/components/common/ActivateTabAlert/ActivateTabAlert.types.d.ts.map +1 -0
- package/dist/components/common/ActivateTabAlert/index.d.ts +2 -0
- package/dist/components/common/ActivateTabAlert/index.d.ts.map +1 -0
- package/dist/components/common/ActivateTabModal/ActivateTabModal.d.ts +4 -0
- package/dist/components/common/ActivateTabModal/ActivateTabModal.d.ts.map +1 -0
- package/dist/components/common/ActivateTabModal/ActivateTabModal.types.d.ts +6 -0
- package/dist/components/common/ActivateTabModal/ActivateTabModal.types.d.ts.map +1 -0
- package/dist/components/common/ActivateTabModal/index.d.ts +2 -0
- package/dist/components/common/ActivateTabModal/index.d.ts.map +1 -0
- package/dist/containers/Wallets/Wallets.d.ts.map +1 -1
- package/dist/containers/Widget/Widget.d.ts.map +1 -1
- package/dist/containers/WidgetInfo/WidgetInfo.d.ts.map +1 -1
- package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts +2 -0
- package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +4 -4
- package/dist/libs/tabManager/index.d.ts +3 -0
- package/dist/libs/tabManager/index.d.ts.map +1 -0
- package/dist/libs/tabManager/tabManager.constants.d.ts +4 -0
- package/dist/libs/tabManager/tabManager.constants.d.ts.map +1 -0
- package/dist/libs/tabManager/tabManager.d.ts +63 -0
- package/dist/libs/tabManager/tabManager.d.ts.map +1 -0
- package/dist/libs/tabManager/tabManager.types.d.ts +29 -0
- package/dist/libs/tabManager/tabManager.types.d.ts.map +1 -0
- package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
- package/dist/pages/Home.d.ts.map +1 -1
- package/dist/pages/WalletsPage.d.ts.map +1 -1
- package/dist/store/ui.d.ts +24 -0
- package/dist/store/ui.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/QueueManager.tsx +4 -1
- package/src/components/ConfirmWalletsModal/WalletList.tsx +3 -0
- package/src/components/Layout/Layout.tsx +36 -2
- package/src/components/QuoteWarningsAndErrors/HighValueLossWarningModal.tsx +3 -1
- package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.tsx +3 -1
- package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.ts +1 -0
- package/src/components/QuoteWarningsAndErrors/SlippageWariningModal.tsx +3 -1
- package/src/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.tsx +3 -1
- package/src/components/SwapDetails/SwapDetails.tsx +3 -0
- package/src/components/SwapDetailsModal/SwapDetailsModal.WalletState.tsx +9 -1
- package/src/components/SwapDetailsModal/SwapDetailsModal.tsx +10 -2
- package/src/components/SwapDetailsModal/SwapDetailsModal.types.ts +2 -0
- package/src/components/common/ActivateTabAlert/ActivateTabAlert.tsx +26 -0
- package/src/components/common/ActivateTabAlert/ActivateTabAlert.types.ts +3 -0
- package/src/components/common/ActivateTabAlert/index.ts +1 -0
- package/src/components/common/ActivateTabModal/ActivateTabModal.tsx +31 -0
- package/src/components/common/ActivateTabModal/ActivateTabModal.types.ts +5 -0
- package/src/components/common/ActivateTabModal/index.ts +1 -0
- package/src/containers/Wallets/Wallets.tsx +3 -1
- package/src/containers/Widget/Widget.tsx +6 -1
- package/src/containers/WidgetInfo/WidgetInfo.tsx +5 -1
- package/src/containers/WidgetInfo/WidgetInfo.types.ts +2 -0
- package/src/libs/tabManager/index.ts +2 -0
- package/src/libs/tabManager/tabManager.constants.ts +3 -0
- package/src/libs/tabManager/tabManager.ts +222 -0
- package/src/libs/tabManager/tabManager.types.ts +28 -0
- package/src/pages/ConfirmSwapPage.tsx +4 -1
- package/src/pages/Home.tsx +4 -1
- package/src/pages/WalletsPage.tsx +3 -0
- package/src/store/ui.ts +49 -0
|
@@ -7,6 +7,7 @@ import { useLanguage } from '../../hooks/useLanguage';
|
|
|
7
7
|
import { useAppStore } from '../../store/AppStore';
|
|
8
8
|
import { useNotificationStore } from '../../store/notification';
|
|
9
9
|
import { useQuoteStore } from '../../store/quote';
|
|
10
|
+
import { setCurrentTabAsActive, useUiStore } from '../../store/ui';
|
|
10
11
|
import { useWalletsStore } from '../../store/wallets';
|
|
11
12
|
import { calculateWalletUsdValue } from '../../utils/wallets';
|
|
12
13
|
|
|
@@ -18,6 +19,7 @@ export const WidgetInfoContext = createContext<
|
|
|
18
19
|
|
|
19
20
|
export function WidgetInfo(props: React.PropsWithChildren) {
|
|
20
21
|
const { manager } = useManager();
|
|
22
|
+
const isActiveTab = useUiStore.use.isActiveTab();
|
|
21
23
|
const retrySwap = useQuoteStore.use.retry();
|
|
22
24
|
const history = new WidgetHistory(manager, { retrySwap });
|
|
23
25
|
const details = useWalletsStore.use.connectedWallets();
|
|
@@ -32,7 +34,9 @@ export function WidgetInfo(props: React.PropsWithChildren) {
|
|
|
32
34
|
const notifications = useNotificationStore().getUnreadNotifications();
|
|
33
35
|
|
|
34
36
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
35
|
-
const value = {
|
|
37
|
+
const value: WidgetInfoContextInterface = {
|
|
38
|
+
isActiveTab,
|
|
39
|
+
setCurrentTabAsActive,
|
|
36
40
|
history,
|
|
37
41
|
wallets: {
|
|
38
42
|
isLoading,
|
|
@@ -6,6 +6,8 @@ import type { Notification } from '../../types/notification';
|
|
|
6
6
|
import type { BlockchainMeta, SwapperMeta, Token } from 'rango-sdk';
|
|
7
7
|
|
|
8
8
|
export interface WidgetInfoContextInterface {
|
|
9
|
+
isActiveTab: boolean;
|
|
10
|
+
setCurrentTabAsActive: () => void;
|
|
9
11
|
history: WidgetHistory;
|
|
10
12
|
wallets: {
|
|
11
13
|
details: ConnectedWallet[];
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Events,
|
|
3
|
+
ID,
|
|
4
|
+
Message,
|
|
5
|
+
TabManagerInterface,
|
|
6
|
+
} from './tabManager.types';
|
|
7
|
+
|
|
8
|
+
import { CHANNEL_NAME, MAXIMUM_TAB_ID, TIMEOUT } from './tabManager.constants';
|
|
9
|
+
|
|
10
|
+
export class TabManager implements TabManagerInterface {
|
|
11
|
+
private tabId: ID;
|
|
12
|
+
private state: 'not-initiated' | 'not-claimed' | 'claimed' = 'not-initiated';
|
|
13
|
+
private lastTryClaim: number | undefined;
|
|
14
|
+
private events: Events = {};
|
|
15
|
+
private channel: BroadcastChannel;
|
|
16
|
+
|
|
17
|
+
constructor(events: Events) {
|
|
18
|
+
this.channel = new BroadcastChannel(CHANNEL_NAME);
|
|
19
|
+
this.tabId = Math.trunc(Math.random() * MAXIMUM_TAB_ID);
|
|
20
|
+
this.events = events;
|
|
21
|
+
this.initEvents();
|
|
22
|
+
void this.tryClaim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* This is applicable when a user in an inactive tab seeks to activate that tab.
|
|
27
|
+
*/
|
|
28
|
+
forceClaim = () => {
|
|
29
|
+
if (!this.isClaimed()) {
|
|
30
|
+
const message: Message = { name: 'force-claim', candidateId: this.tabId };
|
|
31
|
+
this.channel.postMessage(message);
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
if (!this.isClaimed()) {
|
|
34
|
+
this.claim();
|
|
35
|
+
}
|
|
36
|
+
}, TIMEOUT);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
isClaimed = () => {
|
|
41
|
+
return this.state === 'claimed';
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* remove event listeners
|
|
46
|
+
*/
|
|
47
|
+
destroy = () => {
|
|
48
|
+
this.channel.removeEventListener('message', this.handleMessageEvent);
|
|
49
|
+
document.removeEventListener(
|
|
50
|
+
'visibilitychange',
|
|
51
|
+
this.handleVisibilityChange
|
|
52
|
+
);
|
|
53
|
+
document.removeEventListener('resume', this.handleResume);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Reacting to messages and window events to claim.
|
|
58
|
+
*/
|
|
59
|
+
private initEvents() {
|
|
60
|
+
this.channel.addEventListener('message', this.handleMessageEvent);
|
|
61
|
+
|
|
62
|
+
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The "resume" event is currently supported only in certain browsers.
|
|
66
|
+
* It is triggered when a previously frozen tab is unfrozen and resumes execution.
|
|
67
|
+
* To avoid having multiple active tabs,
|
|
68
|
+
* if the current tab is active after the "resume" event,
|
|
69
|
+
* we send a signal to other tabs to verify if any of them currently claim to be active.
|
|
70
|
+
* If this is the case, we deactivate the current tab.
|
|
71
|
+
* https://developer.chrome.com/docs/web-platform/page-lifecycle-api
|
|
72
|
+
*/
|
|
73
|
+
document.addEventListener('resume', this.handleResume);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Runs after a `ping` message and checks if current tab is claimed the tabs,
|
|
78
|
+
* if yes, it responds with `pong`, If not, it doesn't do anything.
|
|
79
|
+
*
|
|
80
|
+
* Note 1: If we receive a `ping` message,
|
|
81
|
+
* it means a tab is trying to claim tabs directly, usually it's the active tab.
|
|
82
|
+
*
|
|
83
|
+
* Note 2: If multiple tabs are opening at once, all of them are broadcasting `ping`
|
|
84
|
+
* and eventually all of them will `claim` the queue after the TIMEOUT.
|
|
85
|
+
* For avoiding this, we will accepts the oldest broadcasted ping. (`isPingSentBefore`)
|
|
86
|
+
*/
|
|
87
|
+
private claimedByCurrentTab(pingAt: number) {
|
|
88
|
+
const isPingSentBefore = this.lastTryClaim && this.lastTryClaim < pingAt;
|
|
89
|
+
|
|
90
|
+
if (this.isClaimed() || isPingSentBefore) {
|
|
91
|
+
const message: Message = {
|
|
92
|
+
name: 'pong',
|
|
93
|
+
};
|
|
94
|
+
this.channel.postMessage(message);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private handleMessageEvent = (event: MessageEvent<Message>) => {
|
|
100
|
+
const name = event.data.name;
|
|
101
|
+
|
|
102
|
+
switch (name) {
|
|
103
|
+
case 'ping':
|
|
104
|
+
this.claimedByCurrentTab(event.data.pingAt);
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
case 'pong':
|
|
108
|
+
this.alreadyClaimedByAnotherTab();
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
case 'force-claim':
|
|
112
|
+
this.forceRelease(event.data.candidateId);
|
|
113
|
+
break;
|
|
114
|
+
|
|
115
|
+
case 'force-release':
|
|
116
|
+
if (this.tabId === event.data.candidateId) {
|
|
117
|
+
this.claim();
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(`${name} is not supported.`);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
private handleVisibilityChange = async () => {
|
|
127
|
+
if (document.visibilityState === 'visible') {
|
|
128
|
+
await this.tryClaim();
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
private handleResume = async () => {
|
|
133
|
+
if (this.isClaimed()) {
|
|
134
|
+
await this.tryClaim();
|
|
135
|
+
if (!this.isClaimed()) {
|
|
136
|
+
this.events.onRelease?.();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Runs after receiving `pong` message, which means one of tabs already claimed the tabs.
|
|
142
|
+
*/
|
|
143
|
+
private alreadyClaimedByAnotherTab() {
|
|
144
|
+
this.resetLastCheck();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Try to send a `ping` message to know if the tabs `claimed` or not.
|
|
149
|
+
* On constructing instance, or whenever page is active we will try.
|
|
150
|
+
*/
|
|
151
|
+
private async tryClaim() {
|
|
152
|
+
/**
|
|
153
|
+
* Try to ask from possible other running tabs.
|
|
154
|
+
*/
|
|
155
|
+
this.setLastCheck();
|
|
156
|
+
return new Promise<void>((resolve) => {
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
this.check();
|
|
159
|
+
resolve();
|
|
160
|
+
}, TIMEOUT);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* If `lastCheck` is exist, it means there is no other tabs which `claimed` the tabs.
|
|
166
|
+
* And we mark the current tab as `claimed`
|
|
167
|
+
*/
|
|
168
|
+
private check() {
|
|
169
|
+
if (this.state === 'not-initiated') {
|
|
170
|
+
this.events.onInit?.();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
*it means we didn't get any response from other tabs, this tab can claim.
|
|
174
|
+
*/
|
|
175
|
+
if (this.lastTryClaim) {
|
|
176
|
+
this.claim();
|
|
177
|
+
this.resetLastCheck();
|
|
178
|
+
} else {
|
|
179
|
+
this.state = 'not-claimed';
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private claim() {
|
|
184
|
+
this.state = 'claimed';
|
|
185
|
+
this.events.onClaim?.();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Setting current time as `lastCheck` and broadcast a `ping` message event.
|
|
190
|
+
*/
|
|
191
|
+
private setLastCheck() {
|
|
192
|
+
this.lastTryClaim = Date.now();
|
|
193
|
+
const message: Message = {
|
|
194
|
+
name: 'ping',
|
|
195
|
+
pingAt: this.lastTryClaim,
|
|
196
|
+
};
|
|
197
|
+
this.channel.postMessage(message);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private resetLastCheck() {
|
|
201
|
+
this.lastTryClaim = undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Upon receipt of a "force-claim" message,
|
|
206
|
+
* the presently active tab is expected to deactivate itself and initiate any attached callback associated with this event.
|
|
207
|
+
*/
|
|
208
|
+
private forceRelease(nextActiveTab: ID) {
|
|
209
|
+
if (this.isClaimed()) {
|
|
210
|
+
this.state = 'not-claimed';
|
|
211
|
+
|
|
212
|
+
this.events.onRelease?.();
|
|
213
|
+
|
|
214
|
+
const message: Message = {
|
|
215
|
+
name: 'force-release',
|
|
216
|
+
candidateId: nextActiveTab,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
this.channel.postMessage(message);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type ID = number;
|
|
2
|
+
|
|
3
|
+
type PingMessage = { name: 'ping'; pingAt: number };
|
|
4
|
+
type PongMessage = { name: 'pong' };
|
|
5
|
+
type ForceClaimMessage = {
|
|
6
|
+
name: 'force-claim';
|
|
7
|
+
candidateId: ID;
|
|
8
|
+
};
|
|
9
|
+
type ForceReleaseMessage = { name: 'force-release'; candidateId: ID };
|
|
10
|
+
|
|
11
|
+
export type Message =
|
|
12
|
+
| PingMessage
|
|
13
|
+
| PongMessage
|
|
14
|
+
| ForceClaimMessage
|
|
15
|
+
| ForceReleaseMessage;
|
|
16
|
+
|
|
17
|
+
export type Events = {
|
|
18
|
+
// Initially attempt to verify if the tab can be activated.
|
|
19
|
+
onInit?: () => void;
|
|
20
|
+
onClaim?: () => void;
|
|
21
|
+
onRelease?: () => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export interface TabManagerInterface {
|
|
25
|
+
forceClaim: () => void;
|
|
26
|
+
isClaimed: () => boolean;
|
|
27
|
+
destroy: () => void;
|
|
28
|
+
}
|
|
@@ -34,6 +34,7 @@ import { QuoteInfo } from '../containers/QuoteInfo';
|
|
|
34
34
|
import { useConfirmSwap } from '../hooks/useConfirmSwap';
|
|
35
35
|
import { useAppStore } from '../store/AppStore';
|
|
36
36
|
import { useQuoteStore } from '../store/quote';
|
|
37
|
+
import { useUiStore } from '../store/ui';
|
|
37
38
|
import { useWalletsStore } from '../store/wallets';
|
|
38
39
|
import { QuoteWarningType } from '../types';
|
|
39
40
|
import { getContainer } from '../utils/common';
|
|
@@ -86,6 +87,7 @@ export function ConfirmSwapPage() {
|
|
|
86
87
|
const { connectedWallets } = useWalletsStore();
|
|
87
88
|
const showWalletsOnInit = !quoteWalletsConfirmed;
|
|
88
89
|
const [showWallets, setShowWallets] = useState(false);
|
|
90
|
+
const { isActiveTab } = useUiStore();
|
|
89
91
|
const disabledLiquiditySources = useAppStore().disabledLiquiditySources;
|
|
90
92
|
const prevDisabledLiquiditySources = useRef(disabledLiquiditySources);
|
|
91
93
|
const { manager } = useManager();
|
|
@@ -282,6 +284,7 @@ export function ConfirmSwapPage() {
|
|
|
282
284
|
loading={fetchingConfirmationQuote}
|
|
283
285
|
refetchQuote={onRefresh}
|
|
284
286
|
showWarningModal={showQuoteWarningModal}
|
|
287
|
+
confirmationDisabled={!isActiveTab}
|
|
285
288
|
onOpenWarningModal={() => setShowQuoteWarningModal(true)}
|
|
286
289
|
onCloseWarningModal={() => setShowQuoteWarningModal(false)}
|
|
287
290
|
onConfirmWarningModal={async () => {
|
|
@@ -324,7 +327,7 @@ export function ConfirmSwapPage() {
|
|
|
324
327
|
size="large"
|
|
325
328
|
fullWidth
|
|
326
329
|
loading={fetchingConfirmationQuote}
|
|
327
|
-
disabled={!!confirmSwapResult.error}
|
|
330
|
+
disabled={!!confirmSwapResult.error || !isActiveTab}
|
|
328
331
|
onClick={onStartConfirmSwap}>
|
|
329
332
|
{i18n.t('Start Swap')}
|
|
330
333
|
</Button>
|
package/src/pages/Home.tsx
CHANGED
|
@@ -21,6 +21,7 @@ import { QuoteInfo } from '../containers/QuoteInfo';
|
|
|
21
21
|
import { useSwapInput } from '../hooks/useSwapInput';
|
|
22
22
|
import { useAppStore } from '../store/AppStore';
|
|
23
23
|
import { useQuoteStore } from '../store/quote';
|
|
24
|
+
import { useUiStore } from '../store/ui';
|
|
24
25
|
import { useWalletsStore } from '../store/wallets';
|
|
25
26
|
import { getContainer } from '../utils/common';
|
|
26
27
|
import { formatTooltipNumbers, numberToString } from '../utils/numbers';
|
|
@@ -64,6 +65,7 @@ export function Home() {
|
|
|
64
65
|
const fetchMetaStatus = useAppStore().fetchStatus;
|
|
65
66
|
|
|
66
67
|
const { connectedWallets, getBalanceFor } = useWalletsStore();
|
|
68
|
+
const { isActiveTab } = useUiStore();
|
|
67
69
|
const [showQuoteWarningModal, setShowQuoteWarningModal] = useState(false);
|
|
68
70
|
const fetchingBalance =
|
|
69
71
|
!!fromBlockchain &&
|
|
@@ -128,7 +130,7 @@ export function Home() {
|
|
|
128
130
|
<Button
|
|
129
131
|
type="primary"
|
|
130
132
|
size="large"
|
|
131
|
-
disabled={swapButtonState.disabled}
|
|
133
|
+
disabled={swapButtonState.disabled || !isActiveTab}
|
|
132
134
|
prefix={
|
|
133
135
|
swapButtonState.action === 'confirm-warning' && <WarningIcon />
|
|
134
136
|
}
|
|
@@ -271,6 +273,7 @@ export function Home() {
|
|
|
271
273
|
loading={fetchingQuote}
|
|
272
274
|
refetchQuote={fetchQuote}
|
|
273
275
|
showWarningModal={showQuoteWarningModal}
|
|
276
|
+
confirmationDisabled={!isActiveTab}
|
|
274
277
|
onOpenWarningModal={() => setShowQuoteWarningModal(true)}
|
|
275
278
|
onCloseWarningModal={() => setShowQuoteWarningModal(false)}
|
|
276
279
|
onConfirmWarningModal={() => {
|
|
@@ -8,6 +8,7 @@ import { Layout, PageContainer } from '../components/Layout';
|
|
|
8
8
|
import { WalletModal } from '../components/WalletModal';
|
|
9
9
|
import { useWalletList } from '../hooks/useWalletList';
|
|
10
10
|
import { useAppStore } from '../store/AppStore';
|
|
11
|
+
import { useUiStore } from '../store/ui';
|
|
11
12
|
import { getContainer } from '../utils/common';
|
|
12
13
|
|
|
13
14
|
const ListContainer = styled('div', {
|
|
@@ -32,6 +33,7 @@ export function WalletsPage() {
|
|
|
32
33
|
const [openModal, setOpenModal] = useState(false);
|
|
33
34
|
const [selectedWalletType, setSelectedWalletType] = useState<WalletType>('');
|
|
34
35
|
let modalTimerId: ReturnType<typeof setTimeout> | null = null;
|
|
36
|
+
const isActiveTab = useUiStore.use.isActiveTab();
|
|
35
37
|
|
|
36
38
|
const { list, handleClick, error } = useWalletList({
|
|
37
39
|
config,
|
|
@@ -79,6 +81,7 @@ export function WalletsPage() {
|
|
|
79
81
|
void handleClick(type);
|
|
80
82
|
}}
|
|
81
83
|
isLoading={fetchMetaStatus === 'loading'}
|
|
84
|
+
disabled={!isActiveTab}
|
|
82
85
|
/>
|
|
83
86
|
);
|
|
84
87
|
})}
|
package/src/store/ui.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { TabManagerInterface } from '../libs/tabManager';
|
|
2
|
+
|
|
3
|
+
import { create } from 'zustand';
|
|
4
|
+
|
|
5
|
+
import { TabManager } from '../libs/tabManager';
|
|
6
|
+
|
|
7
|
+
import createSelectors from './selectors';
|
|
8
|
+
|
|
9
|
+
interface UiState {
|
|
10
|
+
isActiveTab: boolean;
|
|
11
|
+
tabManagerInitiated: boolean;
|
|
12
|
+
showActivateTabModal: boolean;
|
|
13
|
+
activateCurrentTab: (
|
|
14
|
+
setCurrentTabAsActive: () => void,
|
|
15
|
+
hasRunningSwaps: boolean
|
|
16
|
+
) => void;
|
|
17
|
+
setShowActivateTabModal: (flag: boolean) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useUiStore = createSelectors(
|
|
21
|
+
create<UiState>()((set, get) => ({
|
|
22
|
+
isActiveTab: false,
|
|
23
|
+
tabManagerInitiated: false,
|
|
24
|
+
showActivateTabModal: false,
|
|
25
|
+
activateCurrentTab: (setCurrentTabAsActive, hasRunningSwaps) => {
|
|
26
|
+
const { showActivateTabModal } = get();
|
|
27
|
+
|
|
28
|
+
if (!showActivateTabModal && hasRunningSwaps) {
|
|
29
|
+
set({ showActivateTabModal: true });
|
|
30
|
+
} else if (showActivateTabModal || !hasRunningSwaps) {
|
|
31
|
+
setCurrentTabAsActive();
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
setShowActivateTabModal: (flag) => {
|
|
35
|
+
set({ showActivateTabModal: flag });
|
|
36
|
+
},
|
|
37
|
+
}))
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const tabManager: TabManagerInterface = new TabManager({
|
|
41
|
+
onInit: () => useUiStore.setState({ tabManagerInitiated: true }),
|
|
42
|
+
onClaim: () =>
|
|
43
|
+
useUiStore.setState({ isActiveTab: true, showActivateTabModal: false }),
|
|
44
|
+
onRelease: () => useUiStore.setState({ isActiveTab: false }),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export const setCurrentTabAsActive = tabManager.forceClaim;
|
|
48
|
+
|
|
49
|
+
export const destroyTabManager = tabManager.destroy;
|