@doujins/payments-ui 0.0.13 → 0.0.15

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/dist/index.d.cts CHANGED
@@ -623,6 +623,7 @@ interface PaymentExperienceProps {
623
623
  enableNewCard?: boolean;
624
624
  enableStoredMethods?: boolean;
625
625
  enableSolanaPay?: boolean;
626
+ enableAlternativePayments?: boolean;
626
627
  onSolanaSuccess?: (result: SubmitPaymentResponse | string) => void;
627
628
  onSolanaError?: (error: string) => void;
628
629
  initialMode?: 'cards' | 'solana';
package/dist/index.d.ts CHANGED
@@ -623,6 +623,7 @@ interface PaymentExperienceProps {
623
623
  enableNewCard?: boolean;
624
624
  enableStoredMethods?: boolean;
625
625
  enableSolanaPay?: boolean;
626
+ enableAlternativePayments?: boolean;
626
627
  onSolanaSuccess?: (result: SubmitPaymentResponse | string) => void;
627
628
  onSolanaError?: (error: string) => void;
628
629
  initialMode?: 'cards' | 'solana';
package/dist/index.js CHANGED
@@ -304,7 +304,7 @@ var SubscriptionService = class {
304
304
  );
305
305
  }
306
306
  async generateFlexFormUrl(payload) {
307
- return this.api.post("/subscriptions/flexform", {
307
+ return this.api.post(`/subscriptions/ccbill/flexform-url`, {
308
308
  body: { ...payload }
309
309
  });
310
310
  }
@@ -2487,6 +2487,143 @@ var SolanaPaymentView = ({
2487
2487
  renderBody()
2488
2488
  ] });
2489
2489
  };
2490
+ var useSubscriptionActions = () => {
2491
+ const { services } = usePaymentContext();
2492
+ const ensurePrice = (priceId) => {
2493
+ if (!priceId) {
2494
+ throw new Error("payments-ui: priceId is required for subscription actions");
2495
+ }
2496
+ return priceId;
2497
+ };
2498
+ const subscribeWithCard = useCallback(
2499
+ async ({
2500
+ priceId,
2501
+ processor = "nmi",
2502
+ provider,
2503
+ paymentToken,
2504
+ billing
2505
+ }) => {
2506
+ const payload = {
2507
+ priceId: ensurePrice(priceId),
2508
+ paymentToken,
2509
+ processor,
2510
+ provider,
2511
+ email: billing.email,
2512
+ firstName: billing.firstName,
2513
+ lastName: billing.lastName,
2514
+ address1: billing.address1,
2515
+ city: billing.city,
2516
+ state: billing.stateRegion,
2517
+ zipCode: billing.postalCode,
2518
+ country: billing.country
2519
+ };
2520
+ return services.subscriptions.subscribe("nmi", payload);
2521
+ },
2522
+ [services]
2523
+ );
2524
+ const subscribeWithSavedMethod = useCallback(
2525
+ async ({
2526
+ priceId,
2527
+ processor = "nmi",
2528
+ provider,
2529
+ paymentMethodId,
2530
+ email
2531
+ }) => {
2532
+ const payload = {
2533
+ priceId: ensurePrice(priceId),
2534
+ paymentMethodId,
2535
+ processor,
2536
+ provider,
2537
+ email
2538
+ };
2539
+ return services.subscriptions.subscribe("nmi", payload);
2540
+ },
2541
+ [services]
2542
+ );
2543
+ const subscribeWithCCBill = useCallback(
2544
+ async ({
2545
+ priceId,
2546
+ email,
2547
+ firstName,
2548
+ lastName,
2549
+ zipCode,
2550
+ country,
2551
+ processor = "ccbill"
2552
+ }) => {
2553
+ const payload = {
2554
+ priceId: ensurePrice(priceId),
2555
+ email,
2556
+ firstName,
2557
+ lastName,
2558
+ zipCode,
2559
+ country,
2560
+ processor
2561
+ };
2562
+ return services.subscriptions.subscribe("ccbill", payload);
2563
+ },
2564
+ [services]
2565
+ );
2566
+ const generateFlexFormUrl = useCallback(
2567
+ async ({
2568
+ priceId,
2569
+ firstName,
2570
+ lastName,
2571
+ address1,
2572
+ city,
2573
+ state,
2574
+ zipCode,
2575
+ country
2576
+ }) => {
2577
+ const payload = {
2578
+ price_id: ensurePrice(priceId),
2579
+ first_name: firstName,
2580
+ last_name: lastName,
2581
+ address1,
2582
+ city,
2583
+ state,
2584
+ zip_code: zipCode,
2585
+ country
2586
+ };
2587
+ return services.subscriptions.generateFlexFormUrl(payload);
2588
+ },
2589
+ [services]
2590
+ );
2591
+ return {
2592
+ subscribeWithCard,
2593
+ subscribeWithSavedMethod,
2594
+ subscribeWithCCBill,
2595
+ generateFlexFormUrl
2596
+ };
2597
+ };
2598
+
2599
+ // src/hooks/useAlternativePaymentProvider.ts
2600
+ var useAlternativePaymentProvider = () => {
2601
+ const [isLoading, setIsLoading] = useState(false);
2602
+ const [error, setError] = useState(null);
2603
+ const { generateFlexFormUrl } = useSubscriptionActions();
2604
+ const openFlexForm = useCallback(
2605
+ async (payload) => {
2606
+ setIsLoading(true);
2607
+ setError(null);
2608
+ try {
2609
+ const response = await generateFlexFormUrl(payload);
2610
+ if (response?.iframe_url) {
2611
+ window.location.href = response.iframe_url;
2612
+ } else {
2613
+ throw new Error("Unable to launch payment provider.");
2614
+ }
2615
+ } catch (err) {
2616
+ const message = err instanceof Error ? err.message : "Failed to open payment provider.";
2617
+ setError(message);
2618
+ console.error("[payments-ui] failed to open alternative payment provider", err);
2619
+ } finally {
2620
+ setIsLoading(false);
2621
+ }
2622
+ },
2623
+ [generateFlexFormUrl]
2624
+ );
2625
+ return { openFlexForm, isLoading, error };
2626
+ };
2490
2627
  var PaymentExperience = ({
2491
2628
  priceId,
2492
2629
  usdAmount,
@@ -2495,6 +2632,7 @@ var PaymentExperience = ({
2495
2632
  enableNewCard = true,
2496
2633
  enableStoredMethods = true,
2497
2634
  enableSolanaPay = true,
2635
+ enableAlternativePayments = true,
2498
2636
  onSolanaSuccess,
2499
2637
  onSolanaError,
2500
2638
  initialMode = "cards"
@@ -2511,7 +2649,14 @@ var PaymentExperience = ({
2511
2649
  const [savedError, setSavedError] = useState(null);
2512
2650
  const [newCardStatus, setNewCardStatus] = useState("idle");
2513
2651
  const [newCardError, setNewCardError] = useState(null);
2652
+ const [billingDetails, setBillingDetails] = useState(null);
2653
+ const [alternativePaymentError, setAlternativePaymentError] = useState(null);
2514
2654
  const { notifyStatus, notifySuccess, notifyError } = usePaymentNotifications();
2655
+ const {
2656
+ openFlexForm,
2657
+ isLoading: flexFormLoading,
2658
+ error: flexFormError
2659
+ } = useAlternativePaymentProvider();
2515
2660
  useEffect(() => {
2516
2661
  setActiveTab(showStored ? "saved" : "new");
2517
2662
  }, [showStored]);
@@ -2591,6 +2736,48 @@ var PaymentExperience = ({
2591
2736
  },
2592
2737
  [onSolanaError]
2593
2738
  );
2739
+ const handleAlternativePayment = useCallback(() => {
2740
+ if (!enableAlternativePayments || !priceId) {
2741
+ return;
2742
+ }
2743
+ if (!billingDetails) {
2744
+ setAlternativePaymentError("Enter your billing details first.");
2745
+ return;
2746
+ }
2747
+ const requiredFields = [
2748
+ "firstName",
2749
+ "lastName",
2750
+ "address1",
2751
+ "city",
2752
+ "stateRegion",
2753
+ "postalCode",
2754
+ "country"
2755
+ ];
2756
+ const missingField = requiredFields.find((field) => {
2757
+ const value = billingDetails[field];
2758
+ return typeof value !== "string" || value.trim().length === 0;
2759
+ });
2760
+ if (missingField) {
2761
+ setAlternativePaymentError("Please complete your billing address before continuing.");
2762
+ return;
2763
+ }
2764
+ setAlternativePaymentError(null);
2765
+ openFlexForm({
2766
+ priceId,
2767
+ firstName: billingDetails.firstName,
2768
+ lastName: billingDetails.lastName,
2769
+ address1: billingDetails.address1,
2770
+ city: billingDetails.city,
2771
+ state: billingDetails.stateRegion ?? "",
2772
+ zipCode: billingDetails.postalCode,
2773
+ country: billingDetails.country
2774
+ });
2775
+ }, [
2776
+ billingDetails,
2777
+ enableAlternativePayments,
2778
+ openFlexForm,
2779
+ priceId
2780
+ ]);
2594
2781
  const renderSavedTab = () => {
2595
2782
  if (!showStored) {
2596
2783
  return /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Saved payment methods are unavailable right now. Add a new card to get started." });
@@ -2629,7 +2816,8 @@ var PaymentExperience = ({
2629
2816
  submitLabel: "Pay now",
2630
2817
  externalError: newCardError,
2631
2818
  onTokenize: handleNewCardTokenize,
2632
- submitting: newCardStatus === "processing"
2819
+ submitting: newCardStatus === "processing",
2820
+ onBillingChange: setBillingDetails
2633
2821
  }
2634
2822
  );
2635
2823
  };
@@ -2657,6 +2845,19 @@ var PaymentExperience = ({
2657
2845
  ] });
2658
2846
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6 pt-4", children: [
2659
2847
  mode === "cards" && renderCardExperience(),
2848
+ mode === "cards" && enableAlternativePayments && /* @__PURE__ */ jsxs("div", { className: "space-y-2 text-center text-sm text-muted-foreground", children: [
2849
+ /* @__PURE__ */ jsx(
2850
+ "button",
2851
+ {
2852
+ type: "button",
2853
+ className: "text-primary underline-offset-4 hover:underline disabled:opacity-60",
2854
+ onClick: handleAlternativePayment,
2855
+ disabled: flexFormLoading || !priceId,
2856
+ children: flexFormLoading ? "Preparing alternative checkout\u2026" : "Prefer a different processor? Pay with CCBill"
2857
+ }
2858
+ ),
2859
+ (alternativePaymentError || flexFormError) && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: alternativePaymentError || flexFormError })
2860
+ ] }),
2660
2861
  mode === "solana" && enableSolanaPay && /* @__PURE__ */ jsx(
2661
2862
  SolanaPaymentView,
2662
2863
  {
@@ -2697,114 +2898,6 @@ var SubscriptionSuccessDialog = ({
2697
2898
  /* @__PURE__ */ jsx("div", { className: "px-6 py-6", children: /* @__PURE__ */ jsx(Button, { className: "w-full", onClick: onClose, children: "Continue exploring" }) })
2698
2899
  ] }) });
2699
2900
  };
2700
- var useSubscriptionActions = () => {
2701
- const { services } = usePaymentContext();
2702
- const ensurePrice = (priceId) => {
2703
- if (!priceId) {
2704
- throw new Error("payments-ui: priceId is required for subscription actions");
2705
- }
2706
- return priceId;
2707
- };
2708
- const subscribeWithCard = useCallback(
2709
- async ({
2710
- priceId,
2711
- processor = "nmi",
2712
- provider,
2713
- paymentToken,
2714
- billing
2715
- }) => {
2716
- const payload = {
2717
- priceId: ensurePrice(priceId),
2718
- paymentToken,
2719
- processor,
2720
- provider,
2721
- email: billing.email,
2722
- firstName: billing.firstName,
2723
- lastName: billing.lastName,
2724
- address1: billing.address1,
2725
- city: billing.city,
2726
- state: billing.stateRegion,
2727
- zipCode: billing.postalCode,
2728
- country: billing.country
2729
- };
2730
- return services.subscriptions.subscribe("nmi", payload);
2731
- },
2732
- [services]
2733
- );
2734
- const subscribeWithSavedMethod = useCallback(
2735
- async ({
2736
- priceId,
2737
- processor = "nmi",
2738
- provider,
2739
- paymentMethodId,
2740
- email
2741
- }) => {
2742
- const payload = {
2743
- priceId: ensurePrice(priceId),
2744
- paymentMethodId,
2745
- processor,
2746
- provider,
2747
- email
2748
- };
2749
- return services.subscriptions.subscribe("nmi", payload);
2750
- },
2751
- [services]
2752
- );
2753
- const subscribeWithCCBill = useCallback(
2754
- async ({
2755
- priceId,
2756
- email,
2757
- firstName,
2758
- lastName,
2759
- zipCode,
2760
- country,
2761
- processor = "ccbill"
2762
- }) => {
2763
- const payload = {
2764
- priceId: ensurePrice(priceId),
2765
- email,
2766
- firstName,
2767
- lastName,
2768
- zipCode,
2769
- country,
2770
- processor
2771
- };
2772
- return services.subscriptions.subscribe("ccbill", payload);
2773
- },
2774
- [services]
2775
- );
2776
- const generateFlexFormUrl = useCallback(
2777
- async ({
2778
- priceId,
2779
- firstName,
2780
- lastName,
2781
- address1,
2782
- city,
2783
- state,
2784
- zipCode,
2785
- country
2786
- }) => {
2787
- const payload = {
2788
- price_id: ensurePrice(priceId),
2789
- first_name: firstName,
2790
- last_name: lastName,
2791
- address1,
2792
- city,
2793
- state,
2794
- zip_code: zipCode,
2795
- country
2796
- };
2797
- return services.subscriptions.generateFlexFormUrl(payload);
2798
- },
2799
- [services]
2800
- );
2801
- return {
2802
- subscribeWithCard,
2803
- subscribeWithSavedMethod,
2804
- subscribeWithCCBill,
2805
- generateFlexFormUrl
2806
- };
2807
- };
2808
2901
  var SubscriptionCheckoutModal = ({
2809
2902
  open,
2810
2903
  onOpenChange,
@@ -4852,33 +4945,6 @@ var usePaymentStatus = (options = {}) => {
4852
4945
  isPending: getConfirmationStatus() === "pending"
4853
4946
  };
4854
4947
  };
4855
- var useAlternativePaymentProvider = () => {
4856
- const [isLoading, setIsLoading] = useState(false);
4857
- const [error, setError] = useState(null);
4858
- const { generateFlexFormUrl } = useSubscriptionActions();
4859
- const openFlexForm = useCallback(
4860
- async (payload) => {
4861
- setIsLoading(true);
4862
- setError(null);
4863
- try {
4864
- const response = await generateFlexFormUrl(payload);
4865
- if (response?.iframe_url) {
4866
- window.location.href = response.iframe_url;
4867
- } else {
4868
- throw new Error("Unable to launch payment provider.");
4869
- }
4870
- } catch (err) {
4871
- const message = err instanceof Error ? err.message : "Failed to open payment provider.";
4872
- setError(message);
4873
- console.error("[payments-ui] failed to open alternative payment provider", err);
4874
- } finally {
4875
- setIsLoading(false);
4876
- }
4877
- },
4878
- [generateFlexFormUrl]
4879
- );
4880
- return { openFlexForm, isLoading, error };
4881
- };
4882
4948
 
4883
4949
  export { BillingHistory, CancelMembershipDialog, CardDetailsForm, CardPaymentService, EmptyWalletState, PaymentApp, PaymentExperience, PaymentMethodService, PaymentMethodsSection, PaymentProvider, PaymentsDialogProvider, PaymentsRuntime, SolanaPaymentSelector, SolanaPaymentService, SolanaPaymentView, SolanaWalletSection, SolanaWalletService, StoredPaymentMethods, SubscriptionCheckoutModal, SubscriptionService, SubscriptionSuccessDialog, TokenCatalog, WalletCard, WalletDialog, WalletGateway, WalletManagement, WalletModal, createPaymentsRuntime, useAlternativePaymentProvider, useDirectWalletPayment, usePaymentContext, usePaymentDialogs, usePaymentMethodService, usePaymentMethods, usePaymentNotifications, usePaymentStatus, useSolanaDirectPayment, useSolanaQrPayment, useSolanaService, useSubscriptionActions, useSupportedTokens, useTokenBalance, useWalletConnection, useWalletList, useWalletVerification };
4884
4950
  //# sourceMappingURL=index.js.map