split wallet,popup .html

This commit is contained in:
Sebastian 2021-06-16 17:01:06 -03:00
parent 562b2cf8d2
commit 86636142a2
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
10 changed files with 298 additions and 156 deletions

View File

@ -32,13 +32,24 @@ const makePlugins = () => [
]; ];
const webExtensionPageEntryPoint = { const webExtensionWalletEntryPoint = {
input: "lib/pageEntryPoint.js", input: "lib/walletEntryPoint.js",
output: { output: {
file: "dist/pageEntryPoint.js", file: "dist/walletEntryPoint.js",
format: "iife", format: "iife",
exports: "none", exports: "none",
name: "webExtensionPageEntry", name: "webExtensionWalletEntry",
},
plugins: makePlugins(),
};
const webExtensionPopupEntryPoint = {
input: "lib/popupEntryPoint.js",
output: {
file: "dist/popupEntryPoint.js",
format: "iife",
exports: "none",
name: "webExtensionPopupEntry",
}, },
plugins: makePlugins(), plugins: makePlugins(),
}; };
@ -66,7 +77,8 @@ const webExtensionCryptoWorker = {
}; };
export default [ export default [
webExtensionPageEntryPoint, webExtensionPopupEntryPoint,
webExtensionWalletEntryPoint,
webExtensionBackgroundPageScript, webExtensionBackgroundPageScript,
webExtensionCryptoWorker, webExtensionCryptoWorker,
]; ];

View File

@ -1,47 +0,0 @@
/*
This file is part of GNU Taler
(C) 2020 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Main entry point for extension pages.
*
* @author Florian Dold <dold@taler.net>
*/
import { render } from "preact";
import { setupI18n } from "@gnu-taler/taler-util";
import { strings } from "./i18n/strings";
import { Application } from "./Application";
function main(): void {
try {
const container = document.getElementById("container");
if (!container) {
throw Error("container not found, can't mount page contents");
}
render(Application(), container);
} catch (e) {
console.error("got error", e);
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
}
}
setupI18n("en-US", strings);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main);
} else {
main();
}

View File

