aboutsummaryrefslogtreecommitdiff
path: root/packages/merchant-backoffice-ui/src/paths/instance/validators/update
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/paths/instance/validators/update
parentff20c3e25e076c24f7cb93eabe58b6f934f51f35 (diff)
downloadwallet-core-e1d86816a7c07cb8ca2d54676d5cdbbe513f2ba7.tar.xz
backoffcie new version, lot of changes
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/instance/validators/update')
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/validators/update/Update.stories.tsx32
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx185
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx102
3 files changed, 319 insertions, 0 deletions
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/Update.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/Update.stories.tsx
new file mode 100644
index 000000000..fcb77b820
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/Update.stories.tsx
@@ -0,0 +1,32 @@
+/*
+ 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/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { h, VNode, FunctionalComponent } from "preact";
+import { UpdatePage as TestedComponent } from "./UpdatePage.js";
+
+export default {
+ title: "Pages/Validators/Update",
+ component: TestedComponent,
+ argTypes: {
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
+ },
+};
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx
new file mode 100644
index 000000000..585c12e11
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx
@@ -0,0 +1,185 @@
+/*
+ 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/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
+import {
+ FormErrors,
+ FormProvider,
+} from "../../../../components/form/FormProvider.js";
+import { Input } from "../../../../components/form/Input.js";
+import { MerchantBackend, WithId } from "../../../../declaration.js";
+import { InputSelector } from "../../../../components/form/InputSelector.js";
+import { InputWithAddon } from "../../../../components/form/InputWithAddon.js";
+import { randomBase32Key } from "../../../../utils/crypto.js";
+
+type Entity = MerchantBackend.OTP.OtpDevicePatchDetails & WithId;
+
+interface Props {
+ onUpdate: (d: Entity) => Promise<void>;
+ onBack?: () => void;
+ device: Entity;
+}
+const algorithms = [0, 1, 2];
+const algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"];
+export function UpdatePage({ device, onUpdate, onBack }: Props): VNode {
+ const { i18n } = useTranslationContext();
+
+ const [state, setState] = useState<Partial<Entity>>(device);
+ const [showKey, setShowKey] = useState(false);
+
+ const errors: FormErrors<Entity> = {
+ };
+
+ const hasErrors = Object.keys(errors).some(
+ (k) => (errors as any)[k] !== undefined,
+ );
+
+ const submitForm = () => {
+ if (hasErrors) return Promise.reject();
+ return onUpdate(state as any);
+ };
+
+ return (
+ <div>
+ <section class="section">
+ <section class="hero is-hero-bar">
+ <div class="hero-body">
+ <div class="level">
+ <div class="level-left">
+ <div class="level-item">
+ <span class="is-size-4">
+ Device: <b>{device.id}</b>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </section>
+ <hr />
+
+ <section class="section is-main-section">
+ <div class="columns">
+ <div class="column is-four-fifths">
+ <FormProvider
+ object={state}
+ valueHandler={setState}
+ errors={errors}
+ >
+ <Input<Entity>
+ name="otp_description"
+ label={i18n.str`Description`}
+ tooltip={i18n.str`dddd`}
+ />
+ <InputSelector<Entity>
+ name="otp_algorithm"
+ label={i18n.str`Verification algorithm`}
+ tooltip={i18n.str`Algorithm to use to verify transaction in offline mode`}
+ values={algorithms}
+ toStr={(v) => algorithmsNames[v]}
+ fromStr={(v) => Number(v)}
+ />
+ {state.otp_algorithm && state.otp_algorithm > 0 ? (
+ <Fragment>
+ <InputWithAddon<Entity>
+ name="otp_key"
+ label={i18n.str`Device key`}
+ readonly={state.otp_key === undefined}
+ inputType={showKey ? "text" : "password"}
+ help={state.otp_key === undefined ? "Not modified" : "Be sure to be very hard to guess or use the random generator"}
+ tooltip={i18n.str`Your device need to have exactly the same value`}
+ fromStr={(v) => v.toUpperCase()}
+ addonAfter={
+ <span class="icon">
+ {showKey ? (
+ <i class="mdi mdi-eye" />
+ ) : (
+ <i class="mdi mdi-eye-off" />
+ )}
+ </span>
+ }
+ side={
+ state.otp_key === undefined ? <button
+
+ onClick={(e) => {
+ setState((s) => ({ ...s, otp_key: "" }));
+ }}
+ class="button">change key</button> :
+ <span style={{ display: "flex" }}>
+ <button
+ data-tooltip={i18n.str`generate random secret key`}
+ class="button is-info mr-3"
+ onClick={(e) => {
+ setState((s) => ({ ...s, otp_key: randomBase32Key() }));
+ }}
+ >
+ <i18n.Translate>random</i18n.Translate>
+ </button>
+ <button
+ data-tooltip={
+ showKey
+ ? i18n.str`show secret key`
+ : i18n.str`hide secret key`
+ }
+ class="button is-info mr-3"
+ onClick={(e) => {
+ setShowKey(!showKey);
+ }}
+ >
+ {showKey ? (
+ <i18n.Translate>hide</i18n.Translate>
+ ) : (
+ <i18n.Translate>show</i18n.Translate>
+ )}
+ </button>
+ </span>
+ }
+ />
+ </Fragment>
+ ) : undefined} </FormProvider>
+
+ <div class="buttons is-right mt-5">
+ {onBack && (
+ <button class="button" onClick={onBack}>
+ <i18n.Translate>Cancel</i18n.Translate>
+ </button>
+ )}
+ <AsyncButton
+ disabled={hasErrors}
+ data-tooltip={
+ hasErrors
+ ? i18n.str`Need to complete marked fields`
+ : "confirm operation"
+ }
+ onClick={submitForm}
+ >
+ <i18n.Translate>Confirm</i18n.Translate>
+ </AsyncButton>
+ </div>
+ </div>
+ </div>
+ </section>
+ </section>
+ </div>
+ );
+}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx
new file mode 100644
index 000000000..9a27ccfee
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx
@@ -0,0 +1,102 @@
+/*
+ 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/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import {
+ ErrorType,
+ HttpError,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Loading } from "../../../../components/exception/loading.js";
+import { NotificationCard } from "../../../../components/menu/index.js";
+import { MerchantBackend, WithId } from "../../../../declaration.js";
+import { Notification } from "../../../../utils/types.js";
+import { UpdatePage } from "./UpdatePage.js";
+import { HttpStatusCode } from "@gnu-taler/taler-util";
+import { useOtpDeviceAPI, useOtpDeviceDetails } from "../../../../hooks/otp.js";
+
+export type Entity = MerchantBackend.OTP.OtpDevicePatchDetails & WithId;
+
+interface Props {
+ onBack?: () => void;
+ onConfirm: () => void;
+ onUnauthorized: () => VNode;
+ onNotFound: () => VNode;
+ onLoadError: (e: HttpError<MerchantBackend.ErrorDetail>) => VNode;
+ vid: string;
+}
+export default function UpdateValidator({
+ vid,
+ onConfirm,
+ onBack,
+ onUnauthorized,
+ onNotFound,
+ onLoadError,
+}: Props): VNode {
+ const { updateOtpDevice } = useOtpDeviceAPI();
+ const result = useOtpDeviceDetails(vid);
+ const [notif, setNotif] = useState<Notification | undefined>(undefined);
+
+ const { i18n } = useTranslationContext();
+
+ if (result.loading) return <Loading />;
+ if (!result.ok) {
+ if (
+ result.type === ErrorType.CLIENT &&
+ result.status === HttpStatusCode.Unauthorized
+ )
+ return onUnauthorized();
+ if (
+ result.type === ErrorType.CLIENT &&
+ result.status === HttpStatusCode.NotFound
+ )
+ return onNotFound();
+ return onLoadError(result);
+ }
+
+ return (
+ <Fragment>
+ <NotificationCard notification={notif} />
+ <UpdatePage
+ device={{
+ id: vid,
+ otp_algorithm: result.data.otp_algorithm,
+ otp_description: result.data.device_description,
+ otp_key: undefined,
+ otp_ctr: result.data.otp_ctr
+ }}
+ onBack={onBack}
+ onUpdate={(data) => {
+ return updateOtpDevice(vid, data)
+ .then(onConfirm)
+ .catch((error) => {
+ setNotif({
+ message: i18n.str`could not update template`,
+ type: "ERROR",
+ description: error.message,
+ });
+ });
+ }}
+ />
+ </Fragment>
+ );
+}