wallet-core/packages/merchant-backoffice-ui/src/hooks/otp.ts
2023-09-04 14:17:55 -03:00

224 lines
6.7 KiB
TypeScript

/*
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 };
}