@valuepay/react 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +545 -435
- package/dist/cjs/components/ValuePayButton.js +6 -2
- package/dist/cjs/components/ValuePayButton.js.map +1 -1
- package/dist/cjs/hooks/useValuePay.js +48 -19
- package/dist/cjs/hooks/useValuePay.js.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/utils/helpers.js +12 -1
- package/dist/cjs/utils/helpers.js.map +1 -1
- package/dist/esm/components/ValuePayButton.js +6 -2
- package/dist/esm/components/ValuePayButton.js.map +1 -1
- package/dist/esm/hooks/useValuePay.js +48 -19
- package/dist/esm/hooks/useValuePay.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/utils/helpers.js +12 -2
- package/dist/esm/utils/helpers.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types/index.d.ts +13 -2
- package/dist/types/utils/helpers.d.ts +6 -0
- package/package.json +7 -2
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var useValuePay = require('../hooks/useValuePay.js');
|
|
5
5
|
|
|
6
|
-
const ValuePayButton = ({ text, className, style, disabled, children, ...config }) => {
|
|
6
|
+
const ValuePayButton = ({ text, className, style, containerStyle, containerClassName, disabled, children, ...config }) => {
|
|
7
7
|
const { initialize, isReady, isProcessing } = useValuePay.useValuePay(config);
|
|
8
8
|
const defaultText = `Pay \u20A6${config.amount.toLocaleString()} Now`;
|
|
9
9
|
const buttonText = children || text || defaultText;
|
|
10
|
-
|
|
10
|
+
const button = (jsxRuntime.jsx("button", { type: "button", onClick: () => initialize(), disabled: disabled || !isReady || isProcessing, className: className, style: style, "aria-busy": isProcessing, "aria-label": typeof buttonText === "string" ? buttonText : "Pay Now", children: isProcessing ? "Processing..." : buttonText }));
|
|
11
|
+
if (containerStyle || containerClassName) {
|
|
12
|
+
return (jsxRuntime.jsx("div", { style: containerStyle, className: containerClassName, "data-testid": "valuepay-button-container", children: button }));
|
|
13
|
+
}
|
|
14
|
+
return button;
|
|
11
15
|
};
|
|
12
16
|
|
|
13
17
|
exports.ValuePayButton = ValuePayButton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValuePayButton.js","sources":["../../../../src/components/ValuePayButton.tsx"],"sourcesContent":["import React from \"react\";\nimport { useValuePay } from \"../hooks/useValuePay\";\nimport type { ValuePayButtonProps } from \"../types\";\n\nexport const ValuePayButton: React.FC<ValuePayButtonProps> = ({\n text,\n className,\n style,\n disabled,\n children,\n ...config\n}) => {\n const { initialize, isReady, isProcessing } = useValuePay(config);\n\n const defaultText = `Pay \\u20A6${config.amount.toLocaleString()} Now`;\n const buttonText = children || text || defaultText;\n\n
|
|
1
|
+
{"version":3,"file":"ValuePayButton.js","sources":["../../../../src/components/ValuePayButton.tsx"],"sourcesContent":["import React from \"react\";\r\nimport { useValuePay } from \"../hooks/useValuePay\";\r\nimport type { ValuePayButtonProps } from \"../types\";\r\n\r\nexport const ValuePayButton: React.FC<ValuePayButtonProps> = ({\r\n text,\r\n className,\r\n style,\r\n containerStyle,\r\n containerClassName,\r\n disabled,\r\n children,\r\n ...config\r\n}) => {\r\n const { initialize, isReady, isProcessing } = useValuePay(config);\r\n\r\n const defaultText = `Pay \\u20A6${config.amount.toLocaleString()} Now`;\r\n const buttonText = children || text || defaultText;\r\n\r\n const button = (\r\n <button\r\n type=\"button\"\r\n onClick={() => initialize()}\r\n disabled={disabled || !isReady || isProcessing}\r\n className={className}\r\n style={style}\r\n aria-busy={isProcessing}\r\n aria-label={typeof buttonText === \"string\" ? buttonText : \"Pay Now\"}\r\n >\r\n {isProcessing ? \"Processing...\" : buttonText}\r\n </button>\r\n );\r\n\r\n if (containerStyle || containerClassName) {\r\n return (\r\n <div style={containerStyle} className={containerClassName} data-testid=\"valuepay-button-container\">\r\n {button}\r\n </div>\r\n );\r\n }\r\n\r\n return button;\r\n};\r\n"],"names":["useValuePay","_jsx"],"mappings":";;;;;AAIO,MAAM,cAAc,GAAkC,CAAC,EAC5D,IAAI,EACJ,SAAS,EACT,KAAK,EACL,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,KAAI;AACH,IAAA,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,GAAGA,uBAAW,CAAC,MAAM,CAAC;IAEjE,MAAM,WAAW,GAAG,CAAA,UAAA,EAAa,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA,IAAA,CAAM;AACrE,IAAA,MAAM,UAAU,GAAG,QAAQ,IAAI,IAAI,IAAI,WAAW;IAElD,MAAM,MAAM,IACVC,cAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,MAAM,UAAU,EAAE,EAC3B,QAAQ,EAAE,QAAQ,IAAI,CAAC,OAAO,IAAI,YAAY,EAC9C,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EAAA,WAAA,EACD,YAAY,EAAA,YAAA,EACX,OAAO,UAAU,KAAK,QAAQ,GAAG,UAAU,GAAG,SAAS,EAAA,QAAA,EAElE,YAAY,GAAG,eAAe,GAAG,UAAU,EAAA,CACrC,CACV;AAED,IAAA,IAAI,cAAc,IAAI,kBAAkB,EAAE;AACxC,QAAA,QACEA,cAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,kBAAkB,iBAAc,2BAA2B,EAAA,QAAA,EAC/F,MAAM,EAAA,CACH;IAEV;AAEA,IAAA,OAAO,MAAM;AACf;;;;"}
|
|
@@ -5,6 +5,32 @@ var useScript = require('./useScript.js');
|
|
|
5
5
|
var helpers = require('../utils/helpers.js');
|
|
6
6
|
var constants = require('../utils/constants.js');
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Checks whether any callback function is provided in the config,
|
|
10
|
+
* using case-insensitive detection to handle both SDK-style (onCallback)
|
|
11
|
+
* and raw checkout-style (oncallback) casing.
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
function hasCallback(cfg, ...names) {
|
|
15
|
+
return names.some((name) => typeof cfg[name] === "function" || typeof cfg[name.toLowerCase()] === "function");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns true if the config has ANY callback defined (case-insensitive).
|
|
19
|
+
* When true, callbacks take precedence and redirectUrl is ignored.
|
|
20
|
+
*/
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
function hasAnyCallback(cfg) {
|
|
23
|
+
return hasCallback(cfg, "onSuccess", "onCallback", "onCancelled", "onClose", "onError");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Redirects the browser to the given URL with ref and status query params.
|
|
27
|
+
*/
|
|
28
|
+
function redirectTo(redirectUrl, ref, status) {
|
|
29
|
+
const url = new URL(redirectUrl);
|
|
30
|
+
url.searchParams.set("ref", ref);
|
|
31
|
+
url.searchParams.set("status", status);
|
|
32
|
+
window.location.href = url.toString();
|
|
33
|
+
}
|
|
8
34
|
const useValuePay = (config) => {
|
|
9
35
|
const scriptUrl = config.scriptUrl || constants.DEFAULT_SCRIPT_URL;
|
|
10
36
|
const isReady = useScript.useScript(scriptUrl);
|
|
@@ -23,24 +49,33 @@ const useValuePay = (config) => {
|
|
|
23
49
|
setIsProcessing(true);
|
|
24
50
|
const normalized = helpers.normalizeConfig(cfg, overrides);
|
|
25
51
|
const ref = normalized.transactionRef;
|
|
52
|
+
const useRedirect = !hasAnyCallback(cfg) && !!cfg.redirectUrl;
|
|
26
53
|
window.ValuepayCheckout({
|
|
27
54
|
...normalized,
|
|
28
55
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
+
onsuccess: (response) => {
|
|
57
|
+
var _a;
|
|
58
|
+
const res = helpers.normalizeResponse(response, ref, cfg);
|
|
59
|
+
setIsProcessing(false);
|
|
60
|
+
if (useRedirect) {
|
|
61
|
+
redirectTo(cfg.redirectUrl, res.ref, res.status);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (res.status !== "SUCCESS" && res.status !== "COMPLETED") {
|
|
65
|
+
res.status = "SUCCESS";
|
|
66
|
+
}
|
|
67
|
+
(_a = cfg.onSuccess) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
68
|
+
},
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
70
|
oncallback: (response) => {
|
|
30
|
-
var _a
|
|
71
|
+
var _a;
|
|
31
72
|
const res = helpers.normalizeResponse(response, ref, cfg);
|
|
32
73
|
setIsProcessing(false);
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
url.searchParams.set("ref", res.ref);
|
|
36
|
-
url.searchParams.set("status", res.status);
|
|
37
|
-
window.location.href = url.toString();
|
|
74
|
+
if (useRedirect) {
|
|
75
|
+
redirectTo(cfg.redirectUrl, res.ref, res.status);
|
|
38
76
|
return;
|
|
39
77
|
}
|
|
40
78
|
(_a = cfg.onCallback) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
41
|
-
if (res.status === "SUCCESS" || res.status === "COMPLETED") {
|
|
42
|
-
(_b = cfg.onSuccess) === null || _b === void 0 ? void 0 : _b.call(cfg, res);
|
|
43
|
-
}
|
|
44
79
|
},
|
|
45
80
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
81
|
onCancelled: (response) => {
|
|
@@ -48,11 +83,8 @@ const useValuePay = (config) => {
|
|
|
48
83
|
const res = helpers.normalizeResponse(response, ref, cfg);
|
|
49
84
|
res.status = "CANCELLED";
|
|
50
85
|
setIsProcessing(false);
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
url.searchParams.set("ref", res.ref);
|
|
54
|
-
url.searchParams.set("status", "CANCELLED");
|
|
55
|
-
window.location.href = url.toString();
|
|
86
|
+
if (useRedirect) {
|
|
87
|
+
redirectTo(cfg.redirectUrl, res.ref, "CANCELLED");
|
|
56
88
|
return;
|
|
57
89
|
}
|
|
58
90
|
(_a = cfg.onCancelled) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
@@ -70,11 +102,8 @@ const useValuePay = (config) => {
|
|
|
70
102
|
var _a;
|
|
71
103
|
const res = helpers.normalizeResponse(response, ref, cfg);
|
|
72
104
|
setIsProcessing(false);
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
url.searchParams.set("ref", res.ref);
|
|
76
|
-
url.searchParams.set("status", "CLOSED");
|
|
77
|
-
window.location.href = url.toString();
|
|
105
|
+
if (useRedirect) {
|
|
106
|
+
redirectTo(cfg.redirectUrl, res.ref, "CLOSED");
|
|
78
107
|
return;
|
|
79
108
|
}
|
|
80
109
|
(_a = cfg.onClose) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useValuePay.js","sources":["../../../../src/hooks/useValuePay.ts"],"sourcesContent":["import { useCallback, useState, useRef } from \"react\";\nimport { useScript } from \"./useScript\";\nimport { normalizeConfig, normalizeResponse } from \"../utils/helpers\";\nimport { DEFAULT_SCRIPT_URL } from \"../utils/constants\";\nimport type { ValuePayConfig, UseValuePayReturn } from \"../types\";\n\nexport const useValuePay = (config: ValuePayConfig): UseValuePayReturn => {\n const scriptUrl = config.scriptUrl || DEFAULT_SCRIPT_URL;\n const isReady = useScript(scriptUrl);\n const [isProcessing, setIsProcessing] = useState(false);\n const configRef = useRef(config);\n configRef.current = config;\n\n const initialize = useCallback(\n (overrides?: Partial<ValuePayConfig>) => {\n const cfg = configRef.current;\n\n if (typeof window === \"undefined\" || !window.ValuepayCheckout) {\n cfg.onError?.(new Error(\"ValuePay script not loaded. Ensure the script URL is accessible.\"));\n return;\n }\n\n if (isProcessing) return;\n\n setIsProcessing(true);\n\n const normalized = normalizeConfig(cfg, overrides);\n const ref = normalized.transactionRef;\n\n window.ValuepayCheckout({\n ...normalized,\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n
|
|
1
|
+
{"version":3,"file":"useValuePay.js","sources":["../../../../src/hooks/useValuePay.ts"],"sourcesContent":["import { useCallback, useState, useRef } from \"react\";\r\nimport { useScript } from \"./useScript\";\r\nimport { normalizeConfig, normalizeResponse } from \"../utils/helpers\";\r\nimport { DEFAULT_SCRIPT_URL } from \"../utils/constants\";\r\nimport type { ValuePayConfig, UseValuePayReturn } from \"../types\";\r\n\r\n/**\r\n * Checks whether any callback function is provided in the config,\r\n * using case-insensitive detection to handle both SDK-style (onCallback)\r\n * and raw checkout-style (oncallback) casing.\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nfunction hasCallback(cfg: any, ...names: string[]): boolean {\r\n return names.some(\r\n (name) => typeof cfg[name] === \"function\" || typeof cfg[name.toLowerCase()] === \"function\",\r\n );\r\n}\r\n\r\n/**\r\n * Returns true if the config has ANY callback defined (case-insensitive).\r\n * When true, callbacks take precedence and redirectUrl is ignored.\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nfunction hasAnyCallback(cfg: any): boolean {\r\n return hasCallback(cfg, \"onSuccess\", \"onCallback\", \"onCancelled\", \"onClose\", \"onError\");\r\n}\r\n\r\n/**\r\n * Redirects the browser to the given URL with ref and status query params.\r\n */\r\nfunction redirectTo(redirectUrl: string, ref: string, status: string) {\r\n const url = new URL(redirectUrl);\r\n url.searchParams.set(\"ref\", ref);\r\n url.searchParams.set(\"status\", status);\r\n window.location.href = url.toString();\r\n}\r\n\r\nexport const useValuePay = (config: ValuePayConfig): UseValuePayReturn => {\r\n const scriptUrl = config.scriptUrl || DEFAULT_SCRIPT_URL;\r\n const isReady = useScript(scriptUrl);\r\n const [isProcessing, setIsProcessing] = useState(false);\r\n const configRef = useRef(config);\r\n configRef.current = config;\r\n\r\n const initialize = useCallback(\r\n (overrides?: Partial<ValuePayConfig>) => {\r\n const cfg = configRef.current;\r\n\r\n if (typeof window === \"undefined\" || !window.ValuepayCheckout) {\r\n cfg.onError?.(\r\n new Error(\"ValuePay script not loaded. Ensure the script URL is accessible.\"),\r\n );\r\n return;\r\n }\r\n\r\n if (isProcessing) return;\r\n\r\n setIsProcessing(true);\r\n\r\n const normalized = normalizeConfig(cfg, overrides);\r\n const ref = normalized.transactionRef;\r\n const useRedirect = !hasAnyCallback(cfg) && !!cfg.redirectUrl;\r\n\r\n window.ValuepayCheckout({\r\n ...normalized,\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onsuccess: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, res.status);\r\n return;\r\n }\r\n\r\n if (res.status !== \"SUCCESS\" && res.status !== \"COMPLETED\") {\r\n res.status = \"SUCCESS\";\r\n }\r\n cfg.onSuccess?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n oncallback: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, res.status);\r\n return;\r\n }\r\n\r\n cfg.onCallback?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onCancelled: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n res.status = \"CANCELLED\";\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, \"CANCELLED\");\r\n return;\r\n }\r\n\r\n cfg.onCancelled?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onAborted: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n res.status = \"CANCELLED\";\r\n setIsProcessing(false);\r\n cfg.onCancelled?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onClosed: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, \"CLOSED\");\r\n return;\r\n }\r\n\r\n cfg.onClose?.(res);\r\n },\r\n });\r\n },\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [isReady, isProcessing],\r\n );\r\n\r\n return { initialize, isReady, isProcessing };\r\n};\r\n"],"names":["DEFAULT_SCRIPT_URL","useScript","useState","useRef","useCallback","normalizeConfig","normalizeResponse"],"mappings":"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"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -12,5 +12,6 @@ exports.ValuePayButton = ValuePayButton.ValuePayButton;
|
|
|
12
12
|
exports.ValuePayProvider = ValuePayProvider.ValuePayProvider;
|
|
13
13
|
exports.useValuePay = useValuePay.useValuePay;
|
|
14
14
|
exports.useScript = useScript.useScript;
|
|
15
|
+
exports.ensureRefPrefix = helpers.ensureRefPrefix;
|
|
15
16
|
exports.generateTransactionRef = helpers.generateTransactionRef;
|
|
16
17
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
|
|
@@ -13,12 +13,22 @@ const generateTransactionRef = (length = 20) => {
|
|
|
13
13
|
}
|
|
14
14
|
return result;
|
|
15
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Ensure the transaction reference always carries the VPS_TX_ prefix.
|
|
18
|
+
* If the merchant supplies their own ref, the prefix is prepended (unless already present).
|
|
19
|
+
* If omitted, a fully random reference is generated.
|
|
20
|
+
*/
|
|
21
|
+
const ensureRefPrefix = (ref) => {
|
|
22
|
+
return ref.startsWith(constants.TRANSACTION_REF_PREFIX) ? ref : `${constants.TRANSACTION_REF_PREFIX}${ref}`;
|
|
23
|
+
};
|
|
16
24
|
/**
|
|
17
25
|
* Normalize the SDK config into the shape expected by window.ValuepayCheckout.
|
|
18
26
|
*/
|
|
19
27
|
const normalizeConfig = (config, overrides) => {
|
|
20
28
|
const merged = { ...config, ...overrides };
|
|
21
|
-
const ref = merged.transactionRef
|
|
29
|
+
const ref = merged.transactionRef
|
|
30
|
+
? ensureRefPrefix(merged.transactionRef)
|
|
31
|
+
: generateTransactionRef();
|
|
22
32
|
return {
|
|
23
33
|
public_key: merged.publicKey,
|
|
24
34
|
transactionRef: ref,
|
|
@@ -61,6 +71,7 @@ const normalizeResponse = (raw, ref, config) => {
|
|
|
61
71
|
};
|
|
62
72
|
};
|
|
63
73
|
|
|
74
|
+
exports.ensureRefPrefix = ensureRefPrefix;
|
|
64
75
|
exports.generateTransactionRef = generateTransactionRef;
|
|
65
76
|
exports.normalizeConfig = normalizeConfig;
|
|
66
77
|
exports.normalizeResponse = normalizeResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sources":["../../../../src/utils/helpers.ts"],"sourcesContent":["import type { ValuePayConfig, ValuePayResponse } from \"../types\";\nimport { DEFAULT_CURRENCY, DEFAULT_CHANNELS, TRANSACTION_REF_PREFIX } from \"./constants\";\n\n/**\n * Generate a unique transaction reference.\n */\nexport const generateTransactionRef = (length: number = 20): string => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n let result = TRANSACTION_REF_PREFIX;\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n};\n\n/**\n * Normalize the SDK config into the shape expected by window.ValuepayCheckout.\n */\nexport const normalizeConfig = (config: ValuePayConfig, overrides?: Partial<ValuePayConfig>) => {\n const merged = { ...config, ...overrides };\n const ref = merged.transactionRef
|
|
1
|
+
{"version":3,"file":"helpers.js","sources":["../../../../src/utils/helpers.ts"],"sourcesContent":["import type { ValuePayConfig, ValuePayResponse } from \"../types\";\r\nimport { DEFAULT_CURRENCY, DEFAULT_CHANNELS, TRANSACTION_REF_PREFIX } from \"./constants\";\r\n\r\n/**\r\n * Generate a unique transaction reference.\r\n */\r\nexport const generateTransactionRef = (length: number = 20): string => {\r\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\r\n let result = TRANSACTION_REF_PREFIX;\r\n for (let i = 0; i < length; i++) {\r\n result += chars.charAt(Math.floor(Math.random() * chars.length));\r\n }\r\n return result;\r\n};\r\n\r\n/**\r\n * Ensure the transaction reference always carries the VPS_TX_ prefix.\r\n * If the merchant supplies their own ref, the prefix is prepended (unless already present).\r\n * If omitted, a fully random reference is generated.\r\n */\r\nexport const ensureRefPrefix = (ref: string): string => {\r\n return ref.startsWith(TRANSACTION_REF_PREFIX) ? ref : `${TRANSACTION_REF_PREFIX}${ref}`;\r\n};\r\n\r\n/**\r\n * Normalize the SDK config into the shape expected by window.ValuepayCheckout.\r\n */\r\nexport const normalizeConfig = (config: ValuePayConfig, overrides?: Partial<ValuePayConfig>) => {\r\n const merged = { ...config, ...overrides };\r\n const ref = merged.transactionRef\r\n ? ensureRefPrefix(merged.transactionRef)\r\n : generateTransactionRef();\r\n\r\n return {\r\n public_key: merged.publicKey,\r\n transactionRef: ref,\r\n amount: merged.amount,\r\n currency: merged.currency || DEFAULT_CURRENCY,\r\n channels: merged.channels || DEFAULT_CHANNELS,\r\n type: \"default\",\r\n redirect_url: merged.redirectUrl,\r\n metaData: merged.metaData,\r\n customer: {\r\n email: merged.customer.email,\r\n fullName: merged.customer.fullName,\r\n phone: merged.customer.phone,\r\n },\r\n customisedCheckout: merged.customization\r\n ? {\r\n title: merged.customization.title,\r\n description: merged.customization.description,\r\n logoLink: merged.customization.logoUrl,\r\n }\r\n : undefined,\r\n };\r\n};\r\n\r\n/**\r\n * Normalize the raw ValuePay response into our SDK response shape.\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport const normalizeResponse = (raw: any, ref: string, config: ValuePayConfig): ValuePayResponse => {\r\n return {\r\n ref: raw?.ref || raw?.reference || raw?.tx_ref || ref,\r\n transactionRef: raw?.transactionRef || ref,\r\n status: raw?.status || raw?.validation?.status || \"PENDING\",\r\n amount: config.amount,\r\n currency: config.currency || DEFAULT_CURRENCY,\r\n customer: config.customer,\r\n paymentMethod: raw?.paymentMethod,\r\n validation: raw?.validation,\r\n raw,\r\n };\r\n};\r\n"],"names":["TRANSACTION_REF_PREFIX","DEFAULT_CURRENCY","DEFAULT_CHANNELS"],"mappings":"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"}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useValuePay } from '../hooks/useValuePay.js';
|
|
3
3
|
|
|
4
|
-
const ValuePayButton = ({ text, className, style, disabled, children, ...config }) => {
|
|
4
|
+
const ValuePayButton = ({ text, className, style, containerStyle, containerClassName, disabled, children, ...config }) => {
|
|
5
5
|
const { initialize, isReady, isProcessing } = useValuePay(config);
|
|
6
6
|
const defaultText = `Pay \u20A6${config.amount.toLocaleString()} Now`;
|
|
7
7
|
const buttonText = children || text || defaultText;
|
|
8
|
-
|
|
8
|
+
const button = (jsx("button", { type: "button", onClick: () => initialize(), disabled: disabled || !isReady || isProcessing, className: className, style: style, "aria-busy": isProcessing, "aria-label": typeof buttonText === "string" ? buttonText : "Pay Now", children: isProcessing ? "Processing..." : buttonText }));
|
|
9
|
+
if (containerStyle || containerClassName) {
|
|
10
|
+
return (jsx("div", { style: containerStyle, className: containerClassName, "data-testid": "valuepay-button-container", children: button }));
|
|
11
|
+
}
|
|
12
|
+
return button;
|
|
9
13
|
};
|
|
10
14
|
|
|
11
15
|
export { ValuePayButton };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValuePayButton.js","sources":["../../../../src/components/ValuePayButton.tsx"],"sourcesContent":["import React from \"react\";\nimport { useValuePay } from \"../hooks/useValuePay\";\nimport type { ValuePayButtonProps } from \"../types\";\n\nexport const ValuePayButton: React.FC<ValuePayButtonProps> = ({\n text,\n className,\n style,\n disabled,\n children,\n ...config\n}) => {\n const { initialize, isReady, isProcessing } = useValuePay(config);\n\n const defaultText = `Pay \\u20A6${config.amount.toLocaleString()} Now`;\n const buttonText = children || text || defaultText;\n\n
|
|
1
|
+
{"version":3,"file":"ValuePayButton.js","sources":["../../../../src/components/ValuePayButton.tsx"],"sourcesContent":["import React from \"react\";\r\nimport { useValuePay } from \"../hooks/useValuePay\";\r\nimport type { ValuePayButtonProps } from \"../types\";\r\n\r\nexport const ValuePayButton: React.FC<ValuePayButtonProps> = ({\r\n text,\r\n className,\r\n style,\r\n containerStyle,\r\n containerClassName,\r\n disabled,\r\n children,\r\n ...config\r\n}) => {\r\n const { initialize, isReady, isProcessing } = useValuePay(config);\r\n\r\n const defaultText = `Pay \\u20A6${config.amount.toLocaleString()} Now`;\r\n const buttonText = children || text || defaultText;\r\n\r\n const button = (\r\n <button\r\n type=\"button\"\r\n onClick={() => initialize()}\r\n disabled={disabled || !isReady || isProcessing}\r\n className={className}\r\n style={style}\r\n aria-busy={isProcessing}\r\n aria-label={typeof buttonText === \"string\" ? buttonText : \"Pay Now\"}\r\n >\r\n {isProcessing ? \"Processing...\" : buttonText}\r\n </button>\r\n );\r\n\r\n if (containerStyle || containerClassName) {\r\n return (\r\n <div style={containerStyle} className={containerClassName} data-testid=\"valuepay-button-container\">\r\n {button}\r\n </div>\r\n );\r\n }\r\n\r\n return button;\r\n};\r\n"],"names":["_jsx"],"mappings":";;;AAIO,MAAM,cAAc,GAAkC,CAAC,EAC5D,IAAI,EACJ,SAAS,EACT,KAAK,EACL,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,KAAI;AACH,IAAA,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC;IAEjE,MAAM,WAAW,GAAG,CAAA,UAAA,EAAa,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA,IAAA,CAAM;AACrE,IAAA,MAAM,UAAU,GAAG,QAAQ,IAAI,IAAI,IAAI,WAAW;IAElD,MAAM,MAAM,IACVA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,MAAM,UAAU,EAAE,EAC3B,QAAQ,EAAE,QAAQ,IAAI,CAAC,OAAO,IAAI,YAAY,EAC9C,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EAAA,WAAA,EACD,YAAY,EAAA,YAAA,EACX,OAAO,UAAU,KAAK,QAAQ,GAAG,UAAU,GAAG,SAAS,EAAA,QAAA,EAElE,YAAY,GAAG,eAAe,GAAG,UAAU,EAAA,CACrC,CACV;AAED,IAAA,IAAI,cAAc,IAAI,kBAAkB,EAAE;AACxC,QAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,kBAAkB,iBAAc,2BAA2B,EAAA,QAAA,EAC/F,MAAM,EAAA,CACH;IAEV;AAEA,IAAA,OAAO,MAAM;AACf;;;;"}
|
|
@@ -3,6 +3,32 @@ import { useScript } from './useScript.js';
|
|
|
3
3
|
import { normalizeConfig, normalizeResponse } from '../utils/helpers.js';
|
|
4
4
|
import { DEFAULT_SCRIPT_URL } from '../utils/constants.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Checks whether any callback function is provided in the config,
|
|
8
|
+
* using case-insensitive detection to handle both SDK-style (onCallback)
|
|
9
|
+
* and raw checkout-style (oncallback) casing.
|
|
10
|
+
*/
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
function hasCallback(cfg, ...names) {
|
|
13
|
+
return names.some((name) => typeof cfg[name] === "function" || typeof cfg[name.toLowerCase()] === "function");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns true if the config has ANY callback defined (case-insensitive).
|
|
17
|
+
* When true, callbacks take precedence and redirectUrl is ignored.
|
|
18
|
+
*/
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
function hasAnyCallback(cfg) {
|
|
21
|
+
return hasCallback(cfg, "onSuccess", "onCallback", "onCancelled", "onClose", "onError");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Redirects the browser to the given URL with ref and status query params.
|
|
25
|
+
*/
|
|
26
|
+
function redirectTo(redirectUrl, ref, status) {
|
|
27
|
+
const url = new URL(redirectUrl);
|
|
28
|
+
url.searchParams.set("ref", ref);
|
|
29
|
+
url.searchParams.set("status", status);
|
|
30
|
+
window.location.href = url.toString();
|
|
31
|
+
}
|
|
6
32
|
const useValuePay = (config) => {
|
|
7
33
|
const scriptUrl = config.scriptUrl || DEFAULT_SCRIPT_URL;
|
|
8
34
|
const isReady = useScript(scriptUrl);
|
|
@@ -21,24 +47,33 @@ const useValuePay = (config) => {
|
|
|
21
47
|
setIsProcessing(true);
|
|
22
48
|
const normalized = normalizeConfig(cfg, overrides);
|
|
23
49
|
const ref = normalized.transactionRef;
|
|
50
|
+
const useRedirect = !hasAnyCallback(cfg) && !!cfg.redirectUrl;
|
|
24
51
|
window.ValuepayCheckout({
|
|
25
52
|
...normalized,
|
|
26
53
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
+
onsuccess: (response) => {
|
|
55
|
+
var _a;
|
|
56
|
+
const res = normalizeResponse(response, ref, cfg);
|
|
57
|
+
setIsProcessing(false);
|
|
58
|
+
if (useRedirect) {
|
|
59
|
+
redirectTo(cfg.redirectUrl, res.ref, res.status);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (res.status !== "SUCCESS" && res.status !== "COMPLETED") {
|
|
63
|
+
res.status = "SUCCESS";
|
|
64
|
+
}
|
|
65
|
+
(_a = cfg.onSuccess) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
66
|
+
},
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
68
|
oncallback: (response) => {
|
|
28
|
-
var _a
|
|
69
|
+
var _a;
|
|
29
70
|
const res = normalizeResponse(response, ref, cfg);
|
|
30
71
|
setIsProcessing(false);
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
url.searchParams.set("ref", res.ref);
|
|
34
|
-
url.searchParams.set("status", res.status);
|
|
35
|
-
window.location.href = url.toString();
|
|
72
|
+
if (useRedirect) {
|
|
73
|
+
redirectTo(cfg.redirectUrl, res.ref, res.status);
|
|
36
74
|
return;
|
|
37
75
|
}
|
|
38
76
|
(_a = cfg.onCallback) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
39
|
-
if (res.status === "SUCCESS" || res.status === "COMPLETED") {
|
|
40
|
-
(_b = cfg.onSuccess) === null || _b === void 0 ? void 0 : _b.call(cfg, res);
|
|
41
|
-
}
|
|
42
77
|
},
|
|
43
78
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
79
|
onCancelled: (response) => {
|
|
@@ -46,11 +81,8 @@ const useValuePay = (config) => {
|
|
|
46
81
|
const res = normalizeResponse(response, ref, cfg);
|
|
47
82
|
res.status = "CANCELLED";
|
|
48
83
|
setIsProcessing(false);
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
url.searchParams.set("ref", res.ref);
|
|
52
|
-
url.searchParams.set("status", "CANCELLED");
|
|
53
|
-
window.location.href = url.toString();
|
|
84
|
+
if (useRedirect) {
|
|
85
|
+
redirectTo(cfg.redirectUrl, res.ref, "CANCELLED");
|
|
54
86
|
return;
|
|
55
87
|
}
|
|
56
88
|
(_a = cfg.onCancelled) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
@@ -68,11 +100,8 @@ const useValuePay = (config) => {
|
|
|
68
100
|
var _a;
|
|
69
101
|
const res = normalizeResponse(response, ref, cfg);
|
|
70
102
|
setIsProcessing(false);
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
url.searchParams.set("ref", res.ref);
|
|
74
|
-
url.searchParams.set("status", "CLOSED");
|
|
75
|
-
window.location.href = url.toString();
|
|
103
|
+
if (useRedirect) {
|
|
104
|
+
redirectTo(cfg.redirectUrl, res.ref, "CLOSED");
|
|
76
105
|
return;
|
|
77
106
|
}
|
|
78
107
|
(_a = cfg.onClose) === null || _a === void 0 ? void 0 : _a.call(cfg, res);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useValuePay.js","sources":["../../../../src/hooks/useValuePay.ts"],"sourcesContent":["import { useCallback, useState, useRef } from \"react\";\nimport { useScript } from \"./useScript\";\nimport { normalizeConfig, normalizeResponse } from \"../utils/helpers\";\nimport { DEFAULT_SCRIPT_URL } from \"../utils/constants\";\nimport type { ValuePayConfig, UseValuePayReturn } from \"../types\";\n\nexport const useValuePay = (config: ValuePayConfig): UseValuePayReturn => {\n const scriptUrl = config.scriptUrl || DEFAULT_SCRIPT_URL;\n const isReady = useScript(scriptUrl);\n const [isProcessing, setIsProcessing] = useState(false);\n const configRef = useRef(config);\n configRef.current = config;\n\n const initialize = useCallback(\n (overrides?: Partial<ValuePayConfig>) => {\n const cfg = configRef.current;\n\n if (typeof window === \"undefined\" || !window.ValuepayCheckout) {\n cfg.onError?.(new Error(\"ValuePay script not loaded. Ensure the script URL is accessible.\"));\n return;\n }\n\n if (isProcessing) return;\n\n setIsProcessing(true);\n\n const normalized = normalizeConfig(cfg, overrides);\n const ref = normalized.transactionRef;\n\n window.ValuepayCheckout({\n ...normalized,\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n
|
|
1
|
+
{"version":3,"file":"useValuePay.js","sources":["../../../../src/hooks/useValuePay.ts"],"sourcesContent":["import { useCallback, useState, useRef } from \"react\";\r\nimport { useScript } from \"./useScript\";\r\nimport { normalizeConfig, normalizeResponse } from \"../utils/helpers\";\r\nimport { DEFAULT_SCRIPT_URL } from \"../utils/constants\";\r\nimport type { ValuePayConfig, UseValuePayReturn } from \"../types\";\r\n\r\n/**\r\n * Checks whether any callback function is provided in the config,\r\n * using case-insensitive detection to handle both SDK-style (onCallback)\r\n * and raw checkout-style (oncallback) casing.\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nfunction hasCallback(cfg: any, ...names: string[]): boolean {\r\n return names.some(\r\n (name) => typeof cfg[name] === \"function\" || typeof cfg[name.toLowerCase()] === \"function\",\r\n );\r\n}\r\n\r\n/**\r\n * Returns true if the config has ANY callback defined (case-insensitive).\r\n * When true, callbacks take precedence and redirectUrl is ignored.\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nfunction hasAnyCallback(cfg: any): boolean {\r\n return hasCallback(cfg, \"onSuccess\", \"onCallback\", \"onCancelled\", \"onClose\", \"onError\");\r\n}\r\n\r\n/**\r\n * Redirects the browser to the given URL with ref and status query params.\r\n */\r\nfunction redirectTo(redirectUrl: string, ref: string, status: string) {\r\n const url = new URL(redirectUrl);\r\n url.searchParams.set(\"ref\", ref);\r\n url.searchParams.set(\"status\", status);\r\n window.location.href = url.toString();\r\n}\r\n\r\nexport const useValuePay = (config: ValuePayConfig): UseValuePayReturn => {\r\n const scriptUrl = config.scriptUrl || DEFAULT_SCRIPT_URL;\r\n const isReady = useScript(scriptUrl);\r\n const [isProcessing, setIsProcessing] = useState(false);\r\n const configRef = useRef(config);\r\n configRef.current = config;\r\n\r\n const initialize = useCallback(\r\n (overrides?: Partial<ValuePayConfig>) => {\r\n const cfg = configRef.current;\r\n\r\n if (typeof window === \"undefined\" || !window.ValuepayCheckout) {\r\n cfg.onError?.(\r\n new Error(\"ValuePay script not loaded. Ensure the script URL is accessible.\"),\r\n );\r\n return;\r\n }\r\n\r\n if (isProcessing) return;\r\n\r\n setIsProcessing(true);\r\n\r\n const normalized = normalizeConfig(cfg, overrides);\r\n const ref = normalized.transactionRef;\r\n const useRedirect = !hasAnyCallback(cfg) && !!cfg.redirectUrl;\r\n\r\n window.ValuepayCheckout({\r\n ...normalized,\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onsuccess: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, res.status);\r\n return;\r\n }\r\n\r\n if (res.status !== \"SUCCESS\" && res.status !== \"COMPLETED\") {\r\n res.status = \"SUCCESS\";\r\n }\r\n cfg.onSuccess?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n oncallback: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, res.status);\r\n return;\r\n }\r\n\r\n cfg.onCallback?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onCancelled: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n res.status = \"CANCELLED\";\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, \"CANCELLED\");\r\n return;\r\n }\r\n\r\n cfg.onCancelled?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onAborted: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n res.status = \"CANCELLED\";\r\n setIsProcessing(false);\r\n cfg.onCancelled?.(res);\r\n },\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n onClosed: (response: any) => {\r\n const res = normalizeResponse(response, ref, cfg);\r\n setIsProcessing(false);\r\n\r\n if (useRedirect) {\r\n redirectTo(cfg.redirectUrl!, res.ref, \"CLOSED\");\r\n return;\r\n }\r\n\r\n cfg.onClose?.(res);\r\n },\r\n });\r\n },\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [isReady, isProcessing],\r\n );\r\n\r\n return { initialize, isReady, isProcessing };\r\n};\r\n"],"names":[],"mappings":";;;;;AAMA;;;;AAIG;AACH;AACA,SAAS,WAAW,CAAC,GAAQ,EAAE,GAAG,KAAe,EAAA;AAC/C,IAAA,OAAO,KAAK,CAAC,IAAI,CACf,CAAC,IAAI,KAAK,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,UAAU,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,UAAU,CAC3F;AACH;AAEA;;;AAGG;AACH;AACA,SAAS,cAAc,CAAC,GAAQ,EAAA;AAC9B,IAAA,OAAO,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,CAAC;AACzF;AAEA;;AAEG;AACH,SAAS,UAAU,CAAC,WAAmB,EAAE,GAAW,EAAE,MAAc,EAAA;AAClE,IAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC;IAChC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC;IAChC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;IACtC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC,QAAQ,EAAE;AACvC;AAEO,MAAM,WAAW,GAAG,CAAC,MAAsB,KAAuB;AACvE,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,kBAAkB;AACxD,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,SAAS,CAAC;IACpC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AACvD,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;AAChC,IAAA,SAAS,CAAC,OAAO,GAAG,MAAM;AAE1B,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,SAAmC,KAAI;;AACtC,QAAA,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO;QAE7B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE;YAC7D,CAAA,EAAA,GAAA,GAAG,CAAC,OAAO,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,GAAA,EACT,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAC9E;YACD;QACF;AAEA,QAAA,IAAI,YAAY;YAAE;QAElB,eAAe,CAAC,IAAI,CAAC;QAErB,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC;AAClD,QAAA,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc;AACrC,QAAA,MAAM,WAAW,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,WAAW;QAE7D,MAAM,CAAC,gBAAgB,CAAC;AACtB,YAAA,GAAG,UAAU;;AAGb,YAAA,SAAS,EAAE,CAAC,QAAa,KAAI;;gBAC3B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;gBACjD,eAAe,CAAC,KAAK,CAAC;gBAEtB,IAAI,WAAW,EAAE;AACf,oBAAA,UAAU,CAAC,GAAG,CAAC,WAAY,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC;oBACjD;gBACF;AAEA,gBAAA,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,EAAE;AAC1D,oBAAA,GAAG,CAAC,MAAM,GAAG,SAAS;gBACxB;AACA,gBAAA,CAAA,EAAA,GAAA,GAAG,CAAC,SAAS,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,GAAA,EAAG,GAAG,CAAC;YACtB,CAAC;;AAGD,YAAA,UAAU,EAAE,CAAC,QAAa,KAAI;;gBAC5B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;gBACjD,eAAe,CAAC,KAAK,CAAC;gBAEtB,IAAI,WAAW,EAAE;AACf,oBAAA,UAAU,CAAC,GAAG,CAAC,WAAY,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC;oBACjD;gBACF;AAEA,gBAAA,CAAA,EAAA,GAAA,GAAG,CAAC,UAAU,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,GAAA,EAAG,GAAG,CAAC;YACvB,CAAC;;AAGD,YAAA,WAAW,EAAE,CAAC,QAAa,KAAI;;gBAC7B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;AACjD,gBAAA,GAAG,CAAC,MAAM,GAAG,WAAW;gBACxB,eAAe,CAAC,KAAK,CAAC;gBAEtB,IAAI,WAAW,EAAE;oBACf,UAAU,CAAC,GAAG,CAAC,WAAY,EAAE,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC;oBAClD;gBACF;AAEA,gBAAA,CAAA,EAAA,GAAA,GAAG,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,GAAA,EAAG,GAAG,CAAC;YACxB,CAAC;;AAGD,YAAA,SAAS,EAAE,CAAC,QAAa,KAAI;;gBAC3B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;AACjD,gBAAA,GAAG,CAAC,MAAM,GAAG,WAAW;gBACxB,eAAe,CAAC,KAAK,CAAC;AACtB,gBAAA,CAAA,EAAA,GAAA,GAAG,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,GAAA,EAAG,GAAG,CAAC;YACxB,CAAC;;AAGD,YAAA,QAAQ,EAAE,CAAC,QAAa,KAAI;;gBAC1B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;gBACjD,eAAe,CAAC,KAAK,CAAC;gBAEtB,IAAI,WAAW,EAAE;oBACf,UAAU,CAAC,GAAG,CAAC,WAAY,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC;oBAC/C;gBACF;AAEA,gBAAA,CAAA,EAAA,GAAA,GAAG,CAAC,OAAO,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,GAAA,EAAG,GAAG,CAAC;YACpB,CAAC;AACF,SAAA,CAAC;IACJ,CAAC;;AAED,IAAA,CAAC,OAAO,EAAE,YAAY,CAAC,CACxB;AAED,IAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE;AAC9C;;;;"}
|
package/dist/esm/index.js
CHANGED
|
@@ -2,5 +2,5 @@ export { ValuePayButton } from './components/ValuePayButton.js';
|
|
|
2
2
|
export { ValuePayProvider } from './components/ValuePayProvider.js';
|
|
3
3
|
export { useValuePay } from './hooks/useValuePay.js';
|
|
4
4
|
export { useScript } from './hooks/useScript.js';
|
|
5
|
-
export { generateTransactionRef } from './utils/helpers.js';
|
|
5
|
+
export { ensureRefPrefix, generateTransactionRef } from './utils/helpers.js';
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -11,12 +11,22 @@ const generateTransactionRef = (length = 20) => {
|
|
|
11
11
|
}
|
|
12
12
|
return result;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Ensure the transaction reference always carries the VPS_TX_ prefix.
|
|
16
|
+
* If the merchant supplies their own ref, the prefix is prepended (unless already present).
|
|
17
|
+
* If omitted, a fully random reference is generated.
|
|
18
|
+
*/
|
|
19
|
+
const ensureRefPrefix = (ref) => {
|
|
20
|
+
return ref.startsWith(TRANSACTION_REF_PREFIX) ? ref : `${TRANSACTION_REF_PREFIX}${ref}`;
|
|
21
|
+
};
|
|
14
22
|
/**
|
|
15
23
|
* Normalize the SDK config into the shape expected by window.ValuepayCheckout.
|
|
16
24
|
*/
|
|
17
25
|
const normalizeConfig = (config, overrides) => {
|
|
18
26
|
const merged = { ...config, ...overrides };
|
|
19
|
-
const ref = merged.transactionRef
|
|
27
|
+
const ref = merged.transactionRef
|
|
28
|
+
? ensureRefPrefix(merged.transactionRef)
|
|
29
|
+
: generateTransactionRef();
|
|
20
30
|
return {
|
|
21
31
|
public_key: merged.publicKey,
|
|
22
32
|
transactionRef: ref,
|
|
@@ -59,5 +69,5 @@ const normalizeResponse = (raw, ref, config) => {
|
|
|
59
69
|
};
|
|
60
70
|
};
|
|
61
71
|
|
|
62
|
-
export { generateTransactionRef, normalizeConfig, normalizeResponse };
|
|
72
|
+
export { ensureRefPrefix, generateTransactionRef, normalizeConfig, normalizeResponse };
|
|
63
73
|
//# sourceMappingURL=helpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sources":["../../../../src/utils/helpers.ts"],"sourcesContent":["import type { ValuePayConfig, ValuePayResponse } from \"../types\";\nimport { DEFAULT_CURRENCY, DEFAULT_CHANNELS, TRANSACTION_REF_PREFIX } from \"./constants\";\n\n/**\n * Generate a unique transaction reference.\n */\nexport const generateTransactionRef = (length: number = 20): string => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n let result = TRANSACTION_REF_PREFIX;\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n};\n\n/**\n * Normalize the SDK config into the shape expected by window.ValuepayCheckout.\n */\nexport const normalizeConfig = (config: ValuePayConfig, overrides?: Partial<ValuePayConfig>) => {\n const merged = { ...config, ...overrides };\n const ref = merged.transactionRef
|
|
1
|
+
{"version":3,"file":"helpers.js","sources":["../../../../src/utils/helpers.ts"],"sourcesContent":["import type { ValuePayConfig, ValuePayResponse } from \"../types\";\r\nimport { DEFAULT_CURRENCY, DEFAULT_CHANNELS, TRANSACTION_REF_PREFIX } from \"./constants\";\r\n\r\n/**\r\n * Generate a unique transaction reference.\r\n */\r\nexport const generateTransactionRef = (length: number = 20): string => {\r\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\r\n let result = TRANSACTION_REF_PREFIX;\r\n for (let i = 0; i < length; i++) {\r\n result += chars.charAt(Math.floor(Math.random() * chars.length));\r\n }\r\n return result;\r\n};\r\n\r\n/**\r\n * Ensure the transaction reference always carries the VPS_TX_ prefix.\r\n * If the merchant supplies their own ref, the prefix is prepended (unless already present).\r\n * If omitted, a fully random reference is generated.\r\n */\r\nexport const ensureRefPrefix = (ref: string): string => {\r\n return ref.startsWith(TRANSACTION_REF_PREFIX) ? ref : `${TRANSACTION_REF_PREFIX}${ref}`;\r\n};\r\n\r\n/**\r\n * Normalize the SDK config into the shape expected by window.ValuepayCheckout.\r\n */\r\nexport const normalizeConfig = (config: ValuePayConfig, overrides?: Partial<ValuePayConfig>) => {\r\n const merged = { ...config, ...overrides };\r\n const ref = merged.transactionRef\r\n ? ensureRefPrefix(merged.transactionRef)\r\n : generateTransactionRef();\r\n\r\n return {\r\n public_key: merged.publicKey,\r\n transactionRef: ref,\r\n amount: merged.amount,\r\n currency: merged.currency || DEFAULT_CURRENCY,\r\n channels: merged.channels || DEFAULT_CHANNELS,\r\n type: \"default\",\r\n redirect_url: merged.redirectUrl,\r\n metaData: merged.metaData,\r\n customer: {\r\n email: merged.customer.email,\r\n fullName: merged.customer.fullName,\r\n phone: merged.customer.phone,\r\n },\r\n customisedCheckout: merged.customization\r\n ? {\r\n title: merged.customization.title,\r\n description: merged.customization.description,\r\n logoLink: merged.customization.logoUrl,\r\n }\r\n : undefined,\r\n };\r\n};\r\n\r\n/**\r\n * Normalize the raw ValuePay response into our SDK response shape.\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport const normalizeResponse = (raw: any, ref: string, config: ValuePayConfig): ValuePayResponse => {\r\n return {\r\n ref: raw?.ref || raw?.reference || raw?.tx_ref || ref,\r\n transactionRef: raw?.transactionRef || ref,\r\n status: raw?.status || raw?.validation?.status || \"PENDING\",\r\n amount: config.amount,\r\n currency: config.currency || DEFAULT_CURRENCY,\r\n customer: config.customer,\r\n paymentMethod: raw?.paymentMethod,\r\n validation: raw?.validation,\r\n raw,\r\n };\r\n};\r\n"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { ValuePayButton } from "./components/ValuePayButton";
|
|
|
2
2
|
export { ValuePayProvider } from "./components/ValuePayProvider";
|
|
3
3
|
export { useValuePay } from "./hooks/useValuePay";
|
|
4
4
|
export { useScript } from "./hooks/useScript";
|
|
5
|
-
export { generateTransactionRef } from "./utils/helpers";
|
|
5
|
+
export { generateTransactionRef, ensureRefPrefix } from "./utils/helpers";
|
|
6
6
|
export type { ValuePayConfig, ValuePayResponse, ValuePayStatus, ValuePayCustomer, ValuePayCustomization, PaymentChannel, UseValuePayReturn, ValuePayButtonProps, ValuePayProviderProps, ValuePayProviderRef, } from "./types";
|
|
@@ -30,14 +30,21 @@ export interface ValuePayConfig {
|
|
|
30
30
|
customer: ValuePayCustomer;
|
|
31
31
|
currency?: string;
|
|
32
32
|
channels?: PaymentChannel[];
|
|
33
|
+
/** Optional custom transaction reference. The VPS_TX_ prefix is auto-prepended if missing. Auto-generated when omitted. */
|
|
33
34
|
transactionRef?: string;
|
|
35
|
+
/** Optional redirect URL after payment. Only used as a fallback when no callbacks (onSuccess, onCallback, onCancelled, onClose, onError) are provided. Callbacks always take precedence. */
|
|
34
36
|
redirectUrl?: string;
|
|
35
37
|
metaData?: Record<string, unknown>;
|
|
36
38
|
customization?: ValuePayCustomization;
|
|
39
|
+
/** Called on successful payment. Use this OR `onCallback` — not both. When provided, this is passed as `onsuccess` to the checkout and only fires for successful transactions. */
|
|
37
40
|
onSuccess?: (response: ValuePayResponse) => void;
|
|
41
|
+
/** Called when the user closes the checkout modal. */
|
|
38
42
|
onClose?: (response: ValuePayResponse) => void;
|
|
43
|
+
/** Called when the user explicitly cancels the payment. */
|
|
39
44
|
onCancelled?: (response: ValuePayResponse) => void;
|
|
45
|
+
/** General-purpose callback for ALL payment events (success, failure, etc.). Use this OR `onSuccess` — not both. When provided, this is passed as `oncallback` to the checkout and fires for every event. */
|
|
40
46
|
onCallback?: (response: ValuePayResponse) => void;
|
|
47
|
+
/** Called on SDK-level errors (script load failure, etc.). */
|
|
41
48
|
onError?: (error: Error) => void;
|
|
42
49
|
scriptUrl?: string;
|
|
43
50
|
}
|
|
@@ -52,10 +59,14 @@ export interface UseValuePayReturn {
|
|
|
52
59
|
export interface ValuePayButtonProps extends ValuePayConfig {
|
|
53
60
|
/** Button text override. Default: "Pay ₦{amount}" */
|
|
54
61
|
text?: string;
|
|
55
|
-
/** Additional CSS class names */
|
|
62
|
+
/** Additional CSS class names for the button element */
|
|
56
63
|
className?: string;
|
|
57
|
-
/**
|
|
64
|
+
/** Inline styles applied to the button element (text color, font, padding, etc.) */
|
|
58
65
|
style?: CSSProperties;
|
|
66
|
+
/** Inline styles applied to the outer container div (width, height, margin, borders, radius, background, etc.) */
|
|
67
|
+
containerStyle?: CSSProperties;
|
|
68
|
+
/** Additional CSS class names for the outer container div */
|
|
69
|
+
containerClassName?: string;
|
|
59
70
|
/** Disable the button */
|
|
60
71
|
disabled?: boolean;
|
|
61
72
|
/** Custom children override the default button text */
|
|
@@ -3,6 +3,12 @@ import type { ValuePayConfig, ValuePayResponse } from "../types";
|
|
|
3
3
|
* Generate a unique transaction reference.
|
|
4
4
|
*/
|
|
5
5
|
export declare const generateTransactionRef: (length?: number) => string;
|
|
6
|
+
/**
|
|
7
|
+
* Ensure the transaction reference always carries the VPS_TX_ prefix.
|
|
8
|
+
* If the merchant supplies their own ref, the prefix is prepended (unless already present).
|
|
9
|
+
* If omitted, a fully random reference is generated.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ensureRefPrefix: (ref: string) => string;
|
|
6
12
|
/**
|
|
7
13
|
* Normalize the SDK config into the shape expected by window.ValuepayCheckout.
|
|
8
14
|
*/
|
package/package.json
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valuepay/react",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Official React SDK for ValuePay payment gateway",
|
|
5
5
|
"author": "Value Payment Solutions Limited",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/cjs/index.js",
|
|
8
8
|
"module": "dist/esm/index.js",
|
|
9
9
|
"types": "dist/types/index.d.ts",
|
|
10
|
-
"files": [
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
|
+
],
|
|
11
16
|
"exports": {
|
|
12
17
|
".": {
|
|
13
18
|
"import": "./dist/esm/index.js",
|