azirid-react 0.9.4 → 0.9.5

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
@@ -667,6 +667,54 @@ const { data: proofs } = useTransferProofs()
667
667
  // [{ id, status: 'PENDING_REVIEW' | 'APPROVED' | 'REJECTED', ... }]
668
668
  ```
669
669
 
670
+ ### `usePayphoneCheckout`
671
+
672
+ Hook that returns a **renderable widget component** and **payment status**. Pass an `intentId` and get full control over where the widget renders and how to react to the payment result.
673
+
674
+ ```tsx
675
+ import { usePayphoneCheckout } from 'azirid-react'
676
+
677
+ function CheckoutPage({ intentId }: { intentId: string }) {
678
+ const { PayphoneWidget, status, error } = usePayphoneCheckout({
679
+ intentId,
680
+ onSuccess: (data) => {
681
+ // data: { status: 'confirmed' | 'cancelled' | 'already_confirmed', intentId: string }
682
+ console.log('Payment result:', data.status)
683
+ },
684
+ onError: (err) => console.error(err),
685
+ })
686
+
687
+ return (
688
+ <div>
689
+ <h1>Pay</h1>
690
+ <PayphoneWidget />
691
+ {status === 'loading' && <p>Preparing checkout...</p>}
692
+ {status === 'confirming' && <p>Confirming payment...</p>}
693
+ {status === 'confirmed' && <p>Payment confirmed!</p>}
694
+ {status === 'cancelled' && <p>Payment was cancelled</p>}
695
+ {status === 'error' && <p>Error: {error?.message}</p>}
696
+ </div>
697
+ )
698
+ }
699
+ ```
700
+
701
+ | Option | Type | Description |
702
+ |--------|------|-------------|
703
+ | `intentId` | `string` | **Required.** Payment intent ID |
704
+ | `onSuccess` | `(data) => void` | Called after payment confirmation |
705
+ | `onError` | `(error) => void` | Called on any error |
706
+
707
+ | Return | Type | Description |
708
+ |--------|------|-------------|
709
+ | `PayphoneWidget` | `() => ReactElement \| null` | Component to render the Payphone widget |
710
+ | `status` | `PayphoneCheckoutStatus` | `'idle' \| 'loading' \| 'ready' \| 'confirming' \| 'confirmed' \| 'cancelled' \| 'error'` |
711
+ | `intentId` | `string` | The intent ID passed in |
712
+ | `error` | `Error \| null` | Error details if status is `'error'` |
713
+
714
+ The hook handles both phases automatically:
715
+ 1. **Widget phase**: Calls checkout API, loads Payphone SDK, widget renders via `<PayphoneWidget />`.
716
+ 2. **Confirmation phase**: After Payphone redirects back (same page), detects URL params and confirms the payment.
717
+
670
718
  ### `usePayphoneConfirm`
671
719
 
672
720
  Confirm a Payphone payment callback. Used on the Payphone return URL page.
@@ -1564,6 +1612,7 @@ import type {
1564
1612
  | `UsePasswordResetOptions` / `UsePasswordResetReturn` | Options and return type for `usePasswordReset()` |
1565
1613
  | `UseCheckoutOptions` / `CheckoutParams` | Options and params for `useCheckout()` |
1566
1614
  | `UsePayphoneConfirmOptions` / `PayphoneConfirmParams` | Options and params for `usePayphoneConfirm()` |
1615
+ | `PayphoneCheckoutProps` | Props for `PayphoneCheckout` component |
1567
1616
  | `SimpleMutationOptions<T>` | Options for hooks created via `createMutationHook` |
1568
1617
  | `MutationHookConfig<TData, TInput>` | Configuration for `createMutationHook()` |
1569
1618
 
package/dist/index.cjs CHANGED
@@ -2256,8 +2256,9 @@ function usePaymentProviders() {
2256
2256
  }
2257
2257
 
2258
2258
  // src/utils/payphone-loader.ts
2259
- var PAYPHONE_CSS_URL = "https://cdn.payphonetodoesposible.com/box/v1.1/payphone-payment-box.css";
2260
- var PAYPHONE_JS_URL = "https://cdn.payphonetodoesposible.com/box/v1.1/payphone-payment-box.js";
2259
+ var PAYPHONE_CDN = "https://cdn.payphonetodoesposible.com";
2260
+ var PAYPHONE_CSS_URL = `${PAYPHONE_CDN}/box/v1.1/payphone-payment-box.css`;
2261
+ var PAYPHONE_JS_URL = `${PAYPHONE_CDN}/box/v1.1/payphone-payment-box.js`;
2261
2262
  var loadPromise = null;
2262
2263
  function loadCss(href) {
2263
2264
  if (document.querySelector(`link[href="${href}"]`)) return;
@@ -2275,7 +2276,11 @@ function loadScript(src) {
2275
2276
  const script = document.createElement("script");
2276
2277
  script.src = src;
2277
2278
  script.onload = () => resolve();
2278
- script.onerror = () => reject(new Error(`Failed to load Payphone SDK: ${src}`));
2279
+ script.onerror = () => reject(
2280
+ new Error(
2281
+ `Failed to load Payphone SDK from ${src}. If your app uses a Content-Security-Policy, add "${PAYPHONE_CDN}" to both script-src and style-src directives.`
2282
+ )
2283
+ );
2279
2284
  document.head.appendChild(script);
2280
2285
  });
2281
2286
  }
@@ -2284,7 +2289,10 @@ function loadPayphoneSdk() {
2284
2289
  loadPromise = (async () => {
2285
2290
  loadCss(PAYPHONE_CSS_URL);
2286
2291
  await loadScript(PAYPHONE_JS_URL);
2287
- })();
2292
+ })().catch((err) => {
2293
+ loadPromise = null;
2294
+ throw err;
2295
+ });
2288
2296
  return loadPromise;
2289
2297
  }
2290
2298
  function PayphoneModal({ config, successUrl, onClose }) {
@@ -3237,6 +3245,41 @@ var subtextStyle = {
3237
3245
  color: "#6b7280",
3238
3246
  margin: 0
3239
3247
  };
3248
+ function PayphoneWidgetRenderer({
3249
+ config,
3250
+ responseUrl,
3251
+ containerId,
3252
+ onReady,
3253
+ onError
3254
+ }) {
3255
+ const initialized = react.useRef(false);
3256
+ react.useEffect(() => {
3257
+ if (initialized.current) return;
3258
+ initialized.current = true;
3259
+ loadPayphoneSdk().then(() => {
3260
+ requestAnimationFrame(() => {
3261
+ if (typeof window.PPaymentButtonBox === "undefined") {
3262
+ onError?.(new Error("Payphone SDK failed to initialize"));
3263
+ return;
3264
+ }
3265
+ new window.PPaymentButtonBox({
3266
+ token: config.token,
3267
+ clientTransactionId: config.clientTransactionId,
3268
+ amount: config.amount,
3269
+ amountWithoutTax: config.amountWithoutTax,
3270
+ currency: config.currency,
3271
+ storeId: config.storeId,
3272
+ reference: config.reference,
3273
+ responseUrl
3274
+ }).render(containerId);
3275
+ onReady?.();
3276
+ });
3277
+ }).catch((err) => {
3278
+ onError?.(new Error(err instanceof Error ? err.message : "Failed to load Payphone SDK"));
3279
+ });
3280
+ }, [config, responseUrl, containerId, onReady, onError]);
3281
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { id: containerId });
3282
+ }
3240
3283
  var statusConfig = {
3241
3284
  ACTIVE: { bg: "#d1fae5", color: "#065f46", label: "Active" },
3242
3285
  TRIALING: { bg: "#dbeafe", color: "#1e40af", label: "Trial" },
@@ -3698,6 +3741,85 @@ function useTransferProofs() {
3698
3741
  queryFn: () => client.get(client.paths.transferProofs)
3699
3742
  });
3700
3743
  }
3744
+ var CONTAINER_ID = "pp-checkout-azirid";
3745
+ function usePayphoneCheckout({
3746
+ intentId,
3747
+ onSuccess,
3748
+ onError
3749
+ }) {
3750
+ const [status, setStatus] = react.useState("idle");
3751
+ const [widgetConfig, setWidgetConfig] = react.useState(null);
3752
+ const [currentError, setCurrentError] = react.useState(null);
3753
+ const checkoutTriggered = react.useRef(false);
3754
+ const confirmTriggered = react.useRef(false);
3755
+ const responseUrl = typeof window !== "undefined" ? window.location.href.split("?")[0] : "";
3756
+ const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : new URLSearchParams();
3757
+ const callbackId = params.get("id");
3758
+ const callbackClientTxId = params.get("clientTransactionId");
3759
+ const isCallback = !!(callbackId && callbackClientTxId);
3760
+ const { checkout } = useCheckout({
3761
+ redirectOnSuccess: false,
3762
+ onSuccess: (data) => {
3763
+ if (data.provider === "PAYPHONE" && data.widgetConfig) {
3764
+ setWidgetConfig(data.widgetConfig);
3765
+ setStatus("ready");
3766
+ }
3767
+ },
3768
+ onError: (err) => {
3769
+ setCurrentError(err);
3770
+ setStatus("error");
3771
+ onError?.(err);
3772
+ }
3773
+ });
3774
+ react.useEffect(() => {
3775
+ if (isCallback || checkoutTriggered.current) return;
3776
+ checkoutTriggered.current = true;
3777
+ setStatus("loading");
3778
+ checkout({
3779
+ intentId,
3780
+ provider: "PAYPHONE",
3781
+ successUrl: responseUrl,
3782
+ cancelUrl: responseUrl
3783
+ });
3784
+ }, [checkout, intentId, responseUrl, isCallback]);
3785
+ const { mutate: confirm } = usePayphoneConfirm({
3786
+ onSuccess: (data) => {
3787
+ setStatus(data.status === "confirmed" || data.status === "already_confirmed" ? "confirmed" : "cancelled");
3788
+ onSuccess?.(data);
3789
+ },
3790
+ onError: (err) => {
3791
+ setCurrentError(err);
3792
+ setStatus("error");
3793
+ onError?.(err);
3794
+ }
3795
+ });
3796
+ react.useEffect(() => {
3797
+ if (!isCallback || confirmTriggered.current) return;
3798
+ confirmTriggered.current = true;
3799
+ setStatus("confirming");
3800
+ confirm({ id: Number(callbackId), clientTransactionId: callbackClientTxId });
3801
+ }, [isCallback, callbackId, callbackClientTxId, confirm]);
3802
+ const handleSdkError = react.useCallback(
3803
+ (err) => {
3804
+ setCurrentError(err);
3805
+ setStatus("error");
3806
+ onError?.(err);
3807
+ },
3808
+ [onError]
3809
+ );
3810
+ const PayphoneWidget = react.useMemo(() => {
3811
+ return function PayphoneWidgetInner() {
3812
+ if (!widgetConfig || isCallback) return null;
3813
+ return PayphoneWidgetRenderer({
3814
+ config: widgetConfig,
3815
+ responseUrl,
3816
+ containerId: CONTAINER_ID,
3817
+ onError: handleSdkError
3818
+ });
3819
+ };
3820
+ }, [widgetConfig, responseUrl, isCallback, handleSdkError]);
3821
+ return { PayphoneWidget, status, intentId, error: currentError };
3822
+ }
3701
3823
  function useTenants() {
3702
3824
  const client = useAccessClient();
3703
3825
  return reactQuery.useQuery({
@@ -3790,7 +3912,7 @@ function usePasswordToggle() {
3790
3912
  }
3791
3913
 
3792
3914
  // src/index.ts
3793
- var SDK_VERSION = "0.9.4";
3915
+ var SDK_VERSION = "0.9.5";
3794
3916
 
3795
3917
  exports.AuthForm = AuthForm;
3796
3918
  exports.AziridProvider = AziridProvider;
@@ -3802,6 +3924,7 @@ exports.LoginForm = LoginForm;
3802
3924
  exports.PATHS = PATHS;
3803
3925
  exports.PayButton = PayButton;
3804
3926
  exports.PayphoneCallback = PayphoneCallback;
3927
+ exports.PayphoneWidgetRenderer = PayphoneWidgetRenderer;
3805
3928
  exports.PricingTable = PricingTable;
3806
3929
  exports.ReferralCard = ReferralCard;
3807
3930
  exports.ReferralStats = ReferralStats;
@@ -3847,6 +3970,7 @@ exports.usePasskeys = usePasskeys;
3847
3970
  exports.usePasswordReset = usePasswordReset;
3848
3971
  exports.usePasswordToggle = usePasswordToggle;
3849
3972
  exports.usePaymentProviders = usePaymentProviders;
3973
+ exports.usePayphoneCheckout = usePayphoneCheckout;
3850
3974
  exports.usePayphoneConfirm = usePayphoneConfirm;
3851
3975
  exports.usePlans = usePlans;
3852
3976
  exports.useReferral = useReferral;