aboutsummaryrefslogtreecommitdiff
path: root/packages/auditor-backoffice-ui/src/components/form
diff options
context:
space:
mode:
Diffstat (limited to 'packages/auditor-backoffice-ui/src/components/form')
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputArray.tsx139
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputBoolean.tsx91
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputDate.tsx164
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputDuration.tsx186
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputGroup.tsx86
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputImage.tsx122
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputLocation.tsx53
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputPayto.tsx52
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx47
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.tsx397
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputSearchOnList.tsx204
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputSecured.stories.tsx61
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputSecured.tsx186
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputStock.stories.tsx162
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputStock.tsx224
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputTab.tsx90
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/InputTaxes.tsx147
-rw-r--r--packages/auditor-backoffice-ui/src/components/form/TextField.tsx71
18 files changed, 0 insertions, 2482 deletions
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputArray.tsx b/packages/auditor-backoffice-ui/src/components/form/InputArray.tsx
deleted file mode 100644
index b0b9eaefc..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputArray.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { InputProps, useField } from "./useField.js";
-
-export interface Props<T> extends InputProps<T> {
- isValid?: (e: any) => boolean;
- addonBefore?: string;
- toStr?: (v?: any) => string;
- fromStr?: (s: string) => any;
-}
-
-const defaultToString = (f?: any): string => f || "";
-const defaultFromString = (v: string): any => v as any;
-
-export function InputArray<T>({
- name,
- readonly,
- placeholder,
- tooltip,
- label,
- help,
- addonBefore,
- isValid = () => true,
- fromStr = defaultFromString,
- toStr = defaultToString,
-}: Props<keyof T>): VNode {
- const { error: formError, value, onChange, required } = useField<T>(name);
- const [localError, setLocalError] = useState<string | null>(null);
-
- const error = localError || formError;
-
- const array: any[] = (value ? value! : []) as any;
- const [currentValue, setCurrentValue] = useState("");
- const { i18n } = useTranslationContext();
-
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field">
- <div class="field has-addons">
- {addonBefore && (
- <div class="control">
- <a class="button is-static">{addonBefore}</a>
- </div>
- )}
- <p class="control is-expanded has-icons-right">
- <input
- class={error ? "input is-danger" : "input"}
- type="text"
- placeholder={placeholder}
- readonly={readonly}
- disabled={readonly}
- name={String(name)}
- value={currentValue}
- onChange={(e): void => setCurrentValue(e.currentTarget.value)}
- />
- {required && (
- <span class="icon has-text-danger is-right">
- <i class="mdi mdi-alert" />
- </span>
- )}
- </p>
- <p class="control">
- <button
- class="button is-info has-tooltip-left"
- disabled={!currentValue}
- onClick={(): void => {
- const v = fromStr(currentValue);
- if (!isValid(v)) {
- setLocalError(
- i18n.str`The value ${v} is invalid for a payment url`,
- );
- return;
- }
- setLocalError(null);
- onChange([v, ...array] as any);
- setCurrentValue("");
- }}
- data-tooltip={i18n.str`add element to the list`}
- >
- <i18n.Translate>add</i18n.Translate>
- </button>
- </p>
- </div>
- {help}
- {error && <p class="help is-danger"> {error} </p>}
- {array.map((v, i) => (
- <div key={i} class="tags has-addons mt-3 mb-0">
- <span
- class="tag is-medium is-info mb-0"
- style={{ maxWidth: "90%" }}
- >
- {v}
- </span>
- <a
- class="tag is-medium is-danger is-delete mb-0"
- onClick={() => {
- onChange(array.filter((f) => f !== v) as any);
- setCurrentValue(toStr(v));
- }}
- />
- </div>
- ))}
- </div>
- </div>
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputBoolean.tsx b/packages/auditor-backoffice-ui/src/components/form/InputBoolean.tsx
deleted file mode 100644
index bdb2feb6b..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputBoolean.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 } from "preact";
-import { InputProps, useField } from "./useField.js";
-
-interface Props<T> extends InputProps<T> {
- name: T;
- readonly?: boolean;
- expand?: boolean;
- threeState?: boolean;
- toBoolean?: (v?: any) => boolean | undefined;
- fromBoolean?: (s: boolean | undefined) => any;
-}
-
-const defaultToBoolean = (f?: any): boolean | undefined => f || "";
-const defaultFromBoolean = (v: boolean | undefined): any => v as any;
-
-export function InputBoolean<T>({
- name,
- readonly,
- placeholder,
- tooltip,
- label,
- help,
- threeState,
- expand,
- fromBoolean = defaultFromBoolean,
- toBoolean = defaultToBoolean,
-}: Props<keyof T>): VNode {
- const { error, value, onChange } = useField<T>(name);
-
- const onCheckboxClick = (): void => {
- const c = toBoolean(value);
- if (c === false && threeState) return onChange(undefined as any);
- return onChange(fromBoolean(!c));
- };
-
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field">
- <p class={expand ? "control is-expanded" : "control"}>
- <label class="b-checkbox checkbox">
- <input
- type="checkbox"
- class={toBoolean(value) === undefined ? "is-indeterminate" : ""}
- checked={toBoolean(value)}
- placeholder={placeholder}
- readonly={readonly}
- name={String(name)}
- disabled={readonly}
- onChange={onCheckboxClick}
- />
- <span class="check" />
- </label>
- {help}
- </p>
- {error && <p class="help is-danger">{error}</p>}
- </div>
- </div>
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputDate.tsx b/packages/auditor-backoffice-ui/src/components/form/InputDate.tsx
deleted file mode 100644
index cbcc6af2d..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputDate.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { format } from "date-fns";
-import { ComponentChildren, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { DatePicker } from "../picker/DatePicker.js";
-import { InputProps, useField } from "./useField.js";
-import { dateFormatForSettings, useSettings } from "../../hooks/useSettings.js";
-
-export interface Props<T> extends InputProps<T> {
- readonly?: boolean;
- expand?: boolean;
- //FIXME: create separated components InputDate and InputTimestamp
- withTimestampSupport?: boolean;
- side?: ComponentChildren;
-}
-
-export function InputDate<T>({
- name,
- readonly,
- label,
- placeholder,
- help,
- tooltip,
- expand,
- withTimestampSupport,
- side,
-}: Props<keyof T>): VNode {
- const [opened, setOpened] = useState(false);
- const { i18n } = useTranslationContext();
- const [settings] = useSettings()
-
- const { error, required, value, onChange } = useField<T>(name);
-
- let strValue = "";
- if (!value) {
- strValue = withTimestampSupport ? "unknown" : "";
- } else if (value instanceof Date) {
- strValue = format(value, dateFormatForSettings(settings));
- } else if (value.t_s) {
- strValue =
- value.t_s === "never"
- ? withTimestampSupport
- ? "never"
- : ""
- : format(new Date(value.t_s * 1000), dateFormatForSettings(settings));
- }
-
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field">
- <div class="field has-addons">
- <p
- class={
- expand
- ? "control is-expanded has-icons-right"
- : "control has-icons-right"
- }
- >
- <input
- class="input"
- type="text"
- readonly
- value={strValue}
- placeholder={placeholder}
- onClick={() => {
- if (!readonly) setOpened(true);
- }}
- />
- {required && (
- <span class="icon has-text-danger is-right">
- <i class="mdi mdi-alert" />
- </span>
- )}
- {help}
- </p>
- <div
- class="control"
- onClick={() => {
- if (!readonly) setOpened(true);
- }}
- >
- <a class="button is-static">
- <span class="icon">
- <i class="mdi mdi-calendar" />
- </span>
- </a>
- </div>
- </div>
- {error && <p class="help is-danger">{error}</p>}
- </div>
-
- {!readonly && (
- <span
- data-tooltip={
- withTimestampSupport
- ? i18n.str`change value to unknown date`
- : i18n.str`change value to empty`
- }
- >
- <button
- class="button is-info mr-3"
- onClick={() => onChange(undefined as any)}
- >
- <i18n.Translate>clear</i18n.Translate>
- </button>
- </span>
- )}
- {withTimestampSupport && (
- <span data-tooltip={i18n.str`change value to never`}>
- <button
- class="button is-info"
- onClick={() => onChange({ t_s: "never" } as any)}
- >
- <i18n.Translate>never</i18n.Translate>
- </button>
- </span>
- )}
- {side}
- </div>
- <DatePicker
- opened={opened}
- closeFunction={() => setOpened(false)}
- dateReceiver={(d) => {
- if (withTimestampSupport) {
- onChange({ t_s: d.getTime() / 1000 } as any);
- } else {
- onChange(d as any);
- }
- }}
- />
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputDuration.tsx b/packages/auditor-backoffice-ui/src/components/form/InputDuration.tsx
deleted file mode 100644
index 0103a97c1..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputDuration.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { formatDuration, intervalToDuration } from "date-fns";
-import { ComponentChildren, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { SimpleModal } from "../modal/index.js";
-import { DurationPicker } from "../picker/DurationPicker.js";
-import { InputProps, useField } from "./useField.js";
-import { Duration } from "@gnu-taler/taler-util";
-
-export interface Props<T> extends InputProps<T> {
- expand?: boolean;
- readonly?: boolean;
- withForever?: boolean;
- side?: ComponentChildren;
- withoutClear?: boolean;
-}
-
-export function InputDuration<T>({
- name,
- expand,
- placeholder,
- tooltip,
- label,
- help,
- readonly,
- withForever,
- withoutClear,
- side,
-}: Props<keyof T>): VNode {
- const [opened, setOpened] = useState(false);
- const { i18n } = useTranslationContext();
-
- const { error, required, value: anyValue, onChange } = useField<T>(name);
- let strValue = "";
- const value: Duration = anyValue
- if (!value) {
- strValue = "";
- } else if (value.d_ms === "forever") {
- strValue = i18n.str`forever`;
- } else {
- strValue = formatDuration(
- intervalToDuration({ start: 0, end: value.d_ms }),
- {
- locale: {
- formatDistance: (name, value) => {
- switch (name) {
- case "xMonths":
- return i18n.str`${value}M`;
- case "xYears":
- return i18n.str`${value}Y`;
- case "xDays":
- return i18n.str`${value}d`;
- case "xHours":
- return i18n.str`${value}h`;
- case "xMinutes":
- return i18n.str`${value}min`;
- case "xSeconds":
- return i18n.str`${value}sec`;
- }
- },
- localize: {
- day: () => "s",
- month: () => "m",
- ordinalNumber: () => "th",
- dayPeriod: () => "p",
- quarter: () => "w",
- era: () => "e",
- },
- },
- },
- );
- }
-
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal is-flex-grow-3">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
-
- <div class="is-flex-grow-3">
- <div class="field-body ">
- <div class="field">
- <div class="field has-addons">
- <p class={expand ? "control is-expanded " : "control "}>
- <input
- class="input"
- type="text"
- readonly
- value={strValue}
- placeholder={placeholder}
- onClick={() => {
- if (!readonly) setOpened(true);
- }}
- />
- {required && (
- <span class="icon has-text-danger is-right">
- <i class="mdi mdi-alert" />
- </span>
- )}
- </p>
- <div
- class="control"
- onClick={() => {
- if (!readonly) setOpened(true);
- }}
- >
- <a class="button is-static">
- <span class="icon">
- <i class="mdi mdi-clock" />
- </span>
- </a>
- </div>
- </div>
- {error && <p class="help is-danger">{error}</p>}
- </div>
- {withForever && (
- <span data-tooltip={i18n.str`change value to never`}>
- <button
- class="button is-info mr-3"
- onClick={() => onChange({ d_ms: "forever" } as any)}
- >
- <i18n.Translate>forever</i18n.Translate>
- </button>
- </span>
- )}
- {!readonly && !withoutClear && (
- <span data-tooltip={i18n.str`change value to empty`}>
- <button
- class="button is-info "
- onClick={() => onChange(undefined as any)}
- >
- <i18n.Translate>clear</i18n.Translate>
- </button>
- </span>
- )}
- {side}
- </div>
- <span>
- {help}
- </span>
- </div>
-
-
- {opened && (
- <SimpleModal onCancel={() => setOpened(false)}>
- <DurationPicker
- days
- hours
- minutes
- value={!value || value.d_ms === "forever" ? 0 : value.d_ms}
- onChange={(v) => {
- onChange({ d_ms: v } as any);
- }}
- />
- </SimpleModal>
- )}
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputGroup.tsx b/packages/auditor-backoffice-ui/src/components/form/InputGroup.tsx
deleted file mode 100644
index 92b9e8b16..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputGroup.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { ComponentChildren, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { useGroupField } from "./useGroupField.js";
-
-export interface Props<T> {
- name: T;
- children: ComponentChildren;
- label: ComponentChildren;
- tooltip?: ComponentChildren;
- alternative?: ComponentChildren;
- fixed?: boolean;
- initialActive?: boolean;
-}
-
-export function InputGroup<T>({
- name,
- label,
- children,
- tooltip,
- alternative,
- fixed,
- initialActive,
-}: Props<keyof T>): VNode {
- const [active, setActive] = useState(initialActive || fixed);
- const group = useGroupField<T>(name);
-
- return (
- <div class="card">
- <header class="card-header">
- <p class="card-header-title">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- {group?.hasError && (
- <span class="icon has-text-danger" data-tooltip={tooltip}>
- <i class="mdi mdi-alert" />
- </span>
- )}
- </p>
- {!fixed && (
- <button
- class="card-header-icon"
- aria-label="more options"
- onClick={(): void => setActive(!active)}
- >
- <span class="icon">
- {active ? (
- <i class="mdi mdi-arrow-up" />
- ) : (
- <i class="mdi mdi-arrow-down" />
- )}
- </span>
- </button>
- )}
- </header>
- {active ? (
- <div class="card-content">{children}</div>
- ) : alternative ? (
- <div class="card-content">{alternative}</div>
- ) : undefined}
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputImage.tsx b/packages/auditor-backoffice-ui/src/components/form/InputImage.tsx
deleted file mode 100644
index d284b476f..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputImage.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { ComponentChildren, h, VNode } from "preact";
-import { useRef, useState } from "preact/hooks";
-import { MAX_IMAGE_SIZE as MAX_IMAGE_UPLOAD_SIZE } from "../../utils/constants.js";
-import { InputProps, useField } from "./useField.js";
-
-export interface Props<T> extends InputProps<T> {
- expand?: boolean;
- addonAfter?: ComponentChildren;
- children?: ComponentChildren;
-}
-
-export function InputImage<T>({
- name,
- readonly,
- placeholder,
- tooltip,
- label,
- help,
- children,
- expand,
-}: Props<keyof T>): VNode {
- const { error, value, onChange } = useField<T>(name);
-
- const image = useRef<HTMLInputElement>(null);
- const { i18n } = useTranslationContext();
- const [sizeError, setSizeError] = useState(false);
-
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field">
- <p class={expand ? "control is-expanded" : "control"}>
- {value && (
- <img
- src={value}
- style={{ width: 200, height: 200 }}
- onClick={() => image.current?.click()}
- />
- )}
- <input
- ref={image}
- style={{ display: "none" }}
- type="file"
- name={String(name)}
- placeholder={placeholder}
- readonly={readonly}
- onChange={(e) => {
- const f: FileList | null = e.currentTarget.files;
- if (!f || f.length != 1) {
- return onChange(undefined!);
- }
- if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
- setSizeError(true);
- return onChange(undefined!);
- }
- setSizeError(false);
- return f[0].arrayBuffer().then((b) => {
- const b64 = window.btoa(
- new Uint8Array(b).reduce(
- (data, byte) => data + String.fromCharCode(byte),
- "",
- ),
- );
- return onChange(`data:${f[0].type};base64,${b64}` as any);
- });
- }}
- />
- {help}
- {children}
- </p>
- {error && <p class="help is-danger">{error}</p>}
- {sizeError && (
- <p class="help is-danger">
- <i18n.Translate>Image should be smaller than 1 MB</i18n.Translate>
- </p>
- )}
- {!value && (
- <button class="button" onClick={() => image.current?.click()}>
- <i18n.Translate>Add</i18n.Translate>
- </button>
- )}
- {value && (
- <button class="button" onClick={() => onChange(undefined!)}>
- <i18n.Translate>Remove</i18n.Translate>
- </button>
- )}
- </div>
- </div>
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputLocation.tsx b/packages/auditor-backoffice-ui/src/components/form/InputLocation.tsx
deleted file mode 100644
index d4b13d555..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputLocation.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { Fragment, h } from "preact";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Input } from "./Input.js";
-
-export function InputLocation({ name }: { name: string }) {
- const { i18n } = useTranslationContext();
- return (
- <>
- <Input name={`${name}.country`} label={i18n.str`Country`} />
- <Input
- name={`${name}.address_lines`}
- inputType="multiline"
- label={i18n.str`Address`}
- toStr={(v: string[] | undefined) => (!v ? "" : v.join("\n"))}
- fromStr={(v: string) => v.split("\n")}
- />
- <Input
- name={`${name}.building_number`}
- label={i18n.str`Building number`}
- />
- <Input name={`${name}.building_name`} label={i18n.str`Building name`} />
- <Input name={`${name}.street`} label={i18n.str`Street`} />
- <Input name={`${name}.post_code`} label={i18n.str`Post code`} />
- <Input name={`${name}.town_location`} label={i18n.str`Town location`} />
- <Input name={`${name}.town`} label={i18n.str`Town`} />
- <Input name={`${name}.district`} label={i18n.str`District`} />
- <Input
- name={`${name}.country_subdivision`}
- label={i18n.str`Country subdivision`}
- />
- </>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputPayto.tsx b/packages/auditor-backoffice-ui/src/components/form/InputPayto.tsx
deleted file mode 100644
index fcecd8932..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputPayto.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 } from "preact";
-import { InputArray } from "./InputArray.js";
-import { PAYTO_REGEX } from "../../utils/constants.js";
-import { InputProps } from "./useField.js";
-
-export type Props<T> = InputProps<T>;
-
-const PAYTO_START_REGEX = /^payto:\/\//;
-
-export function InputPayto<T>({
- name,
- readonly,
- placeholder,
- tooltip,
- label,
- help,
-}: Props<keyof T>): VNode {
- return (
- <InputArray<T>
- name={name}
- readonly={readonly}
- addonBefore="payto://"
- label={label}
- placeholder={placeholder}
- help={help}
- tooltip={tooltip}
- isValid={(v) => v && PAYTO_REGEX.test(v)}
- toStr={(v?: string) => (!v ? "" : v.replace(PAYTO_START_REGEX, ""))}
- fromStr={(v: string) => `payto://${v}`}
- />
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx b/packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx
deleted file mode 100644
index cc5326bbe..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 } from "preact";
-import * as tests from "@gnu-taler/web-util/testing";
-import { InputPaytoForm } from "./InputPaytoForm.js";
-import { FormProvider } from "./FormProvider.js";
-import { useState } from "preact/hooks";
-
-export default {
- title: "Components/Form/PayTo",
- component: InputPaytoForm,
- argTypes: {
- onUpdate: { action: "onUpdate" },
- onBack: { action: "onBack" },
- },
-};
-
-export const Example = tests.createExample(() => {
- const initial = {
- accounts: [],
- };
- const [form, updateForm] = useState<Partial<typeof initial>>(initial);
- return (
- <FormProvider valueHandler={updateForm} object={form}>
- <InputPaytoForm name="accounts" label="Accounts:" />
- </FormProvider>
- );
-}, {});
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.tsx b/packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.tsx
deleted file mode 100644
index 7eba8b0b5..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputPaytoForm.tsx
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { parsePaytoUri, PaytoUriGeneric, stringifyPaytoUri } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
-import { COUNTRY_TABLE } from "../../utils/constants.js";
-import { undefinedIfEmpty } from "../../utils/table.js";
-import { FormErrors, FormProvider } from "./FormProvider.js";
-import { Input } from "./Input.js";
-import { InputGroup } from "./InputGroup.js";
-import { InputSelector } from "./InputSelector.js";
-import { InputProps, useField } from "./useField.js";
-import { useEffect, useState } from "preact/hooks";
-
-export interface Props<T> extends InputProps<T> {
- isValid?: (e: any) => boolean;
-}
-
-// type Entity = PaytoUriGeneric
-// https://datatracker.ietf.org/doc/html/rfc8905
-type Entity = {
- // iban, bitcoin, x-taler-bank. it defined the format
- target: string;
- // path1 if the first field to be used
- path1?: string;
- // path2 if the second field to be used, optional
- path2?: string;
- // params of the payto uri
- params: {
- "receiver-name"?: string;
- sender?: string;
- message?: string;
- amount?: string;
- instruction?: string;
- [name: string]: string | undefined;
- };
-};
-
-function isEthereumAddress(address: string) {
- if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) {
- return false;
- } else if (
- /^(0x|0X)?[0-9a-f]{40}$/.test(address) ||
- /^(0x|0X)?[0-9A-F]{40}$/.test(address)
- ) {
- return true;
- }
- return checkAddressChecksum(address);
-}
-
-function checkAddressChecksum(address: string) {
- //TODO implement ethereum checksum
- return true;
-}
-
-function validateBitcoin(
- addr: string,
- i18n: ReturnType<typeof useTranslationContext>["i18n"],
-): string | undefined {
- try {
- const valid = /^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,39}$/.test(addr);
- if (valid) return undefined;
- } catch (e) {
- console.log(e);
- }
- return i18n.str`This is not a valid bitcoin address.`;
-}
-
-function validateEthereum(
- addr: string,
- i18n: ReturnType<typeof useTranslationContext>["i18n"],
-): string | undefined {
- try {
- const valid = isEthereumAddress(addr);
- if (valid) return undefined;
- } catch (e) {
- console.log(e);
- }
- return i18n.str`This is not a valid Ethereum address.`;
-}
-
-/**
- * An IBAN is validated by converting it into an integer and performing a
- * basic mod-97 operation (as described in ISO 7064) on it.
- * If the IBAN is valid, the remainder equals 1.
- *
- * The algorithm of IBAN validation is as follows:
- * 1.- Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid
- * 2.- Move the four initial characters to the end of the string
- * 3.- Replace each letter in the string with two digits, thereby expanding the string, where A = 10, B = 11, ..., Z = 35
- * 4.- Interpret the string as a decimal integer and compute the remainder of that number on division by 97
- *
- * If the remainder is 1, the check digit test is passed and the IBAN might be valid.
- *
- */
-function validateIBAN(
- iban: string,
- i18n: ReturnType<typeof useTranslationContext>["i18n"],
-): string | undefined {
- // Check total length
- if (iban.length < 4)
- return i18n.str`IBAN numbers usually have more that 4 digits`;
- if (iban.length > 34)
- return i18n.str`IBAN numbers usually have less that 34 digits`;
-
- const A_code = "A".charCodeAt(0);
- const Z_code = "Z".charCodeAt(0);
- const IBAN = iban.toUpperCase();
- // check supported country
- const code = IBAN.substr(0, 2);
- const found = code in COUNTRY_TABLE;
- if (!found) return i18n.str`IBAN country code not found`;
-
- // 2.- Move the four initial characters to the end of the string
- const step2 = IBAN.substr(4) + iban.substr(0, 4);
- const step3 = Array.from(step2)
- .map((letter) => {
- const code = letter.charCodeAt(0);
- if (code < A_code || code > Z_code) return letter;
- return `${letter.charCodeAt(0) - "A".charCodeAt(0) + 10}`;
- })
- .join("");
-
- function calculate_iban_checksum(str: string): number {
- const numberStr = str.substr(0, 5);
- const rest = str.substr(5);
- const number = parseInt(numberStr, 10);
- const result = number % 97;
- if (rest.length > 0) {
- return calculate_iban_checksum(`${result}${rest}`);
- }
- return result;
- }
-
- const checksum = calculate_iban_checksum(step3);
- if (checksum !== 1)
- return i18n.str`IBAN number is not valid, checksum is wrong`;
- return undefined;
-}
-
-// const targets = ['ach', 'bic', 'iban', 'upi', 'bitcoin', 'ilp', 'void', 'x-taler-bank']
-const targets = [
- "Choose one...",
- "iban",
- "x-taler-bank",
- "bitcoin",
- "ethereum",
-];
-const noTargetValue = targets[0];
-const defaultTarget: Entity = {
- target: noTargetValue,
- params: {},
-};
-
-export function InputPaytoForm<T>({
- name,
- readonly,
- label,
- tooltip,
-}: Props<keyof T>): VNode {
- const { value: initialValueStr, onChange } = useField<T>(name);
-
- const initialPayto = parsePaytoUri(initialValueStr ?? "")
- const paths = !initialPayto ? [] : initialPayto.targetPath.split("/")
- const initialPath1 = paths.length >= 1 ? paths[0] : undefined;
- const initialPath2 = paths.length >= 2 ? paths[1] : undefined;
- const initial: Entity = initialPayto === undefined ? defaultTarget : {
- target: initialPayto.targetType,
- params: initialPayto.params,
- path1: initialPath1,
- path2: initialPath2,
- }
- const [value, setValue] = useState<Partial<Entity>>(initial)
-
- const { i18n } = useTranslationContext();
-
- const errors: FormErrors<Entity> = {
- target:
- value.target === noTargetValue
- ? i18n.str`required`
- : undefined,
- path1: !value.path1
- ? i18n.str`required`
- : value.target === "iban"
- ? validateIBAN(value.path1, i18n)
- : value.target === "bitcoin"
- ? validateBitcoin(value.path1, i18n)
- : value.target === "ethereum"
- ? validateEthereum(value.path1, i18n)
- : undefined,
- path2:
- value.target === "x-taler-bank"
- ? !value.path2
- ? i18n.str`required`
- : undefined
- : undefined,
- params: undefinedIfEmpty({
- "receiver-name": !value.params?.["receiver-name"]
- ? i18n.str`required`
- : undefined,
- }),
- };
-
- const hasErrors = Object.keys(errors).some(
- (k) => (errors as any)[k] !== undefined,
- );
- const str = hasErrors || !value.target ? undefined : stringifyPaytoUri({
- targetType: value.target,
- targetPath: value.path2 ? `${value.path1}/${value.path2}` : (value.path1 ?? ""),
- params: value.params ?? {} as any,
- isKnown: false,
- })
- useEffect(() => {
- onChange(str as any)
- }, [str])
-
- // const submit = useCallback((): void => {
- // // const accounts: MerchantBackend.BankAccounts.AccountAddDetails[] = paytos;
- // // const alreadyExists =
- // // accounts.findIndex((x) => x.payto_uri === paytoURL) !== -1;
- // // if (!alreadyExists) {
- // const newValue: MerchantBackend.BankAccounts.AccountAddDetails = {
- // payto_uri: paytoURL,
- // };
- // if (value.auth) {
- // if (value.auth.url) {
- // newValue.credit_facade_url = value.auth.url;
- // }
- // if (value.auth.type === "none") {
- // newValue.credit_facade_credentials = {
- // type: "none",
- // };
- // }
- // if (value.auth.type === "basic") {
- // newValue.credit_facade_credentials = {
- // type: "basic",
- // username: value.auth.username ?? "",
- // password: value.auth.password ?? "",
- // };
- // }
- // }
- // onChange(newValue as any);
- // // }
- // // valueHandler(defaultTarget);
- // }, [value]);
-
- //FIXME: translating plural singular
- return (
- <InputGroup name="payto" label={label} fixed tooltip={tooltip}>
- <FormProvider<Entity>
- name="tax"
- errors={errors}
- object={value}
- valueHandler={setValue}
- >
- <InputSelector<Entity>
- name="target"
- label={i18n.str`Account type`}
- tooltip={i18n.str`Method to use for wire transfer`}
- values={targets}
- readonly={readonly}
- toStr={(v) => (v === noTargetValue ? i18n.str`Choose one...` : v)}
- />
-
- {value.target === "ach" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- label={i18n.str`Routing`}
- readonly={readonly}
- tooltip={i18n.str`Routing number.`}
- />
- <Input<Entity>
- name="path2"
- label={i18n.str`Account`}
- readonly={readonly}
- tooltip={i18n.str`Account number.`}
- />
- </Fragment>
- )}
- {value.target === "bic" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- label={i18n.str`Code`}
- readonly={readonly}
- tooltip={i18n.str`Business Identifier Code.`}
- />
- </Fragment>
- )}
- {value.target === "iban" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- label={i18n.str`IBAN`}
- tooltip={i18n.str`International Bank Account Number.`}
- readonly={readonly}
- placeholder="DE1231231231"
- inputExtra={{ style: { textTransform: "uppercase" } }}
- />
- </Fragment>
- )}
- {value.target === "upi" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- readonly={readonly}
- label={i18n.str`Account`}
- tooltip={i18n.str`Unified Payment Interface.`}
- />
- </Fragment>
- )}
- {value.target === "bitcoin" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- readonly={readonly}
- label={i18n.str`Address`}
- tooltip={i18n.str`Bitcoin protocol.`}
- />
- </Fragment>
- )}
- {value.target === "ethereum" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- readonly={readonly}
- label={i18n.str`Address`}
- tooltip={i18n.str`Ethereum protocol.`}
- />
- </Fragment>
- )}
- {value.target === "ilp" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- readonly={readonly}
- label={i18n.str`Address`}
- tooltip={i18n.str`Interledger protocol.`}
- />
- </Fragment>
- )}
- {value.target === "void" && <Fragment />}
- {value.target === "x-taler-bank" && (
- <Fragment>
- <Input<Entity>
- name="path1"
- readonly={readonly}
- label={i18n.str`Host`}
- tooltip={i18n.str`Bank host.`}
- />
- <Input<Entity>
- name="path2"
- readonly={readonly}
- label={i18n.str`Account`}
- tooltip={i18n.str`Bank account.`}
- />
- </Fragment>
- )}
-
- {/**
- * Show additional fields apart from the payto
- */}
- {value.target !== noTargetValue && (
- <Fragment>
- <Input
- name="params.receiver-name"
- readonly={readonly}
- label={i18n.str`Owner's name`}
- tooltip={i18n.str`Legal name of the person holding the account.`}
- />
- </Fragment>
- )}
-
- </FormProvider>
- </InputGroup>
- );
-}
-
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputSearchOnList.tsx b/packages/auditor-backoffice-ui/src/components/form/InputSearchOnList.tsx
deleted file mode 100644
index 9956a6427..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputSearchOnList.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import emptyImage from "../../assets/empty.png";
-import { FormErrors, FormProvider } from "./FormProvider.js";
-import { InputWithAddon } from "./InputWithAddon.js";
-import { TranslatedString } from "@gnu-taler/taler-util";
-
-type Entity = {
- id: string,
- description: string;
- image?: string;
- extra?: string;
-};
-
-export interface Props<T extends Entity> {
- selected?: T;
- onChange: (p?: T) => void;
- label: TranslatedString;
- list: T[];
- withImage?: boolean;
-}
-
-interface Search {
- name: string;
-}
-
-export function InputSearchOnList<T extends Entity>({
- selected,
- onChange,
- label,
- list,
- withImage,
-}: Props<T>): VNode {
- const [nameForm, setNameForm] = useState<Partial<Search>>({
- name: "",
- });
-
- const errors: FormErrors<Search> = {
- name: undefined,
- };
- const { i18n } = useTranslationContext();
-
- if (selected) {
- return (
- <article class="media">
- {withImage &&
- <figure class="media-left">
- <p class="image is-128x128">
- <img src={selected.image ? selected.image : emptyImage} />
- </p>
- </figure>
- }
- <div class="media-content">
- <div class="content">
- <p class="media-meta">
- <i18n.Translate>ID</i18n.Translate>: <b>{selected.id}</b>
- </p>
- <p>
- <i18n.Translate>Description</i18n.Translate>:{" "}
- {selected.description}
- </p>
- <div class="buttons is-right mt-5">
- <button
- class="button is-info"
- onClick={() => onChange(undefined)}
- >
- clear
- </button>
- </div>
- </div>
- </div>
- </article>
- );
- }
-
- return (
- <FormProvider<Search>
- errors={errors}
- object={nameForm}
- valueHandler={setNameForm}
- >
- <InputWithAddon<Search>
- name="name"
- label={label}
- tooltip={i18n.str`enter description or id`}
- addonAfter={
- <span class="icon">
- <i class="mdi mdi-magnify" />
- </span>
- }
- >
- <div>
- <DropdownList
- name={nameForm.name}
- list={list}
- onSelect={(p) => {
- setNameForm({ name: "" });
- onChange(p);
- }}
- withImage={!!withImage}
- />
- </div>
- </InputWithAddon>
- </FormProvider>
- );
-}
-
-interface DropdownListProps<T extends Entity> {
- name?: string;
- onSelect: (p: T) => void;
- list: T[];
- withImage: boolean;
-}
-
-function DropdownList<T extends Entity>({ name, onSelect, list, withImage }: DropdownListProps<T>) {
- const { i18n } = useTranslationContext();
- if (!name) {
- /* FIXME
- this BR is added to occupy the space that will be added when the
- dropdown appears
- */
- return (
- <div>
- <br />
- </div>
- );
- }
- const filtered = list.filter(
- (p) => p.id.includes(name) || p.description.includes(name),
- );
-
- return (
- <div class="dropdown is-active">
- <div
- class="dropdown-menu"
- id="dropdown-menu"
- role="menu"
- style={{ minWidth: "20rem" }}
- >
- <div class="dropdown-content">
- {!filtered.length ? (
- <div class="dropdown-item">
- <i18n.Translate>
- no match found with that description or id
- </i18n.Translate>
- </div>
- ) : (
- filtered.map((p) => (
- <div
- key={p.id}
- class="dropdown-item"
- onClick={() => onSelect(p)}
- style={{ cursor: "pointer" }}
- >
- <article class="media">
- {withImage &&
- <div class="media-left">
- <div class="image" style={{ minWidth: 64 }}>
- <img
- src={p.image ? p.image : emptyImage}
- style={{ width: 64, height: 64 }}
- />
- </div>
- </div>
- }
- <div class="media-content">
- <div class="content">
- <p>
- <strong>{p.id}</strong> {p.extra !== undefined ? <small>{p.extra}</small> : undefined}
- <br />
- {p.description}
- </p>
- </div>
- </div>
- </article>
- </div>
- ))
- )}
- </div>
- </div>
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputSecured.stories.tsx b/packages/auditor-backoffice-ui/src/components/form/InputSecured.stories.tsx
deleted file mode 100644
index 4de84d984..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputSecured.stories.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 } from "preact";
-import { useState } from "preact/hooks";
-import { FormProvider } from "./FormProvider.js";
-import { InputSecured } from "./InputSecured.js";
-
-export default {
- title: "Components/Form/InputSecured",
- component: InputSecured,
-};
-
-type T = { auth_token: string | null };
-
-export const InitialValueEmpty = (): VNode => {
- const [state, setState] = useState<Partial<T>>({ auth_token: "" });
- return (
- <FormProvider<T> object={state} errors={{}} valueHandler={setState}>
- Initial value: ''
- <InputSecured<T> name="auth_token" label="Access token" />
- </FormProvider>
- );
-};
-
-export const InitialValueToken = (): VNode => {
- const [state, setState] = useState<Partial<T>>({ auth_token: "token" });
- return (
- <FormProvider<T> object={state} errors={{}} valueHandler={setState}>
- <InputSecured<T> name="auth_token" label="Access token" />
- </FormProvider>
- );
-};
-
-export const InitialValueNull = (): VNode => {
- const [state, setState] = useState<Partial<T>>({ auth_token: null });
- return (
- <FormProvider<T> object={state} errors={{}} valueHandler={setState}>
- Initial value: ''
- <InputSecured<T> name="auth_token" label="Access token" />
- </FormProvider>
- );
-};
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputSecured.tsx b/packages/auditor-backoffice-ui/src/components/form/InputSecured.tsx
deleted file mode 100644
index 4a35ad96c..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputSecured.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { InputProps, useField } from "./useField.js";
-
-export type Props<T> = InputProps<T>;
-
-const TokenStatus = ({ prev, post }: any) => {
- const { i18n } = useTranslationContext();
- if (
- (prev === undefined || prev === null) &&
- (post === undefined || post === null)
- )
- return null;
- return prev === post ? null : post === null ? (
- <span class="tag is-danger is-align-self-center ml-2">
- <i18n.Translate>Deleting</i18n.Translate>
- </span>
- ) : (
- <span class="tag is-warning is-align-self-center ml-2">
- <i18n.Translate>Changing</i18n.Translate>
- </span>
- );
-};
-
-export function InputSecured<T>({
- name,
- readonly,
- placeholder,
- tooltip,
- label,
- help,
-}: Props<keyof T>): VNode {
- const { error, value, initial, onChange, toStr, fromStr } = useField<T>(name);
-
- const [active, setActive] = useState(false);
- const [newValue, setNuewValue] = useState("");
-
- const { i18n } = useTranslationContext();
-
- return (
- <Fragment>
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- {!active ? (
- <Fragment>
- <div class="field has-addons">
- <button
- class="button"
- onClick={(): void => {
- setActive(!active);
- }}
- >
- <div class="icon is-left">
- <i class="mdi mdi-lock-reset" />
- </div>
- <span>
- <i18n.Translate>Manage access token</i18n.Translate>
- </span>
- </button>
- <TokenStatus prev={initial} post={value} />
- </div>
- </Fragment>
- ) : (
- <Fragment>
- <div class="field has-addons">
- <div class="control">
- <a class="button is-static">secret-token:</a>
- </div>
- <div class="control is-expanded">
- <input
- class="input"
- type="text"
- placeholder={placeholder}
- readonly={readonly || !active}
- disabled={readonly || !active}
- name={String(name)}
- value={newValue}
- onInput={(e): void => {
- setNuewValue(e.currentTarget.value);
- }}
- />
- {help}
- </div>
- <div class="control">
- <button
- class="button is-info"
- disabled={fromStr(newValue) === value}
- onClick={(): void => {
- onChange(fromStr(newValue));
- setActive(!active);
- setNuewValue("");
- }}
- >
- <div class="icon is-left">
- <i class="mdi mdi-lock-outline" />
- </div>
- <span>
- <i18n.Translate>Update</i18n.Translate>
- </span>
- </button>
- </div>
- </div>
- </Fragment>
- )}
- {error ? <p class="help is-danger">{error}</p> : null}
- </div>
- </div>
- {active && (
- <div class="field is-horizontal">
- <div class="field-body is-flex-grow-3">
- <div class="level" style={{ width: "100%" }}>
- <div class="level-right is-flex-grow-1">
- <div class="level-item">
- <button
- class="button is-danger"
- disabled={null === value || undefined === value}
- onClick={(): void => {
- onChange(null!);
- setActive(!active);
- setNuewValue("");
- }}
- >
- <div class="icon is-left">
- <i class="mdi mdi-lock-open-variant" />
- </div>
- <span>
- <i18n.Translate>Remove</i18n.Translate>
- </span>
- </button>
- </div>
- <div class="level-item">
- <button
- class="button "
- onClick={(): void => {
- onChange(initial!);
- setActive(!active);
- setNuewValue("");
- }}
- >
- <div class="icon is-left">
- <i class="mdi mdi-lock-open-variant" />
- </div>
- <span>
- <i18n.Translate>Cancel</i18n.Translate>
- </span>
- </button>
- </div>
- </div>
- </div>
- </div>
- </div>
- )}
- </Fragment>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputStock.stories.tsx b/packages/auditor-backoffice-ui/src/components/form/InputStock.stories.tsx
deleted file mode 100644
index d7cf04553..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputStock.stories.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { addDays } from "date-fns";
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { FormProvider } from "./FormProvider.js";
-import { InputStock, Stock } from "./InputStock.js";
-
-export default {
- title: "Components/Form/InputStock",
- component: InputStock,
-};
-
-type T = { stock?: Stock };
-
-export const CreateStockEmpty = () => {
- const [state, setState] = useState<Partial<T>>({});
- return (
- <FormProvider<T>
- name="product"
- object={state}
- errors={{}}
- valueHandler={setState}
- >
- <InputStock<T> name="stock" label="Stock" />
- <div>
- <pre>{JSON.stringify(state, undefined, 2)}</pre>
- </div>
- </FormProvider>
- );
-};
-
-export const CreateStockUnknownRestock = () => {
- const [state, setState] = useState<Partial<T>>({
- stock: {
- current: 10,
- lost: 0,
- sold: 0,
- },
- });
- return (
- <FormProvider<T>
- name="product"
- object={state}
- errors={{}}
- valueHandler={setState}
- >
- <InputStock<T> name="stock" label="Stock" />
- <div>
- <pre>{JSON.stringify(state, undefined, 2)}</pre>
- </div>
- </FormProvider>
- );
-};
-
-export const CreateStockNoRestock = () => {
- const [state, setState] = useState<Partial<T>>({
- stock: {
- current: 10,
- lost: 0,
- sold: 0,
- nextRestock: { t_s: "never" },
- },
- });
- return (
- <FormProvider<T>
- name="product"
- object={state}
- errors={{}}
- valueHandler={setState}
- >
- <InputStock<T> name="stock" label="Stock" />
- <div>
- <pre>{JSON.stringify(state, undefined, 2)}</pre>
- </div>
- </FormProvider>
- );
-};
-
-export const CreateStockWithRestock = () => {
- const [state, setState] = useState<Partial<T>>({
- stock: {
- current: 15,
- lost: 0,
- sold: 0,
- nextRestock: { t_s: addDays(new Date(), 1).getTime() / 1000 },
- },
- });
- return (
- <FormProvider<T>
- name="product"
- object={state}
- errors={{}}
- valueHandler={setState}
- >
- <InputStock<T> name="stock" label="Stock" />
- <div>
- <pre>{JSON.stringify(state, undefined, 2)}</pre>
- </div>
- </FormProvider>
- );
-};
-
-export const UpdatingProductWithManagedStock = () => {
- const [state, setState] = useState<Partial<T>>({
- stock: {
- current: 100,
- lost: 0,
- sold: 0,
- nextRestock: { t_s: addDays(new Date(), 1).getTime() / 1000 },
- },
- });
- return (
- <FormProvider<T>
- name="product"
- object={state}
- errors={{}}
- valueHandler={setState}
- >
- <InputStock<T> name="stock" label="Stock" alreadyExist />
- <div>
- <pre>{JSON.stringify(state, undefined, 2)}</pre>
- </div>
- </FormProvider>
- );
-};
-
-export const UpdatingProductWithInfiniteStock = () => {
- const [state, setState] = useState<Partial<T>>({});
- return (
- <FormProvider<T>
- name="product"
- object={state}
- errors={{}}
- valueHandler={setState}
- >
- <InputStock<T> name="stock" label="Stock" alreadyExist />
- <div>
- <pre>{JSON.stringify(state, undefined, 2)}</pre>
- </div>
- </FormProvider>
- );
-};
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputStock.tsx b/packages/auditor-backoffice-ui/src/components/form/InputStock.tsx
deleted file mode 100644
index 5c98f7311..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputStock.tsx
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 } from "preact";
-import { useLayoutEffect, useState } from "preact/hooks";
-import { MerchantBackend, Timestamp } from "../../declaration.js";
-import { FormErrors, FormProvider } from "./FormProvider.js";
-import { InputDate } from "./InputDate.js";
-import { InputGroup } from "./InputGroup.js";
-import { InputLocation } from "./InputLocation.js";
-import { InputNumber } from "./InputNumber.js";
-import { InputProps, useField } from "./useField.js";
-
-export interface Props<T> extends InputProps<T> {
- alreadyExist?: boolean;
-}
-
-type Entity = Stock;
-
-export interface Stock {
- current: number;
- lost: number;
- sold: number;
- address?: MerchantBackend.Location;
- nextRestock?: Timestamp;
-}
-
-interface StockDelta {
- incoming: number;
- lost: number;
-}
-
-export function InputStock<T>({
- name,
- tooltip,
- label,
- alreadyExist,
-}: Props<keyof T>) {
- const { error, value, onChange } = useField<T>(name);
-
- const [errors, setErrors] = useState<FormErrors<Entity>>({});
-
- const [formValue, valueHandler] = useState<Partial<Entity>>(value);
- const [addedStock, setAddedStock] = useState<StockDelta>({
- incoming: 0,
- lost: 0,
- });
- const { i18n } = useTranslationContext();
-
- useLayoutEffect(() => {
- if (!formValue) {
- onChange(undefined as any);
- } else {
- onChange({
- ...formValue,
- current: (formValue?.current || 0) + addedStock.incoming,
- lost: (formValue?.lost || 0) + addedStock.lost,
- } as any);
- }
- }, [formValue, addedStock]);
-
- if (!formValue) {
- return (
- <Fragment>
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field has-addons">
- {!alreadyExist ? (
- <button
- class="button"
- data-tooltip={i18n.str`click here to configure the stock of the product, leave it as is and the backend will not control stock`}
- onClick={(): void => {
- valueHandler({
- current: 0,
- lost: 0,
- sold: 0,
- } as Stock as any);
- }}
- >
- <span>
- <i18n.Translate>Manage stock</i18n.Translate>
- </span>
- </button>
- ) : (
- <button
- class="button"
- data-tooltip={i18n.str`this product has been configured without stock control`}
- disabled
- >
- <span>
- <i18n.Translate>Infinite</i18n.Translate>
- </span>
- </button>
- )}
- </div>
- </div>
- </div>
- </Fragment>
- );
- }
-
- const currentStock =
- (formValue.current || 0) - (formValue.lost || 0) - (formValue.sold || 0);
-
- const stockAddedErrors: FormErrors<typeof addedStock> = {
- lost:
- currentStock + addedStock.incoming < addedStock.lost
- ? i18n.str`lost cannot be greater than current and incoming (max ${
- currentStock + addedStock.incoming
- })`
- : undefined,
- };
-
- // const stockUpdateDescription = stockAddedErrors.lost ? '' : (
- // !!addedStock.incoming || !!addedStock.lost ?
- // i18n.str`current stock will change from ${currentStock} to ${currentStock + addedStock.incoming - addedStock.lost}` :
- // i18n.str`current stock will stay at ${currentStock}`
- // )
-
- return (
- <Fragment>
- <div class="card">
- <header class="card-header">
- <p class="card-header-title">
- {label}
- {tooltip && (
- <span class="icon" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </p>
- </header>
- <div class="card-content">
- <FormProvider<Entity>
- name="stock"
- errors={errors}
- object={formValue}
- valueHandler={valueHandler}
- >
- {alreadyExist ? (
- <Fragment>
- <FormProvider
- name="added"
- errors={stockAddedErrors}
- object={addedStock}
- valueHandler={setAddedStock as any}
- >
- <InputNumber name="incoming" label={i18n.str`Incoming`} />
- <InputNumber name="lost" label={i18n.str`Lost`} />
- </FormProvider>
-
- {/* <div class="field is-horizontal">
- <div class="field-label is-normal" />
- <div class="field-body is-flex-grow-3">
- <div class="field">
- {stockUpdateDescription}
- </div>
- </div>
- </div> */}
- </Fragment>
- ) : (
- <InputNumber<Entity>
- name="current"
- label={i18n.str`Current`}
- side={
- <button
- class="button is-danger"
- data-tooltip={i18n.str`remove stock control for this product`}
- onClick={(): void => {
- valueHandler(undefined as any);
- }}
- >
- <span>
- <i18n.Translate>without stock</i18n.Translate>
- </span>
- </button>
- }
- />
- )}
-
- <InputDate<Entity>
- name="nextRestock"
- label={i18n.str`Next restock`}
- withTimestampSupport
- />
-
- <InputGroup<Entity> name="address" label={i18n.str`Warehouse address`}>
- <InputLocation name="address" />
- </InputGroup>
- </FormProvider>
- </div>
- </div>
- </Fragment>
- );
-}
-// (
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputTab.tsx b/packages/auditor-backoffice-ui/src/components/form/InputTab.tsx
deleted file mode 100644
index 1cd88d31a..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputTab.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 } from "preact";
-import { InputProps, useField } from "./useField.js";
-
-interface Props<T> extends InputProps<T> {
- readonly?: boolean;
- expand?: boolean;
- values: any[];
- toStr?: (v?: any) => string;
- fromStr?: (s: string) => any;
-}
-
-const defaultToString = (f?: any): string => f || "";
-const defaultFromString = (v: string): any => v as any;
-
-export function InputTab<T>({
- name,
- readonly,
- expand,
- placeholder,
- tooltip,
- label,
- help,
- values,
- fromStr = defaultFromString,
- toStr = defaultToString,
-}: Props<keyof T>): VNode {
- const { error, value, onChange, required } = useField<T>(name);
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field has-icons-right">
- <p class={expand ? "control is-expanded " : "control "}>
- <div class="tabs is-toggle is-fullwidth is-small">
- <ul>
- {values.map((v, i) => {
- return (
- <li key={i} class={value === v ? "is-active" : ""}
- onClick={(e) => { onChange(v) }}
- >
- <a style={{ cursor: "initial" }}>
- <span>{toStr(v)}</span>
- </a>
- </li>
- );
- })}
- </ul>
- </div>
- {help}
- </p>
- {required && (
- <span class="icon has-text-danger is-right" style={{ height: "2.5em" }}>
- <i class="mdi mdi-alert" />
- </span>
- )}
- {error && <p class="help is-danger">{error}</p>}
- </div>
- </div>
- </div>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/InputTaxes.tsx b/packages/auditor-backoffice-ui/src/components/form/InputTaxes.tsx
deleted file mode 100644
index 984b496e7..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/InputTaxes.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { h, VNode } from "preact";
-import { useCallback, useState } from "preact/hooks";
-import * as yup from "yup";
-import { MerchantBackend } from "../../declaration.js";
-import { TaxSchema as schema } from "../../schemas/index.js";
-import { FormErrors, FormProvider } from "./FormProvider.js";
-import { Input } from "./Input.js";
-import { InputGroup } from "./InputGroup.js";
-import { InputProps, useField } from "./useField.js";
-
-export interface Props<T> extends InputProps<T> {
- isValid?: (e: any) => boolean;
-}
-
-type Entity = MerchantBackend.Tax;
-export function InputTaxes<T>({
- name,
- readonly,
- label,
-}: Props<keyof T>): VNode {
- const { value: taxes, onChange } = useField<T>(name);
-
- const [value, valueHandler] = useState<Partial<Entity>>({});
- // const [errors, setErrors] = useState<FormErrors<Entity>>({})
-
- let errors: FormErrors<Entity> = {};
-
- try {
- schema.validateSync(value, { abortEarly: false });
- } catch (err) {
- if (err instanceof yup.ValidationError) {
- const yupErrors = err.inner as yup.ValidationError[];
- errors = yupErrors.reduce(
- (prev, cur) =>
- !cur.path ? prev : { ...prev, [cur.path]: cur.message },
- {},
- );
- }
- }
- const hasErrors = Object.keys(errors).some(
- (k) => (errors as any)[k] !== undefined,
- );
-
- const submit = useCallback((): void => {
- onChange([value as any, ...taxes] as any);
- valueHandler({});
- }, [value]);
-
- const { i18n } = useTranslationContext();
-
- //FIXME: translating plural singular
- return (
- <InputGroup
- name="tax"
- label={label}
- alternative={
- taxes.length > 0 && (
- <p>This product has {taxes.length} applicable taxes configured.</p>
- )
- }
- >
- <FormProvider<Entity>
- name="tax"
- errors={errors}
- object={value}
- valueHandler={valueHandler}
- >
- <div class="field is-horizontal">
- <div class="field-label is-normal" />
- <div class="field-body" style={{ display: "block" }}>
- {taxes.map((v: any, i: number) => (
- <div
- key={i}
- class="tags has-addons mt-3 mb-0 mr-3"
- style={{ flexWrap: "nowrap" }}
- >
- <span
- class="tag is-medium is-info mb-0"
- style={{ maxWidth: "90%" }}
- >
- <b>{v.tax}</b>: {v.name}
- </span>
- <a
- class="tag is-medium is-danger is-delete mb-0"
- onClick={() => {
- onChange(taxes.filter((f: any) => f !== v) as any);
- valueHandler(v);
- }}
- />
- </div>
- ))}
- {!taxes.length && i18n.str`No taxes configured for this product.`}
- </div>
- </div>
-
- <Input<Entity>
- name="tax"
- label={i18n.str`Amount`}
- tooltip={i18n.str`Taxes can be in currencies that differ from the main currency used by the merchant.`}
- >
- <i18n.Translate>
- Enter currency and value separated with a colon, e.g.
- &quot;USD:2.3&quot;.
- </i18n.Translate>
- </Input>
-
- <Input<Entity>
- name="name"
- label={i18n.str`Description`}
- tooltip={i18n.str`Legal name of the tax, e.g. VAT or import duties.`}
- />
-
- <div class="buttons is-right mt-5">
- <button
- class="button is-info"
- data-tooltip={i18n.str`add tax to the tax list`}
- disabled={hasErrors}
- onClick={submit}
- >
- <i18n.Translate>Add</i18n.Translate>
- </button>
- </div>
- </FormProvider>
- </InputGroup>
- );
-}
diff --git a/packages/auditor-backoffice-ui/src/components/form/TextField.tsx b/packages/auditor-backoffice-ui/src/components/form/TextField.tsx
deleted file mode 100644
index 8f897c2d8..000000000
--- a/packages/auditor-backoffice-ui/src/components/form/TextField.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 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 { ComponentChildren, h, VNode } from "preact";
-import { useField, InputProps } from "./useField.js";
-
-interface Props<T> extends InputProps<T> {
- inputType?: "text" | "number" | "multiline" | "password";
- expand?: boolean;
- side?: ComponentChildren;
- children: ComponentChildren;
-}
-
-export function TextField<T>({
- name,
- tooltip,
- label,
- expand,
- help,
- children,
- side,
-}: Props<keyof T>): VNode {
- const { error } = useField<T>(name);
- return (
- <div class="field is-horizontal">
- <div class="field-label is-normal">
- <label class="label">
- {label}
- {tooltip && (
- <span class="icon has-tooltip-right" data-tooltip={tooltip}>
- <i class="mdi mdi-information" />
- </span>
- )}
- </label>
- </div>
- <div class="field-body is-flex-grow-3">
- <div class="field">
- <p
- class={
- expand
- ? "control is-expanded has-icons-right"
- : "control has-icons-right"
- }
- >
- {children}
- {help}
- </p>
- {error && <p class="help is-danger">{error}</p>}
- </div>
- {side}
- </div>
- </div>
- );
-}