summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-12-31 15:32:12 -0300
committerSebastian <sebasjm@gmail.com>2023-12-31 15:32:12 -0300
commitbedeebff1572fa8cfdb0a818030f6b13a3fc0f53 (patch)
treef782867e60420630f179a47d0d4f0d8d35a4ad4b
parent08d3e79a9c2adbc295549bdcc05353b6e50565f3 (diff)
downloadwallet-core-bedeebff1572fa8cfdb0a818030f6b13a3fc0f53.tar.gz
wallet-core-bedeebff1572fa8cfdb0a818030f6b13a3fc0f53.tar.bz2
wallet-core-bedeebff1572fa8cfdb0a818030f6b13a3fc0f53.zip
remove handlers from impl
-rw-r--r--packages/aml-backoffice-ui/src/handlers/Calendar.tsx119
-rw-r--r--packages/aml-backoffice-ui/src/handlers/Caption.tsx32
-rw-r--r--packages/aml-backoffice-ui/src/handlers/Dialog.tsx15
-rw-r--r--packages/aml-backoffice-ui/src/handlers/FormProvider.tsx140
-rw-r--r--packages/aml-backoffice-ui/src/handlers/Group.tsx41
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.stories.tsx60
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.tsx77
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputAmount.stories.tsx59
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputAmount.tsx36
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputArray.stories.tsx79
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputArray.tsx186
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.stories.tsx69
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.tsx87
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.stories.tsx69
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.tsx113
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputFile.stories.tsx64
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputFile.tsx106
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputInteger.stories.tsx55
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputInteger.tsx24
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputLine.stories.tsx59
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputLine.tsx268
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.stories.tsx90
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.tsx154
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputSelectOne.stories.tsx70
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputSelectOne.tsx135
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputText.stories.tsx59
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputText.tsx9
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputTextArea.stories.tsx59
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputTextArea.tsx9
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputToggle.stories.tsx59
-rw-r--r--packages/aml-backoffice-ui/src/handlers/InputToggle.tsx38
-rw-r--r--packages/aml-backoffice-ui/src/handlers/NiceForm.tsx60
-rw-r--r--packages/aml-backoffice-ui/src/handlers/TimePicker.tsx110
-rw-r--r--packages/aml-backoffice-ui/src/handlers/forms.ts141
-rw-r--r--packages/aml-backoffice-ui/src/handlers/index.stories.ts13
-rw-r--r--packages/aml-backoffice-ui/src/handlers/useField.ts95
36 files changed, 0 insertions, 2859 deletions
diff --git a/packages/aml-backoffice-ui/src/handlers/Calendar.tsx b/packages/aml-backoffice-ui/src/handlers/Calendar.tsx
deleted file mode 100644
index e476bf6f6..000000000
--- a/packages/aml-backoffice-ui/src/handlers/Calendar.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import { AbsoluteTime } from "@gnu-taler/taler-util"
-import { useTranslationContext } from "@gnu-taler/web-util/browser"
-import { add as dateAdd, sub as dateSub, eachDayOfInterval, endOfMonth, endOfWeek, format, getMonth, getYear, isSameDay, isSameMonth, startOfDay, startOfMonth, startOfWeek } from "date-fns"
-import { VNode, h } from "preact"
-import { useState } from "preact/hooks"
-
-export function Calendar({ value, onChange }: { value: AbsoluteTime | undefined, onChange: (v: AbsoluteTime) => void }): VNode {
- const today = startOfDay(new Date())
- const selected = !value ? today : new Date(AbsoluteTime.toStampMs(value))
- const [showingDate, setShowingDate] = useState(selected)
- const month = getMonth(showingDate)
- const year = getYear(showingDate)
-
- const start = startOfWeek(startOfMonth(showingDate));
- const end = endOfWeek(endOfMonth(showingDate));
- const daysInMonth = eachDayOfInterval({ start, end });
- const { i18n } = useTranslationContext()
- const monthNames = [
- i18n.str`January`,
- i18n.str`February`,
- i18n.str`March`,
- i18n.str`April`,
- i18n.str`May`,
- i18n.str`June`,
- i18n.str`July`,
- i18n.str`August`,
- i18n.str`September`,
- i18n.str`October`,
- i18n.str`November`,
- i18n.str`December`,
- ]
- return <div class="text-center p-2">
- <div class="flex items-center text-gray-900">
- <button type="button" class="flex px-4 flex-none items-center justify-center p-1.5 text-gray-400 hover:text-gray-500 ring-2 round-sm"
- onClick={() => {
- setShowingDate(dateSub(showingDate, { years: 1 }))
- }}>
- <span class="sr-only">
- {i18n.str`Previous year`}
- </span>
- <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
- <path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
- </svg>
- </button>
- <div class="flex-auto text-sm font-semibold">{year}</div>
- <button type="button" class="flex px-4 flex-none items-center justify-center p-1.5 text-gray-400 hover:text-gray-500 ring-2 round-sm"
- onClick={() => {
- setShowingDate(dateAdd(showingDate, { years: 1 }))
- }}>
- <span class="sr-only">
- {i18n.str`Next year`}
- </span>
- <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
- <path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
- </svg>
- </button>
- </div>
- <div class="mt-4 flex items-center text-gray-900">
- <button type="button" class="flex px-4 flex-none items-center justify-center p-1.5 text-gray-400 hover:text-gray-500 ring-2 round-sm"
- onClick={() => {
- setShowingDate(dateSub(showingDate, { months: 1 }))
- }}>
- <span class="sr-only">
- {i18n.str`Previous month`}
- </span>
- <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
- <path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
- </svg>
- </button>
- <div class="flex-auto text-sm font-semibold">{monthNames[month]}</div>
- <button type="button" class="flex px-4 flex-none items-center justify-center p-1.5 text-gray-400 hover:text-gray-500 ring-2 rounded-sm "
- onClick={() => {
- setShowingDate(dateAdd(showingDate, { months: 1 }))
- }}>
- <span class="sr-only">
- {i18n.str`Next month`}
- </span>
- <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
- <path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
- </svg>
- </button>
- </div>
- <div class="mt-6 grid grid-cols-7 text-xs leading-6 text-gray-500">
- <div>M</div>
- <div>T</div>
- <div>W</div>
- <div>T</div>
- <div>F</div>
- <div>S</div>
- <div>S</div>
- </div>
- <div class="isolate mt-2">
- <div class="grid grid-cols-7 gap-px rounded-lg bg-gray-200 text-sm shadow ring-1 ring-gray-200">
- {daysInMonth.map(current => (
- <button type="button"
- data-month={isSameMonth(current, showingDate)}
- data-today={isSameDay(current, today)}
- data-selected={isSameDay(current, selected)}
- onClick={() => {
- onChange(AbsoluteTime.fromStampMs(current.getTime()))
- }}
- class="text-gray-400 hover:bg-gray-700 focus:z-10 py-1.5
- data-[month=false]:bg-gray-100 data-[month=true]:bg-white
- data-[today=true]:font-semibold
- data-[month=true]:text-gray-900
- data-[today=true]:bg-red-300 data-[today=true]:hover:bg-red-200
- data-[month=true]:hover:bg-gray-200
- data-[selected=true]:!bg-blue-400 data-[selected=true]:hover:!bg-blue-300 ">
- <time dateTime={format(current, "yyyy-MM-dd")}
- class="mx-auto flex h-7 w-7 py-4 px-5 sm:px-8 items-center justify-center rounded-full">
- {format(current, "dd")}
- </time>
- </button>
- ))}
- </div>
- {daysInMonth.length < 40 ? <div class="w-7 h-7 m-1.5" /> : undefined}
- </div>
- </div>
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/Caption.tsx b/packages/aml-backoffice-ui/src/handlers/Caption.tsx
deleted file mode 100644
index 8facddec3..000000000
--- a/packages/aml-backoffice-ui/src/handlers/Caption.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
-import {
- LabelWithTooltipMaybeRequired
-} from "./InputLine.js";
-
-interface Props {
- label: TranslatedString;
- tooltip?: TranslatedString;
- help?: TranslatedString;
- before?: VNode;
- after?: VNode;
-}
-
-export function Caption({ before, after, label, tooltip, help }: Props): VNode {
- return (
- <div class="sm:col-span-6 flex">
- {before !== undefined && (
- <span class="pointer-events-none flex items-center pr-2">{before}</span>
- )}
- <LabelWithTooltipMaybeRequired label={label} tooltip={tooltip} />
- {after !== undefined && (
- <span class="pointer-events-none flex items-center pl-2">{after}</span>
- )}
- {help && (
- <p class="mt-2 text-sm text-gray-500" id="email-description">
- {help}
- </p>
- )}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/Dialog.tsx b/packages/aml-backoffice-ui/src/handlers/Dialog.tsx
deleted file mode 100644
index 7b41fe487..000000000
--- a/packages/aml-backoffice-ui/src/handlers/Dialog.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ComponentChildren, VNode, h } from "preact";
-
-export function Dialog({ children, onClose }: { onClose?: () => void; children: ComponentChildren }): VNode {
- return <div class="relative z-10" aria-labelledby="modal-title" role="dialog" aria-modal="true" onClick={onClose}>
- <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
-
- <div class="fixed inset-0 z-10 w-screen overflow-y-auto">
- <div class="flex min-h-full items-center justify-center p-4 text-center ">
- <div class="relative transform overflow-hidden rounded-lg bg-white p-1 text-left shadow-xl transition-all" onClick={(e) => e.stopPropagation()}>
- {children}
- </div>
- </div>
- </div>
- </div>
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx b/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
deleted file mode 100644
index b9f9f7832..000000000
--- a/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-import {
- AbsoluteTime,
- AmountJson,
- TranslatedString,
-} from "@gnu-taler/taler-util";
-import { ComponentChildren, VNode, createContext, h } from "preact";
-import {
- MutableRef,
- StateUpdater,
- useState
-} from "preact/hooks";
-
-export interface FormType<T extends object> {
- value: MutableRef<Partial<T>>;
- initialValue?: Partial<T>;
- readOnly?: boolean;
- onUpdate?: StateUpdater<T>;
- computeFormState?: (v: T) => FormState<T>;
-}
-
-//@ts-ignore
-export const FormContext = createContext<FormType<any>>({});
-
-/**
- * Map of {[field]:BehaviorResult}
- * for every field of type
- * - any native (string, number, etc...)
- * - absoluteTime
- * - amountJson
- *
- * except for:
- * - object => recurse into
- * - array => behavior result and element field
- */
-export type FormState<T extends object | undefined> = {
- [field in keyof T]?: T[field] extends AbsoluteTime
- ? BehaviorResult
- : T[field] extends AmountJson
- ? BehaviorResult
- : T[field] extends Array<infer P extends object>
- ? InputArrayFieldState<P>
- : T[field] extends (object | undefined)
- ? FormState<T[field]>
- : BehaviorResult;
-};
-
-export type BehaviorResult = Partial<InputFieldState> & FieldUIOptions
-
-export interface InputFieldState {
- /* should show the error */
- error?: TranslatedString;
- /* should not allow to edit */
- readonly: boolean;
- /* should show as disable */
- disabled: boolean;
- /* should not show */
- hidden: boolean;
-}
-
-export interface IconAddon {
- type: "icon";
- icon: VNode;
-}
-export interface ButtonAddon {
- type: "button";
- onClick: () => void;
- children: ComponentChildren;
-}
-export interface TextAddon {
- type: "text";
- text: TranslatedString;
-}
-export type Addon = IconAddon | ButtonAddon | TextAddon;
-
-export interface StringConverter<T> {
- toStringUI: (v?: T) => string;
- fromStringUI: (v?: string) => T;
-}
-
-type FieldUIOptions = {
- placeholder?: TranslatedString;
- tooltip?: TranslatedString;
- help?: TranslatedString;
- required?: boolean;
-}
-
-export interface UIFormProps<T extends object, K extends keyof T> extends FieldUIOptions {
- name: K;
- label: TranslatedString;
- before?: Addon;
- after?: Addon;
- converter?: StringConverter<T[K]>;
-}
-
-export interface InputArrayFieldState<P extends object> extends BehaviorResult {
- elements?: FormState<P>[];
-}
-
-export function FormProvider<T extends object>({
- children,
- initialValue,
- onUpdate: notify,
- onSubmit,
- computeFormState,
- readOnly,
-}: {
- initialValue?: Partial<T>;
- onUpdate?: (v: Partial<T>) => void;
- onSubmit?: (v: Partial<T>, s: FormState<T> | undefined) => void;
- computeFormState?: (v: Partial<T>) => FormState<T>;
- readOnly?: boolean;
- children: ComponentChildren;
-}): VNode {
-
- const [state, setState] = useState<Partial<T>>(initialValue ?? {});
- const value = { current: state };
- const onUpdate = (v: typeof state) => {
- setState(v);
- if (notify) notify(v);
- };
- return (
- <FormContext.Provider
- value={{ initialValue, value, onUpdate, computeFormState, readOnly }}
- >
- <form
- onSubmit={(e) => {
- e.preventDefault();
- //@ts-ignore
- if (onSubmit)
- onSubmit(
- value.current,
- !computeFormState ? undefined : computeFormState(value.current),
- );
- }}
- >
- {children}
- </form>
- </FormContext.Provider>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/Group.tsx b/packages/aml-backoffice-ui/src/handlers/Group.tsx
deleted file mode 100644
index 0645f6d97..000000000
--- a/packages/aml-backoffice-ui/src/handlers/Group.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { RenderAllFieldsByUiConfig, UIFormField } from "./forms.js";
-
-interface Props {
- before?: TranslatedString;
- after?: TranslatedString;
- tooltipBefore?: TranslatedString;
- tooltipAfter?: TranslatedString;
- fields: UIFormField[];
-}
-
-export function Group({
- before,
- after,
- tooltipAfter,
- tooltipBefore,
- fields,
-}: Props): VNode {
- return (
- <div class="sm:col-span-6 p-4 rounded-lg border-r-2 border-2 bg-gray-50">
- <div class="pb-4">
- {before && (
- <LabelWithTooltipMaybeRequired
- label={before}
- tooltip={tooltipBefore}
- />
- )}
- </div>
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-2 sm:grid-cols-6">
- <RenderAllFieldsByUiConfig fields={fields} />
- </div>
- <div class="pt-4">
- {after && (
- <LabelWithTooltipMaybeRequired label={after} tooltip={tooltipAfter} />
- )}
- </div>
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.stories.tsx
deleted file mode 100644
index 54e41ffae..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.stories.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Absolute Time",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- today: AbsoluteTime;
-}
-const initial: TargetObject = {
- today: AbsoluteTime.now()
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "absoluteTime",
- props: {
- label: "label of the field" as TranslatedString,
- name: "today",
- pattern: "dd/MM/yyyy HH:mm"
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.tsx b/packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.tsx
deleted file mode 100644
index 0e03c5595..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputAbsoluteTime.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { AbsoluteTime } from "@gnu-taler/taler-util";
-import { InputLine } from "./InputLine.js";
-import { Fragment, VNode, h } from "preact";
-import { format, parse } from "date-fns";
-import { Dialog } from "./Dialog.js";
-import { Calendar } from "./Calendar.js";
-import { useState } from "preact/hooks";
-import { useField } from "./useField.js";
-import { UIFormProps } from "./FormProvider.js";
-import { TimePicker } from "./TimePicker.js";
-
-export function InputAbsoluteTime<T extends object, K extends keyof T>(
- props: { pattern?: string } & UIFormProps<T, K>,
-): VNode {
- const pattern = props.pattern ?? "dd/MM/yyyy";
- const [open, setOpen] = useState(true)
- const { value, onChange } = useField<T, K>(props.name);
- return (
- <Fragment>
-
- <InputLine<T, K>
- type="text"
- after={{
- type: "button",
- onClick: () => {
- setOpen(true)
- },
- // icon: <CalendarIcon class="h-6 w-6" />,
- children: (
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
- <path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
- </svg>)
- }}
- converter={{
- //@ts-ignore
- fromStringUI: (v): AbsoluteTime | undefined => {
- if (!v) return undefined;
- try {
- const t_ms = parse(v, pattern, Date.now()).getTime();
- return AbsoluteTime.fromMilliseconds(t_ms);
- } catch (e) {
- return undefined;
- }
- },
- //@ts-ignore
- toStringUI: (v: AbsoluteTime | undefined) => {
- return !v || !v.t_ms
- ? undefined
- : v.t_ms === "never"
- ? "never"
- : format(v.t_ms, pattern);
- },
- }}
- {...props}
- />
- {/* {open &&
- <Dialog onClose={() => setOpen(false)}>
- <Calendar value={value as AbsoluteTime ?? AbsoluteTime.now()}
- onChange={(v) => {
- onChange(v as any)
- setOpen(false)
- }} />
- </Dialog>
- } */}
- {open &&
- <Dialog onClose={() => setOpen(false)} >
- <TimePicker value={value as AbsoluteTime ?? AbsoluteTime.now()}
- onChange={(v) => {
- onChange(v as any)
- }}
- onConfirm={() => {
- setOpen(false)
- }} />
- </Dialog>}
- </Fragment>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputAmount.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputAmount.stories.tsx
deleted file mode 100644
index 872726247..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputAmount.stories.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { AmountJson, Amounts, TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Amount",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- amount: AmountJson;
-}
-const initial: TargetObject = {
- amount: Amounts.parseOrThrow("USD:10")
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "amount",
- props: {
- label: "label of the field" as TranslatedString,
- name: "amount",
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputAmount.tsx b/packages/aml-backoffice-ui/src/handlers/InputAmount.tsx
deleted file mode 100644
index 29ec43525..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputAmount.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { AmountJson, Amounts, TranslatedString } from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
-import { InputLine } from "./InputLine.js";
-import { useField } from "./useField.js";
-import { UIFormProps } from "./FormProvider.js";
-
-export function InputAmount<T extends object, K extends keyof T>(
- props: { currency?: string } & UIFormProps<T, K>,
-): VNode {
- const { value } = useField<T, K>(props.name);
- const currency =
- !value || !(value as any).currency
- ? props.currency
- : (value as any).currency;
- return (
- <InputLine<T, K>
- type="text"
- before={{
- type: "text",
- text: currency as TranslatedString,
- }}
- converter={{
- //@ts-ignore
- fromStringUI: (v): AmountJson => {
-
- return Amounts.parse(`${currency}:${v}`) ?? Amounts.zeroOfCurrency(currency);
- },
- //@ts-ignore
- toStringUI: (v: AmountJson) => {
- return v === undefined ? "" : Amounts.stringifyValue(v);
- },
- }}
- {...props}
- />
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputArray.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputArray.stories.tsx
deleted file mode 100644
index ee25d355b..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputArray.stories.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Array",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- people: {
- name: string;
- age: number;
- }[];
-}
-const initial: TargetObject = {
- people: [{
- name: "me",
- age: 17,
- }]
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "array",
- props: {
- label: "People" as TranslatedString,
- name: "comment",
- fields: [{
- type: "text",
- props: {
- label: "the name" as TranslatedString,
- name: "name",
- }
- }, {
- type: "integer",
- props: {
- label: "the age" as TranslatedString,
- name: "age",
- }
- }],
- labelField: "name"
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputArray.tsx b/packages/aml-backoffice-ui/src/handlers/InputArray.tsx
deleted file mode 100644
index 38c399e66..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputArray.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { FormProvider, UIFormProps } from "./FormProvider.js";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { RenderAllFieldsByUiConfig, UIFormField } from "./forms.js";
-import { useField } from "./useField.js";
-
-function Option({
- label,
- disabled,
- isFirst,
- isLast,
- isSelected,
- onClick,
-}: {
- label: TranslatedString;
- isFirst?: boolean;
- isLast?: boolean;
- isSelected?: boolean;
- disabled?: boolean;
- onClick: () => void;
-}): VNode {
- let clazz = "relative flex border p-4 focus:outline-none disabled:text-grey";
- if (isFirst) {
- clazz += " rounded-tl-md rounded-tr-md ";
- }
- if (isLast) {
- clazz += " rounded-bl-md rounded-br-md ";
- }
- if (isSelected) {
- clazz += " z-10 border-indigo-200 bg-indigo-50 ";
- } else {
- clazz += " border-gray-200";
- }
- if (disabled) {
- clazz +=
- " cursor-not-allowed bg-gray-50 text-gray-500 ring-gray-200 text-gray";
- } else {
- clazz += " cursor-pointer";
- }
- return (
- <label class={clazz}>
- <input
- type="radio"
- name="privacy-setting"
- checked={isSelected}
- disabled={disabled}
- onClick={onClick}
- class="mt-0.5 h-4 w-4 shrink-0 text-indigo-600 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200 focus:ring-indigo-600"
- aria-labelledby="privacy-setting-0-label"
- aria-describedby="privacy-setting-0-description"
- />
- <span class="ml-3 flex flex-col">
- <span
- id="privacy-setting-0-label"
- disabled
- class="block text-sm font-medium"
- >
- {label}
- </span>
- {/* <!-- Checked: "text-indigo-700", Not Checked: "text-gray-500" --> */}
- {/* <span
- id="privacy-setting-0-description"
- class="block text-sm"
- >
- This project would be available to anyone who has the link
- </span> */}
- </span>
- </label>
- );
-}
-
-export function InputArray<T extends object, K extends keyof T>(
- props: {
- fields: UIFormField[];
- labelField: string;
- } & UIFormProps<T, K>,
-): VNode {
- const { fields, labelField, name, label, required, tooltip } = props;
- const { value, onChange, state } = useField<T, K>(name);
- const list = (value ?? []) as Array<Record<string, string | undefined>>;
- const [selectedIndex, setSelected] = useState<number | undefined>(undefined);
- const selected =
- selectedIndex === undefined ? undefined : list[selectedIndex];
-
- return (
- <div class="sm:col-span-6">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
-
- <div class="-space-y-px rounded-md bg-white ">
- {list.map((v, idx) => {
- return (
- <Option
- label={v[labelField] as TranslatedString}
- isSelected={selectedIndex === idx}
- isLast={idx === list.length - 1}
- disabled={selectedIndex !== undefined && selectedIndex !== idx}
- isFirst={idx === 0}
- onClick={() => {
- setSelected(selectedIndex === idx ? undefined : idx);
- }}
- />
- );
- })}
- {!state.disabled &&
- <div class="pt-2">
- <Option
- label={"Add..." as TranslatedString}
- isSelected={selectedIndex === list.length}
- isLast
- isFirst
- disabled={
- selectedIndex !== undefined && selectedIndex !== list.length
- }
- onClick={() => {
- setSelected(
- selectedIndex === list.length ? undefined : list.length,
- );
- }}
- />
- </div>
- }
- </div>
- {selectedIndex !== undefined && (
- /**
- * This form provider act as a substate of the parent form
- * Consider creating an InnerFormProvider since not every feature is expected
- */
- <FormProvider
- initialValue={selected}
- readOnly={state.disabled}
- computeFormState={(v) => {
- // current state is ignored
- // the state is defined by the parent form
-
- // elements should be present in the state object since this is expected to be an array
- //@ts-ignore
- return state.elements[selectedIndex];
- }}
- onSubmit={(v) => {
- const newValue = [...list];
- newValue.splice(selectedIndex, 1, v);
- onChange(newValue as T[K]);
- setSelected(undefined);
- }}
- onUpdate={(v) => {
- const newValue = [...list];
- newValue.splice(selectedIndex, 1, v);
- onChange(newValue as T[K]);
- }}
- >
- <div class="px-4 py-6">
- <div class="grid grid-cols-1 gap-y-8 ">
- <RenderAllFieldsByUiConfig fields={fields} />
- </div>
- </div>
- </FormProvider>
- )}
- {selectedIndex !== undefined && (
- <div class="flex items-center pt-3">
- <div class="flex-auto">
- {selected !== undefined && (
- <button
- type="button"
- onClick={() => {
- const newValue = [...list];
- newValue.splice(selectedIndex, 1);
- onChange(newValue as T[K]);
- setSelected(undefined);
- }}
- class="block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 "
- >
- Remove
- </button>
- )}
- </div>
- </div>
- )}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.stories.tsx
deleted file mode 100644
index 7872afac7..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.stories.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Choice Horizontal",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "0"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "choiceHorizontal",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- choices: [{
- label: "first choice" as TranslatedString,
- value: "1"
- }, {
- label: "second choice" as TranslatedString,
- value: "2"
- }, {
- label: "thrid choice" as TranslatedString,
- value: "3"
- },],
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.tsx b/packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.tsx
deleted file mode 100644
index 594b1c32e..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputChoiceHorizontal.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { Fragment, VNode, h } from "preact";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { useField } from "./useField.js";
-import { UIFormProps } from "./FormProvider.js";
-
-export interface Choice<V> {
- label: TranslatedString;
- value: V;
-}
-
-export function InputChoiceHorizontal<T extends object, K extends keyof T>(
- props: {
- choices: Choice<T[K]>[];
- } & UIFormProps<T, K>,
-): VNode {
- const {
- choices,
- name,
- label,
- tooltip,
- help,
- placeholder,
- required,
- before,
- after,
- converter,
- } = props;
- const { value, onChange, state, isDirty } = useField<T, K>(name);
- if (state.hidden) {
- return <Fragment />;
- }
-
- return (
- <div class="sm:col-span-6">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
- <fieldset class="mt-2">
- <div class="isolate inline-flex rounded-md shadow-sm">
- {choices.map((choice, idx) => {
- const isFirst = idx === 0;
- const isLast = idx === choices.length - 1;
- let clazz =
- "relative inline-flex items-center px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 focus:z-10";
- if (choice.value === value) {
- clazz +=
- " text-white bg-indigo-600 hover:bg-indigo-500 ring-2 ring-indigo-600 hover:ring-indigo-500";
- } else {
- clazz += " hover:bg-gray-100 border-gray-300";
- }
- if (isFirst) {
- clazz += " rounded-l-md";
- } else {
- clazz += " -ml-px";
- }
- if (isLast) {
- clazz += " rounded-r-md";
- }
- return (
- <button
- type="button"
- disabled={state.disabled}
- label={choice.label}
- class={clazz}
- onClick={(e) => {
- onChange(
- (value === choice.value ? undefined : choice.value) as T[K],
- );
- }}
- >
- {choice.label}
- </button>
- );
- })}
- </div>
- </fieldset>
- {help && (
- <p class="mt-2 text-sm text-gray-500" id="email-description">
- {help}
- </p>
- )}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.stories.tsx
deleted file mode 100644
index 215418430..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.stories.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Choice Stacked",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "some initial comment"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "choiceStacked",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- choices: [{
- label: "first choice" as TranslatedString,
- value: "1"
- }, {
- label: "second choice" as TranslatedString,
- value: "2"
- }, {
- label: "thrid choice" as TranslatedString,
- value: "3"
- },],
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.tsx b/packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.tsx
deleted file mode 100644
index 48d367ff2..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputChoiceStacked.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { Fragment, VNode, h } from "preact";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { useField } from "./useField.js";
-import { UIFormProps } from "./FormProvider.js";
-
-export interface Choice<V> {
- label: TranslatedString;
- description?: TranslatedString;
- value: V;
-}
-
-export function InputChoiceStacked<T extends object, K extends keyof T>(
- props: {
- choices: Choice<T[K]>[];
- } & UIFormProps<T, K>,
-): VNode {
- const {
- choices,
- name,
- label,
- tooltip,
- help,
- placeholder,
- required,
- before,
- after,
- converter,
- } = props;
- const { value, onChange, state, isDirty } = useField<T, K>(name);
- if (state.hidden) {
- return <Fragment />;
- }
-
- return (
- <div class="sm:col-span-6">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
- <fieldset class="mt-2">
- <div class="space-y-4">
- {choices.map((choice) => {
- // const currentValue = !converter
- // ? choice.value
- // : converter.fromStringUI(choice.value) ?? "";
-
- let clazz =
- "border relative block cursor-pointer rounded-lg bg-white px-6 py-4 shadow-sm focus:outline-none sm:flex sm:justify-between";
- if (choice.value === value) {
- clazz +=
- " border-transparent border-indigo-600 ring-2 ring-indigo-600";
- } else {
- clazz += " border-gray-300";
- }
-
- return (
- <label class={clazz}>
- <input
- type="radio"
- name="server-size"
- // defaultValue={choice.value}
- disabled={state.disabled}
- value={
- (!converter
- ? (choice.value as string)
- : converter?.toStringUI(choice.value)) ?? ""
- }
- onClick={(e) => {
- onChange(
- (value === choice.value
- ? undefined
- : choice.value) as T[K],
- );
- }}
- class="sr-only"
- aria-labelledby="server-size-0-label"
- aria-describedby="server-size-0-description-0 server-size-0-description-1"
- />
- <span class="flex items-center">
- <span class="flex flex-col text-sm">
- <span
- id="server-size-0-label"
- class="font-medium text-gray-900"
- >
- {choice.label}
- </span>
- {choice.description !== undefined && (
- <span
- id="server-size-0-description-0"
- class="text-gray-500"
- >
- <span class="block sm:inline">
- {choice.description}
- </span>
- </span>
- )}
- </span>
- </span>
- </label>
- );
- })}
- </div>
- </fieldset>
- {help && (
- <p class="mt-2 text-sm text-gray-500" id="email-description">
- {help}
- </p>
- )}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputFile.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputFile.stories.tsx
deleted file mode 100644
index 8a1783bda..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputFile.stories.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input File",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "some initial comment"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "file",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- required: true,
- maxBites: 2 * 1024 * 1024,
- accept: ".png",
- tooltip: "this is a very long tooltip that explain what the field does without being short" as TranslatedString,
- help: "Max size of 2 mega bytes" as TranslatedString,
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputFile.tsx b/packages/aml-backoffice-ui/src/handlers/InputFile.tsx
deleted file mode 100644
index bc460f370..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputFile.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import { Fragment, VNode, h } from "preact";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { useField } from "./useField.js";
-import { UIFormProps, BehaviorResult } from "./FormProvider.js";
-
-export function InputFile<T extends object, K extends keyof T>(
- props: { maxBites: number; accept?: string } & UIFormProps<T, K>,
-): VNode {
- const {
- name,
- label,
- placeholder,
- tooltip,
- required,
- help: propsHelp,
- maxBites,
- accept,
- } = props;
- const { value, onChange, state } = useField<T, K>(name);
- const help = propsHelp ?? state.help
- if (state.hidden) {
- return <div />;
- }
- return (
- <div class="col-span-full">
- <LabelWithTooltipMaybeRequired
- label={label}
- tooltip={tooltip}
- required={required}
- />
- {!value || !(value as string).startsWith("data:image/") ? (
- <div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 py-1">
- <div class="text-center">
- <svg
- class="mx-auto h-12 w-12 text-gray-300"
- viewBox="0 0 24 24"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z"
- clip-rule="evenodd"
- />
- </svg>
- {!state.disabled &&
- <div class="my-2 flex text-sm leading-6 text-gray-600">
- <label
- for="file-upload"
- class="relative cursor-pointer rounded-md bg-white font-semibold text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2 hover:text-indigo-500"
- >
- <span>Upload a file</span>
- <input
- id="file-upload"
- name="file-upload"
- type="file"
- class="sr-only"
- accept={accept}
- onChange={(e) => {
- const f: FileList | null = e.currentTarget.files;
- if (!f || f.length != 1) {
- return onChange(undefined!);
- }
- if (f[0].size > maxBites) {
- return onChange(undefined!);
- }
- 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);
- });
- }}
- />
- </label>
- {/* <p class="pl-1">or drag and drop</p> */}
- </div>
- }
- </div>
- </div>
- ) : (
- <div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 relative">
- <img
- src={value as string}
- class=" h-24 w-full object-cover relative"
- />
-
- {!state.disabled &&
- <div
- class="opacity-0 hover:opacity-70 duration-300 absolute rounded-lg border inset-0 z-10 flex justify-center text-xl items-center bg-black text-white cursor-pointer "
- onClick={() => {
- onChange(undefined!);
- }}
- >
- Clear
- </div>
- }
- </div>
- )}
- {help && <p class="text-xs leading-5 text-gray-600 mt-2">{help}</p>}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputInteger.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputInteger.stories.tsx
deleted file mode 100644
index 344865817..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputInteger.stories.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Integer",
-};
-
-
-type TargetObject = {
- age: number;
-}
-const initial: TargetObject = {
- age: 5,
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "integer",
- props: {
- label: "label of the field" as TranslatedString,
- name: "age",
- tooltip: "just numbers" as TranslatedString,
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputInteger.tsx b/packages/aml-backoffice-ui/src/handlers/InputInteger.tsx
deleted file mode 100644
index a6a02ad43..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputInteger.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { VNode, h } from "preact";
-import { InputLine } from "./InputLine.js";
-import { UIFormProps } from "./FormProvider.js";
-
-export function InputInteger<T extends object, K extends keyof T>(
- props: UIFormProps<T, K>,
-): VNode {
- return (
- <InputLine
- type="number"
- converter={{
- //@ts-ignore
- fromStringUI: (v): number => {
- return !v ? 0 : Number.parseInt(v, 10);
- },
- //@ts-ignore
- toStringUI: (v?: number): string => {
- return v === undefined ? "" : String(v);
- },
- }}
- {...props}
- />
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputLine.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputLine.stories.tsx
deleted file mode 100644
index 0d55bddf7..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputLine.stories.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Line",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "some initial comment"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "text",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputLine.tsx b/packages/aml-backoffice-ui/src/handlers/InputLine.tsx
deleted file mode 100644
index 8c44b1ca5..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputLine.tsx
+++ /dev/null
@@ -1,268 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { ComponentChildren, Fragment, VNode, h } from "preact";
-import { useField } from "./useField.js";
-import { useEffect, useState } from "preact/hooks";
-import { UIFormProps } from "./FormProvider.js";
-
-//@ts-ignore
-const TooltipIcon = (
- <svg
- class="w-5 h-5"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 20 20"
- fill="currentColor"
- >
- <path
- fill-rule="evenodd"
- d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z"
- clip-rule="evenodd"
- />
- </svg>
-);
-
-export function LabelWithTooltipMaybeRequired({
- label,
- required,
- tooltip,
-}: {
- label: TranslatedString;
- required?: boolean;
- tooltip?: TranslatedString;
-}): VNode {
- const Label = (
- <Fragment>
- <div class="flex justify-between">
- <label
- htmlFor="email"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- {label}
- </label>
- </div>
- </Fragment>
- );
- const WithTooltip = tooltip ? (
- <div class="relative flex flex-grow items-stretch focus-within:z-10">
- {Label}
- <span class="relative flex items-center group pl-2">
- {TooltipIcon}
- <div class="absolute bottom-0 -ml-10 hidden flex-col items-center mb-6 group-hover:flex w-28">
- <div class="relative z-10 p-2 text-xs leading-none text-white whitespace-no-wrap bg-black shadow-lg">
- {tooltip}
- </div>
- <div class="w-3 h-3 -mt-2 rotate-45 bg-black"></div>
- </div>
- </span>
- </div>
- ) : (
- Label
- );
- if (required) {
- return (
- <div class="flex justify-between">
- {WithTooltip}
- <span class="text-sm leading-6 text-red-600">*</span>
- </div>
- );
- }
- return WithTooltip;
-}
-
-function InputWrapper<T extends object, K extends keyof T>({
- children,
- label,
- tooltip,
- before,
- after,
- help,
- error,
- disabled,
- required,
-}: { error?: string; disabled: boolean, children: ComponentChildren } & UIFormProps<T, K>): VNode {
- return (
- <div class="sm:col-span-6">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
- <div class="relative mt-2 flex rounded-md shadow-sm">
- {before &&
- (before.type === "text" ? (
- <span class="inline-flex items-center rounded-l-md border border-r-0 border-gray-300 px-3 text-gray-500 sm:text-sm">
- {before.text}
- </span>
- ) : before.type === "icon" ? (
- <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
- {before.icon}
- </div>
- ) : before.type === "button" ? (
- <button
- type="button"
- disabled={disabled}
- onClick={before.onClick}
- class="relative -ml-px inline-flex items-center gap-x-1.5 rounded-l-md px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
- >
- {before.children}
- </button>
- ) : undefined)}
-
- {children}
-
- {after &&
- (after.type === "text" ? (
- <span class="inline-flex items-center rounded-r-md border border-l-0 border-gray-300 px-3 text-gray-500 sm:text-sm">
- {after.text}
- </span>
- ) : after.type === "icon" ? (
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
- {after.icon}
- </div>
- ) : after.type === "button" ? (
- <button
- type="button"
- disabled={disabled}
- onClick={after.onClick}
- class="relative -ml-px inline-flex items-center gap-x-1.5 rounded-r-md px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
- >
- {after.children}
- </button>
- ) : undefined)}
- </div>
- {error && (
- <p class="mt-2 text-sm text-red-600" id="email-error">
- {error}
- </p>
- )}
- {help && (
- <p class="mt-2 text-sm text-gray-500" id="email-description">
- {help}
- </p>
- )}
- </div>
- );
-}
-
-function defaultToString(v: unknown) {
- return v === undefined ? "" : typeof v !== "object" ? String(v) : "";
-}
-function defaultFromString(v: string) {
- return v;
-}
-
-type InputType = "text" | "text-area" | "password" | "email" | "number";
-
-export function InputLine<T extends object, K extends keyof T>(
- props: { type: InputType } & UIFormProps<T, K>,
-): VNode {
- const { name, placeholder, before, after, converter, type } = props;
- const { value, onChange, state, isDirty } = useField<T, K>(name);
-
- const [text, setText] = useState("")
- const fromString: (s: string) => any =
- converter?.fromStringUI ?? defaultFromString;
- const toString: (s: any) => string = converter?.toStringUI ?? defaultToString;
-
- useEffect(() => {
- const newValue = toString(value)
- if (newValue) {
- setText(newValue)
- }
- }, [value])
-
- if (state.hidden) return <div />;
-
- let clazz =
- "block w-full rounded-md border-0 py-1.5 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200";
- if (before) {
- switch (before.type) {
- case "icon": {
- clazz += " pl-10";
- break;
- }
- case "button": {
- clazz += " rounded-none rounded-r-md ";
- break;
- }
- case "text": {
- clazz += " min-w-0 flex-1 rounded-r-md rounded-none ";
- break;
- }
- }
- }
- if (after) {
- switch (after.type) {
- case "icon": {
- clazz += " pr-10";
- break;
- }
- case "button": {
- clazz += " rounded-none rounded-l-md";
- break;
- }
- case "text": {
- clazz += " min-w-0 flex-1 rounded-l-md rounded-none ";
- break;
- }
- }
- }
- const showError = isDirty && state.error;
- if (showError) {
- clazz +=
- " text-red-900 ring-red-300 placeholder:text-red-300 focus:ring-red-500";
- } else {
- clazz +=
- " text-gray-900 ring-gray-300 placeholder:text-gray-400 focus:ring-indigo-600";
- }
-
- if (type === "text-area") {
- return (
- <InputWrapper<T, K>
- {...props}
- help={props.help ?? state.help}
- disabled={state.disabled ?? false}
- error={showError ? state.error : undefined}
- >
- <textarea
- rows={4}
- name={String(name)}
- onChange={(e) => {
- onChange(fromString(e.currentTarget.value));
- }}
- placeholder={placeholder ? placeholder : undefined}
- value={toString(value) ?? ""}
- // defaultValue={toString(value)}
- disabled={state.disabled}
- aria-invalid={showError}
- // aria-describedby="email-error"
- class={clazz}
- />
- </InputWrapper>
- );
- }
-
- return (
- <InputWrapper<T, K> {...props}
- help={props.help ?? state.help}
- disabled={state.disabled ?? false} error={showError ? state.error : undefined}
- >
- <input
- name={String(name)}
- type={type}
- onChange={(e) => {
- setText(e.currentTarget.value)
- }}
- placeholder={placeholder ? placeholder : undefined}
- value={text}
- onBlur={() => {
- onChange(fromString(text));
- }}
- // defaultValue={toString(value)}
- disabled={state.disabled}
- aria-invalid={showError}
- // aria-describedby="email-error"
- class={clazz}
- />
- </InputWrapper>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.stories.tsx
deleted file mode 100644
index 4dac61f21..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.stories.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Select Multiple",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- pets: string[];
- things: string[];
-}
-const initial: TargetObject = {
- pets: [],
- things: [],
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "selectMultiple",
- props: {
- label: "allow diplicates" as TranslatedString,
- name: "pets",
- placeholder: "search..." as TranslatedString,
- choices: [{
- label: "one label" as TranslatedString,
- value: "one"
- }, {
- label: "two label" as TranslatedString,
- value: "two"
- }, {
- label: "five label" as TranslatedString,
- value: "five"
- }]
- },
- }, {
- type: "selectMultiple",
- props: {
- label: "unique values" as TranslatedString,
- name: "things",
- unique: true,
- placeholder: "search..." as TranslatedString,
- choices: [{
- label: "one label" as TranslatedString,
- value: "one"
- }, {
- label: "two label" as TranslatedString,
- value: "two"
- }, {
- label: "five label" as TranslatedString,
- value: "five"
- }]
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.tsx b/packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.tsx
deleted file mode 100644
index 06eb91bb3..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputSelectMultiple.tsx
+++ /dev/null
@@ -1,154 +0,0 @@
-import { Fragment, VNode, h } from "preact";
-import { Choice } from "./InputChoiceStacked.js";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { useField } from "./useField.js";
-import { useState } from "preact/hooks";
-import { UIFormProps } from "./FormProvider.js";
-
-export function InputSelectMultiple<T extends object, K extends keyof T>(
- props: {
- choices: Choice<T[K]>[];
- unique?: boolean;
- max?: number;
- } & UIFormProps<T, K>,
-): VNode {
- const { name, label, choices, placeholder, tooltip, required, unique, max } =
- props;
- const { value, onChange, state } = useField<T, K>(name);
-
- const [filter, setFilter] = useState<string | undefined>(undefined);
- const regex = new RegExp(`.*${filter}.*`, "i");
- const choiceMap = choices.reduce((prev, curr) => {
- return { ...prev, [curr.value as string]: curr.label };
- }, {} as Record<string, string>);
-
- const list = (value ?? []) as string[];
- const filteredChoices =
- filter === undefined
- ? undefined
- : choices.filter((v) => {
- return regex.test(v.label);
- });
- return (
- <div class="sm:col-span-6">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
- {list.map((v, idx) => {
- return (
- <span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mr-2 text-xs font-medium text-gray-600">
- {choiceMap[v]}
- <button
- type="button"
- disabled={state.disabled}
- onClick={() => {
- const newValue = [...list];
- newValue.splice(idx, 1);
- onChange(newValue as T[K]);
- setFilter(undefined);
- }}
- class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
- >
- <span class="sr-only">Remove</span>
- <svg
- viewBox="0 0 14 14"
- class="h-5 w-5 stroke-gray-700/50 group-hover:stroke-gray-700/75"
- >
- <path d="M4 4l6 6m0-6l-6 6" />
- </svg>
- <span class="absolute -inset-1"></span>
- </button>
- </span>
- );
- })}
-
- {!state.disabled && <div class="relative mt-2">
- <input
- id="combobox"
- type="text"
- value={filter ?? ""}
- onChange={(e) => {
- setFilter(e.currentTarget.value);
- }}
- placeholder={placeholder}
- class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- role="combobox"
- aria-controls="options"
- aria-expanded="false"
- />
- <button
- type="button"
- disabled={state.disabled}
- onClick={() => {
- setFilter(filter === undefined ? "" : undefined);
- }}
- class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"
- >
- <svg
- class="h-5 w-5 text-gray-400"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z"
- clip-rule="evenodd"
- />
- </svg>
- </button>
-
- {filteredChoices !== undefined && (
- <ul
- class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
- id="options"
- role="listbox"
- >
- {filteredChoices.map((v, idx) => {
- return (
- <li
- class="relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600"
- id="option-0"
- role="option"
- onClick={() => {
- setFilter(undefined);
- if (unique && list.indexOf(v.value as string) !== -1) {
- return;
- }
- if (max !== undefined && list.length >= max) {
- return;
- }
- const newValue = [...list];
- newValue.splice(0, 0, v.value as string);
- onChange(newValue as T[K]);
- }}
-
- // tabindex="-1"
- >
- {/* <!-- Selected: "font-semibold" --> */}
- <span class="block truncate">{v.label}</span>
-
- {/* <!--
- Checkmark, only display for selected option.
-
- Active: "text-white", Not Active: "text-indigo-600"
- --> */}
- </li>
- );
- })}
-
- {/* <!--
- Combobox option, manage highlight styles based on mouseenter/mouseleave and keyboard navigation.
-
- Active: "text-white bg-indigo-600", Not Active: "text-gray-900"
- --> */}
-
- {/* <!-- More items... --> */}
- </ul>
- )}
- </div>}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputSelectOne.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputSelectOne.stories.tsx
deleted file mode 100644
index 0bb871500..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputSelectOne.stories.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Select One",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- things: string;
-}
-const initial: TargetObject = {
- things: "one"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "selectOne",
- props: {
- label: "label of the field" as TranslatedString,
- name: "things",
- placeholder: "search..." as TranslatedString,
- choices: [{
- label: "one label" as TranslatedString,
- value: "one"
- }, {
- label: "two label" as TranslatedString,
- value: "two"
- }, {
- label: "five label" as TranslatedString,
- value: "five"
- }]
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputSelectOne.tsx b/packages/aml-backoffice-ui/src/handlers/InputSelectOne.tsx
deleted file mode 100644
index 98430306e..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputSelectOne.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import { Fragment, VNode, h } from "preact";
-import { Choice } from "./InputChoiceStacked.js";
-import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { useField } from "./useField.js";
-import { useState } from "preact/hooks";
-import { UIFormProps } from "./FormProvider.js";
-
-export function InputSelectOne<T extends object, K extends keyof T>(
- props: {
- choices: Choice<T[K]>[];
- } & UIFormProps<T, K>,
-): VNode {
- const { name, label, choices, placeholder, tooltip, required } = props;
- const { value, onChange } = useField<T, K>(name);
-
- const [filter, setFilter] = useState<string | undefined>(undefined);
- const regex = new RegExp(`.*${filter}.*`, "i");
- const choiceMap = choices.reduce((prev, curr) => {
- return { ...prev, [curr.value as string]: curr.label };
- }, {} as Record<string, string>);
-
- const filteredChoices =
- filter === undefined
- ? undefined
- : choices.filter((v) => {
- return regex.test(v.label);
- });
- return (
- <div class="sm:col-span-6">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
- {value ? (
- <span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mr-2 font-medium text-gray-600">
- {choiceMap[value as string]}
- <button
- type="button"
- onClick={() => {
- onChange(undefined!);
- }}
- class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
- >
- <span class="sr-only">Remove</span>
- <svg
- viewBox="0 0 14 14"
- class="h-5 w-5 stroke-gray-700/50 group-hover:stroke-gray-700/75"
- >
- <path d="M4 4l6 6m0-6l-6 6" />
- </svg>
- <span class="absolute -inset-1"></span>
- </button>
- </span>
- ) : (
- <div class="relative mt-2">
- <input
- id="combobox"
- type="text"
- value={filter ?? ""}
- onChange={(e) => {
- setFilter(e.currentTarget.value);
- }}
- placeholder={placeholder}
- class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- role="combobox"
- aria-controls="options"
- aria-expanded="false"
- />
- <button
- type="button"
- onClick={() => {
- setFilter(filter === undefined ? "" : undefined);
- }}
- class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"
- >
- <svg
- class="h-5 w-5 text-gray-400"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z"
- clip-rule="evenodd"
- />
- </svg>
- </button>
-
- {filteredChoices !== undefined && (
- <ul
- class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
- id="options"
- role="listbox"
- >
- {filteredChoices.map((v, idx) => {
- return (
- <li
- class="relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600"
- id="option-0"
- role="option"
- onClick={() => {
- setFilter(undefined);
- onChange(v.value as T[K]);
- }}
-
- // tabindex="-1"
- >
- {/* <!-- Selected: "font-semibold" --> */}
- <span class="block truncate">{v.label}</span>
-
- {/* <!--
- Checkmark, only display for selected option.
-
- Active: "text-white", Not Active: "text-indigo-600"
- --> */}
- </li>
- );
- })}
-
- {/* <!--
- Combobox option, manage highlight styles based on mouseenter/mouseleave and keyboard navigation.
-
- Active: "text-white bg-indigo-600", Not Active: "text-gray-900"
- --> */}
-
- {/* <!-- More items... --> */}
- </ul>
- )}
- </div>
- )}
- </div>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputText.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputText.stories.tsx
deleted file mode 100644
index 9ce733d4a..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputText.stories.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Text",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "some initial comment"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "text",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputText.tsx b/packages/aml-backoffice-ui/src/handlers/InputText.tsx
deleted file mode 100644
index 7ad36b737..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputText.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { VNode, h } from "preact";
-import { InputLine } from "./InputLine.js";
-import { UIFormProps } from "./FormProvider.js";
-
-export function InputText<T extends object, K extends keyof T>(
- props: UIFormProps<T, K>,
-): VNode {
- return <InputLine type="text" {...props} />;
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputTextArea.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputTextArea.stories.tsx
deleted file mode 100644
index df35b25c4..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputTextArea.stories.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Text Area",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "some initial comment"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "text",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputTextArea.tsx b/packages/aml-backoffice-ui/src/handlers/InputTextArea.tsx
deleted file mode 100644
index 6b76d8329..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputTextArea.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { VNode, h } from "preact";
-import { InputLine } from "./InputLine.js";
-import { UIFormProps } from "./FormProvider.js";
-
-export function InputTextArea<T extends object, K extends keyof T>(
- props: UIFormProps<T, K>,
-): VNode {
- return <InputLine type="text-area" {...props} />;
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/InputToggle.stories.tsx b/packages/aml-backoffice-ui/src/handlers/InputToggle.stories.tsx
deleted file mode 100644
index 735e812f3..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputToggle.stories.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import {
- NiceForm as TestedComponent,
-} from "./NiceForm.js";
-import { FlexibleForm } from "./forms.js";
-
-export default {
- title: "Input Toggle",
-};
-
-export namespace Simplest {
- export interface Form {
- comment: string;
- }
-}
-
-type TargetObject = {
- comment: string;
-}
-const initial: TargetObject = {
- comment: "some initial comment"
-}
-
-const form: FlexibleForm<TargetObject> = {
- design: [{
- title: "this is a simple form" as TranslatedString,
- fields: [{
- type: "toggle",
- props: {
- label: "label of the field" as TranslatedString,
- name: "comment",
- },
- }]
- }]
-}
-
-export const SimpleComment = tests.createExample(TestedComponent, { initial, form });
diff --git a/packages/aml-backoffice-ui/src/handlers/InputToggle.tsx b/packages/aml-backoffice-ui/src/handlers/InputToggle.tsx
deleted file mode 100644
index 1ea8699b2..000000000
--- a/packages/aml-backoffice-ui/src/handlers/InputToggle.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { VNode, h } from "preact";
-import { InputLine, LabelWithTooltipMaybeRequired } from "./InputLine.js";
-import { UIFormProps } from "./FormProvider.js";
-import { useField } from "./useField.js";
-
-export function InputToggle<T extends object, K extends keyof T>(
- props: UIFormProps<T, K>,
-): VNode {
- const {
- name,
- label,
- tooltip,
- help,
- placeholder,
- required,
- before,
- after,
- converter,
- } = props;
- const { value, onChange, state, isDirty } = useField<T, K>(name);
-
- const isOn = !!value
- return <div class="sm:col-span-6">
- <div class="flex items-center justify-between">
- <LabelWithTooltipMaybeRequired
- label={label}
- required={required}
- tooltip={tooltip}
- />
- <button type="button" data-enabled={isOn}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description"
- onClick={() => { onChange(!isOn as any); }}>
- <span aria-hidden="true" data-enabled={isOn} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span>
- </button>
- </div>
- </div>
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/NiceForm.tsx b/packages/aml-backoffice-ui/src/handlers/NiceForm.tsx
deleted file mode 100644
index d01b80b02..000000000
--- a/packages/aml-backoffice-ui/src/handlers/NiceForm.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { ComponentChildren, Fragment, h } from "preact";
-import { FormProvider } from "./FormProvider.js";
-import { FlexibleForm, RenderAllFieldsByUiConfig } from "./forms.js";
-
-export function NiceForm<T extends object>({
- initial,
- onUpdate,
- form,
- onSubmit,
- children,
- readOnly,
-}: {
- children?: ComponentChildren;
- initial: Partial<T>;
- onSubmit?: (v: Partial<T>) => void;
- form: FlexibleForm<T>;
- readOnly?: boolean;
- onUpdate?: (d: Partial<T>) => void;
-}) {
- return (
- <FormProvider
- initialValue={initial}
- onUpdate={onUpdate}
- onSubmit={onSubmit}
- readOnly={readOnly}
- computeFormState={form.behavior}
- >
- <div class="space-y-10 divide-y -mt-5 divide-gray-900/10">
- {form.design.map((section, i) => {
- if (!section) return <Fragment />;
- return (
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3">
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- {section.title}
- </h2>
- {section.description && (
- <p class="mt-1 text-sm leading-6 text-gray-600">
- {section.description}
- </p>
- )}
- </div>
- <div class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-md md:col-span-2">
- <div class="p-3">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <RenderAllFieldsByUiConfig
- key={i}
- fields={section.fields}
- />
- </div>
- </div>
- </div>
- </div>
- );
- })}
- </div>
- {children}
- </FormProvider>
- );
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/TimePicker.tsx b/packages/aml-backoffice-ui/src/handlers/TimePicker.tsx
deleted file mode 100644
index c6dc3e794..000000000
--- a/packages/aml-backoffice-ui/src/handlers/TimePicker.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import { AbsoluteTime } from "@gnu-taler/taler-util"
-import { useTranslationContext } from "@gnu-taler/web-util/browser"
-import { startOfDay, getHours, getMinutes, getSeconds, setHours } from "date-fns"
-import { Fragment, VNode, h } from "preact"
-import { useState } from "preact/hooks"
-
-export function TimePicker({ value, onChange, onConfirm }: { value: AbsoluteTime | undefined, onChange: (v: AbsoluteTime) => void, onConfirm: () => void }): VNode {
- const date = !value ? new Date() : new Date(AbsoluteTime.toStampMs(value))
- const hours = getHours(date) % 12
- const minutes = getMinutes(date)
- const seconds = getSeconds(date)
-
- const { i18n } = useTranslationContext()
-
- return <Fragment>
- <div class="flex flex-col bg-white rounded-t-sm justify-around" >
- {/* time selection */}
- <div id="" class="bg-[#3b71ca] dark:bg-zinc-700 h-24 rounded-t-lg p-12 flex flex-row items-center justify-center">
- <div class="flex w-full justify-evenly">
- <div class="">
- <span class="relative h-full">
- <button type="button" class="py-1 px-3 text-[3.75rem] font-light leading-[1.2] text-white opacity-[.54] border-none bg-transparent p-0 cursor-pointer hover:bg-[#00000026] hover:outline-none focus:bg-[#00000026] focus:outline-none "
- style="pointer-events: none;">
- {new String(hours).padStart(2, "0")}
- </button>
- </span>
- <span type="button" class="font-light leading-[1.2] text-[3.75rem] opacity-[.54] border-none bg-transparent p-0 text-white " >:</span>
- <span class="relative h-full">
- <button type="button" class="py-1 px-3 text-[3.75rem] font-light leading-[1.2] text-white opacity-[.54] border-none bg-transparent p-0 cursor-pointer hover:bg-[#00000026] hover:outline-none focus:bg-[#00000026] focus:outline-none " >
- {new String(minutes).padStart(2, "0")}
- </button>
- </span>
- <span type="button" class="font-light leading-[1.2] text-[3.75rem] opacity-[.54] border-none bg-transparent p-0 text-white " >:</span>
- <span class="relative h-full">
- <button type="button" class="py-1 px-3 text-[3.75rem] font-light leading-[1.2] text-white opacity-[.54] border-none bg-transparent p-0 cursor-pointer hover:bg-[#00000026] hover:outline-none focus:bg-[#00000026] focus:outline-none " >
- {new String(seconds).padStart(2, "0")}
- </button>
- </span>
- </div>
- <div class="flex flex-col justify-center text-[18px] text-[#ffffff8a] ">
- <button type="button" class="py-1 px-3 bg-transparent border-none text-white cursor-pointer hover:bg-[#00000026] hover:outline-none focus:bg-[#00000026] focus:outline-none" >
- AM
- </button>
- <button type="button" class="py-1 px-3 bg-transparent border-none text-white cursor-pointer hover:bg-[#00000026] hover:outline-none focus:bg-[#00000026] focus:outline-none" >
- PM
- </button>
- </div>
- </div>
- </div>
- {/* clock */}
- <div id="" class="mt-2 min-w-[310px] max-w-[325px] min-h-[305px] overflow-x-hidden h-full flex justify-center mx-auto flex-col items-center dark:bg-zinc-500" >
- <div class="relative rounded-[100%] w-[260px] h-[260px] cursor-default my-0 mx-auto bg-[#00000012] dark:bg-zinc-600/50 animate-[show-up-clock_350ms_linear]" >
-
- <span class="top-1/2 left-1/2 w-[6px] h-[6px] -translate-y-1/2 -translate-x-1/2 rounded-[50%] bg-[#3b71ca] absolute" ></span>
- <div class="bg-[#3b71ca] bottom-1/2 h-2/5 left-[calc(50%-1px)] rtl:!left-auto origin-[center_bottom_0] rtl:!origin-[50%_50%_0] w-[2px] absolute" style={{ transform: "rotateZ(60deg)", height: "calc(35% + 1px)" }}>
- {/* <div class="-top-[21px] -left-[15px] w-[4px] border-[14px] border-solid border-[#3b71ca] h-[4px] box-content rounded-[100%] absolute" style="background-color: rgb(25, 118, 210);"></div> */}
- </div>
-
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 12).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 114px; bottom: 224px;">
- <span>0</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 1).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 169px; bottom: 209.263px;">
- <span >1</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 2).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" data-selected={true} style="left: 209.263px; bottom: 169px;" >
- <span >2</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 3).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 224px; bottom: 114px;">
- <span >3</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 4).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 209.263px; bottom: 59px;">
- <span >4</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 5).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 169px; bottom: 18.7372px;">
- <span >5</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 6).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 114px; bottom: 4px;">
- <span >6</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 7).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 59px; bottom: 18.7372px;">
- <span >7</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 8).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 18.7372px; bottom: 59px;">
- <span >8</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 9).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 4px; bottom: 114px;">
- <span >9</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 10).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 18.7372px; bottom: 169px;">
- <span >10</span>
- </span>
- <span onClick={() => onChange(AbsoluteTime.fromStampMs(setHours(date, 11).getTime()))} class="absolute rounded-[100%] w-[32px] h-[32px] text-center cursor-pointer text-[1.1rem] bg-transparent flex justify-center items-center font-light focus:outline-none selection:bg-transparent data-[selected=true]:text-white data-[selected=true]:bg-[#3b71ca] data-[selected=true]:font-normal" style="left: 59px; bottom: 209.263px;">
- <span >11</span>
- </span>
- </div>
- </div>
- </div>
- <div id="" class="rounded-b-lg flex justify-between items-center w-full h-[56px] px-[12px] bg-white dark:bg-zinc-500">
- <div class="w-full flex justify-end">
- <button
- type="submit"
- onClick={onConfirm}
- class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Confirm</i18n.Translate>
- </button>
- </div>
- </div>
- </Fragment>
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/forms.ts b/packages/aml-backoffice-ui/src/handlers/forms.ts
deleted file mode 100644
index 1c212fafa..000000000
--- a/packages/aml-backoffice-ui/src/handlers/forms.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { InputText } from "./InputText.js";
-import { InputAbsoluteTime } from "./InputAbsoluteTime.js";
-import { InputInteger } from "./InputInteger.js";
-import { h as create, Fragment, VNode } from "preact";
-import { InputChoiceStacked } from "./InputChoiceStacked.js";
-import { InputArray } from "./InputArray.js";
-import { InputSelectMultiple } from "./InputSelectMultiple.js";
-import { InputTextArea } from "./InputTextArea.js";
-import { InputFile } from "./InputFile.js";
-import { Caption } from "./Caption.js";
-import { Group } from "./Group.js";
-import { InputSelectOne } from "./InputSelectOne.js";
-import { FormProvider, FormState } from "./FormProvider.js";
-import { InputLine } from "./InputLine.js";
-import { InputAmount } from "./InputAmount.js";
-import { InputChoiceHorizontal } from "./InputChoiceHorizontal.js";
-import { InputToggle } from "./InputToggle.js";
-
-export type DoubleColumnForm = Array<DoubleColumnFormSection | undefined>;
-
-export type DoubleColumnFormSection = {
- title: TranslatedString;
- description?: TranslatedString;
- fields: UIFormField[];
-};
-export interface FlexibleForm<T extends object> {
- design: DoubleColumnForm;
- behavior?: (form: Partial<T>) => FormState<T>;
-}
-
-/**
- * Constrain the type with the ui props
- */
-type FieldType<T extends object = any, K extends keyof T = any> = {
- group: Parameters<typeof Group>[0];
- caption: Parameters<typeof Caption>[0];
- array: Parameters<typeof InputArray<T, K>>[0];
- file: Parameters<typeof InputFile<T, K>>[0];
- selectOne: Parameters<typeof InputSelectOne<T, K>>[0];
- selectMultiple: Parameters<typeof InputSelectMultiple<T, K>>[0];
- text: Parameters<typeof InputText<T, K>>[0];
- textArea: Parameters<typeof InputTextArea<T, K>>[0];
- choiceStacked: Parameters<typeof InputChoiceStacked<T, K>>[0];
- choiceHorizontal: Parameters<typeof InputChoiceHorizontal<T, K>>[0];
- absoluteTime: Parameters<typeof InputAbsoluteTime<T, K>>[0];
- integer: Parameters<typeof InputInteger<T, K>>[0];
- toggle: Parameters<typeof InputToggle<T, K>>[0];
- amount: Parameters<typeof InputAmount<T, K>>[0];
-};
-
-/**
- * List all the form fields so typescript can type-check the form instance
- */
-export type UIFormField =
- | { type: "group"; props: FieldType["group"] }
- | { type: "caption"; props: FieldType["caption"] }
- | { type: "array"; props: FieldType["array"] }
- | { type: "file"; props: FieldType["file"] }
- | { type: "amount"; props: FieldType["amount"] }
- | { type: "selectOne"; props: FieldType["selectOne"] }
- | { type: "selectMultiple"; props: FieldType["selectMultiple"] }
- | { type: "text"; props: FieldType["text"] }
- | { type: "textArea"; props: FieldType["textArea"] }
- | { type: "choiceStacked"; props: FieldType["choiceStacked"] }
- | { type: "choiceHorizontal"; props: FieldType["choiceHorizontal"] }
- | { type: "integer"; props: FieldType["integer"] }
- | { type: "toggle"; props: FieldType["toggle"] }
- | { type: "absoluteTime"; props: FieldType["absoluteTime"] };
-
-type FieldComponentFunction<key extends keyof FieldType> = (
- props: FieldType[key],
-) => VNode;
-
-type UIFormFieldMap = {
- [key in keyof FieldType]: FieldComponentFunction<key>;
-};
-
-/**
- * Maps input type with component implementation
- */
-const UIFormConfiguration: UIFormFieldMap = {
- group: Group,
- caption: Caption,
- //@ts-ignore
- array: InputArray,
- text: InputText,
- //@ts-ignore
- file: InputFile,
- textArea: InputTextArea,
- //@ts-ignore
- absoluteTime: InputAbsoluteTime,
- //@ts-ignore
- choiceStacked: InputChoiceStacked,
- //@ts-ignore
- choiceHorizontal: InputChoiceHorizontal,
- integer: InputInteger,
- //@ts-ignore
- selectOne: InputSelectOne,
- //@ts-ignore
- selectMultiple: InputSelectMultiple,
- //@ts-ignore
- toggle: InputToggle,
- //@ts-ignore
- amount: InputAmount,
-};
-
-export function RenderAllFieldsByUiConfig({
- fields,
-}: {
- fields: UIFormField[];
-}): VNode {
- return create(
- Fragment,
- {},
- fields.map((field, i) => {
- const Component = UIFormConfiguration[
- field.type
- ] as FieldComponentFunction<any>;
- return Component(field.props);
- }),
- );
-}
-
-type FormSet<T extends object> = {
- Provider: typeof FormProvider<T>;
- InputLine: <K extends keyof T>() => typeof InputLine<T, K>;
- InputChoiceHorizontal: <K extends keyof T>() => typeof InputChoiceHorizontal<T, K>;
-};
-export function createNewForm<T extends object>() {
- const res: FormSet<T> = {
- Provider: FormProvider,
- InputLine: () => InputLine,
- InputChoiceHorizontal: () => InputChoiceHorizontal,
- };
- return {
- Provider: res.Provider,
- InputLine: res.InputLine(),
- InputChoiceHorizontal: res.InputChoiceHorizontal(),
- };
-}
diff --git a/packages/aml-backoffice-ui/src/handlers/index.stories.ts b/packages/aml-backoffice-ui/src/handlers/index.stories.ts
deleted file mode 100644
index 55878cb02..000000000
--- a/packages/aml-backoffice-ui/src/handlers/index.stories.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export * as a1 from "./InputAmount.stories.js";
-export * as a2 from "./InputArray.stories.js";
-export * as a3 from "./InputChoiceHorizontal.stories.js";
-export * as a4 from "./InputChoiceStacked.stories.js";
-export * as a5 from "./InputAbsoluteTime.stories.js";
-export * as a6 from "./InputFile.stories.js";
-export * as a7 from "./InputInteger.stories.js";
-export * as a8 from "./InputLine.stories.js";
-export * as a9 from "./InputSelectMultiple.stories.js";
-export * as a10 from "./InputSelectOne.stories.js";
-export * as a11 from "./InputText.stories.js";
-export * as a12 from "./InputTextArea.stories.js";
-export * as a13 from "./InputToggle.stories.js";
diff --git a/packages/aml-backoffice-ui/src/handlers/useField.ts b/packages/aml-backoffice-ui/src/handlers/useField.ts
deleted file mode 100644
index 651778628..000000000
--- a/packages/aml-backoffice-ui/src/handlers/useField.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { useContext, useState } from "preact/compat";
-import { BehaviorResult, FormContext, InputFieldState } from "./FormProvider.js";
-
-export interface InputFieldHandler<Type> {
- value: Type;
- onChange: (s: Type) => void;
- state: BehaviorResult;
- isDirty: boolean;
-}
-
-export function useField<T extends object, K extends keyof T>(
- name: K,
-): InputFieldHandler<T[K]> {
- const {
- initialValue,
- value: formValue,
- computeFormState,
- onUpdate: notifyUpdate,
- readOnly: readOnlyForm,
- } = useContext(FormContext);
-
- type P = typeof name;
- type V = T[P];
- const formState = computeFormState ? computeFormState(formValue.current) : {};
-
- const fieldValue = readField(formValue.current, String(name)) as V;
- // console.log("USE FIELD", String(name), formValue.current, fieldValue);
- const [currentValue, setCurrentValue] = useState<any | undefined>(fieldValue);
- const fieldState =
- readField<Partial<BehaviorResult>>(formState, String(name)) ?? {};
-
- //compute default state
- const state = {
- disabled: readOnlyForm ? true : (fieldState.disabled ?? false),
- readonly: readOnlyForm ? true : (fieldState.readonly ?? false),
- hidden: fieldState.hidden ?? false,
- error: fieldState.error,
- help: fieldState.help,
- elements: "elements" in fieldState ? fieldState.elements ?? [] : [],
- };
-
- function onChange(value: V): void {
- setCurrentValue(value);
- formValue.current = setValueDeeper(
- formValue.current,
- String(name).split("."),
- value,
- );
- if (notifyUpdate) {
- notifyUpdate(formValue.current);
- }
- }
-
- return {
- value: fieldValue,
- onChange,
- isDirty: currentValue !== undefined,
- state,
- };
-}
-
-/**
- * read the field of an object an support accessing it using '.'
- *
- * @param object
- * @param name
- * @returns
- */
-function readField<T>(
- object: any,
- name: string,
- debug?: boolean,
-): T | undefined {
- return name.split(".").reduce((prev, current) => {
- if (debug) {
- console.log(
- "READ",
- name,
- prev,
- current,
- prev ? prev[current] : undefined,
- );
- }
- return prev ? prev[current] : undefined;
- }, object);
-}
-
-function setValueDeeper(object: any, names: string[], value: any): any {
- if (names.length === 0) return value;
- const [head, ...rest] = names;
- if (object === undefined) {
- return { [head]: setValueDeeper({}, rest, value) };
- }
- return { ...object, [head]: setValueDeeper(object[head] ?? {}, rest, value) };
-}