@carlonicora/nextjs-jsonapi 1.28.0 → 1.29.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.
Files changed (95) hide show
  1. package/dist/{BlockNoteEditor-CAUNVZUF.js → BlockNoteEditor-YBVEOPV4.js} +13 -13
  2. package/dist/{BlockNoteEditor-CAUNVZUF.js.map → BlockNoteEditor-YBVEOPV4.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-EOA4OEVX.mjs → BlockNoteEditor-ZM4YPXHO.mjs} +3 -3
  4. package/dist/billing/index.d.mts +47 -17
  5. package/dist/billing/index.d.ts +47 -17
  6. package/dist/billing/index.js +1241 -1073
  7. package/dist/billing/index.js.map +1 -1
  8. package/dist/billing/index.mjs +1375 -1207
  9. package/dist/billing/index.mjs.map +1 -1
  10. package/dist/{chunk-IXI4GAKB.js → chunk-3X7EEFMN.js} +488 -431
  11. package/dist/chunk-3X7EEFMN.js.map +1 -0
  12. package/dist/{chunk-ORFXBO7F.mjs → chunk-DU64WMZD.mjs} +6 -3
  13. package/dist/chunk-DU64WMZD.mjs.map +1 -0
  14. package/dist/{chunk-TSEU4KZ2.js → chunk-J22NEVSK.js} +21 -18
  15. package/dist/chunk-J22NEVSK.js.map +1 -0
  16. package/dist/{chunk-PYASRX75.mjs → chunk-UCD5CUE4.mjs} +81 -24
  17. package/dist/chunk-UCD5CUE4.mjs.map +1 -0
  18. package/dist/client/index.d.mts +14 -5
  19. package/dist/client/index.d.ts +14 -5
  20. package/dist/client/index.js +5 -3
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/client/index.mjs +4 -2
  23. package/dist/components/index.d.mts +2 -2
  24. package/dist/components/index.d.ts +2 -2
  25. package/dist/components/index.js +3 -3
  26. package/dist/components/index.mjs +2 -2
  27. package/dist/{config-B4pZpLT9.d.ts → config-CHwoRDOp.d.ts} +1 -1
  28. package/dist/{config-DT1K-t6I.d.mts → config-DiWyJzk9.d.mts} +1 -1
  29. package/dist/{content.interface-B2Ldg0vg.d.mts → content.interface-BSpowEiW.d.mts} +1 -1
  30. package/dist/{content.interface-D8NHv3DX.d.ts → content.interface-DFQ7mkpL.d.ts} +1 -1
  31. package/dist/contexts/index.d.mts +2 -2
  32. package/dist/contexts/index.d.ts +2 -2
  33. package/dist/contexts/index.js +3 -3
  34. package/dist/contexts/index.mjs +2 -2
  35. package/dist/core/index.d.mts +39 -37
  36. package/dist/core/index.d.ts +39 -37
  37. package/dist/core/index.js +2 -2
  38. package/dist/core/index.mjs +1 -1
  39. package/dist/index.d.mts +4 -4
  40. package/dist/index.d.ts +4 -4
  41. package/dist/index.js +2 -2
  42. package/dist/index.mjs +1 -1
  43. package/dist/{notification.interface-H0L9WBge.d.ts → notification.interface-CmKmObIU.d.ts} +1 -0
  44. package/dist/{notification.interface-DEn-Yp_b.d.mts → notification.interface-D5MbtfZK.d.mts} +1 -0
  45. package/dist/{s3.service-BNytYanU.d.mts → s3.service-BMT7W6KS.d.mts} +19 -19
  46. package/dist/{s3.service-C7f_Ygz5.d.ts → s3.service-DsXo9nop.d.ts} +19 -19
  47. package/dist/server/index.d.mts +3 -3
  48. package/dist/server/index.d.ts +3 -3
  49. package/dist/server/index.js +3 -3
  50. package/dist/server/index.mjs +1 -1
  51. package/dist/{useSocket-BcnThTD0.d.mts → useSocket-DUqGoPya.d.mts} +1 -1
  52. package/dist/{useSocket-QZTOCzRF.d.ts → useSocket-QuHa0ZmO.d.ts} +1 -1
  53. package/package.json +1 -1
  54. package/src/client/index.ts +1 -0
  55. package/src/components/forms/FormSelect.tsx +2 -1
  56. package/src/features/auth/data/auth.ts +0 -2
  57. package/src/features/billing/components/containers/BillingDashboardContainer.tsx +60 -3
  58. package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +12 -152
  59. package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +168 -0
  60. package/src/features/billing/stripe-customer/components/forms/index.ts +1 -0
  61. package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +19 -1
  62. package/src/features/billing/stripe-product/components/forms/ProductEditor.tsx +2 -2
  63. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +24 -235
  64. package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +7 -18
  65. package/src/features/billing/stripe-subscription/components/forms/index.ts +0 -1
  66. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +10 -1
  67. package/src/features/billing/stripe-subscription/components/widgets/IntervalToggle.tsx +28 -0
  68. package/src/features/billing/stripe-subscription/components/widgets/ProductPricingList.tsx +128 -0
  69. package/src/features/billing/stripe-subscription/components/widgets/ProductPricingRow.tsx +54 -0
  70. package/src/features/billing/stripe-subscription/components/widgets/SubscriptionConfirmation.tsx +68 -0
  71. package/src/features/billing/stripe-subscription/components/widgets/index.ts +4 -1
  72. package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +114 -0
  73. package/src/features/billing/stripe-subscription/components/wizards/WizardProgressIndicator.tsx +66 -0
  74. package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +32 -0
  75. package/src/features/billing/stripe-subscription/components/wizards/WizardStepPlanSelection.tsx +103 -0
  76. package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +133 -0
  77. package/src/features/billing/stripe-subscription/components/wizards/index.ts +6 -0
  78. package/src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts +217 -0
  79. package/src/features/billing/stripe-subscription/index.ts +3 -2
  80. package/src/features/company/components/details/TokenStatusIndicator.tsx +19 -9
  81. package/src/features/company/data/company.interface.ts +2 -0
  82. package/src/features/company/data/company.ts +7 -0
  83. package/src/features/company/hooks/index.ts +1 -0
  84. package/src/features/company/hooks/useSubscriptionStatus.ts +71 -0
  85. package/src/features/user/components/forms/UserEditor.tsx +1 -1
  86. package/src/features/user/components/lists/AdminUsersList.tsx +1 -1
  87. package/src/features/user/contexts/CurrentUserContext.tsx +1 -1
  88. package/src/features/user/data/user.ts +1 -1
  89. package/dist/chunk-IXI4GAKB.js.map +0 -1
  90. package/dist/chunk-ORFXBO7F.mjs.map +0 -1
  91. package/dist/chunk-PYASRX75.mjs.map +0 -1
  92. package/dist/chunk-TSEU4KZ2.js.map +0 -1
  93. package/src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx +0 -331
  94. package/src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx +0 -110
  95. /package/dist/{BlockNoteEditor-EOA4OEVX.mjs.map → BlockNoteEditor-ZM4YPXHO.mjs.map} +0 -0
