diff options
| author | Sebastian <sebasjm@gmail.com> | 2022-12-19 16:25:09 -0300 | 
|---|---|---|
| committer | Sebastian <sebasjm@gmail.com> | 2022-12-19 16:25:09 -0300 | 
| commit | cf7f819685c19adfe6443a6bdd10f3afe10b247d (patch) | |
| tree | 20ace56c90d25a05995dce04432733445646e51e /packages/merchant-backoffice-ui/src/hooks | |
| parent | 45691dc991945d8c0a3d4bc95078bd1af5932927 (diff) | |
templates
Diffstat (limited to 'packages/merchant-backoffice-ui/src/hooks')
| -rw-r--r-- | packages/merchant-backoffice-ui/src/hooks/templates.ts | 280 | 
1 files changed, 280 insertions, 0 deletions
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts b/packages/merchant-backoffice-ui/src/hooks/templates.ts new file mode 100644 index 000000000..3e69d78d0 --- /dev/null +++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts @@ -0,0 +1,280 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +import { MerchantBackend } from "../declaration.js"; +import { useBackendContext } from "../context/backend.js"; +import { +  request, +  HttpResponse, +  HttpError, +  HttpResponseOk, +  HttpResponsePaginated, +  useMatchMutate, +} from "./backend.js"; +import useSWR from "swr"; +import { useInstanceContext } from "../context/instance.js"; +import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js"; +import { useEffect, useState } from "preact/hooks"; + +async function templateFetcher<T>( +  url: string, +  token: string, +  backend: string, +  position?: string, +  delta?: number, +): Promise<HttpResponseOk<T>> { +  const params: any = {}; +  if (delta !== undefined) { +    params.limit = delta; +  } +  if (position !== undefined) params.offset = position; + +  return request<T>(`${backend}${url}`, { token, params }); +} + +export function useTemplateAPI(): TemplateAPI { +  const mutateAll = useMatchMutate(); +  const { url: baseUrl, token: adminToken } = useBackendContext(); +  const { token: instanceToken, id, admin } = useInstanceContext(); + +  const { url, token } = !admin +    ? { +        url: baseUrl, +        token: adminToken, +      } +    : { +        url: `${baseUrl}/instances/${id}`, +        token: instanceToken, +      }; + +  const createTemplate = async ( +    data: MerchantBackend.Template.TemplateAddDetails, +  ): Promise<HttpResponseOk<void>> => { +    const res = await request<void>(`${url}/private/templates`, { +      method: "post", +      token, +      data, +    }); +    await mutateAll(/.*private\/templates.*/); +    return res; +  }; + +  const updateTemplate = async ( +    templateId: string, +    data: MerchantBackend.Template.TemplatePatchDetails, +  ): Promise<HttpResponseOk<void>> => { +    const res = await request<void>(`${url}/private/templates/${templateId}`, { +      method: "patch", +      token, +      data, +    }); +    await mutateAll(/.*private\/templates.*/); +    return res; +  }; + +  const deleteTemplate = async ( +    templateId: string, +  ): Promise<HttpResponseOk<void>> => { +    const res = await request<void>(`${url}/private/templates/${templateId}`, { +      method: "delete", +      token, +    }); +    await mutateAll(/.*private\/templates.*/); +    return res; +  }; + +  const createOrder = async ( +    templateId: string, +    data: MerchantBackend.Template.UsingTemplateDetails, +  ): Promise< +    HttpResponseOk<MerchantBackend.Template.UsingTemplateResponse> +  > => { +    const res = await request<MerchantBackend.Template.UsingTemplateResponse>( +      `${url}/private/templates/${templateId}`, +      { +        method: "post", +        token, +        data, +      }, +    ); +    await mutateAll(/.*private\/templates.*/); +    return res; +  }; + +  return { createTemplate, updateTemplate, deleteTemplate, createOrder }; +} + +export interface TemplateAPI { +  createTemplate: ( +    data: MerchantBackend.Template.TemplateAddDetails, +  ) => Promise<HttpResponseOk<void>>; +  updateTemplate: ( +    id: string, +    data: MerchantBackend.Template.TemplatePatchDetails, +  ) => Promise<HttpResponseOk<void>>; +  deleteTemplate: (id: string) => Promise<HttpResponseOk<void>>; +  createOrder: ( +    id: string, +    data: MerchantBackend.Template.UsingTemplateDetails, +  ) => Promise<HttpResponseOk<MerchantBackend.Template.UsingTemplateResponse>>; +} + +export interface InstanceTemplateFilter { +  //FIXME: add filter to the template list +  position?: string; +} + +export function useInstanceTemplates( +  args?: InstanceTemplateFilter, +  updatePosition?: (id: string) => void, +): HttpResponsePaginated<MerchantBackend.Template.TemplateSummaryResponse> { +  const { url: baseUrl, token: baseToken } = useBackendContext(); +  const { token: instanceToken, id, admin } = useInstanceContext(); + +  const { url, token } = !admin +    ? { url: baseUrl, token: baseToken } +    : { url: `${baseUrl}/instances/${id}`, token: instanceToken }; + +  // const [pageBefore, setPageBefore] = useState(1); +  const [pageAfter, setPageAfter] = useState(1); + +  const totalAfter = pageAfter * PAGE_SIZE; +  // const totalBefore = args?.position !== undefined ? pageBefore * PAGE_SIZE : 0; + +  /** +   * FIXME: this can be cleaned up a little +   * +   * the logic of double query should be inside the orderFetch so from the hook perspective and cache +   * is just one query and one error status +   */ +  // const { +  //   data: beforeData, +  //   error: beforeError, +  //   isValidating: loadingBefore, +  // } = useSWR<HttpResponseOk<MerchantBackend.Template.TemplateSummaryResponse>, HttpError>( +  //   [ +  //     `/private/templates`, +  //     token, +  //     url, +  //     args?.position, +  //     totalBefore, +  //   ], +  //   templateFetcher, +  // ); +  const { +    data: afterData, +    error: afterError, +    isValidating: loadingAfter, +  } = useSWR< +    HttpResponseOk<MerchantBackend.Template.TemplateSummaryResponse>, +    HttpError +  >( +    [`/private/templates`, token, url, args?.position, -totalAfter], +    templateFetcher, +  ); + +  //this will save last result +  // const [lastBefore, setLastBefore] = useState< +  //   HttpResponse<MerchantBackend.Template.TemplateSummaryResponse> +  // >({ loading: true }); +  const [lastAfter, setLastAfter] = useState< +    HttpResponse<MerchantBackend.Template.TemplateSummaryResponse> +  >({ loading: true }); +  useEffect(() => { +    if (afterData) setLastAfter(afterData); +    // if (beforeData) setLastBefore(beforeData); +  }, [afterData /*, beforeData*/]); + +  // if (beforeError) return beforeError; +  if (afterError) return afterError; + +  // if the query returns less that we ask, then we have reach the end or beginning +  const isReachingEnd = +    afterData && afterData.data.templates.length < totalAfter; +  const isReachingStart = false; +  // args?.position === undefined +  // || +  // (beforeData && beforeData.data.templates.length < totalBefore); + +  const pagination = { +    isReachingEnd, +    isReachingStart, +    loadMore: () => { +      if (!afterData || isReachingEnd) return; +      if (afterData.data.templates.length < MAX_RESULT_SIZE) { +        setPageAfter(pageAfter + 1); +      } else { +        const from = `${ +          afterData.data.templates[afterData.data.templates.length - 1] +            .template_id +        }`; +        if (from && updatePosition) updatePosition(from); +      } +    }, +    loadMorePrev: () => { +      // if (!beforeData || isReachingStart) return; +      // if (beforeData.data.templates.length < MAX_RESULT_SIZE) { +      //   setPageBefore(pageBefore + 1); +      // } else if (beforeData) { +      //   const from = `${beforeData.data.templates[beforeData.data.templates.length - 1] +      //     .template_id +      //     }`; +      //   if (from && updatePosition) updatePosition(from); +      // } +    }, +  }; + +  const templates = !afterData ? [] : (afterData || lastAfter).data.templates; +  // const templates = +  //   !beforeData || !afterData +  //     ? [] +  //     : (beforeData || lastBefore).data.templates +  //       .slice() +  //       .reverse() +  //       .concat((afterData || lastAfter).data.templates); +  if (loadingAfter /* || loadingBefore */) +    return { loading: true, data: { templates } }; +  if (/*beforeData &&*/ afterData) { +    return { ok: true, data: { templates }, ...pagination }; +  } +  return { loading: true }; +} + +export function useTemplateDetails( +  templateId: string, +): HttpResponse<MerchantBackend.Template.TemplateDetails> { +  const { url: baseUrl, token: baseToken } = useBackendContext(); +  const { token: instanceToken, id, admin } = useInstanceContext(); + +  const { url, token } = !admin +    ? { url: baseUrl, token: baseToken } +    : { url: `${baseUrl}/instances/${id}`, token: instanceToken }; + +  const { data, error, isValidating } = useSWR< +    HttpResponseOk<MerchantBackend.Template.TemplateDetails>, +    HttpError +  >([`/private/templates/${templateId}`, token, url], templateFetcher, { +    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; +  return { loading: true }; +}  | 
