diff --git a/src/__tests__/terminalAPIPredefinedContentHelper.spec.ts b/src/__tests__/terminalAPIPredefinedContentHelper.spec.ts new file mode 100644 index 000000000..faa0f6915 --- /dev/null +++ b/src/__tests__/terminalAPIPredefinedContentHelper.spec.ts @@ -0,0 +1,46 @@ +import { PredefinedContentHelper, DisplayNotificationEvent } from "../typings/terminal/predefinedContentHelper"; + +describe("PredefinedContentHelper", () => { + it("should extract a valid event", () => { + + const ReferenceID = "TransactionID=oLkO001517998574000&TimeStamp=2018-02-07T10%3a16%3a14.000Z&event=PIN_ENTERED"; + + const helper = new PredefinedContentHelper(ReferenceID); + expect(helper.getEvent()).toBe(DisplayNotificationEvent.PIN_ENTERED); + }); + + it("should return null for an invalid event", () => { + const helper = new PredefinedContentHelper("event=INVALID_EVENT"); + expect(helper.getEvent()).toBeNull(); + }); + + it("should extract TransactionID", () => { + const helper = new PredefinedContentHelper("TransactionID=12345&TimeStamp=2018-02-07T10%3a16%3a14.000Z&event=PIN_ENTERED"); + expect(helper.getTransactionId()).toBe("12345"); + }); + + it("should extract TimeStamp", () => { + const helper = new PredefinedContentHelper("TimeStamp=2024-07-11T12:00:00Z"); + expect(helper.getTimeStamp()).toBe("2024-07-11T12:00:00Z"); + }); + + it("should extract arbitrary key", () => { + const helper = new PredefinedContentHelper("foo=bar&baz=qux"); + expect(helper.get("foo")).toBe("bar"); + expect(helper.get("baz")).toBe("qux"); + expect(helper.get("missing")).toBeNull(); + }); + + it("should convert params to object", () => { + const helper = new PredefinedContentHelper("a=1&b=2&event=WAIT_FOR_PIN"); + expect(helper.toObject()).toEqual({ a: "1", b: "2", event: "WAIT_FOR_PIN" }); + }); + + it("should handle empty referenceId", () => { + const helper = new PredefinedContentHelper(""); + expect(helper.getEvent()).toBeNull(); + expect(helper.getTransactionId()).toBeNull(); + expect(helper.getTimeStamp()).toBeNull(); + expect(helper.toObject()).toEqual({}); + }); +}); \ No newline at end of file diff --git a/src/__tests__/terminalCloudAPI.spec.ts b/src/__tests__/terminalCloudAPI.spec.ts index 9ea15245d..4a538b55a 100644 --- a/src/__tests__/terminalCloudAPI.spec.ts +++ b/src/__tests__/terminalCloudAPI.spec.ts @@ -4,7 +4,7 @@ import { asyncRes } from "../__mocks__/terminalApi/async"; import { syncRefund, syncRes, syncResEventNotification, syncResEventNotificationWithAdditionalAttributes, syncResEventNotificationWithUnknownEnum } from "../__mocks__/terminalApi/sync"; import Client from "../client"; import TerminalCloudAPI from "../services/terminalCloudAPI"; -import { terminal} from "../typings"; +import { terminal } from "../typings"; let client: Client; let terminalCloudAPI: TerminalCloudAPI; diff --git a/src/typings/terminal/models.ts b/src/typings/terminal/models.ts index 99145d68f..38e749887 100644 --- a/src/typings/terminal/models.ts +++ b/src/typings/terminal/models.ts @@ -265,6 +265,8 @@ export * from "./transmitResponse"; export * from "./uTMCoordinates"; export * from "./unitOfMeasureType"; export * from "./versionType"; +// helpers +export * from "./predefinedContentHelper"; import { AbortRequest } from "./abortRequest"; import { AccountType } from "./accountType"; diff --git a/src/typings/terminal/predefinedContentHelper.ts b/src/typings/terminal/predefinedContentHelper.ts new file mode 100644 index 000000000..4f78405a3 --- /dev/null +++ b/src/typings/terminal/predefinedContentHelper.ts @@ -0,0 +1,74 @@ +/** + * PredefinedContentHelper class to parse and manage predefined content reference IDs. + */ +export class PredefinedContentHelper { + private params: URLSearchParams; + + constructor(referenceId: string) { + this.params = new URLSearchParams(referenceId); + } + + /** + * Extracts and validates the `event` value from the ReferenceID. + * + * @returns A valid `DisplayNotificationEvent`, otherwise `null`. + * + * @example + * const helper = new PredefinedContentHelper("...&event=PIN_ENTERED"); + * const event = helper.getEvent(); // DisplayNotificationEvent.PIN_ENTERED or null + */ + getEvent(): DisplayNotificationEvent | null { + const event = this.params.get("event"); + + if (event && Object.values(DisplayNotificationEvent).includes(event as DisplayNotificationEvent)) { + return event as DisplayNotificationEvent; + } + return null; + } + + getTransactionId(): string | null { + return this.params.get("TransactionID"); + } + + getTimeStamp(): string | null { + return this.params.get("TimeStamp"); + } + + get(key: string): string | null { + return this.params.get(key); + } + + toObject(): Record { + return Object.fromEntries(this.params); + } +} + +// Supported events for display notifications +export enum DisplayNotificationEvent { + TENDER_CREATED = "TENDER_CREATED", + CARD_INSERTED = "CARD_INSERTED", + CARD_PRESENTED = "CARD_PRESENTED", + CARD_SWIPED = "CARD_SWIPED", + WAIT_FOR_APP_SELECTION = "WAIT_FOR_APP_SELECTION", + APPLICATION_SELECTED = "APPLICATION_SELECTED", + ASK_SIGNATURE = "ASK_SIGNATURE", + CHECK_SIGNATURE = "CHECK_SIGNATURE", + SIGNATURE_CHECKED = "SIGNATURE_CHECKED", + WAIT_FOR_PIN = "WAIT_FOR_PIN", + PIN_ENTERED = "PIN_ENTERED", + PRINT_RECEIPT = "PRINT_RECEIPT", + RECEIPT_PRINTED = "RECEIPT_PRINTED", + CARD_REMOVED = "CARD_REMOVED", + TENDER_FINAL = "TENDER_FINAL", + ASK_DCC = "ASK_DCC", + DCC_ACCEPTED = "DCC_ACCEPTED", + DCC_REJECTED = "DCC_REJECTED", + ASK_GRATUITY = "ASK_GRATUITY", + GRATUITY_ENTERED = "GRATUITY_ENTERED", + BALANCE_QUERY_STARTED = "BALANCE_QUERY_STARTED", + BALANCE_QUERY_COMPLETED = "BALANCE_QUERY_COMPLETED", + LOAD_STARTED = "LOAD_STARTED", + LOAD_COMPLETED = "LOAD_COMPLETED", + PROVIDE_CARD_DETAILS = "PROVIDE_CARD_DETAILS", + CARD_DETAILS_PROVIDED = "CARD_DETAILS_PROVIDED", +}