From b58d53dd93bd8e97aecc28fae788c5c7051fd73d Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 5 Nov 2023 18:04:22 -0300 Subject: sharing components in web-util --- packages/aml-backoffice-ui/src/hooks/useBackend.ts | 27 +++-- .../aml-backoffice-ui/src/hooks/useCaseDetails.ts | 103 ++++------------- packages/aml-backoffice-ui/src/hooks/useCases.ts | 126 +++++++++------------ packages/aml-backoffice-ui/src/hooks/useOfficer.ts | 20 ++-- 4 files changed, 103 insertions(+), 173 deletions(-) (limited to 'packages/aml-backoffice-ui/src/hooks') diff --git a/packages/aml-backoffice-ui/src/hooks/useBackend.ts b/packages/aml-backoffice-ui/src/hooks/useBackend.ts index b9d66fca6..95277a915 100644 --- a/packages/aml-backoffice-ui/src/hooks/useBackend.ts +++ b/packages/aml-backoffice-ui/src/hooks/useBackend.ts @@ -1,3 +1,4 @@ +import { canonicalizeBaseUrl } from "@gnu-taler/taler-util"; import { HttpResponseOk, RequestOptions, @@ -5,9 +6,6 @@ import { } from "@gnu-taler/web-util/browser"; import { useCallback } from "preact/hooks"; import { uiSettings } from "../settings.js"; -import { canonicalizeBaseUrl } from "@gnu-taler/taler-util"; -import { useOfficer } from "./useOfficer.js"; -import { buildQuerySignature } from "../account.js"; interface useBackendType { request: ( @@ -35,7 +33,7 @@ export function usePublicBackend(): useBackendType { ); const fetcher = useCallback( - function fetcherImpl([endpoint, talerAmlOfficerSignature]: [string,string]): Promise> { + function fetcherImpl([endpoint, talerAmlOfficerSignature]: [string, string]): Promise> { return requestHandler(baseUrl, endpoint, { talerAmlOfficerSignature }); @@ -66,18 +64,29 @@ export function usePublicBackend(): useBackendType { export function getInitialBackendBaseURL(): string { const overrideUrl = typeof localStorage !== "undefined" - ? localStorage.getItem("exchange-aml-base-url") + ? localStorage.getItem("exchange-base-url") : undefined; + + let result: string; + if (!overrideUrl) { //normal path if (!uiSettings.backendBaseURL) { console.error( "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'", ); - return canonicalizeBaseUrl(window.origin); + result = window.origin + } else { + result = uiSettings.backendBaseURL; } - return canonicalizeBaseUrl(uiSettings.backendBaseURL); + } else { + // testing/development path + result = overrideUrl + } + try { + return canonicalizeBaseUrl(result) + } catch (e) { + //fall back + return canonicalizeBaseUrl(window.origin) } - // testing/development path - return canonicalizeBaseUrl(overrideUrl); } diff --git a/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts b/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts index 980a35f21..9db1e2aec 100644 --- a/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts +++ b/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts @@ -1,34 +1,29 @@ import { HttpResponse, - HttpResponseOk, - RequestError + HttpResponseOk } from "@gnu-taler/web-util/browser"; import { AmlExchangeBackend } from "../types.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 +import { AmountString, OfficerAccount, PaytoString, TalerExchangeApi, TalerExchangeResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; import _useSWR, { SWRHook, useSWRConfig } from "swr"; -import { AccountId } from "../account.js"; +import { useExchangeApiContext } from "../context/config.js"; import { usePublicBackend } from "./useBackend.js"; +import { useOfficer } from "./useOfficer.js"; const useSWR = _useSWR as unknown as SWRHook; -export function useCaseDetails( - account: AccountId, - paytoHash: string, - signature: string | undefined, -): HttpResponse< - AmlExchangeBackend.AmlDecisionDetails, - AmlExchangeBackend.AmlError -> { - const { fetcher } = usePublicBackend(); +export function useCaseDetails(paytoHash: string) { + const officer = useOfficer(); + const session = officer.state === "ready" ? officer.account : undefined; - const { data, error } = useSWR< - HttpResponseOk, - RequestError ->( [ - `aml/${account}/decision/${(paytoHash)}`, - signature, -], -fetcher, { + const { api } = useExchangeApiContext(); + + async function fetcher([officer, account]: [OfficerAccount, PaytoString]) { + return await api.getDecisionDetails(officer, account) + } + + const { data, error } = useSWR, TalerHttpError>( + !session ? undefined : [session, paytoHash], fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, @@ -41,11 +36,11 @@ fetcher, { }); if (data) return data; - if (error) return error.cause; - return { loading: true }; + if (error) return error; + return undefined; } -const example1: AmlExchangeBackend.AmlDecisionDetails = { +const example1: TalerExchangeApi.AmlDecisionDetails = { aml_history: [ { justification: "Lack of documentation", @@ -54,7 +49,7 @@ const example1: AmlExchangeBackend.AmlDecisionDetails = { t_s: Date.now() / 1000, }, new_state: 2, - new_threshold: "USD:0", + new_threshold: "USD:0" as AmountString, }, { justification: "Doing a transfer of high amount", @@ -63,7 +58,7 @@ const example1: AmlExchangeBackend.AmlDecisionDetails = { t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 6, }, new_state: 1, - new_threshold: "USD:2000", + new_threshold: "USD:2000" as AmountString, }, { justification: "Account is known to the system", @@ -72,7 +67,7 @@ const example1: AmlExchangeBackend.AmlDecisionDetails = { t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 9, }, new_state: 0, - new_threshold: "USD:100", + new_threshold: "USD:100" as AmountString, }, ], kyc_attributes: [ @@ -103,60 +98,4 @@ const example1: AmlExchangeBackend.AmlDecisionDetails = { ], }; -export const exampleResponse: HttpResponse = { - ok: true, - data: example1, -} - - -export function useAmlCasesAPI(): AmlCaseAPI { - const { request } = usePublicBackend(); - const mutateAll = useMatchMutate(); - - const updateDecision = async ( - officer: AccountId, - data: AmlExchangeBackend.AmlDecision, - ): Promise> => { - const res = await request(`aml/${officer}/decision`, { - method: "POST", - data, - contentType: "json", - }); - await mutateAll(/.*aml.*/); - return res; - }; - - return { - updateDecision, - }; -} - -export interface AmlCaseAPI { - updateDecision: ( - officer: AccountId, - data: AmlExchangeBackend.AmlDecision, - ) => Promise>; -} - -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) => { - return mutate(key, value, true); - }); - return Promise.all(mutations); - }; -} diff --git a/packages/aml-backoffice-ui/src/hooks/useCases.ts b/packages/aml-backoffice-ui/src/hooks/useCases.ts index c07bd5f18..2a133f46d 100644 --- a/packages/aml-backoffice-ui/src/hooks/useCases.ts +++ b/packages/aml-backoffice-ui/src/hooks/useCases.ts @@ -1,16 +1,13 @@ -import { useEffect, useState } from "preact/hooks"; +import { useState } from "preact/hooks"; -import { AmlExchangeBackend } from "../types.js"; import { - HttpResponse, - HttpResponseOk, - HttpResponsePaginated, - RequestError, + HttpResponsePaginated } from "@gnu-taler/web-util/browser"; +import { AmlExchangeBackend } from "../types.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 +import { AmountString, OfficerAccount, TalerExchangeApi, TalerExchangeResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; import _useSWR, { SWRHook } from "swr"; -import { usePublicBackend } from "./useBackend.js"; -import { AccountId, buildQuerySignature } from "../account.js"; +import { useExchangeApiContext } from "../context/config.js"; import { useOfficer } from "./useOfficer.js"; const useSWR = _useSWR as unknown as SWRHook; @@ -22,59 +19,49 @@ const MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1; * @param args * @returns */ -export function useCases( - account: AccountId, - state: AmlExchangeBackend.AmlState, - signature: string | undefined, -): HttpResponsePaginated< - AmlExchangeBackend.AmlRecords, - AmlExchangeBackend.AmlError -> { - const { paginatedFetcher } = usePublicBackend(); +export function useCases(state: AmlExchangeBackend.AmlState) { + const officer = useOfficer(); + const session = officer.state === "ready" ? officer.account : undefined; + const { api } = useExchangeApiContext(); - const [page, setPage] = useState(1); + const [offset, setOffet] = useState(); + + async function fetcher([officer, state, offset]: [OfficerAccount, AmlExchangeBackend.AmlState, string | undefined]) { + return await api.getDecisionsByState(officer, state, { + order: "asc", offset, limit: MAX_RESULT_SIZE + }) + } - const { - data: afterData, - error: afterError, - isValidating: loadingAfter, - } = useSWR< - HttpResponseOk, - RequestError - >( - [ - `aml/${account}/decisions/${AmlExchangeBackend.AmlState[state]}`, - page, - PAGE_SIZE, - signature, - ], - paginatedFetcher, + const { data, error } = useSWR, TalerHttpError>( + !session ? undefined : [session, state, offset], + fetcher, ); - const [lastAfter, setLastAfter] = useState< - HttpResponse - >({ loading: true }); + // const [lastAfter, setLastAfter] = useState< + // HttpResponse + // >({ loading: true }); - useEffect(() => { - if (afterData) setLastAfter(afterData); - }, [afterData]); + // useEffect(() => { + // if (afterData) setLastAfter(afterData); + // }, [afterData]); - if (afterError) { - return afterError.cause; - } + // if (afterError) { + // return afterError.cause; + // } // if the query returns less that we ask, then we have reach the end or beginning - const isReachingEnd = - afterData && afterData.data && afterData.data.records.length < PAGE_SIZE; - const isReachingStart = false; + const isLastPage = + data && data.type === "ok" && data.body.records.length < PAGE_SIZE; + const isFirstPage = !offset; const pagination = { - isReachingEnd, - isReachingStart, + isLastPage, + isFirstPage, loadMore: () => { - if (!afterData || isReachingEnd) return; - if (afterData.data && afterData.data.records.length < MAX_RESULT_SIZE) { - setPage(page + 1); + if (isLastPage || data?.type !== "ok") return; + const list = data.body.records + if (list.length < MAX_RESULT_SIZE) { + // setOffset(list[list.length-1].account_name); } }, loadMorePrev: () => { @@ -82,65 +69,62 @@ export function useCases( }, }; - const records = !afterData - ? [] - : ((afterData ?? lastAfter).data ?? { records: [] }).records; - if (loadingAfter) return { loading: true, data: { records } }; - if (afterData) { - return { ok: true, data: { records }, ...pagination }; + // const public_accountslist = data?.type !== "ok" ? [] : data.body.public_accounts; + if (data) { + if (data.type === "fail") { + return { data } + } + return { data, pagination } + } + if (error) { + return error; } - return { loading: true }; + return undefined; } -const example1: AmlExchangeBackend.AmlRecords = { +const example1: TalerExchangeApi.AmlRecords = { records: [ { current_state: 0, h_payto: "QWEQWEQWEQWEWQE", rowid: 1, - threshold: "USD 100", + threshold: "USD 100" as AmountString, }, { current_state: 1, h_payto: "ASDASDASD", rowid: 1, - threshold: "USD 100", + threshold: "USD 100" as AmountString, }, { current_state: 2, h_payto: "ZXCZXCZXCXZC", rowid: 1, - threshold: "USD 1000", + threshold: "USD 1000" as AmountString, }, { current_state: 0, h_payto: "QWEQWEQWEQWEWQE", rowid: 1, - threshold: "USD 100", + threshold: "USD 100" as AmountString, }, { current_state: 1, h_payto: "ASDASDASD", rowid: 1, - threshold: "USD 100", + threshold: "USD 100" as AmountString, }, { current_state: 2, h_payto: "ZXCZXCZXCXZC", rowid: 1, - threshold: "USD 1000", + threshold: "USD 1000" as AmountString, }, ].map((e, idx) => { e.rowid = idx; - e.threshold = `${e.threshold}${idx}`; + e.threshold = `${e.threshold}${idx}` as AmountString; return e; }), }; -export const exampleResponse: HttpResponsePaginated = { - ok: true, - data: example1, - loadMore: () => {}, - loadMorePrev: () => {}, -} diff --git a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts b/packages/aml-backoffice-ui/src/hooks/useOfficer.ts index 4ec43569b..0747170e8 100644 --- a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts +++ b/packages/aml-backoffice-ui/src/hooks/useOfficer.ts @@ -1,16 +1,14 @@ import { AbsoluteTime, Codec, + LockedAccount, + OfficerAccount, buildCodecForObject, codecForAbsoluteTime, codecForString, + createNewOfficerAccount, + unlockOfficerAccount, } from "@gnu-taler/taler-util"; -import { - Account, - LockedAccount, - createNewAccount, - unlockAccount, -} from "../account.js"; import { buildStorageKey, useLocalStorage, @@ -43,7 +41,7 @@ interface OfficerLocked { } interface OfficerReady { state: "ready"; - account: Account; + account: OfficerAccount; forget: () => void; lock: () => void; } @@ -52,7 +50,7 @@ const OFFICER_KEY = buildStorageKey("officer", codecForOfficer()); const ACCOUNT_KEY = "account"; export function useOfficer(): OfficerState { - const accountStorage = useMemoryStorage(ACCOUNT_KEY); + const accountStorage = useMemoryStorage(ACCOUNT_KEY); const officerStorage = useLocalStorage(OFFICER_KEY); const officer = officerStorage.value; @@ -62,13 +60,13 @@ export function useOfficer(): OfficerState { return { state: "not-found", create: async (pwd: string) => { - const { accountId, safe, signingKey } = await createNewAccount(pwd); + const { id, safe, signingKey } = await createNewOfficerAccount(pwd); officerStorage.update({ account: safe, when: AbsoluteTime.now(), }); - accountStorage.update({ accountId, signingKey }); + accountStorage.update({ id, signingKey }); }, }; } @@ -80,7 +78,7 @@ export function useOfficer(): OfficerState { officerStorage.reset(); }, tryUnlock: async (pwd: string) => { - const ac = await unlockAccount(officer.account, pwd); + const ac = await unlockOfficerAccount(officer.account, pwd); accountStorage.update(ac); }, }; -- cgit v1.2.3