diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx index 56f223620..5929b031a 100644 --- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx @@ -19,7 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + useTranslationContext, + HttpError, +} from "@gnu-taler/web-util/lib/index.browser"; import { format } from "date-fns"; import { Fragment, FunctionComponent, h, VNode } from "preact"; import { Route, route, Router } from "preact-router"; @@ -28,7 +31,6 @@ import { Loading } from "./components/exception/loading.js"; import { Menu, NotificationCard } from "./components/menu/index.js"; import { useBackendContext } from "./context/backend.js"; import { InstanceContextProvider } from "./context/instance.js"; -import { HttpError } from "./utils/request.js"; import { useBackendDefaultToken, useBackendInstanceToken, @@ -63,6 +65,7 @@ import InstanceUpdatePage, { import LoginPage from "./paths/login/index.js"; import NotFoundPage from "./paths/notfound/index.js"; import { Notification } from "./utils/types.js"; +import { MerchantBackend } from "./declaration.js"; export enum InstancePaths { // details = '/', @@ -157,7 +160,9 @@ export function InstanceRoutes({ ); function ServerErrorRedirectTo(to: InstancePaths | AdminPaths) { - return function ServerErrorRedirectToImpl(error: HttpError) { + return function ServerErrorRedirectToImpl( + error: HttpError, + ) { setGlobalNotification({ message: i18n.str`The backend reported a problem: HTTP status #${error.status}`, description: i18n.str`Diagnostic from ${error.info?.url} is "${error.message}"`, @@ -551,7 +556,7 @@ function AdminInstanceUpdatePage({ }: { id: string } & InstanceUpdatePageProps): VNode { const [token, changeToken] = useBackendInstanceToken(id); const { updateLoginStatus: changeBackend } = useBackendContext(); - const updateLoginStatus = (url: string, token?: string) => { + const updateLoginStatus = (url: string, token?: string): void => { changeBackend(url); if (token) changeToken(token); }; @@ -566,7 +571,7 @@ function AdminInstanceUpdatePage({ { + onLoadError={(error: HttpError) => { return ( ({ } setSizeError(false); return f[0].arrayBuffer().then((b) => { - const b64 = btoa( + const b64 = window.btoa( new Uint8Array(b).reduce( (data, byte) => data + String.fromCharCode(byte), "", diff --git a/packages/merchant-backoffice-ui/src/context/api.ts b/packages/merchant-backoffice-ui/src/context/api.ts deleted file mode 100644 index 81586bd35..000000000 --- a/packages/merchant-backoffice-ui/src/context/api.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2023 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { ComponentChildren, createContext, h, VNode } from "preact"; -import { useContext } from "preact/hooks"; -import { defaultRequestHandler } from "../utils/request.js"; - -interface Type { - request: typeof defaultRequestHandler; -} - -const Context = createContext({ - request: defaultRequestHandler, -}); - -export const useApiContext = (): Type => useContext(Context); -export const ApiContextProvider = ({ - children, - value, -}: { - value: Type; - children: ComponentChildren; -}): VNode => { - return h(Context.Provider, { value, children }); -}; diff --git a/packages/merchant-backoffice-ui/src/declaration.d.ts b/packages/merchant-backoffice-ui/src/declaration.d.ts index 32e6b44ea..e65835bfd 100644 --- a/packages/merchant-backoffice-ui/src/declaration.d.ts +++ b/packages/merchant-backoffice-ui/src/declaration.d.ts @@ -1355,14 +1355,13 @@ export namespace MerchantBackend { interface UsingTemplateResponse { // After enter the request. The user will be pay with a taler URL. - order_id: string, - token: string, + order_id: string; + token: string; } } namespace Webhooks { interface WebhookAddDetails { - // Webhook ID to use. webhook_id: string; @@ -1380,10 +1379,8 @@ export namespace MerchantBackend { // Body template by the webhook body_template?: string; - } interface WebhookPatchDetails { - // The event of the webhook: why the webhook is used. event_type: string; @@ -1398,25 +1395,19 @@ export namespace MerchantBackend { // Body template by the webhook body_template?: string; - } interface WebhookSummaryResponse { - // List of webhooks that are present in our backend. webhooks: WebhookEntry[]; - } interface WebhookEntry { - // Webhook identifier, as found in the webhook. webhook_id: string; // The event of the webhook: why the webhook is used. event_type: string; - } interface WebhookDetails { - // The event of the webhook: why the webhook is used. event_type: string; @@ -1431,9 +1422,7 @@ export namespace MerchantBackend { // Body template by the webhook body_template?: string; - } - } interface ContractTerms { diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts index 3f3db2fa1..952b33f7e 100644 --- a/packages/merchant-backoffice-ui/src/hooks/backend.ts +++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts @@ -28,8 +28,8 @@ import { HttpResponse, HttpResponseOk, RequestOptions, -} from "../utils/request.js"; -import { useApiContext } from "../context/api.js"; +} from "@gnu-taler/web-util/lib/index.browser"; +import { useApiContext } from "@gnu-taler/web-util/lib/index.browser"; export function useMatchMutate(): ( re: RegExp, @@ -54,12 +54,17 @@ export function useMatchMutate(): ( }; } -export function useBackendInstancesTestForAdmin(): HttpResponse { +export function useBackendInstancesTestForAdmin(): HttpResponse< + MerchantBackend.Instances.InstancesResponse, + MerchantBackend.ErrorDetail +> { const { request } = useBackendBaseRequest(); type Type = MerchantBackend.Instances.InstancesResponse; - const [result, setResult] = useState>({ loading: true }); + const [result, setResult] = useState< + HttpResponse + >({ loading: true }); useEffect(() => { request(`/management/instances`) @@ -70,12 +75,17 @@ export function useBackendInstancesTestForAdmin(): HttpResponse { +export function useBackendConfig(): HttpResponse< + MerchantBackend.VersionResponse, + MerchantBackend.ErrorDetail +> { const { request } = useBackendBaseRequest(); type Type = MerchantBackend.VersionResponse; - const [result, setResult] = useState>({ loading: true }); + const [result, setResult] = useState< + HttpResponse + >({ loading: true }); useEffect(() => { request(`/config`) @@ -88,15 +98,15 @@ export function useBackendConfig(): HttpResponse( - path: string, + endpoint: string, options?: RequestOptions, ) => Promise>; - fetcher: (path: string) => Promise>; - reserveDetailFetcher: (path: string) => Promise>; - tipsDetailFetcher: (path: string) => Promise>; + fetcher: (endpoint: string) => Promise>; + reserveDetailFetcher: (endpoint: string) => Promise>; + tipsDetailFetcher: (endpoint: string) => Promise>; multiFetcher: (url: string[]) => Promise[]>; orderFetcher: ( - path: string, + endpoint: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, @@ -104,26 +114,26 @@ interface useBackendInstanceRequestType { delta?: number, ) => Promise>; transferFetcher: ( - path: string, + endpoint: string, payto_uri?: string, verified?: string, position?: string, delta?: number, ) => Promise>; templateFetcher: ( - path: string, + endpoint: string, position?: string, delta?: number, ) => Promise>; webhookFetcher: ( - path: string, + endpoint: string, position?: string, delta?: number, ) => Promise>; } interface useBackendBaseRequestType { request: ( - path: string, + endpoint: string, options?: RequestOptions, ) => Promise>; } @@ -141,10 +151,10 @@ export function useBackendBaseRequest(): useBackendBaseRequestType { const request = useCallback( function requestImpl( - path: string, + endpoint: string, options: RequestOptions = {}, ): Promise> { - return requestHandler(backend, path, { token, ...options }); + return requestHandler(backend, endpoint, { token, ...options }); }, [backend, token], ); @@ -153,45 +163,47 @@ export function useBackendBaseRequest(): useBackendBaseRequestType { } export function useBackendInstanceRequest(): useBackendInstanceRequestType { - const { url: baseUrl, token: baseToken } = useBackendContext(); + const { url: rootBackendUrl, token: rootToken } = useBackendContext(); const { token: instanceToken, id, admin } = useInstanceContext(); const { request: requestHandler } = useApiContext(); - const { backend, token } = !admin - ? { backend: baseUrl, token: baseToken } - : { backend: `${baseUrl}/instances/${id}`, token: instanceToken }; + const { baseUrl, token } = !admin + ? { baseUrl: rootBackendUrl, token: rootToken } + : { baseUrl: `${rootBackendUrl}/instances/${id}`, token: instanceToken }; const request = useCallback( function requestImpl( - path: string, + endpoint: string, options: RequestOptions = {}, ): Promise> { - return requestHandler(backend, path, { token, ...options }); + return requestHandler(baseUrl, endpoint, { token, ...options }); }, - [backend, token], + [baseUrl, token], ); const multiFetcher = useCallback( function multiFetcherImpl( - paths: string[], + endpoints: string[], ): Promise[]> { return Promise.all( - paths.map((path) => requestHandler(backend, path, { token })), + endpoints.map((endpoint) => + requestHandler(baseUrl, endpoint, { token }), + ), ); }, - [backend, token], + [baseUrl, token], ); const fetcher = useCallback( - function fetcherImpl(path: string): Promise> { - return requestHandler(backend, path, { token }); + function fetcherImpl(endpoint: string): Promise> { + return requestHandler(baseUrl, endpoint, { token }); }, - [backend, token], + [baseUrl, token], ); const orderFetcher = useCallback( function orderFetcherImpl( - path: string, + endpoint: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, @@ -208,42 +220,42 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType { if (refunded !== undefined) params.refunded = refunded; if (wired !== undefined) params.wired = wired; if (date_ms !== undefined) params.date_ms = date_ms; - return requestHandler(backend, path, { params, token }); + return requestHandler(baseUrl, endpoint, { params, token }); }, - [backend, token], + [baseUrl, token], ); const reserveDetailFetcher = useCallback( function reserveDetailFetcherImpl( - path: string, + endpoint: string, ): Promise> { - return requestHandler(backend, path, { + return requestHandler(baseUrl, endpoint, { params: { tips: "yes", }, token, }); }, - [backend, token], + [baseUrl, token], ); const tipsDetailFetcher = useCallback( function tipsDetailFetcherImpl( - path: string, + endpoint: string, ): Promise> { - return requestHandler(backend, path, { + return requestHandler(baseUrl, endpoint, { params: { pickups: "yes", }, token, }); }, - [backend, token], + [baseUrl, token], ); const transferFetcher = useCallback( function transferFetcherImpl( - path: string, + endpoint: string, payto_uri?: string, verified?: string, position?: string, @@ -257,14 +269,14 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType { } if (position !== undefined) params.offset = position; - return requestHandler(backend, path, { params, token }); + return requestHandler(baseUrl, endpoint, { params, token }); }, - [backend, token], + [baseUrl, token], ); const templateFetcher = useCallback( function templateFetcherImpl( - path: string, + endpoint: string, position?: string, delta?: number, ): Promise> { @@ -274,14 +286,14 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType { } if (position !== undefined) params.offset = position; - return requestHandler(backend, path, { params, token }); + return requestHandler(baseUrl, endpoint, { params, token }); }, - [backend, token], + [baseUrl, token], ); const webhookFetcher = useCallback( function webhookFetcherImpl( - path: string, + endpoint: string, position?: string, delta?: number, ): Promise> { @@ -291,9 +303,9 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType { } if (position !== undefined) params.offset = position; - return requestHandler(backend, path, { params, token }); + return requestHandler(baseUrl, endpoint, { params, token }); }, - [backend, token], + [baseUrl, token], ); return { diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts index 3c05472d0..f118e1e6e 100644 --- a/packages/merchant-backoffice-ui/src/hooks/instance.ts +++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts @@ -16,7 +16,11 @@ import useSWR, { useSWRConfig } from "swr"; import { useBackendContext } from "../context/backend.js"; import { MerchantBackend } from "../declaration.js"; -import { HttpError, HttpResponse, HttpResponseOk } from "../utils/request.js"; +import { + HttpError, + HttpResponse, + HttpResponseOk, +} from "@gnu-taler/web-util/lib/index.browser"; import { useBackendBaseRequest, useBackendInstanceRequest, @@ -176,12 +180,15 @@ export function useInstanceAPI(): InstanceAPI { return { updateInstance, deleteInstance, setNewToken, clearToken }; } -export function useInstanceDetails(): HttpResponse { +export function useInstanceDetails(): HttpResponse< + MerchantBackend.Instances.QueryInstancesResponse, + MerchantBackend.ErrorDetail +> { const { fetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/`], fetcher, { refreshInterval: 0, refreshWhenHidden: false, @@ -203,12 +210,15 @@ type KYCStatus = | { type: "ok" } | { type: "redirect"; status: MerchantBackend.Instances.AccountKycRedirects }; -export function useInstanceKYCDetails(): HttpResponse { +export function useInstanceKYCDetails(): HttpResponse< + KYCStatus, + MerchantBackend.ErrorDetail +> { const { fetcher } = useBackendInstanceRequest(); const { data, error } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/kyc`], fetcher, { refreshInterval: 5000, refreshWhenHidden: false, @@ -231,12 +241,15 @@ export function useInstanceKYCDetails(): HttpResponse { export function useManagedInstanceDetails( instanceId: string, -): HttpResponse { +): HttpResponse< + MerchantBackend.Instances.QueryInstancesResponse, + MerchantBackend.ErrorDetail +> { const { request } = useBackendBaseRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/management/instances/${instanceId}`], request, { refreshInterval: 0, refreshWhenHidden: false, @@ -254,12 +267,15 @@ export function useManagedInstanceDetails( return { loading: true }; } -export function useBackendInstances(): HttpResponse { +export function useBackendInstances(): HttpResponse< + MerchantBackend.Instances.InstancesResponse, + MerchantBackend.ErrorDetail +> { const { request } = useBackendBaseRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >(["/management/instances"], request); if (isValidating) return { loading: true, data: data?.data }; diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts b/packages/merchant-backoffice-ui/src/hooks/order.ts index 5be480160..c01f8dd83 100644 --- a/packages/merchant-backoffice-ui/src/hooks/order.ts +++ b/packages/merchant-backoffice-ui/src/hooks/order.ts @@ -22,7 +22,7 @@ import { HttpResponse, HttpResponseOk, HttpResponsePaginated, -} from "../utils/request.js"; +} from "@gnu-taler/web-util/lib/index.browser"; import { useBackendInstanceRequest, useMatchMutate } from "./backend.js"; export interface OrderAPI { @@ -128,12 +128,15 @@ export function useOrderAPI(): OrderAPI { export function useOrderDetails( oderId: string, -): HttpResponse { +): HttpResponse< + MerchantBackend.Orders.MerchantOrderStatusResponse, + MerchantBackend.ErrorDetail +> { const { fetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/orders/${oderId}`], fetcher, { refreshInterval: 0, refreshWhenHidden: false, @@ -158,7 +161,10 @@ export interface InstanceOrderFilter { export function useInstanceOrders( args?: InstanceOrderFilter, updateFilter?: (d: Date) => void, -): HttpResponsePaginated { +): HttpResponsePaginated< + MerchantBackend.Orders.OrderHistory, + MerchantBackend.ErrorDetail +> { const { orderFetcher } = useBackendInstanceRequest(); const [pageBefore, setPageBefore] = useState(1); @@ -177,7 +183,10 @@ export function useInstanceOrders( data: beforeData, error: beforeError, isValidating: loadingBefore, - } = useSWR, HttpError>( + } = useSWR< + HttpResponseOk, + HttpError + >( [ `/private/orders`, args?.paid, @@ -192,7 +201,10 @@ export function useInstanceOrders( data: afterData, error: afterError, isValidating: loadingAfter, - } = useSWR, HttpError>( + } = useSWR< + HttpResponseOk, + HttpError + >( [ `/private/orders`, args?.paid, @@ -206,10 +218,16 @@ export function useInstanceOrders( //this will save last result const [lastBefore, setLastBefore] = useState< - HttpResponse + HttpResponse< + MerchantBackend.Orders.OrderHistory, + MerchantBackend.ErrorDetail + > >({ loading: true }); const [lastAfter, setLastAfter] = useState< - HttpResponse + HttpResponse< + MerchantBackend.Orders.OrderHistory, + MerchantBackend.ErrorDetail + > >({ loading: true }); useEffect(() => { if (afterData) setLastAfter(afterData); diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts b/packages/merchant-backoffice-ui/src/hooks/product.ts index af8ad74f3..5d95a2f8f 100644 --- a/packages/merchant-backoffice-ui/src/hooks/product.ts +++ b/packages/merchant-backoffice-ui/src/hooks/product.ts @@ -15,7 +15,11 @@ */ import useSWR, { useSWRConfig } from "swr"; import { MerchantBackend, WithId } from "../declaration.js"; -import { HttpError, HttpResponse, HttpResponseOk } from "../utils/request.js"; +import { + HttpError, + HttpResponse, + HttpResponseOk, +} from "@gnu-taler/web-util/lib/index.browser"; import { useBackendInstanceRequest, useMatchMutate } from "./backend.js"; export interface ProductAPI { @@ -85,13 +89,14 @@ export function useProductAPI(): ProductAPI { } export function useInstanceProducts(): HttpResponse< - (MerchantBackend.Products.ProductDetail & WithId)[] + (MerchantBackend.Products.ProductDetail & WithId)[], + MerchantBackend.ErrorDetail > { const { fetcher, multiFetcher } = useBackendInstanceRequest(); const { data: list, error: listError } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/products`], fetcher, { refreshInterval: 0, refreshWhenHidden: false, @@ -105,7 +110,7 @@ export function useInstanceProducts(): HttpResponse< ); const { data: products, error: productError } = useSWR< HttpResponseOk[], - HttpError + HttpError >([paths], multiFetcher, { refreshInterval: 0, refreshWhenHidden: false, @@ -122,7 +127,7 @@ export function useInstanceProducts(): HttpResponse< //take the id from the queried url return { ...d.data, - id: d.info?.url.href.replace(/.*\/private\/products\//, "") || "", + id: d.info?.url.replace(/.*\/private\/products\//, "") || "", }; }); return { ok: true, data: dataWithId }; @@ -132,12 +137,15 @@ export function useInstanceProducts(): HttpResponse< export function useProductDetails( productId: string, -): HttpResponse { +): HttpResponse< + MerchantBackend.Products.ProductDetail, + MerchantBackend.ErrorDetail +> { const { fetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/products/${productId}`], fetcher, { refreshInterval: 0, refreshWhenHidden: false, diff --git a/packages/merchant-backoffice-ui/src/hooks/reserves.ts b/packages/merchant-backoffice-ui/src/hooks/reserves.ts index dc127af13..0215f32c5 100644 --- a/packages/merchant-backoffice-ui/src/hooks/reserves.ts +++ b/packages/merchant-backoffice-ui/src/hooks/reserves.ts @@ -15,7 +15,11 @@ */ import useSWR, { useSWRConfig } from "swr"; import { MerchantBackend } from "../declaration.js"; -import { HttpError, HttpResponse, HttpResponseOk } from "../utils/request.js"; +import { + HttpError, + HttpResponse, + HttpResponseOk, +} from "@gnu-taler/web-util/lib/index.browser"; import { useBackendInstanceRequest, useMatchMutate } from "./backend.js"; export function useReservesAPI(): ReserveMutateAPI { @@ -77,7 +81,9 @@ export function useReservesAPI(): ReserveMutateAPI { return res; }; - const deleteReserve = async (pub: string): Promise> => { + const deleteReserve = async ( + pub: string, + ): Promise> => { const res = await request(`/private/reserves/${pub}`, { method: "DELETE", }); @@ -102,15 +108,20 @@ export interface ReserveMutateAPI { authorizeTip: ( data: MerchantBackend.Tips.TipCreateRequest, ) => Promise>; - deleteReserve: (id: string) => Promise>; + deleteReserve: ( + id: string, + ) => Promise>; } -export function useInstanceReserves(): HttpResponse { +export function useInstanceReserves(): HttpResponse< + MerchantBackend.Tips.TippingReserveStatus, + MerchantBackend.ErrorDetail +> { const { fetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/reserves`], fetcher); if (isValidating) return { loading: true, data: data?.data }; @@ -121,12 +132,15 @@ export function useInstanceReserves(): HttpResponse { +): HttpResponse< + MerchantBackend.Tips.ReserveDetail, + MerchantBackend.ErrorDetail +> { const { reserveDetailFetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/reserves/${reserveId}`], reserveDetailFetcher, { refreshInterval: 0, refreshWhenHidden: false, @@ -143,12 +157,12 @@ export function useReserveDetails( export function useTipDetails( tipId: string, -): HttpResponse { +): HttpResponse { const { tipsDetailFetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/tips/${tipId}`], tipsDetailFetcher, { refreshInterval: 0, refreshWhenHidden: false, diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts b/packages/merchant-backoffice-ui/src/hooks/templates.ts index 3a28b903d..124786887 100644 --- a/packages/merchant-backoffice-ui/src/hooks/templates.ts +++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts @@ -23,7 +23,7 @@ import { HttpResponse, HttpResponseOk, HttpResponsePaginated, -} from "../utils/request.js"; +} from "@gnu-taler/web-util/lib/index.browser"; export function useTemplateAPI(): TemplateAPI { const mutateAll = useMatchMutate(); @@ -79,7 +79,12 @@ export function useTemplateAPI(): TemplateAPI { return res; }; - return { createTemplate, updateTemplate, deleteTemplate, createOrderFromTemplate }; + return { + createTemplate, + updateTemplate, + deleteTemplate, + createOrderFromTemplate, + }; } export interface TemplateAPI { @@ -105,7 +110,10 @@ export interface InstanceTemplateFilter { export function useInstanceTemplates( args?: InstanceTemplateFilter, updatePosition?: (id: string) => void, -): HttpResponsePaginated { +): HttpResponsePaginated< + MerchantBackend.Template.TemplateSummaryResponse, + MerchantBackend.ErrorDetail +> { const { templateFetcher } = useBackendInstanceRequest(); // const [pageBefore, setPageBefore] = useState(1); @@ -140,15 +148,18 @@ export function useInstanceTemplates( isValidating: loadingAfter, } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/templates`, args?.position, -totalAfter], templateFetcher); //this will save last result // const [lastBefore, setLastBefore] = useState< - // HttpResponse + // HttpResponse // >({ loading: true }); const [lastAfter, setLastAfter] = useState< - HttpResponse + HttpResponse< + MerchantBackend.Template.TemplateSummaryResponse, + MerchantBackend.ErrorDetail + > >({ loading: true }); useEffect(() => { if (afterData) setLastAfter(afterData); @@ -174,9 +185,10 @@ export function useInstanceTemplates( if (afterData.data.templates.length < MAX_RESULT_SIZE) { setPageAfter(pageAfter + 1); } else { - const from = `${afterData.data.templates[afterData.data.templates.length - 1] - .template_id - }`; + const from = `${ + afterData.data.templates[afterData.data.templates.length - 1] + .template_id + }`; if (from && updatePosition) updatePosition(from); } }, @@ -211,12 +223,15 @@ export function useInstanceTemplates( export function useTemplateDetails( templateId: string, -): HttpResponse { +): HttpResponse< + MerchantBackend.Template.TemplateDetails, + MerchantBackend.ErrorDetail +> { const { templateFetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/templates/${templateId}`], templateFetcher, { refreshInterval: 0, refreshWhenHidden: false, diff --git a/packages/merchant-backoffice-ui/src/hooks/testing.tsx b/packages/merchant-backoffice-ui/src/hooks/testing.tsx index 8c5a5a36b..64e646bb5 100644 --- a/packages/merchant-backoffice-ui/src/hooks/testing.tsx +++ b/packages/merchant-backoffice-ui/src/hooks/testing.tsx @@ -22,10 +22,13 @@ import { MockEnvironment } from "@gnu-taler/web-util/lib/tests/mock"; import { ComponentChildren, FunctionalComponent, h, VNode } from "preact"; import { SWRConfig } from "swr"; -import { ApiContextProvider } from "../context/api.js"; +import { ApiContextProvider } from "@gnu-taler/web-util/lib/index.browser"; import { BackendContextProvider } from "../context/backend.js"; import { InstanceContextProvider } from "../context/instance.js"; -import { HttpResponseOk, RequestOptions } from "../utils/request.js"; +import { + HttpResponseOk, + RequestOptions, +} from "@gnu-taler/web-util/lib/index.browser"; export class ApiMockEnvironment extends MockEnvironment { constructor(debug = false) { @@ -78,7 +81,7 @@ export class ApiMockEnvironment extends MockEnvironment { info: { hasToken: !!options.token, status: !mocked ? 200 : mocked.status, - url: _url, + url: _url.href, payload: options.data, }, }; diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts b/packages/merchant-backoffice-ui/src/hooks/transfer.ts index b86247476..6b30047e9 100644 --- a/packages/merchant-backoffice-ui/src/hooks/transfer.ts +++ b/packages/merchant-backoffice-ui/src/hooks/transfer.ts @@ -22,7 +22,7 @@ import { HttpResponse, HttpResponseOk, HttpResponsePaginated, -} from "../utils/request.js"; +} from "@gnu-taler/web-util/lib/index.browser"; import { useBackendInstanceRequest, useMatchMutate } from "./backend.js"; export function useTransferAPI(): TransferAPI { @@ -67,7 +67,10 @@ export interface InstanceTransferFilter { export function useInstanceTransfers( args?: InstanceTransferFilter, updatePosition?: (id: string) => void, -): HttpResponsePaginated { +): HttpResponsePaginated< + MerchantBackend.Transfers.TransferList, + MerchantBackend.ErrorDetail +> { const { transferFetcher } = useBackendInstanceRequest(); const [pageBefore, setPageBefore] = useState(1); @@ -86,7 +89,10 @@ export function useInstanceTransfers( data: beforeData, error: beforeError, isValidating: loadingBefore, - } = useSWR, HttpError>( + } = useSWR< + HttpResponseOk, + HttpError + >( [ `/private/transfers`, args?.payto_uri, @@ -100,7 +106,10 @@ export function useInstanceTransfers( data: afterData, error: afterError, isValidating: loadingAfter, - } = useSWR, HttpError>( + } = useSWR< + HttpResponseOk, + HttpError + >( [ `/private/transfers`, args?.payto_uri, @@ -113,10 +122,16 @@ export function useInstanceTransfers( //this will save last result const [lastBefore, setLastBefore] = useState< - HttpResponse + HttpResponse< + MerchantBackend.Transfers.TransferList, + MerchantBackend.ErrorDetail + > >({ loading: true }); const [lastAfter, setLastAfter] = useState< - HttpResponse + HttpResponse< + MerchantBackend.Transfers.TransferList, + MerchantBackend.ErrorDetail + > >({ loading: true }); useEffect(() => { if (afterData) setLastAfter(afterData); diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts index 9f196cefa..e1cd3daf2 100644 --- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts +++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts @@ -23,7 +23,7 @@ import { HttpResponse, HttpResponseOk, HttpResponsePaginated, -} from "../utils/request.js"; +} from "@gnu-taler/web-util/lib/index.browser"; export function useWebhookAPI(): WebhookAPI { const mutateAll = useMatchMutate(); @@ -84,7 +84,10 @@ export interface InstanceWebhookFilter { export function useInstanceWebhooks( args?: InstanceWebhookFilter, updatePosition?: (id: string) => void, -): HttpResponsePaginated { +): HttpResponsePaginated< + MerchantBackend.Webhooks.WebhookSummaryResponse, + MerchantBackend.ErrorDetail +> { const { webhookFetcher } = useBackendInstanceRequest(); const [pageAfter, setPageAfter] = useState(1); @@ -97,11 +100,14 @@ export function useInstanceWebhooks( isValidating: loadingAfter, } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/webhooks`, args?.position, -totalAfter], webhookFetcher); const [lastAfter, setLastAfter] = useState< - HttpResponse + HttpResponse< + MerchantBackend.Webhooks.WebhookSummaryResponse, + MerchantBackend.ErrorDetail + > >({ loading: true }); useEffect(() => { if (afterData) setLastAfter(afterData); @@ -121,21 +127,20 @@ export function useInstanceWebhooks( if (afterData.data.webhooks.length < MAX_RESULT_SIZE) { setPageAfter(pageAfter + 1); } else { - const from = `${afterData.data.webhooks[afterData.data.webhooks.length - 1] - .webhook_id - }`; + const from = `${ + afterData.data.webhooks[afterData.data.webhooks.length - 1].webhook_id + }`; if (from && updatePosition) updatePosition(from); } }, loadMorePrev: () => { - return + return; }, }; const webhooks = !afterData ? [] : (afterData || lastAfter).data.webhooks; - if (loadingAfter) - return { loading: true, data: { webhooks } }; + if (loadingAfter) return { loading: true, data: { webhooks } }; if (afterData) { return { ok: true, data: { webhooks }, ...pagination }; } @@ -144,12 +149,15 @@ export function useInstanceWebhooks( export function useWebhookDetails( webhookId: string, -): HttpResponse { +): HttpResponse< + MerchantBackend.Webhooks.WebhookDetails, + MerchantBackend.ErrorDetail +> { const { webhookFetcher } = useBackendInstanceRequest(); const { data, error, isValidating } = useSWR< HttpResponseOk, - HttpError + HttpError >([`/private/webhooks/${webhookId}`], webhookFetcher, { refreshInterval: 0, refreshWhenHidden: false, 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 bac7a39eb..8efb5598d 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx @@ -19,14 +19,16 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../components/exception/loading.js"; import { NotificationCard } from "../../../components/menu/index.js"; import { DeleteModal, PurgeModal } from "../../../components/modal/index.js"; import { MerchantBackend } from "../../../declaration.js"; -import { HttpError } from "../../../utils/request.js"; import { useAdminAPI, useBackendInstances } from "../../../hooks/instance.js"; import { Notification } from "../../../utils/types.js"; import { View } from "./View.js"; @@ -37,7 +39,7 @@ interface Props { instances: MerchantBackend.Instances.Instance[]; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; setInstanceName: (s: string) => void; } 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 56d5c0755..8f7d9b136 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx @@ -13,18 +13,19 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ +import { HttpError } from "@gnu-taler/web-util/lib/index.browser.js"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../components/exception/loading.js"; import { DeleteModal } from "../../../components/modal/index.js"; import { useInstanceContext } from "../../../context/instance.js"; -import { HttpError } from "../../../utils/request.js"; +import { MerchantBackend } from "../../../declaration.js"; import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance.js"; import { DetailPage } from "./DetailPage.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onUpdate: () => void; onNotFound: () => VNode; onDelete: () => void; @@ -63,7 +64,9 @@ export default function Detail({ try { await deleteInstance(); onDelete(); - } catch (error) {} + } catch (error) { + //FIXME: show message error + } setDeleting(false); }} /> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx index 83af002b3..dba2aab21 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx @@ -19,15 +19,16 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { HttpError } from "@gnu-taler/web-util/lib/index.browser.js"; import { h, VNode } from "preact"; import { Loading } from "../../../../components/exception/loading.js"; -import { HttpError } from "../../../../utils/request.js"; +import { MerchantBackend } from "../../../../declaration.js"; import { useInstanceKYCDetails } from "../../../../hooks/instance.js"; import { ListPage } from "./ListPage.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; } 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 5c6293a81..a37df2176 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 @@ -19,18 +19,17 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { HttpError } from "@gnu-taler/web-util/lib/index.browser.js"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useInstanceDetails } from "../../../../hooks/instance.js"; import { useOrderAPI } from "../../../../hooks/order.js"; import { useInstanceProducts } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; import { CreatePage } from "./CreatePage.js"; -import { OrderCreatedSuccessfully } from "./OrderCreatedSuccessfully.js"; export type Entity = { request: MerchantBackend.Orders.PostOrderRequest; @@ -41,7 +40,7 @@ interface Props { onConfirm: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; } export default function OrderCreate({ onConfirm, 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 19aaddf50..986c46b95 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 @@ -13,12 +13,15 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + useTranslationContext, + HttpError, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; -import { HttpError } from "../../../../utils/request.js"; +import { MerchantBackend } from "../../../../declaration.js"; import { useOrderAPI, useOrderDetails } from "../../../../hooks/order.js"; import { Notification } from "../../../../utils/types.js"; import { DetailPage } from "./DetailPage.js"; @@ -29,7 +32,7 @@ export interface Props { onBack: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; } export default function Update({ 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 3744ce8c5..bd0924808 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 @@ -19,13 +19,15 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { InstanceOrderFilter, useInstanceOrders, @@ -38,7 +40,7 @@ import { RefundModal } from "./Table.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onSelect: (id: string) => void; onCreate: () => void; @@ -177,7 +179,7 @@ export default function OrderList({ interface RefundProps { id: string; onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onCancel: () => void; onConfirm: (m: MerchantBackend.Orders.RefundRequest) => void; 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 25332acee..c32339563 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 @@ -19,13 +19,15 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend, WithId } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useInstanceProducts, useProductAPI, @@ -38,7 +40,7 @@ interface Props { onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; - onLoadError: (e: HttpError) => VNode; + onLoadError: (e: HttpError) => VNode; } export default function ProductList({ onUnauthorized, 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 5b19a7aa3..b35606f53 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 @@ -19,13 +19,15 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useProductAPI, useProductDetails } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; @@ -36,7 +38,7 @@ interface Props { onConfirm: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError) => VNode; + onLoadError: (e: HttpError) => VNode; pid: string; } export default function UpdateProduct({ diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx index eeb59611c..c0c36e651 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx @@ -30,8 +30,7 @@ import { import { Input } from "../../../../components/form/Input.js"; import { InputCurrency } from "../../../../components/form/InputCurrency.js"; import { InputSelector } from "../../../../components/form/InputSelector.js"; -import { ExchangeBackend, MerchantBackend } from "../../../../declaration.js"; -// import { request } from "../../../../utils/request.js"; +import { MerchantBackend } from "../../../../declaration.js"; import { PAYTO_WIRE_METHOD_LOOKUP, URL_REGEX, diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx index 57ee566d1..e7ec68fab 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx @@ -19,9 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { HttpError } from "@gnu-taler/web-util/lib/index.browser.js"; import { Fragment, h, VNode } from "preact"; import { Loading } from "../../../../components/exception/loading.js"; -import { HttpError } from "../../../../utils/request.js"; +import { MerchantBackend } from "../../../../declaration.js"; import { useReserveDetails } from "../../../../hooks/reserves.js"; import { DetailPage } from "./DetailPage.js"; @@ -29,7 +30,7 @@ interface Props { rid: string; onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onDelete: () => void; onBack: () => void; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx index 597bde167..e6c6abc23 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx @@ -19,13 +19,15 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useInstanceReserves, useReservesAPI, @@ -36,7 +38,7 @@ import { CardTable } from "./Table.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (e: HttpError) => VNode; + onLoadError: (e: HttpError) => VNode; onSelect: (id: string) => void; onNotFound: () => VNode; onCreate: () => void; 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 5fce3a819..0b7c191bd 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 @@ -19,13 +19,15 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useInstanceTemplates, useTemplateAPI, @@ -35,7 +37,7 @@ import { ListPage } from "./ListPage.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; 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 684ffd429..73489869b 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 @@ -19,13 +19,15 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { MerchantBackend, WithId } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useTemplateAPI, useTemplateDetails, @@ -40,7 +42,7 @@ interface Props { onConfirm: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError) => VNode; + onLoadError: (e: HttpError) => VNode; tid: string; } export default function UpdateTemplate({ diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx index cbcadc608..13576d94d 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx @@ -19,7 +19,6 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode, FunctionalComponent } from "preact"; import { UsePage as TestedComponent } from "./UsePage.js"; export default { 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 fa9a98c6d..d5fa6d39d 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 @@ -19,7 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; @@ -29,7 +32,6 @@ import { useTemplateAPI, useTemplateDetails, } from "../../../../hooks/templates.js"; -import { HttpError } from "../../../../utils/request.js"; import { Notification } from "../../../../utils/types.js"; import { UsePage } from "./UsePage.js"; @@ -39,7 +41,7 @@ interface Props { onOrderCreated: (id: string) => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError) => VNode; + onLoadError: (e: HttpError) => VNode; tid: string; } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx index 59b56a613..9f2b59efd 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx @@ -19,18 +19,18 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { HttpError } from "@gnu-taler/web-util/lib/index.browser.js"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { HttpError } from "../../../../utils/request.js"; import { useInstanceDetails } from "../../../../hooks/instance.js"; import { useInstanceTransfers } from "../../../../hooks/transfer.js"; import { ListPage } from "./ListPage.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onCreate: () => void; } 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 02beb36f2..912393c7c 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx @@ -13,7 +13,11 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + HttpResponse, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../components/exception/loading.js"; @@ -26,7 +30,6 @@ import { useManagedInstanceDetails, useManagementAPI, } from "../../../hooks/instance.js"; -import { HttpError, HttpResponse } from "../../../utils/request.js"; import { Notification } from "../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; @@ -36,8 +39,8 @@ export interface Props { onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError) => VNode; - onUpdateError: (e: HttpError) => void; + onLoadError: (e: HttpError) => VNode; + onUpdateError: (e: HttpError) => void; } export default function Update(props: Props): VNode { @@ -63,7 +66,10 @@ function CommonUpdate( onUpdateError, onUnauthorized, }: Props, - result: HttpResponse, + result: HttpResponse< + MerchantBackend.Instances.QueryInstancesResponse, + MerchantBackend.ErrorDetail + >, updateInstance: any, clearToken: any, setNewToken: any, 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 c5846e4db..670fc7218 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 @@ -19,7 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; @@ -29,13 +32,12 @@ import { useInstanceWebhooks, useWebhookAPI, } from "../../../../hooks/webhooks.js"; -import { HttpError } from "../../../../utils/request.js"; import { Notification } from "../../../../utils/types.js"; import { ListPage } from "./ListPage.js"; interface Props { onUnauthorized: () => VNode; - onLoadError: (error: HttpError) => VNode; + onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; 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 3597fb849..b9a8674b3 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 @@ -19,7 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; @@ -29,7 +32,6 @@ import { useWebhookAPI, useWebhookDetails, } from "../../../../hooks/webhooks.js"; -import { HttpError } from "../../../../utils/request.js"; import { Notification } from "../../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; @@ -40,7 +42,7 @@ interface Props { onConfirm: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError) => VNode; + onLoadError: (e: HttpError) => VNode; tid: string; } export default function UpdateWebhook({ diff --git a/packages/merchant-backoffice-ui/src/utils/request.ts b/packages/merchant-backoffice-ui/src/utils/request.ts deleted file mode 100644 index 821eca4a7..000000000 --- a/packages/merchant-backoffice-ui/src/utils/request.ts +++ /dev/null @@ -1,282 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2023 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ -// import axios, { AxiosError, AxiosResponse } from "axios"; -import { MerchantBackend } from "../declaration.js"; - -export async function defaultRequestHandler( - base: string, - path: string, - options: RequestOptions = {}, -): Promise> { - const requestHeaders = options.token - ? { Authorization: `Bearer ${options.token}` } - : undefined; - - const requestMethod = options?.method ?? "GET"; - const requestBody = options?.data; - const requestTimeout = 2 * 1000; - const requestParams = options.params ?? {}; - - const _url = new URL(`${base}${path}`); - - Object.entries(requestParams).forEach(([key, value]) => { - _url.searchParams.set(key, String(value)); - }); - - let payload: BodyInit | undefined = undefined; - if (requestBody != null) { - if (typeof requestBody === "string") { - payload = requestBody; - } else if (requestBody instanceof ArrayBuffer) { - payload = requestBody; - } else if (ArrayBuffer.isView(requestBody)) { - payload = requestBody; - } else if (typeof requestBody === "object") { - payload = JSON.stringify(requestBody); - } else { - throw Error("unsupported request body type"); - } - } - - const controller = new AbortController(); - const timeoutId = setTimeout(() => { - controller.abort("HTTP_REQUEST_TIMEOUT"); - }, requestTimeout); - - const response = await fetch(_url.href, { - headers: { - ...requestHeaders, - "Content-Type": "text/plain", - }, - method: requestMethod, - credentials: "omit", - mode: "cors", - body: payload, - signal: controller.signal, - }); - - if (timeoutId) { - clearTimeout(timeoutId); - } - const headerMap = new Headers(); - response.headers.forEach((value, key) => { - headerMap.set(key, value); - }); - - if (response.ok) { - const result = await buildRequestOk( - response, - _url, - payload, - !!options.token, - ); - return result; - } else { - const error = await buildRequestFailed( - response, - _url, - payload, - !!options.token, - ); - throw error; - } -} - -export type HttpResponse = - | HttpResponseOk - | HttpResponseLoading - | HttpError; -export type HttpResponsePaginated = - | HttpResponseOkPaginated - | HttpResponseLoading - | HttpError; - -export interface RequestInfo { - url: URL; - hasToken: boolean; - payload: any; - status: number; -} - -interface HttpResponseLoading { - ok?: false; - loading: true; - clientError?: false; - serverError?: false; - - data?: T; -} -export interface HttpResponseOk { - ok: true; - loading?: false; - clientError?: false; - serverError?: false; - - data: T; - info?: RequestInfo; -} - -export type HttpResponseOkPaginated = HttpResponseOk & WithPagination; - -export interface WithPagination { - loadMore: () => void; - loadMorePrev: () => void; - isReachingEnd?: boolean; - isReachingStart?: boolean; -} - -export type HttpError = - | HttpResponseClientError - | HttpResponseServerError - | HttpResponseUnexpectedError; -export interface SwrError { - info: unknown; - status: number; - message: string; -} -export interface HttpResponseServerError { - ok?: false; - loading?: false; - clientError?: false; - serverError: true; - - error?: MerchantBackend.ErrorDetail; - status: number; - message: string; - info?: RequestInfo; -} -interface HttpResponseClientError { - ok?: false; - loading?: false; - clientError: true; - serverError?: false; - - info?: RequestInfo; - isUnauthorized: boolean; - isNotfound: boolean; - status: number; - error?: MerchantBackend.ErrorDetail; - message: string; -} - -interface HttpResponseUnexpectedError { - ok?: false; - loading?: false; - clientError?: false; - serverError?: false; - - info?: RequestInfo; - status?: number; - error: unknown; - message: string; -} - -type Methods = "GET" | "POST" | "PATCH" | "DELETE" | "PUT"; - -export interface RequestOptions { - method?: Methods; - token?: string; - data?: any; - params?: unknown; -} - -async function buildRequestOk( - response: Response, - url: URL, - payload: any, - hasToken: boolean, -): Promise> { - const dataTxt = await response.text(); - const data = dataTxt ? JSON.parse(dataTxt) : undefined; - return { - ok: true, - data, - info: { - payload, - url, - hasToken, - status: response.status, - }, - }; -} - -async function buildRequestFailed( - response: Response, - url: URL, - payload: any, - hasToken: boolean, -): Promise< - | HttpResponseClientError - | HttpResponseServerError - | HttpResponseUnexpectedError -> { - const status = response?.status; - - const info: RequestInfo = { - payload, - url, - hasToken, - status: status || 0, - }; - - try { - const dataTxt = await response.text(); - const data = dataTxt ? JSON.parse(dataTxt) : undefined; - if (status && status >= 400 && status < 500) { - const error: HttpResponseClientError = { - clientError: true, - isNotfound: status === 404, - isUnauthorized: status === 401, - status, - info, - message: data?.hint, - error: data, - }; - return error; - } - if (status && status >= 500 && status < 600) { - const error: HttpResponseServerError = { - serverError: true, - status, - info, - message: `${data?.hint} (code ${data?.code})`, - error: data, - }; - return error; - } - return { - info, - status, - error: {}, - message: "NOT DEFINED", - }; - } catch (ex) { - const error: HttpResponseUnexpectedError = { - info, - status, - error: ex, - message: "NOT DEFINED", - }; - - throw error; - } -} - -// export function isAxiosError( -// error: AxiosError | any, -// ): error is AxiosError { -// return error && error.isAxiosError; -// }