/* This file is part of GNU Taler (C) 2021-2024 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ /** * * @author Sebastian Javier Marchano (sebasjm) */ import { Duration, TalerMerchantApi, createRFC8959AccessTokenPlain, } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { AsyncButton } from "../../../components/exception/AsyncButton.js"; import { FormErrors, FormProvider, } from "../../../components/form/FormProvider.js"; import { Input } from "../../../components/form/Input.js"; import { DefaultInstanceFormFields } from "../../../components/instance/DefaultInstanceFormFields.js"; import { usePreference } from "../../../hooks/preference.js"; import { INSTANCE_ID_REGEX } from "../../../utils/constants.js"; import { undefinedIfEmpty } from "../../../utils/table.js"; import { InputToggle } from "../../../components/form/InputToggle.js"; export type Entity = TalerMerchantApi.InstanceConfigurationMessage & { auth_token?: string; // default_pay_delay: Duration; // default_wire_transfer_delay: Duration; }; interface Props { onCreate: (d: TalerMerchantApi.InstanceConfigurationMessage) => Promise; onBack?: () => void; forceId?: string; } const twoHours = Duration.fromSpec({ hours: 2 }); const twoDays = Duration.fromSpec({ days: 2 }); function with_defaults(id?: string): Partial { return { id, user_type: "business", use_stefan: true, default_pay_delay: Duration.toTalerProtocolDuration(twoHours), default_wire_transfer_delay: Duration.toTalerProtocolDuration(twoDays), }; } type TokenForm = { accessControl: boolean; token: string; repeat: string }; export function CreatePage({ onCreate, onBack, forceId }: Props): VNode { const [pref, updatePref] = usePreference(); const { i18n } = useTranslationContext(); const [value, valueHandler] = useState(with_defaults(forceId)); const [tokenForm, setTokenForm] = useState>({}); const errors = undefinedIfEmpty>({ id: !value.id ? i18n.str`Required` : !INSTANCE_ID_REGEX.test(value.id) ? i18n.str`Invalid` : undefined, name: !value.name ? i18n.str`Required` : undefined, user_type: !value.user_type ? i18n.str`Required` : value.user_type !== "business" && value.user_type !== "individual" ? i18n.str`Must be business or individual` : undefined, // accounts: // !value.accounts || !value.accounts.length // ? i18n.str`Required` // : undefinedIfEmpty( // value.accounts.map((p) => { // return !PAYTO_REGEX.test(p.payto_uri) // ? i18n.str`Invalid` // : undefined; // }), // ), default_pay_delay: !value.default_pay_delay ? i18n.str`Required` : value.default_wire_transfer_delay !== undefined && value.default_wire_transfer_delay.d_us !== "forever" && value.default_pay_delay.d_us !== "forever" && value.default_pay_delay.d_us > value.default_wire_transfer_delay.d_us ? i18n.str`Pay delay can't be greater than wire transfer delay` : undefined, default_wire_transfer_delay: !value.default_wire_transfer_delay ? i18n.str`Required` : undefined, address: undefinedIfEmpty({ address_lines: value.address?.address_lines && value.address?.address_lines.length > 7 ? i18n.str`Max 7 lines` : undefined, }), jurisdiction: undefinedIfEmpty({ address_lines: value.address?.address_lines && value.address?.address_lines.length > 7 ? i18n.str`Max 7 lines` : undefined, }), }); const hasErrors = errors !== undefined; const tokenFormErrors = undefinedIfEmpty>({ token: tokenForm.accessControl === false ? undefined : !tokenForm.token ? i18n.str`Required` : undefined, repeat: tokenForm.accessControl === false ? undefined : !tokenForm.repeat ? i18n.str`Required` : tokenForm.repeat !== tokenForm.token ? i18n.str`Doesn't match` : undefined, }); const hasTokenErrors = tokenFormErrors === undefined; const submit = (): Promise => { // use conversion instead of this const newValue = structuredClone(value); const accessControl = !!tokenForm.accessControl; newValue.auth_token = undefined; newValue.auth = !accessControl ? { method: "external" } : { method: "token", token: createRFC8959AccessTokenPlain(tokenForm.token!), }; if (!newValue.address) newValue.address = {}; if (!newValue.jurisdiction) newValue.jurisdiction = {}; return onCreate(newValue as TalerMerchantApi.InstanceConfigurationMessage); }; return (
  • { updatePref("advanceInstanceMode", false); }} > Simple
  • { updatePref("advanceInstanceMode", true); }} > Advanced
{" "}
errors={errors} object={value} valueHandler={valueHandler} > name="accessControl" threeState={tokenForm.accessControl === undefined} label={i18n.str`Enable access control`} help={i18n.str`Choose if the backend server should authenticate access.`} /> name="token" label={i18n.str`New access token`} tooltip={i18n.str`Next access token to be used`} readonly={ tokenForm.accessControl === false || tokenForm.accessControl === undefined } inputType="password" /> name="repeat" label={i18n.str`Repeat access token`} tooltip={i18n.str`Confirm the same access token`} readonly={ tokenForm.accessControl === false || tokenForm.accessControl === undefined } inputType="password" />
{tokenForm.accessControl === undefined ? (

Access control is not yet decided. This instance can't be created.

) : !tokenForm.accessControl ? (

Authorization must be handled externally.

) : (

Authorization is handled by the backend server.

)}
{onBack && ( )} Confirm
); }