summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-01-08 14:24:07 -0300
committerSebastian <sebasjm@gmail.com>2024-01-08 14:24:20 -0300
commitb0610d24571593909cd6683b340fa266de046e31 (patch)
tree691abc2d9228735eb0a25526eab628168fa8d5a0
parent35cbcce79e22d7c3cd9ac1c676ad9b3480bd3fe1 (diff)
downloadwallet-core-b0610d24571593909cd6683b340fa266de046e31.tar.gz
wallet-core-b0610d24571593909cd6683b340fa266de046e31.tar.bz2
wallet-core-b0610d24571593909cd6683b340fa266de046e31.zip
order config using relative time
-rw-r--r--packages/merchant-backoffice-ui/src/components/form/InputDuration.tsx126
-rw-r--r--packages/merchant-backoffice-ui/src/components/picker/DurationPicker.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/declaration.d.ts7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx116
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx178
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx73
6 files changed, 240 insertions, 262 deletions
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputDuration.tsx b/packages/merchant-backoffice-ui/src/components/form/InputDuration.tsx
index ef4df1df4..8b6b5636d 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputDuration.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputDuration.tsx
@@ -20,16 +20,19 @@
*/
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { formatDuration, intervalToDuration } from "date-fns";
-import { h, VNode } from "preact";
+import { ComponentChildren, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { SimpleModal } from "../modal/index.js";
import { DurationPicker } from "../picker/DurationPicker.js";
import { InputProps, useField } from "./useField.js";
+import { Duration } from "@gnu-taler/taler-util";
export interface Props<T> extends InputProps<T> {
expand?: boolean;
readonly?: boolean;
withForever?: boolean;
+ side?: ComponentChildren;
+ withoutClear?: boolean;
}
export function InputDuration<T>({
@@ -41,19 +44,22 @@ export function InputDuration<T>({
help,
readonly,
withForever,
+ withoutClear,
+ side,
}: Props<keyof T>): VNode {
const [opened, setOpened] = useState(false);
const { i18n } = useTranslationContext();
- const { error, required, value, onChange } = useField<T>(name);
+ const { error, required, value: anyValue, onChange } = useField<T>(name);
let strValue = "";
+ const value: Duration = anyValue
if (!value) {
strValue = "";
- } else if (value.d_us === "forever") {
+ } else if (value.d_ms === "forever") {
strValue = i18n.str`forever`;
} else {
strValue = formatDuration(
- intervalToDuration({ start: 0, end: value.d_us / 1000 }),
+ intervalToDuration({ start: 0, end: value.d_ms }),
{
locale: {
formatDistance: (name, value) => {
@@ -97,72 +103,80 @@ export function InputDuration<T>({
)}
</label>
</div>
- <div class="field-body is-flex-grow-3">
- <div class="field">
- <div class="field has-addons">
- <p class={expand ? "control is-expanded " : "control "}>
- <input
- class="input"
- type="text"
- readonly
- value={strValue}
- placeholder={placeholder}
+
+ <div>
+ <div class="field-body is-flex-grow-3">
+ <div class="field">
+ <div class="field has-addons">
+ <p class={expand ? "control is-expanded " : "control "}>
+ <input
+ class="input"
+ type="text"
+ readonly
+ value={strValue}
+ placeholder={placeholder}
+ onClick={() => {
+ if (!readonly) setOpened(true);
+ }}
+ />
+ {required && (
+ <span class="icon has-text-danger is-right">
+ <i class="mdi mdi-alert" />
+ </span>
+ )}
+ </p>
+ <div
+ class="control"
onClick={() => {
if (!readonly) setOpened(true);
}}
- />
- {required && (
- <span class="icon has-text-danger is-right">
- <i class="mdi mdi-alert" />
- </span>
- )}
- {help}
- </p>
- <div
- class="control"
- onClick={() => {
- if (!readonly) setOpened(true);
- }}
- >
- <a class="button is-static">
- <span class="icon">
- <i class="mdi mdi-clock" />
- </span>
- </a>
+ >
+ <a class="button is-static">
+ <span class="icon">
+ <i class="mdi mdi-clock" />
+ </span>
+ </a>
+ </div>
</div>
+ {error && <p class="help is-danger">{error}</p>}
</div>
- {error && <p class="help is-danger">{error}</p>}
+ {withForever && (
+ <span data-tooltip={i18n.str`change value to never`}>
+ <button
+ class="button is-info mr-3"
+ onClick={() => onChange({ d_ms: "forever" } as any)}
+ >
+ <i18n.Translate>forever</i18n.Translate>
+ </button>
+ </span>
+ )}
+ {!readonly && !withoutClear && (
+ <span data-tooltip={i18n.str`change value to empty`}>
+ <button
+ class="button is-info "
+ onClick={() => onChange(undefined as any)}
+ >
+ <i18n.Translate>clear</i18n.Translate>
+ </button>
+ </span>
+ )}
+ {side}
</div>
- {withForever && (
- <span data-tooltip={i18n.str`change value to never`}>
- <button
- class="button is-info mr-3"
- onClick={() => onChange({ d_us: "forever" } as any)}
- >
- <i18n.Translate>forever</i18n.Translate>
- </button>
- </span>
- )}
- {!readonly && (
- <span data-tooltip={i18n.str`change value to empty`}>
- <button
- class="button is-info "
- onClick={() => onChange(undefined as any)}
- >
- <i18n.Translate>clear</i18n.Translate>
- </button>
- </span>
- )}
+ <span>
+ {help}
+ </span>
</div>
+
+
{opened && (
<SimpleModal onCancel={() => setOpened(false)}>
<DurationPicker
days
hours
minutes
- value={!value || value.d_us === "forever" ? 0 : value.d_us}
+ value={!value || value.d_ms === "forever" ? 0 : value.d_ms}
onChange={(v) => {
- onChange({ d_us: v } as any);
+ onChange({ d_ms: v } as any);
}}
/>
</SimpleModal>
diff --git a/packages/merchant-backoffice-ui/src/components/picker/DurationPicker.tsx b/packages/merchant-backoffice-ui/src/components/picker/DurationPicker.tsx
index 0968b0a17..ba003cce5 100644
--- a/packages/merchant-backoffice-ui/src/components/picker/DurationPicker.tsx
+++ b/packages/merchant-backoffice-ui/src/components/picker/DurationPicker.tsx
@@ -42,7 +42,7 @@ export function DurationPicker({
onChange,
value,
}: Props): VNode {
- const ss = 1000 * 1000;
+ const ss = 1000;
const ms = ss * 60;
const hs = ms * 60;
const ds = hs * 24;
diff --git a/packages/merchant-backoffice-ui/src/declaration.d.ts b/packages/merchant-backoffice-ui/src/declaration.d.ts
index dc53e3e83..f99dd1867 100644
--- a/packages/merchant-backoffice-ui/src/declaration.d.ts
+++ b/packages/merchant-backoffice-ui/src/declaration.d.ts
@@ -23,7 +23,7 @@ type HashCode = string;
type EddsaPublicKey = string;
type EddsaSignature = string;
type WireTransferIdentifierRawP = string;
-type RelativeTime = Duration;
+type RelativeTime = TalerProtocolDuration;
type ImageDataUrl = string;
type MerchantUserType = "business" | "individual";
@@ -38,9 +38,12 @@ interface Timestamp {
// never happen.
t_s: number | "never";
}
-interface Duration {
+interface TalerProtocolDuration {
d_us: number | "forever";
}
+interface Duration {
+ d_ms: number | "forever";
+}
interface WithId {
id: string;
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
index 093c24c3d..d13b7e929 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
@@ -32,13 +32,16 @@ import { MerchantBackend } from "../../../declaration.js";
import { INSTANCE_ID_REGEX } from "../../../utils/constants.js";
import { undefinedIfEmpty } from "../../../utils/table.js";
import { SetTokenNewInstanceModal } from "../../../components/modal/index.js";
+import { Duration } from "@gnu-taler/taler-util";
-export type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & {
+export type Entity = Omit<Omit<MerchantBackend.Instances.InstanceConfigurationMessage, "default_pay_delay">, "default_wire_transfer_delay"> & {
auth_token?: string;
+ default_pay_delay: Duration,
+ default_wire_transfer_delay: Duration,
};
interface Props {
- onCreate: (d: Entity) => Promise<void>;
+ onCreate: (d: MerchantBackend.Instances.InstanceConfigurationMessage) => Promise<void>;
onBack?: () => void;
forceId?: string;
}
@@ -49,8 +52,8 @@ function with_defaults(id?: string): Partial<Entity> {
// accounts: [],
user_type: "business",
use_stefan: true,
- default_pay_delay: { d_us: 2 * 1000 * 60 * 60 * 1000 }, // two hours
- default_wire_transfer_delay: { d_us: 1000 * 2 * 60 * 60 * 24 * 1000 }, // two days
+ default_pay_delay: { d_ms: 2 * 60 * 60 * 1000 }, // two hours
+ default_wire_transfer_delay: { d_ms: 2 * 60 * 60 * 24 * 1000 }, // two days
};
}
@@ -88,9 +91,9 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
default_pay_delay: !value.default_pay_delay
? i18n.str`required`
: !!value.default_wire_transfer_delay &&
- 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 ?
+ value.default_wire_transfer_delay.d_ms !== "forever" &&
+ value.default_pay_delay.d_ms !== "forever" &&
+ value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms ?
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`
@@ -124,7 +127,12 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
if (!value.jurisdiction) value.jurisdiction = {};
// remove above use conversion
// schema.validateSync(value, { abortEarly: false })
- return onCreate(value as Entity);
+ value.default_pay_delay = Duration.toTalerProtocolDuration(value.default_pay_delay!) as any
+ value.default_wire_transfer_delay = Duration.toTalerProtocolDuration(value.default_wire_transfer_delay!) as any
+ // delete value.default_pay_delay;
+ // delete value.default_wire_transfer_delay;
+
+ return onCreate(value as any as MerchantBackend.Instances.InstanceConfigurationMessage);
};
function updateToken(token: string | null) {
@@ -174,54 +182,54 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
</FormProvider>
<div class="level">
- <div class="level-item has-text-centered">
- <h1 class="title">
- <button
- class={
- !isTokenSet
- ? "button is-danger has-tooltip-bottom"
- : !value.auth_token
- ? "button has-tooltip-bottom"
- : "button is-info has-tooltip-bottom"
- }
- data-tooltip={i18n.str`change authorization configuration`}
- onClick={() => updateIsTokenDialogActive(true)}
- >
- <div class="icon is-centered">
- <i class="mdi mdi-lock-reset" />
- </div>
- <span>
- <i18n.Translate>Set access token</i18n.Translate>
- </span>
- </button>
- </h1>
+ <div class="level-item has-text-centered">
+ <h1 class="title">
+ <button
+ class={
+ !isTokenSet
+ ? "button is-danger has-tooltip-bottom"
+ : !value.auth_token
+ ? "button has-tooltip-bottom"
+ : "button is-info has-tooltip-bottom"
+ }
+ data-tooltip={i18n.str`change authorization configuration`}
+ onClick={() => updateIsTokenDialogActive(true)}
+ >
+ <div class="icon is-centered">
+ <i class="mdi mdi-lock-reset" />
+ </div>
+ <span>
+ <i18n.Translate>Set access token</i18n.Translate>
+ </span>
+ </button>
+ </h1>
+ </div>
</div>
- </div>
- <div class="level">
- <div class="level-item has-text-centered">
- {!isTokenSet ? (
- <p class="is-size-6">
- <i18n.Translate>
- Access token is not yet configured. This instance can't be
- created.
- </i18n.Translate>
- </p>
- ) : value.auth_token === undefined ? (
- <p class="is-size-6">
- <i18n.Translate>
- No access token. Authorization must be handled externally.
- </i18n.Translate>
- </p>
- ) : (
- <p class="is-size-6">
- <i18n.Translate>
- Access token is set. Authorization is handled by the
- merchant backend.
- </i18n.Translate>
- </p>
- )}
+ <div class="level">
+ <div class="level-item has-text-centered">
+ {!isTokenSet ? (
+ <p class="is-size-6">
+ <i18n.Translate>
+ Access token is not yet configured. This instance can't be
+ created.
+ </i18n.Translate>
+ </p>
+ ) : value.auth_token === undefined ? (
+ <p class="is-size-6">
+ <i18n.Translate>
+ No access token. Authorization must be handled externally.
+ </i18n.Translate>
+ </p>
+ ) : (
+ <p class="is-size-6">
+ <i18n.Translate>
+ Access token is set. Authorization is handled by the
+ merchant backend.
+ </i18n.Translate>
+ </p>
+ )}
+ </div>
</div>
- </div>
<div class="buttons is-right mt-5">
{onBack && (
<button class="button" onClick={onBack}>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
index 2b1741276..a30f79169 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
@@ -19,32 +19,32 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Amounts } from "@gnu-taler/taler-util";
+import { AbsoluteTime, Amounts, Duration, TalerProtocolDuration } from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { add, isAfter, isBefore, isFuture } from "date-fns";
-import { Fragment, h, VNode } from "preact";
+import { format, isFuture } from "date-fns";
+import { Fragment, VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import {
FormErrors,
FormProvider,
} from "../../../../components/form/FormProvider.js";
import { Input } from "../../../../components/form/Input.js";
-import { InputBoolean } from "../../../../components/form/InputBoolean.js";
import { InputCurrency } from "../../../../components/form/InputCurrency.js";
import { InputDate } from "../../../../components/form/InputDate.js";
+import { InputDuration } from "../../../../components/form/InputDuration.js";
import { InputGroup } from "../../../../components/form/InputGroup.js";
import { InputLocation } from "../../../../components/form/InputLocation.js";
import { InputNumber } from "../../../../components/form/InputNumber.js";
+import { InputToggle } from "../../../../components/form/InputToggle.js";
import { InventoryProductForm } from "../../../../components/product/InventoryProductForm.js";
import { NonInventoryProductFrom } from "../../../../components/product/NonInventoryProductForm.js";
import { ProductList } from "../../../../components/product/ProductList.js";
import { useConfigContext } from "../../../../context/config.js";
-import { Duration, MerchantBackend, WithId } from "../../../../declaration.js";
+import { MerchantBackend, WithId } from "../../../../declaration.js";
+import { useSettings } from "../../../../hooks/useSettings.js";
import { OrderCreateSchema as schema } from "../../../../schemas/index.js";
import { rate } from "../../../../utils/amount.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";
-import { useSettings } from "../../../../hooks/useSettings.js";
-import { InputToggle } from "../../../../components/form/InputToggle.js";
interface Props {
onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void;
@@ -54,23 +54,13 @@ interface Props {
}
interface InstanceConfig {
use_stefan: boolean;
- default_pay_delay: Duration;
- default_wire_transfer_delay: Duration;
+ default_pay_delay: TalerProtocolDuration;
+ default_wire_transfer_delay: TalerProtocolDuration;
}
function with_defaults(config: InstanceConfig, currency: string): Partial<Entity> {
- const defaultPayDeadline =
- !config.default_pay_delay || config.default_pay_delay.d_us === "forever"
- ? undefined
- : add(new Date(), {
- seconds: config.default_pay_delay.d_us / (1000 * 1000),
- });
- const defaultWireDeadline =
- !config.default_wire_transfer_delay || config.default_wire_transfer_delay.d_us === "forever"
- ? undefined
- : add(new Date(), {
- seconds: config.default_wire_transfer_delay.d_us / (1000 * 1000),
- });
+ const defaultPayDeadline = Duration.fromTalerProtocolDuration(config.default_pay_delay);
+ const defaultWireDeadline = Duration.fromTalerProtocolDuration(config.default_wire_transfer_delay);
return {
inventoryProducts: {},
@@ -78,10 +68,10 @@ function with_defaults(config: InstanceConfig, currency: string): Partial<Entity
pricing: {},
payments: {
max_fee: undefined,
- pay_deadline: defaultPayDeadline,
- refund_deadline: defaultPayDeadline,
createToken: true,
- wire_transfer_deadline: defaultWireDeadline,
+ pay_deadline: (defaultPayDeadline),
+ refund_deadline: (defaultPayDeadline),
+ wire_transfer_deadline: (defaultWireDeadline),
},
shipping: {},
extra: {},
@@ -107,10 +97,10 @@ interface Shipping {
fullfilment_url?: string;
}
interface Payments {
- refund_deadline?: Date;
- pay_deadline?: Date;
- wire_transfer_deadline?: Date;
- auto_refund_deadline?: Date;
+ refund_deadline: Duration;
+ pay_deadline: Duration;
+ wire_transfer_deadline: Duration;
+ auto_refund_deadline: Duration;
max_fee?: string;
createToken: boolean;
minimum_age?: number;
@@ -164,53 +154,41 @@ export function CreatePage({
? i18n.str`must be greater than 0`
: undefined,
}),
- // extra:
- // value.extra && !stringIsValidJSON(value.extra)
- // ? i18n.str`not a valid json`
- // : undefined,
payments: undefinedIfEmpty({
refund_deadline: !value.payments?.refund_deadline
? undefined
- : !isFuture(value.payments.refund_deadline)
- ? i18n.str`should be in the future`
- : value.payments.pay_deadline &&
- isBefore(value.payments.refund_deadline, value.payments.pay_deadline)
- ? i18n.str`refund deadline cannot be before pay deadline`
- : value.payments.wire_transfer_deadline &&
- isBefore(
- value.payments.wire_transfer_deadline,
- value.payments.refund_deadline,
- )
- ? i18n.str`wire transfer deadline cannot be before refund deadline`
- : undefined,
- pay_deadline: !value.payments?.pay_deadline
- ? i18n.str`required`
- : !isFuture(value.payments.pay_deadline)
- ? i18n.str`should be in the future`
+ : value.payments.pay_deadline &&
+ Duration.cmp(value.payments.refund_deadline, value.payments.pay_deadline) === -1
+ ? i18n.str`refund deadline cannot be before pay deadline`
: value.payments.wire_transfer_deadline &&
- isBefore(
+ Duration.cmp(
value.payments.wire_transfer_deadline,
- value.payments.pay_deadline,
- )
- ? i18n.str`wire transfer deadline cannot be before pay deadline`
+ value.payments.refund_deadline,
+ ) === -1
+ ? i18n.str`wire transfer deadline cannot be before refund deadline`
: undefined,
- wire_transfer_deadline: !value.payments?.wire_transfer_deadline
+ pay_deadline: !value.payments?.pay_deadline
? i18n.str`required`
- : !isFuture(value.payments.wire_transfer_deadline)
- ? i18n.str`should be in the future`
+ : value.payments.wire_transfer_deadline &&
+ Duration.cmp(
+ value.payments.wire_transfer_deadline,
+ value.payments.pay_deadline,
+ ) === -1
+ ? i18n.str`wire transfer deadline cannot be before pay deadline`
: undefined,
+ wire_transfer_deadline: !value.payments?.wire_transfer_deadline
+ ? i18n.str`required`
+ : undefined,
auto_refund_deadline: !value.payments?.auto_refund_deadline
? undefined
- : !isFuture(value.payments.auto_refund_deadline)
- ? i18n.str`should be in the future`
- : !value.payments?.refund_deadline
- ? i18n.str`should have a refund deadline`
- : !isAfter(
- value.payments.refund_deadline,
- value.payments.auto_refund_deadline,
- )
- ? i18n.str`auto refund cannot be after refund deadline`
- : undefined,
+ : !value.payments?.refund_deadline
+ ? i18n.str`should have a refund deadline`
+ : Duration.cmp(
+ value.payments.refund_deadline,
+ value.payments.auto_refund_deadline,
+ ) == -1
+ ? i18n.str`auto refund cannot be after refund deadline`
+ : undefined,
}),
shipping: undefinedIfEmpty({
@@ -226,7 +204,7 @@ export function CreatePage({
);
const submit = (): void => {
- const order = schema.cast(value);
+ const order = value as any; //schema.cast(value);
if (!value.payments) return;
if (!value.shipping) return;
@@ -236,29 +214,18 @@ export function CreatePage({
summary: order.pricing.summary,
products: productList,
extra: undefinedIfEmpty(value.extra),
- pay_deadline: value.payments.pay_deadline
- ? {
- t_s: Math.floor(value.payments.pay_deadline.getTime() / 1000),
- }
- : undefined,
+ pay_deadline: !value.payments.pay_deadline ?
+ i18n.str`required` :
+ AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.pay_deadline))
+ ,// : undefined,
wire_transfer_deadline: value.payments.wire_transfer_deadline
- ? {
- t_s: Math.floor(
- value.payments.wire_transfer_deadline.getTime() / 1000,
- ),
- }
+ ? AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.wire_transfer_deadline))
: undefined,
refund_deadline: value.payments.refund_deadline
- ? {
- t_s: Math.floor(value.payments.refund_deadline.getTime() / 1000),
- }
+ ? AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.refund_deadline))
: undefined,
auto_refund: value.payments.auto_refund_deadline
- ? {
- d_us: Math.floor(
- value.payments.auto_refund_deadline.getTime() * 1000,
- ),
- }
+ ? Duration.toTalerProtocolDuration(value.payments.auto_refund_deadline)
: undefined,
max_fee: value.payments.max_fee as string,
@@ -360,10 +327,18 @@ export function CreatePage({
0,
);
+ // if there is no default pay deadline
const noDefault_payDeadline = !instance_default.payments || !instance_default.payments.pay_deadline
+ // and there is no defailt wire deadline
const noDefault_wireDeadline = !instance_default.payments || !instance_default.payments.wire_transfer_deadline
+ // user required to set the taler options
const requiresSomeTalerOptions = noDefault_payDeadline || noDefault_wireDeadline
+ const whenPay = !value.payments?.pay_deadline ? undefined : AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.pay_deadline)
+ const whenRefund = !value.payments?.refund_deadline ? undefined : AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.refund_deadline)
+ const whenWire = !value.payments?.wire_transfer_deadline ? undefined : AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.wire_transfer_deadline)
+ const whenAutoRefund = !value.payments?.auto_refund_deadline ? undefined : AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.auto_refund_deadline)
+
return (
<div>
@@ -522,10 +497,13 @@ export function CreatePage({
label={i18n.str`Taler payment options`}
tooltip={i18n.str`Override default Taler payment settings for this order`}
>
- {(settings.advanceOrderMode || noDefault_payDeadline) && <InputDate
+ {(settings.advanceOrderMode || noDefault_payDeadline) && <InputDuration
name="payments.pay_deadline"
- label={i18n.str`Payment deadline`}
- tooltip={i18n.str`Deadline for the customer to pay for the offer before it expires. Inventory products will be reserved until this deadline.`}
+ label={i18n.str`Payment time`}
+ help={whenPay && whenPay.t_ms !== "never" ? i18n.str`Deadline at ${format(whenPay.t_ms, "dd/MM/yy HH:mm")}` : i18n.str`Without deadline`}
+ withForever
+ withoutClear
+ tooltip={i18n.str`Time for the customer to pay for the offer before it expires. Inventory products will be reserved until this deadline. Time start to run after the order is created.`}
side={
<span>
<button class="button" onClick={() => {
@@ -543,10 +521,13 @@ export function CreatePage({
</span>
}
/>}
- {settings.advanceOrderMode && <InputDate
+ {settings.advanceOrderMode && <InputDuration
name="payments.refund_deadline"
- label={i18n.str`Refund deadline`}
- tooltip={i18n.str`Time until which the order can be refunded by the merchant.`}
+ label={i18n.str`Refund time`}
+ help={whenRefund && whenRefund.t_ms !== "never" ? i18n.str`Deadline at ${format(whenRefund.t_ms, "dd/MM/yy HH:mm")}` : i18n.str`Without deadline`}
+ withForever
+ withoutClear
+ tooltip={i18n.str`Time while the order can be refunded by the merchant. Time starts after the order is created.`}
side={
<span>
<button class="button" onClick={() => {
@@ -563,10 +544,13 @@ export function CreatePage({
</span>
}
/>}
- {(settings.advanceOrderMode || noDefault_wireDeadline) && <InputDate
+ {(settings.advanceOrderMode || noDefault_wireDeadline) && <InputDuration
name="payments.wire_transfer_deadline"
- label={i18n.str`Wire transfer deadline`}
- tooltip={i18n.str`Deadline for the exchange to make the wire transfer.`}
+ label={i18n.str`Wire transfer time`}
+ help={whenWire && whenWire.t_ms !== "never" ? i18n.str`Deadline at ${format(whenWire.t_ms, "dd/MM/yy HH:mm")}` : i18n.str`Without deadline`}
+ withoutClear
+ withForever
+ tooltip={i18n.str`Time for the exchange to make the wire transfer. Time starts after the order is created.`}
side={
<span>
<button class="button" onClick={() => {
@@ -583,10 +567,12 @@ export function CreatePage({
</span>
}
/>}
- {settings.advanceOrderMode && <InputDate
+ {settings.advanceOrderMode && <InputDuration
name="payments.auto_refund_deadline"
- label={i18n.str`Auto-refund deadline`}
+ label={i18n.str`Auto-refund interval`}
+ help={whenAutoRefund && whenAutoRefund.t_ms !== "never" ? i18n.str`Deadline at ${format(whenAutoRefund.t_ms, "dd/MM/yy HH:mm")}` : i18n.str`Without deadline`}
tooltip={i18n.str`Time until which the wallet will automatically check for refunds without user interaction.`}
+ withForever
/>}
{settings.advanceOrderMode && <InputCurrency
@@ -703,3 +689,5 @@ function asProduct(p: ProductAndQuantity): MerchantBackend.Product {
minimum_age: p.product.minimum_age,
};
}
+
+
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx
index 5b88b550f..a27a0cb06 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx
@@ -31,14 +31,16 @@ import { DefaultInstanceFormFields } from "../../../components/instance/DefaultI
import { useInstanceContext } from "../../../context/instance.js";
import { MerchantBackend } from "../../../declaration.js";
import { undefinedIfEmpty } from "../../../utils/table.js";
+import { Duration } from "@gnu-taler/taler-util";
-type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage & {
- auth_token?: string;
+export type Entity = Omit<Omit<MerchantBackend.Instances.InstanceReconfigurationMessage, "default_pay_delay">, "default_wire_transfer_delay"> & {
+ default_pay_delay: Duration,
+ default_wire_transfer_delay: Duration,
};
//MerchantBackend.Instances.InstanceAuthConfigurationMessage
interface Props {
- onUpdate: (d: Entity) => void;
+ onUpdate: (d: MerchantBackend.Instances.InstanceReconfigurationMessage) => void;
selected: MerchantBackend.Instances.QueryInstancesResponse;
isLoading: boolean;
onBack: () => void;
@@ -47,21 +49,12 @@ interface Props {
function convert(
from: MerchantBackend.Instances.QueryInstancesResponse,
): Entity {
- const { ...rest } = from;
- // const accounts = qAccounts
- // .filter((a) => a.active)
- // .map(
- // (a) =>
- // ({
- // payto_uri: a.payto_uri,
- // credit_facade_url: a.credit_facade_url,
- // credit_facade_credentials: a.credit_facade_credentials,
- // } as MerchantBackend.Instances.MerchantBankAccount),
- // );
+ const { default_pay_delay, default_wire_transfer_delay, ...rest } = from;
+
const defaults = {
use_stefan: false,
- default_pay_delay: { d_us: 2 * 1000 * 1000 * 60 * 60 }, //two hours
- default_wire_transfer_delay: { d_us: 2 * 1000 * 1000 * 60 * 60 * 2 }, //two hours
+ default_pay_delay: Duration.fromTalerProtocolDuration(default_pay_delay),
+ default_wire_transfer_delay: Duration.fromTalerProtocolDuration(default_wire_transfer_delay),
};
return { ...defaults, ...rest };
}
@@ -72,20 +65,6 @@ export function UpdatePage({
onBack,
}: Props): VNode {
const { id } = useInstanceContext();
- // const currentTokenValue = getTokenValuePart(token);
-
- // function updateToken(token: string | undefined | null) {
- // const value =
- // token && token.startsWith("secret-token:")
- // ? token.substring("secret-token:".length)
- // : token;
-
- // if (!token) {
- // onChangeAuth({ method: "external" });
- // } else {
- // onChangeAuth({ method: "token", token: `secret-token:${value}` });
- // }
- // }
const [value, valueHandler] = useState<Partial<Entity>>(convert(selected));
@@ -101,9 +80,9 @@ export function UpdatePage({
default_pay_delay: !value.default_pay_delay
? i18n.str`required`
: !!value.default_wire_transfer_delay &&
- 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 ?
+ value.default_wire_transfer_delay.d_ms !== "forever" &&
+ value.default_pay_delay.d_ms !== "forever" &&
+ value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms ?
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`
@@ -127,7 +106,13 @@ export function UpdatePage({
);
const submit = async (): Promise<void> => {
- await onUpdate(value as Entity);
+ const { default_pay_delay, default_wire_transfer_delay, ...rest } = value as Required<Entity>;
+ const result: MerchantBackend.Instances.InstanceReconfigurationMessage = {
+ default_pay_delay: Duration.toTalerProtocolDuration(default_pay_delay),
+ default_wire_transfer_delay: Duration.toTalerProtocolDuration(default_wire_transfer_delay),
+ ...rest,
+ }
+ await onUpdate(result);
};
// const [active, setActive] = useState(false);
@@ -144,26 +129,6 @@ export function UpdatePage({
</span>
</div>
</div>
- {/* <div class="level-right">
- <div class="level-item">
- <h1 class="title">
- <button
- class="button is-danger"
- data-tooltip={i18n.str`Change the authorization method use for this instance.`}
- onClick={(): void => {
- setActive(!active);
- }}
- >
- <div class="icon is-left">
- <i class="mdi mdi-lock-reset" />
- </div>
- <span>
- <i18n.Translate>Manage access token</i18n.Translate>
- </span>
- </button>
- </h1>
- </div>
- </div> */}
</div>
</div>
</section>