find taler action in clipboard and withdraw with mobile
This commit is contained in:
parent
9b2d6d766f
commit
dda90b51f6
@ -25,9 +25,11 @@ import { platform } from "../platform/api.js";
|
|||||||
|
|
||||||
interface Type {
|
interface Type {
|
||||||
findTalerUriInActiveTab: () => Promise<string | undefined>;
|
findTalerUriInActiveTab: () => Promise<string | undefined>;
|
||||||
|
findTalerUriInClipboard: () => Promise<string | undefined>;
|
||||||
}
|
}
|
||||||
const Context = createContext<Type>({
|
const Context = createContext<Type>({
|
||||||
findTalerUriInActiveTab: async () => undefined,
|
findTalerUriInActiveTab: async () => undefined,
|
||||||
|
findTalerUriInClipboard: async () => undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +58,10 @@ export const IoCProviderForRuntime = ({
|
|||||||
children: any;
|
children: any;
|
||||||
}): VNode => {
|
}): VNode => {
|
||||||
return h(Context.Provider, {
|
return h(Context.Provider, {
|
||||||
value: { findTalerUriInActiveTab: platform.findTalerUriInActiveTab },
|
value: {
|
||||||
|
findTalerUriInActiveTab: platform.findTalerUriInActiveTab,
|
||||||
|
findTalerUriInClipboard: platform.findTalerUriInClipboard,
|
||||||
|
},
|
||||||
children,
|
children,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -122,13 +122,13 @@ export function ReadyView({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i18n.Translate>Exchange</i18n.Translate>
|
<i18n.Translate>Exchange</i18n.Translate>
|
||||||
<Link>
|
{/* <Link>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
title="Edit"
|
title="Edit"
|
||||||
dangerouslySetInnerHTML={{ __html: editIcon }}
|
dangerouslySetInnerHTML={{ __html: editIcon }}
|
||||||
color="black"
|
color="black"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link> */}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
text={<ExchangeDetails exchange={exchangeUrl} />}
|
text={<ExchangeDetails exchange={exchangeUrl} />}
|
||||||
|
@ -85,6 +85,7 @@ export namespace State {
|
|||||||
|
|
||||||
ageRestriction?: SelectFieldHandler;
|
ageRestriction?: SelectFieldHandler;
|
||||||
|
|
||||||
|
talerWithdrawUri?: string;
|
||||||
cancel: () => Promise<void>;
|
cancel: () => Promise<void>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -410,6 +410,7 @@ export function useComponentStateFromURI(
|
|||||||
toBeReceived,
|
toBeReceived,
|
||||||
withdrawalFee,
|
withdrawalFee,
|
||||||
chosenAmount,
|
chosenAmount,
|
||||||
|
talerWithdrawUri,
|
||||||
ageRestriction,
|
ageRestriction,
|
||||||
doWithdrawal: {
|
doWithdrawal: {
|
||||||
onClick:
|
onClick:
|
||||||
|
@ -23,6 +23,7 @@ import { SelectList } from "../../components/SelectList.js";
|
|||||||
import {
|
import {
|
||||||
Input,
|
Input,
|
||||||
Link,
|
Link,
|
||||||
|
LinkSuccess,
|
||||||
SubTitle,
|
SubTitle,
|
||||||
SuccessBox,
|
SuccessBox,
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
@ -35,6 +36,8 @@ import { TermsOfServiceSection } from "../TermsOfServiceSection.js";
|
|||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
import editIcon from "../../svg/edit_24px.svg";
|
import editIcon from "../../svg/edit_24px.svg";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
|
import { QR } from "../../components/QR.js";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -126,13 +129,13 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i18n.Translate>Exchange</i18n.Translate>
|
<i18n.Translate>Exchange</i18n.Translate>
|
||||||
<Link>
|
{/* <Link>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
title="Edit"
|
title="Edit"
|
||||||
dangerouslySetInnerHTML={{ __html: editIcon }}
|
dangerouslySetInnerHTML={{ __html: editIcon }}
|
||||||
color="black"
|
color="black"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link> */}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
text={<ExchangeDetails exchange={state.exchangeUrl} />}
|
text={<ExchangeDetails exchange={state.exchangeUrl} />}
|
||||||
@ -164,31 +167,36 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
</section>
|
</section>
|
||||||
{state.tosProps && <TermsOfServiceSection {...state.tosProps} />}
|
{state.tosProps && <TermsOfServiceSection {...state.tosProps} />}
|
||||||
{state.tosProps ? (
|
{state.tosProps ? (
|
||||||
<section>
|
<Fragment>
|
||||||
{(state.tosProps.terms.status === "accepted" ||
|
<section>
|
||||||
(state.mustAcceptFirst && state.tosProps.reviewed)) && (
|
{(state.tosProps.terms.status === "accepted" ||
|
||||||
<Button
|
(state.mustAcceptFirst && state.tosProps.reviewed)) && (
|
||||||
variant="contained"
|
<Button
|
||||||
color="success"
|
variant="contained"
|
||||||
disabled={!state.doWithdrawal.onClick}
|
color="success"
|
||||||
onClick={state.doWithdrawal.onClick}
|
disabled={!state.doWithdrawal.onClick}
|
||||||
>
|
onClick={state.doWithdrawal.onClick}
|
||||||
<i18n.Translate>
|
>
|
||||||
Withdraw <Amount value={state.toBeReceived} />
|
<i18n.Translate>
|
||||||
</i18n.Translate>
|
Withdraw <Amount value={state.toBeReceived} />
|
||||||
</Button>
|
</i18n.Translate>
|
||||||
)}
|
</Button>
|
||||||
{state.tosProps.terms.status === "notfound" && (
|
)}
|
||||||
<Button
|
{state.tosProps.terms.status === "notfound" && (
|
||||||
variant="contained"
|
<Button
|
||||||
color="warning"
|
variant="contained"
|
||||||
disabled={!state.doWithdrawal.onClick}
|
color="warning"
|
||||||
onClick={state.doWithdrawal.onClick}
|
disabled={!state.doWithdrawal.onClick}
|
||||||
>
|
onClick={state.doWithdrawal.onClick}
|
||||||
<i18n.Translate>Withdraw anyway</i18n.Translate>
|
>
|
||||||
</Button>
|
<i18n.Translate>Withdraw anyway</i18n.Translate>
|
||||||
)}
|
</Button>
|
||||||
</section>
|
)}
|
||||||
|
</section>
|
||||||
|
{state.talerWithdrawUri ? (
|
||||||
|
<WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} />
|
||||||
|
) : undefined}
|
||||||
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<section>
|
<section>
|
||||||
<i18n.Translate>Loading terms of service...</i18n.Translate>
|
<i18n.Translate>Loading terms of service...</i18n.Translate>
|
||||||
@ -202,3 +210,35 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function WithdrawWithMobile({
|
||||||
|
talerWithdrawUri,
|
||||||
|
}: {
|
||||||
|
talerWithdrawUri: string;
|
||||||
|
}): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
const [showQR, setShowQR] = useState<boolean>(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
|
||||||
|
{!showQR ? (
|
||||||
|
<i18n.Translate>Withdraw to a mobile phone</i18n.Translate>
|
||||||
|
) : (
|
||||||
|
<i18n.Translate>Hide QR</i18n.Translate>
|
||||||
|
)}
|
||||||
|
</LinkSuccess>
|
||||||
|
{showQR && (
|
||||||
|
<div>
|
||||||
|
<QR text={talerWithdrawUri} />
|
||||||
|
<i18n.Translate>
|
||||||
|
Scan the QR code or
|
||||||
|
<a href={talerWithdrawUri}>
|
||||||
|
<i18n.Translate>click here</i18n.Translate>
|
||||||
|
</a>
|
||||||
|
</i18n.Translate>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -17,20 +17,39 @@
|
|||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { useIocContext } from "../context/iocContext.js";
|
import { useIocContext } from "../context/iocContext.js";
|
||||||
|
|
||||||
|
export interface UriLocation {
|
||||||
|
uri: string;
|
||||||
|
location: "clipboard" | "activeTab"
|
||||||
|
}
|
||||||
|
|
||||||
export function useTalerActionURL(): [
|
export function useTalerActionURL(): [
|
||||||
string | undefined,
|
UriLocation | undefined,
|
||||||
(s: boolean) => void,
|
(s: boolean) => void,
|
||||||
] {
|
] {
|
||||||
const [talerActionUrl, setTalerActionUrl] = useState<string | undefined>(
|
const [talerActionUrl, setTalerActionUrl] = useState<UriLocation | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
const [dismissed, setDismissed] = useState(false);
|
const [dismissed, setDismissed] = useState(false);
|
||||||
const { findTalerUriInActiveTab } = useIocContext();
|
const { findTalerUriInActiveTab, findTalerUriInClipboard } = useIocContext();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function check(): Promise<void> {
|
async function check(): Promise<void> {
|
||||||
const talerUri = await findTalerUriInActiveTab();
|
const clipUri = await findTalerUriInClipboard();
|
||||||
setTalerActionUrl(talerUri);
|
if (clipUri) {
|
||||||
|
setTalerActionUrl({
|
||||||
|
location: "clipboard",
|
||||||
|
uri: clipUri
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tabUri = await findTalerUriInActiveTab();
|
||||||
|
if (tabUri) {
|
||||||
|
setTalerActionUrl({
|
||||||
|
location: "activeTab",
|
||||||
|
uri: tabUri
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
check();
|
check();
|
||||||
});
|
});
|
||||||
|
@ -163,13 +163,22 @@ export interface PlatformAPI {
|
|||||||
findTalerUriInActiveTab(): Promise<string | undefined>;
|
findTalerUriInActiveTab(): Promise<string | undefined>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used from the frontend to send commands to the wallet
|
* Popup API
|
||||||
*
|
*
|
||||||
* @param operation
|
* Read the current tab html and try to find any Taler URI or QR code present.
|
||||||
* @param payload
|
|
||||||
*
|
*
|
||||||
* @return response from the backend
|
* @return Taler URI if found
|
||||||
*/
|
*/
|
||||||
|
findTalerUriInClipboard(): Promise<string | undefined>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used from the frontend to send commands to the wallet
|
||||||
|
*
|
||||||
|
* @param operation
|
||||||
|
* @param payload
|
||||||
|
*
|
||||||
|
* @return response from the backend
|
||||||
|
*/
|
||||||
sendMessageToWalletBackground(
|
sendMessageToWalletBackground(
|
||||||
operation: string,
|
operation: string,
|
||||||
payload: any,
|
payload: any,
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
const api: PlatformAPI = {
|
const api: PlatformAPI = {
|
||||||
isFirefox,
|
isFirefox,
|
||||||
findTalerUriInActiveTab,
|
findTalerUriInActiveTab,
|
||||||
|
findTalerUriInClipboard,
|
||||||
getPermissionsApi,
|
getPermissionsApi,
|
||||||
getWalletWebExVersion,
|
getWalletWebExVersion,
|
||||||
listenToWalletBackground,
|
listenToWalletBackground,
|
||||||
@ -689,6 +690,11 @@ async function findTalerUriInTab(tabId: number): Promise<string | undefined> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function findTalerUriInClipboard(): Promise<string | undefined> {
|
||||||
|
const textInClipboard = await window.navigator.clipboard.readText();
|
||||||
|
return textInClipboard.startsWith("taler://") || textInClipboard.startsWith("taler+http://") ? textInClipboard : undefined
|
||||||
|
}
|
||||||
|
|
||||||
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
||||||
const tab = await getCurrentTab();
|
const tab = await getCurrentTab();
|
||||||
if (!tab || tab.id === undefined) return;
|
if (!tab || tab.id === undefined) return;
|
||||||
|
@ -23,6 +23,7 @@ const api: PlatformAPI = {
|
|||||||
isFirefox: () => false,
|
isFirefox: () => false,
|
||||||
keepAlive: (cb: VoidFunction) => cb(),
|
keepAlive: (cb: VoidFunction) => cb(),
|
||||||
findTalerUriInActiveTab: async () => undefined,
|
findTalerUriInActiveTab: async () => undefined,
|
||||||
|
findTalerUriInClipboard: async () => undefined,
|
||||||
containsTalerHeaderListener: () => {
|
containsTalerHeaderListener: () => {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -42,13 +42,15 @@ import { BalancePage } from "./BalancePage.js";
|
|||||||
import { TalerActionFound } from "./TalerActionFound.js";
|
import { TalerActionFound } from "./TalerActionFound.js";
|
||||||
|
|
||||||
function CheckTalerActionComponent(): VNode {
|
function CheckTalerActionComponent(): VNode {
|
||||||
const [talerActionUrl] = useTalerActionURL();
|
const [action] = useTalerActionURL();
|
||||||
|
|
||||||
|
const actionUri = action?.uri;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (talerActionUrl) {
|
if (actionUri) {
|
||||||
route(Pages.cta({ action: encodeURIComponent(talerActionUrl) }));
|
route(Pages.cta({ action: encodeURIComponent(actionUri) }));
|
||||||
}
|
}
|
||||||
}, [talerActionUrl]);
|
}, [actionUri]);
|
||||||
|
|
||||||
return <Fragment />;
|
return <Fragment />;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user