aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx118
1 files changed, 74 insertions, 44 deletions
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
index e87a8894f..d529d162b 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
@@ -17,52 +17,75 @@ import {
export interface Props {
initialValue?: string;
expectedCurrency?: string;
- knownExchanges: ExchangeListItem[];
onCancel: () => void;
onVerify: (s: string) => Promise<TalerConfigResponse | undefined>;
onConfirm: (url: string) => Promise<string | undefined>;
withError?: string;
}
+function useEndpointStatus<T>(
+ endpoint: string,
+ onVerify: (e: string) => Promise<T>,
+): {
+ loading: boolean;
+ error?: string;
+ endpoint: string;
+ result: T | undefined;
+ updateEndpoint: (s: string) => void;
+} {
+ const [value, setValue] = useState<string>(endpoint);
+ const [dirty, setDirty] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [result, setResult] = useState<T | undefined>(undefined);
+ const [error, setError] = useState<string | undefined>(undefined);
+
+ const [handler, setHandler] = useState<number | undefined>(undefined);
+
+ useEffect(() => {
+ if (!value) return;
+ window.clearTimeout(handler);
+ const h = window.setTimeout(async () => {
+ setDirty(true);
+ setLoading(true);
+ try {
+ const url = canonicalizeBaseUrl(value);
+ const result = await onVerify(url);
+ setResult(result);
+ setError(undefined);
+ setLoading(false);
+ } catch (e) {
+ const errorMessage =
+ e instanceof Error ? e.message : `unknown error: ${e}`;
+ setError(errorMessage);
+ setLoading(false);
+ setResult(undefined);
+ }
+ }, 500);
+ setHandler(h);
+ }, [value]);
+
+ return {
+ error: dirty ? error : undefined,
+ loading: loading,
+ result: result,
+ endpoint: value,
+ updateEndpoint: setValue,
+ };
+}
+
export function ExchangeSetUrlPage({
initialValue,
- knownExchanges,
expectedCurrency,
onCancel,
onVerify,
onConfirm,
- withError,
}: Props) {
- const [value, setValue] = useState<string>(initialValue || "");
- const [dirty, setDirty] = useState(false);
- const [result, setResult] = useState<TalerConfigResponse | undefined>(
- undefined,
- );
- const [error, setError] = useState<string | undefined>(withError);
-
- useEffect(() => {
- try {
- const url = canonicalizeBaseUrl(value);
+ const { loading, result, endpoint, updateEndpoint, error } =
+ useEndpointStatus(initialValue ?? "", onVerify);
- const found =
- knownExchanges.findIndex((e) => e.exchangeBaseUrl === url) !== -1;
-
- if (found) {
- setError("This exchange is already known");
- return;
- }
- onVerify(url)
- .then((r) => {
- setResult(r);
- })
- .catch(() => {
- setResult(undefined);
- });
- setDirty(true);
- } catch {
- setResult(undefined);
- }
- }, [value]);
+ const [confirmationError, setConfirmationError] = useState<
+ string | undefined
+ >(undefined);
return (
<Fragment>
@@ -72,21 +95,32 @@ export function ExchangeSetUrlPage({
) : (
<h2>Add exchange for {expectedCurrency}</h2>
)}
+ {result && expectedCurrency && expectedCurrency !== result.currency && (
+ <WarningBox>
+ This exchange doesn't match the expected currency{" "}
+ <b>{expectedCurrency}</b>
+ </WarningBox>
+ )}
<ErrorMessage
title={error && "Unable to add this exchange"}
description={error}
/>
+ <ErrorMessage
+ title={confirmationError && "Unable to add this exchange"}
+ description={confirmationError}
+ />
<p>
- <Input invalid={dirty && !!error}>
+ <Input invalid={!!error}>
<label>URL</label>
<input
type="text"
placeholder="https://"
- value={value}
- onInput={(e) => setValue(e.currentTarget.value)}
+ value={endpoint}
+ onInput={(e) => updateEndpoint(e.currentTarget.value)}
/>
</Input>
- {result && (
+ {loading && <div>loading... </div>}
+ {result && !loading && (
<Fragment>
<Input>
<label>Version</label>
@@ -100,12 +134,6 @@ export function ExchangeSetUrlPage({
)}
</p>
</section>
- {result && expectedCurrency && expectedCurrency !== result.currency && (
- <WarningBox>
- This exchange doesn't match the expected currency{" "}
- <b>{expectedCurrency}</b>
- </WarningBox>
- )}
<footer>
<Button onClick={onCancel}>
<i18n.Translate>Cancel</i18n.Translate>
@@ -118,8 +146,10 @@ export function ExchangeSetUrlPage({
expectedCurrency !== result.currency)
}
onClick={() => {
- const url = canonicalizeBaseUrl(value);
- return onConfirm(url).then((r) => (r ? setError(r) : undefined));
+ const url = canonicalizeBaseUrl(endpoint);
+ return onConfirm(url).then((r) =>
+ r ? setConfirmationError(r) : undefined,
+ );
}}
>
<i18n.Translate>Next</i18n.Translate>