new dev environment

This commit is contained in:
Sebastian 2022-03-25 16:57:27 -03:00
parent 00fb648269
commit ddfb40e50c
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
28 changed files with 1087 additions and 529 deletions

View File

@ -0,0 +1,4 @@
/mocha.css
/mocha.js
/mocha.js.map
/manifest.json

View File

@ -0,0 +1,48 @@
<html>
<head>
<meta charset="utf-8" />
<link rel="manifest" href="./manifest.json" />
</head>
<body>
<script>
function openPopup() {
window.frames["popup"].location = "/popup.html";
}
function openWallet() {
window.frames["wallet"].location = "/wallet.html";
}
function closeWallet() {
window.frames["wallet"].location = "about:blank";
}
</script>
<input type="text" />
<button value="asd" onclick="openPopup()">open popup</button>
<button value="asd" onclick="closeWallet();openWallet()">
reload wallet page
</button>
<hr />
<iframe
id="popup-window"
name="popup"
src="about:blank"
name="popup"
width="500"
height="325"
>
</iframe>
<hr />
<iframe
id="wallet-window"
name="wallet"
src="about:blank"
name="wallet"
width="800"
height="100%"
>
</iframe>
<hr />
<iframe src="/tests.html" name="wallet" width="800" height="100%"> </iframe>
<hr />
<script src="/dist/background.dev.js"></script>
</body>
</html>

View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
html {
font-family: sans-serif; /* 1 */
}
body {
margin: 0;
}
</style>
<style>
html {
}
h1 {
font-size: 2em;
}
input {
font: inherit;
}
body {
margin: 0;
font-size: 100%;
padding: 0;
overflow: hidden;
background-color: #f8faf7;
font-family: Arial, Helvetica, sans-serif;
}
</style>
<link rel="stylesheet" type="text/css" href="/dist/popupEntryPoint.css" />
<script src="/dist/popupEntryPoint.dev.js"></script>
</head>
<body>
<taler-popup id="container" class="popup-container"></taler-popup>
</body>
</html>

View File

@ -2,19 +2,18 @@
<html> <html>
<head> <head>
<title>Mocha Tests</title> <title>Mocha Tests</title>
<link rel="stylesheet" href="node_modules/mocha/mocha.css" /> <link rel="stylesheet" href="/mocha.css" />
</head> </head>
<body> <body>
<div id="mocha"></div> <div id="mocha"></div>
<script src="node_modules/mocha/mocha.js"></script> <script src="/mocha.js"></script>
<script> <script>
mocha.setup("bdd"); mocha.setup("bdd");
</script> </script>
<!-- load code you want to test here --> <!-- load code you want to test here -->
<script src="/dist/stories.test.js"></script>
<script src="dist/stories.test.js"></script> <script src="/dist/hooks/useTalerActionURL.test.js"></script>
<script src="dist/hooks/useTalerActionURL.test.js"></script>
<!-- load your test files here --> <!-- load your test files here -->
<script> <script>

View File

@ -0,0 +1,29 @@
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
<style>
html {
font-family: sans-serif; /* 1 */
}
h1 {
font-size: 2em;
}
input {
font: inherit;
}
body {
margin: 0;
font-size: 100%;
padding: 0;
background-color: #f8faf7;
font-family: Arial, Helvetica, sans-serif;
}
</style>
<script src="/dist/walletEntryPoint.dev.js"></script>
</head>
<body>
<div id="container" class="wallet-container"></div>
</body>
</html>

View File

@ -1,14 +0,0 @@
<html>
<head>
<link rel="manifest" href="./manifest.json" />
</head>
<body>
<iframe src="./static/popup.html" name="popup" width="500" height="400">
algo
</iframe>
<hr />
<iframe src="./static/wallet.html" name="wallet" width="800" height="100%">
otroe
</iframe>
</body>
</html>

View File

@ -0,0 +1,22 @@
import linaria from '@linaria/esbuild'
import esbuild from 'esbuild'
import { buildConfig } from "./build-fast-with-linaria.mjs"
import fs from 'fs';
fs.writeFileSync("dev-html/manifest.json", fs.readFileSync("manifest-v2.json"))
fs.writeFileSync("dev-html/mocha.css", fs.readFileSync("node_modules/mocha/mocha.css"))
fs.writeFileSync("dev-html/mocha.js", fs.readFileSync("node_modules/mocha/mocha.js"))
fs.writeFileSync("dev-html/mocha.js.map", fs.readFileSync("node_modules/mocha/mocha.js.map"))
const server = await esbuild
.serve({
servedir: 'dev-html',
}, { ...buildConfig, outdir: 'dev-html/dist' })
.catch((e) => {
console.log(e)
process.exit(1)
});
console.log("ready!", server.port);

View File

@ -0,0 +1,43 @@
/*
This file is part of GNU Taler
(C) 2021 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/>
*/
/**
* Entry point for the background page.
*
* @author sebasjm
*/
/**
* Imports.
*/
import { platform, setupPlatform } from "./platform/api";
import devAPI from "./platform/dev"
import { wxMain } from "./wxBackend";
console.log("Wallet setup for Dev API")
setupPlatform(devAPI)
try {
platform.registerOnInstalled(() => {
platform.openWalletPage("/welcome")
})
} catch (e) {
console.error(e);
}
platform.notifyWhenAppIsReady(() => {
wxMain();
})

View File

