diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/hooks/webhooks.ts')
-rw-r--r-- | packages/merchant-backoffice-ui/src/hooks/webhooks.ts | 222 |
1 files changed, 81 insertions, 141 deletions
diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts index ad6bf96e2..fe37162aa 100644 --- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts +++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2021-2023 Taler Systems S.A. + (C) 2021-2024 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 @@ -13,166 +13,106 @@ 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 { - HttpResponse, - HttpResponseOk, - HttpResponsePaginated, - RequestError, -} from "@gnu-taler/web-util/browser"; -import { useEffect, useState } from "preact/hooks"; -import { MerchantBackend } from "../declaration.js"; -import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js"; -import { useBackendInstanceRequest, useMatchMutate } from "./backend.js"; +import { PAGINATED_LIST_REQUEST } from "../utils/constants.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 -import _useSWR, { SWRHook } from "swr"; +import { AccessToken, OperationOk, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util"; +import _useSWR, { SWRHook, mutate } from "swr"; +import { useSessionContext } from "../context/session.js"; const useSWR = _useSWR as unknown as SWRHook; -export function useWebhookAPI(): WebhookAPI { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); +export interface InstanceWebhookFilter { +} - const createWebhook = async ( - data: MerchantBackend.Webhooks.WebhookAddDetails, - ): Promise<HttpResponseOk<void>> => { - const res = await request<void>(`/private/webhooks`, { - method: "POST", - data, - }); - await mutateAll(/.*private\/webhooks.*/); - return res; - }; +export function revalidateInstanceWebhooks() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listWebhooks", + undefined, + { revalidate: true }, + ); +} +export function useInstanceWebhooks() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useSessionContext(); - const updateWebhook = async ( - webhookId: string, - data: MerchantBackend.Webhooks.WebhookPatchDetails, - ): Promise<HttpResponseOk<void>> => { - const res = await request<void>(`/private/webhooks/${webhookId}`, { - method: "PATCH", - data, - }); - await mutateAll(/.*private\/webhooks.*/); - return res; - }; + // const [offset, setOffset] = useState<string | undefined>(); - const deleteWebhook = async ( - webhookId: string, - ): Promise<HttpResponseOk<void>> => { - const res = await request<void>(`/private/webhooks/${webhookId}`, { - method: "DELETE", + async function fetcher([token, _bid]: [AccessToken, string]) { + return await instance.listWebhooks(token, { + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", }); - await mutateAll(/.*private\/webhooks.*/); - return res; - }; + } - return { createWebhook, updateWebhook, deleteWebhook }; -} + const { data, error } = useSWR< + TalerMerchantManagementResultByMethod<"listWebhooks">, + TalerHttpError + >([session.token, "offset", "listWebhooks"], fetcher); -export interface WebhookAPI { - createWebhook: ( - data: MerchantBackend.Webhooks.WebhookAddDetails, - ) => Promise<HttpResponseOk<void>>; - updateWebhook: ( - id: string, - data: MerchantBackend.Webhooks.WebhookPatchDetails, - ) => Promise<HttpResponseOk<void>>; - deleteWebhook: (id: string) => Promise<HttpResponseOk<void>>; + if (error) return error; + if (data === undefined) return undefined; + if (data.type !== "ok") return data; + + // return buildPaginatedResult(data.body.webhooks, offset, setOffset, (d) => d.webhook_id) + return data; } -export interface InstanceWebhookFilter { - //FIXME: add filter to the webhook list - position?: string; +type PaginatedResult<T> = OperationOk<T> & { + isLastPage: boolean; + isFirstPage: boolean; + loadNext(): void; + loadFirst(): void; } -export function useInstanceWebhooks( - args?: InstanceWebhookFilter, - updatePosition?: (id: string) => void, -): HttpResponsePaginated< - MerchantBackend.Webhooks.WebhookSummaryResponse, - MerchantBackend.ErrorDetail -> { - const { webhookFetcher } = useBackendInstanceRequest(); - - const [pageBefore, setPageBefore] = useState(1); - const [pageAfter, setPageAfter] = useState(1); - - const totalAfter = pageAfter * PAGE_SIZE; - const totalBefore = args?.position ? pageBefore * PAGE_SIZE : 0; - - const { - data: afterData, - error: afterError, - isValidating: loadingAfter, - } = useSWR< - HttpResponseOk<MerchantBackend.Webhooks.WebhookSummaryResponse>, - RequestError<MerchantBackend.ErrorDetail> - >([`/private/webhooks`, args?.position, -totalAfter], webhookFetcher); - - const [lastAfter, setLastAfter] = useState< - HttpResponse< - MerchantBackend.Webhooks.WebhookSummaryResponse, - MerchantBackend.ErrorDetail - > - >({ loading: true }); - useEffect(() => { - if (afterData) setLastAfter(afterData); - }, [afterData]); - - if (afterError) return afterError.cause; - - const isReachingEnd = - afterData && afterData.data.webhooks.length < totalAfter; - const isReachingStart = true; - - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) return; - if (afterData.data.webhooks.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = `${ - afterData.data.webhooks[afterData.data.webhooks.length - 1].webhook_id - }`; - if (from && updatePosition) updatePosition(from); - } +//TODO: consider sending this to web-util +export function buildPaginatedResult<R, OffId>(data: R[], offset: OffId | undefined, setOffset: (o: OffId | undefined) => void, getId: (r: R) => OffId): PaginatedResult<R[]> { + + const isLastPage = data.length < PAGINATED_LIST_REQUEST; + const isFirstPage = offset === undefined; + + const result = structuredClone(data); + if (result.length == PAGINATED_LIST_REQUEST) { + result.pop(); + } + return { + type: "ok", + body: result, + isLastPage, + isFirstPage, + loadNext: () => { + if (!result.length) return; + const id = getId(result[result.length - 1]) + setOffset(id); }, - loadMorePrev: () => { - return; + loadFirst: () => { + setOffset(undefined); }, }; +} - const webhooks = !afterData ? [] : (afterData || lastAfter).data.webhooks; - if (loadingAfter) return { loading: true, data: { webhooks } }; - if (afterData) { - return { ok: true, data: { webhooks }, ...pagination }; - } - return { loading: true }; +export function revalidateWebhookDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getWebhookDetails", + undefined, + { revalidate: true }, + ); } +export function useWebhookDetails(webhookId: string) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useSessionContext(); + + async function fetcher([hookId, token]: [string, AccessToken]) { + return await instance.getWebhookDetails(token, hookId); + } + + const { data, error } = useSWR< + TalerMerchantManagementResultByMethod<"getWebhookDetails">, + TalerHttpError + >([webhookId, session.token, "getWebhookDetails"], fetcher); -export function useWebhookDetails( - webhookId: string, -): HttpResponse< - MerchantBackend.Webhooks.WebhookDetails, - MerchantBackend.ErrorDetail -> { - const { webhookFetcher } = useBackendInstanceRequest(); - - const { data, error, isValidating } = useSWR< - HttpResponseOk<MerchantBackend.Webhooks.WebhookDetails>, - RequestError<MerchantBackend.ErrorDetail> - >([`/private/webhooks/${webhookId}`], webhookFetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false, - }); - - if (isValidating) return { loading: true, data: data?.data }; if (data) return data; - if (error) return error.cause; - return { loading: true }; + if (error) return error; + return undefined; } |