aboutsummaryrefslogtreecommitdiff
path: root/packages/merchant-backoffice-ui/src/hooks
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-09-04 14:17:55 -0300
committerSebastian <sebasjm@gmail.com>2023-09-04 14:17:55 -0300
commite1d86816a7c07cb8ca2d54676d5cdbbe513f2ba7 (patch)
treed4ed5506ab3550a7e9b1a082d7ffeddf9f3c4954 /packages/merchant-backoffice-ui/src/hooks
parentff20c3e25e076c24f7cb93eabe58b6f934f51f35 (diff)
downloadwallet-core-e1d86816a7c07cb8ca2d54676d5cdbbe513f2ba7.tar.xz
backoffcie new version, lot of changes
Diffstat (limited to 'packages/merchant-backoffice-ui/src/hooks')
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/backend.ts111
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/bank.ts217
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/index.ts23
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/instance.test.ts6
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/instance.ts5
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/otp.ts223
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/reserve.test.ts114
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/reserves.ts64
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/urls.ts34
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/useSettings.ts37
10 files changed, 662 insertions, 172 deletions
diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts
index 145a366f6..ecd34df6d 100644
--- a/packages/merchant-backoffice-ui/src/hooks/backend.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts
@@ -33,8 +33,9 @@ import {
} from "@gnu-taler/web-util/browser";
import { useApiContext } from "@gnu-taler/web-util/browser";
+
export function useMatchMutate(): (
- re: RegExp,
+ re?: RegExp,
value?: unknown,
) => Promise<any> {
const { cache, mutate } = useSWRConfig();
@@ -45,13 +46,19 @@ export function useMatchMutate(): (
);
}
- 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 function matchRegexMutate(re?: RegExp) {
+ return mutate((key) => {
+ // evict if no key or regex === all
+ if (!key || !re) return true
+ // match string
+ if (typeof key === 'string' && re.test(key)) return true
+ // record or object have the path at [0]
+ if (typeof key === 'object' && re.test(key[0])) return true
+ //key didn't match regex
+ return false
+ }, undefined, {
+ revalidate: true,
});
- return Promise.all(mutations);
};
}
@@ -106,32 +113,32 @@ interface useBackendInstanceRequestType {
) => Promise<HttpResponseOk<T>>;
fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
reserveDetailFetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
- tipsDetailFetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
- multiFetcher: <T>(url: string[]) => Promise<HttpResponseOk<T>[]>;
+ rewardsDetailFetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
+ multiFetcher: <T>(params: [url: string[]]) => Promise<HttpResponseOk<T>[]>;
orderFetcher: <T>(
- endpoint: string,
- paid?: YesOrNo,
- refunded?: YesOrNo,
- wired?: YesOrNo,
- searchDate?: Date,
- delta?: number,
+ params: [endpoint: string,
+ paid?: YesOrNo,
+ refunded?: YesOrNo,
+ wired?: YesOrNo,
+ searchDate?: Date,
+ delta?: number,]
) => Promise<HttpResponseOk<T>>;
transferFetcher: <T>(
- endpoint: string,
- payto_uri?: string,
- verified?: string,
- position?: string,
- delta?: number,
+ params: [endpoint: string,
+ payto_uri?: string,
+ verified?: string,
+ position?: string,
+ delta?: number,]
) => Promise<HttpResponseOk<T>>;
templateFetcher: <T>(
- endpoint: string,
- position?: string,
- delta?: number,
+ params: [endpoint: string,
+ position?: string,
+ delta?: number]
) => Promise<HttpResponseOk<T>>;
webhookFetcher: <T>(
- endpoint: string,
- position?: string,
- delta?: number,
+ params: [endpoint: string,
+ position?: string,
+ delta?: number]
) => Promise<HttpResponseOk<T>>;
}
interface useBackendBaseRequestType {
@@ -147,7 +154,7 @@ export function useCredentialsChecker() {
const { request } = useApiContext();
//check against instance details endpoint
//while merchant backend doesn't have a login endpoint
- return async function testLogin(
+ async function testLogin(
instance: string,
token: string,
): Promise<{
@@ -167,6 +174,7 @@ export function useCredentialsChecker() {
return { valid: false, cause: ErrorType.UNEXPECTED };
}
};
+ return testLogin
}
/**
@@ -212,8 +220,9 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
const multiFetcher = useCallback(
function multiFetcherImpl<T>(
- endpoints: string[],
+ args: [endpoints: string[]],
): Promise<HttpResponseOk<T>[]> {
+ const [endpoints] = args
return Promise.all(
endpoints.map((endpoint) =>
requestHandler<T>(baseUrl, endpoint, { token }),
@@ -232,13 +241,14 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
const orderFetcher = useCallback(
function orderFetcherImpl<T>(
- endpoint: string,
- paid?: YesOrNo,
- refunded?: YesOrNo,
- wired?: YesOrNo,
- searchDate?: Date,
- delta?: number,
+ args: [endpoint: string,
+ paid?: YesOrNo,
+ refunded?: YesOrNo,
+ wired?: YesOrNo,
+ searchDate?: Date,
+ delta?: number,]
): Promise<HttpResponseOk<T>> {
+ const [endpoint, paid, refunded, wired, searchDate, delta] = args
const date_s =
delta && delta < 0 && searchDate
? (searchDate.getTime() / 1000) + 1
@@ -260,7 +270,7 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
): Promise<HttpResponseOk<T>> {
return requestHandler<T>(baseUrl, endpoint, {
params: {
- tips: "yes",
+ rewards: "yes",
},
token,
});
@@ -268,8 +278,8 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
[baseUrl, token],
);
- const tipsDetailFetcher = useCallback(
- function tipsDetailFetcherImpl<T>(
+ const rewardsDetailFetcher = useCallback(
+ function rewardsDetailFetcherImpl<T>(
endpoint: string,
): Promise<HttpResponseOk<T>> {
return requestHandler<T>(baseUrl, endpoint, {
@@ -284,12 +294,13 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
const transferFetcher = useCallback(
function transferFetcherImpl<T>(
- endpoint: string,
- payto_uri?: string,
- verified?: string,
- position?: string,
- delta?: number,
+ args: [endpoint: string,
+ payto_uri?: string,
+ verified?: string,
+ position?: string,
+ delta?: number,]
): Promise<HttpResponseOk<T>> {
+ const [endpoint, payto_uri, verified, position, delta] = args
const params: any = {};
if (payto_uri !== undefined) params.payto_uri = payto_uri;
if (verified !== undefined) params.verified = verified;
@@ -305,10 +316,11 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
const templateFetcher = useCallback(
function templateFetcherImpl<T>(
- endpoint: string,
- position?: string,
- delta?: number,
+ args: [endpoint: string,
+ position?: string,
+ delta?: number,]
): Promise<HttpResponseOk<T>> {
+ const [endpoint, position, delta] = args
const params: any = {};
if (delta !== undefined) {
params.limit = delta;
@@ -322,10 +334,11 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
const webhookFetcher = useCallback(
function webhookFetcherImpl<T>(
- endpoint: string,
- position?: string,
- delta?: number,
+ args: [endpoint: string,
+ position?: string,
+ delta?: number,]
): Promise<HttpResponseOk<T>> {
+ const [endpoint, position, delta] = args
const params: any = {};
if (delta !== undefined) {
params.limit = delta;
@@ -343,7 +356,7 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {
multiFetcher,
orderFetcher,
reserveDetailFetcher,
- tipsDetailFetcher,
+ rewardsDetailFetcher,
transferFetcher,
templateFetcher,
webhookFetcher,
diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts b/packages/merchant-backoffice-ui/src/hooks/bank.ts
new file mode 100644
index 000000000..03b064646
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts
@@ -0,0 +1,217 @@
+/*
+ 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 {
+ 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";
+
+// FIX default import https://github.com/microsoft/TypeScript/issues/49189
+import _useSWR, { SWRHook } from "swr";
+const useSWR = _useSWR as unknown as SWRHook;
+
+// const MOCKED_ACCOUNTS: Record<string, MerchantBackend.BankAccounts.AccountAddDetails> = {
+// "hwire1": {
+// h_wire: "hwire1",
+// payto_uri: "payto://fake/iban/123",
+// salt: "qwe",
+// },
+// "hwire2": {
+// h_wire: "hwire2",
+// payto_uri: "payto://fake/iban/123",
+// salt: "qwe2",
+// },
+// }
+
+export function useBankAccountAPI(): BankAccountAPI {
+ const mutateAll = useMatchMutate();
+ const { request } = useBackendInstanceRequest();
+
+ const createBankAccount = async (
+ data: MerchantBackend.BankAccounts.AccountAddDetails,
+ ): Promise<HttpResponseOk<void>> => {
+ // MOCKED_ACCOUNTS[data.h_wire] = data
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/accounts`, {
+ method: "POST",
+ data,
+ });
+ await mutateAll(/.*private\/accounts.*/);
+ return res;
+ };
+
+ const updateBankAccount = async (
+ h_wire: string,
+ data: MerchantBackend.BankAccounts.AccountPatchDetails,
+ ): Promise<HttpResponseOk<void>> => {
+ // MOCKED_ACCOUNTS[h_wire].credit_facade_credentials = data.credit_facade_credentials
+ // MOCKED_ACCOUNTS[h_wire].credit_facade_url = data.credit_facade_url
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/accounts/${h_wire}`, {
+ method: "PATCH",
+ data,
+ });
+ await mutateAll(/.*private\/accounts.*/);
+ return res;
+ };
+
+ const deleteBankAccount = async (
+ h_wire: string,
+ ): Promise<HttpResponseOk<void>> => {
+ // delete MOCKED_ACCOUNTS[h_wire]
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/accounts/${h_wire}`, {
+ method: "DELETE",
+ });
+ await mutateAll(/.*private\/accounts.*/);
+ return res;
+ };
+
+ return {
+ createBankAccount,
+ updateBankAccount,
+ deleteBankAccount,
+ };
+}
+
+export interface BankAccountAPI {
+ createBankAccount: (
+ data: MerchantBackend.BankAccounts.AccountAddDetails,
+ ) => Promise<HttpResponseOk<void>>;
+ updateBankAccount: (
+ id: string,
+ data: MerchantBackend.BankAccounts.AccountPatchDetails,
+ ) => Promise<HttpResponseOk<void>>;
+ deleteBankAccount: (id: string) => Promise<HttpResponseOk<void>>;
+}
+
+export interface InstanceBankAccountFilter {
+}
+
+export function useInstanceBankAccounts(
+ args?: InstanceBankAccountFilter,
+ updatePosition?: (id: string) => void,
+): HttpResponsePaginated<
+ MerchantBackend.BankAccounts.AccountsSummaryResponse,
+ MerchantBackend.ErrorDetail
+> {
+ // return {
+ // ok: true,
+ // loadMore() { },
+ // loadMorePrev() { },
+ // data: {
+ // accounts: Object.values(MOCKED_ACCOUNTS).map(e => ({
+ // ...e,
+ // active: true,
+ // }))
+ // }
+ // }
+ const { fetcher } = useBackendInstanceRequest();
+
+ const [pageAfter, setPageAfter] = useState(1);
+
+ const totalAfter = pageAfter * PAGE_SIZE;
+ const {
+ data: afterData,
+ error: afterError,
+ isValidating: loadingAfter,
+ } = useSWR<
+ HttpResponseOk<MerchantBackend.BankAccounts.AccountsSummaryResponse>,
+ RequestError<MerchantBackend.ErrorDetail>
+ >([`/private/accounts`], fetcher);
+
+ const [lastAfter, setLastAfter] = useState<
+ HttpResponse<
+ MerchantBackend.BankAccounts.AccountsSummaryResponse,
+ MerchantBackend.ErrorDetail
+ >
+ >({ loading: true });
+ useEffect(() => {
+ if (afterData) setLastAfter(afterData);
+ }, [afterData /*, beforeData*/]);
+
+ 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.accounts.length < totalAfter;
+ const isReachingStart = false;
+
+ const pagination = {
+ isReachingEnd,
+ isReachingStart,
+ loadMore: () => {
+ if (!afterData || isReachingEnd) return;
+ if (afterData.data.accounts.length < MAX_RESULT_SIZE) {
+ setPageAfter(pageAfter + 1);
+ } else {
+ const from = `${afterData.data.accounts[afterData.data.accounts.length - 1]
+ .h_wire
+ }`;
+ if (from && updatePosition) updatePosition(from);
+ }
+ },
+ loadMorePrev: () => {
+ },
+ };
+
+ const accounts = !afterData ? [] : (afterData || lastAfter).data.accounts;
+ if (loadingAfter /* || loadingBefore */)
+ return { loading: true, data: { accounts } };
+ if (/*beforeData &&*/ afterData) {
+ return { ok: true, data: { accounts }, ...pagination };
+ }
+ return { loading: true };
+}
+
+export function useBankAccountDetails(
+ h_wire: string,
+): HttpResponse<
+ MerchantBackend.BankAccounts.BankAccountEntry,
+ MerchantBackend.ErrorDetail
+> {
+ // return {
+ // ok: true,
+ // data: {
+ // ...MOCKED_ACCOUNTS[h_wire],
+ // active: true,
+ // }
+ // }
+ const { fetcher } = useBackendInstanceRequest();
+
+ const { data, error, isValidating } = useSWR<
+ HttpResponseOk<MerchantBackend.BankAccounts.BankAccountEntry>,
+ RequestError<MerchantBackend.ErrorDetail>
+ >([`/private/accounts/${h_wire}`], 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 };
+}
diff --git a/packages/merchant-backoffice-ui/src/hooks/index.ts b/packages/merchant-backoffice-ui/src/hooks/index.ts
index b77b9dea8..79b22304a 100644
--- a/packages/merchant-backoffice-ui/src/hooks/index.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/index.ts
@@ -19,9 +19,10 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { StateUpdater, useCallback, useState } from "preact/hooks";
+import { StateUpdater, useCallback, useEffect, useState } from "preact/hooks";
import { ValueOrFunction } from "../utils/types.js";
import { useMemoryStorage } from "@gnu-taler/web-util/browser";
+import { useMatchMutate } from "./backend.js";
const calculateRootPath = () => {
const rootPath =
@@ -56,8 +57,22 @@ export function useBackendDefaultToken(
): [string | undefined, ((d: string | undefined) => void)] {
// uncomment for testing
initialValue = "secret-token:secret" as string | undefined
- const { update, value } = useMemoryStorage(`backend-token`, initialValue)
- return [value, update];
+ const { update: setToken, value: token, reset } = useMemoryStorage(`backend-token`, initialValue)
+ const clearCache = useMatchMutate()
+ useEffect(() => {
+ clearCache()
+ }, [token])
+
+ function updateToken(
+ value: (string | undefined)
+ ): void {
+ if (value === undefined) {
+ reset()
+ } else {
+ setToken(value)
+ }
+ }
+ return [token, updateToken];
}
export function useBackendInstanceToken(
@@ -73,14 +88,12 @@ export function useBackendInstanceToken(
function updateToken(
value: (string | undefined)
): void {
- console.log("seeting token", value)
if (value === undefined) {
reset()
} else {
setToken(value)
}
}
- console.log("token", token)
return [token, updateToken];
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
index f78de85dd..d15b3f6d7 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
@@ -113,7 +113,7 @@ describe("instance api interaction with details", () => {
name: "instance_name",
auth: {
method: "token",
- token: "not-secret",
+ // token: "not-secret",
},
} as MerchantBackend.Instances.QueryInstancesResponse,
});
@@ -154,7 +154,7 @@ describe("instance api interaction with details", () => {
name: "instance_name",
auth: {
method: "token",
- token: "secret",
+ // token: "secret",
},
} as MerchantBackend.Instances.QueryInstancesResponse,
});
@@ -190,7 +190,7 @@ describe("instance api interaction with details", () => {
name: "instance_name",
auth: {
method: "token",
- token: "not-secret",
+ // token: "not-secret",
},
} as MerchantBackend.Instances.QueryInstancesResponse,
});
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts
index eae65d64c..32ed30c6f 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -198,6 +198,7 @@ export function useInstanceDetails(): HttpResponse<
revalidateOnFocus: false,
revalidateOnReconnect: false,
refreshWhenOffline: false,
+ revalidateIfStale: false,
errorRetryCount: 0,
errorRetryInterval: 1,
shouldRetryOnError: false,
@@ -211,7 +212,7 @@ export function useInstanceDetails(): HttpResponse<
type KYCStatus =
| { type: "ok" }
- | { type: "redirect"; status: MerchantBackend.Instances.AccountKycRedirects };
+ | { type: "redirect"; status: MerchantBackend.KYC.AccountKycRedirects };
export function useInstanceKYCDetails(): HttpResponse<
KYCStatus,
@@ -220,7 +221,7 @@ export function useInstanceKYCDetails(): HttpResponse<
const { fetcher } = useBackendInstanceRequest();
const { data, error } = useSWR<
- HttpResponseOk<MerchantBackend.Instances.AccountKycRedirects>,
+ HttpResponseOk<MerchantBackend.KYC.AccountKycRedirects>,
RequestError<MerchantBackend.ErrorDetail>
>([`/private/kyc`], fetcher, {
refreshInterval: 60 * 1000,
diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts b/packages/merchant-backoffice-ui/src/hooks/otp.ts
new file mode 100644
index 000000000..3544b4881
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts
@@ -0,0 +1,223 @@
+/*
+ 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 {
+ 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";
+
+// FIX default import https://github.com/microsoft/TypeScript/issues/49189
+import _useSWR, { SWRHook } from "swr";
+const useSWR = _useSWR as unknown as SWRHook;
+
+const MOCKED_DEVICES: Record<string, MerchantBackend.OTP.OtpDeviceAddDetails> = {
+ "1": {
+ otp_description: "first device",
+ otp_algorithm: 1,
+ otp_device_id: "1",
+ otp_key: "123",
+ },
+ "2": {
+ otp_description: "second device",
+ otp_algorithm: 0,
+ otp_device_id: "2",
+ otp_key: "456",
+ }
+}
+
+export function useOtpDeviceAPI(): OtpDeviceAPI {
+ const mutateAll = useMatchMutate();
+ const { request } = useBackendInstanceRequest();
+
+ const createOtpDevice = async (
+ data: MerchantBackend.OTP.OtpDeviceAddDetails,
+ ): Promise<HttpResponseOk<void>> => {
+ // MOCKED_DEVICES[data.otp_device_id] = data
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/otp-devices`, {
+ method: "POST",
+ data,
+ });
+ await mutateAll(/.*private\/otp-devices.*/);
+ return res;
+ };
+
+ const updateOtpDevice = async (
+ deviceId: string,
+ data: MerchantBackend.OTP.OtpDevicePatchDetails,
+ ): Promise<HttpResponseOk<void>> => {
+ // MOCKED_DEVICES[deviceId].otp_algorithm = data.otp_algorithm
+ // MOCKED_DEVICES[deviceId].otp_ctr = data.otp_ctr
+ // MOCKED_DEVICES[deviceId].otp_device_description = data.otp_device_description
+ // MOCKED_DEVICES[deviceId].otp_key = data.otp_key
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/otp-devices/${deviceId}`, {
+ method: "PATCH",
+ data,
+ });
+ await mutateAll(/.*private\/otp-devices.*/);
+ return res;
+ };
+
+ const deleteOtpDevice = async (
+ deviceId: string,
+ ): Promise<HttpResponseOk<void>> => {
+ // delete MOCKED_DEVICES[deviceId]
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/otp-devices/${deviceId}`, {
+ method: "DELETE",
+ });
+ await mutateAll(/.*private\/otp-devices.*/);
+ return res;
+ };
+
+ return {
+ createOtpDevice,
+ updateOtpDevice,
+ deleteOtpDevice,
+ };
+}
+
+export interface OtpDeviceAPI {
+ createOtpDevice: (
+ data: MerchantBackend.OTP.OtpDeviceAddDetails,
+ ) => Promise<HttpResponseOk<void>>;
+ updateOtpDevice: (
+ id: string,
+ data: MerchantBackend.OTP.OtpDevicePatchDetails,
+ ) => Promise<HttpResponseOk<void>>;
+ deleteOtpDevice: (id: string) => Promise<HttpResponseOk<void>>;
+}
+
+export interface InstanceOtpDeviceFilter {
+}
+
+export function useInstanceOtpDevices(
+ args?: InstanceOtpDeviceFilter,
+ updatePosition?: (id: string) => void,
+): HttpResponsePaginated<
+ MerchantBackend.OTP.OtpDeviceSummaryResponse,
+ MerchantBackend.ErrorDetail
+> {
+ // return {
+ // ok: true,
+ // loadMore: () => { },
+ // loadMorePrev: () => { },
+ // data: {
+ // otp_devices: Object.values(MOCKED_DEVICES).map(d => ({
+ // device_description: d.otp_device_description,
+ // otp_device_id: d.otp_device_id
+ // }))
+ // }
+ // }
+
+ const { fetcher } = useBackendInstanceRequest();
+
+ const [pageAfter, setPageAfter] = useState(1);
+
+ const totalAfter = pageAfter * PAGE_SIZE;
+ const {
+ data: afterData,
+ error: afterError,
+ isValidating: loadingAfter,
+ } = useSWR<
+ HttpResponseOk<MerchantBackend.OTP.OtpDeviceSummaryResponse>,
+ RequestError<MerchantBackend.ErrorDetail>
+ >([`/private/otp-devices`], fetcher);
+
+ const [lastAfter, setLastAfter] = useState<
+ HttpResponse<
+ MerchantBackend.OTP.OtpDeviceSummaryResponse,
+ MerchantBackend.ErrorDetail
+ >
+ >({ loading: true });
+ useEffect(() => {
+ if (afterData) setLastAfter(afterData);
+ }, [afterData /*, beforeData*/]);
+
+ 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.otp_devices.length < totalAfter;
+ const isReachingStart = false;
+
+ const pagination = {
+ isReachingEnd,
+ isReachingStart,
+ loadMore: () => {
+ if (!afterData || isReachingEnd) return;
+ if (afterData.data.otp_devices.length < MAX_RESULT_SIZE) {
+ setPageAfter(pageAfter + 1);
+ } else {
+ const from = `${afterData.data.otp_devices[afterData.data.otp_devices.length - 1]
+ .otp_device_id
+ }`;
+ if (from && updatePosition) updatePosition(from);
+ }
+ },
+ loadMorePrev: () => {
+ },
+ };
+
+ const otp_devices = !afterData ? [] : (afterData || lastAfter).data.otp_devices;
+ if (loadingAfter /* || loadingBefore */)
+ return { loading: true, data: { otp_devices } };
+ if (/*beforeData &&*/ afterData) {
+ return { ok: true, data: { otp_devices }, ...pagination };
+ }
+ return { loading: true };
+}
+
+export function useOtpDeviceDetails(
+ deviceId: string,
+): HttpResponse<
+ MerchantBackend.OTP.OtpDeviceDetails,
+ MerchantBackend.ErrorDetail
+> {
+ // return {
+ // ok: true,
+ // data: {
+ // device_description: MOCKED_DEVICES[deviceId].otp_device_description,
+ // otp_algorithm: MOCKED_DEVICES[deviceId].otp_algorithm,
+ // otp_ctr: MOCKED_DEVICES[deviceId].otp_ctr
+ // }
+ // }
+ const { fetcher } = useBackendInstanceRequest();
+
+ const { data, error, isValidating } = useSWR<
+ HttpResponseOk<MerchantBackend.OTP.OtpDeviceDetails>,
+ RequestError<MerchantBackend.ErrorDetail>
+ >([`/private/otp-devices/${deviceId}`], 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 };
+}
diff --git a/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts b/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts
index d2831ecff..b3eecd754 100644
--- a/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts
@@ -25,16 +25,16 @@ import {
useInstanceReserves,
useReserveDetails,
useReservesAPI,
- useTipDetails,
+ useRewardDetails,
} from "./reserves.js";
import { ApiMockEnvironment } from "./testing.js";
import {
- API_AUTHORIZE_TIP,
- API_AUTHORIZE_TIP_FOR_RESERVE,
+ API_AUTHORIZE_REWARD,
+ API_AUTHORIZE_REWARD_FOR_RESERVE,
API_CREATE_RESERVE,
API_DELETE_RESERVE,
API_GET_RESERVE_BY_ID,
- API_GET_TIP_BY_ID,
+ API_GET_REWARD_BY_ID,
API_LIST_RESERVES,
} from "./urls.js";
import * as tests from "@gnu-taler/web-util/testing";
@@ -48,7 +48,7 @@ describe("reserve api interaction with listing", () => {
reserves: [
{
reserve_pub: "11",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
],
},
});
@@ -89,10 +89,10 @@ describe("reserve api interaction with listing", () => {
reserves: [
{
reserve_pub: "11",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
{
reserve_pub: "22",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
],
},
});
@@ -115,10 +115,10 @@ describe("reserve api interaction with listing", () => {
reserves: [
{
reserve_pub: "11",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
{
reserve_pub: "22",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
],
});
},
@@ -138,13 +138,13 @@ describe("reserve api interaction with listing", () => {
reserves: [
{
reserve_pub: "11",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
{
reserve_pub: "22",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
{
reserve_pub: "33",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
],
},
});
@@ -182,10 +182,10 @@ describe("reserve api interaction with listing", () => {
reserves: [
{
reserve_pub: "22",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
{
reserve_pub: "33",
- } as MerchantBackend.Tips.ReserveStatusEntry,
+ } as MerchantBackend.Rewards.ReserveStatusEntry,
],
},
});
@@ -213,16 +213,16 @@ describe("reserve api interaction with listing", () => {
});
describe("reserve api interaction with details", () => {
- it("should evict cache when adding a tip for a specific reserve", async () => {
+ it("should evict cache when adding a reward for a specific reserve", async () => {
const env = new ApiMockEnvironment();
env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
response: {
accounts: [{ payto_uri: "payto://here" }],
- tips: [{ reason: "why?", tip_id: "id1", total_amount: "USD:10" }],
- } as MerchantBackend.Tips.ReserveDetail,
+ rewards: [{ reason: "why?", reward_id: "id1", total_amount: "USD:10" }],
+ } as MerchantBackend.Rewards.ReserveDetail,
qparam: {
- tips: "yes",
+ rewards: "yes",
},
});
@@ -246,37 +246,37 @@ describe("reserve api interaction with details", () => {
if (!query.ok) return;
expect(query.data).deep.equals({
accounts: [{ payto_uri: "payto://here" }],
- tips: [{ reason: "why?", tip_id: "id1", total_amount: "USD:10" }],
+ rewards: [{ reason: "why?", reward_id: "id1", total_amount: "USD:10" }],
});
- env.addRequestExpectation(API_AUTHORIZE_TIP_FOR_RESERVE("11"), {
+ env.addRequestExpectation(API_AUTHORIZE_REWARD_FOR_RESERVE("11"), {
request: {
amount: "USD:12",
justification: "not",
next_url: "http://taler.net",
},
response: {
- tip_id: "id2",
- taler_tip_uri: "uri",
- tip_expiration: { t_s: 1 },
- tip_status_url: "url",
+ reward_id: "id2",
+ taler_reward_uri: "uri",
+ reward_expiration: { t_s: 1 },
+ reward_status_url: "url",
},
});
env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
response: {
accounts: [{ payto_uri: "payto://here" }],
- tips: [
- { reason: "why?", tip_id: "id1", total_amount: "USD:10" },
- { reason: "not", tip_id: "id2", total_amount: "USD:12" },
+ rewards: [
+ { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
+ { reason: "not", reward_id: "id2", total_amount: "USD:12" },
],
- } as MerchantBackend.Tips.ReserveDetail,
+ } as MerchantBackend.Rewards.ReserveDetail,
qparam: {
- tips: "yes",
+ rewards: "yes",
},
});
- api.authorizeTipReserve("11", {
+ api.authorizeRewardReserve("11", {
amount: "USD:12",
justification: "not",
next_url: "http://taler.net",
@@ -294,9 +294,9 @@ describe("reserve api interaction with details", () => {
expect(query.data).deep.equals({
accounts: [{ payto_uri: "payto://here" }],
- tips: [
- { reason: "why?", tip_id: "id1", total_amount: "USD:10" },
- { reason: "not", tip_id: "id2", total_amount: "USD:12" },
+ rewards: [
+ { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
+ { reason: "not", reward_id: "id2", total_amount: "USD:12" },
],
});
},
@@ -308,16 +308,16 @@ describe("reserve api interaction with details", () => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
});
- it("should evict cache when adding a tip for a random reserve", async () => {
+ it("should evict cache when adding a reward for a random reserve", async () => {
const env = new ApiMockEnvironment();
env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
response: {
accounts: [{ payto_uri: "payto://here" }],
- tips: [{ reason: "why?", tip_id: "id1", total_amount: "USD:10" }],
- } as MerchantBackend.Tips.ReserveDetail,
+ rewards: [{ reason: "why?", reward_id: "id1", total_amount: "USD:10" }],
+ } as MerchantBackend.Rewards.ReserveDetail,
qparam: {
- tips: "yes",
+ rewards: "yes",
},
});
@@ -341,37 +341,37 @@ describe("reserve api interaction with details", () => {
if (!query.ok) return;
expect(query.data).deep.equals({
accounts: [{ payto_uri: "payto://here" }],
- tips: [{ reason: "why?", tip_id: "id1", total_amount: "USD:10" }],
+ rewards: [{ reason: "why?", reward_id: "id1", total_amount: "USD:10" }],
});
- env.addRequestExpectation(API_AUTHORIZE_TIP, {
+ env.addRequestExpectation(API_AUTHORIZE_REWARD, {
request: {
amount: "USD:12",
justification: "not",
next_url: "http://taler.net",
},
response: {
- tip_id: "id2",
- taler_tip_uri: "uri",
- tip_expiration: { t_s: 1 },
- tip_status_url: "url",
+ reward_id: "id2",
+ taler_reward_uri: "uri",
+ reward_expiration: { t_s: 1 },
+ reward_status_url: "url",
},
});
env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
response: {
accounts: [{ payto_uri: "payto://here" }],
- tips: [
- { reason: "why?", tip_id: "id1", total_amount: "USD:10" },
- { reason: "not", tip_id: "id2", total_amount: "USD:12" },
+ rewards: [
+ { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
+ { reason: "not", reward_id: "id2", total_amount: "USD:12" },
],
- } as MerchantBackend.Tips.ReserveDetail,
+ } as MerchantBackend.Rewards.ReserveDetail,
qparam: {
- tips: "yes",
+ rewards: "yes",
},
});
- api.authorizeTip({
+ api.authorizeReward({
amount: "USD:12",
justification: "not",
next_url: "http://taler.net",
@@ -387,9 +387,9 @@ describe("reserve api interaction with details", () => {
expect(query.data).deep.equals({
accounts: [{ payto_uri: "payto://here" }],
- tips: [
- { reason: "why?", tip_id: "id1", total_amount: "USD:10" },
- { reason: "not", tip_id: "id2", total_amount: "USD:12" },
+ rewards: [
+ { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
+ { reason: "not", reward_id: "id2", total_amount: "USD:12" },
],
});
},
@@ -402,15 +402,15 @@ describe("reserve api interaction with details", () => {
});
});
-describe("reserve api interaction with tip details", () => {
- it("should list tips", async () => {
+describe("reserve api interaction with reward details", () => {
+ it("should list rewards", async () => {
const env = new ApiMockEnvironment();
- env.addRequestExpectation(API_GET_TIP_BY_ID("11"), {
+ env.addRequestExpectation(API_GET_REWARD_BY_ID("11"), {
response: {
total_picked_up: "USD:12",
reason: "not",
- } as MerchantBackend.Tips.TipDetails,
+ } as MerchantBackend.Rewards.RewardDetails,
qparam: {
pickups: "yes",
},
@@ -418,7 +418,7 @@ describe("reserve api interaction with tip details", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const query = useTipDetails("11");
+ const query = useRewardDetails("11");
return { query };
},
{},
diff --git a/packages/merchant-backoffice-ui/src/hooks/reserves.ts b/packages/merchant-backoffice-ui/src/hooks/reserves.ts
index bb55b2474..b719bfbe6 100644
--- a/packages/merchant-backoffice-ui/src/hooks/reserves.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/reserves.ts
@@ -31,11 +31,11 @@ export function useReservesAPI(): ReserveMutateAPI {
const { request } = useBackendInstanceRequest();
const createReserve = async (
- data: MerchantBackend.Tips.ReserveCreateRequest,
+ data: MerchantBackend.Rewards.ReserveCreateRequest,
): Promise<
- HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>
+ HttpResponseOk<MerchantBackend.Rewards.ReserveCreateConfirmation>
> => {
- const res = await request<MerchantBackend.Tips.ReserveCreateConfirmation>(
+ const res = await request<MerchantBackend.Rewards.ReserveCreateConfirmation>(
`/private/reserves`,
{
method: "POST",
@@ -49,12 +49,12 @@ export function useReservesAPI(): ReserveMutateAPI {
return res;
};
- const authorizeTipReserve = async (
+ const authorizeRewardReserve = async (
pub: string,
- data: MerchantBackend.Tips.TipCreateRequest,
- ): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => {
- const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(
- `/private/reserves/${pub}/authorize-tip`,
+ data: MerchantBackend.Rewards.RewardCreateRequest,
+ ): Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>> => {
+ const res = await request<MerchantBackend.Rewards.RewardCreateConfirmation>(
+ `/private/reserves/${pub}/authorize-reward`,
{
method: "POST",
data,
@@ -67,11 +67,11 @@ export function useReservesAPI(): ReserveMutateAPI {
return res;
};
- const authorizeTip = async (
- data: MerchantBackend.Tips.TipCreateRequest,
- ): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => {
- const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(
- `/private/tips`,
+ const authorizeReward = async (
+ data: MerchantBackend.Rewards.RewardCreateRequest,
+ ): Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>> => {
+ const res = await request<MerchantBackend.Rewards.RewardCreateConfirmation>(
+ `/private/rewards`,
{
method: "POST",
data,
@@ -97,33 +97,33 @@ export function useReservesAPI(): ReserveMutateAPI {
return res;
};
- return { createReserve, authorizeTip, authorizeTipReserve, deleteReserve };
+ return { createReserve, authorizeReward, authorizeRewardReserve, deleteReserve };
}
export interface ReserveMutateAPI {
createReserve: (
- data: MerchantBackend.Tips.ReserveCreateRequest,
- ) => Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>>;
- authorizeTipReserve: (
+ data: MerchantBackend.Rewards.ReserveCreateRequest,
+ ) => Promise<HttpResponseOk<MerchantBackend.Rewards.ReserveCreateConfirmation>>;
+ authorizeRewardReserve: (
id: string,
- data: MerchantBackend.Tips.TipCreateRequest,
- ) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>;
- authorizeTip: (
- data: MerchantBackend.Tips.TipCreateRequest,
- ) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>;
+ data: MerchantBackend.Rewards.RewardCreateRequest,
+ ) => Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>>;
+ authorizeReward: (
+ data: MerchantBackend.Rewards.RewardCreateRequest,
+ ) => Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>>;
deleteReserve: (
id: string,
) => Promise<HttpResponse<void, MerchantBackend.ErrorDetail>>;
}
export function useInstanceReserves(): HttpResponse<
- MerchantBackend.Tips.TippingReserveStatus,
+ MerchantBackend.Rewards.RewardReserveStatus,
MerchantBackend.ErrorDetail
> {
const { fetcher } = useBackendInstanceRequest();
const { data, error, isValidating } = useSWR<
- HttpResponseOk<MerchantBackend.Tips.TippingReserveStatus>,
+ HttpResponseOk<MerchantBackend.Rewards.RewardReserveStatus>,
RequestError<MerchantBackend.ErrorDetail>
>([`/private/reserves`], fetcher);
@@ -136,13 +136,13 @@ export function useInstanceReserves(): HttpResponse<
export function useReserveDetails(
reserveId: string,
): HttpResponse<
- MerchantBackend.Tips.ReserveDetail,
+ MerchantBackend.Rewards.ReserveDetail,
MerchantBackend.ErrorDetail
> {
const { reserveDetailFetcher } = useBackendInstanceRequest();
const { data, error, isValidating } = useSWR<
- HttpResponseOk<MerchantBackend.Tips.ReserveDetail>,
+ HttpResponseOk<MerchantBackend.Rewards.ReserveDetail>,
RequestError<MerchantBackend.ErrorDetail>
>([`/private/reserves/${reserveId}`], reserveDetailFetcher, {
refreshInterval: 0,
@@ -158,15 +158,15 @@ export function useReserveDetails(
return { loading: true };
}
-export function useTipDetails(
- tipId: string,
-): HttpResponse<MerchantBackend.Tips.TipDetails, MerchantBackend.ErrorDetail> {
- const { tipsDetailFetcher } = useBackendInstanceRequest();
+export function useRewardDetails(
+ rewardId: string,
+): HttpResponse<MerchantBackend.Rewards.RewardDetails, MerchantBackend.ErrorDetail> {
+ const { rewardsDetailFetcher } = useBackendInstanceRequest();
const { data, error, isValidating } = useSWR<
- HttpResponseOk<MerchantBackend.Tips.TipDetails>,
+ HttpResponseOk<MerchantBackend.Rewards.RewardDetails>,
RequestError<MerchantBackend.ErrorDetail>
- >([`/private/tips/${tipId}`], tipsDetailFetcher, {
+ >([`/private/rewards/${rewardId}`], rewardsDetailFetcher, {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
diff --git a/packages/merchant-backoffice-ui/src/hooks/urls.ts b/packages/merchant-backoffice-ui/src/hooks/urls.ts
index 6b339c05a..00c5e95af 100644
--- a/packages/merchant-backoffice-ui/src/hooks/urls.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/urls.ts
@@ -139,15 +139,15 @@ export const API_DELETE_PRODUCT = (id: string): Query<unknown, unknown> => ({
////////////////////
export const API_CREATE_RESERVE: Query<
- MerchantBackend.Tips.ReserveCreateRequest,
- MerchantBackend.Tips.ReserveCreateConfirmation
+ MerchantBackend.Rewards.ReserveCreateRequest,
+ MerchantBackend.Rewards.ReserveCreateConfirmation
> = {
method: "POST",
url: "http://backend/instances/default/private/reserves",
};
export const API_LIST_RESERVES: Query<
unknown,
- MerchantBackend.Tips.TippingReserveStatus
+ MerchantBackend.Rewards.RewardReserveStatus
> = {
method: "GET",
url: "http://backend/instances/default/private/reserves",
@@ -155,34 +155,34 @@ export const API_LIST_RESERVES: Query<
export const API_GET_RESERVE_BY_ID = (
pub: string,
-): Query<unknown, MerchantBackend.Tips.ReserveDetail> => ({
+): Query<unknown, MerchantBackend.Rewards.ReserveDetail> => ({
method: "GET",
url: `http://backend/instances/default/private/reserves/${pub}`,
});
-export const API_GET_TIP_BY_ID = (
+export const API_GET_REWARD_BY_ID = (
pub: string,
-): Query<unknown, MerchantBackend.Tips.TipDetails> => ({
+): Query<unknown, MerchantBackend.Rewards.RewardDetails> => ({
method: "GET",
- url: `http://backend/instances/default/private/tips/${pub}`,
+ url: `http://backend/instances/default/private/rewards/${pub}`,
});
-export const API_AUTHORIZE_TIP_FOR_RESERVE = (
+export const API_AUTHORIZE_REWARD_FOR_RESERVE = (
pub: string,
): Query<
- MerchantBackend.Tips.TipCreateRequest,
- MerchantBackend.Tips.TipCreateConfirmation
+ MerchantBackend.Rewards.RewardCreateRequest,
+ MerchantBackend.Rewards.RewardCreateConfirmation
> => ({
method: "POST",
- url: `http://backend/instances/default/private/reserves/${pub}/authorize-tip`,
+ url: `http://backend/instances/default/private/reserves/${pub}/authorize-reward`,
});
-export const API_AUTHORIZE_TIP: Query<
- MerchantBackend.Tips.TipCreateRequest,
- MerchantBackend.Tips.TipCreateConfirmation
+export const API_AUTHORIZE_REWARD: Query<
+ MerchantBackend.Rewards.RewardCreateRequest,
+ MerchantBackend.Rewards.RewardCreateConfirmation
> = {
method: "POST",
- url: `http://backend/instances/default/private/tips`,
+ url: `http://backend/instances/default/private/rewards`,
};
export const API_DELETE_RESERVE = (id: string): Query<unknown, unknown> => ({
@@ -211,7 +211,7 @@ export const API_GET_INSTANCE_BY_ID = (
export const API_GET_INSTANCE_KYC_BY_ID = (
id: string,
-): Query<unknown, MerchantBackend.Instances.AccountKycRedirects> => ({
+): Query<unknown, MerchantBackend.KYC.AccountKycRedirects> => ({
method: "GET",
url: `http://backend/management/instances/${id}/kyc`,
});
@@ -263,7 +263,7 @@ export const API_GET_CURRENT_INSTANCE: Query<
export const API_GET_CURRENT_INSTANCE_KYC: Query<
unknown,
- MerchantBackend.Instances.AccountKycRedirects
+ MerchantBackend.KYC.AccountKycRedirects
> = {
method: "GET",
url: `http://backend/instances/default/private/kyc`,
diff --git a/packages/merchant-backoffice-ui/src/hooks/useSettings.ts b/packages/merchant-backoffice-ui/src/hooks/useSettings.ts
index 5c0932f27..7dee9f896 100644
--- a/packages/merchant-backoffice-ui/src/hooks/useSettings.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/useSettings.ts
@@ -19,6 +19,9 @@ import {
Codec,
buildCodecForObject,
codecForBoolean,
+ codecForConstString,
+ codecForEither,
+ codecForString,
} from "@gnu-taler/taler-util";
function parse_json_or_undefined<T>(str: string | undefined): T | undefined {
@@ -31,29 +34,49 @@ function parse_json_or_undefined<T>(str: string | undefined): T | undefined {
}
export interface Settings {
- advanceOrderMode: boolean
+ advanceOrderMode: boolean;
+ dateFormat: "ymd" | "dmy" | "mdy";
}
const defaultSettings: Settings = {
advanceOrderMode: false,
+ dateFormat: "ymd",
}
export const codecForSettings = (): Codec<Settings> =>
buildCodecForObject<Settings>()
.property("advanceOrderMode", codecForBoolean())
+ .property("dateFormat", codecForEither(
+ codecForConstString("ymd"),
+ codecForConstString("dmy"),
+ codecForConstString("mdy"),
+ ))
.build("Settings");
const SETTINGS_KEY = buildStorageKey("merchant-settings", codecForSettings());
export function useSettings(): [
Readonly<Settings>,
- <T extends keyof Settings>(key: T, value: Settings[T]) => void,
+ (s: Settings) => void,
] {
- const { value, update } = useLocalStorage(SETTINGS_KEY);
+ const { value, update } = useLocalStorage(SETTINGS_KEY, defaultSettings);
- const parsed: Settings = value ?? defaultSettings;
- function updateField<T extends keyof Settings>(k: T, v: Settings[T]) {
- update({ ...parsed, [k]: v });
+ // const parsed: Settings = value ?? defaultSettings;
+ // function updateField<T extends keyof Settings>(k: T, v: Settings[T]) {
+ // const next = { ...parsed, [k]: v }
+ // update(next);
+ // }
+ return [value, update];
+}
+
+export function dateFormatForSettings(s: Settings): string {
+ switch (s.dateFormat) {
+ case "ymd": return "yyyy/MM/dd"
+ case "dmy": return "dd/MM/yyyy"
+ case "mdy": return "MM/dd/yyyy"
}
- return [parsed, updateField];
}
+
+export function datetimeFormatForSettings(s: Settings): string {
+ return dateFormatForSettings(s) + " HH:mm:ss"
+} \ No newline at end of file