@ -30,8 +30,8 @@ import { wxMain } from "./wxBackend";
const isFirefox = typeof (window as any)['InstallTrigger'] !== 'undefined' const isFirefox = typeof (window as any)['InstallTrigger'] !== 'undefined'
//FIXME: create different entry point for any platform instead of // FIXME: create different entry point for any platform instead of
//switching in runtime // switching in runtime
if (isFirefox) { if (isFirefox) {
console.log("Wallet setup for Firefox API") console.log("Wallet setup for Firefox API")
setupPlatform(firefoxAPI) setupPlatform(firefoxAPI)

View File

@ -32,7 +32,7 @@ const worker: Worker = self as any as Worker;
async function handleRequest( async function handleRequest(
operation: string, operation: string,
id: number, id: number,
args: string[], req: unknown,
): Promise<void> { ): Promise<void> {
const impl = nativeCrypto; const impl = nativeCrypto;
@ -42,7 +42,7 @@ async function handleRequest(
} }
try { try {
const result = await (impl as any)[operation](...args); const result = await (impl as any)[operation](req);
worker.postMessage({ result, id }); worker.postMessage({ result, id });
} catch (e) { } catch (e) {
logger.error("error during operation", e); logger.error("error during operation", e);
@ -51,9 +51,9 @@ async function handleRequest(
} }
worker.onmessage = (msg: MessageEvent) => { worker.onmessage = (msg: MessageEvent) => {
const args = msg.data.args; const req = msg.data.req;
if (!Array.isArray(args)) { if (typeof req !== "object") {
console.error("args must be array"); console.error("request must be an object");
return; return;
} }
const id = msg.data.id; const id = msg.data.id;
@ -67,7 +67,7 @@ worker.onmessage = (msg: MessageEvent) => {
return; return;
} }
handleRequest(operation, id, args).catch((e) => { handleRequest(operation, id, req).catch((e) => {
console.error("error in browser worker", e); console.error("error in browser worker", e);
}); });
}; };

View File

@ -143,7 +143,7 @@ export const Middle = styled.div`
export const PopupBox = styled.div<{ noPadding?: boolean; devMode: boolean }>` export const PopupBox = styled.div<{ noPadding?: boolean; devMode: boolean }>`
height: 290px; height: 290px;
width: 500px; width: 500px;
overflow-y: scroll; overflow-y: visible;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;

View File

@ -40,41 +40,18 @@ async function handleExtendedPerm(isEnabled: boolean, onChange: (value: boolean)
if (!isEnabled) { if (!isEnabled) {
// We set permissions here, since apparently FF wants this to be done // We set permissions here, since apparently FF wants this to be done
// as the result of an input event ... // as the result of an input event ...
const granted = await platform.getPermissionsApi().request(getReadRequestPermissions()); let granted: boolean;
console.log("permissions granted:", granted); try {
const lastError = platform.getLastError(); granted = await platform.getPermissionsApi().request(getReadRequestPermissions());
if (lastError) { } catch (lastError) {
console.error("error requesting permissions"); console.error("error requesting permissions");
console.error(lastError); console.error(lastError);
onChange(false); onChange(false);
return; return
} }
// try { console.log("permissions granted:", granted);
const res = await wxApi.setExtendedPermissions(granted); const res = await wxApi.setExtendedPermissions(granted);
onChange(res.newValue); onChange(res.newValue);
// } finally {
// return
// }
// return new Promise<void>((res) => {
// platform.getPermissionsApi().request(getReadRequestPermissions(), async (granted: boolean) => {
// console.log("permissions granted:", granted);
// const lastError = getLastError()
// if (lastError) {
// console.error("error requesting permissions");
// console.error(lastError);
// onChange(false);
// return;
// }
// try {
// const res = await wxApi.setExtendedPermissions(granted);
// onChange(res.newValue);
// } finally {
// res()
// }
// });
// })
} }
await wxApi.setExtendedPermissions(false).then(r => onChange(r.newValue)); await wxApi.setExtendedPermissions(false).then(r => onChange(r.newValue));
return return

View File

@ -38,7 +38,7 @@ export interface CrossBrowserPermissionsApi {
request(p: Permissions): Promise<boolean>; request(p: Permissions): Promise<boolean>;
remove(p: Permissions): Promise<boolean>; remove(p: Permissions): Promise<boolean>;
addPermissionsListener(callback: (p: Permissions) => void): void; addPermissionsListener(callback: (p: Permissions, lastError?: string) => void): void;
} }
@ -57,31 +57,132 @@ export interface WalletVersion {
*/ */
export interface PlatformAPI { export interface PlatformAPI {
/** /**
* FIXME: should not be needed
*
* check if the platform is firefox * check if the platform is firefox
*/ */
isFirefox(): boolean; isFirefox(): boolean;
/** /**
* * Permission API for checking and add a listener
*/ */
getPermissionsApi(): CrossBrowserPermissionsApi; getPermissionsApi(): CrossBrowserPermissionsApi;
/**
* Backend API
*
* Register a callback to be called when the wallet is ready to start
* @param callback
*/
notifyWhenAppIsReady(callback: () => void): void; notifyWhenAppIsReady(callback: () => void): void;
openWalletURIFromPopup(uriType: TalerUriType, talerUri: string): void;
/**
* Popup API
*
* Used when an TalerURI is found and open up from the popup UI.
* Closes the popup and open the URI into the wallet UI.
*
* @param talerUri
*/
openWalletURIFromPopup(talerUri: string): void;
/**
* Backend API
*
* Open a page into the wallet UI
* @param page
*/
openWalletPage(page: string): void; openWalletPage(page: string): void;
/**
* Popup API
*
* Open a page into the wallet UI and closed the popup
* @param page
*/
openWalletPageFromPopup(page: string): void; openWalletPageFromPopup(page: string): void;
setMessageToWalletBackground(operation: string, payload: any): Promise<CoreApiResponse>;
listenToWalletNotifications(listener: (m: any) => void): () => void; /**
sendMessageToAllChannels(message: MessageFromBackend): void; * Backend API
registerAllIncomingConnections(): void; *
registerOnNewMessage(onNewMessage: (message: any, sender: any, callback: any) => void): void; * When a tab has been detected to have a Taler action the background process
registerReloadOnNewVersion(): void; * can use this function to redirect the tab to the wallet UI
*
* @param tabId
* @param page
*/
redirectTabToWalletPage(tabId: number, page: string): void; redirectTabToWalletPage(tabId: number, page: string): void;
/**
* Get the wallet version from manifest
*/
getWalletVersion(): WalletVersion; getWalletVersion(): WalletVersion;
/**
* Backend API
*/
registerAllIncomingConnections(): void;
/**
* Backend API
*/
registerReloadOnNewVersion(): void;
/**
* Backend API
*/
registerTalerHeaderListener(onHeader: (tabId: number, url: string) => void): void; registerTalerHeaderListener(onHeader: (tabId: number, url: string) => void): void;
/**
* Backend API
*/
registerOnInstalled(callback: () => void): void; registerOnInstalled(callback: () => void): void;
/**
* Backend API
*
* Check if background process run as service worker. This is used from the
* wallet use different http api and crypto worker.
*/
useServiceWorkerAsBackgroundProcess(): boolean; useServiceWorkerAsBackgroundProcess(): boolean;
getLastError(): string | undefined;
searchForTalerLinks(): string | undefined; /**
* Popup API
*
* Read the current tab html and try to find any Taler URI or QR code present.
*
* @return Taler URI if found
*/
findTalerUriInActiveTab(): Promise<string | undefined>; findTalerUriInActiveTab(): Promise<string | undefined>;
/**
* Used from the frontend to send commands to the wallet
*
* @param operation
* @param payload
*
* @return response from the backend
*/
sendMessageToWalletBackground(operation: string, payload: any): Promise<CoreApiResponse>;
/**
* Used from the frontend to receive notifications about new information
* @param listener
* @return function to unsubscribe the listener
*/
listenToWalletBackground(listener: (message: MessageFromBackend) => void): () => void;
/**
* Use by the wallet backend to receive operations from frontend (popup & wallet)
* and send a response back.
*
* @param onNewMessage
*/
listenToAllChannels(onNewMessage: (message: any, sender: any, sendResponse: (r: CoreApiResponse) => void) => void): void;
/**
* Used by the wallet backend to send notification about new information
* @param message
*/
sendMessageToAllChannels(message: MessageFromBackend): void;
} }
export let platform: PlatformAPI = undefined as any; export let platform: PlatformAPI = undefined as any;

View File

@ -14,17 +14,16 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import { TalerUriType } from "@gnu-taler/taler-util"; import { classifyTalerUri, CoreApiResponse, TalerUriType } from "@gnu-taler/taler-util";
import { getReadRequestPermissions } from "../permissions"; import { getReadRequestPermissions } from "../permissions";
import { CrossBrowserPermissionsApi, MessageFromBackend, Permissions, PlatformAPI } from "./api.js"; import { CrossBrowserPermissionsApi, MessageFromBackend, Permissions, PlatformAPI } from "./api.js";
const api: PlatformAPI = { const api: PlatformAPI = {
isFirefox, isFirefox,
findTalerUriInActiveTab, findTalerUriInActiveTab,
getLastError,
getPermissionsApi, getPermissionsApi,
getWalletVersion, getWalletVersion,
listenToWalletNotifications, listenToWalletBackground,
notifyWhenAppIsReady, notifyWhenAppIsReady,
openWalletPage, openWalletPage,
openWalletPageFromPopup, openWalletPageFromPopup,
@ -32,12 +31,11 @@ const api: PlatformAPI = {
redirectTabToWalletPage, redirectTabToWalletPage,
registerAllIncomingConnections, registerAllIncomingConnections,
registerOnInstalled, registerOnInstalled,
registerOnNewMessage, listenToAllChannels,
registerReloadOnNewVersion, registerReloadOnNewVersion,
registerTalerHeaderListener, registerTalerHeaderListener,
searchForTalerLinks,
sendMessageToAllChannels, sendMessageToAllChannels,
setMessageToWalletBackground, sendMessageToWalletBackground,
useServiceWorkerAsBackgroundProcess useServiceWorkerAsBackgroundProcess
} }
@ -50,7 +48,7 @@ function isFirefox(): boolean {
export function contains(p: Permissions): Promise<boolean> { export function contains(p: Permissions): Promise<boolean> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
chrome.permissions.contains(p, (resp) => { chrome.permissions.contains(p, (resp) => {
const le = getLastError() const le = chrome.runtime.lastError?.message
if (le) { if (le) {
rej(le) rej(le)
} }
@ -62,7 +60,7 @@ export function contains(p: Permissions): Promise<boolean> {
export async function request(p: Permissions): Promise<boolean> { export async function request(p: Permissions): Promise<boolean> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
chrome.permissions.request(p, (resp) => { chrome.permissions.request(p, (resp) => {
const le = getLastError() const le = chrome.runtime.lastError?.message
if (le) { if (le) {
rej(le) rej(le)
} }
@ -74,7 +72,7 @@ export async function request(p: Permissions): Promise<boolean> {
export async function remove(p: Permissions): Promise<boolean> { export async function remove(p: Permissions): Promise<boolean> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
chrome.permissions.remove(p, (resp) => { chrome.permissions.remove(p, (resp) => {
const le = getLastError() const le = chrome.runtime.lastError?.message
if (le) { if (le) {
rej(le) rej(le)
} }
@ -83,9 +81,12 @@ export async function remove(p: Permissions): Promise<boolean> {
}) })
} }
function addPermissionsListener(callback: (p: Permissions) => void): void { function addPermissionsListener(callback: (p: Permissions, lastError?: string) => void): void {
console.log("addPermissionListener is not supported for Firefox"); console.log("addPermissionListener is not supported for Firefox");
chrome.permissions.onAdded.addListener(callback) chrome.permissions.onAdded.addListener((perm: Permissions) => {
const lastError = chrome.runtime.lastError?.message;
callback(perm, lastError)
})
} }
function getPermissionsApi(): CrossBrowserPermissionsApi { function getPermissionsApi(): CrossBrowserPermissionsApi {
@ -107,7 +108,9 @@ function notifyWhenAppIsReady(callback: () => void) {
} }
function openWalletURIFromPopup(uriType: TalerUriType, talerUri: string) { function openWalletURIFromPopup(talerUri: string) {
const uriType = classifyTalerUri(talerUri);
let url: string | undefined = undefined; let url: string | undefined = undefined;
switch (uriType) { switch (uriType) {
case TalerUriType.TalerWithdraw: case TalerUriType.TalerWithdraw:
@ -150,7 +153,7 @@ function openWalletPageFromPopup(page: string) {
); );
} }
async function setMessageToWalletBackground(operation: string, payload: any): Promise<any> { async function sendMessageToWalletBackground(operation: string, payload: any): Promise<any> {
return new Promise<any>((resolve, reject) => { return new Promise<any>((resolve, reject) => {
chrome.runtime.sendMessage({ operation, payload, id: "(none)" }, (resp) => { chrome.runtime.sendMessage({ operation, payload, id: "(none)" }, (resp) => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
@ -164,7 +167,7 @@ async function setMessageToWalletBackground(operation: string, payload: any): Pr
} }
let notificationPort: chrome.runtime.Port | undefined; let notificationPort: chrome.runtime.Port | undefined;
function listenToWalletNotifications(listener: (m: any) => void) { function listenToWalletBackground(listener: (m: any) => void) {
if (notificationPort === undefined) { if (notificationPort === undefined) {
notificationPort = chrome.runtime.connect({ name: "notifications" }) notificationPort = chrome.runtime.connect({ name: "notifications" })
} }
@ -203,7 +206,7 @@ function registerAllIncomingConnections() {
}); });
} }
function registerOnNewMessage(cb: (message: any, sender: any, callback: any) => void) { function listenToAllChannels(cb: (message: any, sender: any, callback: (r: CoreApiResponse) => void) => void) {
chrome.runtime.onMessage.addListener((m, s, c) => { chrome.runtime.onMessage.addListener((m, s, c) => {
cb(m, s, c) cb(m, s, c)
@ -311,11 +314,6 @@ function useServiceWorkerAsBackgroundProcess() {
return chrome.runtime.getManifest().manifest_version === 3 return chrome.runtime.getManifest().manifest_version === 3
} }
function getLastError() {
return chrome.runtime.lastError?.message;
}
function searchForTalerLinks(): string | undefined { function searchForTalerLinks(): string | undefined {
let found; let found;
found = document.querySelector("a[href^='taler://'") found = document.querySelector("a[href^='taler://'")

View File

@ -0,0 +1,159 @@
/*
This file is part of GNU Taler
(C) 2021 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/>
*/
import { classifyTalerUri, CoreApiResponse, TalerUriType } from "@gnu-taler/taler-util";
import { MessageFromBackend, PlatformAPI } from "./api";
const frames = ["popup", "wallet"]
const api: PlatformAPI = ({
isFirefox: () => false,
findTalerUriInActiveTab: async () => undefined,
getPermissionsApi: () => ({
addPermissionsListener: () => undefined, contains: async () => true, remove: async () => false, request: async () => false
}),
getWalletVersion: () => ({
version: 'none'
}),
notifyWhenAppIsReady: (fn: () => void) => {
let total = frames.length
function waitAndNotify() {
total--
if (total < 1) {
console.log('done')
fn()
}
}
frames.forEach(f => {
const theFrame = window.frames[f as any]
if (theFrame.location.href === 'about:blank') {
waitAndNotify()
} else {
theFrame.addEventListener("load", waitAndNotify)
}
})
},
openWalletPage: (page: string) => {
window.frames['wallet' as any].location = `/wallet.html#${page}`
},
openWalletPageFromPopup: (page: string) => {
window.parent.frames['wallet' as any].location = `/wallet.html#${page}`
window.location.href = "about:blank"
},
openWalletURIFromPopup: (page: string) => {
alert('openWalletURIFromPopup not implemented yet')
},
redirectTabToWalletPage: (tabId: number, page: string) => {
alert('redirectTabToWalletPage not implemented yet')
},
registerAllIncomingConnections: () => undefined,
registerOnInstalled: (fn: () => void) => fn(),
registerReloadOnNewVersion: () => undefined,
registerTalerHeaderListener: () => undefined,
useServiceWorkerAsBackgroundProcess: () => false,
listenToAllChannels: (fn: (m: any, s: any, c: (r: CoreApiResponse) => void) => void) => {
window.addEventListener("message", (event: MessageEvent<IframeMessageType>) => {
if (event.data.type !== 'command') return
const sender = event.data.header.replyMe
fn(event.data.body, sender, (resp: CoreApiResponse) => {
if (event.source) {
const msg: IframeMessageResponse = {
type: "response",
header: { responseId: sender },
body: resp
}
window.parent.postMessage(msg)
}
})
})
},
sendMessageToAllChannels: (message: MessageFromBackend) => {
Array.from(window.frames).forEach(w => {
try {
w.postMessage({
header: {}, body: message
});
} catch (e) {
console.error(e)
}
})
},
listenToWalletBackground: (onNewMessage: (m: MessageFromBackend) => void) => {
function listener(event: MessageEvent<IframeMessageType>) {
if (event.data.type !== 'notification') return
onNewMessage(event.data.body)
}
window.parent.addEventListener("message", listener)
return () => {
window.parent.removeEventListener("message", listener)
}
},
sendMessageToWalletBackground: async (operation: string, payload: any) => {
const replyMe = `reply-${Math.floor(Math.random() * 100000)}`
const message: IframeMessageCommand = {
type: 'command',
header: { replyMe },
body: { operation, payload, id: "(none)" }
}
window.parent.postMessage(message)
return new Promise((res, rej) => {
function listener(event: MessageEvent<IframeMessageType>) {
if (event.data.type !== "response" || event.data.header.responseId !== replyMe) {
return
}
res(event.data.body)
window.parent.removeEventListener("message", listener)
}
window.parent.addEventListener("message", listener, {
})
})
},
})
type IframeMessageType = IframeMessageNotification | IframeMessageResponse | IframeMessageCommand;
interface IframeMessageNotification {
type: "notification";
header: {
},
body: MessageFromBackend
}
interface IframeMessageResponse {
type: "response";
header: {
responseId: string;
},
body: CoreApiResponse
}
interface IframeMessageCommand {
type: "command";
header: {
replyMe: string;
},
body: {
operation: any, id: string, payload: any
}
}
export default api;