@@ -1,20 +1,13 @@
1
1
  "use client";
2
2
 
3
- import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
4
- import { useEffect, useState } from "react";
5
3
  import {
6
- Alert,
7
- AlertDescription,
8
- Button,
9
- Checkbox,
10
4
  Dialog,
11
5
  DialogContent,
12
6
  DialogDescription,
13
7
  DialogHeader,
14
8
  DialogTitle,
15
- Label,
16
9
  } from "../../../../../shadcnui";
17
- import { StripeCustomerService } from "../../data";
10
+ import { PaymentMethodForm } from "./PaymentMethodForm";
18
11
 
19
12
  type PaymentMethodEditorProps = {
20
13
  open: boolean;
@@ -23,86 +16,13 @@ type PaymentMethodEditorProps = {
23
16
  };
24
17
 
25
18
  export function PaymentMethodEditor({ open, onOpenChange, onSuccess }: PaymentMethodEditorProps) {
26
- const stripe = useStripe();
27
- const elements = useElements();
28
-
29
- const [setupIntent, setSetupIntent] = useState<{ clientSecret: string } | null>(null);
30
- const [loading, setLoading] = useState<boolean>(true);
31
- const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
32
- const [error, setError] = useState<string | null>(null);
33
- const [setAsDefault, setSetAsDefault] = useState<boolean>(true);
34
-
35
- // Fetch setup intent on component mount
36
- useEffect(() => {
37
- const fetchSetupIntent = async () => {
38
- setLoading(true);
39
- try {
40
- const intent = await StripeCustomerService.createSetupIntent();
41
- setSetupIntent(intent);
42
- } catch (err) {
43
- console.error("[PaymentMethodEditor] Failed to create setup intent:", err);
44
- setError("Failed to initialize payment form. Please try again.");
45
- } finally {
46
- setLoading(false);
47
- }
48
- };
49
-
50
- if (open) {
51
- fetchSetupIntent();
52
- }
53
- }, [open]);
54
-
55
- const handleSubmit = async (e: React.FormEvent) => {
56
- e.preventDefault();
57
-
58
- if (!stripe || !elements || !setupIntent) {
59
- return;
60
- }
61
-
62
- setIsSubmitting(true);
63
- setError(null);
64
-
65
- try {
66
- const cardElement = elements.getElement(CardElement);
67
- if (!cardElement) {
68
- throw new Error("Card element not found");
69
- }
70
-
71
- // Confirm card setup with Stripe
72
- const { error: stripeError, setupIntent: confirmedSetupIntent } = await stripe.confirmCardSetup(
73
- setupIntent.clientSecret,
74
- {
75
- payment_method: {
76
- card: cardElement,
77
- },
78
- },
79
- );
80
-
81
- if (stripeError) {
82
- console.error("[PaymentMethodEditor] Stripe error:", stripeError);
83
- setError(stripeError.message || "Failed to add payment method. Please check your card details.");
84
- setIsSubmitting(false);
85
- return;
86
- }
87
-
88
- // Set as default if checkbox is checked
89
- if (setAsDefault && confirmedSetupIntent?.payment_method) {
90
- await StripeCustomerService.setDefaultPaymentMethod({
91
- paymentMethodId:
92
- typeof confirmedSetupIntent.payment_method === "string"
93
- ? confirmedSetupIntent.payment_method
94
- : confirmedSetupIntent.payment_method.id,
95
- });
96
- }
19
+ const handleSuccess = () => {
20
+ onSuccess();
21
+ onOpenChange(false);
22
+ };
97
23
 
98
- onSuccess();
99
- onOpenChange(false);
100
- } catch (err: any) {
101
- console.error("[PaymentMethodEditor] Error:", err);
102
- setError(err.message || "An unexpected error occurred. Please try again.");
103
- } finally {
104
- setIsSubmitting(false);
105
- }
24
+ const handleCancel = () => {
25
+ onOpenChange(false);
106
26
  };
107
27
 
108
28
  return (
@@ -114,71 +34,11 @@ export function PaymentMethodEditor({ open, onOpenChange, onSuccess }: PaymentMe
114
34
  Add a new payment method to your account. Your card information is securely processed by Stripe.
115
35
  </DialogDescription>
116
36
  </DialogHeader>
117
-
118
- {loading && (
119
- <div className="flex items-center justify-center py-8">
120
- <p className="text-muted-foreground">Loading payment form...</p>
121
- </div>
122
- )}
123
-
124
- {!loading && setupIntent && (
125
- <form onSubmit={handleSubmit} className="flex flex-col gap-y-4">
126
- {/* Card Element */}
127
- <div className="rounded-md border border-gray-300 p-3">
128
- <CardElement
129
- options={{
130
- style: {
131
- base: {
132
- fontSize: "16px",
133
- color: "#424770",
134
- "::placeholder": {
135
- color: "#aab7c4",
136
- },
137
- },
138
- invalid: {
139
- color: "#9e2146",
140
- },
141
- },
142
- }}
143
- />
144
- </div>
145
-
146
- {/* Set as Default Checkbox */}
147
- <div className="flex items-center gap-x-2">
148
- <Checkbox
149
- id="setAsDefault"
150
- checked={setAsDefault}
151
- onCheckedChange={(checked) => setSetAsDefault(!!checked)}
152
- />
153
- <Label htmlFor="setAsDefault" className="text-sm font-normal">
154
- Set as default payment method
155
- </Label>
156
- </div>
157
-
158
- {/* Error Alert */}
159
- {error && (
160
- <Alert variant="destructive" className="bg-red-50 border-red-200">
161
- <AlertDescription>{error}</AlertDescription>
162
- </Alert>
163
- )}
164
-
165
- {/* Action Buttons */}
166
- <div className="flex justify-end gap-x-2">
167
- <Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={isSubmitting}>
168
- Cancel
169
- </Button>
170
- <Button type="submit" disabled={!stripe || isSubmitting}>
171
- {isSubmitting ? "Processing..." : "Add Card"}
172
- </Button>
173
- </div>
174
- </form>
175
- )}
176
-
177
- {/* Error State */}
178
- {!loading && !setupIntent && error && (
179
- <Alert variant="destructive" className="bg-red-50 border-red-200">
180
- <AlertDescription>{error}</AlertDescription>
181
- </Alert>
37
+ {open && (
38
+ <PaymentMethodForm
39
+ onSuccess={handleSuccess}
40
+ onCancel={handleCancel}
41
+ />
182
42
  )}
183
43
  </DialogContent>
184
44
  </Dialog>
@@ -0,0 +1,168 @@
1
+ "use client";
2
+
3
+ import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
4
+ import { useEffect, useState } from "react";
5
+ import {
6
+ Alert,
7
+ AlertDescription,
8
+ Button,
9
+ Checkbox,
10
+ Label,
11
+ } from "../../../../../shadcnui";
12
+ import { StripeCustomerService } from "../../data";
13
+
14
+ type PaymentMethodFormProps = {
15
+ onSuccess: () => void;
16
+ onCancel: () => void;
17
+ isLoading?: boolean;
18
+ };
19
+
20
+ export function PaymentMethodForm({ onSuccess, onCancel, isLoading = false }: PaymentMethodFormProps) {
21
+ const stripe = useStripe();
22
+ const elements = useElements();
23
+
24
+ const [setupIntent, setSetupIntent] = useState<{ clientSecret: string } | null>(null);
25
+ const [loading, setLoading] = useState<boolean>(true);
26
+ const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
27
+ const [error, setError] = useState<string | null>(null);
28
+ const [setAsDefault, setSetAsDefault] = useState<boolean>(true);
29
+
30
+ // Fetch setup intent on component mount
31
+ useEffect(() => {
32
+ const fetchSetupIntent = async () => {
33
+ setLoading(true);
34
+ try {
35
+ const intent = await StripeCustomerService.createSetupIntent();
36
+ setSetupIntent(intent);
37
+ } catch (err) {
38
+ console.error("[PaymentMethodForm] Failed to create setup intent:", err);
39
+ setError("Failed to initialize payment form. Please try again.");
40
+ } finally {
41
+ setLoading(false);
42
+ }
43
+ };
44
+
45
+ fetchSetupIntent();
46
+ }, []);
47
+
48
+ const handleSubmit = async (e: React.FormEvent) => {
49
+ e.preventDefault();
50
+
51
+ if (!stripe || !elements || !setupIntent) {
52
+ return;
53
+ }
54
+
55
+ setIsSubmitting(true);
56
+ setError(null);
57
+
58
+ try {
59
+ const cardElement = elements.getElement(CardElement);
60
+ if (!cardElement) {
61
+ throw new Error("Card element not found");
62
+ }
63
+
64
+ // Confirm card setup with Stripe
65
+ const { error: stripeError, setupIntent: confirmedSetupIntent } = await stripe.confirmCardSetup(
66
+ setupIntent.clientSecret,
67
+ {
68
+ payment_method: {
69
+ card: cardElement,
70
+ },
71
+ },
72
+ );
73
+
74
+ if (stripeError) {
75
+ console.error("[PaymentMethodForm] Stripe error:", stripeError);
76
+ setError(stripeError.message || "Failed to add payment method. Please check your card details.");
77
+ setIsSubmitting(false);
78
+ return;
79
+ }
80
+
81
+ // Set as default if checkbox is checked
82
+ if (setAsDefault && confirmedSetupIntent?.payment_method) {
83
+ await StripeCustomerService.setDefaultPaymentMethod({
84
+ paymentMethodId:
85
+ typeof confirmedSetupIntent.payment_method === "string"
86
+ ? confirmedSetupIntent.payment_method
87
+ : confirmedSetupIntent.payment_method.id,
88
+ });
89
+ }
90
+
91
+ onSuccess();
92
+ } catch (err: any) {
93
+ console.error("[PaymentMethodForm] Error:", err);
94
+ setError(err.message || "An unexpected error occurred. Please try again.");
95
+ } finally {
96
+ setIsSubmitting(false);
97
+ }
98
+ };
99
+
100
+ if (loading) {
101
+ return (
102
+ <div className="flex items-center justify-center py-8">
103
+ <p className="text-muted-foreground">Loading payment form...</p>
104
+ </div>
105
+ );
106
+ }
107
+
108
+ if (!setupIntent && error) {
109
+ return (
110
+ <Alert variant="destructive" className="bg-red-50 border-red-200">
111
+ <AlertDescription>{error}</AlertDescription>
112
+ </Alert>
113
+ );
114
+ }
115
+
116
+ return (
117
+ <form onSubmit={handleSubmit} className="flex flex-col gap-y-4">
118
+ {/* Card Element */}
119
+ <div className="rounded-md border border-gray-300 p-3">
120
+ <CardElement
121
+ options={{
122
+ style: {
123
+ base: {
124
+ fontSize: "16px",
125
+ color: "#424770",
126
+ "::placeholder": {
127
+ color: "#aab7c4",
128
+ },
129
+ },
130
+ invalid: {
131
+ color: "#9e2146",
132
+ },
133
+ },
134
+ }}
135
+ />
136
+ </div>
137
+
138
+ {/* Set as Default Checkbox */}
139
+ <div className="flex items-center gap-x-2">
140
+ <Checkbox
141
+ id="setAsDefault"
142
+ checked={setAsDefault}
143
+ onCheckedChange={(checked) => setSetAsDefault(!!checked)}
144
+ />
145
+ <Label htmlFor="setAsDefault" className="text-sm font-normal">
146
+ Set as default payment method
147
+ </Label>
148
+ </div>
149
+
150
+ {/* Error Alert */}
151
+ {error && (
152
+ <Alert variant="destructive" className="bg-red-50 border-red-200">
153
+ <AlertDescription>{error}</AlertDescription>
154
+ </Alert>
155
+ )}
156
+
157
+ {/* Action Buttons */}
158
+ <div className="flex justify-end gap-x-2">
159
+ <Button type="button" variant="outline" onClick={onCancel} disabled={isSubmitting || isLoading}>
160
+ Cancel
161
+ </Button>
162
+ <Button type="submit" disabled={!stripe || isSubmitting || isLoading}>
163
+ {isSubmitting ? "Processing..." : "Add Card"}
164
+ </Button>
165
+ </div>
166
+ </form>
167
+ );
168
+ }
@@ -1 +1,2 @@
1
1
  export * from "./PaymentMethodEditor";
2
+ export * from "./PaymentMethodForm";
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
4
  import { AlertCircle, PlusIcon, XIcon } from "lucide-react";
5
- import { useState } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import { SubmitHandler, useForm } from "react-hook-form";
7
7
  import { v4 } from "uuid";
8
8
  import { z } from "zod";
@@ -85,6 +85,24 @@ export function PriceEditor({ productId, price, open, onOpenChange, onSuccess }:
85
85
  },
86
86
  });
87
87
 
88
+ // Reset form when dialog opens to ensure fresh state
89
+ useEffect(() => {
90
+ if (open) {
91
+ form.reset({
92
+ unitAmount: price?.unitAmount ? price.unitAmount / 100 : 0,
93
+ currency: price?.currency || "usd",
94
+ interval: price?.priceType === "one_time" ? "one_time" : price?.recurring?.interval || "month",
95
+ intervalCount: price?.recurring?.intervalCount || 1,
96
+ usageType: price?.recurring?.usageType || "licensed",
97
+ nickname: price?.nickname || "",
98
+ active: price?.active ?? true,
99
+ description: price?.description || "",
100
+ features: price?.features || [],
101
+ token: price?.token?.toString() ?? "",
102
+ });
103
+ }
104
+ }, [open, price?.id]);
105
+
88
106
  const watchInterval = form.watch("interval");
89
107
  const isRecurring = watchInterval !== "one_time";
90
108
 
@@ -23,7 +23,7 @@ export function ProductEditor({ product, open, onOpenChange, onSuccess }: Produc
23
23
 
24
24
  const formSchema = z.object({
25
25
  name: z.string().min(1, { message: "Product name is required" }),
26
- description: z.string().optional(),
26
+ description: z.string().min(1, { message: "Description is required" }),
27
27
  active: z.boolean(),
28
28
  });
29
29
 
@@ -85,7 +85,7 @@ export function ProductEditor({ product, open, onOpenChange, onSuccess }: Produc
85
85
  form={form}
86
86
  id="description"
87
87
  name="Description"
88
- placeholder="Enter product description (optional)"
88
+ placeholder="Enter product description"
89
89
  className="min-h-32"
90
90
  />
91
91