@ -48,6 +48,14 @@ import { PageLink, renderAmount } from "../renderHtml";
import * as wxApi from "../wxApi"; import * as wxApi from "../wxApi";
import { PermissionsCheckbox, useExtendedPermissions, Diagnostics } from "./welcome"; import { PermissionsCheckbox, useExtendedPermissions, Diagnostics } from "./welcome";
export enum Pages {
balance = '/balance',
settings = '/settings',
debug = '/debug',
history = '/history',
transaction = '/transaction/:tid',
}
interface TabProps { interface TabProps {
target: string; target: string;
current?: string; current?: string;
@ -66,13 +74,13 @@ function Tab(props: TabProps): JSX.Element {
); );
} }
function WalletNavBar({ current }: { current?: string }) { export function WalletNavBar({ current }: { current?: string }) {
return ( return (
<div className="nav" id="header"> <div className="nav" id="header">
<Tab target="/popup/balance" current={current}>{i18n.str`Balance`}</Tab> <Tab target="/balance" current={current}>{i18n.str`Balance`}</Tab>
<Tab target="/popup/history" current={current}>{i18n.str`History`}</Tab> <Tab target="/history" current={current}>{i18n.str`History`}</Tab>
<Tab target="/popup/settings" current={current}>{i18n.str`Settings`}</Tab> <Tab target="/settings" current={current}>{i18n.str`Settings`}</Tab>
<Tab target="/popup/debug" current={current}>{i18n.str`Debug`}</Tab> <Tab target="/debug" current={current}>{i18n.str`Debug`}</Tab>
</div> </div>
); );
} }
@ -99,7 +107,7 @@ function EmptyBalanceView(): JSX.Element {
); );
} }
class WalletBalanceView extends Component<any, any> { export class WalletBalanceView extends Component<any, any> {
private balance?: BalancesResponse; private balance?: BalancesResponse;
private gotError = false; private gotError = false;
private canceler: (() => void) | undefined = undefined; private canceler: (() => void) | undefined = undefined;
@ -400,7 +408,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
} }
} }
function WalletHistory(props: any): JSX.Element { export function WalletHistory(props: any): JSX.Element {
const [transactions, setTransactions] = useState< const [transactions, setTransactions] = useState<
TransactionsResponse | undefined TransactionsResponse | undefined
>(undefined); >(undefined);
@ -707,7 +715,7 @@ export function WalletTransactionView({ transaction, onDelete, onBack }: WalletT
return <div></div> return <div></div>
} }
function WalletTransaction({ tid }: { tid: string }): JSX.Element { export function WalletTransaction({ tid }: { tid: string }): JSX.Element {
const [transaction, setTransaction] = useState< const [transaction, setTransaction] = useState<
Transaction | undefined Transaction | undefined
>(undefined); >(undefined);
@ -732,7 +740,7 @@ function WalletTransaction({ tid }: { tid: string }): JSX.Element {
/> />
} }
function WalletSettings() { export function WalletSettings() {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions() const [permissionsEnabled, togglePermissions] = useExtendedPermissions()
return ( return (
<div> <div>
@ -799,7 +807,7 @@ async function confirmReset(): Promise<void> {
} }
} }
function WalletDebug(props: any): JSX.Element { export function WalletDebug(props: any): JSX.Element {
return ( return (
<div> <div>
<p>Debug tools:</p> <p>Debug tools:</p>
@ -845,23 +853,23 @@ function makeExtensionUrlWithParams(
return innerUrl.href; return innerUrl.href;
} }
function actionForTalerUri(talerUri: string): string | undefined { export function actionForTalerUri(talerUri: string): string | undefined {
const uriType = classifyTalerUri(talerUri); const uriType = classifyTalerUri(talerUri);
switch (uriType) { switch (uriType) {
case TalerUriType.TalerWithdraw: case TalerUriType.TalerWithdraw:
return makeExtensionUrlWithParams("static/popup.html#/withdraw", { return makeExtensionUrlWithParams("static/wallet.html#/withdraw", {
talerWithdrawUri: talerUri, talerWithdrawUri: talerUri,
}); });
case TalerUriType.TalerPay: case TalerUriType.TalerPay:
return makeExtensionUrlWithParams("static/popup.html#/pay", { return makeExtensionUrlWithParams("static/wallet.html#/pay", {
talerPayUri: talerUri, talerPayUri: talerUri,
}); });
case TalerUriType.TalerTip: case TalerUriType.TalerTip:
return makeExtensionUrlWithParams("static/popup.html#/tip", { return makeExtensionUrlWithParams("static/wallet.html#/tip", {
talerTipUri: talerUri, talerTipUri: talerUri,
}); });
case TalerUriType.TalerRefund: case TalerUriType.TalerRefund:
return makeExtensionUrlWithParams("static/popup.html#/refund", { return makeExtensionUrlWithParams("static/wallet.html#/refund", {
talerRefundUri: talerUri, talerRefundUri: talerUri,
}); });
case TalerUriType.TalerNotifyReserve: case TalerUriType.TalerNotifyReserve:
@ -876,7 +884,7 @@ function actionForTalerUri(talerUri: string): string | undefined {
return undefined; return undefined;
} }
async function findTalerUriInActiveTab(): Promise<string | undefined> { export async function findTalerUriInActiveTab(): Promise<string | undefined> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
chrome.tabs.executeScript( chrome.tabs.executeScript(
{ {
@ -901,68 +909,54 @@ async function findTalerUriInActiveTab(): Promise<string | undefined> {
}); });
} }
export function WalletPopup(): JSX.Element { // export function WalletPopup(): JSX.Element {
const [talerActionUrl, setTalerActionUrl] = useState<string | undefined>( // const [talerActionUrl, setTalerActionUrl] = useState<string | undefined>(
undefined, // undefined,
); // );
const [dismissed, setDismissed] = useState(false); // const [dismissed, setDismissed] = useState(false);
useEffect(() => { // useEffect(() => {
async function check(): Promise<void> { // async function check(): Promise<void> {
const talerUri = await findTalerUriInActiveTab(); // const talerUri = await findTalerUriInActiveTab();
if (talerUri) { // if (talerUri) {
const actionUrl = actionForTalerUri(talerUri); // const actionUrl = actionForTalerUri(talerUri);
setTalerActionUrl(actionUrl); // setTalerActionUrl(actionUrl);
} // }
} // }
check(); // check();
}, []); // }, []);
if (talerActionUrl && !dismissed) { // if (talerActionUrl && !dismissed) {
return ( // return (
<div style={{ padding: "1em", width: 400 }}> // <div style={{ padding: "1em", width: 400 }}>
<h1>Taler Action</h1> // <h1>Taler Action</h1>
<p>This page has a Taler action. </p> // <p>This page has a Taler action. </p>
<p> // <p>
<button // <button
onClick={() => { // onClick={() => {
window.open(talerActionUrl, "_blank"); // window.open(talerActionUrl, "_blank");
}} // }}
> // >
Open // Open
</button> // </button>
</p> // </p>
<p> // <p>
<button onClick={() => setDismissed(true)}>Dismiss</button> // <button onClick={() => setDismissed(true)}>Dismiss</button>
</p> // </p>
</div> // </div>
); // );
} // }
return ( // return (
<div> // <div>
<Match>{({ path }: any) => <WalletNavBar current={path} />}</Match> // <Match>{({ path }: any) => <WalletNavBar current={path} />}</Match>
<div style={{ margin: "1em", width: 400 }}> // <div style={{ margin: "1em", width: 400 }}>
<Router> // <Router>
<Route path={Pages.balance} component={WalletBalanceView} /> // <Route path={Pages.balance} component={WalletBalanceView} />
<Route path={Pages.settings} component={WalletSettings} /> // <Route path={Pages.settings} component={WalletSettings} />
<Route path={Pages.debug} component={WalletDebug} /> // <Route path={Pages.debug} component={WalletDebug} />
<Route path={Pages.history} component={WalletHistory} /> // <Route path={Pages.history} component={WalletHistory} />
<Route path={Pages.transaction} component={WalletTransaction} /> // <Route path={Pages.transaction} component={WalletTransaction} />
</Router> // </Router>
</div> // </div>
</div> // </div>
); // );
} // }
enum Pages {
balance = '/popup/balance',
transaction = '/popup/transaction/:tid',
settings = '/popup/settings',
debug = '/popup/debug',
history = '/popup/history',
}
export function Redirect({ to }: { to: string }): null {
useEffect(() => {
route(to, true)
})
return null
}

View File

@ -48,6 +48,10 @@ export interface ViewProps {
}; };
export function View({ talerWithdrawUri, details, cancelled, selectedExchange, accept, setCancelled, setSelecting }: ViewProps) { export function View({ talerWithdrawUri, details, cancelled, selectedExchange, accept, setCancelled, setSelecting }: ViewProps) {
const [state, setState] = useState(1)
setTimeout(() => {
setState(s => s + 1)
}, 1000);
if (!talerWithdrawUri) { if (!talerWithdrawUri) {
return <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>; return <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>;
} }
@ -57,7 +61,7 @@ export function View({ talerWithdrawUri, details, cancelled, selectedExchange, a
} }
if (cancelled) { if (cancelled) {
return <span><i18n.Translate>Withdraw operation has been cancelled.</i18n.Translate></span>; return <span><i18n.Translate>Withdraw operation has been cancelled.{state}</i18n.Translate></span>;
} }
return ( return (

View File

@ -0,0 +1,128 @@
/*
This file is part of GNU Taler
(C) 2020 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Main entry point for extension pages.
*
* @author Florian Dold <dold@taler.net>
*/
import { render } from "preact";
import { setupI18n } from "@gnu-taler/taler-util";
import { strings } from "./i18n/strings";
import { useEffect, useState } from "preact/hooks";
import {
actionForTalerUri, findTalerUriInActiveTab, Pages, WalletBalanceView, WalletDebug, WalletHistory,
WalletNavBar, WalletSettings, WalletTransaction, WalletTransactionView
} from "./pages/popup";
import Match from "preact-router/match";
import Router, { route, Route } from "preact-router";
// import { Application } from "./Application";
function main(): void {
try {
const container = document.getElementById("container");
if (!container) {
throw Error("container not found, can't mount page contents");
}
render(<Application />, container);
} catch (e) {
console.error("got error", e);
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
}
}
setupI18n("en-US", strings);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main);
} else {
main();
}
function useTalerActionURL(): [string | undefined, (s: boolean) => void] {
const [talerActionUrl, setTalerActionUrl] = useState<string | undefined>(
undefined,
);
const [dismissed, setDismissed] = useState(false);
useEffect(() => {
async function check(): Promise<void> {
const talerUri = await findTalerUriInActiveTab();
if (talerUri) {
const actionUrl = actionForTalerUri(talerUri);
setTalerActionUrl(actionUrl);
}
}
check();
}, []);
const url = dismissed ? undefined : talerActionUrl
return [url, setDismissed]
}
interface Props {
url: string;
onDismiss: (s: boolean) => void;
}
function TalerActionFound({ url, onDismiss }: Props) {
return <div style={{ padding: "1em", width: 400 }}>
<h1>Taler Action </h1>
<p>This page has a Taler action.</p>
<p>
<button onClick={() => { window.open(url, "_blank"); }}>
Open
</button>
</p>
<p>
<button onClick={() => onDismiss(true)}> Dismiss </button>
</p>
</div>
}
function Application() {
const [talerActionUrl, setDismissed] = useTalerActionURL()
if (talerActionUrl) {
return <TalerActionFound url={talerActionUrl} onDismiss={setDismissed} />
}
return (
<div>
<Match>{({ path }: any) => <WalletNavBar current={path} />}</Match >
<div style={{ margin: "1em", width: 400 }}>
<Router>
<Route path={Pages.balance} component={WalletBalanceView} />
<Route path={Pages.settings} component={WalletSettings} />
<Route path={Pages.debug} component={WalletDebug} />
<Route path={Pages.history} component={WalletHistory} />
<Route path={Pages.transaction} component={WalletTransaction} />
<Route default component={Redirect} to={Pages.balance} />
</Router>
</div>
</div>
);
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
route(to, true)
})
return null
}

View File

@ -167,7 +167,7 @@ export function ProgressButton({isLoading, ...rest}: LoadingButtonProps): JSX.El
export function PageLink( export function PageLink(
props: { pageName: string, children?: ComponentChildren }, props: { pageName: string, children?: ComponentChildren },
): JSX.Element { ): JSX.Element {
const url = chrome.extension.getURL(`/static/popup.html#/${props.pageName}`); const url = chrome.extension.getURL(`/static/wallet.html#/${props.pageName}`);
return ( return (
<a <a
className="actionLink" className="actionLink"

View File

@ -1,16 +1,61 @@
import Router, { route, Route } from "preact-router"; /*
import { createHashHistory } from 'history'; This file is part of GNU Taler
import { useEffect } from "preact/hooks"; (C) 2020 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Main entry point for extension pages.
*
* @author Florian Dold <dold@taler.net>
*/
import { render } from "preact";
import { setupI18n } from "@gnu-taler/taler-util";
import { strings } from "./i18n/strings";
import { createHashHistory } from 'history';
import { WalletPopup } from "./pages/popup";
import { WithdrawalDialog } from "./pages/withdraw"; import { WithdrawalDialog } from "./pages/withdraw";
import { Welcome } from "./pages/welcome"; import { Welcome } from "./pages/welcome";
import { TalerPayDialog } from "./pages/pay"; import { TalerPayDialog } from "./pages/pay";
import { RefundStatusView } from "./pages/refund"; import { RefundStatusView } from "./pages/refund";
import { TalerTipDialog } from './pages/tip'; import { TalerTipDialog } from './pages/tip';
import Router, { route, Route } from "preact-router";
export enum Pages { function main(): void {
try {
const container = document.getElementById("container");
if (!container) {
throw Error("container not found, can't mount page contents");
}
render(<Application />, container);
} catch (e) {
console.error("got error", e);
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
}
}
setupI18n("en-US", strings);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main);
} else {
main();
}
enum Pages {
welcome = '/welcome', welcome = '/welcome',
pay = '/pay', pay = '/pay',
payback = '/payback', payback = '/payback',
@ -19,16 +64,15 @@ export enum Pages {
return_coins = '/return-coins', return_coins = '/return-coins',
tips = '/tips', tips = '/tips',
withdraw = '/withdraw', withdraw = '/withdraw',
popup = '/popup/:rest*', // popup = '/popup/:rest*',
} }
export function Application() { function Application() {
const sp = new URL(document.location.href).searchParams const sp = new URL(document.location.href).searchParams
const queryParams: any = {} const queryParams: any = {}
sp.forEach((v, k) => { queryParams[k] = v; }); sp.forEach((v, k) => { queryParams[k] = v; });
return <Router history={createHashHistory()} > return <Router history={createHashHistory()} >
<Route path={Pages.popup} component={WalletPopup} />
<Route path={Pages.welcome} component={() => { <Route path={Pages.welcome} component={() => {
return <section id="main"> return <section id="main">
@ -87,13 +131,5 @@ export function Application() {
<Route path={Pages.payback} component={() => <div>no yet implemented</div>} /> <Route path={Pages.payback} component={() => <div>no yet implemented</div>} />
<Route path={Pages.return_coins} component={() => <div>no yet implemented</div>} /> <Route path={Pages.return_coins} component={() => <div>no yet implemented</div>} />
<Route default component={Redirect} to='/popup/balance' />
</Router> </Router>
} }
export function Redirect({ to }: { to: string }): null {
useEffect(() => {
route(to, true)
})
return null
}

View File

@ -285,7 +285,7 @@ try {
chrome.runtime.onInstalled.addListener((details) => { chrome.runtime.onInstalled.addListener((details) => {
console.log("onInstalled with reason", details.reason); console.log("onInstalled with reason", details.reason);
if (details.reason === "install") { if (details.reason === "install") {
const url = chrome.extension.getURL("/static/popup.html#/welcome"); const url = chrome.extension.getURL("/static/wallet.html#/welcome");
chrome.tabs.create({ active: true, url: url }); chrome.tabs.create({ active: true, url: url });
} }
}); });
@ -320,7 +320,7 @@ function headerListener(
switch (uriType) { switch (uriType) {
case TalerUriType.TalerWithdraw: case TalerUriType.TalerWithdraw:
return makeSyncWalletRedirect( return makeSyncWalletRedirect(
"/static/popup.html#/withdraw", "/static/wallet.html#/withdraw",
details.tabId, details.tabId,
details.url, details.url,
{ {
@ -329,7 +329,7 @@ function headerListener(
); );
case TalerUriType.TalerPay: case TalerUriType.TalerPay:
return makeSyncWalletRedirect( return makeSyncWalletRedirect(
"/static/popup.html#/pay", "/static/wallet.html#/pay",
details.tabId, details.tabId,
details.url, details.url,
{ {
@ -338,7 +338,7 @@ function headerListener(
); );
case TalerUriType.TalerTip: case TalerUriType.TalerTip:
return makeSyncWalletRedirect( return makeSyncWalletRedirect(
"/static/popup.html#/tip", "/static/wallet.html#/tip",
details.tabId, details.tabId,
details.url, details.url,
{ {
@ -347,7 +347,7 @@ function headerListener(
); );
case TalerUriType.TalerRefund: case TalerUriType.TalerRefund:
return makeSyncWalletRedirect( return makeSyncWalletRedirect(
"/static/popup.html#/refund", "/static/wallet.html#/refund",
details.tabId, details.tabId,
details.url, details.url,
{ {

View File

@ -6,7 +6,7 @@
<link rel="stylesheet" type="text/css" href="/static/style/wallet.css" /> <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" />
<link rel="stylesheet" type="text/css" href="/static/style/popup.css" /> <link rel="stylesheet" type="text/css" href="/static/style/popup.css" />
<link rel="icon" href="/static/img/icon.png" /> <link rel="icon" href="/static/img/icon.png" />
<script src="/dist/pageEntryPoint.js"></script> <script src="/dist/popupEntryPoint.js"></script>
</head> </head>
<body> <body>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="/static/style/pure.css" />
<link rel="stylesheet" type="text/css" href="/static/style/wallet.css" />
<link rel="stylesheet" type="text/css" href="/static/style/popup.css" />
<link rel="icon" href="/static/img/icon.png" />
<script src="/dist/walletEntryPoint.js"></script>
</head>
<body>
<div id="container" style="margin: 0; padding: 0;"></div>
</body>
</html>