diff options
Diffstat (limited to 'packages/merchant-backoffice-ui')
53 files changed, 189 insertions, 231 deletions
diff --git a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx index cb4442897..2a24dfbe2 100644 --- a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx +++ b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx @@ -20,10 +20,10 @@ */ import { - useTranslationContext + useMerchantApiContext, + useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; -import { useSessionContext } from "../../context/session.js"; import { Entity } from "../../paths/admin/create/CreatePage.js"; import { Input } from "../form/Input.js"; import { InputDuration } from "../form/InputDuration.js"; @@ -42,15 +42,13 @@ export function DefaultInstanceFormFields({ showId: boolean; }): VNode { const { i18n } = useTranslationContext(); - const { - state: { backendUrl }, - } = useSessionContext(); + const { url: backendUrl } = useMerchantApiContext(); return ( <Fragment> {showId && ( <InputWithAddon<Entity> name="id" - addonBefore={new URL("instances/", backendUrl).href} + addonBefore={new URL("instances/", 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 d6a9308bf..9875ce42e 100644 --- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx +++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx @@ -40,12 +40,15 @@ export function Sidebar({ mobile }: Props): VNode { const { i18n } = useTranslationContext(); const kycStatus = useInstanceKYCDetails(); - const needKYC = kycStatus !== undefined && !(kycStatus instanceof TalerError) && kycStatus.type === "ok" && !!kycStatus.body; + const needKYC = + kycStatus !== undefined && + !(kycStatus instanceof TalerError) && + kycStatus.type === "ok" && + !!kycStatus.body; const { state, logOut } = useSessionContext(); const isLoggedIn = state.status === "loggedIn"; const hasToken = isLoggedIn && state.token !== undefined; - const backendURL = state.backendUrl; - const { config } = useMerchantApiContext(); + const { config, url: backendURL } = useMerchantApiContext(); return ( <aside @@ -212,7 +215,7 @@ export function Sidebar({ mobile }: Props): VNode { <i class="mdi mdi-web" /> </span> <span class="menu-item-label"> - {new URL(backendURL).hostname} + {backendURL.hostname} </span> </div> </li> 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<string, unknown>)[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 : ( <InputWithAddon<Entity> 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<LoggedIn> => buildCodecForObject<LoggedIn>() .property("status", codecForConstString("loggedIn")) - .property("backendUrl", codecForString()) .property("instance", codecForString()) .property("impersonate", codecOptional(codecForImpresonate())) .property("token", codecOptional(codecForString() as Codec<AccessToken>)) @@ -79,7 +75,6 @@ export const codecForSessionStateLoggedIn = (): Codec<LoggedIn> => export const codecForSessionStateExpired = (): Codec<Expired> => buildCodecForObject<Expired>() .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<Expired> => export const codecForSessionStateLoggedOut = (): Codec<LoggedOut> => buildCodecForObject<LoggedOut>() .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<string | undefined>(); 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<string | undefined>(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<string | undefined>(); 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<number | undefined>(); 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<ProductWithId | undefined> = 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<string | undefined>(); 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<string | undefined>(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<string | undefined>(); 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<Props>( <MerchantApiProviderTesting value={{ cancelRequest: () => {}, + 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<Props>( <MerchantApiProviderTesting value={{ cancelRequest: () => {}, + 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 ( <div class="table-container"> <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> @@ -198,10 +202,16 @@ function Table({ </td> <td> <a - href={`#/orders?instance=${i.id}`} - onClick={(e) => { - 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 { <CreatePage onBack={onBack} onCreate={(request: Entity) => { - 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} /> </section> ); 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<string[]>([]); @@ -83,10 +75,6 @@ export function CardTable({ onSelect={onSelect} rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} - onLoadMoreAfter={onLoadMoreAfter} - onLoadMoreBefore={onLoadMoreBefore} - hasMoreAfter={hasMoreAfter} - hasMoreBefore={hasMoreBefore} /> ) : ( <EmptyTable /> @@ -103,20 +91,12 @@ interface TableProps { onDelete: (e: Entity) => void; onSelect: (e: Entity) => void; rowSelectionHandler: StateUpdater<string[]>; - 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<PaytoType | "unknown", { parsed: PaytoUri, acc: Entity }[]> = { "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({ } <ListPage devices={result.body} - onLoadMoreBefore={ - result.isFirstPage ? undefined: result.loadFirst - } - onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} + // onLoadMoreBefore={ + // result.isFirstPage ? undefined: result.loadFirst + // } + // onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { 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<Props>( <MerchantApiProviderTesting value={{ cancelRequest: () => { }, + 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({ <CreatePage onBack={onBack} onCreate={(request: TalerMerchantApi.PostOrderRequest) => { - 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<Partial<Paid>>(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 { <JumpToElementById testIfExist={async (order) => { - 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 { <CreatePage onBack={onBack} onCreate={(request: Entity) => { - 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 { <CreatePage onBack={onBack} onCreate={(request: TalerMerchantApi.ProductAddDetail) => { - 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({ <JumpToElementById testIfExist={async (id) => { - 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<void> => { 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<Partial<Entity>>({ @@ -201,7 +199,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { > <InputWithAddon<Entity> 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 { <CreatePage onBack={onBack} onCreate={(request: TalerMerchantApi.TemplateAddDetails) => { - 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({ <JumpToElementById testIfExist={async (id) => { - 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<void> => { 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<Partial<Entity>>({ 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 { <div class="level-left"> <div class="level-item"> <span class="is-size-4"> - {new URL(`templates/${template.otp_id}`,backendUrl).href} + {new URL(`templates/${template.otp_id}`,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 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<void> => { 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<void> => { 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 { <CreatePage onBack={onBack} onCreate={(request: TalerMerchantApi.WebhookAddDetails) => { - 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<Notification | undefined>(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 { > <p> <i18n.Translate> - Need the access token for the instance <b>"{state.instance}"</b> + Need the access token for the instance{" "} + <b>"{state.instance}"</b> </i18n.Translate> </p> <div class="field is-horizontal"> @@ -190,7 +199,9 @@ export function LoginPage(_p: Props): VNode { class="modal-card-body" style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} > - <i18n.Translate>Please enter your access token for <b>"{state.instance}"</b>.</i18n.Translate> + <i18n.Translate> + Please enter your access token for <b>"{state.instance}"</b>. + </i18n.Translate> <div class="field is-horizontal"> <div class="field-label is-normal"> |