From 072ac43b9f69807b8514eb11f8214637561a2573 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 4 Apr 2024 16:24:55 -0300 Subject: fix some API differences including whatwg-url params --- packages/aml-backoffice-ui/src/context/config.ts | 4 +- packages/aml-backoffice-ui/src/pages/Cases.tsx | 398 ++++++++++++--------- packages/bank-ui/src/context/config.ts | 4 +- packages/bank-ui/src/pages/admin/AdminHome.tsx | 10 +- .../instance/DefaultInstanceFormFields.tsx | 10 +- .../src/components/menu/SideBar.tsx | 11 +- .../src/components/product/ProductForm.tsx | 16 +- .../merchant-backoffice-ui/src/context/session.ts | 24 +- packages/merchant-backoffice-ui/src/hooks/bank.ts | 31 +- .../src/hooks/instance.test.ts | 14 +- .../merchant-backoffice-ui/src/hooks/instance.ts | 16 +- .../merchant-backoffice-ui/src/hooks/order.test.ts | 10 +- packages/merchant-backoffice-ui/src/hooks/order.ts | 8 +- packages/merchant-backoffice-ui/src/hooks/otp.ts | 8 +- .../src/hooks/product.test.ts | 8 +- .../merchant-backoffice-ui/src/hooks/product.ts | 12 +- .../merchant-backoffice-ui/src/hooks/templates.ts | 8 +- .../src/hooks/transfer.test.ts | 2 +- .../merchant-backoffice-ui/src/hooks/transfer.ts | 4 +- .../merchant-backoffice-ui/src/hooks/webhooks.ts | 8 +- .../src/paths/admin/create/Create.stories.tsx | 5 +- .../src/paths/admin/create/index.tsx | 2 +- .../src/paths/admin/create/stories.tsx | 1 + .../src/paths/admin/list/TableActive.tsx | 20 +- .../src/paths/admin/list/index.tsx | 4 +- .../src/paths/instance/accounts/create/index.tsx | 2 +- .../src/paths/instance/accounts/list/ListPage.tsx | 22 +- .../src/paths/instance/accounts/list/Table.tsx | 22 +- .../src/paths/instance/accounts/list/index.tsx | 12 +- .../src/paths/instance/accounts/update/index.tsx | 2 +- .../src/paths/instance/details/index.tsx | 2 +- .../src/paths/instance/details/stories.tsx | 1 + .../src/paths/instance/orders/create/index.tsx | 2 +- .../paths/instance/orders/details/DetailPage.tsx | 9 +- .../src/paths/instance/orders/details/index.tsx | 2 +- .../src/paths/instance/orders/list/index.tsx | 6 +- .../otp_devices/create/CreatedSuccessfully.tsx | 8 +- .../paths/instance/otp_devices/create/index.tsx | 2 +- .../src/paths/instance/otp_devices/list/index.tsx | 2 +- .../paths/instance/otp_devices/update/index.tsx | 2 +- .../src/paths/instance/products/create/index.tsx | 2 +- .../src/paths/instance/products/list/index.tsx | 6 +- .../src/paths/instance/products/update/index.tsx | 2 +- .../paths/instance/templates/create/CreatePage.tsx | 8 +- .../src/paths/instance/templates/create/index.tsx | 2 +- .../src/paths/instance/templates/list/index.tsx | 4 +- .../src/paths/instance/templates/qr/QrPage.tsx | 8 +- .../paths/instance/templates/update/UpdatePage.tsx | 9 +- .../src/paths/instance/templates/update/index.tsx | 2 +- .../src/paths/instance/templates/use/index.tsx | 2 +- .../src/paths/instance/token/index.tsx | 4 +- .../src/paths/instance/transfers/create/index.tsx | 2 +- .../src/paths/instance/update/index.tsx | 6 +- .../src/paths/instance/webhooks/create/index.tsx | 2 +- .../src/paths/instance/webhooks/list/index.tsx | 2 +- .../src/paths/instance/webhooks/update/index.tsx | 2 +- .../src/paths/login/index.tsx | 39 +- packages/taler-harness/src/index.ts | 12 + packages/taler-util/src/http-client/bank-core.ts | 8 +- packages/taler-util/src/http-client/exchange.ts | 2 + packages/taler-util/src/http-client/merchant.ts | 4 +- packages/taler-util/src/http-client/types.ts | 24 +- packages/taler-util/src/whatwg-url.ts | 9 +- .../src/wallet/AddExchange/index.ts | 5 +- .../src/wallet/AddExchange/state.ts | 11 +- .../src/wallet/AddExchange/views.tsx | 113 ++++-- packages/web-util/src/context/activity.ts | 5 +- packages/web-util/src/context/bank-api.ts | 47 +-- packages/web-util/src/context/merchant-api.ts | 64 ++-- packages/web-util/src/utils/http-impl.sw.ts | 5 +- 70 files changed, 638 insertions(+), 507 deletions(-) diff --git a/packages/aml-backoffice-ui/src/context/config.ts b/packages/aml-backoffice-ui/src/context/config.ts index 0ea491ca4..7004225eb 100644 --- a/packages/aml-backoffice-ui/src/context/config.ts +++ b/packages/aml-backoffice-ui/src/context/config.ts @@ -65,7 +65,9 @@ export const ExchangeApiProvider = ({ useEffect(() => { api.getConfig() .then((resp) => { - if (api.isCompatible(resp.body.version)) { + if (resp.type === "fail") { + setChecked({ type: "error", error: TalerError.fromUncheckedDetail(resp.detail) }); + }else if (api.isCompatible(resp.body.version)) { setChecked({ type: "ok", config: resp.body }); } else { setChecked({ type: "incompatible", result: resp.body, supported: api.PROTOCOL_VERSION }) diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx b/packages/aml-backoffice-ui/src/pages/Cases.tsx index 88580a4ce..faef0ca54 100644 --- a/packages/aml-backoffice-ui/src/pages/Cases.tsx +++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx @@ -1,168 +1,198 @@ -import { HttpStatusCode, TalerError, TalerExchangeApi, TranslatedString, assertUnreachable } from "@gnu-taler/taler-util"; -import { ErrorLoading, Loading, createNewForm, useTranslationContext } from "@gnu-taler/web-util/browser"; +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ +import { + HttpStatusCode, + TalerError, + TalerExchangeApi, + assertUnreachable +} from "@gnu-taler/taler-util"; +import { + ErrorLoading, + Loading, + createNewForm, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; import { useState } from "preact/hooks"; import { useCases } from "../hooks/useCases.js"; import { Pages } from "../pages.js"; -import { Officer } from "./Officer.js"; import { amlStateConverter } from "../utils/converter.js"; import { AmlExchangeBackend } from "../utils/types.js"; +import { Officer } from "./Officer.js"; -export function CasesUI({ records, filter, onChangeFilter, onFirstPage, onNext }: { onFirstPage?: () => void, onNext?: () => void, filter: AmlExchangeBackend.AmlState, onChangeFilter: (f: AmlExchangeBackend.AmlState) => void, records: TalerExchangeApi.AmlRecord[] }): VNode { +export function CasesUI({ + records, + filter, + onChangeFilter, + onFirstPage, + onNext, +}: { + onFirstPage?: () => void; + onNext?: () => void; + filter: AmlExchangeBackend.AmlState; + onChangeFilter: (f: AmlExchangeBackend.AmlState) => void; + records: TalerExchangeApi.AmlRecord[]; +}): VNode { const { i18n } = useTranslationContext(); const form = createNewForm<{ state: AmlExchangeBackend.AmlState }>(); - return
-
-
-

- - Cases - -

-

- - A list of all the account with the status - -

-
-
- { - onChangeFilter(v.state ?? filter); - }} - onSubmit={(v) => { }} - > - - - + return ( +
+
+
+

+ Cases +

+

+ + A list of all the account with the status + +

+
+
+ { + onChangeFilter(v.state ?? filter); + }} + onSubmit={(_v) => {}} + > + + +
-
-
-
- {!records.length ? ( -
empty result
- ) : ( -
- - - - - - - - - - {records.map((r) => { - return ( - - - + + + ); + })} + +
- - Account Id - - - - Status - - - - Threshold - -
- - - {((state: AmlExchangeBackend.AmlState): VNode => { - switch (state) { - case AmlExchangeBackend.AmlState.normal: { - return ( - - Normal - - ); - } - case AmlExchangeBackend.AmlState.pending: { - return ( - - Pending - - ); +
+
+ {!records.length ? ( +
empty result
+ ) : ( +
+ + + + + + + + + + {records.map((r) => { + return ( + + + - - - ); - })} - -
+ Account Id + + Status + + Threshold +
+ + + {((state: AmlExchangeBackend.AmlState): VNode => { + switch (state) { + case AmlExchangeBackend.AmlState.normal: { + return ( + + Normal + + ); + } + case AmlExchangeBackend.AmlState.pending: { + return ( + + Pending + + ); + } + case AmlExchangeBackend.AmlState.frozen: { + return ( + + Frozen + + ); + } } - case AmlExchangeBackend.AmlState.frozen: { - return ( - - Frozen - - ); - } - } - })(r.current_state)} - - {r.threshold} -
- -
- )} + })(r.current_state)} +
+ {r.threshold} +
+ +
+ )} +
-
- + ); } - export function Cases() { - const [stateFilter, setStateFilter] = useState(AmlExchangeBackend.AmlState.pending); + const [stateFilter, setStateFilter] = useState( + AmlExchangeBackend.AmlState.pending, + ); const list = useCases(stateFilter); if (!list) { - return + return ; } if (list instanceof TalerError) { - return + return ; } if (list.data.type === "fail") { @@ -170,34 +200,81 @@ export function Cases() { case HttpStatusCode.Unauthorized: case HttpStatusCode.Forbidden: case HttpStatusCode.NotFound: - case HttpStatusCode.Conflict: return - default: assertUnreachable(list.data) + case HttpStatusCode.Conflict: + return ; + default: + assertUnreachable(list.data); } } - const { records } = list.data.body + const { records } = list.data.body; - return + return ( + + ); } -export const PeopleIcon = () => - - +export const PeopleIcon = () => ( + + + +); -export const HomeIcon = () => - - +export const HomeIcon = () => ( + + + +); -function Pagination({ onFirstPage, onNext }: { onFirstPage?: () => void, onNext?: () => void, }) { - const { i18n } = useTranslationContext() +function Pagination({ + onFirstPage, + onNext, +}: { + onFirstPage?: () => void; + onNext?: () => void; +}) { + const { i18n } = useTranslationContext(); return ( -
diff --git a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx index 468e5f635..781d2de2c 100644 --- a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx +++ b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx @@ -19,13 +19,14 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util"; import { + useMerchantApiContext, 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, @@ -38,7 +39,6 @@ import { InputNumber } from "../form/InputNumber.js"; import { InputStock, Stock } from "../form/InputStock.js"; import { InputTaxes } from "../form/InputTaxes.js"; import { InputWithAddon } from "../form/InputWithAddon.js"; -import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util"; type Entity = TalerMerchantApi.ProductDetail & { product_id: string }; @@ -84,11 +84,11 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { } } const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, + (k) => (errors as Record)[k] !== undefined, ); const submit = useCallback((): Entity | undefined => { - const stock: Stock = (value as any).stock; + const stock = (value).stock; if (!stock) { value.total_stock = -1; @@ -101,7 +101,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { : stock.nextRestock; value.address = stock.address; } - delete (value as any).stock; + delete value.stock; if (typeof value.minimum_age !== "undefined" && value.minimum_age < 1) { delete value.minimum_age; @@ -116,9 +116,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { onSubscribe(hasErrors ? undefined : submit); }, [submit, hasErrors]); - const { - state: { backendUrl }, - } = useSessionContext(); + const { url: backendUrl } = useMerchantApiContext(); const { i18n } = useTranslationContext(); return ( @@ -132,7 +130,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { {alreadyExist ? undefined : ( name="product_id" - addonBefore={new URL("product/", backendUrl).href} + addonBefore={new URL("product/", 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 98cb27400..7a5ef33d7 100644 --- a/packages/merchant-backoffice-ui/src/context/session.ts +++ b/packages/merchant-backoffice-ui/src/context/session.ts @@ -39,7 +39,6 @@ export type SessionState = LoggedIn | LoggedOut | Expired; interface LoggedIn { status: "loggedIn"; - backendUrl: string; isAdmin: boolean; instance: string; token: AccessToken | undefined; @@ -52,7 +51,6 @@ interface Impersonate { } interface Expired { status: "expired"; - backendUrl: string; isAdmin: boolean; instance: string; token?: undefined; @@ -60,7 +58,6 @@ interface Expired { } interface LoggedOut { status: "loggedOut"; - backendUrl: string; instance: string; isAdmin: boolean; token?: undefined; @@ -69,7 +66,6 @@ interface LoggedOut { export const codecForSessionStateLoggedIn = (): Codec => buildCodecForObject() .property("status", codecForConstString("loggedIn")) - .property("backendUrl", codecForString()) .property("instance", codecForString()) .property("impersonate", codecOptional(codecForImpresonate())) .property("token", codecOptional(codecForString() as Codec)) @@ -79,7 +75,6 @@ export const codecForSessionStateLoggedIn = (): Codec => export const codecForSessionStateExpired = (): Codec => buildCodecForObject() .property("status", codecForConstString("expired")) - .property("backendUrl", codecForString()) .property("instance", codecForString()) .property("impersonate", codecOptional(codecForImpresonate())) .property("isAdmin", codecForBoolean()) @@ -88,7 +83,6 @@ export const codecForSessionStateExpired = (): Codec => export const codecForSessionStateLoggedOut = (): Codec => buildCodecForObject() .property("status", codecForConstString("loggedOut")) - .property("backendUrl", codecForString()) .property("instance", codecForString()) .property("isAdmin", codecForBoolean()) .build("SessionState.LoggedOut"); @@ -121,7 +115,6 @@ export const defaultState = (url: URL): SessionState => { return { status: "loggedIn", instance, - backendUrl: url.href, isAdmin: instance === DEFAULT_ADMIN_USERNAME, token: undefined, impersonate: undefined, @@ -151,7 +144,7 @@ export interface SessionStateHandler { * from loggedIn to impersonate * @param info */ - impersonate(info: { instance: string; token?: AccessToken }): void; + impersonate(info: { instance: string; baseUrl: URL, token?: AccessToken }): void; } const SESSION_STATE_KEY = buildStorageKey( @@ -169,20 +162,19 @@ export const INSTANCE_ID_LOOKUP = /\/instances\/([^/]*)\/?$/; * base URL. */ export function useSessionContext(): SessionStateHandler { - const { url } = useMerchantApiContext(); + const { url: merchantUrl, changeBackend } = useMerchantApiContext(); const { value: state, update } = useLocalStorage( SESSION_STATE_KEY, - defaultState(url), + defaultState(merchantUrl), ); return { state, logOut() { - const instance = inferInstanceName(url); + const instance = inferInstanceName(merchantUrl); const nextState: SessionState = { status: "loggedOut", - backendUrl: url.href, instance, isAdmin: instance === DEFAULT_ADMIN_USERNAME, }; @@ -196,9 +188,10 @@ export function useSessionContext(): SessionStateHandler { if (state.impersonate === undefined) { return; } + const newURL = new URL(`/`, state.impersonate.originalBackendUrl); + changeBackend(newURL); const nextState: SessionState = { status: "loggedIn", - backendUrl: state.impersonate.originalBackendUrl, isAdmin: state.impersonate.originalInstance === DEFAULT_ADMIN_USERNAME, instance: state.impersonate.originalInstance, token: state.impersonate.originalToken, @@ -211,16 +204,15 @@ export function useSessionContext(): SessionStateHandler { // can't impersonate if not loggedin return; } + changeBackend(info.baseUrl); const nextState: SessionState = { status: "loggedIn", - backendUrl: new URL(`instances/${info.instance}`, state.backendUrl) - .href, 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: state.backendUrl, + originalBackendUrl: merchantUrl.href, originalToken: state.token, originalInstance: state.instance, }, diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts b/packages/merchant-backoffice-ui/src/hooks/bank.ts index e1f2638ed..513314f17 100644 --- a/packages/merchant-backoffice-ui/src/hooks/bank.ts +++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts @@ -17,7 +17,6 @@ import { useMerchantApiContext } from "@gnu-taler/web-util/browser"; import { useState } from "preact/hooks"; -import { PAGE_SIZE } from "../utils/constants.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util"; @@ -38,12 +37,12 @@ export function revalidateInstanceBankAccounts() { } export function useInstanceBankAccounts() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); const [offset, setOffset] = useState(); async function fetcher([token, bid]: [AccessToken, string]) { - return await management.listBankAccounts(token, { + return await instance.listBankAccounts(token, { limit: 5, offset: bid, order: "dec", @@ -55,28 +54,6 @@ export function useInstanceBankAccounts() { TalerHttpError >([session.token, offset, "listBankAccounts"], fetcher); - const isLastPage = - data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE; - const isFirstPage = !offset; - - const result = - data && data.type == "ok" ? structuredClone(data.body.accounts) : []; - if (result.length == PAGE_SIZE + 1) { - result.pop(); - } - const pagination = { - result, - isLastPage, - isFirstPage, - loadNext: () => { - if (!result.length) return; - setOffset(result[result.length - 1].h_wire); - }, - loadFirst: () => { - setOffset(undefined); - }, - }; - if (error) return error; if (data === undefined) return undefined; if (data.type !== "ok") return data; @@ -93,10 +70,10 @@ export function revalidateBankAccountDetails() { } export function useBankAccountDetails(h_wire: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([token, wireId]: [AccessToken, string]) { - return await management.getBankAccountDetails(token, wireId); + return await instance.getBankAccountDetails(token, wireId); } const { data, error } = useSWR< diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts index 64f534a06..f409592b0 100644 --- a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts +++ b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts @@ -20,6 +20,7 @@ */ import { TalerMerchantApi } from "@gnu-taler/taler-util"; +import { useMerchantApiContext } from "@gnu-taler/web-util/browser"; import * as tests from "@gnu-taler/web-util/testing"; import { expect } from "chai"; import { @@ -36,7 +37,6 @@ import { API_UPDATE_CURRENT_INSTANCE_AUTH, API_UPDATE_INSTANCE_BY_ID, } from "./urls.js"; -import { useMerchantApiContext } from "@gnu-taler/web-util/browser"; describe("instance api interaction with details", () => { it("should evict cache when updating an instance", async () => { @@ -81,7 +81,7 @@ describe("instance api interaction with details", () => { name: "other_name", } as TalerMerchantApi.QueryInstancesResponse, }); - api.management.updateCurrentInstance(undefined, { + api.instance.updateCurrentInstance(undefined, { name: "other_name", } as TalerMerchantApi.InstanceReconfigurationMessage); }, @@ -242,7 +242,7 @@ describe("instance api interaction with details", () => { } as TalerMerchantApi.QueryInstancesResponse, }); - api.management.updateCurrentInstanceAuthentication(undefined, { + api.instance.updateCurrentInstanceAuthentication(undefined, { method: "external" }); }, @@ -380,7 +380,7 @@ describe("instance admin api interaction with listing", () => { }, }); - api.management.createInstance(undefined, { + api.instance.createInstance(undefined, { name: "other_name", } as TalerMerchantApi.InstanceConfigurationMessage) }, @@ -470,7 +470,7 @@ describe("instance admin api interaction with listing", () => { }, }); - api.management.deleteInstance(undefined, "the_id"); + api.instance.deleteInstance(undefined, "the_id"); }, ({ query, api }) => { expect(env.assertJustExpectedRequestWereMade()).deep.eq({ @@ -628,7 +628,7 @@ describe("instance admin api interaction with listing", () => { }, }); - api.management.deleteInstance(undefined, "the_id", { purge: true }) + api.instance.deleteInstance(undefined, "the_id", { purge: true }) }, ({ query, api }) => { expect(env.assertJustExpectedRequestWereMade()).deep.eq({ @@ -712,7 +712,7 @@ describe("instance management api interaction with listing", () => { }, }); - api.management.updateCurrentInstance(undefined, { + api.instance.updateCurrentInstance(undefined, { name: "other_name", } as TalerMerchantApi.InstanceConfigurationMessage); }, diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts index cc907bd8f..1fa84c9d9 100644 --- a/packages/merchant-backoffice-ui/src/hooks/instance.ts +++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts @@ -33,10 +33,10 @@ export function revalidateInstanceDetails() { } export function useInstanceDetails() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([token]: [AccessToken]) { - return await management.getCurrentInstanceDetails(token); + return await instance.getCurrentInstanceDetails(token); } const { data, error } = useSWR< @@ -58,10 +58,10 @@ export function revalidateInstanceKYCDetails() { } export function useInstanceKYCDetails() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([token]: [AccessToken]) { - return await management.getCurrentIntanceKycStatus(token, {}); + return await instance.getCurrentIntanceKycStatus(token, {}); } const { data, error } = useSWR< @@ -85,10 +85,10 @@ export function revalidateManagedInstanceDetails() { } export function useManagedInstanceDetails(instanceId: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([token, instanceId]: [AccessToken, string]) { - return await management.getInstanceDetails(token, instanceId); + return await instance.getInstanceDetails(token, instanceId); } const { data, error } = useSWR< @@ -110,10 +110,10 @@ export function revalidateBackendInstances() { } export function useBackendInstances() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([token]: [AccessToken]) { - return await management.listInstances(token); + return await instance.listInstances(token); } const { data, error } = useSWR< diff --git a/packages/merchant-backoffice-ui/src/hooks/order.test.ts b/packages/merchant-backoffice-ui/src/hooks/order.test.ts index 243415bdd..1aa2fcf0a 100644 --- a/packages/merchant-backoffice-ui/src/hooks/order.test.ts +++ b/packages/merchant-backoffice-ui/src/hooks/order.test.ts @@ -86,7 +86,7 @@ describe("order api interaction with listing", () => { }, }); - api.management.createOrder(undefined, { + api.instance.createOrder(undefined, { order: { amount: "ARS:12" as AmountString, summary: "pay me" }, }) }, @@ -171,7 +171,7 @@ describe("order api interaction with listing", () => { }, }); - api.management.addRefund(undefined, "1", { + api.instance.addRefund(undefined, "1", { reason: "double pay", refund: "EUR:1" as AmountString, }) @@ -247,7 +247,7 @@ describe("order api interaction with listing", () => { }, }); - api.management.deleteOrder(undefined, "1") + api.instance.deleteOrder(undefined, "1") }, ({ query, api }) => { expect(env.assertJustExpectedRequestWereMade()).deep.eq({ @@ -316,7 +316,7 @@ describe("order api interaction with details", () => { } as unknown as TalerMerchantApi.CheckPaymentPaidResponse, }); - api.management.addRefund(undefined, "1", { + api.instance.addRefund(undefined, "1", { reason: "double pay", refund: "EUR:1" as AmountString, }) @@ -386,7 +386,7 @@ describe("order api interaction with details", () => { } as unknown as TalerMerchantApi.CheckPaymentPaidResponse, }); - api.management.forgetOrder(undefined, "1", { + api.instance.forgetOrder(undefined, "1", { fields: ["$.summary"], }) }, diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts b/packages/merchant-backoffice-ui/src/hooks/order.ts index 47ddf1c38..b1805f6e3 100644 --- a/packages/merchant-backoffice-ui/src/hooks/order.ts +++ b/packages/merchant-backoffice-ui/src/hooks/order.ts @@ -36,10 +36,10 @@ export function revalidateOrderDetails() { } export function useOrderDetails(oderId: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([dId, token]: [string, AccessToken]) { - return await management.getOrderDetails(token, dId); + return await instance.getOrderDetails(token, dId); } const { data, error } = useSWR< @@ -65,12 +65,12 @@ export function useInstanceOrders( updatePosition: (d: string | undefined) => void = () => { }, ) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); // const [offset, setOffset] = useState(args?.position); async function fetcher([token, o, p, r, w, d]: [AccessToken, string, boolean, boolean, boolean, AbsoluteTime]) { - return await management.listOrders(token, { + return await instance.listOrders(token, { limit: PAGE_SIZE, offset: o, order: "dec", diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts b/packages/merchant-backoffice-ui/src/hooks/otp.ts index 69e4a0f4f..898a27a69 100644 --- a/packages/merchant-backoffice-ui/src/hooks/otp.ts +++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts @@ -35,12 +35,12 @@ export function revalidateInstanceOtpDevices() { } export function useInstanceOtpDevices() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); const [offset, setOffset] = useState(); async function fetcher([token, bid]: [AccessToken, string]) { - return await management.listOtpDevices(token, { + return await instance.listOtpDevices(token, { limit: PAGE_SIZE, offset: bid, order: "dec", @@ -68,10 +68,10 @@ export function revalidateOtpDeviceDetails() { } export function useOtpDeviceDetails(deviceId: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([dId, token]: [string, AccessToken]) { - return await management.getOtpDeviceDetails(token, dId); + return await instance.getOtpDeviceDetails(token, dId); } const { data, error } = useSWR< diff --git a/packages/merchant-backoffice-ui/src/hooks/product.test.ts b/packages/merchant-backoffice-ui/src/hooks/product.test.ts index 1be00201a..39281241c 100644 --- a/packages/merchant-backoffice-ui/src/hooks/product.test.ts +++ b/packages/merchant-backoffice-ui/src/hooks/product.test.ts @@ -99,7 +99,7 @@ describe("product api interaction with listing", () => { } as TalerMerchantApi.ProductDetail, }); - api.management.addProduct(undefined, { + api.instance.addProduct(undefined, { price: "ARS:23", } as any); }, @@ -187,7 +187,7 @@ describe("product api interaction with listing", () => { } as TalerMerchantApi.ProductDetail, }); - api.management.updateProduct(undefined, "1234", { + api.instance.updateProduct(undefined, "1234", { price: "ARS:13", } as any); }, @@ -267,7 +267,7 @@ describe("product api interaction with listing", () => { price: "ARS:12", } as TalerMerchantApi.ProductDetail, }); - api.management.deleteProduct(undefined, "2345"); + api.instance.deleteProduct(undefined, "2345"); }, ({ query, api }) => { expect(env.assertJustExpectedRequestWereMade()).deep.eq({ @@ -337,7 +337,7 @@ describe("product api interaction with details", () => { } as TalerMerchantApi.ProductDetail, }); - api.management.updateProduct(undefined, "12", { + api.instance.updateProduct(undefined, "12", { description: "other description", } as any); }, diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts b/packages/merchant-backoffice-ui/src/hooks/product.ts index 6721136a5..cfbd4a653 100644 --- a/packages/merchant-backoffice-ui/src/hooks/product.ts +++ b/packages/merchant-backoffice-ui/src/hooks/product.ts @@ -40,14 +40,14 @@ export function revalidateInstanceProducts() { } export function useInstanceProducts() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); const [offset, setOffset] = useState(); async function fetcher([token, bid]: [AccessToken, number]) { - const list = await management.listProducts(token, { + const list = await instance.listProducts(token, { limit: PAGE_SIZE, - offset: String(bid), + offset: bid === undefined ? undefined: String(bid), order: "dec", }); if (list.type !== "ok") { @@ -55,7 +55,7 @@ export function useInstanceProducts() { } const all: Array = await Promise.all( list.body.products.map(async (c) => { - const r = await management.getProductDetails(token, c.product_id); + const r = await instance.getProductDetails(token, c.product_id); if (r.type === "fail") { return undefined; } @@ -89,10 +89,10 @@ export function revalidateProductDetails() { } export function useProductDetails(productId: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([pid, token]: [string, AccessToken]) { - return await management.getProductDetails(token, pid); + return await instance.getProductDetails(token, pid); } const { data, error } = useSWR< diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts b/packages/merchant-backoffice-ui/src/hooks/templates.ts index 10e480b01..dbea93fdf 100644 --- a/packages/merchant-backoffice-ui/src/hooks/templates.ts +++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts @@ -39,12 +39,12 @@ export function revalidateInstanceTemplates() { } export function useInstanceTemplates() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); const [offset, setOffset] = useState(); async function fetcher([token, bid]: [AccessToken, string]) { - return await management.listTemplates(token, { + return await instance.listTemplates(token, { limit: PAGE_SIZE, offset: bid, order: "dec", @@ -73,10 +73,10 @@ export function revalidateProductDetails() { } export function useTemplateDetails(templateId: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([tid, token]: [string, AccessToken]) { - return await management.getTemplateDetails(token, tid); + return await instance.getTemplateDetails(token, tid); } const { data, error } = useSWR< diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts b/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts index b424e9686..d0865d236 100644 --- a/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts +++ b/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts @@ -86,7 +86,7 @@ describe("transfer api interaction with listing", () => { }, }); - api.management.informWireTransfer(undefined, { + api.instance.informWireTransfer(undefined, { wtid: "3", credit_amount: "EUR:1" as AmountString, exchange_url: "exchange.url", diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts b/packages/merchant-backoffice-ui/src/hooks/transfer.ts index 2810a4cba..44068f52d 100644 --- a/packages/merchant-backoffice-ui/src/hooks/transfer.ts +++ b/packages/merchant-backoffice-ui/src/hooks/transfer.ts @@ -43,12 +43,12 @@ export function useInstanceTransfers( updatePosition: (id: string | undefined) => void = (() => { }), ) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); // const [offset, setOffset] = useState(args?.position); async function fetcher([token, o, p, v]: [AccessToken, string, string, boolean]) { - return await management.listWireTransfers(token, { + return await instance.listWireTransfers(token, { paytoURI: p, verified: v, limit: PAGE_SIZE, diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts index 5e2e08bcc..c69db6e80 100644 --- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts +++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts @@ -37,12 +37,12 @@ export function revalidateInstanceWebhooks() { } export function useInstanceWebhooks() { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); const [offset, setOffset] = useState(); async function fetcher([token, bid]: [AccessToken, string]) { - return await management.listWebhooks(token, { + return await instance.listWebhooks(token, { limit: 5, offset: bid, order: "dec", @@ -104,10 +104,10 @@ export function revalidateWebhookDetails() { } export function useWebhookDetails(webhookId: string) { const { state: session } = useSessionContext(); - const { lib: { management } } = useMerchantApiContext(); + const { lib: { instance } } = useMerchantApiContext(); async function fetcher([hookId, token]: [string, AccessToken]) { - return await management.getWebhookDetails(token, hookId); + return await instance.getWebhookDetails(token, hookId); } const { data, error } = useSWR< diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx index 39fdb6bdc..54d947e14 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx @@ -19,9 +19,9 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode, FunctionalComponent } from "preact"; -import { CreatePage as TestedComponent } from "./CreatePage.js"; import { MerchantApiProviderTesting } from "@gnu-taler/web-util/browser"; +import { FunctionalComponent, h } from "preact"; +import { CreatePage as TestedComponent } from "./CreatePage.js"; export default { title: "Pages/Instance/Create", @@ -40,6 +40,7 @@ function createExample( {}, + changeBackend: () => {}, config: { currency: "ARS", version: "1", 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 431015d6f..8ee8608a3 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx @@ -54,7 +54,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode { ) => { if (state.status !== "loggedIn") return; try { - await lib.management.createInstance(state.token, d); + await lib.instance.createInstance(state.token, d); if (d.auth.token) { //if auth has been updated, request a new access token const result = await lib.authenticate.createAccessTokenBearer( diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx index 8166dc739..d4258058b 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx @@ -40,6 +40,7 @@ function createExample( {}, + changeBackend: () => {}, config: { currency: "ARS", version: "1", 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 a03a2659b..923c095d3 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx @@ -20,7 +20,10 @@ */ import { TalerMerchantApi } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { + useMerchantApiContext, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { StateUpdater, useEffect, useState } from "preact/hooks"; import { useSessionContext } from "../../../context/session.js"; @@ -149,7 +152,8 @@ function Table({ onPurge, }: TableProps): VNode { const { i18n } = useTranslationContext(); - const { impersonate } = useSessionContext() + const { lib } = useMerchantApiContext(); + const { impersonate } = useSessionContext(); return (
@@ -198,10 +202,16 @@ function Table({
{ - impersonate({instance: i.id}); + href={`#/orders`} + 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, + }); }} > {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 f26ff8935..7bf64cdbb 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx @@ -91,7 +91,7 @@ export default function Instances({ return; } try { - await lib.management.deleteInstance(state.token, deleting.id); + await lib.instance.deleteInstance(state.token, deleting.id); // pushNotification({message: 'delete_success', type: 'SUCCESS' }) setNotif({ message: i18n.str`Instance "${deleting.name}" (ID: ${deleting.id}) has been deleted`, @@ -118,7 +118,7 @@ export default function Instances({ return; } try { - await lib.management.deleteInstance(state.token, purging.id, { purge: true }); + await lib.instance.deleteInstance(state.token, purging.id, { purge: true }); setNotif({ message: i18n.str`Instance '${purging.name}' (ID: ${purging.id}) has been disabled`, type: "SUCCESS", 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 0ce126b76..3d27b9a1a 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 @@ -46,7 +46,7 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode { { - return api.management.addBankAccount(state.token, request) + return api.instance.addBankAccount(state.token, request) .then(() => { onConfirm() }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx index 50cf0fe70..4ee68cd80 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx @@ -24,12 +24,12 @@ import { h, VNode } from "preact"; import { CardTable } from "./Table.js"; export interface Props { - devices: TalerMerchantApi.BankAccountEntry[]; - onLoadMoreBefore?: () => void; - onLoadMoreAfter?: () => void; + devices: TalerMerchantApi.BankAccountSummaryEntry[]; + // onLoadMoreBefore?: () => void; + // onLoadMoreAfter?: () => void; onCreate: () => void; - onDelete: (e: TalerMerchantApi.BankAccountEntry) => void; - onSelect: (e: TalerMerchantApi.BankAccountEntry) => void; + onDelete: (e: TalerMerchantApi.BankAccountSummaryEntry) => void; + onSelect: (e: TalerMerchantApi.BankAccountSummaryEntry) => void; } export function ListPage({ @@ -37,8 +37,8 @@ export function ListPage({ onCreate, onDelete, onSelect, - onLoadMoreBefore, - onLoadMoreAfter, + // onLoadMoreBefore, + // onLoadMoreAfter, }: Props): VNode { return ( @@ -51,10 +51,10 @@ export function ListPage({ onCreate={onCreate} onDelete={onDelete} onSelect={onSelect} - onLoadMoreBefore={onLoadMoreBefore} - hasMoreBefore={!onLoadMoreBefore} - onLoadMoreAfter={onLoadMoreAfter} - hasMoreAfter={!onLoadMoreAfter} + // onLoadMoreBefore={onLoadMoreBefore} + // hasMoreBefore={!onLoadMoreBefore} + // onLoadMoreAfter={onLoadMoreAfter} + // hasMoreAfter={!onLoadMoreAfter} /> ); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx index 690e3a2fc..efe484402 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx @@ -24,17 +24,13 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { StateUpdater, useState } from "preact/hooks"; -type Entity = TalerMerchantApi.BankAccountEntry; +type Entity = TalerMerchantApi.BankAccountSummaryEntry; interface Props { accounts: Entity[]; onDelete: (e: Entity) => void; onSelect: (e: Entity) => void; onCreate: () => void; - onLoadMoreBefore?: () => void; - hasMoreBefore?: boolean; - hasMoreAfter?: boolean; - onLoadMoreAfter?: () => void; } export function CardTable({ @@ -42,10 +38,6 @@ export function CardTable({ onCreate, onDelete, onSelect, - onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore, }: Props): VNode { const [rowSelection, rowSelectionHandler] = useState([]); @@ -83,10 +75,6 @@ export function CardTable({ onSelect={onSelect} rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} - onLoadMoreAfter={onLoadMoreAfter} - onLoadMoreBefore={onLoadMoreBefore} - hasMoreAfter={hasMoreAfter} - hasMoreBefore={hasMoreBefore} /> ) : ( @@ -103,20 +91,12 @@ interface TableProps { onDelete: (e: Entity) => void; onSelect: (e: Entity) => void; rowSelectionHandler: StateUpdater; - onLoadMoreBefore?: () => void; - hasMoreBefore?: boolean; - hasMoreAfter?: boolean; - onLoadMoreAfter?: () => void; } function Table({ accounts, - onLoadMoreAfter, onDelete, onSelect, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore, }: TableProps): VNode { const { i18n } = useTranslationContext(); const emptyList: Record = { "bitcoin": [], "x-taler-bank": [], "iban": [], "unknown": [], } 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 a9454cd07..ccfab3c45 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 @@ -81,16 +81,16 @@ export default function ListOtpDevices({ } { onSelect(e.h_wire); }} - onDelete={(e: TalerMerchantApi.BankAccountEntry) => { - return api.management.deleteBankAccount(state.token, e.h_wire) + onDelete={(e: TalerMerchantApi.BankAccountSummaryEntry) => { + return api.instance.deleteBankAccount(state.token, e.h_wire) .then(() => setNotif({ message: i18n.str`bank account delete successfully`, 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 97610e96b..6b8af50a9 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 @@ -80,7 +80,7 @@ export default function UpdateValidator({ account={{ ...result.body, id: bid }} onBack={onBack} onUpdate={(data) => { - return api.management.updateBankAccount(state.token, bid, data) + return api.instance.updateBankAccount(state.token, bid, data) .then(onConfirm) .catch((error) => { setNotif({ 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 bb1ee944b..76e3bf878 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx @@ -77,7 +77,7 @@ export default function Detail({ return } try { - await lib.management.deleteCurrentInstance(state.token); + await lib.instance.deleteCurrentInstance(state.token); onDelete(); } catch (error) { //FIXME: show message error diff --git a/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx index 6914b7432..42cb1cb02 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx @@ -40,6 +40,7 @@ function createExample( { }, + changeBackend: () => { }, config: { currency: "ARS", version: "1", 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 f612389fe..849711df6 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 @@ -94,7 +94,7 @@ export default function OrderCreate({ { - lib.management.createOrder(state.token, request) + lib.instance.createOrder(state.token, request) .then((r) => { if (r.type === "ok") { return onConfirm(r.body.order_id) 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 4ed78b002..4afc40285 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 @@ -25,7 +25,7 @@ import { TalerMerchantApi, stringifyRefundUri, } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; import { format, formatDistance } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; @@ -38,7 +38,6 @@ 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, @@ -427,12 +426,10 @@ function PaidPage({ }); const [value, valueHandler] = useState>(order); - const { - state: { backendUrl }, - } = useSessionContext(); + const { url: backendUrl } = useMerchantApiContext(); const refundurl = stringifyRefundUri({ - merchantBaseUrl: backendUrl, + merchantBaseUrl: backendUrl.href, orderId: order.contract_terms.order_id, }); const refundable = 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 b232a146b..4785c795d 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 @@ -84,7 +84,7 @@ export default function Update({ oid, onBack }: Props): VNode { if (state.status !== "loggedIn") { return; } - api.management + api.instance .addRefund(state.token, id, value) .then(() => setNotif({ 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 165ced3dc..217eb998a 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 @@ -110,7 +110,7 @@ export default function OrderList({ onCreate, onSelect }: Props): VNode { { - const resp = await lib.management.getOrderDetails(state.token, order); + const resp = await lib.instance.getOrderDetails(state.token, order); return resp.type === "ok"; }} onSelect={onSelect} @@ -135,7 +135,7 @@ export default function OrderList({ onCreate, onSelect }: Props): VNode { jumpToDate={filter.date} onSelectDate={setNewDate} onCopyURL={async (id) => { - const resp = await lib.management.getOrderDetails(state.token, id); + const resp = await lib.instance.getOrderDetails(state.token, id); if (resp.type === "ok") { if (resp.body.order_status === "unpaid") { copyToClipboard(resp.body.taler_pay_uri); @@ -161,7 +161,7 @@ export default function OrderList({ onCreate, onSelect }: Props): VNode { id={orderToBeRefunded.order_id} onCancel={() => setOrderToBeRefunded(undefined)} onConfirm={(value) => { - lib.management + lib.instance .addRefund(state.token, orderToBeRefunded.order_id, value) .then(() => setNotif({ 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 b1b4a0cf7..982132057 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 { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useMerchantApiContext, 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,11 +33,9 @@ export function CreatedSuccessfully({ onConfirm, }: Props): VNode { const { i18n } = useTranslationContext(); - const { - state: { backendUrl }, - } = useSessionContext(); + const { url: backendUrl } = useMerchantApiContext(); const { state } = useSessionContext(); - const issuer = backendUrl; + const issuer = 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 6ad1295ed..864190c9f 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 @@ -52,7 +52,7 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode { { - return api.management.addOtpDevice(state.token, request) + return api.instance.addOtpDevice(state.token, request) .then((d) => { setCreated(request) }) 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 6b3eded17..324207f59 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 @@ -85,7 +85,7 @@ export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode { onSelect(e.otp_device_id); }} onDelete={(e: TalerMerchantApi.OtpDeviceEntry) => { - return lib.management + return lib.instance .deleteOtpDevice(state.token, e.otp_device_id) .then(() => setNotif({ 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 4dc3ec67f..5e34e4c8a 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 @@ -98,7 +98,7 @@ export default function UpdateValidator({ }} onBack={onBack} onUpdate={async (newInfo) => { - return lib.management + return lib.instance .updateOtpDevice(state.token, vid, newInfo) .then((d) => { if (d.type === "ok") { 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 6cb083025..e1e3c846a 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 @@ -45,7 +45,7 @@ export default function CreateProduct({ onConfirm, onBack }: Props): VNode { { - return lib.management.addProduct(state.token, request) + return lib.instance.addProduct(state.token, request) .then(() => onConfirm()) .catch((error) => { setNotif({ 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 73c221662..dfd633150 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 @@ -81,7 +81,7 @@ export default function ProductList({ { - const resp = await lib.management.getProductDetails(state.token, id); + const resp = await lib.instance.getProductDetails(state.token, id); return resp.type === "ok"; }} onSelect={onSelect} @@ -94,7 +94,7 @@ export default function ProductList({ onCreate={onCreate} onUpdate={async (id, prod) => { try { - await lib.management.updateProduct(state.token, id, prod); + await lib.instance.updateProduct(state.token, id, prod); setNotif({ message: i18n.str`product updated successfully`, type: "SUCCESS", @@ -123,7 +123,7 @@ export default function ProductList({ onCancel={() => setDeleting(null)} onConfirm={async (): Promise => { try { - await lib.management.deleteProduct(state.token, deleting.id); + await lib.instance.deleteProduct(state.token, deleting.id); setNotif({ message: i18n.str`Product "${deleting.description}" (ID: ${deleting.id}) has been deleted`, type: "SUCCESS", 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 08b169610..06f813b14 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 @@ -79,7 +79,7 @@ export default function UpdateProduct({ product={{ ...result.body, product_id: pid }} onBack={onBack} onUpdate={(data) => { - return lib.management.updateProduct(state.token, pid, data) + return lib.instance.updateProduct(state.token, pid, data) .then(onConfirm) .catch((error) => { setNotif({ 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 82c0d0e53..2ba637f44 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,6 +28,7 @@ import { assertUnreachable, } from "@gnu-taler/taler-util"; import { + useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; @@ -44,7 +45,6 @@ import { InputNumber } from "../../../../components/form/InputNumber.js"; import { InputSearchOnList } from "../../../../components/form/InputSearchOnList.js"; import { InputTab } from "../../../../components/form/InputTab.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; -import { useSessionContext } from "../../../../context/session.js"; import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; enum Steps { @@ -73,9 +73,7 @@ interface Props { export function CreatePage({ onCreate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const { - state: { backendUrl }, - } = useSessionContext(); + const { url: backendUrl } = useMerchantApiContext(); const devices = useInstanceOtpDevices(); const [state, setState] = useState>({ @@ -201,7 +199,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { > name="id" - help={new URL(`templates/${state.id ?? ""}`, backendUrl).href} + help={new URL(`templates/${state.id ?? ""}`, 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 d23afb609..f71ca4794 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 @@ -46,7 +46,7 @@ export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { { - return lib.management.addTemplate(state.token, request) + return lib.instance.addTemplate(state.token, request) .then(() => onConfirm()) .catch((error) => { setNotif({ 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 23bc95943..f9ab6678b 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 @@ -85,7 +85,7 @@ export default function ListTemplates({ { - const resp = await lib.management.getTemplateDetails(state.token, id) + const resp = await lib.instance.getTemplateDetails(state.token, id) return resp.type === "ok" }} onSelect={onSelect} @@ -124,7 +124,7 @@ export default function ListTemplates({ onCancel={() => setDeleting(null)} onConfirm={async (): Promise => { try { - await lib.management.deleteTemplate(state.token, deleting.template_id); + await lib.instance.deleteTemplate(state.token, deleting.template_id); setNotif({ message: i18n.str`Template "${deleting.template_description}" (ID: ${deleting.template_id}) has been deleted`, type: "SUCCESS", 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 d48e5e956..0749f45d3 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 @@ -33,7 +33,6 @@ import { } 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; @@ -45,10 +44,7 @@ interface Props { export function QrPage({ contract, id: templateId, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const { - state: { backendUrl }, - } = useSessionContext(); - const { config } = useMerchantApiContext(); + const { config, url: backendUrl } = useMerchantApiContext(); const [state, setState] = useState>({ amount: contract.amount, @@ -73,7 +69,7 @@ export function QrPage({ contract, id: templateId, onBack }: Props): VNode { templateParams.summary = state.summary ?? ""; } - const merchantBaseUrl = backendUrl; + const merchantBaseUrl = 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 cf1c13fc4..e1493a870 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 @@ -27,7 +27,7 @@ import { TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; import { useState } from "preact/hooks"; import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; @@ -41,7 +41,6 @@ import { InputDuration } from "../../../../components/form/InputDuration.js"; import { InputNumber } from "../../../../components/form/InputNumber.js"; import { InputSearchOnList } from "../../../../components/form/InputSearchOnList.js"; import { InputTab } from "../../../../components/form/InputTab.js"; -import { useSessionContext } from "../../../../context/session.js"; import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; enum Steps { @@ -68,9 +67,7 @@ interface Props { export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const { - state: { backendUrl }, - } = useSessionContext(); + const { url: backendUrl } = useMerchantApiContext(); const intialStep = @@ -190,7 +187,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
- {new URL(`templates/${template.otp_id}`,backendUrl).href} + {new URL(`templates/${template.otp_id}`,backendUrl.href).href}
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 5fc8bee93..2c0c358e2 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 @@ -82,7 +82,7 @@ export default function UpdateTemplate({ template={result.body} onBack={onBack} onUpdate={(data) => { - return lib.management.updateTemplate(state.token, tid, data) + return lib.instance.updateTemplate(state.token, tid, data) .then(onConfirm) .catch((error) => { setNotif({ 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 d631cef96..46d4da8d7 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 @@ -83,7 +83,7 @@ export default function TemplateUsePage({ request: TalerMerchantApi.UsingTemplateDetails, ) => { - return lib.management.useTemplateCreateOrder(tid, request) + return lib.instance.useTemplateCreateOrder(tid, request) .then((res) => { if (res.type === "ok") { onOrderCreated(res.body.order_id) 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 768e21325..cc8f7f9e8 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx @@ -70,7 +70,7 @@ export default function Token({ hasToken={hasToken} onClearToken={async (currentToken): Promise => { try { - await lib.management.updateCurrentInstanceAuthentication(currentToken, { + await lib.instance.updateCurrentInstanceAuthentication(currentToken, { method: "external", }) onChange(); @@ -86,7 +86,7 @@ export default function Token({ }} onNewToken={async (currentToken, newToken): Promise => { try { - await lib.management.updateCurrentInstanceAuthentication(currentToken, { + await lib.instance.updateCurrentInstanceAuthentication(currentToken, { token: newToken, method: "token" }) 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 35389f5f5..4a92c1178 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 @@ -56,7 +56,7 @@ export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { onBack={onBack} accounts={accounts} onCreate={(request: TalerMerchantApi.TransferInformation) => { - return lib.management + return lib.instance .informWireTransfer(state.token, request) .then(() => onConfirm()) .catch((error) => { 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 b5319bc2d..4afc400f8 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx @@ -45,15 +45,15 @@ export interface Props { export default function Update(props: Props): VNode { const { lib } = useMerchantApiContext(); - const updateInstance = lib.management.updateCurrentInstance.bind(lib.management) + 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 t = lib.instance(props.instanceId) - const updateInstance = lib.instance(props.instanceId).updateCurrentInstance.bind(t) + const t = lib.subInstanceApi(props.instanceId).instance; + const updateInstance = t.updateCurrentInstance.bind(t) const result = useManagedInstanceDetails(props.instanceId); return CommonUpdate(props, result, updateInstance,); } 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 50c431079..e4d260b04 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 @@ -46,7 +46,7 @@ export default function CreateWebhook({ onConfirm, onBack }: Props): VNode { { - return lib.management.addWebhook(state.token, request) + return lib.instance.addWebhook(state.token, request) .then(() => onConfirm()) .catch((error) => { setNotif({ 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 102aef96e..6c68bc973 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 @@ -84,7 +84,7 @@ export default function ListWebhooks({ onCreate, onSelect }: Props): VNode { onSelect(e.webhook_id); }} onDelete={(e: TalerMerchantApi.WebhookEntry) => { - return lib.management + return lib.instance .deleteWebhook(state.token, e.webhook_id) .then(() => setNotif({ 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 262e5bba4..1253cd9a2 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 @@ -82,7 +82,7 @@ export default function UpdateWebhook({ webhook={{ ...result.body, id: tid }} onBack={onBack} onUpdate={(data) => { - return lib.management.updateWebhook(state.token, tid, data) + return lib.instance.updateWebhook(state.token, tid, data) .then(onConfirm) .catch((error) => { setNotif({ diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx index 86ec9a9e6..30b5c37bd 100644 --- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx @@ -19,9 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { - HttpStatusCode -} from "@gnu-taler/taler-util"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; import { useMerchantApiContext, useTranslationContext, @@ -29,12 +27,10 @@ import { import { ComponentChildren, Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { NotificationCard } from "../../components/menu/index.js"; -import { - useSessionContext -} from "../../context/session.js"; +import { useSessionContext } from "../../context/session.js"; import { Notification } from "../../utils/types.js"; -interface Props { } +interface Props {} const tokenRequest = { scope: "write", @@ -47,18 +43,30 @@ const tokenRequest = { export function LoginPage(_p: Props): VNode { const [token, setToken] = useState(""); const [notif, setNotif] = useState(undefined); - const { state, logIn } = useSessionContext(); + const { state, logIn, impersonate } = useSessionContext(); const { lib } = useMerchantApiContext(); const { i18n } = useTranslationContext(); async function doImpersonateImpl(instanceId: string) { - const result = await lib - .impersonate(instanceId) - .createAccessTokenBearer(token, tokenRequest); + 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; - logIn({ token }); + impersonate({ instance: instanceId, baseUrl: new URL(newInstanceApi.instance.baseUrl), token }); return; } else { switch (result.case) { @@ -126,7 +134,8 @@ export function LoginPage(_p: Props): VNode { >

- Need the access token for the instance "{state.instance}" + Need the access token for the instance{" "} + "{state.instance}"

@@ -190,7 +199,9 @@ export function LoginPage(_p: Props): VNode { class="modal-card-body" style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} > - Please enter your access token for "{state.instance}". + + Please enter your access token for "{state.instance}". +
diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts index 727c3b674..5f2708b85 100644 --- a/packages/taler-harness/src/index.ts +++ b/packages/taler-harness/src/index.ts @@ -653,6 +653,12 @@ deploymentCli const bc = await bank.getConfig() + if (bc.type === "fail") { + logger.error( + `couldn't get bank config. ${bc.detail.hint}`, + ); + return; + } if (!bank.isCompatible(bc.body.version)) { logger.error( `bank server version is not compatible: ${bc.body.version}, client version: ${bank.PROTOCOL_VERSION}`, @@ -660,6 +666,12 @@ deploymentCli return; } const mc = await merchantManager.getConfig() + if (mc.type === "fail") { + logger.error( + `couldn't get merchant config. ${mc.detail.hint}`, + ); + return; + } if (!merchantManager.isCompatible(mc.body.version)) { logger.error( `merchant server version is not compatible: ${mc.body.version}, client version: ${merchantManager.PROTOCOL_VERSION}`, diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts index b89ac8af6..59698a68b 100644 --- a/packages/taler-util/src/http-client/bank-core.ts +++ b/packages/taler-util/src/http-client/bank-core.ts @@ -128,6 +128,8 @@ export class TalerCoreBankHttpClient { switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForCoreBankConfig()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); default: return opUnknownFailure(resp, await readTalerErrorResponse(resp)); } @@ -146,9 +148,9 @@ export class TalerCoreBankHttpClient { body: TalerCorebankApi.RegisterAccountRequest, ) { const url = new URL(`accounts`, this.baseUrl); - const headers: Record = {} + const headers: Record = {}; if (auth) { - headers.Authorization = makeBearerTokenAuthHeader(auth) + headers.Authorization = makeBearerTokenAuthHeader(auth); } const resp = await this.httpLib.fetch(url.href, { method: "POST", @@ -936,7 +938,7 @@ export class TalerCoreBankHttpClient { ); } if (params.date) { - const {t_s: seconds} = AbsoluteTime.toProtocolTimestamp(params.date) + const { t_s: seconds } = AbsoluteTime.toProtocolTimestamp(params.date); if (seconds !== "never") { url.searchParams.set("date_s", String(seconds)); } diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts index befde4d20..ea7f44cf9 100644 --- a/packages/taler-util/src/http-client/exchange.ts +++ b/packages/taler-util/src/http-client/exchange.ts @@ -71,6 +71,8 @@ export class TalerExchangeHttpClient { switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForExchangeConfig()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); default: return opUnknownFailure(resp, await readTalerErrorResponse(resp)); } diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts index 7d80cacb5..cfe3155d1 100644 --- a/packages/taler-util/src/http-client/merchant.ts +++ b/packages/taler-util/src/http-client/merchant.ts @@ -127,6 +127,8 @@ export class TalerMerchantInstanceHttpClient { switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForMerchantConfig()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); default: return opUnknownFailure(resp, await readTalerErrorResponse(resp)); } @@ -1677,7 +1679,7 @@ export class TalerMerchantInstanceHttpClient { }); switch (resp.status) { - case HttpStatusCode.NoContent: + case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForWebhookSummaryResponse()); case HttpStatusCode.Unauthorized: // FIXME: missing in docs return opKnownHttpFailure(resp.status, resp); diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts index 8037b5a16..dd2161deb 100644 --- a/packages/taler-util/src/http-client/types.ts +++ b/packages/taler-util/src/http-client/types.ts @@ -524,17 +524,24 @@ export const codecForAccountAddResponse = export const codecForAccountsSummaryResponse = (): Codec => buildCodecForObject() - .property("accounts", codecForList(codecForBankAccountEntry())) + .property("accounts", codecForList(codecForBankAccountSummaryEntry())) .build("TalerMerchantApi.AccountsSummaryResponse"); +export const codecForBankAccountSummaryEntry = + (): Codec => + buildCodecForObject() + .property("payto_uri", codecForPaytoString()) + .property("h_wire", codecForString()) + .build("TalerMerchantApi.BankAccountSummaryEntry"); + export const codecForBankAccountEntry = (): Codec => buildCodecForObject() .property("payto_uri", codecForPaytoString()) .property("h_wire", codecForString()) .property("salt", codecForString()) - .property("credit_facade_url", codecForURL()) - .property("active", codecForBoolean()) + .property("credit_facade_url", codecOptional(codecForURL())) + .property("active", codecOptional(codecForBoolean())) .build("TalerMerchantApi.BankAccountEntry"); export const codecForInventorySummaryResponse = @@ -3772,7 +3779,14 @@ export namespace TalerMerchantApi { export interface AccountsSummaryResponse { // List of accounts that are known for the instance. - accounts: BankAccountEntry[]; + accounts: BankAccountSummaryEntry[]; + } + export interface BankAccountSummaryEntry { + // payto:// URI of the account. + payto_uri: PaytoString; + + // Hash over the wire details (including over the salt). + h_wire: HashCode; } export interface BankAccountEntry { // payto:// URI of the account. @@ -3790,7 +3804,7 @@ export namespace TalerMerchantApi { // true if this account is active, // false if it is historic. - active: boolean; + active?: boolean; } export interface ProductAddDetail { diff --git a/packages/taler-util/src/whatwg-url.ts b/packages/taler-util/src/whatwg-url.ts index 991528ae6..13abf5397 100644 --- a/packages/taler-util/src/whatwg-url.ts +++ b/packages/taler-util/src/whatwg-url.ts @@ -1908,15 +1908,22 @@ function parseURL( } export class URLImpl { - constructor(url: string, base?: string) { + //Include URL type for "url" and "base" params. + constructor(url: string | URL, base?: string | URL) { let parsedBase = null; if (base !== undefined) { + if (base instanceof URL) { + base = base.href; + } parsedBase = basicURLParse(base); if (parsedBase === null) { throw new TypeError(`Invalid base URL: ${base}`); } } + if (url instanceof URL) { + url = url.href; + } const parsedURL = basicURLParse(url, { baseURL: parsedBase }); if (parsedURL === null) { throw new TypeError(`Invalid URL: ${url}`); diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts index d59501212..3d5a105ec 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts @@ -14,12 +14,12 @@ GNU Taler; see the file COPYING. If not, see */ -import { OperationFailWithBody, OperationOk, OperationResult, TalerExchangeApi } from "@gnu-taler/taler-util"; +import { OperationFailWithBody, OperationOk, TalerExchangeApi } from "@gnu-taler/taler-util"; import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; import { ErrorAlert } from "../../context/alert.js"; import { TextFieldHandler } from "../../mui/handlers.js"; -import { compose, StateViewMap } from "../../utils/index.js"; +import { StateViewMap, compose } from "../../utils/index.js"; import { useComponentState } from "./state.js"; import { ConfirmView, VerifyView } from "./views.js"; @@ -37,6 +37,7 @@ export type State = State.Loading export type CheckExchangeErrors = { "invalid-version": string; "invalid-currency": string; + "not-found": void; "already-active": void; "invalid-protocol": void; } diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts index 5ae0aa8f4..4a04f762a 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts @@ -14,15 +14,15 @@ GNU Taler; see the file COPYING. If not, see */ -import { ExchangeEntryStatus, OperationFailWithBody, OperationOk, TalerExchangeApi, TalerExchangeHttpClient, canonicalizeBaseUrl, opKnownFailureWithBody } from "@gnu-taler/taler-util"; +import { ExchangeEntryStatus, TalerExchangeHttpClient, canonicalizeBaseUrl, opKnownFailureWithBody } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser"; import { useCallback, useEffect, useState } from "preact/hooks"; import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { withSafe } from "../../mui/handlers.js"; import { RecursiveState } from "../../utils/index.js"; import { CheckExchangeErrors, Props, State } from "./index.js"; -import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser"; function urlFromInput(str: string): URL { let result: URL; @@ -83,6 +83,9 @@ export function useComponentState({ onBack, currency, noDebounce }: Props): Recu */ const api = new TalerExchangeHttpClient(baseUrl.href, new BrowserFetchHttpLib() as any); const config = await api.getConfig() + if (config.type === "fail") { + return opKnownFailureWithBody("not-found", undefined) + } if (!api.isCompatible(config.body.version)) { return opKnownFailureWithBody("invalid-version", config.body.version) } @@ -155,7 +158,7 @@ function useDebounce( const [result, setResult] = useState(undefined); const [error, setError] = useState(undefined); - const [handler, setHandler] = useState(undefined); + const [handler, setHandler] = useState(undefined); if (!disabled) { useEffect(() => { @@ -180,7 +183,7 @@ function useDebounce( setResult(undefined); } }, 500); - setHandler(h); + setHandler(h as unknown as number); }, [value, setHandler, onTrigger]); } diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx index 489d7eb3b..21309fd7b 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx @@ -17,13 +17,18 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { ErrorMessage } from "../../components/ErrorMessage.js"; -import { Input, LightText, SubTitle, Title, WarningBox } from "../../components/styled/index.js"; +import { + Input, + LightText, + SubTitle, + Title, + WarningBox, +} from "../../components/styled/index.js"; import { TermsOfService } from "../../components/TermsOfService/index.js"; import { Button } from "../../mui/Button.js"; import { State } from "./index.js"; import { assertUnreachable } from "@gnu-taler/taler-util"; - export function VerifyView({ expectedCurrency, onCancel, @@ -57,40 +62,71 @@ export function VerifyView({ {(() => { if (!result) return; if (result.type == "ok") { - return - - An exchange has been found! Review the information and click next - - + return ( + + + An exchange has been found! Review the information and click + next + + + ); } switch (result.case) { case "already-active": { - return - This exchange is already in your list. - + return ( + + + This exchange is already in your list. + + + ); } case "invalid-protocol": { - return - Only exchange accessible through "http" and "https" are allowed. - + return ( + + + Only exchange accessible through "http" and "https" are + allowed. + + + ); } case "invalid-version": { - return - This exchange protocol version is not supported: "{result.body}". - + return ( + + + This exchange protocol version is not supported: " + {result.body}". + + + ); } case "invalid-currency": { - return - This exchange currency "{result.body}" doesn't match the expected currency {expectedCurrency}. - + return ( + + + This exchange currency "{result.body}" doesn't match + the expected currency {expectedCurrency}. + + + ); + } + case "not-found": { + return ( + + + No exchange found in that URL. + + + ); } default: { - assertUnreachable(result.case) + assertUnreachable(result.case); } } })()}

- + { if (url.onInput) { - url.onInput(e.currentTarget.value) + url.onInput(e.currentTarget.value); } }} /> @@ -138,10 +174,7 @@ export function VerifyView({

- - +