summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-04-15 12:01:16 -0300
committerSebastian <sebasjm@gmail.com>2024-04-15 12:01:16 -0300
commita7c8f0f3edd738a59d719105cda3aa8821886b90 (patch)
treeacb402075b7b0c0788ec0c5fbecfb58ece64357d
parent56a6c92c814547fcf8af25f183f6ecd75fbbfbb9 (diff)
downloadwallet-core-a7c8f0f3edd738a59d719105cda3aa8821886b90.tar.gz
wallet-core-a7c8f0f3edd738a59d719105cda3aa8821886b90.tar.bz2
wallet-core-a7c8f0f3edd738a59d719105cda3aa8821886b90.zip
fix #8604
-rw-r--r--packages/merchant-backoffice-ui/src/Application.tsx383
-rw-r--r--packages/merchant-backoffice-ui/src/Routing.tsx10
-rw-r--r--packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx3
-rw-r--r--packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx21
-rw-r--r--packages/merchant-backoffice-ui/src/components/menu/index.tsx13
-rw-r--r--packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx13
-rw-r--r--packages/merchant-backoffice-ui/src/context/session.ts282
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/bank.ts9
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/instance.ts11
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/order.ts7
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/otp.ts9
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/product.ts7
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/templates.ts7
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/transfer.ts5
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/webhooks.ts9
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx45
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx13
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx9
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx8
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx6
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx10
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx8
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx9
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx4
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx24
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx9
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx6
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx18
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx98
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx9
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx10
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/paths/login/index.tsx119
-rw-r--r--packages/taler-harness/src/index.ts96
-rw-r--r--packages/taler-util/src/codec.ts34
-rw-r--r--packages/taler-util/src/http-client/authentication.ts4
-rw-r--r--packages/taler-util/src/http-client/types.ts16
-rw-r--r--packages/taler-util/src/http-client/utils.ts2
-rw-r--r--packages/web-util/src/context/activity.ts2
-rw-r--r--packages/web-util/src/context/merchant-api.ts34
59 files changed, 719 insertions, 777 deletions
diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx
index d5a05e821..097e98567 100644
--- a/packages/merchant-backoffice-ui/src/Application.tsx
+++ b/packages/merchant-backoffice-ui/src/Application.tsx
@@ -19,14 +19,21 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { CacheEvictor, TalerMerchantApi, TalerMerchantInstanceCacheEviction, TalerMerchantManagementCacheEviction, assertUnreachable, canonicalizeBaseUrl } from "@gnu-taler/taler-util";
+import {
+ CacheEvictor,
+ TalerMerchantApi,
+ TalerMerchantInstanceCacheEviction,
+ TalerMerchantManagementCacheEviction,
+ assertUnreachable,
+ canonicalizeBaseUrl,
+} from "@gnu-taler/taler-util";
import {
BrowserHashNavigationProvider,
ConfigResultFail,
MerchantApiProvider,
TalerWalletIntegrationBrowserProvider,
TranslationProvider,
- useTranslationContext
+ useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
@@ -35,16 +42,43 @@ import { Routing } from "./Routing.js";
import { Loading } from "./components/exception/loading.js";
import { NotificationCard } from "./components/menu/index.js";
import { SettingsProvider } from "./context/settings.js";
-import { revalidateBankAccountDetails, revalidateInstanceBankAccounts } from "./hooks/bank.js";
-import { revalidateBackendInstances, revalidateInstanceDetails, revalidateManagedInstanceDetails } from "./hooks/instance.js";
-import { revalidateInstanceOtpDevices, revalidateOtpDeviceDetails } from "./hooks/otp.js";
-import { revalidateInstanceProducts, revalidateProductDetails } from "./hooks/product.js";
-import { revalidateInstanceTemplates, revalidateTemplateDetails } from "./hooks/templates.js";
+import {
+ revalidateBankAccountDetails,
+ revalidateInstanceBankAccounts,
+} from "./hooks/bank.js";
+import {
+ revalidateBackendInstances,
+ revalidateInstanceDetails,
+ revalidateManagedInstanceDetails,
+} from "./hooks/instance.js";
+import {
+ revalidateInstanceOtpDevices,
+ revalidateOtpDeviceDetails,
+} from "./hooks/otp.js";
+import {
+ revalidateInstanceProducts,
+ revalidateProductDetails,
+} from "./hooks/product.js";
+import {
+ revalidateInstanceTemplates,
+ revalidateTemplateDetails,
+} from "./hooks/templates.js";
import { revalidateInstanceTransfers } from "./hooks/transfer.js";
-import { revalidateInstanceWebhooks, revalidateWebhookDetails } from "./hooks/webhooks.js";
+import {
+ revalidateInstanceWebhooks,
+ revalidateWebhookDetails,
+} from "./hooks/webhooks.js";
import { strings } from "./i18n/strings.js";
-import { MerchantUiSettings, buildDefaultBackendBaseURL, fetchSettings } from "./settings.js";
-import { revalidateInstanceOrders, revalidateOrderDetails } from "./hooks/order.js";
+import {
+ MerchantUiSettings,
+ buildDefaultBackendBaseURL,
+ fetchSettings,
+} from "./settings.js";
+import {
+ revalidateInstanceOrders,
+ revalidateOrderDetails,
+} from "./hooks/order.js";
+import { SessionContextProvider } from "./context/session.js";
const WITH_LOCAL_STORAGE_CACHE = false;
export function Application(): VNode {
@@ -64,42 +98,48 @@ export function Application(): VNode {
de: strings["de"].completeness,
}}
>
- <MerchantApiProvider baseUrl={new URL("./", baseUrl)} frameOnError={OnConfigError} evictors={{
- management: swrCacheEvictor
- }}>
- <SWRConfig
- value={{
- provider: WITH_LOCAL_STORAGE_CACHE
- ? localStorageProvider
- : undefined,
- // normally, do not revalidate
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- revalidateIfStale: false,
- revalidateOnMount: undefined,
- focusThrottleInterval: undefined,
+ <MerchantApiProvider
+ baseUrl={new URL("./", baseUrl)}
+ frameOnError={OnConfigError}
+ evictors={{
+ management: swrCacheEvictor,
+ }}
+ >
+ <SessionContextProvider>
+ <SWRConfig
+ value={{
+ provider: WITH_LOCAL_STORAGE_CACHE
+ ? localStorageProvider
+ : undefined,
+ // normally, do not revalidate
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ revalidateIfStale: false,
+ revalidateOnMount: undefined,
+ focusThrottleInterval: undefined,
- // normally, do not refresh
- refreshInterval: undefined,
- dedupingInterval: 2000,
- refreshWhenHidden: false,
- refreshWhenOffline: false,
+ // normally, do not refresh
+ refreshInterval: undefined,
+ dedupingInterval: 2000,
+ refreshWhenHidden: false,
+ refreshWhenOffline: false,
- // ignore errors
- shouldRetryOnError: false,
- errorRetryCount: 0,
- errorRetryInterval: undefined,
+ // ignore errors
+ shouldRetryOnError: false,
+ errorRetryCount: 0,
+ errorRetryInterval: undefined,
- // do not go to loading again if already has data
- keepPreviousData: true,
- }}
- >
- <TalerWalletIntegrationBrowserProvider>
- <BrowserHashNavigationProvider>
- <Routing />
- </BrowserHashNavigationProvider>
- </TalerWalletIntegrationBrowserProvider>
- </SWRConfig>
+ // do not go to loading again if already has data
+ keepPreviousData: true,
+ }}
+ >
+ <TalerWalletIntegrationBrowserProvider>
+ <BrowserHashNavigationProvider>
+ <Routing />
+ </BrowserHashNavigationProvider>
+ </TalerWalletIntegrationBrowserProvider>
+ </SWRConfig>
+ </SessionContextProvider>
</MerchantApiProvider>
</TranslationProvider>
</SettingsProvider>
@@ -150,187 +190,157 @@ function localStorageProvider(): Map<unknown, unknown> {
return map;
}
-function OnConfigError({ state }: { state: ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined }): VNode {
+function OnConfigError({
+ state,
+}: {
+ state: ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined;
+}): VNode {
const { i18n } = useTranslationContext();
if (!state) {
- return <i18n.Translate>checking compatibility with server...</i18n.Translate>
+ return (
+ <i18n.Translate>checking compatibility with server...</i18n.Translate>
+ );
}
switch (state.type) {
case "error": {
- return <NotificationCard
- notification={{
- message: i18n.str`Contacting the server failed`,
- description: state.error.message,
- details: JSON.stringify(state.error.errorDetail, undefined, 2),
- type: "ERROR",
- }}
- />
+ return (
+ <NotificationCard
+ notification={{
+ message: i18n.str`Contacting the server failed`,
+ description: state.error.message,
+ details: JSON.stringify(state.error.errorDetail, undefined, 2),
+ type: "ERROR",
+ }}
+ />
+ );
}
case "incompatible": {
- return <NotificationCard
- notification={{
- message: i18n.str`The server version is not supported`,
- description: i18n.str`Supported version "${state.supported}", server version "${state.result.version}".`,
- type: "WARN",
- }}
- />
+ return (
+ <NotificationCard
+ notification={{
+ message: i18n.str`The server version is not supported`,
+ description: i18n.str`Supported version "${state.supported}", server version "${state.result.version}".`,
+ type: "WARN",
+ }}
+ />
+ );
}
- default: assertUnreachable(state)
+ default:
+ assertUnreachable(state);
}
}
-const swrCacheEvictor= new class implements CacheEvictor<TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction> {
- async notifySuccess(op: TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction) {
- switch(op) {
+const swrCacheEvictor = new (class
+ implements
+ CacheEvictor<
+ TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction
+ >
+{
+ async notifySuccess(
+ op:
+ | TalerMerchantManagementCacheEviction
+ | TalerMerchantInstanceCacheEviction,
+ ) {
+ switch (op) {
case TalerMerchantManagementCacheEviction.CREATE_INSTANCE: {
- await Promise.all([
- revalidateBackendInstances()
- ])
- return
+ await Promise.all([revalidateBackendInstances()]);
+ return;
}
case TalerMerchantManagementCacheEviction.UPDATE_INSTANCE: {
- await Promise.all([
- revalidateManagedInstanceDetails()
- ])
- return
+ await Promise.all([revalidateManagedInstanceDetails()]);
+ return;
}
- case TalerMerchantManagementCacheEviction.DELETE_INSTANCE:{
- await Promise.all([
- revalidateBackendInstances()
- ])
- return
+ case TalerMerchantManagementCacheEviction.DELETE_INSTANCE: {
+ await Promise.all([revalidateBackendInstances()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.UPDATE_CURRENT_INSTANCE:{
- await Promise.all([
- revalidateInstanceDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.UPDATE_CURRENT_INSTANCE: {
+ await Promise.all([revalidateInstanceDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_CURRENT_INSTANCE:{
- await Promise.all([
- revalidateInstanceDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_CURRENT_INSTANCE: {
+ await Promise.all([revalidateInstanceDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_BANK_ACCOUNT:{
- await Promise.all([
- revalidateInstanceBankAccounts()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_BANK_ACCOUNT: {
+ await Promise.all([revalidateInstanceBankAccounts()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.UPDATE_BANK_ACCOUNT:{
- await Promise.all([
- revalidateBankAccountDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.UPDATE_BANK_ACCOUNT: {
+ await Promise.all([revalidateBankAccountDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_BANK_ACCOUNT:{
- await Promise.all([
- revalidateInstanceBankAccounts()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_BANK_ACCOUNT: {
+ await Promise.all([revalidateInstanceBankAccounts()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_PRODUCT:{
- await Promise.all([
- revalidateInstanceProducts()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_PRODUCT: {
+ await Promise.all([revalidateInstanceProducts()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT:{
- await Promise.all([
- revalidateProductDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT: {
+ await Promise.all([revalidateProductDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_PRODUCT:{
- await Promise.all([
- revalidateInstanceProducts()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_PRODUCT: {
+ await Promise.all([revalidateInstanceProducts()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_TRANSFER:{
- await Promise.all([
- revalidateInstanceTransfers()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_TRANSFER: {
+ await Promise.all([revalidateInstanceTransfers()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_TRANSFER:{
- await Promise.all([
- revalidateInstanceTransfers()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_TRANSFER: {
+ await Promise.all([revalidateInstanceTransfers()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_DEVICE:{
- await Promise.all([
- revalidateInstanceOtpDevices()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_DEVICE: {
+ await Promise.all([revalidateInstanceOtpDevices()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.UPDATE_DEVICE:{
- await Promise.all([
- revalidateOtpDeviceDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.UPDATE_DEVICE: {
+ await Promise.all([revalidateOtpDeviceDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_DEVICE:{
- await Promise.all([
- revalidateInstanceOtpDevices()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_DEVICE: {
+ await Promise.all([revalidateInstanceOtpDevices()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE:{
- await Promise.all([
- revalidateInstanceTemplates()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE: {
+ await Promise.all([revalidateInstanceTemplates()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.UPDATE_TEMPLATE:{
- await Promise.all([
- revalidateTemplateDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.UPDATE_TEMPLATE: {
+ await Promise.all([revalidateTemplateDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_TEMPLATE:{
- await Promise.all([
- revalidateInstanceTemplates()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_TEMPLATE: {
+ await Promise.all([revalidateInstanceTemplates()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK:{
- await Promise.all([
- revalidateInstanceWebhooks()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK: {
+ await Promise.all([revalidateInstanceWebhooks()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.UPDATE_WEBHOOK:{
- await Promise.all([
- revalidateWebhookDetails()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.UPDATE_WEBHOOK: {
+ await Promise.all([revalidateWebhookDetails()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.DELETE_WEBHOOK:{
- await Promise.all([
- revalidateInstanceWebhooks()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.DELETE_WEBHOOK: {
+ await Promise.all([revalidateInstanceWebhooks()]);
+ return;
}
- case TalerMerchantInstanceCacheEviction.CREATE_ORDER:{
- await Promise.all([
- revalidateInstanceOrders()
- ])
- return
+ case TalerMerchantInstanceCacheEviction.CREATE_ORDER: {
+ await Promise.all([revalidateInstanceOrders()]);
+ return;
}
case TalerMerchantInstanceCacheEviction.UPDATE_ORDER: {
- await Promise.all([
- revalidateOrderDetails()
- ])
- return
+ await Promise.all([revalidateOrderDetails()]);
+ return;
}
case TalerMerchantInstanceCacheEviction.DELETE_ORDER: {
- await Promise.all([
- revalidateInstanceOrders()
- ])
- return
+ await Promise.all([revalidateInstanceOrders()]);
+ return;
}
case TalerMerchantInstanceCacheEviction.LAST:
// case TalerMerchantInstanceCacheEviction.CREATE_TOKENFAMILY:{
@@ -351,5 +361,4 @@ const swrCacheEvictor= new class implements CacheEvictor<TalerMerchantManagement
// }
}
}
-
-}
+})();
diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx b/packages/merchant-backoffice-ui/src/Routing.tsx
index 66f352118..665137415 100644
--- a/packages/merchant-backoffice-ui/src/Routing.tsx
+++ b/packages/merchant-backoffice-ui/src/Routing.tsx
@@ -22,12 +22,9 @@
import {
AbsoluteTime,
TalerError,
- TranslatedString
+ TranslatedString,
} from "@gnu-taler/taler-util";
-import {
- urlPattern,
- useTranslationContext
-} from "@gnu-taler/web-util/browser";
+import { urlPattern, useTranslationContext } from "@gnu-taler/web-util/browser";
import { createHashHistory } from "history";
import { Fragment, VNode, h } from "preact";
import { Route, Router, route } from "preact-router";
@@ -168,8 +165,7 @@ export function Routing(_p: Props): VNode {
(AbsoluteTime.isNever(preference.hideMissingAccountUntil) ||
AbsoluteTime.cmp(now, preference.hideMissingAccountUntil) > 1);
- const shouldLogin =
- state.status === "loggedOut" || state.status === "expired";
+ const shouldLogin = state.status === "loggedOut";
// function ServerErrorRedirectTo(to: InstancePaths | AdminPaths) {
// return function ServerErrorRedirectToImpl(
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx b/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
index 76d38db84..11396b88e 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
@@ -23,6 +23,7 @@ import { ComponentChildren, h, VNode } from "preact";
import { InputWithAddon } from "./InputWithAddon.js";
import { InputProps } from "./useField.js";
import { AmountString } from "@gnu-taler/taler-util";
+import { useSessionContext } from "../../context/session.js";
export interface Props<T> extends InputProps<T> {
expand?: boolean;
@@ -43,7 +44,7 @@ export function InputCurrency<T>({
children,
side,
}: Props<keyof T>): VNode {
- const { config } = useMerchantApiContext();
+ const { config } = useSessionContext();
return (
<InputWithAddon<T>
name={name}
diff --git a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
index 2a24dfbe2..dd41b6fbd 100644
--- a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
+++ b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
@@ -33,6 +33,7 @@ import { InputLocation } from "../form/InputLocation.js";
import { InputSelector } from "../form/InputSelector.js";
import { InputToggle } from "../form/InputToggle.js";
import { InputWithAddon } from "../form/InputWithAddon.js";
+import { useSessionContext } from "../../context/session.js";
export function DefaultInstanceFormFields({
readonlyId,
@@ -42,13 +43,13 @@ export function DefaultInstanceFormFields({
showId: boolean;
}): VNode {
const { i18n } = useTranslationContext();
- const { url: backendUrl } = useMerchantApiContext();
+ const { state } = useSessionContext();
return (
<Fragment>
{showId && (
<InputWithAddon<Entity>
name="id"
- addonBefore={new URL("instances/", backendUrl.href).href}
+ addonBefore={new URL("instances/", state.backendUrl.href).href}
readonly={readonlyId}
label={i18n.str`Identifier`}
tooltip={i18n.str`Name of the instance in URLs. The 'default' instance is special in that it is used to administer other instances.`}
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index 9819c1911..2090704d9 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -19,15 +19,12 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import {
- useMerchantApiContext,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
+import { TalerError } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useSessionContext } from "../../context/session.js";
import { useInstanceKYCDetails } from "../../hooks/instance.js";
import { LangSelector } from "./LangSelector.js";
-import { TalerError } from "@gnu-taler/taler-util";
// const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
@@ -38,6 +35,7 @@ interface Props {
export function Sidebar({ mobile }: Props): VNode {
const { i18n } = useTranslationContext();
+ const { state, logOut, config } = useSessionContext();
const kycStatus = useInstanceKYCDetails();
const needKYC =
@@ -45,11 +43,9 @@ export function Sidebar({ mobile }: Props): VNode {
!(kycStatus instanceof TalerError) &&
kycStatus.type === "ok" &&
!!kycStatus.body;
- const { state, logOut } = useSessionContext();
const isLoggedIn = state.status === "loggedIn";
const hasToken = isLoggedIn && state.token !== undefined;
- const { config, url: backendURL } = useMerchantApiContext();
-
+
return (
<aside
class="aside is-placed-left is-expanded"
@@ -195,10 +191,7 @@ export function Sidebar({ mobile }: Props): VNode {
</p>
<ul class="menu-list">
<li>
- <a
- class="has-icon is-state-info is-hoverable"
- href="/interface"
- >
+ <a class="has-icon is-state-info is-hoverable" href="/interface">
<span class="icon">
<i class="mdi mdi-newspaper" />
</span>
@@ -212,9 +205,7 @@ export function Sidebar({ mobile }: Props): VNode {
<span style={{ width: "3rem" }} class="icon">
<i class="mdi mdi-web" />
</span>
- <span class="menu-item-label">
- {backendURL.hostname}
- </span>
+ <span class="menu-item-label">{state.backendUrl.hostname}</span>
</div>
</li>
<li>
diff --git a/packages/merchant-backoffice-ui/src/components/menu/index.tsx b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
index aa955db4e..a35c07ace 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/index.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
@@ -104,7 +104,7 @@ export function Menu(_p: MenuProps): VNode {
? getInstanceTitle(path, state.instance)
: getAdminTitle(path, state.instance);
- const isLoggedIn =state.status === "loggedIn";
+ const isLoggedIn = state.status === "loggedIn";
return (
<WithTitle title={titleWithSubtitle}>
@@ -117,11 +117,9 @@ export function Menu(_p: MenuProps): VNode {
title={titleWithSubtitle}
/>
- {isLoggedIn && (
- <Sidebar mobile={mobileOpen} />
- )}
+ {isLoggedIn && <Sidebar mobile={mobileOpen} />}
- {state.status !== "loggedOut" && state.impersonate !== undefined && (
+ {state.status !== "loggedOut" && state.impersonated && (
<nav
class="level"
style={{
@@ -137,9 +135,8 @@ export function Menu(_p: MenuProps): VNode {
.{" "}
<a
href="#/instances"
- onClick={(e) => {
+ onClick={() => {
deImpersonate();
- e.preventDefault();
}}
>
go back
@@ -228,7 +225,7 @@ export function NotYetReadyAppMenu({ title }: NotYetReadyAppMenuProps): VNode {
useEffect(() => {
document.title = `Taler Backoffice: ${title}`;
}, [title]);
-
+
const isLoggedIn = state.status === "loggedIn";
return (
diff --git a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
index 781d2de2c..c6d687b85 100644
--- a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
+++ b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
@@ -20,13 +20,11 @@
*/
import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util";
-import {
- useMerchantApiContext,
- useTranslationContext
-} from "@gnu-taler/web-util/browser";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h } from "preact";
import { useCallback, useEffect, useState } from "preact/hooks";
import * as yup from "yup";
+import { useSessionContext } from "../../context/session.js";
import {
ProductCreateSchema as createSchema,
ProductUpdateSchema as updateSchema,
@@ -88,7 +86,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) {
);
const submit = useCallback((): Entity | undefined => {
- const stock = (value).stock;
+ const stock = value.stock;
if (!stock) {
value.total_stock = -1;
@@ -116,9 +114,8 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) {
onSubscribe(hasErrors ? undefined : submit);
}, [submit, hasErrors]);
- const { url: backendUrl } = useMerchantApiContext();
const { i18n } = useTranslationContext();
-
+ const { state } = useSessionContext();
return (
<div>
<FormProvider<Entity>
@@ -130,7 +127,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) {
{alreadyExist ? undefined : (
<InputWithAddon<Entity>
name="product_id"
- addonBefore={new URL("product/", backendUrl.href).href}
+ addonBefore={new URL("product/", state.backendUrl.href).href}
label={i18n.str`ID`}
tooltip={i18n.str`product identification to use in URLs (for internal use only)`}
/>
diff --git a/packages/merchant-backoffice-ui/src/context/session.ts b/packages/merchant-backoffice-ui/src/context/session.ts
index 6d01464e0..fb1b7b374 100644
--- a/packages/merchant-backoffice-ui/src/context/session.ts
+++ b/packages/merchant-backoffice-ui/src/context/session.ts
@@ -17,11 +17,10 @@
import {
AccessToken,
Codec,
+ TalerMerchantApi,
buildCodecForObject,
- buildCodecForUnion,
- codecForBoolean,
- codecForConstString,
codecForString,
+ codecForURL,
codecOptional,
} from "@gnu-taler/taler-util";
import {
@@ -29,99 +28,79 @@ import {
useLocalStorage,
useMerchantApiContext,
} from "@gnu-taler/web-util/browser";
+import { ComponentChildren, VNode, createContext, h } from "preact";
+import { useContext, useEffect, useState } from "preact/hooks";
import { mutate } from "swr";
+import { MerchantLib } from "../../../web-util/lib/context/activity.js";
/**
* Has the information to reach and
* authenticate at the bank's backend.
*/
-export type SessionState = LoggedIn | LoggedOut | Expired;
+export type SessionState = LoggedIn | LoggedOut;
interface LoggedIn {
status: "loggedIn";
+
+ // is this instance admin? usually "default" name
isAdmin: boolean;
+
+ // url where all the request will be made
+ // usually this is from where the SPA was loaded
+ // unless it's using impersonate feature
+ backendUrl: URL;
+
+ // instance name
instance: string;
+
+ // session is not the same from where it was loaded
+ impersonated: boolean;
+
+ //instane access token
token: AccessToken | undefined;
- impersonate: Impersonate | undefined;
-}
-interface Impersonate {
- originalInstance: string;
- originalToken: AccessToken | undefined;
- originalBackendUrl: string;
-}
-interface Expired {
- status: "expired";
- isAdmin: boolean;
- instance: string;
- token?: undefined;
- impersonate: Impersonate | undefined;
}
+
interface LoggedOut {
status: "loggedOut";
+ backendUrl: URL;
instance: string;
isAdmin: boolean;
- token?: undefined;
+ token: AccessToken | undefined;
}
-export const codecForSessionStateLoggedIn = (): Codec<LoggedIn> =>
- buildCodecForObject<LoggedIn>()
- .property("status", codecForConstString("loggedIn"))
- .property("instance", codecForString())
- .property("impersonate", codecOptional(codecForImpresonate()))
+interface SavedSession {
+ backendUrl: URL;
+ token: AccessToken | undefined;
+ prevToken: AccessToken | undefined;
+}
+
+export const codecForSessionState = (): Codec<SavedSession> =>
+ buildCodecForObject<SavedSession>()
+ .property("backendUrl", codecForURL())
.property("token", codecOptional(codecForString() as Codec<AccessToken>))
- .property("isAdmin", codecForBoolean())
- .build("SessionState.LoggedIn");
-
-export const codecForSessionStateExpired = (): Codec<Expired> =>
- buildCodecForObject<Expired>()
- .property("status", codecForConstString("expired"))
- .property("instance", codecForString())
- .property("impersonate", codecOptional(codecForImpresonate()))
- .property("isAdmin", codecForBoolean())
- .build("SessionState.Expired");
-
-export const codecForSessionStateLoggedOut = (): Codec<LoggedOut> =>
- buildCodecForObject<LoggedOut>()
- .property("status", codecForConstString("loggedOut"))
- .property("instance", codecForString())
- .property("isAdmin", codecForBoolean())
- .build("SessionState.LoggedOut");
-
-export const codecForImpresonate = (): Codec<Impersonate> =>
- buildCodecForObject<Impersonate>()
- .property("originalInstance", codecForString())
.property(
- "originalToken",
+ "prevToken",
codecOptional(codecForString() as Codec<AccessToken>),
)
- .property("originalBackendUrl", codecForString())
- .build("SessionState.Impersonate");
-
-export const codecForSessionState = (): Codec<SessionState> =>
- buildCodecForUnion<SessionState>()
- .discriminateOn("status")
- .alternative("loggedIn", codecForSessionStateLoggedIn())
- .alternative("loggedOut", codecForSessionStateLoggedOut())
- .alternative("expired", codecForSessionStateExpired())
- .build("SessionState");
+ .build("SavedSession");
function inferInstanceName(url: URL) {
const match = INSTANCE_ID_LOOKUP.exec(url.href);
return !match || !match[1] ? DEFAULT_ADMIN_USERNAME : match[1];
}
-export const defaultState = (url: URL): SessionState => {
- const instance = inferInstanceName(url);
+export const defaultState = (url: URL): SavedSession => {
return {
- status: "loggedIn",
- instance,
- isAdmin: instance === DEFAULT_ADMIN_USERNAME,
+ backendUrl: url,
token: undefined,
- impersonate: undefined,
+ prevToken: undefined,
};
};
export interface SessionStateHandler {
+ lib: MerchantLib;
+ config: TalerMerchantApi.VersionResponse;
+
state: SessionState;
/**
* from every state to logout state
@@ -132,19 +111,15 @@ export interface SessionStateHandler {
*/
deImpersonate(): void;
/**
- * from non-loggedOut state to expired
- */
- expired(): void;
- /**
* from any to loggedIn
* @param info
*/
- logIn(info: { token?: AccessToken }): void;
+ logIn(token: AccessToken | undefined): void;
/**
* from loggedIn to impersonate
* @param info
*/
- impersonate(info: { instance: string; baseUrl: URL, token?: AccessToken }): void;
+ impersonate(baseUrl: URL): void;
}
const SESSION_STATE_KEY = buildStorageKey(
@@ -156,95 +131,116 @@ export const DEFAULT_ADMIN_USERNAME = "default";
export const INSTANCE_ID_LOOKUP = /\/instances\/([^/]*)\/?$/;
-/**
- * Return getters and setters for
- * login credentials and backend's
- * base URL.
- */
-export function useSessionContext(): SessionStateHandler {
- const { url: merchantUrl, changeBackend } = useMerchantApiContext();
+export function cleanAllCache(): void {
+ mutate(() => true, undefined, { revalidate: false });
+}
+const Context = createContext<SessionStateHandler>(undefined!);
+
+export const useSessionContext = (): SessionStateHandler => useContext(Context);
+
+export const SessionContextProvider = ({
+ children,
+ // value,
+}: {
+ // value: MerchantUiSettings;
+ children: ComponentChildren;
+}): VNode => {
+ const {
+ lib: rootLib,
+ config: rootConfig,
+ url: merchantUrl,
+ } = useMerchantApiContext();
+ const [status, setStatus] = useState<"loggedIn" | "loggedOut">("loggedIn");
+ const [currentConfig, setCurrentConfig] =
+ useState<TalerMerchantApi.VersionResponse>();
const { value: state, update } = useLocalStorage(
SESSION_STATE_KEY,
defaultState(merchantUrl),
);
- return {
- state,
+ const currentInstance = inferInstanceName(state.backendUrl);
+
+ let lib: MerchantLib;
+ let config: TalerMerchantApi.VersionResponse;
+ const doingImpersonation = state.backendUrl.href !== merchantUrl.href;
+ if (doingImpersonation) {
+ /**
+ * FIXME: can't impersonate other than local instances
+ */
+ lib = rootLib.subInstanceApi(inferInstanceName(state.backendUrl));
+
+ config = currentConfig ?? rootConfig;
+ } else {
+ lib = rootLib;
+ config = rootConfig;
+ }
+
+ useEffect(() => {
+ // FIXME: handle what happen if the subinstance /config
+ // fails
+ if (!doingImpersonation) return;
+ lib.instance.getConfig().then((resp) => {
+ if (resp.type === "ok") {
+ setCurrentConfig(resp.body);
+ }
+ });
+ }, [state.backendUrl.href]);
+
+ const value: SessionStateHandler = {
+ state: {
+ backendUrl: state.backendUrl,
+ token: state.token,
+ impersonated: doingImpersonation,
+ instance: currentInstance,
+ isAdmin: currentInstance === DEFAULT_ADMIN_USERNAME,
+ status: status,
+ },
+ lib,
+ config,
logOut() {
- const instance = inferInstanceName(merchantUrl);
- const nextState: SessionState = {
- status: "loggedOut",
- instance,
- isAdmin: instance === DEFAULT_ADMIN_USERNAME,
- };
- update(nextState);
+ setStatus("loggedOut");
+ update({
+ backendUrl: merchantUrl,
+ token: undefined,
+ prevToken: undefined,
+ });
+ cleanAllCache();
},
deImpersonate() {
- if (state.status === "loggedOut" || state.status === "expired") {
- // can't impersonate if not loggedin
- return;
- }
- if (state.impersonate === undefined) {
- return;
- }
- const newURL = new URL(`./`, state.impersonate.originalBackendUrl);
- changeBackend(newURL);
- const nextState: SessionState = {
- status: "loggedIn",
- isAdmin: state.impersonate.originalInstance === DEFAULT_ADMIN_USERNAME,
- instance: state.impersonate.originalInstance,
- token: state.impersonate.originalToken,
- impersonate: undefined,
- };
- update(nextState);
- },
- impersonate(info) {
- if (state.status === "loggedOut" || state.status === "expired") {
- // can't impersonate if not loggedin
- return;
- }
- changeBackend(info.baseUrl);
- const nextState: SessionState = {
- status: "loggedIn",
- isAdmin: info.instance === DEFAULT_ADMIN_USERNAME,
- instance: info.instance,
- // FIXME: bank and merchant should have consistent behavior
- token: info.token?.substring("secret-token:".length) as AccessToken,
- impersonate: {
- originalBackendUrl: merchantUrl.href,
- originalToken: state.token,
- originalInstance: state.instance,
- },
- };
- update(nextState);
+ cleanAllCache();
+ update({
+ backendUrl: merchantUrl,
+ token: state.prevToken,
+ prevToken: undefined,
+ });
+ setStatus("loggedIn");
},
- expired() {
- if (state.status === "loggedOut") return;
-
- const nextState: SessionState = {
- ...state,
- status: "expired",
+ impersonate(baseUrl) {
+ /**
+ * FIXME: can't impersonate other than local instances
+ */
+ update({
+ backendUrl: baseUrl,
token: undefined,
- };
- update(nextState);
+ prevToken: state.token,
+ });
+ setStatus("loggedIn");
+ cleanAllCache();
},
- logIn(info) {
- // admin is defined by the username
- const nextState: SessionState = {
- impersonate: undefined,
- ...state,
- status: "loggedIn",
- // FIXME: bank and merchant should have consistent behavior
- token: info.token?.substring("secret-token:".length) as AccessToken,
- // token: info.token,
- };
- update(nextState);
+ logIn(token) {
cleanAllCache();
+ setStatus("loggedIn");
+ update({
+ backendUrl: state.backendUrl,
+ token: token,
+ prevToken: state.prevToken,
+ });
},
};
-}
-export function cleanAllCache(): void {
- mutate(() => true, undefined, { revalidate: false });
-}
+ return h(Context.Provider, {
+ value,
+ children,
+ });
+};
diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts b/packages/merchant-backoffice-ui/src/hooks/bank.ts
index abfaecf68..8857ad839 100644
--- a/packages/merchant-backoffice-ui/src/hooks/bank.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts
@@ -16,14 +16,11 @@
import {
useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useState } from "preact/hooks";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util";
import _useSWR, { SWRHook, mutate } from "swr";
import { useSessionContext } from "../context/session.js";
-import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
-import { buildPaginatedResult } from "./webhooks.js";
const useSWR = _useSWR as unknown as SWRHook;
export interface InstanceBankAccountFilter {
@@ -38,11 +35,11 @@ export function revalidateInstanceBankAccounts() {
}
export function useInstanceBankAccounts() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
// const [offset, setOffset] = useState<string | undefined>();
- async function fetcher([token, bid]: [AccessToken, string]) {
+ async function fetcher([token, _bid]: [AccessToken, string]) {
return await instance.listBankAccounts(token, {
// limit: PAGINATED_LIST_REQUEST,
// offset: bid,
@@ -72,7 +69,7 @@ export function revalidateBankAccountDetails() {
}
export function useBankAccountDetails(h_wire: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([token, wireId]: [AccessToken, string]) {
return await instance.getBankAccountDetails(token, wireId);
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts
index 1fa84c9d9..f5f8893cd 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util";
@@ -33,7 +30,7 @@ export function revalidateInstanceDetails() {
}
export function useInstanceDetails() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([token]: [AccessToken]) {
return await instance.getCurrentInstanceDetails(token);
@@ -58,7 +55,7 @@ export function revalidateInstanceKYCDetails() {
}
export function useInstanceKYCDetails() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([token]: [AccessToken]) {
return await instance.getCurrentIntanceKycStatus(token, {});
@@ -85,7 +82,7 @@ export function revalidateManagedInstanceDetails() {
}
export function useManagedInstanceDetails(instanceId: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([token, instanceId]: [AccessToken, string]) {
return await instance.getInstanceDetails(token, instanceId);
@@ -110,7 +107,7 @@ export function revalidateBackendInstances() {
}
export function useBackendInstances() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([token]: [AccessToken]) {
return await instance.listInstances(token);
diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts b/packages/merchant-backoffice-ui/src/hooks/order.ts
index 79f970ec2..d0513dc40 100644
--- a/packages/merchant-backoffice-ui/src/hooks/order.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/order.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -36,7 +33,7 @@ export function revalidateOrderDetails() {
}
export function useOrderDetails(oderId: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([dId, token]: [string, AccessToken]) {
return await instance.getOrderDetails(token, dId);
@@ -72,7 +69,7 @@ export function useInstanceOrders(
updatePosition: (d: string | undefined) => void = () => { },
) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
// const [offset, setOffset] = useState<string | undefined>(args?.position);
diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts b/packages/merchant-backoffice-ui/src/hooks/otp.ts
index 8438a46b3..41ed89f70 100644
--- a/packages/merchant-backoffice-ui/src/hooks/otp.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util";
@@ -32,11 +29,11 @@ export function revalidateInstanceOtpDevices() {
}
export function useInstanceOtpDevices() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
// const [offset, setOffset] = useState<string | undefined>();
- async function fetcher([token, bid]: [AccessToken, string]) {
+ async function fetcher([token, _bid]: [AccessToken, string]) {
return await instance.listOtpDevices(token, {
// limit: PAGINATED_LIST_REQUEST,
// offset: bid,
@@ -66,7 +63,7 @@ export function revalidateOtpDeviceDetails() {
}
export function useOtpDeviceDetails(deviceId: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([dId, token]: [string, AccessToken]) {
return await instance.getOtpDeviceDetails(token, dId);
diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts b/packages/merchant-backoffice-ui/src/hooks/product.ts
index 7f3504c64..defda5552 100644
--- a/packages/merchant-backoffice-ui/src/hooks/product.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/product.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import { AccessToken, OperationOk, TalerHttpError, TalerMerchantApi, TalerMerchantManagementErrorsByMethod, TalerMerchantManagementResultByMethod, opFixedSuccess } from "@gnu-taler/taler-util";
@@ -40,7 +37,7 @@ export function revalidateInstanceProducts() {
}
export function useInstanceProducts() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
const [offset, setOffset] = useState<number | undefined>();
@@ -89,7 +86,7 @@ export function revalidateProductDetails() {
}
export function useProductDetails(productId: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([pid, token]: [string, AccessToken]) {
return await instance.getProductDetails(token, pid);
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts b/packages/merchant-backoffice-ui/src/hooks/templates.ts
index e0065e284..12d99f3fc 100644
--- a/packages/merchant-backoffice-ui/src/hooks/templates.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
import { useState } from "preact/hooks";
import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
@@ -39,7 +36,7 @@ export function revalidateInstanceTemplates() {
}
export function useInstanceTemplates() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
const [offset, setOffset] = useState<string | undefined>();
@@ -73,7 +70,7 @@ export function revalidateTemplateDetails() {
}
export function useTemplateDetails(templateId: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([tid, token]: [string, AccessToken]) {
return await instance.getTemplateDetails(token, tid);
diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
index 6c2fc1d75..6f77369c2 100644
--- a/packages/merchant-backoffice-ui/src/hooks/transfer.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -43,7 +40,7 @@ export function useInstanceTransfers(
updatePosition: (id: string | undefined) => void = (() => { }),
) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
// const [offset, setOffset] = useState<string | undefined>(args?.position);
diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
index df53c06bc..fe37162aa 100644
--- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
@@ -13,9 +13,6 @@
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 {
- useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -36,11 +33,11 @@ export function revalidateInstanceWebhooks() {
}
export function useInstanceWebhooks() {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
// const [offset, setOffset] = useState<string | undefined>();
- async function fetcher([token, bid]: [AccessToken, string]) {
+ async function fetcher([token, _bid]: [AccessToken, string]) {
return await instance.listWebhooks(token, {
// limit: PAGINATED_LIST_REQUEST,
// offset: bid,
@@ -104,7 +101,7 @@ export function revalidateWebhookDetails() {
}
export function useWebhookDetails(webhookId: string) {
const { state: session } = useSessionContext();
- const { lib: { instance } } = useMerchantApiContext();
+ const { lib: { instance } } = useSessionContext();
async function fetcher([hookId, token]: [string, AccessToken]) {
return await instance.getWebhookDetails(token, hookId);
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
index 731ea8939..4a5ab440b 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
@@ -19,7 +19,11 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Duration, TalerMerchantApi } from "@gnu-taler/taler-util";
+import {
+ Duration,
+ TalerMerchantApi,
+ createAccessToken,
+} from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -33,10 +37,13 @@ import { SetTokenNewInstanceModal } from "../../../components/modal/index.js";
import { INSTANCE_ID_REGEX } from "../../../utils/constants.js";
import { undefinedIfEmpty } from "../../../utils/table.js";
-export type Entity = Omit<Omit<TalerMerchantApi.InstanceConfigurationMessage, "default_pay_delay">, "default_wire_transfer_delay"> & {
+export type Entity = Omit<
+ Omit<TalerMerchantApi.InstanceConfigurationMessage, "default_pay_delay">,
+ "default_wire_transfer_delay"
+> & {
auth_token?: string;
- default_pay_delay: Duration,
- default_wire_transfer_delay: Duration,
+ default_pay_delay: Duration;
+ default_wire_transfer_delay: Duration;
};
interface Props {
@@ -90,10 +97,11 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
default_pay_delay: !value.default_pay_delay
? i18n.str`required`
: !!value.default_wire_transfer_delay &&
- value.default_wire_transfer_delay.d_ms !== "forever" &&
- value.default_pay_delay.d_ms !== "forever" &&
- value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms ?
- i18n.str`pay delay can't be greater than wire transfer delay` : undefined,
+ value.default_wire_transfer_delay.d_ms !== "forever" &&
+ value.default_pay_delay.d_ms !== "forever" &&
+ value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms
+ ? i18n.str`pay delay can't be greater than wire transfer delay`
+ : undefined,
default_wire_transfer_delay: !value.default_wire_transfer_delay
? i18n.str`required`
: undefined,
@@ -112,7 +120,7 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
};
const hasErrors = Object.keys(errors).some(
- (k) => (errors as any)[k] !== undefined,
+ (k) => (errors as Record<string, unknown>)[k] !== undefined,
);
const submit = (): Promise<void> => {
@@ -121,19 +129,26 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
const newToken = newValue.auth_token;
newValue.auth_token = undefined;
- newValue.auth = newToken === null || newToken === undefined
- ? { method: "external" }
- : { method: "token", token: `secret-token:${newToken}` };
+ newValue.auth =
+ newToken === null || newToken === undefined
+ ? { method: "external" }
+ : { method: "token", token: createAccessToken(newToken) };
if (!newValue.address) newValue.address = {};
if (!newValue.jurisdiction) newValue.jurisdiction = {};
// remove above use conversion
// schema.validateSync(value, { abortEarly: false })
- newValue.default_pay_delay = Duration.toTalerProtocolDuration(newValue.default_pay_delay!) as any
- newValue.default_wire_transfer_delay = Duration.toTalerProtocolDuration(newValue.default_wire_transfer_delay!) as any
+ newValue.default_pay_delay = Duration.toTalerProtocolDuration(
+ newValue.default_pay_delay!,
+ ) as any;
+ newValue.default_wire_transfer_delay = Duration.toTalerProtocolDuration(
+ newValue.default_wire_transfer_delay!,
+ ) as any;
// delete value.default_pay_delay;
// delete value.default_wire_transfer_delay;
- return onCreate(newValue as any as TalerMerchantApi.InstanceConfigurationMessage);
+ return onCreate(
+ newValue as any as TalerMerchantApi.InstanceConfigurationMessage,
+ );
};
function updateToken(token: string | null) {
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
index 8ee8608a3..b00cfbe7d 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
@@ -19,8 +19,7 @@
*/
import { TalerMerchantApi } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -39,7 +38,7 @@ export type Entity = TalerMerchantApi.InstanceConfigurationMessage;
export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state, logIn } = useSessionContext();
return (
@@ -69,7 +68,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
);
if (result.type === "ok") {
const { token } = result.body;
- logIn({ token });
+ logIn(token);
}
}
onConfirm();
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
index b246bb3e2..cff3c5a02 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
@@ -21,7 +21,6 @@
import { TalerMerchantApi } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
@@ -152,7 +151,7 @@ function Table({
onPurge,
}: TableProps): VNode {
const { i18n } = useTranslationContext();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { impersonate } = useSessionContext();
return (
<div class="table-container">
@@ -203,15 +202,11 @@ function Table({
<td>
<a
href={`#/orders`}
- onClick={async (e) => {
- e.preventDefault();
+ onClick={async (_e) => {
+ // e.preventDefault();
const newInstanceApi = lib.subInstanceApi(i.id);
//not checking /config since this comes from instance list
- impersonate({
- instance: i.id,
- baseUrl: new URL(newInstanceApi.instance.baseUrl),
- token: undefined,
- });
+ impersonate(new URL(newInstanceApi.instance.baseUrl));
}}
>
{i.id}
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
index 7bf64cdbb..5b492e45c 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -33,8 +32,8 @@ import { DeleteModal, PurgeModal } from "../../../components/modal/index.js";
import { useSessionContext } from "../../../context/session.js";
import { useBackendInstances } from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
-import { View } from "./View.js";
import { LoginPage } from "../../login/index.js";
+import { View } from "./View.js";
interface Props {
onCreate: () => void;
@@ -53,7 +52,7 @@ export default function Instances({
useState<TalerMerchantApi.Instance | null>(null);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
if (!result) return <Loading />
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
index fb50ab995..9bab33f6f 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
@@ -32,15 +32,14 @@ import {
} from "@gnu-taler/taler-util";
import {
BrowserFetchHttpLib,
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
import { Notification } from "../../../../utils/types.js";
import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
export type Entity = TalerMerchantApi.AccountAddDetails;
interface Props {
@@ -49,7 +48,7 @@ interface Props {
}
export default function CreateValidator({ onConfirm, onBack }: Props): VNode {
- const { lib: api } = useMerchantApiContext();
+ const { lib: api } = useSessionContext();
const { state } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
index 613cb9614..1eda7382d 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -32,9 +31,9 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { useSessionContext } from "../../../../context/session.js";
import { useInstanceBankAccounts } from "../../../../hooks/bank.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
interface Props {
onCreate: () => void;
@@ -47,7 +46,7 @@ export default function ListOtpDevices({
}: Props): VNode {
const { i18n } = useTranslationContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { lib: api } = useMerchantApiContext();
+ const { lib: api } = useSessionContext();
const { state } = useSessionContext();
const result = useInstanceBankAccounts();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
index 519c9f56a..70942fd55 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -34,8 +33,8 @@ import { useBankAccountDetails } from "../../../../hooks/bank.js";
import { Notification } from "../../../../utils/types.js";
import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
-import { UpdatePage } from "./UpdatePage.js";
import { TestRevenueErrorType, testRevenueAPI } from "../create/index.js";
+import { UpdatePage } from "./UpdatePage.js";
export type Entity = TalerMerchantApi.AccountPatchDetails & WithId;
@@ -49,7 +48,7 @@ export default function UpdateValidator({
onConfirm,
onBack,
}: Props): VNode {
- const { lib: api } = useMerchantApiContext();
+ const { lib: api } = useSessionContext();
const { state } = useSessionContext();
const result = useBankAccountDetails(bid);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
index 76e3bf878..e1a7f87f0 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
@@ -14,7 +14,6 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { HttpStatusCode, TalerError, assertUnreachable } from "@gnu-taler/taler-util";
-import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { ErrorLoadingMerchant } from "../../../components/ErrorLoadingMerchant.js";
@@ -23,8 +22,8 @@ import { DeleteModal } from "../../../components/modal/index.js";
import { useSessionContext } from "../../../context/session.js";
import { useInstanceDetails } from "../../../hooks/instance.js";
import { LoginPage } from "../../login/index.js";
-import { DetailPage } from "./DetailPage.js";
import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
+import { DetailPage } from "./DetailPage.js";
interface Props {
onUpdate: () => void;
@@ -40,7 +39,7 @@ export default function Detail({
const [deleting, setDeleting] = useState<boolean>(false);
// const { deleteInstance } = useInstanceAPI();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
if (!result) return <Loading />
if (result instanceof TalerError) {
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
index 041ec73e7..7be3d23f6 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
@@ -28,8 +28,7 @@ import {
TalerProtocolDuration,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { format, isFuture } from "date-fns";
import { Fragment, VNode, h } from "preact";
@@ -49,6 +48,7 @@ import { InputToggle } from "../../../../components/form/InputToggle.js";
import { InventoryProductForm } from "../../../../components/product/InventoryProductForm.js";
import { NonInventoryProductFrom } from "../../../../components/product/NonInventoryProductForm.js";
import { ProductList } from "../../../../components/product/ProductList.js";
+import { useSessionContext } from "../../../../context/session.js";
import { usePreference } from "../../../../hooks/preference.js";
import { rate } from "../../../../utils/amount.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";
@@ -134,7 +134,7 @@ export function CreatePage({
instanceConfig,
instanceInventory,
}: Props): VNode {
- const { config } = useMerchantApiContext();
+ const { config } = useSessionContext();
const instance_default = with_defaults(instanceConfig, config.currency);
const [value, valueHandler] = useState(instance_default);
const zero = Amounts.zeroOfCurrency(config.currency);
@@ -679,7 +679,6 @@ export function CreatePage({
value.extra &&
value.extra[key] !== undefined
) {
- console.log(value.extra);
delete value.extra[key];
}
valueHandler({
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
index 849711df6..861114014 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
@@ -20,7 +20,6 @@
*/
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
-import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js";
@@ -30,9 +29,9 @@ import { useSessionContext } from "../../../../context/session.js";
import { useInstanceDetails } from "../../../../hooks/instance.js";
import { useInstanceProducts } from "../../../../hooks/product.js";
import { Notification } from "../../../../utils/types.js";
-import { CreatePage } from "./CreatePage.js";
-import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { LoginPage } from "../../../login/index.js";
+import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
+import { CreatePage } from "./CreatePage.js";
export type Entity = {
request: TalerMerchantApi.PostOrderRequest;
@@ -46,7 +45,7 @@ export default function OrderCreate({
onConfirm,
onBack,
}: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { state } = useSessionContext();
const detailsResult = useInstanceDetails();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
index 4aed0cc42..498ea83e3 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
@@ -26,8 +26,7 @@ import {
stringifyRefundUri,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { format, formatDistance } from "date-fns";
import { Fragment, VNode, h } from "preact";
@@ -41,6 +40,7 @@ import { InputGroup } from "../../../../components/form/InputGroup.js";
import { InputLocation } from "../../../../components/form/InputLocation.js";
import { TextField } from "../../../../components/form/TextField.js";
import { ProductList } from "../../../../components/product/ProductList.js";
+import { useSessionContext } from "../../../../context/session.js";
import {
datetimeFormatForSettings,
usePreference,
@@ -430,10 +430,10 @@ function PaidPage({
});
const [value, valueHandler] = useState<Partial<Paid>>(order);
- const { url: backendUrl } = useMerchantApiContext();
+ const { state } = useSessionContext();
const refundurl = stringifyRefundUri({
- merchantBaseUrl: backendUrl.href,
+ merchantBaseUrl: state.backendUrl.href,
orderId: order.contract_terms.order_id,
});
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
index 4785c795d..b28e59b29 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
@@ -19,8 +19,7 @@ import {
assertUnreachable,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -30,9 +29,9 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { useSessionContext } from "../../../../context/session.js";
import { useOrderDetails } from "../../../../hooks/order.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { DetailPage } from "./DetailPage.js";
-import { LoginPage } from "../../../login/index.js";
export interface Props {
oid: string;
@@ -42,7 +41,7 @@ export interface Props {
export default function Update({ oid, onBack }: Props): VNode {
const result = useOrderDetails(oid);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { lib: api } = useMerchantApiContext();
+ const { lib: api } = useSessionContext();
const { state } = useSessionContext();
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
index a9314d005..5ece34409 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
@@ -21,8 +21,7 @@
import { Amounts, TalerMerchantApi } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { format } from "date-fns";
import { VNode, h } from "preact";
@@ -36,6 +35,7 @@ import { InputCurrency } from "../../../../components/form/InputCurrency.js";
import { InputGroup } from "../../../../components/form/InputGroup.js";
import { InputSelector } from "../../../../components/form/InputSelector.js";
import { ConfirmModal } from "../../../../components/modal/index.js";
+import { useSessionContext } from "../../../../context/session.js";
import {
datetimeFormatForSettings,
usePreference,
@@ -258,7 +258,7 @@ export function RefundModal({
order.order_status === "paid" ? order.refund_details : []
).reduce(mergeRefunds, []);
- const { config } = useMerchantApiContext();
+ const { config } = useSessionContext();
const totalRefunded = refunds
.map((r) => r.amount)
.reduce(
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
index af1ffbcc6..8a1f85b1c 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
@@ -27,8 +27,7 @@ import {
assertUnreachable,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -43,10 +42,10 @@ import {
useOrderDetails,
} from "../../../../hooks/order.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { ListPage } from "./ListPage.js";
import { RefundModal } from "./Table.js";
-import { LoginPage } from "../../../login/index.js";
interface Props {
onSelect: (id: string) => void;
@@ -65,7 +64,7 @@ export default function OrderList({ onCreate, onSelect }: Props): VNode {
const result = useInstanceOrders(filter, (d) =>
setFilter({ ...filter, position: d }),
);
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
index 982132057..7723bec81 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
@@ -15,7 +15,7 @@
*/
import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { QR } from "../../../../components/exception/QR.js";
import { CreatedSuccessfully as Template } from "../../../../components/notifications/CreatedSuccessfully.js";
@@ -33,9 +33,8 @@ export function CreatedSuccessfully({
onConfirm,
}: Props): VNode {
const { i18n } = useTranslationContext();
- const { url: backendUrl } = useMerchantApiContext();
const { state } = useSessionContext();
- const issuer = backendUrl.href;
+ const issuer = state.backendUrl.href;
const qrText = `otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key}`;
const qrTextSafe = `otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key.substring(0, 6)}...`;
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
index 864190c9f..8ab0e1f26 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
@@ -20,14 +20,14 @@
*/
import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
import { Notification } from "../../../../utils/types.js";
-import { CreatedSuccessfully } from "./CreatedSuccessfully.js";
import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
+import { CreatedSuccessfully } from "./CreatedSuccessfully.js";
export type Entity = TalerMerchantApi.OtpDeviceAddDetails;
interface Props {
@@ -36,7 +36,7 @@ interface Props {
}
export default function CreateValidator({ onConfirm, onBack }: Props): VNode {
- const { lib: api } = useMerchantApiContext();
+ const { lib: api } = useSessionContext();
const { state } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
index 776823a95..b6a077863 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
@@ -26,7 +26,6 @@ import {
assertUnreachable
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -37,9 +36,9 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { useSessionContext } from "../../../../context/session.js";
import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
interface Props {
onCreate: () => void;
@@ -50,7 +49,7 @@ export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode {
// const [position, setPosition] = useState<string | undefined>(undefined);
const { i18n } = useTranslationContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const result = useInstanceOtpDevices();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
index 5e34e4c8a..99edb95c3 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
@@ -26,7 +26,6 @@ import {
assertUnreachable
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -37,10 +36,10 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { useSessionContext } from "../../../../context/session.js";
import { useOtpDeviceDetails } from "../../../../hooks/otp.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { CreatedSuccessfully } from "../create/CreatedSuccessfully.js";
import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
export type Entity = TalerMerchantApi.OtpDevicePatchDetails & WithId;
@@ -58,7 +57,7 @@ export default function UpdateValidator({
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const [keyUpdated, setKeyUpdated] =
useState<TalerMerchantApi.OtpDeviceAddDetails | null>(null);
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
index e1e3c846a..9de5cae78 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
@@ -20,13 +20,13 @@
*/
import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
import { Notification } from "../../../../utils/types.js";
import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
export type Entity = TalerMerchantApi.ProductAddDetail;
interface Props {
@@ -34,7 +34,7 @@ interface Props {
onConfirm: () => void;
}
export default function CreateProduct({ onConfirm, onBack }: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
index db6cf5376..6ad0d4598 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
@@ -36,9 +35,9 @@ import {
useInstanceProducts
} from "../../../../hooks/product.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { CardTable } from "./Table.js";
-import { LoginPage } from "../../../login/index.js";
interface Props {
onCreate: () => void;
@@ -49,7 +48,7 @@ export default function ProductList({
onSelect,
}: Props): VNode {
const result = useInstanceProducts();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const [deleting, setDeleting] =
useState<TalerMerchantApi.ProductDetail & WithId | null>(null);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
index 06f813b14..5e3e58d80 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -32,9 +31,9 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { useSessionContext } from "../../../../context/session.js";
import { useProductDetails } from "../../../../hooks/product.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
export type Entity = TalerMerchantApi.ProductAddDetail;
interface Props {
@@ -49,7 +48,7 @@ export default function UpdateProduct({
}: Props): VNode {
const result = useProductDetails(pid);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index 139ee7aa3..78d7c83ac 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -28,8 +28,7 @@ import {
TranslatedString,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -46,6 +45,7 @@ import { InputSelector } from "../../../../components/form/InputSelector.js";
import { InputToggle } from "../../../../components/form/InputToggle.js";
import { InputWithAddon } from "../../../../components/form/InputWithAddon.js";
import { TextField } from "../../../../components/form/TextField.js";
+import { useSessionContext } from "../../../../context/session.js";
import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
// type Entity = TalerMerchantApi.TemplateAddDetails & { type: Steps };
@@ -69,7 +69,8 @@ interface Props {
export function CreatePage({ onCreate, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
- const { url: backendUrl, config } = useMerchantApiContext();
+ const { config } = useSessionContext();
+ const {state:session} = useSessionContext();
const devices = useInstanceOtpDevices();
const [state, setState] = useState<Partial<Entity>>({
@@ -175,7 +176,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
<InputWithAddon<Entity>
name="id"
help={
- new URL(`templates/${state.id ?? ""}`, backendUrl.href).href
+ new URL(`templates/${state.id ?? ""}`, session.backendUrl.href).href
}
label={i18n.str`Identifier`}
tooltip={i18n.str`Name of the template in URLs.`}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
index f71ca4794..499c7c859 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
@@ -20,7 +20,7 @@
*/
import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../../components/menu/index.js";
@@ -35,7 +35,7 @@ interface Props {
}
export default function CreateTransfer({ onConfirm, onBack }: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
index f9ab6678b..9e59609c7 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
@@ -36,9 +35,9 @@ import {
useInstanceTemplates
} from "../../../../hooks/templates.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
interface Props {
onCreate: () => void;
@@ -55,7 +54,7 @@ export default function ListTemplates({
}: Props): VNode {
const { i18n } = useTranslationContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const result = useInstanceTemplates();
const [deleting, setDeleting] =
useState<TalerMerchantApi.TemplateEntry | null>(null);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
index cd6b8b45c..7322ca169 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
@@ -19,22 +19,18 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { TalerMerchantApi, stringifyPayTemplateUri } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ TalerMerchantApi,
+ stringifyPayTemplateUri
+} from "@gnu-taler/taler-util";
+import {
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
-import { useState } from "preact/hooks";
import { QR } from "../../../../components/exception/QR.js";
-import {
- FormErrors,
- FormProvider,
-} from "../../../../components/form/FormProvider.js";
-import { Input } from "../../../../components/form/Input.js";
-import { InputCurrency } from "../../../../components/form/InputCurrency.js";
+import { useSessionContext } from "../../../../context/session.js";
-type Entity = TalerMerchantApi.UsingTemplateDetails;
+// type Entity = TalerMerchantApi.UsingTemplateDetails;
interface Props {
contract: TalerMerchantApi.TemplateContractDetails;
@@ -42,9 +38,9 @@ interface Props {
onBack?: () => void;
}
-export function QrPage({ contract, id: templateId, onBack }: Props): VNode {
+export function QrPage({ id: templateId, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
- const { config, url: backendUrl } = useMerchantApiContext();
+ const { state } = useSessionContext();
// const [state, setState] = useState<Partial<Entity>>({
// amount: contract.amount,
@@ -69,7 +65,7 @@ export function QrPage({ contract, id: templateId, onBack }: Props): VNode {
// templateParams.summary = state.summary ?? "";
// }
- const merchantBaseUrl = backendUrl.href;
+ const merchantBaseUrl = state.backendUrl.href;
const payTemplateUri = stringifyPayTemplateUri({
merchantBaseUrl,
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
index a4813c8e9..eedb77f28 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
@@ -28,8 +28,7 @@ import {
TranslatedString,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -45,6 +44,7 @@ import { InputNumber } from "../../../../components/form/InputNumber.js";
import { InputSelector } from "../../../../components/form/InputSelector.js";
import { InputToggle } from "../../../../components/form/InputToggle.js";
import { TextField } from "../../../../components/form/TextField.js";
+import { useSessionContext } from "../../../../context/session.js";
import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
type Entity = {
@@ -67,7 +67,8 @@ interface Props {
export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
- const { url: backendUrl, config } = useMerchantApiContext();
+ const { config } = useSessionContext();
+ const {state:session} = useSessionContext();
const [state, setState] = useState<Partial<Entity>>({
description: template.template_description,
@@ -176,7 +177,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
<div class="level-left">
<div class="level-item">
<span class="is-size-4">
- {new URL(`templates/${template.id}`, backendUrl.href).href}
+ {new URL(`templates/${template.id}`, session.backendUrl.href).href}
</span>
</div>
</div>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
index 9e5099947..6185bd2a9 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -34,9 +33,9 @@ import {
useTemplateDetails,
} from "../../../../hooks/templates.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
export type Entity = TalerMerchantApi.TemplatePatchDetails & WithId;
@@ -50,7 +49,7 @@ export default function UpdateTemplate({
onConfirm,
onBack,
}: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const result = useTemplateDetails(tid);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
index 46d4da8d7..00cb2b827 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -33,9 +32,10 @@ import {
useTemplateDetails
} from "../../../../hooks/templates.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { UsePage } from "./UsePage.js";
-import { LoginPage } from "../../../login/index.js";
+import { useSessionContext } from "../../../../context/session.js";
export type Entity = TalerMerchantApi.TransferInformation;
interface Props {
@@ -49,7 +49,7 @@ export default function TemplateUsePage({
onOrderCreated,
onBack,
}: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const result = useTemplateDetails(tid);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
index 0274d6caa..f75ee89b8 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
@@ -27,7 +27,7 @@ import { FormProvider } from "../../../components/form/FormProvider.js";
import { Input } from "../../../components/form/Input.js";
import { NotificationCard } from "../../../components/menu/index.js";
import { useSessionContext } from "../../../context/session.js";
-import { AccessToken } from "@gnu-taler/taler-util";
+import { AccessToken, createAccessToken } from "@gnu-taler/taler-util";
interface Props {
hasToken: boolean | undefined;
@@ -67,7 +67,7 @@ export function DetailPage({
};
const hasErrors = Object.keys(errors).some(
- (k) => (errors as any)[k] !== undefined,
+ (k) => (errors as Record<string, unknown>)[k] !== undefined,
);
const { state } = useSessionContext();
@@ -76,11 +76,12 @@ export function DetailPage({
async function submitForm() {
if (hasErrors) return;
- const oldToken = hasToken
- ? (form.old_token as AccessToken)
- : undefined;
- const newToken = form.new_token as AccessToken;
- onNewToken(oldToken, `secret-token:${newToken}` as AccessToken);
+ const oldToken =
+ form.old_token !== undefined && hasToken
+ ? createAccessToken(form.old_token)
+ : undefined;
+ const newToken = createAccessToken(form.new_token!);
+ onNewToken(oldToken, newToken);
}
return (
@@ -133,8 +134,7 @@ export function DetailPage({
class="button"
onClick={() => {
if (hasToken) {
- const oldToken = form.old_token as AccessToken;
- onClearToken(oldToken);
+ onClearToken(form.old_token ? createAccessToken(form.old_token) : undefined);
} else {
onClearToken(undefined);
}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
index cc8f7f9e8..c23e5be17 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
@@ -13,8 +13,14 @@
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 { HttpStatusCode, TalerError, assertUnreachable } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
+import {
+ HttpStatusCode,
+ TalerError,
+ assertUnreachable,
+} from "@gnu-taler/taler-util";
+import {
+ useTranslationContext
+} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { ErrorLoadingMerchant } from "../../../components/ErrorLoadingMerchant.js";
@@ -24,43 +30,40 @@ import { useSessionContext } from "../../../context/session.js";
import { useInstanceDetails } from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
import { LoginPage } from "../../login/index.js";
-import { DetailPage } from "./DetailPage.js";
import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
+import { DetailPage } from "./DetailPage.js";
interface Props {
onChange: () => void;
onCancel: () => void;
}
-export default function Token({
- onChange,
- onCancel,
-}: Props): VNode {
+export default function Token({ onChange, onCancel }: Props): VNode {
const { i18n } = useTranslationContext();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { logIn } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const result = useInstanceDetails()
+ const result = useInstanceDetails();
- if (!result) return <Loading />
+ if (!result) return <Loading />;
if (result instanceof TalerError) {
- return <ErrorLoadingMerchant error={result} />
+ return <ErrorLoadingMerchant error={result} />;
}
if (result.type === "fail") {
- switch(result.case) {
+ switch (result.case) {
case HttpStatusCode.Unauthorized: {
- return <LoginPage />
+ return <LoginPage />;
}
case HttpStatusCode.NotFound: {
return <NotFoundPageOrAdminCreate />;
}
default: {
- assertUnreachable(result)
+ assertUnreachable(result);
}
}
}
- const hasToken = result.body.auth.method === "token"
+ const hasToken = result.body.auth.method === "token";
return (
<Fragment>
@@ -70,13 +73,24 @@ export default function Token({
hasToken={hasToken}
onClearToken={async (currentToken): Promise<void> => {
try {
- await lib.instance.updateCurrentInstanceAuthentication(currentToken, {
- method: "external",
- })
- onChange();
+ const resp = await lib.instance.updateCurrentInstanceAuthentication(
+ currentToken,
+ {
+ method: "external",
+ },
+ );
+ if (resp.type === "ok") {
+ onChange();
+ } else {
+ return setNotif({
+ message: i18n.str`Failed to clear token`,
+ type: "ERROR",
+ description: resp.detail.hint,
+ });
+ }
} catch (error) {
if (error instanceof Error) {
- setNotif({
+ return setNotif({
message: i18n.str`Failed to clear token`,
type: "ERROR",
description: error.message,
@@ -86,29 +100,45 @@ export default function Token({
}}
onNewToken={async (currentToken, newToken): Promise<void> => {
try {
- await lib.instance.updateCurrentInstanceAuthentication(currentToken, {
- token: newToken,
- method: "token"
- })
- const resp = await lib.authenticate.createAccessTokenBearer(newToken, {
- scope: "write",
- duration: {
- d_us: "forever"
+ {
+ const resp =
+ await lib.instance.updateCurrentInstanceAuthentication(
+ currentToken,
+ {
+ token: newToken,
+ method: "token",
+ },
+ );
+ if (resp.type === "fail") {
+ return setNotif({
+ message: i18n.str`Failed to set new token`,
+ type: "ERROR",
+ description: resp.detail.hint,
+ });
+ }
+ }
+ const resp = await lib.authenticate.createAccessTokenBearer(
+ newToken,
+ {
+ scope: "write",
+ duration: {
+ d_us: "forever",
+ },
+ refreshable: true,
},
- refreshable: true,
- })
+ );
if (resp.type === "ok") {
- logIn({ token: resp.body.token })
- onChange();
+ logIn(resp.body.token);
+ return onChange();
} else {
- setNotif({
+ return setNotif({
message: i18n.str`Failed to set new token`,
type: "ERROR",
});
}
} catch (error) {
if (error instanceof Error) {
- setNotif({
+ return setNotif({
message: i18n.str`Failed to set new token`,
type: "ERROR",
description: error.message,
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
index 27eab97ed..428476337 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
@@ -21,16 +21,15 @@
import { TalerError, TalerMerchantApi } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
import { useInstanceBankAccounts } from "../../../../hooks/bank.js";
import { Notification } from "../../../../utils/types.js";
import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
export type Entity = TalerMerchantApi.TransferInformation;
interface Props {
@@ -39,7 +38,7 @@ interface Props {
}
export default function CreateTransfer({ onConfirm, onBack }: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
index 4afc400f8..9da7f7efb 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
@@ -15,7 +15,6 @@
*/
import { HttpStatusCode, TalerError, TalerMerchantApi, TalerMerchantInstanceHttpClient, TalerMerchantManagementResultByMethod, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -30,8 +29,8 @@ import {
} from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
import { LoginPage } from "../../login/index.js";
-import { UpdatePage } from "./UpdatePage.js";
import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
+import { UpdatePage } from "./UpdatePage.js";
export interface Props {
onBack: () => void;
@@ -44,14 +43,14 @@ export interface Props {
}
export default function Update(props: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const updateInstance = lib.instance.updateCurrentInstance.bind(lib.instance)
const result = useInstanceDetails();
return CommonUpdate(props, result, updateInstance,);
}
export function AdminUpdate(props: Props & { instanceId: string }): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const t = lib.subInstanceApi(props.instanceId).instance;
const updateInstance = t.updateCurrentInstance.bind(t)
const result = useManagedInstanceDetails(props.instanceId);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
index e4d260b04..70f246ff1 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
@@ -19,14 +19,14 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { TalerMerchantApi } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
import { Notification } from "../../../../utils/types.js";
import { CreatePage } from "./CreatePage.js";
-import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useSessionContext } from "../../../../context/session.js";
export type Entity = TalerMerchantApi.WebhookAddDetails;
interface Props {
@@ -37,7 +37,7 @@ interface Props {
export default function CreateWebhook({ onConfirm, onBack }: Props): VNode {
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
return (
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
index 988a54604..789b8d73b 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
@@ -26,8 +26,7 @@ import {
assertUnreachable,
} from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -37,9 +36,9 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { useSessionContext } from "../../../../context/session.js";
import { useInstanceWebhooks } from "../../../../hooks/webhooks.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
interface Props {
onCreate: () => void;
@@ -49,7 +48,7 @@ interface Props {
export default function ListWebhooks({ onCreate, onSelect }: Props): VNode {
const { i18n } = useTranslationContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const result = useInstanceWebhooks();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
index 1253cd9a2..5b2ba7bb9 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
@@ -21,7 +21,6 @@
import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -34,9 +33,9 @@ import {
useWebhookDetails,
} from "../../../../hooks/webhooks.js";
import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
export type Entity = TalerMerchantApi.WebhookPatchDetails & WithId;
@@ -50,7 +49,7 @@ export default function UpdateWebhook({
onConfirm,
onBack,
}: Props): VNode {
- const { lib } = useMerchantApiContext();
+ const { lib } = useSessionContext();
const { state } = useSessionContext();
const result = useWebhookDetails(tid);
const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index 30b5c37bd..272c40b55 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -19,10 +19,9 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { HttpStatusCode } from "@gnu-taler/taler-util";
+import { HttpStatusCode, createAccessToken } from "@gnu-taler/taler-util";
import {
- useMerchantApiContext,
- useTranslationContext,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { ComponentChildren, Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -43,58 +42,19 @@ const tokenRequest = {
export function LoginPage(_p: Props): VNode {
const [token, setToken] = useState("");
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { state, logIn, impersonate } = useSessionContext();
- const { lib } = useMerchantApiContext();
+ const { state, logIn } = useSessionContext();
+ const { lib } = useSessionContext();
const { i18n } = useTranslationContext();
- async function doImpersonateImpl(instanceId: string) {
- const newInstanceApi = lib.subInstanceApi(instanceId);
- const cfg = await newInstanceApi.instance.getConfig();
- if (cfg.type !== "ok") {
- setNotif({
- message: "Could not load the configuration of this instance.",
- description: newInstanceApi.instance.baseUrl,
- type: "ERROR",
- });
- return;
- }
- const result = await newInstanceApi.authenticate.createAccessTokenBearer(
- token,
- tokenRequest,
- );
-
- if (result.type === "ok") {
- const { token } = result.body;
- impersonate({ instance: instanceId, baseUrl: new URL(newInstanceApi.instance.baseUrl), token });
- return;
- } else {
- switch (result.case) {
- case HttpStatusCode.Unauthorized: {
- setNotif({
- message: "Your password is incorrect",
- type: "ERROR",
- });
- return;
- }
- case HttpStatusCode.NotFound: {
- setNotif({
- message: "Your instance not found",
- type: "ERROR",
- });
- return;
- }
- }
- }
- }
async function doLoginImpl() {
const result = await lib.authenticate.createAccessTokenBearer(
- token,
+ createAccessToken(token),
tokenRequest,
);
if (result.type === "ok") {
const { token } = result.body;
- logIn({ token });
+ logIn(token);
return;
} else {
switch (result.case) {
@@ -116,73 +76,6 @@ export function LoginPage(_p: Props): VNode {
}
}
- if (state.status === "loggedIn" && state.impersonate !== undefined) {
- //the user is loggedin but trying to do an impersonation
- return (
- <div class="columns is-centered" style={{ margin: "auto" }}>
- <div class="column is-two-thirds ">
- <div class="modal-card" style={{ width: "100%", margin: 0 }}>
- <header
- class="modal-card-head"
- style={{ border: "1px solid", borderBottom: 0 }}
- >
- <p class="modal-card-title">{i18n.str`Login required`}</p>
- </header>
- <section
- class="modal-card-body"
- style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
- >
- <p>
- <i18n.Translate>
- Need the access token for the instance{" "}
- <b>"{state.instance}"</b>
- </i18n.Translate>
- </p>
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- <i18n.Translate>Access Token</i18n.Translate>
- </label>
- </div>
- <div class="field-body">
- <div class="field">
- <p class="control is-expanded">
- <input
- class="input"
- type="password"
- placeholder={"current access token"}
- name="token"
- onKeyPress={(e) =>
- e.keyCode === 13
- ? doImpersonateImpl(state.instance)
- : null
- }
- value={token}
- onInput={(e): void => setToken(e?.currentTarget.value)}
- />
- </p>
- </div>
- </div>
- </div>
- </section>
- <footer
- class="modal-card-foot "
- style={{
- justifyContent: "flex-end",
- border: "1px solid",
- borderTop: 0,
- }}
- >
- <AsyncButton onClick={() => doImpersonateImpl(state.instance)}>
- <i18n.Translate>Confirm</i18n.Translate>
- </AsyncButton>
- </footer>
- </div>
- </div>
- </div>
- );
- }
-
return (
<Fragment>
<NotificationCard notification={notif} />
diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts
index 2dcde39b9..0f282e123 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -34,6 +34,7 @@ import {
TalerMerchantInstanceHttpClient,
TalerMerchantManagementHttpClient,
TransactionsResponse,
+ createAccessToken,
decodeCrock,
encodeCrock,
generateIban,
@@ -55,7 +56,8 @@ import {
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core";
import {
- downloadExchangeInfo, topupReserveWithBank,
+ downloadExchangeInfo,
+ topupReserveWithBank,
} from "@gnu-taler/taler-wallet-core/dbless";
import { deepStrictEqual } from "assert";
import fs from "fs";
@@ -614,7 +616,10 @@ deploymentCli
},
)
.maybeOption("bankToken", ["--bank-admin-token"], clk.STRING, {
- help: "libeufin bank admin's password if the account creation is restricted",
+ help: "libeufin bank admin's token if the account creation is restricted",
+ })
+ .maybeOption("bankPassword", ["--bank-admin-password"], clk.STRING, {
+ help: "libeufin bank admin's password if the account creation is restricted, it will override --bank-admin-token",
})
.requiredOption("name", ["--legal-name"], clk.STRING, {
help: "legal name of the merchant",
@@ -638,10 +643,13 @@ deploymentCli
help: "if everything worked ok, change the password of the accounts at the end",
})
.action(async (args) => {
- const managementToken = args.provisionBankMerchant
- .merchantToken as AccessToken;
- const bankAdminPassword = args.provisionBankMerchant
- .bankToken as AccessToken;
+ const managementToken = createAccessToken(
+ args.provisionBankMerchant.merchantToken,
+ );
+ const bankAdminPassword = args.provisionBankMerchant.bankPassword;
+ const bankAdminTokenArg = args.provisionBankMerchant.bankToken
+ ? createAccessToken(args.provisionBankMerchant.bankToken)
+ : undefined;
const id = args.provisionBankMerchant.id;
const name = args.provisionBankMerchant.name;
const email = args.provisionBankMerchant.email;
@@ -694,21 +702,48 @@ deploymentCli
return;
}
+ let bankAdminToken: AccessToken | undefined;
+ if (bankAdminPassword) {
+ const adminAuth = new TalerAuthenticationHttpClient(
+ bank.getAuthenticationAPI("admin").href,
+ httpLib,
+ );
+
+ const resp = await adminAuth.createAccessTokenBasic(
+ "admin",
+ bankAdminPassword,
+ {
+ scope: "write",
+ duration: {
+ d_us: 1000 * 1000 * 10, //10 secs
+ },
+ refreshable: false,
+ },
+ );
+ if (resp.type === "fail") {
+ logger.error(`could not get bank admin token from password.`);
+ return;
+ }
+ bankAdminToken = resp.body.access_token;
+ } else {
+ bankAdminToken = bankAdminTokenArg;
+ }
+
/**
* create bank account
*/
let accountPayto: PaytoString;
{
- const resp = await bank.createAccount(bankAdminPassword, {
+ const resp = await bank.createAccount(bankAdminToken, {
name: name,
password: password,
username: id,
contact_data:
email || phone
? {
- email: email,
- phone: phone,
- }
+ email: email,
+ phone: phone,
+ }
: undefined,
});
@@ -730,7 +765,7 @@ deploymentCli
address: {},
auth: {
method: "token",
- token: `secret-token:${password}`,
+ token: createAccessToken(password),
},
default_pay_delay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ hours: 1 }),
@@ -762,7 +797,7 @@ deploymentCli
*/
{
const resp = await merchantInstance.addBankAccount(
- password as AccessToken,
+ createAccessToken(password),
{
payto_uri: accountPayto,
credit_facade_url: bank.getRevenueAPI(id).href,
@@ -805,7 +840,7 @@ deploymentCli
{
const resp = await merchantInstance.addTemplate(
- password as AccessToken,
+ createAccessToken(password),
{
template_id: "default",
template_description: "First template",
@@ -840,7 +875,7 @@ deploymentCli
let finalPassword = password;
if (args.provisionBankMerchant.randomPassword) {
- const prevPassword = password as AccessToken;
+ const prevPassword = password;
const randomPassword = encodeCrock(randomBytes(16));
logger.info("random password: ", randomPassword);
let token: AccessToken;
@@ -885,10 +920,10 @@ deploymentCli
{
const resp = await merchantInstance.updateCurrentInstanceAuthentication(
- prevPassword,
+ createAccessToken(prevPassword),
{
method: "token",
- token: `secret-token:${randomPassword}` as AccessToken,
+ token: createAccessToken(randomPassword),
},
);
if (resp.type === "fail") {
@@ -902,7 +937,7 @@ deploymentCli
{
const resp = await merchantInstance.updateBankAccount(
- randomPassword as AccessToken,
+ createAccessToken(randomPassword),
wireAccount,
{
credit_facade_url: bank.getRevenueAPI(id).href,
@@ -960,17 +995,12 @@ deploymentCli
const httpLib = createPlatformHttpLib({});
const baseUrl = args.provisionMerchantInstance.merchantApiBaseUrl;
const api = new TalerMerchantManagementHttpClient(baseUrl, httpLib);
- const mt = args.provisionMerchantInstance.managementToken;
- const mtWithoutPrefix = mt.startsWith("secret-token:")
- ? mt.substring("secret-token:".length)
- : mt;
- const managementToken = mtWithoutPrefix as AccessToken;
-
- const it = args.provisionMerchantInstance.instanceToken;
- const itWithoutPrefix = it.startsWith("secret-token:")
- ? it.substring("secret-token:".length)
- : it;
- const instanceToken = itWithoutPrefix as AccessToken;
+ const managementToken = createAccessToken(
+ args.provisionMerchantInstance.managementToken,
+ );
+ const instanceToken = createAccessToken(
+ args.provisionMerchantInstance.instanceToken,
+ );
const instanceId = args.provisionMerchantInstance.id;
const instancceName = args.provisionMerchantInstance.name;
const bankURL = args.provisionMerchantInstance.bankURL;
@@ -982,7 +1012,7 @@ deploymentCli
address: {},
auth: {
method: "token",
- token: `secret-token:${instanceToken}`,
+ token: instanceToken,
},
default_pay_delay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ hours: 1 }),
@@ -1011,10 +1041,10 @@ deploymentCli
credit_facade_credentials:
bankUser && bankPassword
? {
- type: "basic",
- username: bankUser,
- password: bankPassword,
- }
+ type: "basic",
+ username: bankUser,
+ password: bankPassword,
+ }
: undefined,
});
if (createAccountResp.type != "ok") {
diff --git a/packages/taler-util/src/codec.ts b/packages/taler-util/src/codec.ts
index 701fc8835..678c3f092 100644
--- a/packages/taler-util/src/codec.ts
+++ b/packages/taler-util/src/codec.ts
@@ -361,6 +361,40 @@ export function codecForStringURL(shouldEndWithSlash?: boolean): Codec<string> {
}
/**
+ * Return a codec for a value that must be a string.
+ */
+export function codecForURL(shouldEndWithSlash?: boolean): Codec<URL> {
+ return {
+ decode(x: any, c?: Context): URL {
+ if (typeof x !== "string") {
+ throw new DecodingError(
+ `expected string at ${renderContext(c)} but got ${typeof x}`,
+ );
+ }
+ if (shouldEndWithSlash && !x.endsWith("/")) {
+ throw new DecodingError(
+ `expected URL string that ends with slash at ${renderContext(
+ c,
+ )} but got ${x}`,
+ );
+ }
+ try {
+ const url = new URL(x);
+ return url;
+ } catch (e) {
+ if (e instanceof Error) {
+ throw new DecodingError(e.message);
+ } else {
+ throw new DecodingError(
+ `expected an URL string at ${renderContext(c)} but got "${x}"`,
+ );
+ }
+ }
+ },
+ };
+}
+
+/**
* Codec that allows any value.
*/
export function codecForAny(): Codec<any> {
diff --git a/packages/taler-util/src/http-client/authentication.ts b/packages/taler-util/src/http-client/authentication.ts
index b8affee7b..8897a2fa0 100644
--- a/packages/taler-util/src/http-client/authentication.ts
+++ b/packages/taler-util/src/http-client/authentication.ts
@@ -92,14 +92,14 @@ export class TalerAuthenticationHttpClient {
* @returns
*/
async createAccessTokenBearer(
- token: string,
+ token: AccessToken,
body: TalerAuthentication.TokenRequest,
) {
const url = new URL(`token`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(token as AccessToken),
+ Authorization: makeBearerTokenAuthHeader(token),
},
body,
});
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts
index 35603264a..94eafb329 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -185,10 +185,24 @@ export interface LoginToken {
}
declare const __ac_token: unique symbol;
+/**
+ * Use `createAccessToken(string)` function to build one.
+ */
export type AccessToken = string & {
[__ac_token]: true;
};
+/**
+ * Create a rfc8959 access token.
+ * Adds secret-token: prefix if there is none.
+ *
+ * @param token
+ * @returns
+ */
+export function createAccessToken(token: string): AccessToken {
+ return (token.startsWith("secret-token:") ? token : `secret-token:${token}`) as AccessToken
+}
+
declare const __officer_signature: unique symbol;
export type OfficerSignature = string & {
[__officer_signature]: true;
@@ -3604,7 +3618,7 @@ export namespace TalerMerchantApi {
// After the auth token has been set (with method "token"),
// the value must be provided in a "Authorization: Bearer $token"
// header.
- token?: string;
+ token?: AccessToken;
}
export interface InstanceReconfigurationMessage {
diff --git a/packages/taler-util/src/http-client/utils.ts b/packages/taler-util/src/http-client/utils.ts
index c579cd852..bf186ce46 100644
--- a/packages/taler-util/src/http-client/utils.ts
+++ b/packages/taler-util/src/http-client/utils.ts
@@ -39,7 +39,7 @@ export function makeBasicAuthHeader(
* @returns
*/
export function makeBearerTokenAuthHeader(token: AccessToken): string {
- return `Bearer secret-token:${token}`;
+ return `Bearer ${token}`;
}
/**
diff --git a/packages/web-util/src/context/activity.ts b/packages/web-util/src/context/activity.ts
index 9a16f6673..422b25909 100644
--- a/packages/web-util/src/context/activity.ts
+++ b/packages/web-util/src/context/activity.ts
@@ -26,7 +26,7 @@ export class ActiviyTracker<Event> {
this.notify = this.notify.bind(this)
this.subscribe = this.subscribe.bind(this)
}
- notify(data: Event) {
+ notify(data: Event): void {
this.observers.forEach((observer) => observer(data))
}
subscribe(func: Listener<Event>): Unsuscriber {
diff --git a/packages/web-util/src/context/merchant-api.ts b/packages/web-util/src/context/merchant-api.ts
index 9998b3aeb..03c95d48e 100644
--- a/packages/web-util/src/context/merchant-api.ts
+++ b/packages/web-util/src/context/merchant-api.ts
@@ -69,7 +69,9 @@ enum VersionHint {
}
type Evictors = {
- management?: CacheEvictor<TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction>;
+ management?: CacheEvictor<
+ TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction
+ >;
};
type ConfigResult<T> =
@@ -81,7 +83,7 @@ export type ConfigResultFail<T> =
| { type: "incompatible"; result: T; supported: string }
| { type: "error"; error: TalerError };
-const CONFIG_FAIL_TRY_AGAIN_MS = 5000
+const CONFIG_FAIL_TRY_AGAIN_MS = 5000;
export const MerchantApiProvider = ({
baseUrl,
@@ -108,7 +110,7 @@ export const MerchantApiProvider = ({
let keepRetrying = true;
async function testConfig(): Promise<void> {
try {
- const config = await getRemoteConfig();
+ const config = await getRemoteConfig();
if (LibtoolVersion.compare(VERSION, config.version)) {
setChecked({ type: "ok", config, hints: [] });
} else {
@@ -122,7 +124,7 @@ export const MerchantApiProvider = ({
if (error instanceof TalerError) {
if (keepRetrying) {
setTimeout(() => {
- testConfig()
+ testConfig();
}, CONFIG_FAIL_TRY_AGAIN_MS);
}
setChecked({ type: "error", error });
@@ -135,7 +137,7 @@ export const MerchantApiProvider = ({
return () => {
// on unload, stop retry
keepRetrying = false;
- }
+ };
}, []);
if (!checked || checked.type !== "ok") {
@@ -183,30 +185,18 @@ function buildMerchantApiClient(
httpLib,
);
- // const instance = (instanceId: string): TalerMerchantInstanceHttpClient => {
- // return new TalerMerchantInstanceHttpClient(
- // management.getSubInstanceAPI(instanceId).href,
- // httpLib,
- // evictors.instance ? evictors.instance(instanceId) : undefined,
- // );
- // }
- // const impersonate = (instanceId: string): TalerAuthenticationHttpClient => {
- // return new TalerAuthenticationHttpClient(
- // instance(instanceId).getAuthenticationAPI().href,
- // httpLib,
- // );
- // }
- const rootUrl = url;
function getSubInstanceAPI(instanceId: string): MerchantLib {
- const newURL = new URL(`instance/${instanceId}/`, rootUrl);
- const api = buildMerchantApiClient(newURL, evictors);
+ const api = buildMerchantApiClient(
+ instance.getSubInstanceAPI(instanceId) as URL,
+ evictors,
+ );
return api.lib;
}
async function getRemoteConfig(): Promise<TalerMerchantApi.VersionResponse> {
const resp = await instance.getConfig();
if (resp.type === "fail") {
- throw TalerError.fromUncheckedDetail(resp.detail)
+ throw TalerError.fromUncheckedDetail(resp.detail);
}
return resp.body;
}