intrpay-payments 1.1.0 → 1.2.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 CHANGED
File without changes
package/dist/index.cjs CHANGED
@@ -31,11 +31,13 @@ var import_react2 = require("react");
31
31
  // src/payment-shared.ts
32
32
  var import_react = require("react");
33
33
  var BASE_URL = "https://pay.intrpay.us";
34
+ var DEV_BASE_URL = "https://pay.intrpay.dev";
34
35
  var baseParams = {
35
36
  showHeader: false
36
37
  };
37
- function buildPaymentUrl(paymentLinkId, params) {
38
- const url = new URL(`${BASE_URL}/pay/${paymentLinkId}`);
38
+ function buildPaymentUrl(paymentLinkId, params, devHost) {
39
+ const baseUrl = devHost ? DEV_BASE_URL : BASE_URL;
40
+ const url = new URL(`${baseUrl}/pay/${paymentLinkId}`);
39
41
  const combinedParams = { ...baseParams, ...params };
40
42
  Object.entries(combinedParams).forEach(([key, value]) => {
41
43
  if (value === void 0 || value === null) return;
@@ -55,15 +57,17 @@ function usePaymentIframe({
55
57
  paymentLinkId,
56
58
  params,
57
59
  onSuccess,
58
- onFailure
60
+ onFailure,
61
+ devHost
59
62
  }) {
60
63
  const iframeUrl = (0, import_react.useMemo)(
61
- () => buildPaymentUrl(paymentLinkId, params),
62
- [paymentLinkId, params]
64
+ () => buildPaymentUrl(paymentLinkId, params, devHost),
65
+ [paymentLinkId, params, devHost]
63
66
  );
64
67
  (0, import_react.useEffect)(() => {
68
+ const expectedOrigin = devHost ? DEV_BASE_URL : BASE_URL;
65
69
  const handleMessage = (event) => {
66
- if (event.origin !== BASE_URL) return;
70
+ if (event.origin !== expectedOrigin) return;
67
71
  const data = event.data ?? {};
68
72
  const { type } = data;
69
73
  if (type === "payment_success") {
@@ -74,7 +78,7 @@ function usePaymentIframe({
74
78
  };
75
79
  window.addEventListener("message", handleMessage);
76
80
  return () => window.removeEventListener("message", handleMessage);
77
- }, [onSuccess, onFailure]);
81
+ }, [onSuccess, onFailure, devHost]);
78
82
  return { iframeUrl };
79
83
  }
80
84
 
@@ -91,13 +95,15 @@ function PaymentDrawer({
91
95
  onSuccess,
92
96
  onFailure,
93
97
  closeOnOverlayClick = true,
94
- zIndex = 2e3
98
+ zIndex = 2e3,
99
+ devHost
95
100
  }) {
96
101
  const { iframeUrl } = usePaymentIframe({
97
102
  paymentLinkId,
98
103
  params,
99
104
  onSuccess,
100
- onFailure
105
+ onFailure,
106
+ devHost
101
107
  });
102
108
  const handleKeyDown = (0, import_react2.useCallback)(
103
109
  (event) => {
@@ -258,13 +264,15 @@ function PaymentEmbed({
258
264
  height = 400,
259
265
  width = "100%",
260
266
  className,
261
- style
267
+ style,
268
+ devHost
262
269
  }) {
263
270
  const { iframeUrl } = usePaymentIframe({
264
271
  paymentLinkId,
265
272
  params,
266
273
  onSuccess,
267
- onFailure
274
+ onFailure,
275
+ devHost
268
276
  });
269
277
  const iframeHeight = typeof height === "number" ? `${height}px` : height;
270
278
  const iframeWidth = typeof width === "number" ? `${width}px` : width;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/PaymentDrawer.tsx","../src/payment-shared.ts","../src/components/PaymentEmbed.tsx"],"sourcesContent":["export { PaymentDrawer } from './components/PaymentDrawer';\nexport { PaymentEmbed } from './components/PaymentEmbed';\nexport type { PaymentDrawerProps, PaymentParams } from './components/PaymentDrawer';\nexport type { PaymentEmbedProps } from './components/PaymentEmbed';\n","import React, { useEffect, useCallback, CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport type { PaymentParams };\n\nexport interface PaymentDrawerProps {\n /** Whether the drawer is open */\n open: boolean;\n /** Callback when the drawer should close */\n onClose: () => void;\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Width of the drawer (default: 400px) */\n width?: string | number;\n /** Position of the drawer */\n position?: \"left\" | \"right\";\n /** Whether to show overlay backdrop */\n showOverlay?: boolean;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Whether clicking overlay closes the drawer */\n closeOnOverlayClick?: boolean;\n /** Z-index for the drawer */\n zIndex?: number;\n}\n\nexport function PaymentDrawer({\n open,\n onClose,\n paymentLinkId,\n params,\n width = 550,\n position = \"right\",\n showOverlay = true,\n onSuccess,\n onFailure,\n closeOnOverlayClick = true,\n zIndex = 2000,\n}: PaymentDrawerProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n });\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && open) {\n onClose();\n }\n },\n [open, onClose],\n );\n\n useEffect(() => {\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [handleKeyDown]);\n\n useEffect(() => {\n if (open) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [open]);\n\n const handleOverlayClick = () => {\n if (closeOnOverlayClick) {\n onClose();\n }\n };\n\n const drawerWidth = typeof width === \"number\" ? `${width}px` : width;\n\n const styles: Record<string, CSSProperties> = {\n overlay: {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n zIndex,\n opacity: open ? 1 : 0,\n visibility: open ? \"visible\" : \"hidden\",\n transition: \"opacity 0.3s ease, visibility 0.3s ease\",\n },\n drawer: {\n position: \"fixed\",\n top: 0,\n bottom: 0,\n [position]: 0,\n width: drawerWidth,\n maxWidth: \"100%\",\n backgroundColor: \"#ffffff\",\n zIndex: zIndex + 1,\n boxShadow:\n position === \"right\"\n ? \"-4px 0 20px rgba(0, 0, 0, 0.15)\"\n : \"4px 0 20px rgba(0, 0, 0, 0.15)\",\n transform: open\n ? \"translateX(0)\"\n : `translateX(${position === \"right\" ? \"100%\" : \"-100%\"})`,\n transition: \"transform 0.3s ease\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n closeButton: {\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 36,\n height: 36,\n border: \"1px solid rgba(0, 0, 0, 0.2)\",\n backgroundColor: \"#ffffff\",\n borderRadius: \"50%\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#000000\",\n zIndex: 10,\n boxShadow: \"0 1px 4px rgba(0, 0, 0, 0.2)\",\n },\n content: {\n flex: 1,\n overflow: \"hidden\",\n },\n iframe: {\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n },\n };\n\n return (\n <>\n {showOverlay && (\n <div\n style={styles.overlay}\n onClick={handleOverlayClick}\n aria-hidden=\"true\"\n />\n )}\n <div\n style={styles.drawer}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Payment\"\n >\n <button\n style={styles.closeButton}\n onClick={onClose}\n aria-label=\"Close drawer\"\n type=\"button\"\n onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\";\n e.currentTarget.style.color = \"#000000\";\n }}\n onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#ffffff\";\n e.currentTarget.style.color = \"#000000\";\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n <div style={styles.content}>\n <iframe\n src={open ? iframeUrl : \"about:blank\"}\n title=\"Payment\"\n style={styles.iframe}\n allow=\"payment; clipboard-write\"\n />\n </div>\n </div>\n </>\n );\n}\n","import { useEffect, useMemo } from \"react\";\n\nexport const BASE_URL = \"https://pay.intrpay.us\";\n\nconst baseParams = {\n showHeader: false,\n};\n\nexport interface PaymentParams {\n /** Payment amount */\n amount?: number;\n /** Customer's first name */\n firstName?: string;\n /** Customer's last name */\n lastName?: string;\n /** Customer's email */\n email?: string;\n /** Customer's phone number */\n phone?: string;\n /** Company name */\n companyName?: string;\n /** Whether to show the contact form */\n showContactForm?: boolean;\n /** Checkout item IDs (sent as checkout_items, comma-separated) */\n checkoutItems?: string[];\n /** Whether to allow partial payment */\n allowPartialPayments?: boolean;\n /** Payment description */\n description?: string;\n /** Primary theme color (hex, e.g. '#000076') */\n primaryColor?: string;\n /** Secondary theme color (hex, e.g. '#4774c0') */\n secondaryColor?: string;\n /** Text color (hex, e.g. '#f3fcff') */\n textColor?: string;\n /** Logo URL */\n logo?: string;\n /** Custom button text */\n buttonText?: string;\n /** Whether to show the header */\n showHeader?: boolean;\n /** Lock to a specific payment method */\n paymentMethod?: 'card' | 'daf' | 'ojc' | 'pledger' | 'donorsFund' | 'matbia';\n /** Enable preview mode */\n previewMode?: boolean;\n}\n\nexport function buildPaymentUrl(\n paymentLinkId: string,\n params?: PaymentParams\n): string {\n const url = new URL(`${BASE_URL}/pay/${paymentLinkId}`);\n const combinedParams = { ...baseParams, ...params };\n\n Object.entries(combinedParams).forEach(([key, value]) => {\n if (value === undefined || value === null) return;\n if (key === \"checkoutItems\" && Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(\"checkoutItems\", value.join(\",\"));\n }\n return;\n }\n if (value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n });\n\n return url.toString();\n}\n\nexport interface UsePaymentIframeOptions {\n paymentLinkId: string;\n params?: PaymentParams;\n onSuccess?: (data: unknown) => void;\n onFailure?: (data: unknown) => void;\n}\n\nexport function usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n}: UsePaymentIframeOptions) {\n const iframeUrl = useMemo(\n () => buildPaymentUrl(paymentLinkId, params),\n [paymentLinkId, params]\n );\n\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== BASE_URL) return;\n\n const data = event.data ?? {};\n const { type } = data as { type?: string };\n\n if (type === \"payment_success\") {\n onSuccess?.(data);\n } else if (type === \"payment_failure\") {\n onFailure?.(data);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [onSuccess, onFailure]);\n\n return { iframeUrl };\n}\n","import React, { CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport interface PaymentEmbedProps {\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Height of the iframe (default: 400px) */\n height?: string | number;\n /** Width of the iframe (default: 100%) */\n width?: string | number;\n /** Optional CSS class name */\n className?: string;\n /** Optional inline styles for the container */\n style?: CSSProperties;\n}\n\nexport function PaymentEmbed({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n height = 400,\n width = \"100%\",\n className,\n style,\n}: PaymentEmbedProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n });\n\n const iframeHeight = typeof height === \"number\" ? `${height}px` : height;\n const iframeWidth = typeof width === \"number\" ? `${width}px` : width;\n\n return (\n <div className={className} style={style}>\n <iframe\n src={iframeUrl}\n title=\"Payment\"\n style={{\n width: iframeWidth,\n height: iframeHeight,\n border: \"none\",\n }}\n allow=\"payment; clipboard-write\"\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAA6D;;;ACA7D,mBAAmC;AAE5B,IAAM,WAAW;AAExB,IAAM,aAAa;AAAA,EACjB,YAAY;AACd;AAyCO,SAAS,gBACd,eACA,QACQ;AACR,QAAM,MAAM,IAAI,IAAI,GAAG,QAAQ,QAAQ,aAAa,EAAE;AACtD,QAAM,iBAAiB,EAAE,GAAG,YAAY,GAAG,OAAO;AAElD,SAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,QAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,QAAI,QAAQ,mBAAmB,MAAM,QAAQ,KAAK,GAAG;AACnD,UAAI,MAAM,SAAS,GAAG;AACpB,YAAI,aAAa,IAAI,iBAAiB,MAAM,KAAK,GAAG,CAAC;AAAA,MACvD;AACA;AAAA,IACF;AACA,QAAI,UAAU,IAAI;AAChB,UAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO,IAAI,SAAS;AACtB;AASO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,gBAAY;AAAA,IAChB,MAAM,gBAAgB,eAAe,MAAM;AAAA,IAC3C,CAAC,eAAe,MAAM;AAAA,EACxB;AAEA,8BAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,UAAwB;AAC7C,UAAI,MAAM,WAAW,SAAU;AAE/B,YAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,YAAM,EAAE,KAAK,IAAI;AAEjB,UAAI,SAAS,mBAAmB;AAC9B,oBAAY,IAAI;AAAA,MAClB,WAAW,SAAS,mBAAmB;AACrC,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,WAAW,SAAS,CAAC;AAEzB,SAAO,EAAE,UAAU;AACrB;;;ADuCI;AAnHG,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB,SAAS;AACX,GAAuB;AACrB,QAAM,EAAE,UAAU,IAAI,iBAAiB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,oBAAgB;AAAA,IACpB,CAAC,UAAyB;AACxB,UAAI,MAAM,QAAQ,YAAY,MAAM;AAClC,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,+BAAU,MAAM;AACd,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,aAAa,CAAC;AAElB,+BAAU,MAAM;AACd,QAAI,MAAM;AACR,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC,OAAO;AACL,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC;AACA,WAAO,MAAM;AACX,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,qBAAqB,MAAM;AAC/B,QAAI,qBAAqB;AACvB,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAE/D,QAAM,SAAwC;AAAA,IAC5C,SAAS;AAAA,MACP,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB;AAAA,MACA,SAAS,OAAO,IAAI;AAAA,MACpB,YAAY,OAAO,YAAY;AAAA,MAC/B,YAAY;AAAA,IACd;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,CAAC,QAAQ,GAAG;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB,QAAQ,SAAS;AAAA,MACjB,WACE,aAAa,UACT,oCACA;AAAA,MACN,WAAW,OACP,kBACA,cAAc,aAAa,UAAU,SAAS,OAAO;AAAA,MACzD,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,eAAe;AAAA,IACjB;AAAA,IACA,aAAa;AAAA,MACX,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,IACb;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,SACE,4EACG;AAAA,mBACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,OAAO;AAAA,QACd,SAAS;AAAA,QACT,eAAY;AAAA;AAAA,IACd;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,OAAO;AAAA,QACd,MAAK;AAAA,QACL,cAAW;AAAA,QACX,cAAW;AAAA,QAEX;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,OAAO;AAAA,cACd,SAAS;AAAA,cACT,cAAW;AAAA,cACX,MAAK;AAAA,cACL,cAAc,CAAC,MAA2C;AACxD,kBAAE,cAAc,MAAM,kBAAkB;AACxC,kBAAE,cAAc,MAAM,QAAQ;AAAA,cAChC;AAAA,cACA,cAAc,CAAC,MAA2C;AACxD,kBAAE,cAAc,MAAM,kBAAkB;AACxC,kBAAE,cAAc,MAAM,QAAQ;AAAA,cAChC;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBACN,QAAO;AAAA,kBACP,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,aAAY;AAAA,kBACZ,eAAc;AAAA,kBACd,gBAAe;AAAA,kBAEf;AAAA,gEAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,oBACpC,4CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,cACtC;AAAA;AAAA,UACF;AAAA,UACA,4CAAC,SAAI,OAAO,OAAO,SACjB;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,OAAO,YAAY;AAAA,cACxB,OAAM;AAAA,cACN,OAAO,OAAO;AAAA,cACd,OAAM;AAAA;AAAA,UACR,GACF;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;AE1JM,IAAAC,sBAAA;AAtBC,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,QAAQ;AAAA,EACR;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,EAAE,UAAU,IAAI,iBAAiB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,eAAe,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAClE,QAAM,cAAc,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAE/D,SACE,6CAAC,SAAI,WAAsB,OACzB;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAM;AAAA,MACN,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,MACA,OAAM;AAAA;AAAA,EACR,GACF;AAEJ;","names":["import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/PaymentDrawer.tsx","../src/payment-shared.ts","../src/components/PaymentEmbed.tsx"],"sourcesContent":["export { PaymentDrawer } from './components/PaymentDrawer';\nexport { PaymentEmbed } from './components/PaymentEmbed';\nexport type { PaymentDrawerProps, PaymentParams } from './components/PaymentDrawer';\nexport type { PaymentEmbedProps } from './components/PaymentEmbed';\n","import React, { useEffect, useCallback, CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport type { PaymentParams };\n\nexport interface PaymentDrawerProps {\n /** Whether the drawer is open */\n open: boolean;\n /** Callback when the drawer should close */\n onClose: () => void;\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Width of the drawer (default: 400px) */\n width?: string | number;\n /** Position of the drawer */\n position?: \"left\" | \"right\";\n /** Whether to show overlay backdrop */\n showOverlay?: boolean;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Whether clicking overlay closes the drawer */\n closeOnOverlayClick?: boolean;\n /** Z-index for the drawer */\n zIndex?: number;\n devHost?: boolean;\n}\n\nexport function PaymentDrawer({\n open,\n onClose,\n paymentLinkId,\n params,\n width = 550,\n position = \"right\",\n showOverlay = true,\n onSuccess,\n onFailure,\n closeOnOverlayClick = true,\n zIndex = 2000,\n devHost,\n}: PaymentDrawerProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n devHost,\n });\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && open) {\n onClose();\n }\n },\n [open, onClose],\n );\n\n useEffect(() => {\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [handleKeyDown]);\n\n useEffect(() => {\n if (open) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [open]);\n\n const handleOverlayClick = () => {\n if (closeOnOverlayClick) {\n onClose();\n }\n };\n\n const drawerWidth = typeof width === \"number\" ? `${width}px` : width;\n\n const styles: Record<string, CSSProperties> = {\n overlay: {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n zIndex,\n opacity: open ? 1 : 0,\n visibility: open ? \"visible\" : \"hidden\",\n transition: \"opacity 0.3s ease, visibility 0.3s ease\",\n },\n drawer: {\n position: \"fixed\",\n top: 0,\n bottom: 0,\n [position]: 0,\n width: drawerWidth,\n maxWidth: \"100%\",\n backgroundColor: \"#ffffff\",\n zIndex: zIndex + 1,\n boxShadow:\n position === \"right\"\n ? \"-4px 0 20px rgba(0, 0, 0, 0.15)\"\n : \"4px 0 20px rgba(0, 0, 0, 0.15)\",\n transform: open\n ? \"translateX(0)\"\n : `translateX(${position === \"right\" ? \"100%\" : \"-100%\"})`,\n transition: \"transform 0.3s ease\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n closeButton: {\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 36,\n height: 36,\n border: \"1px solid rgba(0, 0, 0, 0.2)\",\n backgroundColor: \"#ffffff\",\n borderRadius: \"50%\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#000000\",\n zIndex: 10,\n boxShadow: \"0 1px 4px rgba(0, 0, 0, 0.2)\",\n },\n content: {\n flex: 1,\n overflow: \"hidden\",\n },\n iframe: {\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n },\n };\n\n return (\n <>\n {showOverlay && (\n <div\n style={styles.overlay}\n onClick={handleOverlayClick}\n aria-hidden=\"true\"\n />\n )}\n <div\n style={styles.drawer}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Payment\"\n >\n <button\n style={styles.closeButton}\n onClick={onClose}\n aria-label=\"Close drawer\"\n type=\"button\"\n onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\";\n e.currentTarget.style.color = \"#000000\";\n }}\n onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#ffffff\";\n e.currentTarget.style.color = \"#000000\";\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n <div style={styles.content}>\n <iframe\n src={open ? iframeUrl : \"about:blank\"}\n title=\"Payment\"\n style={styles.iframe}\n allow=\"payment; clipboard-write\"\n />\n </div>\n </div>\n </>\n );\n}\n","import { useEffect, useMemo } from \"react\";\n\nexport const BASE_URL = \"https://pay.intrpay.us\";\nexport const DEV_BASE_URL = \"https://pay.intrpay.dev\";\n\nconst baseParams = {\n showHeader: false,\n};\n\nexport interface PaymentParams {\n /** Payment amount */\n amount?: number;\n /** Customer's first name */\n firstName?: string;\n /** Customer's last name */\n lastName?: string;\n /** Customer's email */\n email?: string;\n /** Customer's phone number */\n phone?: string;\n /** Company name */\n companyName?: string;\n /** Whether to show the contact form */\n showContactForm?: boolean;\n /** Checkout item IDs (sent as checkout_items, comma-separated) */\n checkoutItems?: string[];\n /** Whether to allow partial payment */\n allowPartialPayments?: boolean;\n /** Payment description */\n description?: string;\n /** Primary theme color (hex, e.g. '#000076') */\n primaryColor?: string;\n /** Secondary theme color (hex, e.g. '#4774c0') */\n secondaryColor?: string;\n /** Text color (hex, e.g. '#f3fcff') */\n textColor?: string;\n /** Logo URL */\n logo?: string;\n /** Custom button text */\n buttonText?: string;\n /** Whether to show the header */\n showHeader?: boolean;\n /** Lock to a specific payment method */\n paymentMethod?: 'card' | 'daf' | 'ojc' | 'pledger' | 'donorsFund' | 'matbia';\n}\n\nexport function buildPaymentUrl(\n paymentLinkId: string,\n params?: PaymentParams,\n devHost?: boolean\n): string {\n const baseUrl = devHost ? DEV_BASE_URL : BASE_URL;\n const url = new URL(`${baseUrl}/pay/${paymentLinkId}`);\n const combinedParams = { ...baseParams, ...params };\n\n Object.entries(combinedParams).forEach(([key, value]) => {\n if (value === undefined || value === null) return;\n if (key === \"checkoutItems\" && Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(\"checkoutItems\", value.join(\",\"));\n }\n return;\n }\n if (value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n });\n\n return url.toString();\n}\n\nexport interface UsePaymentIframeOptions {\n paymentLinkId: string;\n params?: PaymentParams;\n onSuccess?: (data: unknown) => void;\n onFailure?: (data: unknown) => void;\n devHost?: boolean;\n}\n\nexport function usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n devHost,\n}: UsePaymentIframeOptions) {\n const iframeUrl = useMemo(\n () => buildPaymentUrl(paymentLinkId, params, devHost),\n [paymentLinkId, params, devHost]\n );\n\n useEffect(() => {\n const expectedOrigin = devHost ? DEV_BASE_URL : BASE_URL;\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) return;\n\n const data = event.data ?? {};\n const { type } = data as { type?: string };\n\n if (type === \"payment_success\") {\n onSuccess?.(data);\n } else if (type === \"payment_failure\") {\n onFailure?.(data);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [onSuccess, onFailure, devHost]);\n\n return { iframeUrl };\n}\n","import React, { CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport interface PaymentEmbedProps {\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Height of the iframe (default: 400px) */\n height?: string | number;\n /** Width of the iframe (default: 100%) */\n width?: string | number;\n /** Optional CSS class name */\n className?: string;\n /** Optional inline styles for the container */\n style?: CSSProperties;\n devHost?: boolean;\n}\n\nexport function PaymentEmbed({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n height = 400,\n width = \"100%\",\n className,\n style,\n devHost,\n}: PaymentEmbedProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n devHost,\n });\n\n const iframeHeight = typeof height === \"number\" ? `${height}px` : height;\n const iframeWidth = typeof width === \"number\" ? `${width}px` : width;\n\n return (\n <div className={className} style={style}>\n <iframe\n src={iframeUrl}\n title=\"Payment\"\n style={{\n width: iframeWidth,\n height: iframeHeight,\n border: \"none\",\n }}\n allow=\"payment; clipboard-write\"\n />\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime"]}
package/dist/index.d.cts CHANGED
@@ -36,8 +36,6 @@ interface PaymentParams {
36
36
  showHeader?: boolean;
37
37
  /** Lock to a specific payment method */
38
38
  paymentMethod?: 'card' | 'daf' | 'ojc' | 'pledger' | 'donorsFund' | 'matbia';
39
- /** Enable preview mode */
40
- previewMode?: boolean;
41
39
  }
42
40
 
43
41
  interface PaymentDrawerProps {
@@ -63,8 +61,9 @@ interface PaymentDrawerProps {
63
61
  closeOnOverlayClick?: boolean;
64
62
  /** Z-index for the drawer */
65
63
  zIndex?: number;
64
+ devHost?: boolean;
66
65
  }
67
- declare function PaymentDrawer({ open, onClose, paymentLinkId, params, width, position, showOverlay, onSuccess, onFailure, closeOnOverlayClick, zIndex, }: PaymentDrawerProps): react_jsx_runtime.JSX.Element;
66
+ declare function PaymentDrawer({ open, onClose, paymentLinkId, params, width, position, showOverlay, onSuccess, onFailure, closeOnOverlayClick, zIndex, devHost, }: PaymentDrawerProps): react_jsx_runtime.JSX.Element;
68
67
 
69
68
  interface PaymentEmbedProps {
70
69
  /** Payment link ID */
@@ -83,7 +82,8 @@ interface PaymentEmbedProps {
83
82
  className?: string;
84
83
  /** Optional inline styles for the container */
85
84
  style?: CSSProperties;
85
+ devHost?: boolean;
86
86
  }
87
- declare function PaymentEmbed({ paymentLinkId, params, onSuccess, onFailure, height, width, className, style, }: PaymentEmbedProps): react_jsx_runtime.JSX.Element;
87
+ declare function PaymentEmbed({ paymentLinkId, params, onSuccess, onFailure, height, width, className, style, devHost, }: PaymentEmbedProps): react_jsx_runtime.JSX.Element;
88
88
 
89
89
  export { PaymentDrawer, type PaymentDrawerProps, PaymentEmbed, type PaymentEmbedProps, type PaymentParams };
package/dist/index.d.ts CHANGED
@@ -36,8 +36,6 @@ interface PaymentParams {
36
36
  showHeader?: boolean;
37
37
  /** Lock to a specific payment method */
38
38
  paymentMethod?: 'card' | 'daf' | 'ojc' | 'pledger' | 'donorsFund' | 'matbia';
39
- /** Enable preview mode */
40
- previewMode?: boolean;
41
39
  }
42
40
 
43
41
  interface PaymentDrawerProps {
@@ -63,8 +61,9 @@ interface PaymentDrawerProps {
63
61
  closeOnOverlayClick?: boolean;
64
62
  /** Z-index for the drawer */
65
63
  zIndex?: number;
64
+ devHost?: boolean;
66
65
  }
67
- declare function PaymentDrawer({ open, onClose, paymentLinkId, params, width, position, showOverlay, onSuccess, onFailure, closeOnOverlayClick, zIndex, }: PaymentDrawerProps): react_jsx_runtime.JSX.Element;
66
+ declare function PaymentDrawer({ open, onClose, paymentLinkId, params, width, position, showOverlay, onSuccess, onFailure, closeOnOverlayClick, zIndex, devHost, }: PaymentDrawerProps): react_jsx_runtime.JSX.Element;
68
67
 
69
68
  interface PaymentEmbedProps {
70
69
  /** Payment link ID */
@@ -83,7 +82,8 @@ interface PaymentEmbedProps {
83
82
  className?: string;
84
83
  /** Optional inline styles for the container */
85
84
  style?: CSSProperties;
85
+ devHost?: boolean;
86
86
  }
87
- declare function PaymentEmbed({ paymentLinkId, params, onSuccess, onFailure, height, width, className, style, }: PaymentEmbedProps): react_jsx_runtime.JSX.Element;
87
+ declare function PaymentEmbed({ paymentLinkId, params, onSuccess, onFailure, height, width, className, style, devHost, }: PaymentEmbedProps): react_jsx_runtime.JSX.Element;
88
88
 
89
89
  export { PaymentDrawer, type PaymentDrawerProps, PaymentEmbed, type PaymentEmbedProps, type PaymentParams };
package/dist/index.js CHANGED
@@ -4,11 +4,13 @@ import { useEffect as useEffect2, useCallback } from "react";
4
4
  // src/payment-shared.ts
5
5
  import { useEffect, useMemo } from "react";
6
6
  var BASE_URL = "https://pay.intrpay.us";
7
+ var DEV_BASE_URL = "https://pay.intrpay.dev";
7
8
  var baseParams = {
8
9
  showHeader: false
9
10
  };
10
- function buildPaymentUrl(paymentLinkId, params) {
11
- const url = new URL(`${BASE_URL}/pay/${paymentLinkId}`);
11
+ function buildPaymentUrl(paymentLinkId, params, devHost) {
12
+ const baseUrl = devHost ? DEV_BASE_URL : BASE_URL;
13
+ const url = new URL(`${baseUrl}/pay/${paymentLinkId}`);
12
14
  const combinedParams = { ...baseParams, ...params };
13
15
  Object.entries(combinedParams).forEach(([key, value]) => {
14
16
  if (value === void 0 || value === null) return;
@@ -28,15 +30,17 @@ function usePaymentIframe({
28
30
  paymentLinkId,
29
31
  params,
30
32
  onSuccess,
31
- onFailure
33
+ onFailure,
34
+ devHost
32
35
  }) {
33
36
  const iframeUrl = useMemo(
34
- () => buildPaymentUrl(paymentLinkId, params),
35
- [paymentLinkId, params]
37
+ () => buildPaymentUrl(paymentLinkId, params, devHost),
38
+ [paymentLinkId, params, devHost]
36
39
  );
37
40
  useEffect(() => {
41
+ const expectedOrigin = devHost ? DEV_BASE_URL : BASE_URL;
38
42
  const handleMessage = (event) => {
39
- if (event.origin !== BASE_URL) return;
43
+ if (event.origin !== expectedOrigin) return;
40
44
  const data = event.data ?? {};
41
45
  const { type } = data;
42
46
  if (type === "payment_success") {
@@ -47,7 +51,7 @@ function usePaymentIframe({
47
51
  };
48
52
  window.addEventListener("message", handleMessage);
49
53
  return () => window.removeEventListener("message", handleMessage);
50
- }, [onSuccess, onFailure]);
54
+ }, [onSuccess, onFailure, devHost]);
51
55
  return { iframeUrl };
52
56
  }
53
57
 
@@ -64,13 +68,15 @@ function PaymentDrawer({
64
68
  onSuccess,
65
69
  onFailure,
66
70
  closeOnOverlayClick = true,
67
- zIndex = 2e3
71
+ zIndex = 2e3,
72
+ devHost
68
73
  }) {
69
74
  const { iframeUrl } = usePaymentIframe({
70
75
  paymentLinkId,
71
76
  params,
72
77
  onSuccess,
73
- onFailure
78
+ onFailure,
79
+ devHost
74
80
  });
75
81
  const handleKeyDown = useCallback(
76
82
  (event) => {
@@ -231,13 +237,15 @@ function PaymentEmbed({
231
237
  height = 400,
232
238
  width = "100%",
233
239
  className,
234
- style
240
+ style,
241
+ devHost
235
242
  }) {
236
243
  const { iframeUrl } = usePaymentIframe({
237
244
  paymentLinkId,
238
245
  params,
239
246
  onSuccess,
240
- onFailure
247
+ onFailure,
248
+ devHost
241
249
  });
242
250
  const iframeHeight = typeof height === "number" ? `${height}px` : height;
243
251
  const iframeWidth = typeof width === "number" ? `${width}px` : width;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/PaymentDrawer.tsx","../src/payment-shared.ts","../src/components/PaymentEmbed.tsx"],"sourcesContent":["import React, { useEffect, useCallback, CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport type { PaymentParams };\n\nexport interface PaymentDrawerProps {\n /** Whether the drawer is open */\n open: boolean;\n /** Callback when the drawer should close */\n onClose: () => void;\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Width of the drawer (default: 400px) */\n width?: string | number;\n /** Position of the drawer */\n position?: \"left\" | \"right\";\n /** Whether to show overlay backdrop */\n showOverlay?: boolean;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Whether clicking overlay closes the drawer */\n closeOnOverlayClick?: boolean;\n /** Z-index for the drawer */\n zIndex?: number;\n}\n\nexport function PaymentDrawer({\n open,\n onClose,\n paymentLinkId,\n params,\n width = 550,\n position = \"right\",\n showOverlay = true,\n onSuccess,\n onFailure,\n closeOnOverlayClick = true,\n zIndex = 2000,\n}: PaymentDrawerProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n });\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && open) {\n onClose();\n }\n },\n [open, onClose],\n );\n\n useEffect(() => {\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [handleKeyDown]);\n\n useEffect(() => {\n if (open) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [open]);\n\n const handleOverlayClick = () => {\n if (closeOnOverlayClick) {\n onClose();\n }\n };\n\n const drawerWidth = typeof width === \"number\" ? `${width}px` : width;\n\n const styles: Record<string, CSSProperties> = {\n overlay: {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n zIndex,\n opacity: open ? 1 : 0,\n visibility: open ? \"visible\" : \"hidden\",\n transition: \"opacity 0.3s ease, visibility 0.3s ease\",\n },\n drawer: {\n position: \"fixed\",\n top: 0,\n bottom: 0,\n [position]: 0,\n width: drawerWidth,\n maxWidth: \"100%\",\n backgroundColor: \"#ffffff\",\n zIndex: zIndex + 1,\n boxShadow:\n position === \"right\"\n ? \"-4px 0 20px rgba(0, 0, 0, 0.15)\"\n : \"4px 0 20px rgba(0, 0, 0, 0.15)\",\n transform: open\n ? \"translateX(0)\"\n : `translateX(${position === \"right\" ? \"100%\" : \"-100%\"})`,\n transition: \"transform 0.3s ease\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n closeButton: {\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 36,\n height: 36,\n border: \"1px solid rgba(0, 0, 0, 0.2)\",\n backgroundColor: \"#ffffff\",\n borderRadius: \"50%\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#000000\",\n zIndex: 10,\n boxShadow: \"0 1px 4px rgba(0, 0, 0, 0.2)\",\n },\n content: {\n flex: 1,\n overflow: \"hidden\",\n },\n iframe: {\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n },\n };\n\n return (\n <>\n {showOverlay && (\n <div\n style={styles.overlay}\n onClick={handleOverlayClick}\n aria-hidden=\"true\"\n />\n )}\n <div\n style={styles.drawer}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Payment\"\n >\n <button\n style={styles.closeButton}\n onClick={onClose}\n aria-label=\"Close drawer\"\n type=\"button\"\n onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\";\n e.currentTarget.style.color = \"#000000\";\n }}\n onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#ffffff\";\n e.currentTarget.style.color = \"#000000\";\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n <div style={styles.content}>\n <iframe\n src={open ? iframeUrl : \"about:blank\"}\n title=\"Payment\"\n style={styles.iframe}\n allow=\"payment; clipboard-write\"\n />\n </div>\n </div>\n </>\n );\n}\n","import { useEffect, useMemo } from \"react\";\n\nexport const BASE_URL = \"https://pay.intrpay.us\";\n\nconst baseParams = {\n showHeader: false,\n};\n\nexport interface PaymentParams {\n /** Payment amount */\n amount?: number;\n /** Customer's first name */\n firstName?: string;\n /** Customer's last name */\n lastName?: string;\n /** Customer's email */\n email?: string;\n /** Customer's phone number */\n phone?: string;\n /** Company name */\n companyName?: string;\n /** Whether to show the contact form */\n showContactForm?: boolean;\n /** Checkout item IDs (sent as checkout_items, comma-separated) */\n checkoutItems?: string[];\n /** Whether to allow partial payment */\n allowPartialPayments?: boolean;\n /** Payment description */\n description?: string;\n /** Primary theme color (hex, e.g. '#000076') */\n primaryColor?: string;\n /** Secondary theme color (hex, e.g. '#4774c0') */\n secondaryColor?: string;\n /** Text color (hex, e.g. '#f3fcff') */\n textColor?: string;\n /** Logo URL */\n logo?: string;\n /** Custom button text */\n buttonText?: string;\n /** Whether to show the header */\n showHeader?: boolean;\n /** Lock to a specific payment method */\n paymentMethod?: 'card' | 'daf' | 'ojc' | 'pledger' | 'donorsFund' | 'matbia';\n /** Enable preview mode */\n previewMode?: boolean;\n}\n\nexport function buildPaymentUrl(\n paymentLinkId: string,\n params?: PaymentParams\n): string {\n const url = new URL(`${BASE_URL}/pay/${paymentLinkId}`);\n const combinedParams = { ...baseParams, ...params };\n\n Object.entries(combinedParams).forEach(([key, value]) => {\n if (value === undefined || value === null) return;\n if (key === \"checkoutItems\" && Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(\"checkoutItems\", value.join(\",\"));\n }\n return;\n }\n if (value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n });\n\n return url.toString();\n}\n\nexport interface UsePaymentIframeOptions {\n paymentLinkId: string;\n params?: PaymentParams;\n onSuccess?: (data: unknown) => void;\n onFailure?: (data: unknown) => void;\n}\n\nexport function usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n}: UsePaymentIframeOptions) {\n const iframeUrl = useMemo(\n () => buildPaymentUrl(paymentLinkId, params),\n [paymentLinkId, params]\n );\n\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== BASE_URL) return;\n\n const data = event.data ?? {};\n const { type } = data as { type?: string };\n\n if (type === \"payment_success\") {\n onSuccess?.(data);\n } else if (type === \"payment_failure\") {\n onFailure?.(data);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [onSuccess, onFailure]);\n\n return { iframeUrl };\n}\n","import React, { CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport interface PaymentEmbedProps {\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Height of the iframe (default: 400px) */\n height?: string | number;\n /** Width of the iframe (default: 100%) */\n width?: string | number;\n /** Optional CSS class name */\n className?: string;\n /** Optional inline styles for the container */\n style?: CSSProperties;\n}\n\nexport function PaymentEmbed({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n height = 400,\n width = \"100%\",\n className,\n style,\n}: PaymentEmbedProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n });\n\n const iframeHeight = typeof height === \"number\" ? `${height}px` : height;\n const iframeWidth = typeof width === \"number\" ? `${width}px` : width;\n\n return (\n <div className={className} style={style}>\n <iframe\n src={iframeUrl}\n title=\"Payment\"\n style={{\n width: iframeWidth,\n height: iframeHeight,\n border: \"none\",\n }}\n allow=\"payment; clipboard-write\"\n />\n </div>\n );\n}\n"],"mappings":"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","names":["useEffect","useEffect","jsx"]}
1
+ {"version":3,"sources":["../src/components/PaymentDrawer.tsx","../src/payment-shared.ts","../src/components/PaymentEmbed.tsx"],"sourcesContent":["import React, { useEffect, useCallback, CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport type { PaymentParams };\n\nexport interface PaymentDrawerProps {\n /** Whether the drawer is open */\n open: boolean;\n /** Callback when the drawer should close */\n onClose: () => void;\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Width of the drawer (default: 400px) */\n width?: string | number;\n /** Position of the drawer */\n position?: \"left\" | \"right\";\n /** Whether to show overlay backdrop */\n showOverlay?: boolean;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Whether clicking overlay closes the drawer */\n closeOnOverlayClick?: boolean;\n /** Z-index for the drawer */\n zIndex?: number;\n devHost?: boolean;\n}\n\nexport function PaymentDrawer({\n open,\n onClose,\n paymentLinkId,\n params,\n width = 550,\n position = \"right\",\n showOverlay = true,\n onSuccess,\n onFailure,\n closeOnOverlayClick = true,\n zIndex = 2000,\n devHost,\n}: PaymentDrawerProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n devHost,\n });\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && open) {\n onClose();\n }\n },\n [open, onClose],\n );\n\n useEffect(() => {\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [handleKeyDown]);\n\n useEffect(() => {\n if (open) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [open]);\n\n const handleOverlayClick = () => {\n if (closeOnOverlayClick) {\n onClose();\n }\n };\n\n const drawerWidth = typeof width === \"number\" ? `${width}px` : width;\n\n const styles: Record<string, CSSProperties> = {\n overlay: {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n zIndex,\n opacity: open ? 1 : 0,\n visibility: open ? \"visible\" : \"hidden\",\n transition: \"opacity 0.3s ease, visibility 0.3s ease\",\n },\n drawer: {\n position: \"fixed\",\n top: 0,\n bottom: 0,\n [position]: 0,\n width: drawerWidth,\n maxWidth: \"100%\",\n backgroundColor: \"#ffffff\",\n zIndex: zIndex + 1,\n boxShadow:\n position === \"right\"\n ? \"-4px 0 20px rgba(0, 0, 0, 0.15)\"\n : \"4px 0 20px rgba(0, 0, 0, 0.15)\",\n transform: open\n ? \"translateX(0)\"\n : `translateX(${position === \"right\" ? \"100%\" : \"-100%\"})`,\n transition: \"transform 0.3s ease\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n closeButton: {\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 36,\n height: 36,\n border: \"1px solid rgba(0, 0, 0, 0.2)\",\n backgroundColor: \"#ffffff\",\n borderRadius: \"50%\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#000000\",\n zIndex: 10,\n boxShadow: \"0 1px 4px rgba(0, 0, 0, 0.2)\",\n },\n content: {\n flex: 1,\n overflow: \"hidden\",\n },\n iframe: {\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n },\n };\n\n return (\n <>\n {showOverlay && (\n <div\n style={styles.overlay}\n onClick={handleOverlayClick}\n aria-hidden=\"true\"\n />\n )}\n <div\n style={styles.drawer}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Payment\"\n >\n <button\n style={styles.closeButton}\n onClick={onClose}\n aria-label=\"Close drawer\"\n type=\"button\"\n onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\";\n e.currentTarget.style.color = \"#000000\";\n }}\n onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.backgroundColor = \"#ffffff\";\n e.currentTarget.style.color = \"#000000\";\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n <div style={styles.content}>\n <iframe\n src={open ? iframeUrl : \"about:blank\"}\n title=\"Payment\"\n style={styles.iframe}\n allow=\"payment; clipboard-write\"\n />\n </div>\n </div>\n </>\n );\n}\n","import { useEffect, useMemo } from \"react\";\n\nexport const BASE_URL = \"https://pay.intrpay.us\";\nexport const DEV_BASE_URL = \"https://pay.intrpay.dev\";\n\nconst baseParams = {\n showHeader: false,\n};\n\nexport interface PaymentParams {\n /** Payment amount */\n amount?: number;\n /** Customer's first name */\n firstName?: string;\n /** Customer's last name */\n lastName?: string;\n /** Customer's email */\n email?: string;\n /** Customer's phone number */\n phone?: string;\n /** Company name */\n companyName?: string;\n /** Whether to show the contact form */\n showContactForm?: boolean;\n /** Checkout item IDs (sent as checkout_items, comma-separated) */\n checkoutItems?: string[];\n /** Whether to allow partial payment */\n allowPartialPayments?: boolean;\n /** Payment description */\n description?: string;\n /** Primary theme color (hex, e.g. '#000076') */\n primaryColor?: string;\n /** Secondary theme color (hex, e.g. '#4774c0') */\n secondaryColor?: string;\n /** Text color (hex, e.g. '#f3fcff') */\n textColor?: string;\n /** Logo URL */\n logo?: string;\n /** Custom button text */\n buttonText?: string;\n /** Whether to show the header */\n showHeader?: boolean;\n /** Lock to a specific payment method */\n paymentMethod?: 'card' | 'daf' | 'ojc' | 'pledger' | 'donorsFund' | 'matbia';\n}\n\nexport function buildPaymentUrl(\n paymentLinkId: string,\n params?: PaymentParams,\n devHost?: boolean\n): string {\n const baseUrl = devHost ? DEV_BASE_URL : BASE_URL;\n const url = new URL(`${baseUrl}/pay/${paymentLinkId}`);\n const combinedParams = { ...baseParams, ...params };\n\n Object.entries(combinedParams).forEach(([key, value]) => {\n if (value === undefined || value === null) return;\n if (key === \"checkoutItems\" && Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(\"checkoutItems\", value.join(\",\"));\n }\n return;\n }\n if (value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n });\n\n return url.toString();\n}\n\nexport interface UsePaymentIframeOptions {\n paymentLinkId: string;\n params?: PaymentParams;\n onSuccess?: (data: unknown) => void;\n onFailure?: (data: unknown) => void;\n devHost?: boolean;\n}\n\nexport function usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n devHost,\n}: UsePaymentIframeOptions) {\n const iframeUrl = useMemo(\n () => buildPaymentUrl(paymentLinkId, params, devHost),\n [paymentLinkId, params, devHost]\n );\n\n useEffect(() => {\n const expectedOrigin = devHost ? DEV_BASE_URL : BASE_URL;\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) return;\n\n const data = event.data ?? {};\n const { type } = data as { type?: string };\n\n if (type === \"payment_success\") {\n onSuccess?.(data);\n } else if (type === \"payment_failure\") {\n onFailure?.(data);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [onSuccess, onFailure, devHost]);\n\n return { iframeUrl };\n}\n","import React, { CSSProperties } from \"react\";\nimport { usePaymentIframe } from \"../payment-shared\";\nimport type { PaymentParams } from \"../payment-shared\";\n\nexport interface PaymentEmbedProps {\n /** Payment link ID */\n paymentLinkId: string;\n /** Payment parameters to pass as URL query params */\n params?: PaymentParams;\n /** Callback when payment succeeds; receives the message data from the iframe */\n onSuccess?: (data: unknown) => void;\n /** Callback when payment fails; receives the message data from the iframe */\n onFailure?: (data: unknown) => void;\n /** Height of the iframe (default: 400px) */\n height?: string | number;\n /** Width of the iframe (default: 100%) */\n width?: string | number;\n /** Optional CSS class name */\n className?: string;\n /** Optional inline styles for the container */\n style?: CSSProperties;\n devHost?: boolean;\n}\n\nexport function PaymentEmbed({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n height = 400,\n width = \"100%\",\n className,\n style,\n devHost,\n}: PaymentEmbedProps) {\n const { iframeUrl } = usePaymentIframe({\n paymentLinkId,\n params,\n onSuccess,\n onFailure,\n devHost,\n });\n\n const iframeHeight = typeof height === \"number\" ? `${height}px` : height;\n const iframeWidth = typeof width === \"number\" ? `${width}px` : width;\n\n return (\n <div className={className} style={style}>\n <iframe\n src={iframeUrl}\n title=\"Payment\"\n style={{\n width: iframeWidth,\n height: iframeHeight,\n border: \"none\",\n }}\n allow=\"payment; clipboard-write\"\n />\n </div>\n );\n}\n"],"mappings":";AAAA,SAAgB,aAAAA,YAAW,mBAAkC;;;ACA7D,SAAS,WAAW,eAAe;AAE5B,IAAM,WAAW;AACjB,IAAM,eAAe;AAE5B,IAAM,aAAa;AAAA,EACjB,YAAY;AACd;AAuCO,SAAS,gBACd,eACA,QACA,SACQ;AACR,QAAM,UAAU,UAAU,eAAe;AACzC,QAAM,MAAM,IAAI,IAAI,GAAG,OAAO,QAAQ,aAAa,EAAE;AACrD,QAAM,iBAAiB,EAAE,GAAG,YAAY,GAAG,OAAO;AAElD,SAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,QAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,QAAI,QAAQ,mBAAmB,MAAM,QAAQ,KAAK,GAAG;AACnD,UAAI,MAAM,SAAS,GAAG;AACpB,YAAI,aAAa,IAAI,iBAAiB,MAAM,KAAK,GAAG,CAAC;AAAA,MACvD;AACA;AAAA,IACF;AACA,QAAI,UAAU,IAAI;AAChB,UAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO,IAAI,SAAS;AACtB;AAUO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,YAAY;AAAA,IAChB,MAAM,gBAAgB,eAAe,QAAQ,OAAO;AAAA,IACpD,CAAC,eAAe,QAAQ,OAAO;AAAA,EACjC;AAEA,YAAU,MAAM;AACd,UAAM,iBAAiB,UAAU,eAAe;AAChD,UAAM,gBAAgB,CAAC,UAAwB;AAC7C,UAAI,MAAM,WAAW,eAAgB;AAErC,YAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,YAAM,EAAE,KAAK,IAAI;AAEjB,UAAI,SAAS,mBAAmB;AAC9B,oBAAY,IAAI;AAAA,MAClB,WAAW,SAAS,mBAAmB;AACrC,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,WAAW,WAAW,OAAO,CAAC;AAElC,SAAO,EAAE,UAAU;AACrB;;;ADsCI,mBAEI,KA0BE,YA5BN;AArHG,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB,SAAS;AAAA,EACT;AACF,GAAuB;AACrB,QAAM,EAAE,UAAU,IAAI,iBAAiB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAAyB;AACxB,UAAI,MAAM,QAAQ,YAAY,MAAM;AAClC,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,EAAAC,WAAU,MAAM;AACd,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,aAAa,CAAC;AAElB,EAAAA,WAAU,MAAM;AACd,QAAI,MAAM;AACR,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC,OAAO;AACL,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC;AACA,WAAO,MAAM;AACX,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,qBAAqB,MAAM;AAC/B,QAAI,qBAAqB;AACvB,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAE/D,QAAM,SAAwC;AAAA,IAC5C,SAAS;AAAA,MACP,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB;AAAA,MACA,SAAS,OAAO,IAAI;AAAA,MACpB,YAAY,OAAO,YAAY;AAAA,MAC/B,YAAY;AAAA,IACd;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,CAAC,QAAQ,GAAG;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB,QAAQ,SAAS;AAAA,MACjB,WACE,aAAa,UACT,oCACA;AAAA,MACN,WAAW,OACP,kBACA,cAAc,aAAa,UAAU,SAAS,OAAO;AAAA,MACzD,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,eAAe;AAAA,IACjB;AAAA,IACA,aAAa;AAAA,MACX,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,IACb;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,SACE,iCACG;AAAA,mBACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,OAAO;AAAA,QACd,SAAS;AAAA,QACT,eAAY;AAAA;AAAA,IACd;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,OAAO;AAAA,QACd,MAAK;AAAA,QACL,cAAW;AAAA,QACX,cAAW;AAAA,QAEX;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,OAAO;AAAA,cACd,SAAS;AAAA,cACT,cAAW;AAAA,cACX,MAAK;AAAA,cACL,cAAc,CAAC,MAA2C;AACxD,kBAAE,cAAc,MAAM,kBAAkB;AACxC,kBAAE,cAAc,MAAM,QAAQ;AAAA,cAChC;AAAA,cACA,cAAc,CAAC,MAA2C;AACxD,kBAAE,cAAc,MAAM,kBAAkB;AACxC,kBAAE,cAAc,MAAM,QAAQ;AAAA,cAChC;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBACN,QAAO;AAAA,kBACP,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,aAAY;AAAA,kBACZ,eAAc;AAAA,kBACd,gBAAe;AAAA,kBAEf;AAAA,wCAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,oBACpC,oBAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,cACtC;AAAA;AAAA,UACF;AAAA,UACA,oBAAC,SAAI,OAAO,OAAO,SACjB;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,OAAO,YAAY;AAAA,cACxB,OAAM;AAAA,cACN,OAAO,OAAO;AAAA,cACd,OAAM;AAAA;AAAA,UACR,GACF;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;AE1JM,gBAAAC,YAAA;AAxBC,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,EAAE,UAAU,IAAI,iBAAiB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,eAAe,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAClE,QAAM,cAAc,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAE/D,SACE,gBAAAA,KAAC,SAAI,WAAsB,OACzB,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAM;AAAA,MACN,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,MACA,OAAM;AAAA;AAAA,EACR,GACF;AAEJ;","names":["useEffect","useEffect","jsx"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intrpay-payments",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A package for integrating Intrpay payments into your React application",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -37,15 +37,15 @@
37
37
  "react-dom": ">=17.0.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@eslint/js": "^9.0.0",
41
- "@types/react": "^18.2.0",
42
- "@types/react-dom": "^18.2.0",
43
- "eslint": "^9.0.0",
44
- "eslint-plugin-react-hooks": "^5.0.0",
45
- "react": "^18.2.0",
46
- "react-dom": "^18.2.0",
47
- "tsup": "^8.0.0",
48
- "typescript": "^5.0.0",
49
- "typescript-eslint": "^8.0.0"
40
+ "@eslint/js": "^9.39.4",
41
+ "@types/react": "^18.3.28",
42
+ "@types/react-dom": "^18.3.7",
43
+ "eslint": "^9.39.4",
44
+ "eslint-plugin-react-hooks": "^5.2.0",
45
+ "react": "^18.3.1",
46
+ "react-dom": "^18.3.1",
47
+ "tsup": "^8.5.1",
48
+ "typescript": "^5.9.3",
49
+ "typescript-eslint": "^8.59.1"
50
50
  }
51
51
  }