View File

@ -0,0 +1,183 @@
/*
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 sebasjm
*/
import { createHashHistory } from "history";
import { Fragment, h, VNode } from "preact";
import Router, { route, Route } from "preact-router";
import { Match } from "preact-router/match";
import { useEffect, useState } from "preact/hooks";
import PendingTransactions from "../components/PendingTransactions";
import { PopupBox } from "../components/styled";
import { DevContextProvider } from "../context/devContext";
import { IoCProviderForRuntime } from "../context/iocContext";
import {
TranslationProvider,
useTranslationContext,
} from "../context/translation";
import { useTalerActionURL } from "../hooks/useTalerActionURL";
import { Pages, PopupNavBar } from "../NavigationBar";
import { platform } from "../platform/api";
import { BackupPage } from "../wallet/BackupPage";
import { ProviderDetailPage } from "../wallet/ProviderDetailPage";
import { BalancePage } from "./BalancePage";
import { TalerActionFound } from "./TalerActionFound";
function CheckTalerActionComponent(): VNode {
const [talerActionUrl] = useTalerActionURL();
useEffect(() => {
if (talerActionUrl)
route(Pages.cta.replace(":action", encodeURIComponent(talerActionUrl)));
}, [talerActionUrl]);
return <Fragment />;
}
export function Application(): VNode {
const hash_history = createHashHistory();
return (
<TranslationProvider>
<DevContextProvider>
{({ devMode }: { devMode: boolean }) => (
<IoCProviderForRuntime>
<PendingTransactions
goToTransaction={(txId: string) =>
route(Pages.balance_transaction.replace(":tid", txId))
}
/>
<Match>
{({ path }: { path: string }) => <PopupNavBar path={path} />}
</Match>
<CheckTalerActionComponent />
<PopupBox devMode={devMode}>
<Router history={hash_history}>
<Route
path={Pages.balance}
component={BalancePage}
goToWalletManualWithdraw={() =>
route(
Pages.balance_manual_withdraw.replace(":currency?", ""),
)
}
goToWalletDeposit={(currency: string) =>
route(Pages.balance_deposit.replace(":currency", currency))
}
goToWalletHistory={(currency: string) =>
route(Pages.balance_history.replace(":currency?", currency))
}
/>
<Route
path={Pages.cta}
component={function Action({ action }: { action: string }) {
const [, setDismissed] = useTalerActionURL();
return (
<TalerActionFound
url={decodeURIComponent(action)}
onDismiss={() => {
setDismissed(true);
route(Pages.balance);
}}
/>
);
}}
/>
<Route
path={Pages.backup}
component={BackupPage}
onAddProvider={() => {
route(Pages.backup_provider_add);
}}
/>
<Route
path={Pages.backup_provider_detail}
component={ProviderDetailPage}
onBack={() => {
route(Pages.backup);
}}
/>
<Route
path={Pages.balance_transaction}
component={RedirectToWalletPage}
/>
<Route
path={Pages.balance_manual_withdraw}
component={RedirectToWalletPage}
/>
<Route
path={Pages.balance_deposit}
component={RedirectToWalletPage}
/>
<Route
path={Pages.balance_history}
component={RedirectToWalletPage}
/>
<Route
path={Pages.backup_provider_add}
component={RedirectToWalletPage}
/>
<Route path={Pages.settings} component={RedirectToWalletPage} />
<Route
path={Pages.settings_exchange_add}
component={RedirectToWalletPage}
/>
<Route path={Pages.dev} component={RedirectToWalletPage} />
<Route default component={Redirect} to={Pages.balance} />
</Router>
</PopupBox>
</IoCProviderForRuntime>
)}
</DevContextProvider>
</TranslationProvider>
);
}
function RedirectToWalletPage(): VNode {
const page = (document.location.hash || "#/").replace("#", "");
const [showText, setShowText] = useState(false);
useEffect(() => {
platform.openWalletPageFromPopup(page);
setTimeout(() => {
setShowText(true);
}, 250);
});
const { i18n } = useTranslationContext();
if (!showText) return <Fragment />;
return (
<span>
<i18n.Translate>
this popup is being closed and you are being redirected to {page}
</i18n.Translate>
</span>
);
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
route(to, true);
});
return null;
}

