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