/* 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 { useSWRConfig } from "swr"; import { MerchantBackend } from "../declaration.js"; import { useBackendContext } from "../context/backend.js"; import { useCallback, useEffect, useState } from "preact/hooks"; import { useInstanceContext } from "../context/instance.js"; import { HttpResponse, HttpResponseOk, RequestOptions, } from "../utils/request.js"; import { useApiContext } from "../context/api.js"; export function useMatchMutate(): ( re: RegExp, value?: unknown, ) => Promise { const { cache, mutate } = useSWRConfig(); if (!(cache instanceof Map)) { throw new Error( "matchMutate requires the cache provider to be a Map instance", ); } return function matchRegexMutate(re: RegExp, value?: unknown) { const allKeys = Array.from(cache.keys()); const keys = allKeys.filter((key) => re.test(key)); const mutations = keys.map((key) => { // console.log(key) mutate(key, value, true); }); return Promise.all(mutations); }; } export function useBackendInstancesTestForAdmin(): HttpResponse { const { request } = useBackendBaseRequest(); type Type = MerchantBackend.Instances.InstancesResponse; const [result, setResult] = useState>({ loading: true }); useEffect(() => { request(`/management/instances`) .then((data) => setResult(data)) .catch((error) => setResult(error)); }, [request]); return result; } export function useBackendConfig(): HttpResponse { const { request } = useBackendBaseRequest(); type Type = MerchantBackend.VersionResponse; const [result, setResult] = useState>({ loading: true }); useEffect(() => { request(`/config`) .then((data) => setResult(data)) .catch((error) => setResult(error)); }, [request]); return result; } interface useBackendInstanceRequestType { request: ( path: string, options?: RequestOptions, ) => Promise>; fetcher: (path: string) => Promise>; reserveDetailFetcher: (path: string) => Promise>; tipsDetailFetcher: (path: string) => Promise>; multiFetcher: (url: string[]) => Promise[]>; orderFetcher: ( path: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, searchDate?: Date, delta?: number, ) => Promise>; transferFetcher: ( path: string, payto_uri?: string, verified?: string, position?: string, delta?: number, ) => Promise>; templateFetcher: ( path: string, position?: string, delta?: number, ) => Promise>; webhookFetcher: ( path: string, position?: string, delta?: number, ) => Promise>; } interface useBackendBaseRequestType { request: ( path: string, options?: RequestOptions, ) => Promise>; } type YesOrNo = "yes" | "no"; /** * * @param root the request is intended to the base URL and no the instance URL * @returns request handler to */ export function useBackendBaseRequest(): useBackendBaseRequestType { const { url: backend, token } = useBackendContext(); const { request: requestHandler } = useApiContext(); const request = useCallback( function requestImpl( path: string, options: RequestOptions = {}, ): Promise> { return requestHandler(backend, path, { token, ...options }); }, [backend, token], ); return { request }; } export function useBackendInstanceRequest(): useBackendInstanceRequestType { const { url: baseUrl, token: baseToken } = 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 request = useCallback( function requestImpl( path: string, options: RequestOptions = {}, ): Promise> { return requestHandler(backend, path, { token, ...options }); }, [backend, token], ); const multiFetcher = useCallback( function multiFetcherImpl( paths: string[], ): Promise[]> { return Promise.all( paths.map((path) => requestHandler(backend, path, { token })), ); }, [backend, token], ); const fetcher = useCallback( function fetcherImpl(path: string): Promise> { return requestHandler(backend, path, { token }); }, [backend, token], ); const orderFetcher = useCallback( function orderFetcherImpl( path: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, searchDate?: Date, delta?: number, ): Promise> { const date_ms = delta && delta < 0 && searchDate ? searchDate.getTime() + 1 : searchDate?.getTime(); const params: any = {}; if (paid !== undefined) params.paid = paid; if (delta !== undefined) params.delta = delta; 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 }); }, [backend, token], ); const reserveDetailFetcher = useCallback( function reserveDetailFetcherImpl( path: string, ): Promise> { return requestHandler(backend, path, { params: { tips: "yes", }, token, }); }, [backend, token], ); const tipsDetailFetcher = useCallback( function tipsDetailFetcherImpl( path: string, ): Promise> { return requestHandler(backend, path, { params: { pickups: "yes", }, token, }); }, [backend, token], ); const transferFetcher = useCallback( function transferFetcherImpl( path: string, payto_uri?: string, verified?: string, position?: string, delta?: number, ): Promise> { const params: any = {}; if (payto_uri !== undefined) params.payto_uri = payto_uri; if (verified !== undefined) params.verified = verified; if (delta !== undefined) { params.limit = delta; } if (position !== undefined) params.offset = position; return requestHandler(backend, path, { params, token }); }, [backend, token], ); const templateFetcher = useCallback( function templateFetcherImpl( path: string, position?: string, delta?: number, ): Promise> { const params: any = {}; if (delta !== undefined) { params.limit = delta; } if (position !== undefined) params.offset = position; return requestHandler(backend, path, { params, token }); }, [backend, token], ); const webhookFetcher = useCallback( function webhookFetcherImpl( path: string, position?: string, delta?: number, ): Promise> { const params: any = {}; if (delta !== undefined) { params.limit = delta; } if (position !== undefined) params.offset = position; return requestHandler(backend, path, { params, token }); }, [backend, token], ); return { request, fetcher, multiFetcher, orderFetcher, reserveDetailFetcher, tipsDetailFetcher, transferFetcher, templateFetcher, webhookFetcher, }; }