View File

@ -34,7 +34,7 @@ export function TalerActionFound({ url, onDismiss }: Props) {
const uriType = classifyTalerUri(url); const uriType = classifyTalerUri(url);
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();
function redirectToWallet() { function redirectToWallet() {
platform.openWalletURIFromPopup(uriType, url); platform.openWalletURIFromPopup(url);
} }
return ( return (
<Fragment> <Fragment>

View File

@ -0,0 +1,54 @@
/*
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 sebasjm
*/
import { setupI18n } from "@gnu-taler/taler-util";
import { Fragment, h, render } from "preact";
import { strings } from "./i18n/strings";
import { setupPlatform } from "./platform/api";
import devAPI from "./platform/dev";
import { Application } from "./popup/Application";
console.log("Wallet setup for Dev API");
setupPlatform(devAPI);
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);
if (e instanceof Error) {
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
}
}
}
setupI18n("en", strings);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main);
} else {
main();
}

View File

@ -21,29 +21,23 @@
*/ */
import { setupI18n } from "@gnu-taler/taler-util"; import { setupI18n } from "@gnu-taler/taler-util";
import { createHashHistory } from "history"; import { Fragment, h, render } from "preact";
import { Fragment, h, render, VNode } from "preact";
import Router, { route, Route } from "preact-router";
import { Match } from "preact-router/match";
import { useEffect, useState } from "preact/hooks";
import PendingTransactions from "./components/PendingTransactions";
import { PopupBox } from "./components/styled";
import { DevContextProvider } from "./context/devContext";
import { IoCProviderForRuntime } from "./context/iocContext";
import {
TranslationProvider,
useTranslationContext,
} from "./context/translation";
import { useTalerActionURL } from "./hooks/useTalerActionURL";
import { strings } from "./i18n/strings"; import { strings } from "./i18n/strings";
import { Pages, PopupNavBar } from "./NavigationBar"; import { setupPlatform } from "./platform/api";
import { platform, setupPlatform } from "./platform/api";
import chromeAPI from "./platform/chrome"; import chromeAPI from "./platform/chrome";
import firefoxAPI from "./platform/firefox"; import firefoxAPI from "./platform/firefox";
import { BalancePage } from "./popup/BalancePage"; import { Application } from "./popup/Application";
import { TalerActionFound } from "./popup/TalerActionFound";
import { BackupPage } from "./wallet/BackupPage"; //FIXME: create different entry point for any platform instead of
import { ProviderDetailPage } from "./wallet/ProviderDetailPage"; //switching in runtime
const isFirefox = typeof (window as any)["InstallTrigger"] !== "undefined";
if (isFirefox) {
console.log("Wallet setup for Firefox API");
setupPlatform(firefoxAPI);
} else {
console.log("Wallet setup for Chrome API");
setupPlatform(chromeAPI);
}
function main(): void { function main(): void {
try { try {
@ -62,160 +56,8 @@ function main(): void {
setupI18n("en", strings); setupI18n("en", strings);
//FIXME: create different entry point for any platform instead of
//switching in runtime
const isFirefox = typeof (window as any)["InstallTrigger"] !== "undefined";
if (isFirefox) {
console.log("Wallet setup for Firefox API");
setupPlatform(firefoxAPI);
} else {
console.log("Wallet setup for Chrome API");
setupPlatform(chromeAPI);
}
if (document.readyState === "loading") { if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main); document.addEventListener("DOMContentLoaded", main);
} else { } else {
main(); main();
} }
function CheckTalerActionComponent(): VNode {
const [talerActionUrl] = useTalerActionURL();
useEffect(() => {
if (talerActionUrl)
route(Pages.cta.replace(":action", encodeURIComponent(talerActionUrl)));
}, [talerActionUrl]);
return <Fragment />;
}
function Application(): VNode {
const hash_history = createHashHistory();
return (
<TranslationProvider>
<DevContextProvider>
{({ devMode }: { devMode: boolean }) => (
<IoCProviderForRuntime>
<PendingTransactions
goToTransaction={(txId: string) =>
route(Pages.balance_transaction.replace(":tid", txId))
}
/>
<Match>
{({ path }: { path: string }) => <PopupNavBar path={path} />}
</Match>
<CheckTalerActionComponent />
<PopupBox devMode={devMode}>
<Router history={hash_history}>
<Route
path={Pages.balance}
component={BalancePage}
goToWalletManualWithdraw={() =>
route(
Pages.balance_manual_withdraw.replace(":currency?", ""),
)
}
goToWalletDeposit={(currency: string) =>
route(Pages.balance_deposit.replace(":currency", currency))
}
goToWalletHistory={(currency: string) =>
route(Pages.balance_history.replace(":currency?", currency))
}
/>
<Route
path={Pages.cta}
component={function Action({ action }: { action: string }) {
const [, setDismissed] = useTalerActionURL();
return (
<TalerActionFound
url={decodeURIComponent(action)}
onDismiss={() => {
setDismissed(true);
route(Pages.balance);
}}
/>
);
}}
/>
<Route
path={Pages.backup}
component={BackupPage}
onAddProvider={() => {
route(Pages.backup_provider_add);
}}
/>
<Route
path={Pages.backup_provider_detail}
component={ProviderDetailPage}
onBack={() => {
route(Pages.backup);
}}
/>
<Route
path={Pages.balance_transaction}
component={RedirectToWalletPage}
/>
<Route
path={Pages.balance_manual_withdraw}
component={RedirectToWalletPage}
/>
<Route
path={Pages.balance_deposit}
component={RedirectToWalletPage}
/>
<Route
path={Pages.balance_history}
component={RedirectToWalletPage}
/>
<Route
path={Pages.backup_provider_add}
component={RedirectToWalletPage}
/>
<Route path={Pages.settings} component={RedirectToWalletPage} />
<Route
path={Pages.settings_exchange_add}
component={RedirectToWalletPage}
/>
<Route path={Pages.dev} component={RedirectToWalletPage} />
<Route default component={Redirect} to={Pages.balance} />
</Router>
</PopupBox>
</IoCProviderForRuntime>
)}
</DevContextProvider>
</TranslationProvider>
);
}
function RedirectToWalletPage(): VNode {
const page = (document.location.hash || "#/").replace("#", "");
const [showText, setShowText] = useState(false);
useEffect(() => {
platform.openWalletPageFromPopup(page);
setTimeout(() => {
setShowText(true);
}, 250);
});
const { i18n } = useTranslationContext();
if (!showText) return <Fragment />;
return (
<span>
<i18n.Translate>
this popup is being closed and you are being redirected to {page}
</i18n.Translate>
</span>
);
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
route(to, true);
});
return null;
}

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 92 92" enable-background="new 0 0 92 92" xml:space="preserve">
width="92px" height="92px" viewBox="0 0 92 92" enable-background="new 0 0 92 92" xml:space="preserve"> <path id="XMLID_467_" d="M46,63c-1.1,0-2.1-0.4-2.9-1.2l-25-26c-1.5-1.6-1.5-4.1,0.1-5.7c1.6-1.5,4.1-1.5,5.7,0.1l22.1,23l22.1-23
<path id="XMLID_467_" d="M46,63c-1.1,0-2.1-0.4-2.9-1.2l-25-26c-1.5-1.6-1.5-4.1,0.1-5.7c1.6-1.5,4.1-1.5,5.7,0.1l22.1,23l22.1-23 c1.5-1.6,4.1-1.6,5.7-0.1c1.6,1.5,1.6,4.1,0.1,5.7l-25,26C48.1,62.6,47.1,63,46,63z" />
c1.5-1.6,4.1-1.6,5.7-0.1c1.6,1.5,1.6,4.1,0.1,5.7l-25,26C48.1,62.6,47.1,63,46,63z"/> </svg>
</svg>

Before

Width:  |  Height:  |  Size: 584 B

After

Width:  |  Height:  |  Size: 556 B

View File

@ -15,7 +15,7 @@ export function AddNewActionView({ onCancel }: Props): VNode {
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();
function redirectToWallet() { function redirectToWallet() {
platform.openWalletURIFromPopup(uriType, url); platform.openWalletURIFromPopup(url);
} }
return ( return (

View File

@ -0,0 +1,263 @@
/*
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 sebasjm
*/
import { createHashHistory } from "history";
import { Fragment, h, VNode } from "preact";
import Router, { route, Route } from "preact-router";
import Match from "preact-router/match";
import { useEffect, useState } from "preact/hooks";
import { LogoHeader } from "../components/LogoHeader";
import PendingTransactions from "../components/PendingTransactions";
import { SuccessBox, WalletBox } from "../components/styled";
import { DevContextProvider } from "../context/devContext";
import { IoCProviderForRuntime } from "../context/iocContext";
import {
TranslationProvider,
useTranslationContext,
} from "../context/translation";
import { PayPage } from "../cta/Pay";
import { RefundPage } from "../cta/Refund";
import { TipPage } from "../cta/Tip";
import { WithdrawPage } from "../cta/Withdraw";
import { Pages, WalletNavBar } from "../NavigationBar";
import { DeveloperPage } from "../popup/DeveloperPage";
import { BackupPage } from "./BackupPage";
import { DepositPage } from "./DepositPage";
import { ExchangeAddPage } from "./ExchangeAddPage";
import { HistoryPage } from "./History";
import { ManualWithdrawPage } from "./ManualWithdrawPage";
import { ProviderAddPage } from "./ProviderAddPage";
import { ProviderDetailPage } from "./ProviderDetailPage";
import { SettingsPage } from "./Settings";
import { TransactionPage } from "./Transaction";
import { WelcomePage } from "./Welcome";
export function Application(): VNode {
const [globalNotification, setGlobalNotification] = useState<
VNode | undefined
>(undefined);
const hash_history = createHashHistory();
function clearNotification(): void {
setGlobalNotification(undefined);
}
function clearNotificationWhenMovingOut(): void {
// const movingOutFromNotification =
// globalNotification && e.url !== globalNotification.to;
if (globalNotification) {
//&& movingOutFromNotification) {
setGlobalNotification(undefined);
}
}
const { i18n } = useTranslationContext();
return (
<TranslationProvider>
<DevContextProvider>
<IoCProviderForRuntime>
{/* <Match/> won't work in the first render if <Router /> is not called first */}
{/* https://github.com/preactjs/preact-router/issues/415 */}
<Router history={hash_history} />
<Match>
{({ path }: { path: string }) => {
if (path && path.startsWith("/cta")) return;
return (
<Fragment>
<LogoHeader />
<WalletNavBar path={path} />
<div
style={{
backgroundColor: "lightcyan",
display: "flex",
justifyContent: "center",
}}
>
<PendingTransactions
goToTransaction={(txId: string) =>
route(Pages.balance_transaction.replace(":tid", txId))
}
/>
</div>
</Fragment>
);
}}
</Match>
<WalletBox>
{globalNotification && (
<SuccessBox onClick={clearNotification}>
<div>{globalNotification}</div>
</SuccessBox>
)}
<Router
history={hash_history}
onChange={clearNotificationWhenMovingOut}
>
<Route path={Pages.welcome} component={WelcomePage} />
{/**
* BALANCE
*/}
<Route
path={Pages.balance_history}
component={HistoryPage}
goToWalletDeposit={(currency: string) =>
route(Pages.balance_deposit.replace(":currency", currency))
}
goToWalletManualWithdraw={(currency?: string) =>
route(
Pages.balance_manual_withdraw.replace(
":currency?",
currency || "",
),
)
}
/>
<Route
path={Pages.balance_transaction}
component={TransactionPage}
goToWalletHistory={(currency?: string) => {
route(
Pages.balance_history.replace(":currency?", currency || ""),
);
}}
/>
<Route
path={Pages.balance_manual_withdraw}
component={ManualWithdrawPage}
onCancel={() => {
route(Pages.balance);
}}
/>
<Route
path={Pages.balance_deposit}
component={DepositPage}
onCancel={(currency: string) => {
route(Pages.balance_history.replace(":currency?", currency));
}}
onSuccess={(currency: string) => {
route(Pages.balance_history.replace(":currency?", currency));
setGlobalNotification(
<i18n.Translate>
All done, your transaction is in progress
</i18n.Translate>,
);
}}
/>
{/**
* PENDING
*/}
<Route path={Pages.settings} component={SettingsPage} />
{/**
* BACKUP
*/}
<Route
path={Pages.backup}
component={BackupPage}
onAddProvider={() => {
route(Pages.backup_provider_add);
}}
/>
<Route
path={Pages.backup_provider_detail}
component={ProviderDetailPage}
onBack={() => {
route(Pages.backup);
}}
/>
<Route
path={Pages.backup_provider_add}
component={ProviderAddPage}
onBack={() => {
route(Pages.backup);
}}
/>
{/**
* SETTINGS
*/}
<Route
path={Pages.settings_exchange_add}
component={ExchangeAddPage}
onBack={() => {
route(Pages.balance);
}}
/>
{/**
* DEV
*/}
<Route path={Pages.dev} component={DeveloperPage} />
{/**
* CALL TO ACTION
*/}
<Route
path={Pages.cta_pay}
component={PayPage}
goToWalletManualWithdraw={(currency?: string) =>
route(
Pages.balance_manual_withdraw.replace(
":currency?",
currency || "",
),
)
}
goBack={() => route(Pages.balance)}
/>
<Route path={Pages.cta_refund} component={RefundPage} />
<Route path={Pages.cta_tips} component={TipPage} />
<Route path={Pages.cta_withdraw} component={WithdrawPage} />
{/**
* NOT FOUND
* all redirects should be at the end
*/}
<Route
path={Pages.balance}
component={Redirect}
to={Pages.balance_history.replace(":currency?", "")}
/>
<Route
default
component={Redirect}
to={Pages.balance_history.replace(":currency?", "")}
/>
</Router>
</WalletBox>
</IoCProviderForRuntime>
</DevContextProvider>
</TranslationProvider>
);
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
console.log("got some wrong route", to);
route(to, true);
});
return null;
}

View File

@ -253,9 +253,6 @@ export function View({
There is no known bank account to send money to There is no known bank account to send money to
</i18n.Translate> </i18n.Translate>
</p> </p>
<ButtonBoxWarning>
<i18n.Translate>Withdraw</i18n.Translate>
</ButtonBoxWarning>
</WarningBox> </WarningBox>
<footer> <footer>
<Button onClick={onCancel}> <Button onClick={onCancel}>

View File

@ -0,0 +1,54 @@
/*
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 sebasjm
*/
import { setupI18n } from "@gnu-taler/taler-util";
import { Fragment, h, render } from "preact";
import { strings } from "./i18n/strings";
import { setupPlatform } from "./platform/api";
import devAPI from "./platform/dev";
import { Application } from "./wallet/Application";
console.log("Wallet setup for Dev API");
setupPlatform(devAPI);
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);
if (e instanceof Error) {
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
}
}
}
setupI18n("en", strings);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main);
} else {
main();
}

