diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/components')
5 files changed, 244 insertions, 30 deletions
diff --git a/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx b/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx index 7bcebd706..0d53c4d08 100644 --- a/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx +++ b/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx @@ -82,6 +82,12 @@ export interface FormType<T> { const FormContext = createContext<FormType<unknown>>(null!); +/** + * FIXME: + * USE MEMORY EVENTS INSTEAD OF CONTEXT + * @deprecated + */ + export function useFormContext<T>() { return useContext<FormType<T>>(FormContext); } diff --git a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx new file mode 100644 index 000000000..2c1961639 --- /dev/null +++ b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx @@ -0,0 +1,47 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { h } from "preact"; +import { tests } from "@gnu-taler/web-util/lib/index.browser"; +import { InputPaytoForm } from "./InputPaytoForm.js"; +import { FormProvider } from "./FormProvider.js"; +import { useState } from "preact/hooks"; + +export default { + title: "Components/Form/PayTo", + component: InputPaytoForm, + argTypes: { + onUpdate: { action: "onUpdate" }, + onBack: { action: "onBack" }, + }, +}; + +export const Example = tests.createExample(() => { + const initial = { + accounts: [], + }; + const [form, updateForm] = useState<Partial<typeof initial>>(initial); + return ( + <FormProvider valueHandler={updateForm} object={form}> + <InputPaytoForm name="accounts" label="Accounts:" /> + </FormProvider> + ); +}, {}); diff --git a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx index 3cd36a6e0..98fe2f91a 100644 --- a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx +++ b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx @@ -28,6 +28,8 @@ import { Input } from "./Input.js"; import { InputGroup } from "./InputGroup.js"; import { InputSelector } from "./InputSelector.js"; import { InputProps, useField } from "./useField.js"; +import { InputWithAddon } from "./InputWithAddon.js"; +import { MerchantBackend } from "../../declaration.js"; export interface Props<T> extends InputProps<T> { isValid?: (e: any) => boolean; @@ -50,6 +52,13 @@ type Entity = { instruction?: string; [name: string]: string | undefined; }; + auth: { + type: "unset" | "basic" | "none"; + url?: string; + username?: string; + password?: string; + repeat?: string; + }; }; function isEthereumAddress(address: string) { @@ -162,8 +171,15 @@ const targets = [ "bitcoin", "ethereum", ]; +const accountAuthType = ["none", "basic"]; const noTargetValue = targets[0]; -const defaultTarget = { target: noTargetValue, options: {} }; +const defaultTarget: Partial<Entity> = { + target: noTargetValue, + options: {}, + auth: { + type: "unset" as const, + }, +}; export function InputPaytoForm<T>({ name, @@ -187,7 +203,7 @@ export function InputPaytoForm<T>({ } const { i18n } = useTranslationContext(); - const ops = value.options!; + const ops = value.options ?? {}; const url = tryUrl(`payto://${value.target}${payToPath}`); if (url) { Object.keys(ops).forEach((opt_key) => { @@ -222,6 +238,24 @@ export function InputPaytoForm<T>({ ? i18n.str`required` : undefined, }), + auth: !value.auth + ? undefined + : undefinedIfEmpty({ + username: + value.auth.type === "basic" && !value.auth.username + ? i18n.str`required` + : undefined, + password: + value.auth.type === "basic" && !value.auth.password + ? i18n.str`required` + : undefined, + repeat: + value.auth.type === "basic" && !value.auth.repeat + ? i18n.str`required` + : value.auth.repeat !== value.auth.password + ? i18n.str`is not the same` + : undefined, + }), }; const hasErrors = Object.keys(errors).some( @@ -229,10 +263,31 @@ export function InputPaytoForm<T>({ ); const submit = useCallback((): void => { + const accounts: MerchantBackend.Instances.MerchantBankAccount[] = paytos; const alreadyExists = - paytos.findIndex((x: string) => x === paytoURL) !== -1; + accounts.findIndex((x) => x.payto_uri === paytoURL) !== -1; if (!alreadyExists) { - onChange([paytoURL, ...paytos] as any); + const newValue: MerchantBackend.Instances.MerchantBankAccount = { + payto_uri: paytoURL, + }; + if (value.auth) { + if (value.auth.url) { + newValue.credit_facade_url = value.auth.url; + } + if (value.auth.type === "none") { + newValue.credit_facade_credentials = { + type: "none", + }; + } + if (value.auth.type === "basic") { + newValue.credit_facade_credentials = { + type: "basic", + username: value.auth.username ?? "", + password: value.auth.password ?? "", + }; + } + } + onChange([newValue, ...accounts] as any); } valueHandler(defaultTarget); }, [value]); @@ -339,37 +394,126 @@ export function InputPaytoForm<T>({ </Fragment> )} + {/** + * Show additional fields apart from the payto + */} {value.target !== noTargetValue && ( - <Input - name="options.receiver-name" - label={i18n.str`Name`} - tooltip={i18n.str`Bank account owner's name.`} - /> - )} + <Fragment> + <Input + name="options.receiver-name" + label={i18n.str`Name`} + tooltip={i18n.str`Bank account owner's name.`} + /> + <InputWithAddon + name="auth.url" + label={i18n.str`Account info URL`} + help="https://bank.com" + expand + tooltip={i18n.str`From where the merchant can download information about incoming wire transfers to this account`} + /> + <InputSelector + name="auth.type" + label={i18n.str`Auth type`} + tooltip={i18n.str`Choose the authentication type for the account info URL`} + values={accountAuthType} + toStr={(str) => { + // if (str === "unset") { + // return "Without change"; + // } + if (str === "none") return "Without authentication"; + return "Username and password"; + }} + /> + {value.auth?.type === "basic" ? ( + <Fragment> + <Input + name="auth.username" + label={i18n.str`Username`} + tooltip={i18n.str`Username to access the account information.`} + /> + <Input + name="auth.password" + inputType="password" + label={i18n.str`Password`} + tooltip={i18n.str`Password to access the account information.`} + /> + <Input + name="auth.repeat" + inputType="password" + label={i18n.str`Repeat password`} + /> + </Fragment> + ) : undefined} + {/* <InputWithAddon + name="options.credit_credentials" + label={i18n.str`Account info`} + inputType={showKey ? "text" : "password"} + help="From where the merchant can download information about incoming wire transfers to this account" + expand + tooltip={i18n.str`Useful to validate the purchase`} + fromStr={(v) => v.toUpperCase()} + addonAfter={ + <span class="icon"> + {showKey ? ( + <i class="mdi mdi-eye" /> + ) : ( + <i class="mdi mdi-eye-off" /> + )} + </span> + } + side={ + <span style={{ display: "flex" }}> + <button + data-tooltip={ + showKey + ? i18n.str`show secret key` + : i18n.str`hide secret key` + } + class="button is-info mr-3" + onClick={(e) => { + setShowKey(!showKey); + }} + > + {showKey ? ( + <i18n.Translate>hide</i18n.Translate> + ) : ( + <i18n.Translate>show</i18n.Translate> + )} + </button> + </span> + } + /> */} + </Fragment> + )} + {/** + * Show the values in the list + */} <div class="field is-horizontal"> <div class="field-label is-normal" /> <div class="field-body" style={{ display: "block" }}> - {paytos.map((v: any, i: number) => ( - <div - key={i} - class="tags has-addons mt-3 mb-0 mr-3" - style={{ flexWrap: "nowrap" }} - > - <span - class="tag is-medium is-info mb-0" - style={{ maxWidth: "90%" }} + {paytos.map( + (v: MerchantBackend.Instances.MerchantBankAccount, i: number) => ( + <div + key={i} + class="tags has-addons mt-3 mb-0 mr-3" + style={{ flexWrap: "nowrap" }} > - {v} - </span> - <a - class="tag is-medium is-danger is-delete mb-0" - onClick={() => { - onChange(paytos.filter((f: any) => f !== v) as any); - }} - /> - </div> - ))} + <span + class="tag is-medium is-info mb-0" + style={{ maxWidth: "90%" }} + > + {v.payto_uri} + </span> + <a + class="tag is-medium is-danger is-delete mb-0" + onClick={() => { + onChange(paytos.filter((f: any) => f !== v) as any); + }} + /> + </div> + ), + )} {!paytos.length && i18n.str`No accounts yet.`} {required && ( <span class="icon has-text-danger is-right"> diff --git a/packages/merchant-backoffice-ui/src/components/index.stories.ts b/packages/merchant-backoffice-ui/src/components/index.stories.ts new file mode 100644 index 000000000..c57ddab14 --- /dev/null +++ b/packages/merchant-backoffice-ui/src/components/index.stories.ts @@ -0,0 +1,17 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +export * as payto from "./form/InputPaytoForm.stories.js"; diff --git a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx index 3a3bdd6f3..bbdc9708a 100644 --- a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx +++ b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx @@ -86,7 +86,7 @@ export function DefaultInstanceFormFields({ /> <InputPaytoForm<Entity> - name="payto_uris" + name="accounts" label={i18n.str`Bank account`} tooltip={i18n.str`URI specifying bank account for crediting revenue.`} /> |