-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathuseRampsPaymentMethods.ts
More file actions
167 lines (152 loc) · 4.8 KB
/
useRampsPaymentMethods.ts
File metadata and controls
167 lines (152 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import { useCallback, useEffect, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useSelector } from 'react-redux';
import { strings } from '../../../../../locales/i18n';
import {
selectPaymentMethods,
selectProviders,
selectTokens,
selectUserRegion,
} from '../../../../selectors/rampsController';
import { type PaymentMethod } from '@metamask/ramps-controller';
import Engine from '../../../../core/Engine';
import { rampsQueries } from '../queries';
import { parseUserFacingError } from '../utils/parseUserFacingError';
import { normalizeAssetIdForApi } from '../utils/normalizeAssetIdForApi';
export type RampsQueryStatus = 'idle' | 'loading' | 'success' | 'error';
/**
* Result returned by the useRampsPaymentMethods hook.
*/
export interface UseRampsPaymentMethodsResult {
/**
* The list of payment methods available for the current context.
*/
paymentMethods: PaymentMethod[];
/**
* The currently selected payment method, or null if none selected.
*/
selectedPaymentMethod: PaymentMethod | null;
/**
* Sets the selected payment method by ID.
* @param paymentMethod - The payment method to select, or null to clear selection.
*/
setSelectedPaymentMethod: (paymentMethod: PaymentMethod | null) => void;
/**
* Whether the payment methods request is currently loading (no cached data).
*/
isLoading: boolean;
/**
* Whether a fetch is in-flight (includes background refetches with cached data).
*/
isFetching: boolean;
/**
* Query lifecycle status for the active payment methods request.
*/
status: RampsQueryStatus;
/**
* Whether the active payment methods request completed successfully.
*/
isSuccess: boolean;
/**
* The error message if the request failed, or null.
*/
error: string | null;
}
/**
* Hook to get payment methods via React Query.
*
* The query fires only when a provider is selected (provider change is the
* sole trigger). Token and fiat are passed to the API call but are NOT part
* of the query key, so changing them does not cause a refetch.
*
* @returns Payment methods state.
*/
export function useRampsPaymentMethods(): UseRampsPaymentMethodsResult {
const { selected: selectedPaymentMethod } = useSelector(selectPaymentMethods);
const { selected: selectedProvider } = useSelector(selectProviders);
const { selected: selectedToken } = useSelector(selectTokens);
const userRegion = useSelector(selectUserRegion);
const queryEnabled = Boolean(
userRegion?.regionCode &&
userRegion?.country?.currency &&
selectedProvider?.id,
);
const paymentMethodsQuery = useQuery({
...rampsQueries.paymentMethods.options({
regionCode: userRegion?.regionCode ?? '',
fiat: userRegion?.country?.currency ?? '',
assetId: normalizeAssetIdForApi(selectedToken?.assetId),
providerId: selectedProvider?.id ?? '',
}),
enabled: queryEnabled,
});
const setSelectedPaymentMethod = useCallback(
(paymentMethod: PaymentMethod | null) =>
(
Engine.context.RampsController as {
setSelectedPaymentMethod: (
pm?: PaymentMethod | string | null,
) => void;
}
).setSelectedPaymentMethod(paymentMethod),
[],
);
useEffect(() => {
const methods = paymentMethodsQuery.data;
if (!methods || methods.length === 0) return;
let target: PaymentMethod | null = null;
if (selectedPaymentMethod) {
target = methods.find((m) => m.id === selectedPaymentMethod.id) ?? null;
}
if (!target) {
target = methods[0];
}
if (target.id !== selectedPaymentMethod?.id) {
setSelectedPaymentMethod(target);
}
}, [
paymentMethodsQuery.data,
selectedPaymentMethod,
setSelectedPaymentMethod,
]);
const isAutoSelecting = Boolean(
paymentMethodsQuery.data?.length &&
(!selectedPaymentMethod ||
paymentMethodsQuery.data.every(
(m) => m.id !== selectedPaymentMethod.id,
)),
);
const status = useMemo<RampsQueryStatus>(() => {
if (!queryEnabled) {
return 'idle';
}
if (paymentMethodsQuery.isLoading) {
return 'loading';
}
if (paymentMethodsQuery.isError) {
return 'error';
}
return 'success';
}, [
paymentMethodsQuery.isError,
paymentMethodsQuery.isLoading,
queryEnabled,
]);
return {
paymentMethods: paymentMethodsQuery.data ?? [],
selectedPaymentMethod,
setSelectedPaymentMethod,
isLoading: status === 'loading' || isAutoSelecting,
isFetching: paymentMethodsQuery.isFetching,
status,
isSuccess: status === 'success',
error:
paymentMethodsQuery.error != null
? parseUserFacingError(
paymentMethodsQuery.error,
strings('fiat_on_ramp.payment_error'),
)
: null,
};
}
export default useRampsPaymentMethods;