fix permission api, grouping all cta into same path
This commit is contained in:
parent
e38be8d8ec
commit
2a417881bb
@ -13,20 +13,30 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
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 { NotificationType } from "@gnu-taler/taler-util";
|
import { NotificationType, TalerErrorDetails } from "@gnu-taler/taler-util";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import * as wxApi from "../wxApi";
|
import * as wxApi from "../wxApi";
|
||||||
|
import { OperationFailedError } from "@gnu-taler/taler-wallet-core";
|
||||||
|
|
||||||
interface HookOk<T> {
|
interface HookOk<T> {
|
||||||
hasError: false;
|
hasError: false;
|
||||||
response: T;
|
response: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HookError {
|
export type HookError = HookGenericError | HookOperationalError
|
||||||
|
|
||||||
|
export interface HookGenericError {
|
||||||
hasError: true;
|
hasError: true;
|
||||||
|
operational: false,
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HookOperationalError {
|
||||||
|
hasError: true;
|
||||||
|
operational: true,
|
||||||
|
details: TalerErrorDetails;
|
||||||
|
}
|
||||||
|
|
||||||
export type HookResponse<T> = HookOk<T> | HookError | undefined;
|
export type HookResponse<T> = HookOk<T> | HookError | undefined;
|
||||||
|
|
||||||
//"withdraw-group-finished"
|
//"withdraw-group-finished"
|
||||||
@ -41,8 +51,10 @@ export function useAsyncAsHook<T>(
|
|||||||
const response = await fn();
|
const response = await fn();
|
||||||
setHookResponse({ hasError: false, response });
|
setHookResponse({ hasError: false, response });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof OperationFailedError) {
|
||||||
setHookResponse({ hasError: true, message: e.message });
|
setHookResponse({ hasError: true, operational: true, details: e.operationError });
|
||||||
|
} else if (e instanceof Error) {
|
||||||
|
setHookResponse({ hasError: true, operational: false, message: e.message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
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 {
|
|
||||||
ProviderInfo,
|
|
||||||
ProviderPaymentPaid,
|
|
||||||
ProviderPaymentStatus,
|
|
||||||
ProviderPaymentType,
|
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
|
||||||
import { useEffect, useState } from "preact/hooks";
|
|
||||||
import * as wxApi from "../wxApi";
|
|
||||||
|
|
||||||
export interface BackupStatus {
|
|
||||||
deviceName: string;
|
|
||||||
providers: ProviderInfo[];
|
|
||||||
sync: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStatusTypeOrder(t: ProviderPaymentStatus) {
|
|
||||||
return [
|
|
||||||
ProviderPaymentType.InsufficientBalance,
|
|
||||||
ProviderPaymentType.TermsChanged,
|
|
||||||
ProviderPaymentType.Unpaid,
|
|
||||||
ProviderPaymentType.Paid,
|
|
||||||
ProviderPaymentType.Pending,
|
|
||||||
].indexOf(t.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStatusPaidOrder(a: ProviderPaymentPaid, b: ProviderPaymentPaid) {
|
|
||||||
return a.paidUntil.t_ms === "never"
|
|
||||||
? -1
|
|
||||||
: b.paidUntil.t_ms === "never"
|
|
||||||
? 1
|
|
||||||
: a.paidUntil.t_ms - b.paidUntil.t_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useBackupStatus(): BackupStatus | undefined {
|
|
||||||
const [status, setStatus] = useState<BackupStatus | undefined>(undefined);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function run() {
|
|
||||||
//create a first list of backup info by currency
|
|
||||||
const status = await wxApi.getBackupInfo();
|
|
||||||
|
|
||||||
const providers = status.providers.sort((a, b) => {
|
|
||||||
if (
|
|
||||||
a.paymentStatus.type === ProviderPaymentType.Paid &&
|
|
||||||
b.paymentStatus.type === ProviderPaymentType.Paid
|
|
||||||
) {
|
|
||||||
return getStatusPaidOrder(a.paymentStatus, b.paymentStatus);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
getStatusTypeOrder(a.paymentStatus) -
|
|
||||||
getStatusTypeOrder(b.paymentStatus)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
async function sync() {
|
|
||||||
await wxApi.syncAllProviders();
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus({ deviceName: status.deviceId, providers, sync });
|
|
||||||
}
|
|
||||||
run();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
@ -17,16 +17,13 @@
|
|||||||
import { useState, useEffect } from "preact/hooks";
|
import { useState, useEffect } from "preact/hooks";
|
||||||
import * as wxApi from "../wxApi";
|
import * as wxApi from "../wxApi";
|
||||||
import { getPermissionsApi } from "../compat";
|
import { getPermissionsApi } from "../compat";
|
||||||
import { extendedPermissions } from "../permissions";
|
import { getReadRequestPermissions } from "../permissions";
|
||||||
|
|
||||||
export function useExtendedPermissions(): [boolean, () => void] {
|
export function useExtendedPermissions(): [boolean, () => void] {
|
||||||
const [enabled, setEnabled] = useState(false);
|
const [enabled, setEnabled] = useState(false);
|
||||||
|
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
setEnabled((v) => !v);
|
handleExtendedPerm(enabled, setEnabled)
|
||||||
handleExtendedPerm(enabled).then((result) => {
|
|
||||||
setEnabled(result);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -39,30 +36,22 @@ export function useExtendedPermissions(): [boolean, () => void] {
|
|||||||
return [enabled, toggle];
|
return [enabled, toggle];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleExtendedPerm(isEnabled: boolean): Promise<boolean> {
|
function handleExtendedPerm(isEnabled: boolean, onChange: (value: boolean) => void): void {
|
||||||
let nextVal: boolean | undefined;
|
|
||||||
|
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
const granted = await new Promise<boolean>((resolve, reject) => {
|
|
||||||
// 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 ...
|
||||||
getPermissionsApi().request(extendedPermissions, (granted: boolean) => {
|
getPermissionsApi().request(getReadRequestPermissions(), async (granted: boolean) => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("error requesting permissions");
|
console.error("error requesting permissions");
|
||||||
console.error(chrome.runtime.lastError);
|
console.error(chrome.runtime.lastError);
|
||||||
reject(chrome.runtime.lastError);
|
onChange(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("permissions granted:", granted);
|
console.log("permissions granted:", granted);
|
||||||
resolve(granted);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const res = await wxApi.setExtendedPermissions(granted);
|
const res = await wxApi.setExtendedPermissions(granted);
|
||||||
nextVal = res.newValue;
|
onChange(res.newValue);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const res = await wxApi.setExtendedPermissions(false);
|
wxApi.setExtendedPermissions(false).then(r => onChange(r.newValue));
|
||||||
nextVal = res.newValue;
|
|
||||||
}
|
}
|
||||||
console.log("new permissions applied:", nextVal ?? false);
|
|
||||||
return nextVal ?? false;
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const extendedPermissions = {
|
export const getReadRequestPermissions = () =>
|
||||||
|
chrome.runtime.getManifest().manifest_version === 3 ? ({
|
||||||
permissions: ["webRequest"],
|
permissions: ["webRequest"],
|
||||||
origins: ["http://*/*", "https://*/*"],
|
origins: ["http://*/*", "https://*/*"],
|
||||||
};
|
}) : ({
|
||||||
|
permissions: ["webRequest", "webRequestBlocking"],
|
||||||
|
origins: ["http://*/*", "https://*/*"],
|
||||||
|
});
|
||||||
|
@ -17,12 +17,13 @@
|
|||||||
import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
|
import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { BalanceTable } from "../components/BalanceTable";
|
import { BalanceTable } from "../components/BalanceTable";
|
||||||
import { ButtonPrimary, ErrorBox } from "../components/styled";
|
import { Loading } from "../components/Loading";
|
||||||
|
import { LoadingError } from "../components/LoadingError";
|
||||||
|
import { MultiActionButton } from "../components/MultiActionButton";
|
||||||
|
import { ButtonPrimary } from "../components/styled";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||||
import { PageLink } from "../renderHtml";
|
import { PageLink } from "../renderHtml";
|
||||||
import * as wxApi from "../wxApi";
|
import * as wxApi from "../wxApi";
|
||||||
import { MultiActionButton } from "../components/MultiActionButton";
|
|
||||||
import { Loading } from "../components/Loading";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
goToWalletDeposit: (currency: string) => void;
|
goToWalletDeposit: (currency: string) => void;
|
||||||
@ -42,15 +43,7 @@ export function BalancePage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return (
|
return <LoadingError title="Could not load balance page" error={state} />;
|
||||||
<Fragment>
|
|
||||||
<ErrorBox>{state.message}</ErrorBox>
|
|
||||||
<p>
|
|
||||||
Click <PageLink pageName="welcome">here</PageLink> for help and
|
|
||||||
diagnostics.
|
|
||||||
</p>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -98,7 +98,7 @@ function Application(): VNode {
|
|||||||
component={BalancePage}
|
component={BalancePage}
|
||||||
goToWalletManualWithdraw={() =>
|
goToWalletManualWithdraw={() =>
|
||||||
goToWalletPage(
|
goToWalletPage(
|
||||||
Pages.manual_withdraw.replace(":currency?", ""),
|
Pages.balance_manual_withdraw.replace(":currency?", ""),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
goToWalletHistory={(currency: string) =>
|
goToWalletHistory={(currency: string) =>
|
||||||
@ -128,9 +128,9 @@ function Application(): VNode {
|
|||||||
<Route path={Pages.last_activity} component={LastActivityPage} />
|
<Route path={Pages.last_activity} component={LastActivityPage} />
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={Pages.transaction}
|
path={Pages.balance_transaction}
|
||||||
component={({ tid }: { tid: string }) =>
|
component={({ tid }: { tid: string }) =>
|
||||||
goToWalletPage(Pages.transaction.replace(":tid", tid))
|
goToWalletPage(Pages.balance_transaction.replace(":tid", tid))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -138,18 +138,18 @@ function Application(): VNode {
|
|||||||
path={Pages.backup}
|
path={Pages.backup}
|
||||||
component={BackupPage}
|
component={BackupPage}
|
||||||
onAddProvider={() => {
|
onAddProvider={() => {
|
||||||
route(Pages.provider_add);
|
route(Pages.backup_provider_add);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.provider_detail}
|
path={Pages.backup_provider_detail}
|
||||||
component={ProviderDetailPage}
|
component={ProviderDetailPage}
|
||||||
onBack={() => {
|
onBack={() => {
|
||||||
route(Pages.backup);
|
route(Pages.backup);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.provider_add}
|
path={Pages.backup_provider_add}
|
||||||
component={ProviderAddPage}
|
component={ProviderAddPage}
|
||||||
onBack={() => {
|
onBack={() => {
|
||||||
route(Pages.backup);
|
route(Pages.backup);
|
||||||
@ -157,7 +157,7 @@ function Application(): VNode {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={Pages.exchange_add}
|
path={Pages.settings_exchange_add}
|
||||||
component={ExchangeAddPage}
|
component={ExchangeAddPage}
|
||||||
onBack={() => {
|
onBack={() => {
|
||||||
route(Pages.balance);
|
route(Pages.balance);
|
||||||
|
@ -193,19 +193,19 @@ export function actionForTalerUri(
|
|||||||
): string | undefined {
|
): string | undefined {
|
||||||
switch (uriType) {
|
switch (uriType) {
|
||||||
case TalerUriType.TalerWithdraw:
|
case TalerUriType.TalerWithdraw:
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/withdraw", {
|
return makeExtensionUrlWithParams("static/wallet.html#/cta/withdraw", {
|
||||||
talerWithdrawUri: talerUri,
|
talerWithdrawUri: talerUri,
|
||||||
});
|
});
|
||||||
case TalerUriType.TalerPay:
|
case TalerUriType.TalerPay:
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/pay", {
|
return makeExtensionUrlWithParams("static/wallet.html#/cta/pay", {
|
||||||
talerPayUri: talerUri,
|
talerPayUri: talerUri,
|
||||||
});
|
});
|
||||||
case TalerUriType.TalerTip:
|
case TalerUriType.TalerTip:
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/tip", {
|
return makeExtensionUrlWithParams("static/wallet.html#/cta/tip", {
|
||||||
talerTipUri: talerUri,
|
talerTipUri: talerUri,
|
||||||
});
|
});
|
||||||
case TalerUriType.TalerRefund:
|
case TalerUriType.TalerRefund:
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/refund", {
|
return makeExtensionUrlWithParams("static/wallet.html#/cta/refund", {
|
||||||
talerRefundUri: talerUri,
|
talerRefundUri: talerUri,
|
||||||
});
|
});
|
||||||
case TalerUriType.TalerNotifyReserve:
|
case TalerUriType.TalerNotifyReserve:
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
import { i18n, Timestamp } from "@gnu-taler/taler-util";
|
import { i18n, Timestamp } from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
ProviderInfo,
|
ProviderInfo,
|
||||||
|
ProviderPaymentPaid,
|
||||||
ProviderPaymentStatus,
|
ProviderPaymentStatus,
|
||||||
|
ProviderPaymentType,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import {
|
import {
|
||||||
differenceInMonths,
|
differenceInMonths,
|
||||||
@ -25,6 +27,8 @@ import {
|
|||||||
intervalToDuration,
|
intervalToDuration,
|
||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
|
import { Loading } from "../components/Loading";
|
||||||
|
import { LoadingError } from "../components/LoadingError";
|
||||||
import {
|
import {
|
||||||
BoldLight,
|
BoldLight,
|
||||||
ButtonPrimary,
|
ButtonPrimary,
|
||||||
@ -36,23 +40,58 @@ import {
|
|||||||
SmallLightText,
|
SmallLightText,
|
||||||
SmallText,
|
SmallText,
|
||||||
} from "../components/styled";
|
} from "../components/styled";
|
||||||
import { useBackupStatus } from "../hooks/useBackupStatus";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||||
import { Pages } from "../NavigationBar";
|
import { Pages } from "../NavigationBar";
|
||||||
|
import * as wxApi from "../wxApi";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onAddProvider: () => void;
|
onAddProvider: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interface BackupStatus {
|
||||||
|
// deviceName: string;
|
||||||
|
// providers: ProviderInfo[];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async function getBackupInfoOrdered(): BackupStatus {
|
||||||
|
// //create a first list of backup info by currency
|
||||||
|
// const status = await wxApi.getBackupInfo();
|
||||||
|
|
||||||
|
// return { deviceName: status.deviceId, providers };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async function sync() {
|
||||||
|
// await wxApi.syncAllProviders();
|
||||||
|
// }
|
||||||
|
|
||||||
export function BackupPage({ onAddProvider }: Props): VNode {
|
export function BackupPage({ onAddProvider }: Props): VNode {
|
||||||
const status = useBackupStatus();
|
const status = useAsyncAsHook(wxApi.getBackupInfo);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return <div>Loading...</div>;
|
return <Loading />;
|
||||||
|
}
|
||||||
|
if (status.hasError) {
|
||||||
|
return (
|
||||||
|
<LoadingError title="Could not load backup providers" error={status} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const providers = status.response.providers.sort((a, b) => {
|
||||||
|
if (
|
||||||
|
a.paymentStatus.type === ProviderPaymentType.Paid &&
|
||||||
|
b.paymentStatus.type === ProviderPaymentType.Paid
|
||||||
|
) {
|
||||||
|
return getStatusPaidOrder(a.paymentStatus, b.paymentStatus);
|
||||||
}
|
}
|
||||||
|
return (
|
||||||
|
getStatusTypeOrder(a.paymentStatus) - getStatusTypeOrder(b.paymentStatus)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BackupView
|
<BackupView
|
||||||
providers={status.providers}
|
providers={providers}
|
||||||
onAddProvider={onAddProvider}
|
onAddProvider={onAddProvider}
|
||||||
onSyncAll={status.sync}
|
onSyncAll={wxApi.syncAllProviders}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -128,7 +167,7 @@ function BackupLayout(props: TransactionLayoutProps): VNode {
|
|||||||
<RowBorderGray>
|
<RowBorderGray>
|
||||||
<div style={{ color: !props.active ? "grey" : undefined }}>
|
<div style={{ color: !props.active ? "grey" : undefined }}>
|
||||||
<a
|
<a
|
||||||
href={Pages.provider_detail.replace(
|
href={Pages.backup_provider_detail.replace(
|
||||||
":pid",
|
":pid",
|
||||||
encodeURIComponent(props.id),
|
encodeURIComponent(props.id),
|
||||||
)}
|
)}
|
||||||
@ -194,3 +233,21 @@ function daysUntil(d: Timestamp): string {
|
|||||||
});
|
});
|
||||||
return `${str}`;
|
return `${str}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStatusTypeOrder(t: ProviderPaymentStatus) {
|
||||||
|
return [
|
||||||
|
ProviderPaymentType.InsufficientBalance,
|
||||||
|
ProviderPaymentType.TermsChanged,
|
||||||
|
ProviderPaymentType.Unpaid,
|
||||||
|
ProviderPaymentType.Paid,
|
||||||
|
ProviderPaymentType.Pending,
|
||||||
|
].indexOf(t.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusPaidOrder(a: ProviderPaymentPaid, b: ProviderPaymentPaid) {
|
||||||
|
return a.paidUntil.t_ms === "never"
|
||||||
|
? -1
|
||||||
|
: b.paidUntil.t_ms === "never"
|
||||||
|
? 1
|
||||||
|
: a.paidUntil.t_ms - b.paidUntil.t_ms;
|
||||||
|
}
|
||||||
|
@ -18,13 +18,9 @@ import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { BalanceTable } from "../components/BalanceTable";
|
import { BalanceTable } from "../components/BalanceTable";
|
||||||
import { Loading } from "../components/Loading";
|
import { Loading } from "../components/Loading";
|
||||||
|
import { LoadingError } from "../components/LoadingError";
|
||||||
import { MultiActionButton } from "../components/MultiActionButton";
|
import { MultiActionButton } from "../components/MultiActionButton";
|
||||||
import {
|
import { ButtonPrimary, Centered } from "../components/styled";
|
||||||
ButtonPrimary,
|
|
||||||
Centered,
|
|
||||||
ErrorBox,
|
|
||||||
SuccessBox,
|
|
||||||
} from "../components/styled";
|
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||||
import { PageLink } from "../renderHtml";
|
import { PageLink } from "../renderHtml";
|
||||||
import * as wxApi from "../wxApi";
|
import * as wxApi from "../wxApi";
|
||||||
@ -49,15 +45,7 @@ export function BalancePage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return (
|
return <LoadingError title="Could not load balance page" error={state} />;
|
||||||
<Fragment>
|
|
||||||
<ErrorBox>{state.message}</ErrorBox>
|
|
||||||
<p>
|
|
||||||
Click <PageLink pageName="welcome">here</PageLink> for help and
|
|
||||||
diagnostics.
|
|
||||||
</p>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
canonicalizeBaseUrl,
|
canonicalizeBaseUrl,
|
||||||
ExchangeListItem,
|
|
||||||
i18n,
|
i18n,
|
||||||
TalerConfigResponse,
|
TalerConfigResponse,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
@ -23,12 +23,12 @@ import {
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { Loading } from "../components/Loading";
|
import { Loading } from "../components/Loading";
|
||||||
|
import { LoadingError } from "../components/LoadingError";
|
||||||
import {
|
import {
|
||||||
ButtonBoxPrimary,
|
ButtonBoxPrimary,
|
||||||
ButtonBoxWarning,
|
ButtonBoxWarning,
|
||||||
ButtonPrimary,
|
ButtonPrimary,
|
||||||
DateSeparator,
|
DateSeparator,
|
||||||
ErrorBox,
|
|
||||||
NiceSelect,
|
NiceSelect,
|
||||||
WarningBox,
|
WarningBox,
|
||||||
} from "../components/styled";
|
} from "../components/styled";
|
||||||
@ -62,10 +62,10 @@ export function HistoryPage({
|
|||||||
|
|
||||||
if (transactionQuery.hasError) {
|
if (transactionQuery.hasError) {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<LoadingError
|
||||||
<ErrorBox>{transactionQuery.message}</ErrorBox>
|
title="Could not load the list of transactions"
|
||||||
<p>There was an error loading the transactions.</p>
|
error={transactionQuery}
|
||||||
</Fragment>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,23 +14,23 @@
|
|||||||
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 { VNode, h, Fragment } from "preact";
|
|
||||||
import { useState } from "preact/hooks";
|
|
||||||
import { CreateManualWithdraw } from "./CreateManualWithdraw";
|
|
||||||
import * as wxApi from "../wxApi";
|
|
||||||
import {
|
import {
|
||||||
AcceptManualWithdrawalResult,
|
AcceptManualWithdrawalResult,
|
||||||
AmountJson,
|
AmountJson,
|
||||||
Amounts,
|
Amounts,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { ReserveCreated } from "./ReserveCreated";
|
import { h, VNode } from "preact";
|
||||||
import { route } from "preact-router";
|
import { route } from "preact-router";
|
||||||
import { Pages } from "../NavigationBar";
|
import { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
|
||||||
import { ExchangeAddPage } from "./ExchangeAddPage";
|
|
||||||
import { Loading } from "../components/Loading";
|
import { Loading } from "../components/Loading";
|
||||||
import { ErrorBox } from "../components/styled";
|
import { LoadingError } from "../components/LoadingError";
|
||||||
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||||
|
import { Pages } from "../NavigationBar";
|
||||||
|
import * as wxApi from "../wxApi";
|
||||||
|
import { CreateManualWithdraw } from "./CreateManualWithdraw";
|
||||||
|
import { ExchangeAddPage } from "./ExchangeAddPage";
|
||||||
|
import { ReserveCreated } from "./ReserveCreated";
|
||||||
|
|
||||||
export function ManualWithdrawPage({ currency }: { currency?: string }): VNode {
|
export function ManualWithdrawPage({ currency }: { currency?: string }): VNode {
|
||||||
const [success, setSuccess] = useState<
|
const [success, setSuccess] = useState<
|
||||||
@ -92,12 +92,13 @@ export function ManualWithdrawPage({ currency }: { currency?: string }): VNode {
|
|||||||
}
|
}
|
||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<LoadingError
|
||||||
<ErrorBox>{state.message}</ErrorBox>
|
title="Could not load the list of known exchanges"
|
||||||
<p>There was an error getting the known exchanges</p>
|
error={state}
|
||||||
</Fragment>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const exchangeList = state.response.exchanges.reduce(
|
const exchangeList = state.response.exchanges.reduce(
|
||||||
(p, c) => ({
|
(p, c) => ({
|
||||||
...p,
|
...p,
|
||||||
|
@ -142,7 +142,9 @@ export function SettingsView({
|
|||||||
)}
|
)}
|
||||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
<div />
|
<div />
|
||||||
<LinkPrimary href={Pages.exchange_add}>Add an exchange</LinkPrimary>
|
<LinkPrimary href={Pages.settings_exchange_add}>
|
||||||
|
Add an exchange
|
||||||
|
</LinkPrimary>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Config</h2>
|
<h2>Config</h2>
|
||||||
|
@ -78,6 +78,9 @@ function Application(): VNode {
|
|||||||
string | undefined
|
string | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
const hash_history = createHashHistory();
|
const hash_history = createHashHistory();
|
||||||
|
function clearNotification(): void {
|
||||||
|
setGlobalNotification(undefined);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<DevContextProvider>
|
<DevContextProvider>
|
||||||
@ -94,21 +97,36 @@ function Application(): VNode {
|
|||||||
</Match>
|
</Match>
|
||||||
<WalletBox>
|
<WalletBox>
|
||||||
{globalNotification && (
|
{globalNotification && (
|
||||||
<SuccessBox onClick={() => setGlobalNotification(undefined)}>
|
<SuccessBox onClick={clearNotification}>
|
||||||
<div>{globalNotification}</div>
|
<div>{globalNotification}</div>
|
||||||
</SuccessBox>
|
</SuccessBox>
|
||||||
)}
|
)}
|
||||||
<Router history={hash_history}>
|
<Router
|
||||||
|
history={hash_history}
|
||||||
|
onChange={() => {
|
||||||
|
// const movingOutFromNotification =
|
||||||
|
// globalNotification && e.url !== globalNotification.to;
|
||||||
|
if (globalNotification) {
|
||||||
|
setGlobalNotification(undefined);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Route path={Pages.welcome} component={WelcomePage} />
|
<Route path={Pages.welcome} component={WelcomePage} />
|
||||||
|
|
||||||
|
{/**
|
||||||
|
* BALANCE
|
||||||
|
*/}
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={Pages.balance}
|
path={Pages.balance}
|
||||||
component={BalancePage}
|
component={BalancePage}
|
||||||
goToWalletManualWithdraw={() =>
|
goToWalletManualWithdraw={() =>
|
||||||
route(Pages.manual_withdraw.replace(":currency?", ""))
|
route(
|
||||||
|
Pages.balance_manual_withdraw.replace(":currency?", ""),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
goToWalletDeposit={(currency: string) =>
|
goToWalletDeposit={(currency: string) =>
|
||||||
route(Pages.deposit.replace(":currency", currency))
|
route(Pages.balance_deposit.replace(":currency", currency))
|
||||||
}
|
}
|
||||||
goToWalletHistory={(currency: string) =>
|
goToWalletHistory={(currency: string) =>
|
||||||
route(Pages.balance_history.replace(":currency", currency))
|
route(Pages.balance_history.replace(":currency", currency))
|
||||||
@ -118,11 +136,11 @@ function Application(): VNode {
|
|||||||
path={Pages.balance_history}
|
path={Pages.balance_history}
|
||||||
component={HistoryPage}
|
component={HistoryPage}
|
||||||
goToWalletDeposit={(currency: string) =>
|
goToWalletDeposit={(currency: string) =>
|
||||||
route(Pages.deposit.replace(":currency", currency))
|
route(Pages.balance_deposit.replace(":currency", currency))
|
||||||
}
|
}
|
||||||
goToWalletManualWithdraw={(currency?: string) =>
|
goToWalletManualWithdraw={(currency?: string) =>
|
||||||
route(
|
route(
|
||||||
Pages.manual_withdraw.replace(
|
Pages.balance_manual_withdraw.replace(
|
||||||
":currency?",
|
":currency?",
|
||||||
currency || "",
|
currency || "",
|
||||||
),
|
),
|
||||||
@ -130,48 +148,17 @@ function Application(): VNode {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.last_activity}
|
path={Pages.balance_transaction}
|
||||||
component={LastActivityPage}
|
component={TransactionPage}
|
||||||
/>
|
|
||||||
<Route path={Pages.transaction} component={TransactionPage} />
|
|
||||||
<Route path={Pages.settings} component={SettingsPage} />
|
|
||||||
<Route
|
|
||||||
path={Pages.backup}
|
|
||||||
component={BackupPage}
|
|
||||||
onAddProvider={() => {
|
|
||||||
route(Pages.provider_add);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={Pages.provider_detail}
|
|
||||||
component={ProviderDetailPage}
|
|
||||||
onBack={() => {
|
|
||||||
route(Pages.backup);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={Pages.provider_add}
|
|
||||||
component={ProviderAddPage}
|
|
||||||
onBack={() => {
|
|
||||||
route(Pages.backup);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={Pages.exchange_add}
|
path={Pages.balance_manual_withdraw}
|
||||||
component={ExchangeAddPage}
|
|
||||||
onBack={() => {
|
|
||||||
route(Pages.balance);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route
|
|
||||||
path={Pages.manual_withdraw}
|
|
||||||
component={ManualWithdrawPage}
|
component={ManualWithdrawPage}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={Pages.deposit}
|
path={Pages.balance_deposit}
|
||||||
component={DepositPage}
|
component={DepositPage}
|
||||||
onSuccess={(currency: string) => {
|
onSuccess={(currency: string) => {
|
||||||
route(Pages.balance_history.replace(":currency", currency));
|
route(Pages.balance_history.replace(":currency", currency));
|
||||||
@ -180,28 +167,66 @@ function Application(): VNode {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{/**
|
||||||
|
* LAST ACTIVITY
|
||||||
|
*/}
|
||||||
<Route
|
<Route
|
||||||
path={Pages.reset_required}
|
path={Pages.last_activity}
|
||||||
component={() => <div>no yet implemented</div>}
|
component={LastActivityPage}
|
||||||
|
/>
|
||||||
|
<Route path={Pages.settings} component={SettingsPage} />
|
||||||
|
|
||||||
|
{/**
|
||||||
|
* BACKUP
|
||||||
|
*/}
|
||||||
|
<Route
|
||||||
|
path={Pages.backup}
|
||||||
|
component={BackupPage}
|
||||||
|
onAddProvider={() => {
|
||||||
|
route(Pages.backup_provider_add);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.payback}
|
path={Pages.backup_provider_detail}
|
||||||
component={() => <div>no yet implemented</div>}
|
component={ProviderDetailPage}
|
||||||
|
onBack={() => {
|
||||||
|
route(Pages.backup);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.return_coins}
|
path={Pages.backup_provider_add}
|
||||||
component={() => <div>no yet implemented</div>}
|
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} />
|
<Route path={Pages.dev} component={DeveloperPage} />
|
||||||
|
|
||||||
{/** call to action */}
|
{/**
|
||||||
|
* CALL TO ACTION
|
||||||
|
*/}
|
||||||
<Route
|
<Route
|
||||||
path={Pages.pay}
|
path={Pages.cta_pay}
|
||||||
component={PayPage}
|
component={PayPage}
|
||||||
goToWalletManualWithdraw={(currency?: string) =>
|
goToWalletManualWithdraw={(currency?: string) =>
|
||||||
route(
|
route(
|
||||||
Pages.manual_withdraw.replace(
|
Pages.balance_manual_withdraw.replace(
|
||||||
":currency?",
|
":currency?",
|
||||||
currency || "",
|
currency || "",
|
||||||
),
|
),
|
||||||
@ -209,15 +234,13 @@ function Application(): VNode {
|
|||||||
}
|
}
|
||||||
goBack={() => route(Pages.balance)}
|
goBack={() => route(Pages.balance)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route path={Pages.cta_refund} component={RefundPage} />
|
||||||
path={Pages.pay}
|
<Route path={Pages.cta_tips} component={TipPage} />
|
||||||
component={PayPage}
|
<Route path={Pages.cta_withdraw} component={WithdrawPage} />
|
||||||
goBack={() => route(Pages.balance)}
|
|
||||||
/>
|
|
||||||
<Route path={Pages.refund} component={RefundPage} />
|
|
||||||
<Route path={Pages.tips} component={TipPage} />
|
|
||||||
<Route path={Pages.withdraw} component={WithdrawPage} />
|
|
||||||
|
|
||||||
|
{/**
|
||||||
|
* NOT FOUND
|
||||||
|
*/}
|
||||||
<Route default component={Redirect} to={Pages.balance} />
|
<Route default component={Redirect} to={Pages.balance} />
|
||||||
</Router>
|
</Router>
|
||||||
</WalletBox>
|
</WalletBox>
|
||||||
@ -230,7 +253,7 @@ function Application(): VNode {
|
|||||||
|
|
||||||
function Redirect({ to }: { to: string }): null {
|
function Redirect({ to }: { to: string }): null {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("go some wrong route");
|
console.log("got some wrong route", to);
|
||||||
route(to, true);
|
route(to, true);
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
|
@ -40,7 +40,7 @@ import {
|
|||||||
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
|
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
|
||||||
import { BrowserHttpLib } from "./browserHttpLib";
|
import { BrowserHttpLib } from "./browserHttpLib";
|
||||||
import { getPermissionsApi, isFirefox } from "./compat";
|
import { getPermissionsApi, isFirefox } from "./compat";
|
||||||
import { extendedPermissions } from "./permissions";
|
import { getReadRequestPermissions } from "./permissions";
|
||||||
import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
|
import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
|
||||||
import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib";
|
import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib";
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ async function dispatch(
|
|||||||
}
|
}
|
||||||
case "wxGetExtendedPermissions": {
|
case "wxGetExtendedPermissions": {
|
||||||
const res = await new Promise((resolve, reject) => {
|
const res = await new Promise((resolve, reject) => {
|
||||||
getPermissionsApi().contains(extendedPermissions, (result: boolean) => {
|
getPermissionsApi().contains(getReadRequestPermissions(), (result: boolean) => {
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -143,7 +143,7 @@ async function dispatch(
|
|||||||
r = wrapResponse({ newValue: true });
|
r = wrapResponse({ newValue: true });
|
||||||
} else {
|
} else {
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
getPermissionsApi().remove(extendedPermissions, (rem) => {
|
getPermissionsApi().remove(getReadRequestPermissions(), (rem) => {
|
||||||
console.log("permissions removed:", rem);
|
console.log("permissions removed:", rem);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -339,7 +339,7 @@ function headerListener(
|
|||||||
switch (uriType) {
|
switch (uriType) {
|
||||||
case TalerUriType.TalerWithdraw:
|
case TalerUriType.TalerWithdraw:
|
||||||
return makeSyncWalletRedirect(
|
return makeSyncWalletRedirect(
|
||||||
"/static/wallet.html#/withdraw",
|
"/static/wallet.html#/cta/withdraw",
|
||||||
details.tabId,
|
details.tabId,
|
||||||
details.url,
|
details.url,
|
||||||
{
|
{
|
||||||
@ -348,7 +348,7 @@ function headerListener(
|
|||||||
);
|
);
|
||||||
case TalerUriType.TalerPay:
|
case TalerUriType.TalerPay:
|
||||||
return makeSyncWalletRedirect(
|
return makeSyncWalletRedirect(
|
||||||
"/static/wallet.html#/pay",
|
"/static/wallet.html#/cta/pay",
|
||||||
details.tabId,
|
details.tabId,
|
||||||
details.url,
|
details.url,
|
||||||
{
|
{
|
||||||
@ -357,7 +357,7 @@ function headerListener(
|
|||||||
);
|
);
|
||||||
case TalerUriType.TalerTip:
|
case TalerUriType.TalerTip:
|
||||||
return makeSyncWalletRedirect(
|
return makeSyncWalletRedirect(
|
||||||
"/static/wallet.html#/tip",
|
"/static/wallet.html#/cta/tip",
|
||||||
details.tabId,
|
details.tabId,
|
||||||
details.url,
|
details.url,
|
||||||
{
|
{
|
||||||
@ -366,7 +366,7 @@ function headerListener(
|
|||||||
);
|
);
|
||||||
case TalerUriType.TalerRefund:
|
case TalerUriType.TalerRefund:
|
||||||
return makeSyncWalletRedirect(
|
return makeSyncWalletRedirect(
|
||||||
"/static/wallet.html#/refund",
|
"/static/wallet.html#/cta/refund",
|
||||||
details.tabId,
|
details.tabId,
|
||||||
details.url,
|
details.url,
|
||||||
{
|
{
|
||||||
@ -402,7 +402,7 @@ function setupHeaderListener(): void {
|
|||||||
}
|
}
|
||||||
console.log("setting up header listener");
|
console.log("setting up header listener");
|
||||||
// Handlers for catching HTTP requests
|
// Handlers for catching HTTP requests
|
||||||
getPermissionsApi().contains(extendedPermissions, (result: boolean) => {
|
getPermissionsApi().contains(getReadRequestPermissions(), (result: boolean) => {
|
||||||
if (
|
if (
|
||||||
"webRequest" in chrome &&
|
"webRequest" in chrome &&
|
||||||
"onHeadersReceived" in chrome.webRequest &&
|
"onHeadersReceived" in chrome.webRequest &&
|
||||||
|
Loading…
Reference in New Issue
Block a user