diff options
Diffstat (limited to 'packages/taler-wallet-webextension')
8 files changed, 141 insertions, 48 deletions
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index fc917088d..527600c96 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -128,6 +128,7 @@ export const Pages = { ctaWithdraw: "/cta/withdraw", ctaDeposit: "/cta/deposit", ctaExperiment: "/cta/experiment", + ctaAddExchange: "/cta/add/exchange", ctaInvoiceCreate: pageDefinition<{ amount?: string }>( "/cta/invoice/create/:amount?", ), @@ -153,6 +154,7 @@ const talerUriActionToPageName: { [TalerUriAction.PayTemplate]: "ctaPayTemplate", [TalerUriAction.WithdrawExchange]: "ctaWithdrawManual", [TalerUriAction.DevExperiment]: "ctaExperiment", + [TalerUriAction.AddExchange]: "ctaAddExchange", }; export function getPathnameForTalerURI(talerUri: string): string | undefined { diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index ee071347a..6c5510eb6 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -221,6 +221,13 @@ function openWalletURIFromPopup(uri: TalerUri): void { )}`, ); break; + case TalerUriAction.AddExchange: + url = chrome.runtime.getURL( + `static/wallet.html#/cta/add/exchange?talerUri=${encodeURIComponent( + talerUri, + )}`, + ); + break; case TalerUriAction.DevExperiment: logger.warn(`taler://dev-experiment URIs are not allowed in headers`); return; @@ -474,26 +481,26 @@ function setAlertedIcon(): void { interface OffscreenCanvasRenderingContext2D extends CanvasState, - CanvasTransform, - CanvasCompositing, - CanvasImageSmoothing, - CanvasFillStrokeStyles, - CanvasShadowStyles, - CanvasFilters, - CanvasRect, - CanvasDrawPath, - CanvasUserInterface, - CanvasText, - CanvasDrawImage, - CanvasImageData, - CanvasPathDrawingStyles, - CanvasTextDrawingStyles, - CanvasPath { + CanvasTransform, + CanvasCompositing, + CanvasImageSmoothing, + CanvasFillStrokeStyles, + CanvasShadowStyles, + CanvasFilters, + CanvasRect, + CanvasDrawPath, + CanvasUserInterface, + CanvasText, + CanvasDrawImage, + CanvasImageData, + CanvasPathDrawingStyles, + CanvasTextDrawingStyles, + CanvasPath { readonly canvas: OffscreenCanvas; } declare const OffscreenCanvasRenderingContext2D: { prototype: OffscreenCanvasRenderingContext2D; - new (): OffscreenCanvasRenderingContext2D; + new(): OffscreenCanvasRenderingContext2D; }; interface OffscreenCanvas extends EventTarget { @@ -506,7 +513,7 @@ interface OffscreenCanvas extends EventTarget { } declare const OffscreenCanvas: { prototype: OffscreenCanvas; - new (width: number, height: number): OffscreenCanvas; + new(width: number, height: number): OffscreenCanvas; }; function createCanvas(size: number): OffscreenCanvas { diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx index 11a888412..21373c7cd 100644 --- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx +++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx @@ -77,6 +77,17 @@ function ContentByUriType({ </Button> </div> ); + case TalerUriAction.AddExchange: + return ( + <div> + <p> + <i18n.Translate>This page has a add exchange action.</i18n.Translate> + </p> + <Button variant="contained" color="success" onClick={onConfirm}> + <i18n.Translate>Open add exchange page</i18n.Translate> + </Button> + </div> + ); case TalerUriAction.DevExperiment: case TalerUriAction.PayPull: diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts index 3d5a105ec..94b32c157 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts @@ -21,7 +21,7 @@ import { ErrorAlert } from "../../context/alert.js"; import { TextFieldHandler } from "../../mui/handlers.js"; import { StateViewMap, compose } from "../../utils/index.js"; import { useComponentState } from "./state.js"; -import { ConfirmView, VerifyView } from "./views.js"; +import { ConfirmAddExchangeView, VerifyView } from "./views.js"; export interface Props { currency?: string; @@ -81,7 +81,7 @@ export namespace State { const viewMapping: StateViewMap<State> = { loading: Loading, error: ErrorAlertView, - confirm: ConfirmView, + confirm: ConfirmAddExchangeView, verify: VerifyView, }; diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/stories.tsx b/packages/taler-wallet-webextension/src/wallet/AddExchange/stories.tsx index 4e2610743..f205b6415 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/stories.tsx @@ -19,8 +19,6 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import * as tests from "@gnu-taler/web-util/testing"; -import { ConfirmView, VerifyView } from "./views.js"; export default { title: "example", diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx index 21309fd7b..f6537bc68 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx @@ -205,7 +205,7 @@ export function VerifyView({ ); } -export function ConfirmView({ +export function ConfirmAddExchangeView({ url, onCancel, onConfirm, diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index 1fc1e46f4..5c31701e2 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -23,7 +23,9 @@ import { Amounts, TalerUri, + TalerUriAction, TranslatedString, + parseTalerUri, stringifyTalerUri, } from "@gnu-taler/taler-util"; import { @@ -84,6 +86,7 @@ import { WelcomePage } from "./Welcome.js"; import { WalletActivity } from "../components/WalletActivity.js"; import { EnabledBySettings } from "../components/EnabledBySettings.js"; import { DevExperimentPage } from "../cta/DevExperiment/index.js"; +import { ConfirmAddExchangeView } from "./AddExchange/views.js"; export function Application(): VNode { const { i18n } = useTranslationContext(); @@ -510,7 +513,28 @@ export function Application(): VNode { </CallToActionTemplate> )} /> - + <Route + path={Pages.ctaAddExchange} + component={({ talerUri }: { talerUri: string }) => { + const tUri = parseTalerUri(decodeURIComponent(talerUri)) + const baseUrl = tUri?.type === TalerUriAction.AddExchange ? tUri.exchangeBaseUrl : undefined + if (!baseUrl) { + redirectTo(Pages.balanceHistory({})) + return <div> + invalid url {talerUri} + </div> + } + return <CallToActionTemplate title={i18n.str`Add exchange`}> + <ConfirmAddExchangeView + url={baseUrl} + status="confirm" + error={undefined} + onCancel={() => redirectTo(Pages.balanceHistory({}))} + onConfirm={() => redirectTo(Pages.balanceHistory({}))} + /> + </CallToActionTemplate> + }} + /> {/** * NOT FOUND * all redirects should be at the end diff --git a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx index 999223fd8..1d18b3993 100644 --- a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx +++ b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx @@ -15,8 +15,10 @@ */ import { + assertUnreachable, parseTalerUri, TalerUri, + TalerUriAction, TranslatedString, } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -30,6 +32,7 @@ import { Button } from "../mui/Button.js"; import { Grid } from "../mui/Grid.js"; import { InputFile } from "../mui/InputFile.js"; import { TextField } from "../mui/TextField.js"; +import { EnabledBySettings } from "../components/EnabledBySettings.js"; const QrCanvas = css` width: 80%; @@ -211,6 +214,23 @@ export function QrReaderPage({ onDetected }: Props): VNode { const { i18n } = useTranslationContext(); + function onChangeDetect(str: string) { + if (!!str) { + const uri = parseTalerUri(str) + if (!uri) { + setError( + i18n.str`URI is not valid. Taler URI should start with "taler://"`, + ); + } else { + onDetected(uri) + setError(undefined); + } + } else { + setError(undefined); + } + setValue(str); + } + function onChange(str: string) { if (!!str) { if (!parseTalerUri(str)) { @@ -244,7 +264,7 @@ export function QrReaderPage({ onDetected }: Props): VNode { try { const code = await createCanvasFromVideo(video, canvasRef.current); if (code) { - onChange(code); + onChangeDetect(code); setShow("canvas"); } stream.getTracks().forEach((e) => { @@ -264,7 +284,7 @@ export function QrReaderPage({ onDetected }: Props): VNode { try { const code = await createCanvasFromFile(fileContent, canvasRef.current); if (code) { - onChange(code); + onChangeDetect(code); setShow("canvas"); } else { setError(i18n.str`Could not found a QR code in the file`); @@ -273,6 +293,7 @@ export function QrReaderPage({ onDetected }: Props): VNode { setError(i18n.str`something unexpected happen: ${error}`); } } + const uri = parseTalerUri(value); const active = value === ""; return ( @@ -297,38 +318,46 @@ export function QrReaderPage({ onDetected }: Props): VNode { <Grid item xs={2}> <p>{error && <Alert severity="error">{error}</Alert>}</p> </Grid> - <Grid item xs={1}> - {!active && ( - <Button - variant="contained" - onClick={async () => { - setShow("nothing"); - onChange(""); - }} - color="error" - > - <i18n.Translate>Clear</i18n.Translate> - </Button> - )} - </Grid> - <Grid item xs={1}> - {value && ( + {uri && ( + <Grid item xs={2}> <Button disabled={!!error} variant="contained" color="success" onClick={async () => { - const uri = parseTalerUri(value); if (uri) onDetected(uri); }} > - <i18n.Translate>Open</i18n.Translate> + {(function (talerUri: TalerUri): VNode { + switch (talerUri.type) { + case TalerUriAction.Pay: + return <i18n.Translate>Pay invoice</i18n.Translate> + case TalerUriAction.Withdraw: + return <i18n.Translate>Withdrawal from bank</i18n.Translate> + case TalerUriAction.Refund: + return <i18n.Translate>Claim refund</i18n.Translate> + case TalerUriAction.PayPull: + return <i18n.Translate>Pay invoice</i18n.Translate> + case TalerUriAction.PayPush: + return <i18n.Translate>Accept payment</i18n.Translate> + case TalerUriAction.PayTemplate: + return <i18n.Translate>Complete order</i18n.Translate> + case TalerUriAction.Restore: + return <i18n.Translate>Restore wallet</i18n.Translate> + case TalerUriAction.DevExperiment: + return <i18n.Translate>Enable experiment</i18n.Translate> + case TalerUriAction.WithdrawExchange: + return <i18n.Translate>Withdraw from exchange</i18n.Translate> + case TalerUriAction.AddExchange: + return <i18n.Translate>Add exchange</i18n.Translate> + default: { + assertUnreachable(talerUri) + } + } + })(uri)} </Button> - )} - </Grid> - <Grid item xs={1}> - <InputFile onChange={onFileRead}>Read QR from file</InputFile> - </Grid> + </Grid> + )} <Grid item xs={1}> <p> <Button variant="contained" onClick={startVideo}> @@ -336,6 +365,28 @@ export function QrReaderPage({ onDetected }: Props): VNode { </Button> </p> </Grid> + {!active && ( + <Grid item xs={1}> + <p> + + <Button + variant="contained" + onClick={async () => { + setShow("nothing"); + onChange(""); + }} + color="error" + > + <i18n.Translate>Clear</i18n.Translate> + </Button> + </p> + </Grid> + )} + <EnabledBySettings name="advancedMode"> + <Grid item xs={2}> + <InputFile onChange={onFileRead}>Read QR from file</InputFile> + </Grid> + </EnabledBySettings> </Grid> </section> <div> |