diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/hooks/product.ts')
-rw-r--r-- | packages/merchant-backoffice-ui/src/hooks/product.ts | 212 |
1 files changed, 69 insertions, 143 deletions
diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts b/packages/merchant-backoffice-ui/src/hooks/product.ts index c0ace0d32..defda5552 100644 --- a/packages/merchant-backoffice-ui/src/hooks/product.ts +++ b/packages/merchant-backoffice-ui/src/hooks/product.ts @@ -13,165 +13,91 @@ 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, - RequestError, -} from "@gnu-taler/web-util/browser"; -import { useBackendInstanceRequest, useMatchMutate } from "./backend.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 -import _useSWR, { SWRHook, useSWRConfig } from "swr"; -import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { AccessToken, OperationOk, TalerHttpError, TalerMerchantApi, TalerMerchantManagementErrorsByMethod, TalerMerchantManagementResultByMethod, opFixedSuccess } from "@gnu-taler/taler-util"; +import { useState } from "preact/hooks"; +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 ProductAPI { - getProduct: ( - id: string, - ) => Promise<void>; - createProduct: ( - data: TalerMerchantApi.ProductAddDetail, - ) => Promise<void>; - updateProduct: ( - id: string, - data: TalerMerchantApi.ProductPatchDetail, - ) => Promise<void>; - deleteProduct: (id: string) => Promise<void>; - lockProduct: ( - id: string, - data: TalerMerchantApi.LockRequest, - ) => Promise<void>; +type ProductWithId = TalerMerchantApi.ProductDetail & { id: string, serial: number }; +function notUndefined(c: ProductWithId | undefined): c is ProductWithId { + return c !== undefined; } -export function useProductAPI(): ProductAPI { - const mutateAll = useMatchMutate(); - const { mutate } = useSWRConfig(); - - const { request } = useBackendInstanceRequest(); - - const createProduct = async ( - data: TalerMerchantApi.ProductAddDetail, - ): Promise<void> => { - const res = await request(`/private/products`, { - method: "POST", - data, - }); - - return await mutateAll(/.*\/private\/products.*/); - }; - - const updateProduct = async ( - productId: string, - data: TalerMerchantApi.ProductPatchDetail, - ): Promise<void> => { - const r = await request(`/private/products/${productId}`, { - method: "PATCH", - data, - }); +export function revalidateInstanceProducts() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listProductsWithId", + undefined, + { revalidate: true }, + ); +} +export function useInstanceProducts() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useSessionContext(); - return await mutateAll(/.*\/private\/products.*/); - }; + const [offset, setOffset] = useState<number | undefined>(); - const deleteProduct = async (productId: string): Promise<void> => { - await request(`/private/products/${productId}`, { - method: "DELETE", - }); - await mutate([`/private/products`]); - }; - - const lockProduct = async ( - productId: string, - data: TalerMerchantApi.LockRequest, - ): Promise<void> => { - await request(`/private/products/${productId}/lock`, { - method: "POST", - data, + async function fetcher([token, bid]: [AccessToken, number]) { + const list = await instance.listProducts(token, { + limit: PAGINATED_LIST_REQUEST, + offset: bid === undefined ? undefined: String(bid), + order: "dec", }); + if (list.type !== "ok") { + return list; + } + const all: Array<ProductWithId | undefined> = await Promise.all( + list.body.products.map(async (c) => { + const r = await instance.getProductDetails(token, c.product_id); + if (r.type === "fail") { + return undefined; + } + return { ...r.body, id: c.product_id, serial: c.product_serial }; + }), + ); + const products = all.filter(notUndefined); + + return opFixedSuccess({ products }); + } - return await mutateAll(/.*"\/private\/products.*/); - }; - - const getProduct = async ( - productId: string, - ): Promise<void> => { - await request(`/private/products/${productId}`, { - method: "GET", - }); + const { data, error } = useSWR< + OperationOk<{ products: ProductWithId[] }> | + TalerMerchantManagementErrorsByMethod<"listProducts">, + TalerHttpError + >([session.token, offset, "listProductsWithId"], fetcher); - return - }; + if (error) return error; + if (data === undefined) return undefined; + if (data.type !== "ok") return data; - return { createProduct, updateProduct, deleteProduct, lockProduct, getProduct }; + return buildPaginatedResult(data.body.products, offset, setOffset, (d) => d.serial) } -export function useInstanceProducts(): HttpResponse< - (TalerMerchantApi.ProductDetail & WithId)[], - TalerErrorDetail -> { - const { fetcher, multiFetcher } = useBackendInstanceRequest(); - - const { data: list, error: listError } = useSWR< - HttpResponseOk<TalerMerchantApi.InventorySummaryResponse>, - RequestError<TalerErrorDetail> - >([`/private/products`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false, - }); - - const paths = (list?.data.products || []).map( - (p) => `/private/products/${p.product_id}`, +export function revalidateProductDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getProductDetails", + undefined, + { revalidate: true }, ); - const { data: products, error: productError } = useSWR< - HttpResponseOk<TalerMerchantApi.ProductDetail>[], - RequestError<TalerErrorDetail> - >([paths], multiFetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false, - }); - - if (listError) return listError.cause; - if (productError) return productError.cause; - - if (products) { - const dataWithId = products.map((d) => { - //take the id from the queried url - return { - ...d.data, - id: d.info?.url.replace(/.*\/private\/products\//, "") || "", - }; - }); - return { ok: true, data: dataWithId }; - } - return { loading: true }; } +export function useProductDetails(productId: string) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useSessionContext(); + + async function fetcher([pid, token]: [string, AccessToken]) { + return await instance.getProductDetails(token, pid); + } + + const { data, error } = useSWR< + TalerMerchantManagementResultByMethod<"getProductDetails">, + TalerHttpError + >([productId, session.token, "getProductDetails"], fetcher); -export function useProductDetails( - productId: string, -): HttpResponse< - TalerMerchantApi.ProductDetail, - TalerErrorDetail -> { - const { fetcher } = useBackendInstanceRequest(); - - const { data, error, isValidating } = useSWR< - HttpResponseOk<TalerMerchantApi.ProductDetail>, - RequestError<TalerErrorDetail> - >([`/private/products/${productId}`], fetcher, { - 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; } |