View File

@ -21,40 +21,24 @@
*/ */
import { setupI18n } from "@gnu-taler/taler-util"; import { setupI18n } from "@gnu-taler/taler-util";
import { createHashHistory } from "history"; import { Fragment, h, render } from "preact";
import { Fragment, h, render, VNode } from "preact";
import Router, { route, Route } from "preact-router";
import Match from "preact-router/match";
import { useEffect, useState } from "preact/hooks";
import { LogoHeader } from "./components/LogoHeader";
import PendingTransactions from "./components/PendingTransactions";
import { SuccessBox, WalletBox } from "./components/styled";
import { DevContextProvider } from "./context/devContext";
import { IoCProviderForRuntime } from "./context/iocContext";
import {
TranslationProvider,
useTranslationContext,
} from "./context/translation";
import { PayPage } from "./cta/Pay";
import { RefundPage } from "./cta/Refund";
import { TipPage } from "./cta/Tip";
import { WithdrawPage } from "./cta/Withdraw";
import { strings } from "./i18n/strings"; import { strings } from "./i18n/strings";
import { Pages, WalletNavBar } from "./NavigationBar";
import { setupPlatform } from "./platform/api"; import { setupPlatform } from "./platform/api";
import chromeAPI from "./platform/chrome"; import chromeAPI from "./platform/chrome";
import firefoxAPI from "./platform/firefox"; import firefoxAPI from "./platform/firefox";
import { DeveloperPage } from "./popup/DeveloperPage"; import { Application } from "./wallet/Application";
import { BackupPage } from "./wallet/BackupPage";
import { DepositPage } from "./wallet/DepositPage"; const isFirefox = typeof (window as any)["InstallTrigger"] !== "undefined";
import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
import { HistoryPage } from "./wallet/History"; //FIXME: create different entry point for any platform instead of
import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage"; //switching in runtime
import { ProviderAddPage } from "./wallet/ProviderAddPage"; if (isFirefox) {
import { ProviderDetailPage } from "./wallet/ProviderDetailPage"; console.log("Wallet setup for Firefox API");
import { SettingsPage } from "./wallet/Settings"; setupPlatform(firefoxAPI);
import { TransactionPage } from "./wallet/Transaction"; } else {
import { WelcomePage } from "./wallet/Welcome"; console.log("Wallet setup for Chrome API");
setupPlatform(chromeAPI);
}
function main(): void { function main(): void {
try { try {
@ -73,230 +57,8 @@ function main(): void {
setupI18n("en", strings); setupI18n("en", strings);
const isFirefox = typeof (window as any)["InstallTrigger"] !== "undefined";
//FIXME: create different entry point for any platform instead of
//switching in runtime
if (isFirefox) {
console.log("Wallet setup for Firefox API");
setupPlatform(firefoxAPI);
} else {
console.log("Wallet setup for Chrome API");
setupPlatform(chromeAPI);
}
if (document.readyState === "loading") { if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main); document.addEventListener("DOMContentLoaded", main);
} else { } else {
main(); main();
} }
function Application(): VNode {
const [globalNotification, setGlobalNotification] = useState<
VNode | undefined
>(undefined);
const hash_history = createHashHistory();
function clearNotification(): void {
setGlobalNotification(undefined);
}
function clearNotificationWhenMovingOut(): void {
// const movingOutFromNotification =
// globalNotification && e.url !== globalNotification.to;
if (globalNotification) {
//&& movingOutFromNotification) {
setGlobalNotification(undefined);
}
}
const { i18n } = useTranslationContext();
return (
<TranslationProvider>
<DevContextProvider>
<IoCProviderForRuntime>
{/* <Match/> won't work in the first render if <Router /> is not called first */}
{/* https://github.com/preactjs/preact-router/issues/415 */}
<Router history={hash_history} />
<Match>
{({ path }: { path: string }) => {
if (path && path.startsWith("/cta")) return;
return (
<Fragment>
<LogoHeader />
<WalletNavBar path={path} />
<div
style={{
backgroundColor: "lightcyan",
display: "flex",
justifyContent: "center",
}}
>
<PendingTransactions
goToTransaction={(txId: string) =>
route(Pages.balance_transaction.replace(":tid", txId))
}
/>
</div>
</Fragment>
);
}}
</Match>
<WalletBox>
{globalNotification && (
<SuccessBox onClick={clearNotification}>
<div>{globalNotification}</div>
</SuccessBox>
)}
<Router
history={hash_history}
onChange={clearNotificationWhenMovingOut}
>
<Route path={Pages.welcome} component={WelcomePage} />
{/**
* BALANCE
*/}
<Route
path={Pages.balance_history}
component={HistoryPage}
goToWalletDeposit={(currency: string) =>
route(Pages.balance_deposit.replace(":currency", currency))
}
goToWalletManualWithdraw={(currency?: string) =>
route(
Pages.balance_manual_withdraw.replace(
":currency?",
currency || "",
),
)
}
/>
<Route
path={Pages.balance_transaction}
component={TransactionPage}
goToWalletHistory={(currency?: string) => {
route(
Pages.balance_history.replace(":currency?", currency || ""),
);
}}
/>
<Route
path={Pages.balance_manual_withdraw}
component={ManualWithdrawPage}
onCancel={() => {
route(Pages.balance);
}}
/>
<Route
path={Pages.balance_deposit}
component={DepositPage}
onCancel={(currency: string) => {
route(Pages.balance_history.replace(":currency?", currency));
}}
onSuccess={(currency: string) => {
route(Pages.balance_history.replace(":currency?", currency));
setGlobalNotification(
<i18n.Translate>
All done, your transaction is in progress
</i18n.Translate>,
);
}}
/>
{/**
* PENDING
*/}
<Route path={Pages.settings} component={SettingsPage} />
{/**
* BACKUP
*/}
<Route
path={Pages.backup}
component={BackupPage}
onAddProvider={() => {
route(Pages.backup_provider_add);
}}
/>
<Route
path={Pages.backup_provider_detail}
component={ProviderDetailPage}
onBack={() => {
route(Pages.backup);
}}
/>
<Route
path={Pages.backup_provider_add}
component={ProviderAddPage}
onBack={() => {
route(Pages.backup);
}}
/>
{/**
* SETTINGS
*/}
<Route
path={Pages.settings_exchange_add}
component={ExchangeAddPage}
onBack={() => {
route(Pages.balance);
}}
/>
{/**
* DEV
*/}
<Route path={Pages.dev} component={DeveloperPage} />
{/**
* CALL TO ACTION
*/}
<Route
path={Pages.cta_pay}
component={PayPage}
goToWalletManualWithdraw={(currency?: string) =>
route(
Pages.balance_manual_withdraw.replace(
":currency?",
currency || "",
),
)
}
goBack={() => route(Pages.balance)}
/>
<Route path={Pages.cta_refund} component={RefundPage} />
<Route path={Pages.cta_tips} component={TipPage} />
<Route path={Pages.cta_withdraw} component={WithdrawPage} />
{/**
* NOT FOUND
* all redirects should be at the end
*/}
<Route
path={Pages.balance}
component={Redirect}
to={Pages.balance_history.replace(":currency?", "")}
/>
<Route
default
component={Redirect}
to={Pages.balance_history.replace(":currency?", "")}
/>
</Router>
</WalletBox>
</IoCProviderForRuntime>
</DevContextProvider>
</TranslationProvider>
);
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
console.log("got some wrong route", to);
route(to, true);
});
return null;
}

View File

@ -97,7 +97,7 @@ export interface UpgradeResponse {
async function callBackend(operation: string, payload: any): Promise<any> { async function callBackend(operation: string, payload: any): Promise<any> {
let response: CoreApiResponse; let response: CoreApiResponse;
try { try {
response = await platform.setMessageToWalletBackground(operation, payload); response = await platform.sendMessageToWalletBackground(operation, payload);
} catch (e) { } catch (e) {
console.log("Error calling backend"); console.log("Error calling backend");
throw new Error(`Error contacting backend: ${e}`); throw new Error(`Error contacting backend: ${e}`);
@ -417,11 +417,11 @@ export function onUpdateNotification(
messageTypes: Array<NotificationType>, messageTypes: Array<NotificationType>,
doCallback: () => void, doCallback: () => void,
): () => void { ): () => void {
const listener = (message: MessageFromBackend): void => { const onNewMessage = (message: MessageFromBackend): void => {
const shouldNotify = messageTypes.includes(message.type); const shouldNotify = messageTypes.includes(message.type);
if (shouldNotify) { if (shouldNotify) {
doCallback(); doCallback();
} }
}; };
return platform.listenToWalletNotifications(listener); return platform.listenToWalletBackground(onNewMessage);
} }

View File

@ -269,7 +269,7 @@ export async function wxMain(): Promise<void> {
// Handlers for messages coming directly from the content // Handlers for messages coming directly from the content
// script on the page // script on the page
platform.registerOnNewMessage((message, sender, callback) => { platform.listenToAllChannels((message, sender, callback) => {
afterWalletIsInitialized.then(() => { afterWalletIsInitialized.then(() => {
dispatch(message, sender, callback); dispatch(message, sender, callback);
}); });
@ -285,8 +285,7 @@ export async function wxMain(): Promise<void> {
// On platforms that support it, also listen to external // On platforms that support it, also listen to external
// modification of permissions. // modification of permissions.
platform.getPermissionsApi().addPermissionsListener((perm) => { platform.getPermissionsApi().addPermissionsListener((perm, lastError) => {
const lastError = platform.getLastError()
if (lastError) { if (lastError) {
console.error(lastError); console.error(lastError);
return; return;

View File

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="/dist/popupEntryPoint.css" /> <link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
<link rel="icon" href="/static/img/icon.png" /> <link rel="icon" href="/static/img/icon.png" />
<script src="/dist/walletEntryPoint.js"></script> <script src="/dist/walletEntryPoint.js"></script>
<style> <style>