aboutsummaryrefslogtreecommitdiff
path: root/packages/merchant-backoffice-ui/src/paths/instance
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-08-15 13:47:29 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-08-15 13:47:29 +0200
commit819949d7f2cfcce8d334cbfdb701255daac64951 (patch)
tree592043554f59ec209f9afc1c31c20c4fb585c3ca /packages/merchant-backoffice-ui/src/paths/instance
parent77ea209ddb6d457db0ce113f91247207cc29fbd8 (diff)
parentadb0e70f151e63d103f27852312319520f4d0a84 (diff)
Merge branch 'master' into age-withdraw
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/instance')
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx309
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx31
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/details/Timeline.tsx20
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx4
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx38
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx40
6 files changed, 225 insertions, 217 deletions
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 c8cc20ae0..fa9347c6e 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
@@ -43,6 +43,7 @@ import { Duration, MerchantBackend, WithId } from "../../../../declaration.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";
interface Props {
onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void;
@@ -62,8 +63,8 @@ function with_defaults(config: InstanceConfig): Partial<Entity> {
!config.default_pay_delay || config.default_pay_delay.d_us === "forever"
? undefined
: add(new Date(), {
- seconds: config.default_pay_delay.d_us / (1000 * 1000),
- });
+ seconds: config.default_pay_delay.d_us / (1000 * 1000),
+ });
return {
inventoryProducts: {},
@@ -138,7 +139,7 @@ export function CreatePage({
const [value, valueHandler] = useState(with_defaults(instanceConfig));
const config = useConfigContext();
const zero = Amounts.zeroOfCurrency(config.currency);
-
+ const [settings] = useSettings()
const inventoryList = Object.values(value.inventoryProducts || {});
const productList = Object.values(value.products || {});
@@ -154,10 +155,10 @@ export function CreatePage({
order_price: !value.pricing?.order_price
? i18n.str`required`
: !parsedPrice
- ? i18n.str`not valid`
- : Amounts.isZero(parsedPrice)
- ? i18n.str`must be greater than 0`
- : undefined,
+ ? i18n.str`not valid`
+ : Amounts.isZero(parsedPrice)
+ ? i18n.str`must be greater than 0`
+ : undefined,
}),
extra:
value.extra && !stringIsValidJSON(value.extra)
@@ -167,47 +168,47 @@ export function CreatePage({
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,
+ ? 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
? undefined
: !isFuture(value.payments.pay_deadline)
- ? i18n.str`should be in the future`
- : value.payments.wire_transfer_deadline &&
- isBefore(
- value.payments.wire_transfer_deadline,
- value.payments.pay_deadline,
- )
- ? i18n.str`wire transfer deadline cannot be before pay deadline`
- : undefined,
+ ? i18n.str`should be in the future`
+ : value.payments.wire_transfer_deadline &&
+ isBefore(
+ value.payments.wire_transfer_deadline,
+ value.payments.pay_deadline,
+ )
+ ? i18n.str`wire transfer deadline cannot be before pay deadline`
+ : 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,
+ ? 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,
}),
shipping: undefinedIfEmpty({
delivery_date: !value.shipping?.delivery_date
? undefined
: !isFuture(value.shipping.delivery_date)
- ? i18n.str`should be in the future`
- : undefined,
+ ? i18n.str`should be in the future`
+ : undefined,
}),
};
const hasErrors = Object.keys(errors).some(
@@ -227,27 +228,27 @@ export function CreatePage({
extra: value.extra,
pay_deadline: value.payments.pay_deadline
? {
- t_s: Math.floor(value.payments.pay_deadline.getTime() / 1000),
- }
+ t_s: Math.floor(value.payments.pay_deadline.getTime() / 1000),
+ }
: undefined,
wire_transfer_deadline: value.payments.wire_transfer_deadline
? {
- t_s: Math.floor(
- value.payments.wire_transfer_deadline.getTime() / 1000,
- ),
- }
+ t_s: Math.floor(
+ value.payments.wire_transfer_deadline.getTime() / 1000,
+ ),
+ }
: undefined,
refund_deadline: value.payments.refund_deadline
? {
- t_s: Math.floor(value.payments.refund_deadline.getTime() / 1000),
- }
+ t_s: Math.floor(value.payments.refund_deadline.getTime() / 1000),
+ }
: undefined,
auto_refund: value.payments.auto_refund_deadline
? {
- d_us: Math.floor(
- value.payments.auto_refund_deadline.getTime() * 1000,
- ),
- }
+ d_us: Math.floor(
+ value.payments.auto_refund_deadline.getTime() * 1000,
+ ),
+ }
: undefined,
wire_fee_amortization: value.payments.wire_fee_amortization as number,
max_fee: value.payments.max_fee as string,
@@ -374,13 +375,15 @@ export function CreatePage({
inventory={instanceInventory}
/>
- <NonInventoryProductFrom
- productToEdit={editingProduct}
- onAddProduct={(p) => {
- setEditingProduct(undefined);
- return addNewProduct(p);
- }}
- />
+ {settings.advanceOrderMode &&
+ <NonInventoryProductFrom
+ productToEdit={editingProduct}
+ onAddProduct={(p) => {
+ setEditingProduct(undefined);
+ return addNewProduct(p);
+ }}
+ />
+ }
{allProducts.length > 0 && (
<ProductList
@@ -423,8 +426,8 @@ export function CreatePage({
discountOrRise > 0 &&
(discountOrRise < 1
? `discount of %${Math.round(
- (1 - discountOrRise) * 100,
- )}`
+ (1 - discountOrRise) * 100,
+ )}`
: `rise of %${Math.round((discountOrRise - 1) * 100)}`)
}
tooltip={i18n.str`Amount to be paid by the customer`}
@@ -445,102 +448,108 @@ export function CreatePage({
tooltip={i18n.str`Title of the order to be shown to the customer`}
/>
- <InputGroup
- name="shipping"
- label={i18n.str`Shipping and Fulfillment`}
- initialActive
- >
- <InputDate
- name="shipping.delivery_date"
- label={i18n.str`Delivery date`}
- tooltip={i18n.str`Deadline for physical delivery assured by the merchant.`}
- />
- {value.shipping?.delivery_date && (
- <InputGroup
- name="shipping.delivery_location"
- label={i18n.str`Location`}
- tooltip={i18n.str`address where the products will be delivered`}
- >
- <InputLocation name="shipping.delivery_location" />
- </InputGroup>
- )}
- <Input
- name="shipping.fullfilment_url"
- label={i18n.str`Fulfillment URL`}
- tooltip={i18n.str`URL to which the user will be redirected after successful payment.`}
- />
- </InputGroup>
+ {settings.advanceOrderMode &&
+ <InputGroup
+ name="shipping"
+ label={i18n.str`Shipping and Fulfillment`}
+ initialActive
+ >
+ <InputDate
+ name="shipping.delivery_date"
+ label={i18n.str`Delivery date`}
+ tooltip={i18n.str`Deadline for physical delivery assured by the merchant.`}
+ />
+ {value.shipping?.delivery_date && (
+ <InputGroup
+ name="shipping.delivery_location"
+ label={i18n.str`Location`}
+ tooltip={i18n.str`address where the products will be delivered`}
+ >
+ <InputLocation name="shipping.delivery_location" />
+ </InputGroup>
+ )}
+ <Input
+ name="shipping.fullfilment_url"
+ label={i18n.str`Fulfillment URL`}
+ tooltip={i18n.str`URL to which the user will be redirected after successful payment.`}
+ />
+ </InputGroup>
+ }
- <InputGroup
- name="payments"
- label={i18n.str`Taler payment options`}
- tooltip={i18n.str`Override default Taler payment settings for this order`}
- >
- <InputDate
- 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.`}
- />
- <InputDate
- name="payments.refund_deadline"
- label={i18n.str`Refund deadline`}
- tooltip={i18n.str`Time until which the order can be refunded by the merchant.`}
- />
- <InputDate
- name="payments.wire_transfer_deadline"
- label={i18n.str`Wire transfer deadline`}
- tooltip={i18n.str`Deadline for the exchange to make the wire transfer.`}
- />
- <InputDate
- name="payments.auto_refund_deadline"
- label={i18n.str`Auto-refund deadline`}
- tooltip={i18n.str`Time until which the wallet will automatically check for refunds without user interaction.`}
- />
+ {settings.advanceOrderMode &&
+ <InputGroup
+ name="payments"
+ label={i18n.str`Taler payment options`}
+ tooltip={i18n.str`Override default Taler payment settings for this order`}
+ >
+ <InputDate
+ 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.`}
+ />
+ <InputDate
+ name="payments.refund_deadline"
+ label={i18n.str`Refund deadline`}
+ tooltip={i18n.str`Time until which the order can be refunded by the merchant.`}
+ />
+ <InputDate
+ name="payments.wire_transfer_deadline"
+ label={i18n.str`Wire transfer deadline`}
+ tooltip={i18n.str`Deadline for the exchange to make the wire transfer.`}
+ />
+ <InputDate
+ name="payments.auto_refund_deadline"
+ label={i18n.str`Auto-refund deadline`}
+ tooltip={i18n.str`Time until which the wallet will automatically check for refunds without user interaction.`}
+ />
- <InputCurrency
- name="payments.max_fee"
- label={i18n.str`Maximum deposit fee`}
- tooltip={i18n.str`Maximum deposit fees the merchant is willing to cover for this order. Higher deposit fees must be covered in full by the consumer.`}
- />
- <InputCurrency
- name="payments.max_wire_fee"
- label={i18n.str`Maximum wire fee`}
- tooltip={i18n.str`Maximum aggregate wire fees the merchant is willing to cover for this order. Wire fees exceeding this amount are to be covered by the customers.`}
- />
- <InputNumber
- name="payments.wire_fee_amortization"
- label={i18n.str`Wire fee amortization`}
- tooltip={i18n.str`Factor by which wire fees exceeding the above threshold are divided to determine the share of excess wire fees to be paid explicitly by the consumer.`}
- />
- <InputBoolean
- name="payments.createToken"
- label={i18n.str`Create token`}
- tooltip={i18n.str`Uncheck this option if the merchant backend generated an order ID with enough entropy to prevent adversarial claims.`}
- />
- <InputNumber
- name="payments.minimum_age"
- label={i18n.str`Minimum age required`}
- tooltip={i18n.str`Any value greater than 0 will limit the coins able be used to pay this contract. If empty the age restriction will be defined by the products`}
- help={
- minAgeByProducts > 0
- ? i18n.str`Min age defined by the producs is ${minAgeByProducts}`
- : undefined
- }
- />
- </InputGroup>
+ <InputCurrency
+ name="payments.max_fee"
+ label={i18n.str`Maximum deposit fee`}
+ tooltip={i18n.str`Maximum deposit fees the merchant is willing to cover for this order. Higher deposit fees must be covered in full by the consumer.`}
+ />
+ <InputCurrency
+ name="payments.max_wire_fee"
+ label={i18n.str`Maximum wire fee`}
+ tooltip={i18n.str`Maximum aggregate wire fees the merchant is willing to cover for this order. Wire fees exceeding this amount are to be covered by the customers.`}
+ />
+ <InputNumber
+ name="payments.wire_fee_amortization"
+ label={i18n.str`Wire fee amortization`}
+ tooltip={i18n.str`Factor by which wire fees exceeding the above threshold are divided to determine the share of excess wire fees to be paid explicitly by the consumer.`}
+ />
+ <InputBoolean
+ name="payments.createToken"
+ label={i18n.str`Create token`}
+ tooltip={i18n.str`Uncheck this option if the merchant backend generated an order ID with enough entropy to prevent adversarial claims.`}
+ />
+ <InputNumber
+ name="payments.minimum_age"
+ label={i18n.str`Minimum age required`}
+ tooltip={i18n.str`Any value greater than 0 will limit the coins able be used to pay this contract. If empty the age restriction will be defined by the products`}
+ help={
+ minAgeByProducts > 0
+ ? i18n.str`Min age defined by the producs is ${minAgeByProducts}`
+ : undefined
+ }
+ />
+ </InputGroup>
+ }
- <InputGroup
- name="extra"
- label={i18n.str`Additional information`}
- tooltip={i18n.str`Custom information to be included in the contract for this order.`}
- >
- <Input
+ {settings.advanceOrderMode &&
+ <InputGroup
name="extra"
- inputType="multiline"
- label={`Value`}
- tooltip={i18n.str`You must enter a value in JavaScript Object Notation (JSON).`}
- />
- </InputGroup>
+ label={i18n.str`Additional information`}
+ tooltip={i18n.str`Custom information to be included in the contract for this order.`}
+ >
+ <Input
+ name="extra"
+ inputType="multiline"
+ label={`Value`}
+ tooltip={i18n.str`You must enter a value in JavaScript Object Notation (JSON).`}
+ />
+ </InputGroup>
+ }
</FormProvider>
<div class="buttons is-right mt-5">
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
index 8dabfbe12..8965d41c9 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
@@ -21,7 +21,7 @@
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
+import { format, formatDistance } from "date-fns";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { FormProvider } from "../../../../components/form/FormProvider.js";
@@ -223,6 +223,7 @@ function ClaimedPage({
</div>
</div>
</div>
+
<div class="level">
<div class="level-left">
<div class="level-item">
@@ -419,6 +420,11 @@ function PaidPage({
}
}
+ const now = new Date()
+ const nextEvent = events.find((e) => {
+ return e.when.getTime() > now.getTime()
+ })
+
const [value, valueHandler] = useState<Partial<Paid>>(order);
const { url } = useBackendContext();
const refundHost = url.replace(/.*:\/\//, ""); // remove protocol part
@@ -504,22 +510,13 @@ function PaidPage({
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
- // maxWidth: '100%',
}}
>
<p>
- <a
- href={order.contract_terms.fulfillment_url}
- rel="nofollow"
- target="new"
- >
- {order.contract_terms.fulfillment_url}
- </a>
- </p>
- <p>
- {format(
- new Date(order.contract_terms.timestamp.t_s * 1000),
- "yyyy/MM/dd HH:mm:ss",
+ <i18n.Translate>Next event in </i18n.Translate> {formatDistance(
+ nextEvent!.when,
+ new Date(),
+ // "yyyy/MM/dd HH:mm:ss",
)}
</p>
</div>
@@ -668,9 +665,9 @@ function UnpaidPage({
{order.creation_time.t_s === "never"
? "never"
: format(
- new Date(order.creation_time.t_s * 1000),
- "yyyy-MM-dd HH:mm:ss",
- )}
+ new Date(order.creation_time.t_s * 1000),
+ "yyyy-MM-dd HH:mm:ss",
+ )}
</p>
</div>
</div>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/Timeline.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/Timeline.tsx
index d73ba3acc..e68889a92 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/Timeline.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/Timeline.tsx
@@ -67,7 +67,7 @@ export function Timeline({ events: e }: Props) {
);
case "start":
return (
- <div class="timeline-marker is-icon is-success">
+ <div class="timeline-marker is-icon">
<i class="mdi mdi-flag " />
</div>
);
@@ -104,7 +104,7 @@ export function Timeline({ events: e }: Props) {
}
})()}
<div class="timeline-content">
- <p class="heading">{format(e.when, "yyyy/MM/dd HH:mm:ss")}</p>
+ {e.description !== "now" && <p class="heading">{format(e.when, "yyyy/MM/dd HH:mm:ss")}</p>}
<p>{e.description}</p>
</div>
</div>
@@ -117,12 +117,12 @@ export interface Event {
when: Date;
description: string;
type:
- | "start"
- | "refund"
- | "refund-taken"
- | "wired"
- | "wired-range"
- | "deadline"
- | "delivery"
- | "now";
+ | "start"
+ | "refund"
+ | "refund-taken"
+ | "wired"
+ | "wired-range"
+ | "deadline"
+ | "delivery"
+ | "now";
}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
index 56d9dda74..37770d273 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
@@ -164,7 +164,7 @@ export function ListPage({
<div class="field has-addons">
{jumpToDate && (
<div class="control">
- <a class="button" onClick={() => onSelectDate(undefined)}>
+ <a class="button is-fullwidth" onClick={() => onSelectDate(undefined)}>
<span
class="icon"
data-tooltip={i18n.str`clear date filter`}
@@ -191,7 +191,7 @@ export function ListPage({
<div class="control">
<span class="has-tooltip-left" data-tooltip={dateTooltip}>
<a
- class="button"
+ class="button is-fullwidth"
onClick={() => {
setPickDate(true);
}}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index 4dde202c4..e20b9bc27 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -85,34 +85,34 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
template_contract: !state.template_contract
? undefined
: undefinedIfEmpty({
- amount: !state.template_contract?.amount
- ? undefined
- : !parsedPrice
+ amount: !state.template_contract?.amount
+ ? undefined
+ : !parsedPrice
? i18n.str`not valid`
: Amounts.isZero(parsedPrice)
- ? i18n.str`must be greater than 0`
- : undefined,
- minimum_age:
- state.template_contract.minimum_age < 0
- ? i18n.str`should be greater that 0`
+ ? i18n.str`must be greater than 0`
: undefined,
- pay_duration: !state.template_contract.pay_duration
- ? i18n.str`can't be empty`
- : state.template_contract.pay_duration.d_us === "forever"
+ minimum_age:
+ state.template_contract.minimum_age < 0
+ ? i18n.str`should be greater that 0`
+ : undefined,
+ pay_duration: !state.template_contract.pay_duration
+ ? i18n.str`can't be empty`
+ : state.template_contract.pay_duration.d_us === "forever"
? undefined
: state.template_contract.pay_duration.d_us < 1000 * 1000 //less than one second
- ? i18n.str`to short`
- : undefined,
- } as Partial<MerchantTemplateContractDetails>),
+ ? i18n.str`to short`
+ : undefined,
+ } as Partial<MerchantTemplateContractDetails>),
pos_key: !state.pos_key
? !state.pos_algorithm
? undefined
: i18n.str`required`
: !isBase32RFC3548Charset(state.pos_key)
- ? i18n.str`just letters and numbers from 2 to 7`
- : state.pos_key.length !== 32
- ? i18n.str`size of the key should be 32`
- : undefined,
+ ? i18n.str`just letters and numbers from 2 to 7`
+ : state.pos_key.length !== 32
+ ? i18n.str`size of the key should be 32`
+ : undefined,
};
const hasErrors = Object.keys(errors).some(
@@ -139,7 +139,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
>
<InputWithAddon<Entity>
name="template_id"
- addonBefore={`${backend.url}/instances/templates/`}
+ help={`${backend.url}/instances/templates/${state.template_id ?? ""}`}
label={i18n.str`Identifier`}
tooltip={i18n.str`Name of the template in URLs.`}
/>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
index 90084f113..0f30efafd 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
@@ -34,6 +34,7 @@ import { useBackendContext } from "../../../../context/backend.js";
import { useConfigContext } from "../../../../context/config.js";
import { useInstanceContext } from "../../../../context/instance.js";
import { MerchantBackend } from "../../../../declaration.js";
+import { stringifyPayTemplateUri } from "@gnu-taler/taler-util";
type Entity = MerchantBackend.Template.UsingTemplateDetails;
@@ -64,46 +65,47 @@ export function QrPage({ template, id: templateId, onBack }: Props): VNode {
const fixedAmount = !!template.template_contract.amount;
const fixedSummary = !!template.template_contract.summary;
- const params = new URLSearchParams();
+ const templateParams: Record<string, string> = {}
if (!fixedAmount) {
if (state.amount) {
- params.append("amount", state.amount);
+ templateParams.amount = state.amount
} else {
- params.append("amount", config.currency);
+ templateParams.amount = config.currency
}
}
+
if (!fixedSummary) {
- params.append("summary", state.summary ?? "");
+ templateParams.summary = state.summary ?? ""
}
- const paramsStr = fixedAmount && fixedSummary ? "" : "?" + params.toString();
- const merchantURL = new URL(backendUrl);
-
- const talerProto =
- merchantURL.protocol === "http:" ? "taler+http:" : "taler:";
+ const merchantBaseUrl = new URL(backendUrl).href;
- const payTemplateUri = `${talerProto}//pay-template/${merchantURL.hostname}/${templateId}${paramsStr}`;
+ const payTemplateUri = stringifyPayTemplateUri({
+ merchantBaseUrl,
+ templateId,
+ templateParams
+ })
const issuer = encodeURIComponent(
- `${new URL(backendUrl).hostname}/${instanceId}`,
+ `${new URL(backendUrl).host}/${instanceId}`,
);
const oauthUri = !template.pos_algorithm
? undefined
: template.pos_algorithm === 1
- ? `otpauth://totp/${issuer}:${templateId}?secret=${template.pos_key}&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
- : template.pos_algorithm === 2
- ? `otpauth://totp/${issuer}:${templateId}?secret=${template.pos_key}&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
- : undefined;
+ ? `otpauth://totp/${issuer}:${templateId}?secret=${template.pos_key}&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
+ : template.pos_algorithm === 2
+ ? `otpauth://totp/${issuer}:${templateId}?secret=${template.pos_key}&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
+ : undefined;
const keySlice = template.pos_key?.substring(0, 4);
const oauthUriWithoutSecret = !template.pos_algorithm
? undefined
: template.pos_algorithm === 1
- ? `otpauth://totp/${issuer}:${templateId}?secret=${keySlice}...&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
- : template.pos_algorithm === 2
- ? `otpauth://totp/${issuer}:${templateId}?secret=${keySlice}...&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
- : undefined;
+ ? `otpauth://totp/${issuer}:${templateId}?secret=${keySlice}...&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
+ : template.pos_algorithm === 2
+ ? `otpauth://totp/${issuer}:${templateId}?secret=${keySlice}...&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
+ : undefined;
return (
<div>
{oauthUri && (