summaryrefslogtreecommitdiff
path: root/packages/merchant-backoffice-ui/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/merchant-backoffice-ui/src/utils')
-rw-r--r--packages/merchant-backoffice-ui/src/utils/amount.ts71
-rw-r--r--packages/merchant-backoffice-ui/src/utils/constants.ts194
-rw-r--r--packages/merchant-backoffice-ui/src/utils/regex.test.ts88
-rw-r--r--packages/merchant-backoffice-ui/src/utils/table.ts56
-rw-r--r--packages/merchant-backoffice-ui/src/utils/types.ts31
5 files changed, 440 insertions, 0 deletions
diff --git a/packages/merchant-backoffice-ui/src/utils/amount.ts b/packages/merchant-backoffice-ui/src/utils/amount.ts
new file mode 100644
index 000000000..c94101b4b
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/utils/amount.ts
@@ -0,0 +1,71 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+import {
+ amountFractionalBase,
+ AmountJson,
+ Amounts,
+ TalerMerchantApi,
+} from "@gnu-taler/taler-util";
+
+/**
+ * merge refund with the same description and a difference less than one minute
+ * @param prev list of refunds that will hold the merged refunds
+ * @param cur new refund to add to the list
+ * @returns list with the new refund, may be merged with the last
+ */
+export function mergeRefunds(
+ prev: TalerMerchantApi.RefundDetails[],
+ cur: TalerMerchantApi.RefundDetails,
+): TalerMerchantApi.RefundDetails[] {
+ let tail;
+
+ if (
+ prev.length === 0 || //empty list
+ cur.timestamp.t_s === "never" || //current does not have timestamp
+ (tail = prev[prev.length - 1]).timestamp.t_s === "never" || // last does not have timestamp
+ cur.reason !== tail.reason || //different reason
+ cur.pending !== tail.pending || //different pending state
+ Math.abs(cur.timestamp.t_s - tail.timestamp.t_s) > 1000 * 60
+ ) {
+ //more than 1 minute difference
+
+ //can't merge refunds, they are different or to distant in time
+ prev.push(cur);
+ return prev;
+ }
+
+ const a = Amounts.parseOrThrow(tail.amount);
+ const b = Amounts.parseOrThrow(cur.amount);
+ const r = Amounts.add(a, b).amount;
+
+ prev[prev.length - 1] = {
+ ...tail,
+ amount: Amounts.stringify(r),
+ };
+
+ return prev;
+}
+
+export function rate(a: AmountJson, b: AmountJson): number {
+ const af = toFloat(a);
+ const bf = toFloat(b);
+ if (bf === 0) return 0;
+ return af / bf;
+}
+
+function toFloat(amount: AmountJson): number {
+ return amount.value + amount.fraction / amountFractionalBase;
+}
diff --git a/packages/merchant-backoffice-ui/src/utils/constants.ts b/packages/merchant-backoffice-ui/src/utils/constants.ts
new file mode 100644
index 000000000..6b4d8eade
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/utils/constants.ts
@@ -0,0 +1,194 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+//https://tools.ietf.org/html/rfc8905
+export const PAYTO_REGEX =
+ /^payto:\/\/[a-zA-Z][a-zA-Z0-9-.]+(\/[a-zA-Z0-9\-\.\~\(\)@_%:!$&'*+,;=]*)*\??((amount|receiver-name|sender-name|instruction|message)=[a-zA-Z0-9\-\.\~\(\)@_%:!$'*+,;=]*&?)*$/;
+export const PAYTO_WIRE_METHOD_LOOKUP =
+ /payto:\/\/([a-zA-Z][a-zA-Z0-9-.]+)\/.*/;
+
+export const AMOUNT_REGEX = /^[a-zA-Z][a-zA-Z]{1,11}:[0-9][0-9,]*\.?[0-9,]*$/;
+
+export const AMOUNT_ZERO_REGEX = /^[a-zA-Z][a-zA-Z]*:0$/;
+
+export const CROCKFORD_BASE32_REGEX =
+ /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]+[*~$=U]*$/;
+
+export const URL_REGEX =
+ /^((https?:)(\/\/\/?)([\w]*(?::[\w]*)?@)?([\d\w\.-]+)(?::(\d+))?)\/$/;
+
+export const PAGINATED_LIST_SIZE = 5;
+// when doing paginated request, ask for one more
+// and use it to know if there are more to request
+export const PAGINATED_LIST_REQUEST = PAGINATED_LIST_SIZE + 1;
+
+// how much we will wait for all request, in seconds
+export const DEFAULT_REQUEST_TIMEOUT = 10;
+
+export const MAX_IMAGE_SIZE = 1024 * 1024;
+
+export const INSTANCE_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.@-]+$/;
+
+export const COUNTRY_TABLE = {
+ AE: "U.A.E.",
+ AF: "Afghanistan",
+ AL: "Albania",
+ AM: "Armenia",
+ AN: "Netherlands Antilles",
+ AR: "Argentina",
+ AT: "Austria",
+ AU: "Australia",
+ AZ: "Azerbaijan",
+ BA: "Bosnia and Herzegovina",
+ BD: "Bangladesh",
+ BE: "Belgium",
+ BG: "Bulgaria",
+ BH: "Bahrain",
+ BN: "Brunei Darussalam",
+ BO: "Bolivia",
+ BR: "Brazil",
+ BT: "Bhutan",
+ BY: "Belarus",
+ BZ: "Belize",
+ CA: "Canada",
+ CG: "Congo",
+ CH: "Switzerland",
+ CI: "Cote d'Ivoire",
+ CL: "Chile",
+ CM: "Cameroon",
+ CN: "People's Republic of China",
+ CO: "Colombia",
+ CR: "Costa Rica",
+ CS: "Serbia and Montenegro",
+ CZ: "Czech Republic",
+ DE: "Germany",
+ DK: "Denmark",
+ DO: "Dominican Republic",
+ DZ: "Algeria",
+ EC: "Ecuador",
+ EE: "Estonia",
+ EG: "Egypt",
+ ER: "Eritrea",
+ ES: "Spain",
+ ET: "Ethiopia",
+ FI: "Finland",
+ FO: "Faroe Islands",
+ FR: "France",
+ GB: "United Kingdom",
+ GD: "Caribbean",
+ GE: "Georgia",
+ GL: "Greenland",
+ GR: "Greece",
+ GT: "Guatemala",
+ HK: "Hong Kong",
+ // HK: "Hong Kong S.A.R.",
+ HN: "Honduras",
+ HR: "Croatia",
+ HT: "Haiti",
+ HU: "Hungary",
+ ID: "Indonesia",
+ IE: "Ireland",
+ IL: "Israel",
+ IN: "India",
+ IQ: "Iraq",
+ IR: "Iran",
+ IS: "Iceland",
+ IT: "Italy",
+ JM: "Jamaica",
+ JO: "Jordan",
+ JP: "Japan",
+ KE: "Kenya",
+ KG: "Kyrgyzstan",
+ KH: "Cambodia",
+ KR: "South Korea",
+ KW: "Kuwait",
+ KZ: "Kazakhstan",
+ LA: "Laos",
+ LB: "Lebanon",
+ LI: "Liechtenstein",
+ LK: "Sri Lanka",
+ LT: "Lithuania",
+ LU: "Luxembourg",
+ LV: "Latvia",
+ LY: "Libya",
+ MA: "Morocco",
+ MC: "Principality of Monaco",
+ MD: "Moldava",
+ // MD: "Moldova",
+ ME: "Montenegro",
+ MK: "Former Yugoslav Republic of Macedonia",
+ ML: "Mali",
+ MM: "Myanmar",
+ MN: "Mongolia",
+ MO: "Macau S.A.R.",
+ MT: "Malta",
+ MV: "Maldives",
+ MX: "Mexico",
+ MY: "Malaysia",
+ NG: "Nigeria",
+ NI: "Nicaragua",
+ NL: "Netherlands",
+ NO: "Norway",
+ NP: "Nepal",
+ NZ: "New Zealand",
+ OM: "Oman",
+ PA: "Panama",
+ PE: "Peru",
+ PH: "Philippines",
+ PK: "Islamic Republic of Pakistan",
+ PL: "Poland",
+ PR: "Puerto Rico",
+ PT: "Portugal",
+ PY: "Paraguay",
+ QA: "Qatar",
+ RE: "Reunion",
+ RO: "Romania",
+ RS: "Serbia",
+ RU: "Russia",
+ RW: "Rwanda",
+ SA: "Saudi Arabia",
+ SE: "Sweden",
+ SG: "Singapore",
+ SI: "Slovenia",
+ SK: "Slovak",
+ SN: "Senegal",
+ SO: "Somalia",
+ SR: "Suriname",
+ SV: "El Salvador",
+ SY: "Syria",
+ TH: "Thailand",
+ TJ: "Tajikistan",
+ TM: "Turkmenistan",
+ TN: "Tunisia",
+ TR: "Turkey",
+ TT: "Trinidad and Tobago",
+ TW: "Taiwan",
+ TZ: "Tanzania",
+ UA: "Ukraine",
+ US: "United States",
+ UY: "Uruguay",
+ VA: "Vatican",
+ VE: "Venezuela",
+ VN: "Viet Nam",
+ YE: "Yemen",
+ ZA: "South Africa",
+ ZW: "Zimbabwe",
+};
diff --git a/packages/merchant-backoffice-ui/src/utils/regex.test.ts b/packages/merchant-backoffice-ui/src/utils/regex.test.ts
new file mode 100644
index 000000000..78f2ef5ae
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/utils/regex.test.ts
@@ -0,0 +1,88 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { expect } from "chai";
+import { AMOUNT_REGEX, PAYTO_REGEX } from "./constants.js";
+
+describe("payto uri format", () => {
+ const valids = [
+ "payto://iban/DE75512108001245126199?amount=EUR:200.0&message=hello",
+ "payto://ach/122000661/1234",
+ "payto://upi/alice@example.com?receiver-name=Alice&amount=INR:200",
+ "payto://void/?amount=EUR:10.5",
+ "payto://ilp/g.acme.bob",
+ ];
+
+ it("should be valid", () => {
+ valids.forEach((v) => expect(v).match(PAYTO_REGEX));
+ });
+
+ const invalids = [
+ // has two question marks
+ "payto://iban/DE75?512108001245126199?amount=EUR:200.0&message=hello",
+ // has a space
+ "payto://ach /122000661/1234",
+ // has a space
+ "payto://upi/alice@ example.com?receiver-name=Alice&amount=INR:200",
+ // invalid field name (mount instead of amount)
+ "payto://void/?mount=EUR:10.5",
+ // payto:// is incomplete
+ "payto: //ilp/g.acme.bob",
+ ];
+
+ it("should not be valid", () => {
+ invalids.forEach((v) => expect(v).not.match(PAYTO_REGEX));
+ });
+});
+
+describe("amount format", () => {
+ const valids = [
+ "ARS:10",
+ "COL:10.2",
+ "UY:1,000.2",
+ "ARS:10.123,123",
+ "ARS:1,000,000",
+ "ARSCOL:10",
+ "LONGESTCURR:1,000,000.123,123",
+ ];
+
+
+ it("should be valid", () => {
+ valids.forEach((v) => expect(v).match(AMOUNT_REGEX));
+ });
+
+ const invalids = [
+ //no currency name
+ ":10",
+ //use . instead of ,
+ "ARS:1.000.000",
+ //currency name with numbers
+ "1ARS:10",
+ //currency name with numbers
+ "AR5:10",
+ //missing value
+ "USD:",
+ ];
+
+ it("should not be valid", () => {
+ invalids.forEach((v) => expect(v).not.match(AMOUNT_REGEX));
+ });
+});
diff --git a/packages/merchant-backoffice-ui/src/utils/table.ts b/packages/merchant-backoffice-ui/src/utils/table.ts
new file mode 100644
index 000000000..982b68e5e
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/utils/table.ts
@@ -0,0 +1,56 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+export interface Actions<T extends WithId> {
+ element: T;
+ type: "DELETE" | "UPDATE";
+}
+
+function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
+ return value !== null && value !== undefined;
+}
+
+export function buildActions<T extends WithId>(
+ instances: T[],
+ selected: string[],
+ action: "DELETE",
+): Actions<T>[] {
+ return selected
+ .map((id) => instances.find((i) => i.id === id))
+ .filter(notEmpty)
+ .map((id) => ({ element: id, type: action }));
+}
+
+/**
+ * For any object or array, return the same object if is not empty.
+ * not empty:
+ * - for arrays: at least one element not undefined
+ * - for objects: at least one property not undefined
+ * @param obj
+ * @returns
+ */
+export function undefinedIfEmpty<
+ T extends Record<string, unknown> | Array<unknown>,
+>(obj: T | undefined): T | undefined {
+ if (obj === undefined) return undefined;
+ return Object.values(obj).some((v) => v !== undefined) ? obj : undefined;
+}
diff --git a/packages/merchant-backoffice-ui/src/utils/types.ts b/packages/merchant-backoffice-ui/src/utils/types.ts
new file mode 100644
index 000000000..9ce6da4d1
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/utils/types.ts
@@ -0,0 +1,31 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+import { VNode } from "preact";
+
+export interface KeyValue {
+ [key: string]: string;
+}
+
+export interface Notification {
+ message: string;
+ description?: string | VNode;
+ details?: string | VNode | string;
+ type: MessageType;
+}
+
+export type ValueOrFunction<T> = T | ((p: T) => T);
+export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS";