@doujins/payments-ui 0.0.9 → 0.0.11

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.cjs CHANGED
@@ -1848,13 +1848,10 @@ var useSolanaQrPayment = (options) => {
1848
1848
  const resetState = React3.useCallback(
1849
1849
  (message) => {
1850
1850
  clearTimers();
1851
- setIntent((prev) => prev ? null : prev);
1852
- setQrDataUri((prev) => prev ? null : prev);
1853
- setTimeRemaining((prev) => prev !== 0 ? 0 : prev);
1854
- setError((prev) => {
1855
- const next = message === void 0 ? null : message;
1856
- return prev === next ? prev : next;
1857
- });
1851
+ setIntent(null);
1852
+ setQrDataUri(null);
1853
+ setTimeRemaining(0);
1854
+ setError(message ?? null);
1858
1855
  },
1859
1856
  [clearTimers]
1860
1857
  );
@@ -2688,6 +2685,245 @@ var PaymentExperience = ({
2688
2685
  )
2689
2686
  ] });
2690
2687
  };
2688
+ var SubscriptionSuccessDialog = ({
2689
+ open,
2690
+ planName = "Premium Plan",
2691
+ amountLabel = "$0.00",
2692
+ billingPeriodLabel = "billing period",
2693
+ onClose
2694
+ }) => {
2695
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: (value) => {
2696
+ if (!value) onClose();
2697
+ }, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-w-sm text-center", children: [
2698
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
2699
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex flex-col items-center gap-3 text-foreground", children: [
2700
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-10 w-10 text-primary" }),
2701
+ "Subscription activated"
2702
+ ] }),
2703
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogDescription, { className: "text-base text-muted-foreground", children: [
2704
+ "You now have access to ",
2705
+ planName,
2706
+ ". Billing: ",
2707
+ amountLabel,
2708
+ " / ",
2709
+ billingPeriodLabel,
2710
+ "."
2711
+ ] })
2712
+ ] }),
2713
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { className: "mt-6 w-full", onClick: onClose, children: "Continue" })
2714
+ ] }) });
2715
+ };
2716
+ var useSubscriptionActions = () => {
2717
+ const { services } = usePaymentContext();
2718
+ const ensurePrice = (priceId) => {
2719
+ if (!priceId) {
2720
+ throw new Error("payments-ui: priceId is required for subscription actions");
2721
+ }
2722
+ return priceId;
2723
+ };
2724
+ const subscribeWithCard = React3.useCallback(
2725
+ async ({
2726
+ priceId,
2727
+ processor = "nmi",
2728
+ provider,
2729
+ paymentToken,
2730
+ billing
2731
+ }) => {
2732
+ const payload = {
2733
+ priceId: ensurePrice(priceId),
2734
+ paymentToken,
2735
+ processor,
2736
+ provider,
2737
+ email: billing.email,
2738
+ firstName: billing.firstName,
2739
+ lastName: billing.lastName,
2740
+ address1: billing.address1,
2741
+ city: billing.city,
2742
+ state: billing.stateRegion,
2743
+ zipCode: billing.postalCode,
2744
+ country: billing.country
2745
+ };
2746
+ return services.subscriptions.subscribe("nmi", payload);
2747
+ },
2748
+ [services]
2749
+ );
2750
+ const subscribeWithSavedMethod = React3.useCallback(
2751
+ async ({
2752
+ priceId,
2753
+ processor = "nmi",
2754
+ provider,
2755
+ paymentMethodId,
2756
+ email
2757
+ }) => {
2758
+ const payload = {
2759
+ priceId: ensurePrice(priceId),
2760
+ paymentMethodId,
2761
+ processor,
2762
+ provider,
2763
+ email
2764
+ };
2765
+ return services.subscriptions.subscribe("nmi", payload);
2766
+ },
2767
+ [services]
2768
+ );
2769
+ const subscribeWithCCBill = React3.useCallback(
2770
+ async ({
2771
+ priceId,
2772
+ email,
2773
+ firstName,
2774
+ lastName,
2775
+ zipCode,
2776
+ country,
2777
+ processor = "ccbill"
2778
+ }) => {
2779
+ const payload = {
2780
+ priceId: ensurePrice(priceId),
2781
+ email,
2782
+ firstName,
2783
+ lastName,
2784
+ zipCode,
2785
+ country,
2786
+ processor
2787
+ };
2788
+ return services.subscriptions.subscribe("ccbill", payload);
2789
+ },
2790
+ [services]
2791
+ );
2792
+ const generateFlexFormUrl = React3.useCallback(
2793
+ async ({
2794
+ priceId,
2795
+ firstName,
2796
+ lastName,
2797
+ address1,
2798
+ city,
2799
+ state,
2800
+ zipCode,
2801
+ country
2802
+ }) => {
2803
+ const payload = {
2804
+ price_id: ensurePrice(priceId),
2805
+ first_name: firstName,
2806
+ last_name: lastName,
2807
+ address1,
2808
+ city,
2809
+ state,
2810
+ zip_code: zipCode,
2811
+ country
2812
+ };
2813
+ return services.subscriptions.generateFlexFormUrl(payload);
2814
+ },
2815
+ [services]
2816
+ );
2817
+ return {
2818
+ subscribeWithCard,
2819
+ subscribeWithSavedMethod,
2820
+ subscribeWithCCBill,
2821
+ generateFlexFormUrl
2822
+ };
2823
+ };
2824
+ var SubscriptionCheckoutModal = ({
2825
+ open,
2826
+ onOpenChange,
2827
+ priceId,
2828
+ usdAmount = 0,
2829
+ planName,
2830
+ amountLabel,
2831
+ billingPeriodLabel,
2832
+ userEmail,
2833
+ provider = "mobius",
2834
+ onSuccess,
2835
+ enableSolanaPay = true
2836
+ }) => {
2837
+ const [showSuccess, setShowSuccess] = React3.useState(false);
2838
+ const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
2839
+ const handleClose = React3.useCallback(
2840
+ (nextOpen) => {
2841
+ onOpenChange(nextOpen);
2842
+ if (!nextOpen) {
2843
+ setShowSuccess(false);
2844
+ }
2845
+ },
2846
+ [onOpenChange]
2847
+ );
2848
+ const ensurePrice = () => {
2849
+ if (!priceId) {
2850
+ throw new Error("Select a plan before subscribing.");
2851
+ }
2852
+ return priceId;
2853
+ };
2854
+ const notifySuccess = (result) => {
2855
+ setShowSuccess(true);
2856
+ onSuccess?.();
2857
+ if (result && typeof window !== "undefined") {
2858
+ console.debug("[payments-ui] subscription success", result);
2859
+ }
2860
+ };
2861
+ const handleNewCardPayment = async ({ token, billing }) => {
2862
+ await subscribeWithCard({
2863
+ priceId: ensurePrice(),
2864
+ provider,
2865
+ paymentToken: token,
2866
+ billing
2867
+ });
2868
+ notifySuccess();
2869
+ };
2870
+ const handleSavedMethodPayment = async ({ paymentMethodId }) => {
2871
+ await subscribeWithSavedMethod({
2872
+ priceId: ensurePrice(),
2873
+ provider,
2874
+ paymentMethodId,
2875
+ email: userEmail ?? ""
2876
+ });
2877
+ notifySuccess();
2878
+ };
2879
+ const solanaSuccess = (result) => {
2880
+ notifySuccess(result);
2881
+ onOpenChange(false);
2882
+ };
2883
+ const summary = React3.useMemo(() => {
2884
+ if (!planName && !amountLabel) return null;
2885
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border/60 bg-muted/10 p-3 text-sm text-muted-foreground", children: [
2886
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-foreground", children: planName ?? "Selected plan" }),
2887
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
2888
+ amountLabel ?? `$${usdAmount.toFixed(2)}`,
2889
+ " ",
2890
+ billingPeriodLabel ? `/ ${billingPeriodLabel}` : ""
2891
+ ] })
2892
+ ] });
2893
+ }, [planName, amountLabel, billingPeriodLabel, usdAmount]);
2894
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2895
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-3xl", children: [
2896
+ !priceId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 flex items-center gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
2897
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
2898
+ " Select a subscription plan to continue."
2899
+ ] }),
2900
+ /* @__PURE__ */ jsxRuntime.jsx(
2901
+ PaymentExperience,
2902
+ {
2903
+ priceId: priceId ?? "",
2904
+ usdAmount,
2905
+ checkoutSummary: summary,
2906
+ onNewCardPayment: priceId ? handleNewCardPayment : void 0,
2907
+ onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
2908
+ enableNewCard: Boolean(priceId),
2909
+ enableStoredMethods: Boolean(priceId),
2910
+ enableSolanaPay: enableSolanaPay && Boolean(priceId),
2911
+ onSolanaSuccess: solanaSuccess
2912
+ }
2913
+ )
2914
+ ] }) }),
2915
+ /* @__PURE__ */ jsxRuntime.jsx(
2916
+ SubscriptionSuccessDialog,
2917
+ {
2918
+ open: showSuccess,
2919
+ onClose: () => setShowSuccess(false),
2920
+ planName,
2921
+ amountLabel: amountLabel ?? `$${usdAmount.toFixed(2)}`,
2922
+ billingPeriodLabel
2923
+ }
2924
+ )
2925
+ ] });
2926
+ };
2691
2927
  var useTokenBalance = (tokens) => {
2692
2928
  const { publicKey } = walletAdapterReact.useWallet();
2693
2929
  const { connection } = walletAdapterReact.useConnection();
@@ -3179,113 +3415,32 @@ var usePaymentStatus = (options = {}) => {
3179
3415
  isPending: getConfirmationStatus() === "pending"
3180
3416
  };
3181
3417
  };
3182
- var useSubscriptionActions = () => {
3183
- const { services } = usePaymentContext();
3184
- const ensurePrice = (priceId) => {
3185
- if (!priceId) {
3186
- throw new Error("payments-ui: priceId is required for subscription actions");
3187
- }
3188
- return priceId;
3189
- };
3190
- const subscribeWithCard = React3.useCallback(
3191
- async ({
3192
- priceId,
3193
- processor = "nmi",
3194
- provider,
3195
- paymentToken,
3196
- billing
3197
- }) => {
3198
- const payload = {
3199
- priceId: ensurePrice(priceId),
3200
- paymentToken,
3201
- processor,
3202
- provider,
3203
- email: billing.email,
3204
- firstName: billing.firstName,
3205
- lastName: billing.lastName,
3206
- address1: billing.address1,
3207
- city: billing.city,
3208
- state: billing.stateRegion,
3209
- zipCode: billing.postalCode,
3210
- country: billing.country
3211
- };
3212
- return services.subscriptions.subscribe("nmi", payload);
3213
- },
3214
- [services]
3215
- );
3216
- const subscribeWithSavedMethod = React3.useCallback(
3217
- async ({
3218
- priceId,
3219
- processor = "nmi",
3220
- provider,
3221
- paymentMethodId,
3222
- email
3223
- }) => {
3224
- const payload = {
3225
- priceId: ensurePrice(priceId),
3226
- paymentMethodId,
3227
- processor,
3228
- provider,
3229
- email
3230
- };
3231
- return services.subscriptions.subscribe("nmi", payload);
3232
- },
3233
- [services]
3234
- );
3235
- const subscribeWithCCBill = React3.useCallback(
3236
- async ({
3237
- priceId,
3238
- email,
3239
- firstName,
3240
- lastName,
3241
- zipCode,
3242
- country,
3243
- processor = "ccbill"
3244
- }) => {
3245
- const payload = {
3246
- priceId: ensurePrice(priceId),
3247
- email,
3248
- firstName,
3249
- lastName,
3250
- zipCode,
3251
- country,
3252
- processor
3253
- };
3254
- return services.subscriptions.subscribe("ccbill", payload);
3255
- },
3256
- [services]
3257
- );
3258
- const generateFlexFormUrl = React3.useCallback(
3259
- async ({
3260
- priceId,
3261
- firstName,
3262
- lastName,
3263
- address1,
3264
- city,
3265
- state,
3266
- zipCode,
3267
- country
3268
- }) => {
3269
- const payload = {
3270
- price_id: ensurePrice(priceId),
3271
- first_name: firstName,
3272
- last_name: lastName,
3273
- address1,
3274
- city,
3275
- state,
3276
- zip_code: zipCode,
3277
- country
3278
- };
3279
- return services.subscriptions.generateFlexFormUrl(payload);
3418
+ var useAlternativePaymentProvider = () => {
3419
+ const [isLoading, setIsLoading] = React3.useState(false);
3420
+ const [error, setError] = React3.useState(null);
3421
+ const { generateFlexFormUrl } = useSubscriptionActions();
3422
+ const openFlexForm = React3.useCallback(
3423
+ async (payload) => {
3424
+ setIsLoading(true);
3425
+ setError(null);
3426
+ try {
3427
+ const response = await generateFlexFormUrl(payload);
3428
+ if (response?.iframe_url) {
3429
+ window.location.href = response.iframe_url;
3430
+ } else {
3431
+ throw new Error("Unable to launch payment provider.");
3432
+ }
3433
+ } catch (err) {
3434
+ const message = err instanceof Error ? err.message : "Failed to open payment provider.";
3435
+ setError(message);
3436
+ console.error("[payments-ui] failed to open alternative payment provider", err);
3437
+ } finally {
3438
+ setIsLoading(false);
3439
+ }
3280
3440
  },
3281
- [services]
3441
+ [generateFlexFormUrl]
3282
3442
  );
3283
- return {
3284
- subscribeWithCard,
3285
- subscribeWithSavedMethod,
3286
- subscribeWithCCBill,
3287
- generateFlexFormUrl
3288
- };
3443
+ return { openFlexForm, isLoading, error };
3289
3444
  };
3290
3445
 
3291
3446
  exports.CardDetailsForm = CardDetailsForm;
@@ -3297,10 +3452,13 @@ exports.PaymentProvider = PaymentProvider;
3297
3452
  exports.SolanaPaymentSelector = SolanaPaymentSelector;
3298
3453
  exports.SolanaPaymentService = SolanaPaymentService;
3299
3454
  exports.StoredPaymentMethods = StoredPaymentMethods;
3455
+ exports.SubscriptionCheckoutModal = SubscriptionCheckoutModal;
3300
3456
  exports.SubscriptionService = SubscriptionService;
3457
+ exports.SubscriptionSuccessDialog = SubscriptionSuccessDialog;
3301
3458
  exports.TokenCatalog = TokenCatalog;
3302
3459
  exports.WalletGateway = WalletGateway;
3303
3460
  exports.createPaymentStore = createPaymentStore;
3461
+ exports.useAlternativePaymentProvider = useAlternativePaymentProvider;
3304
3462
  exports.useDirectWalletPayment = useDirectWalletPayment;
3305
3463
  exports.usePaymentContext = usePaymentContext;
3306
3464
  exports.usePaymentMethodService = usePaymentMethodService;