diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta/Withdraw/state.ts')
-rw-r--r-- | packages/taler-wallet-webextension/src/cta/Withdraw/state.ts | 140 |
1 files changed, 91 insertions, 49 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts index 05aef690e..90ad65d6e 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -14,14 +14,14 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -/* eslint-disable react-hooks/rules-of-hooks */ import { AmountJson, + AmountString, Amounts, ExchangeFullDetails, ExchangeListItem, NotificationType, - TalerError, + TransactionMajorState, parseWithdrawExchangeUri, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; @@ -44,6 +44,7 @@ export function useComponentStateFromParams({ const api = useBackendContext(); const { i18n } = useTranslationContext(); const paramsAmount = amount ? Amounts.parse(amount) : undefined; + const [updatedExchangeByUser, setUpdatedExchangeByUser] = useState<string>(); const uriInfoHook = useAsyncAsHook(async () => { const exchanges = await api.wallet.call( WalletApiOperation.ListExchanges, @@ -52,12 +53,12 @@ export function useComponentStateFromParams({ const uri = maybeTalerUri ? parseWithdrawExchangeUri(maybeTalerUri) : undefined; - const exchangeByTalerUri = uri?.exchangeBaseUrl; + const exchangeByTalerUri = updatedExchangeByUser ?? uri?.exchangeBaseUrl; + let ex: ExchangeFullDetails | undefined; - if (exchangeByTalerUri && uri.exchangePub) { + if (exchangeByTalerUri) { await api.wallet.call(WalletApiOperation.AddExchange, { exchangeBaseUrl: exchangeByTalerUri, - masterPub: uri.exchangePub, }); const info = await api.wallet.call( WalletApiOperation.GetExchangeDetailedInfo, @@ -159,6 +160,7 @@ export function useComponentStateFromParams({ async function doManualWithdraw( exchange: string, ageRestricted: number | undefined, + amount: AmountString, ): Promise<{ transactionId: string; confirmTransferUrl: string | undefined; @@ -167,7 +169,7 @@ export function useComponentStateFromParams({ WalletApiOperation.AcceptManualWithdrawal, { exchangeBaseUrl: exchange, - amount: Amounts.stringify(chosenAmount), + amount, restrictAge: ageRestricted, }, ); @@ -184,8 +186,10 @@ export function useComponentStateFromParams({ onSuccess, undefined, chosenAmount, + chosenAmount.currency, exchangeList, exchangeByTalerUri, + setUpdatedExchangeByUser, ); } @@ -196,6 +200,8 @@ export function useComponentStateFromURI({ }: PropsFromURI): RecursiveState<State> { const api = useBackendContext(); const { i18n } = useTranslationContext(); + + const [updatedExchangeByUser, setUpdatedExchangeByUser] = useState<string>(); /** * Ask the wallet about the withdraw URI */ @@ -206,31 +212,33 @@ export function useComponentStateFromURI({ : maybeTalerUri; const uriInfo = await api.wallet.call( - WalletApiOperation.GetWithdrawalDetailsForUri, + WalletApiOperation.PrepareBankIntegratedWithdrawal, { talerWithdrawUri, - notifyChangeFromPendingTimeoutMs: 30 * 1000, + selectedExchange: updatedExchangeByUser, }, ); const { amount, defaultExchangeBaseUrl, possibleExchanges, - operationId, confirmTransferUrl, status, - } = uriInfo; - const transaction = await api.wallet.call( - WalletApiOperation.GetWithdrawalTransactionByUri, - { talerWithdrawUri }, - ); + } = uriInfo.info; + const txInfo = + uriInfo.transactionId === undefined + ? undefined + : await api.wallet.call(WalletApiOperation.GetTransactionById, { + transactionId: uriInfo.transactionId, + }); return { talerWithdrawUri, - operationId, status, - transaction, + transactionId: uriInfo.transactionId, + currency: uriInfo.info.currency, + txInfo: txInfo, confirmTransferUrl, - amount: Amounts.parseOrThrow(amount), + amount: !amount ? undefined : Amounts.parseOrThrow(amount), thisExchange: defaultExchangeBaseUrl, exchanges: possibleExchanges, }; @@ -239,13 +247,20 @@ export function useComponentStateFromURI({ const readyToListen = uriInfoHook && !uriInfoHook.hasError; useEffect(() => { - if (!uriInfoHook) { + if (!uriInfoHook || uriInfoHook.hasError) { return; } + const txId = uriInfoHook.response.transactionId; + return api.listener.onUpdateNotification( - [NotificationType.WithdrawalOperationTransition], - (asd) => { - uriInfoHook.retry(); + [NotificationType.TransactionStateTransition], + (notif) => { + if ( + notif.type === NotificationType.TransactionStateTransition && + notif.transactionId === txId + ) { + uriInfoHook.retry(); + } }, ); }, [readyToListen]); @@ -264,39 +279,45 @@ export function useComponentStateFromURI({ } const uri = uriInfoHook.response.talerWithdrawUri; - const chosenAmount = uriInfoHook.response.amount; + const txId = uriInfoHook.response.transactionId; + const infoAmount = uriInfoHook.response.amount; const defaultExchange = uriInfoHook.response.thisExchange; const exchangeList = uriInfoHook.response.exchanges; async function doManagedWithdraw( exchange: string, ageRestricted: number | undefined, + amount: AmountString, ): Promise<{ transactionId: string; confirmTransferUrl: string | undefined; }> { - const res = await api.wallet.call( - WalletApiOperation.AcceptBankIntegratedWithdrawal, - { - exchangeBaseUrl: exchange, - talerWithdrawUri: uri, - restrictAge: ageRestricted, - }, - ); + if (!txId) { + throw Error("can't confirm transaction"); + } + const res = await api.wallet.call(WalletApiOperation.ConfirmWithdrawal, { + exchangeBaseUrl: exchange, + amount, + restrictAge: ageRestricted, + transactionId: txId, + }); return { confirmTransferUrl: res.confirmTransferUrl, transactionId: res.transactionId, }; } - if (uriInfoHook.response.status !== "pending") { - if (uriInfoHook.response.transaction) { - onSuccess(uriInfoHook.response.transaction.transactionId); - } + if ( + uriInfoHook.response.txInfo && + uriInfoHook.response.status !== "pending" + ) { + const info = uriInfoHook.response.txInfo; return { status: "already-completed", operationState: uriInfoHook.response.status, confirmTransferUrl: uriInfoHook.response.confirmTransferUrl, + thisWallet: info.txState.major === TransactionMajorState.Pending, + redirectToTx: () => onSuccess(info.transactionId), error: undefined, }; } @@ -307,9 +328,11 @@ export function useComponentStateFromURI({ cancel, onSuccess, uri, - chosenAmount, + infoAmount, + uriInfoHook.response.currency, exchangeList, defaultExchange, + setUpdatedExchangeByUser, ); }, []); } @@ -317,6 +340,7 @@ export function useComponentStateFromURI({ type ManualOrManagedWithdrawFunction = ( exchange: string, ageRestricted: number | undefined, + amount: AmountString, ) => Promise<{ transactionId: string; confirmTransferUrl: string | undefined }>; function exchangeSelectionState( @@ -324,21 +348,37 @@ function exchangeSelectionState( cancel: () => Promise<void>, onSuccess: (txid: string) => Promise<void>, talerWithdrawUri: string | undefined, - chosenAmount: AmountJson, + infoAmount: AmountJson | undefined, + currency: string, exchangeList: ExchangeListItem[], exchangeSuggestedByTheBank: string | undefined, + onExchangeUpdated: (ex: string) => void, ): RecursiveState<State> { const api = useBackendContext(); const selectedExchange = useSelectedExchange({ - currency: chosenAmount.currency, + currency: currency, defaultExchange: exchangeSuggestedByTheBank, list: exchangeList, }); + const current = + selectedExchange.status !== "ready" + ? undefined + : selectedExchange.selected.exchangeBaseUrl; + useEffect(() => { + if (current) { + onExchangeUpdated(current); + } + }, [current]); + + const safeAmount = !infoAmount ? Amounts.zeroOfCurrency(currency) : infoAmount + const [choosenAmount, setChoosenAmount] = useState(safeAmount) + if (selectedExchange.status !== "ready") { return selectedExchange; } + return useCallback((): | State.Success | State.LoadingUriError @@ -348,9 +388,7 @@ function exchangeSelectionState( const [ageRestricted, setAgeRestricted] = useState(0); const currentExchange = selectedExchange.selected; - const [selectedCurrency, setSelectedCurrency] = useState<string>( - chosenAmount.currency, - ); + const [selectedCurrency, setSelectedCurrency] = useState<string>(currency); /** * With the exchange and amount, ask the wallet the information * about the withdrawal @@ -360,7 +398,7 @@ function exchangeSelectionState( WalletApiOperation.GetWithdrawalDetailsForAmount, { exchangeBaseUrl: currentExchange.exchangeBaseUrl, - amount: Amounts.stringify(chosenAmount), + amount: Amounts.stringify(choosenAmount), restrictAge: ageRestricted, }, ); @@ -377,9 +415,6 @@ function exchangeSelectionState( }; }, []); - const [withdrawError, setWithdrawError] = useState<TalerError | undefined>( - undefined, - ); const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false); async function doWithdrawAndCheckError(): Promise<void> { @@ -388,6 +423,7 @@ function exchangeSelectionState( const res = await doWithdraw( currentExchange.exchangeBaseUrl, !ageRestricted ? undefined : ageRestricted, + Amounts.stringify(choosenAmount), ); if (res.confirmTransferUrl) { document.location.href = res.confirmTransferUrl; @@ -395,9 +431,9 @@ function exchangeSelectionState( onSuccess(res.transactionId); } } catch (e) { - if (e instanceof TalerError) { - setWithdrawError(e); - } + console.error(e); + // if (e instanceof TalerError) { + // } } setDoingWithdraw(false); } @@ -427,7 +463,7 @@ function exchangeSelectionState( const ageRestrictionOptions = amountHook.response.ageRestrictionOptions?.reduce( - (p, c) => ({ ...p, [c]: `under ${c}` }), + (p, c) => ({ ...p, [c]: i18n.str`under ${c}` }), {} as Record<string, string>, ); @@ -454,6 +490,7 @@ function exchangeSelectionState( altCurrencies.length === 0 ? [] : [toBeReceived.currency, ...altCurrencies]; + const convAccount = amountHook.response.accounts.find((c) => { return ( c.currencySpecification && @@ -480,7 +517,12 @@ function exchangeSelectionState( }, conversionInfo, withdrawalFee, - chosenAmount, + amount: { + value: choosenAmount, + onInput: pushAlertOnError(async (v) => { + setChoosenAmount(v) + }) + }, talerWithdrawUri, ageRestriction, doWithdrawal: { |