@carlonicora/nextjs-jsonapi 1.15.0 → 1.16.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 (271) hide show
  1. package/dist/{ApiResponseInterface-B4QdWh-y.d.mts → ApiResponseInterface-BvWIeLkq.d.ts} +2 -1
  2. package/dist/{ApiResponseInterface-QLDnxLA9.d.ts → ApiResponseInterface-CAbw0sv7.d.mts} +2 -1
  3. package/dist/{BlockNoteEditor-ITJLAOXC.mjs → BlockNoteEditor-HFX7Z5BQ.mjs} +5 -5
  4. package/dist/{BlockNoteEditor-FGXYUAWI.js → BlockNoteEditor-MBFDWP7X.js} +15 -15
  5. package/dist/{BlockNoteEditor-FGXYUAWI.js.map → BlockNoteEditor-MBFDWP7X.js.map} +1 -1
  6. package/dist/JsonApiRequest-45CLE65I.js +24 -0
  7. package/dist/{JsonApiRequest-FXZCYIER.js.map → JsonApiRequest-45CLE65I.js.map} +1 -1
  8. package/dist/{JsonApiRequest-HFWXMKMA.mjs → JsonApiRequest-6IPS3DZJ.mjs} +2 -2
  9. package/dist/{chunk-C6QXZGL7.js → chunk-2AZLCF6D.js} +1617 -158
  10. package/dist/chunk-2AZLCF6D.js.map +1 -0
  11. package/dist/{chunk-WAFOKMKT.mjs → chunk-5RAUCUAA.mjs} +3722 -396
  12. package/dist/chunk-5RAUCUAA.mjs.map +1 -0
  13. package/dist/{chunk-TGBXBUWM.mjs → chunk-BCKYJQ3K.mjs} +8 -1
  14. package/dist/chunk-BCKYJQ3K.mjs.map +1 -0
  15. package/dist/{chunk-JGVXZS7M.mjs → chunk-BCQSE3EU.mjs} +1588 -129
  16. package/dist/chunk-BCQSE3EU.mjs.map +1 -0
  17. package/dist/{chunk-FPZPD4JI.js → chunk-GPGJNTHP.js} +17 -10
  18. package/dist/chunk-GPGJNTHP.js.map +1 -0
  19. package/dist/{chunk-PK5DRSUD.js → chunk-ONB2DAIV.js} +4090 -764
  20. package/dist/chunk-ONB2DAIV.js.map +1 -0
  21. package/dist/{chunk-SJIVGCNM.mjs → chunk-POKIJ56Q.mjs} +7 -2
  22. package/dist/chunk-POKIJ56Q.mjs.map +1 -0
  23. package/dist/{chunk-6YD42BP6.js → chunk-R5QSSISB.js} +14 -9
  24. package/dist/chunk-R5QSSISB.js.map +1 -0
  25. package/dist/client/index.d.mts +5 -5
  26. package/dist/client/index.d.ts +5 -5
  27. package/dist/client/index.js +7 -5
  28. package/dist/client/index.js.map +1 -1
  29. package/dist/client/index.mjs +6 -4
  30. package/dist/components/index.d.mts +253 -9
  31. package/dist/components/index.d.ts +253 -9
  32. package/dist/components/index.js +83 -5
  33. package/dist/components/index.js.map +1 -1
  34. package/dist/components/index.mjs +82 -4
  35. package/dist/{config-eceYM5kN.d.ts → config-CWsTwnsK.d.mts} +7 -2
  36. package/dist/{config-C5tGGrYf.d.mts → config-DEaUbBqR.d.ts} +7 -2
  37. package/dist/{content.interface-TB2MfJGs.d.ts → content.interface-D_4b4RQt.d.ts} +1 -1
  38. package/dist/{content.interface-CxBBC7ec.d.mts → content.interface-Dk4UZcJM.d.mts} +1 -1
  39. package/dist/contexts/index.d.mts +2 -2
  40. package/dist/contexts/index.d.ts +2 -2
  41. package/dist/contexts/index.js +5 -5
  42. package/dist/contexts/index.mjs +4 -4
  43. package/dist/core/index.d.mts +521 -18
  44. package/dist/core/index.d.ts +521 -18
  45. package/dist/core/index.js +53 -3
  46. package/dist/core/index.js.map +1 -1
  47. package/dist/core/index.mjs +52 -2
  48. package/dist/index.d.mts +7 -7
  49. package/dist/index.d.ts +7 -7
  50. package/dist/index.js +56 -4
  51. package/dist/index.js.map +1 -1
  52. package/dist/index.mjs +55 -3
  53. package/dist/{notification.interface-lG6UpTpt.d.mts → notification.interface-BllkURRm.d.mts} +1 -2
  54. package/dist/{notification.interface-lG6UpTpt.d.ts → notification.interface-BllkURRm.d.ts} +1 -2
  55. package/dist/{s3.service-DP_hsssD.d.mts → s3.service-BEfGqho0.d.ts} +20 -2
  56. package/dist/{s3.service-Dq-PTUNa.d.ts → s3.service-DIQRYe93.d.mts} +20 -2
  57. package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
  58. package/dist/scripts/generate-web-module/generator.js +66 -0
  59. package/dist/scripts/generate-web-module/generator.js.map +1 -1
  60. package/dist/scripts/generate-web-module/templates/index.d.ts +8 -0
  61. package/dist/scripts/generate-web-module/templates/index.d.ts.map +1 -1
  62. package/dist/scripts/generate-web-module/templates/index.js +18 -1
  63. package/dist/scripts/generate-web-module/templates/index.js.map +1 -1
  64. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts +7 -0
  65. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts.map +1 -0
  66. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js +141 -0
  67. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js.map +1 -0
  68. package/dist/scripts/generate-web-module/templates/project/env.template.d.ts +7 -0
  69. package/dist/scripts/generate-web-module/templates/project/env.template.d.ts.map +1 -0
  70. package/dist/scripts/generate-web-module/templates/project/env.template.js +110 -0
  71. package/dist/scripts/generate-web-module/templates/project/env.template.js.map +1 -0
  72. package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts +7 -0
  73. package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts.map +1 -0
  74. package/dist/scripts/generate-web-module/templates/project/main-layout.template.js +101 -0
  75. package/dist/scripts/generate-web-module/templates/project/main-layout.template.js.map +1 -0
  76. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts +7 -0
  77. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts.map +1 -0
  78. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js +66 -0
  79. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js.map +1 -0
  80. package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts +7 -0
  81. package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts.map +1 -0
  82. package/dist/scripts/generate-web-module/templates/project/settings-container.template.js +257 -0
  83. package/dist/scripts/generate-web-module/templates/project/settings-container.template.js.map +1 -0
  84. package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts +7 -0
  85. package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts.map +1 -0
  86. package/dist/scripts/generate-web-module/templates/project/settings-context.template.js +124 -0
  87. package/dist/scripts/generate-web-module/templates/project/settings-context.template.js.map +1 -0
  88. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts +7 -0
  89. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts.map +1 -0
  90. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js +78 -0
  91. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js.map +1 -0
  92. package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts +7 -0
  93. package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts.map +1 -0
  94. package/dist/scripts/generate-web-module/templates/project/settings-page.template.js +75 -0
  95. package/dist/scripts/generate-web-module/templates/project/settings-page.template.js.map +1 -0
  96. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +1 -1
  97. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -1
  98. package/dist/server/index.d.mts +4 -4
  99. package/dist/server/index.d.ts +4 -4
  100. package/dist/server/index.js +12 -12
  101. package/dist/server/index.mjs +2 -2
  102. package/dist/stripe-subscription.interface-C63L6hVg.d.mts +226 -0
  103. package/dist/stripe-subscription.interface-CUvNDvw5.d.ts +226 -0
  104. package/dist/{useSocket-Bua6MwLi.d.mts → useSocket-BpenBR2z.d.mts} +1 -1
  105. package/dist/{useSocket-D5dhUp4m.d.ts → useSocket-D-QYA0Sr.d.ts} +1 -1
  106. package/package.json +9 -1
  107. package/scripts/generate-web-module/generator.ts +83 -0
  108. package/scripts/generate-web-module/templates/index.ts +10 -0
  109. package/scripts/generate-web-module/templates/project/bootstrapper.template.ts +108 -0
  110. package/scripts/generate-web-module/templates/project/env.template.ts +77 -0
  111. package/scripts/generate-web-module/templates/project/main-layout.template.tsx +68 -0
  112. package/scripts/generate-web-module/templates/project/middleware-env.template.ts +33 -0
  113. package/scripts/generate-web-module/templates/project/settings-container.template.tsx +224 -0
  114. package/scripts/generate-web-module/templates/project/settings-context.template.tsx +91 -0
  115. package/scripts/generate-web-module/templates/project/settings-module-page.template.tsx +45 -0
  116. package/scripts/generate-web-module/templates/project/settings-page.template.tsx +42 -0
  117. package/scripts/generate-web-module/types/template-data.interface.ts +1 -1
  118. package/src/client/config.ts +9 -0
  119. package/src/components/index.ts +7 -0
  120. package/src/core/abstracts/AbstractService.ts +104 -0
  121. package/src/core/endpoint/EndpointCreator.ts +7 -4
  122. package/src/core/index.ts +12 -4
  123. package/src/core/interfaces/ApiResponseInterface.ts +1 -0
  124. package/src/core/registry/ModuleRegistry.ts +11 -2
  125. package/src/core/utils/translateResponse.ts +17 -0
  126. package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +97 -0
  127. package/src/features/billing/components/cards/CustomerInfoCard.tsx +112 -0
  128. package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +114 -0
  129. package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +119 -0
  130. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +146 -0
  131. package/src/features/billing/components/cards/index.ts +5 -0
  132. package/src/features/billing/components/containers/BillingDashboardContainer.tsx +427 -0
  133. package/src/features/billing/components/containers/index.ts +1 -0
  134. package/src/features/billing/components/index.ts +6 -0
  135. package/src/features/billing/components/modals/BillingDetailModal.tsx +36 -0
  136. package/src/features/billing/components/modals/index.ts +1 -0
  137. package/src/features/billing/components/providers/StripeProvider.tsx +48 -0
  138. package/src/features/billing/components/providers/index.ts +1 -0
  139. package/src/features/billing/components/utils/currency.ts +49 -0
  140. package/src/features/billing/components/utils/date.ts +21 -0
  141. package/src/features/billing/components/utils/index.ts +2 -0
  142. package/src/features/billing/components/widgets/BillingAlertBanner.tsx +63 -0
  143. package/src/features/billing/components/widgets/index.ts +1 -0
  144. package/src/features/billing/data/Billing.ts +17 -0
  145. package/src/features/billing/data/billing.service.ts +58 -0
  146. package/src/features/billing/data/index.ts +5 -0
  147. package/src/features/billing/index.ts +3 -0
  148. package/src/features/billing/modules/billing.module.ts +9 -0
  149. package/src/features/billing/modules/index.ts +1 -0
  150. package/src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx +79 -0
  151. package/src/features/billing/stripe-customer/components/containers/index.ts +1 -0
  152. package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +151 -0
  153. package/src/features/billing/stripe-customer/components/details/index.ts +1 -0
  154. package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +186 -0
  155. package/src/features/billing/stripe-customer/components/forms/index.ts +1 -0
  156. package/src/features/billing/stripe-customer/components/index.ts +4 -0
  157. package/src/features/billing/stripe-customer/components/lists/PaymentMethodsList.tsx +19 -0
  158. package/src/features/billing/stripe-customer/components/lists/index.ts +1 -0
  159. package/src/features/billing/stripe-customer/data/index.ts +5 -0
  160. package/src/features/billing/stripe-customer/data/payment-method.interface.ts +27 -0
  161. package/src/features/billing/stripe-customer/data/payment-method.ts +119 -0
  162. package/src/features/billing/stripe-customer/data/stripe-customer.interface.ts +16 -0
  163. package/src/features/billing/stripe-customer/data/stripe-customer.service.ts +128 -0
  164. package/src/features/billing/stripe-customer/data/stripe-customer.ts +71 -0
  165. package/src/features/billing/stripe-customer/index.ts +3 -0
  166. package/src/features/billing/stripe-customer/stripe-customer.module.ts +9 -0
  167. package/src/features/billing/stripe-customer/stripe-payment-method.module.ts +9 -0
  168. package/src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx +66 -0
  169. package/src/features/billing/stripe-invoice/components/containers/index.ts +1 -0
  170. package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +172 -0
  171. package/src/features/billing/stripe-invoice/components/details/index.ts +1 -0
  172. package/src/features/billing/stripe-invoice/components/index.ts +4 -0
  173. package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +84 -0
  174. package/src/features/billing/stripe-invoice/components/lists/index.ts +1 -0
  175. package/src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx +41 -0
  176. package/src/features/billing/stripe-invoice/components/widgets/index.ts +1 -0
  177. package/src/features/billing/stripe-invoice/data/index.ts +3 -0
  178. package/src/features/billing/stripe-invoice/data/stripe-invoice.interface.ts +65 -0
  179. package/src/features/billing/stripe-invoice/data/stripe-invoice.service.ts +64 -0
  180. package/src/features/billing/stripe-invoice/data/stripe-invoice.ts +177 -0
  181. package/src/features/billing/stripe-invoice/index.ts +2 -0
  182. package/src/features/billing/stripe-invoice/stripe-invoice.module.ts +9 -0
  183. package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +304 -0
  184. package/src/features/billing/stripe-price/components/forms/index.ts +1 -0
  185. package/src/features/billing/stripe-price/components/index.ts +2 -0
  186. package/src/features/billing/stripe-price/components/lists/PricesList.tsx +283 -0
  187. package/src/features/billing/stripe-price/components/lists/index.ts +1 -0
  188. package/src/features/billing/stripe-price/data/index.ts +3 -0
  189. package/src/features/billing/stripe-price/data/stripe-price.interface.ts +48 -0
  190. package/src/features/billing/stripe-price/data/stripe-price.service.ts +123 -0
  191. package/src/features/billing/stripe-price/data/stripe-price.ts +156 -0
  192. package/src/features/billing/stripe-price/index.ts +2 -0
  193. package/src/features/billing/stripe-price/stripe-price.module.ts +9 -0
  194. package/src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx +86 -0
  195. package/src/features/billing/stripe-product/components/containers/index.ts +1 -0
  196. package/src/features/billing/stripe-product/components/forms/ProductEditor.tsx +100 -0
  197. package/src/features/billing/stripe-product/components/forms/index.ts +1 -0
  198. package/src/features/billing/stripe-product/components/index.ts +3 -0
  199. package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +206 -0
  200. package/src/features/billing/stripe-product/components/lists/index.ts +1 -0
  201. package/src/features/billing/stripe-product/data/index.ts +3 -0
  202. package/src/features/billing/stripe-product/data/stripe-product.interface.ts +18 -0
  203. package/src/features/billing/stripe-product/data/stripe-product.service.ts +112 -0
  204. package/src/features/billing/stripe-product/data/stripe-product.ts +74 -0
  205. package/src/features/billing/stripe-product/index.ts +2 -0
  206. package/src/features/billing/stripe-product/stripe-product.module.ts +9 -0
  207. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +304 -0
  208. package/src/features/billing/stripe-subscription/components/containers/index.ts +1 -0
  209. package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +223 -0
  210. package/src/features/billing/stripe-subscription/components/details/index.ts +1 -0
  211. package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +116 -0
  212. package/src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx +331 -0
  213. package/src/features/billing/stripe-subscription/components/forms/index.ts +2 -0
  214. package/src/features/billing/stripe-subscription/components/index.ts +5 -0
  215. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +104 -0
  216. package/src/features/billing/stripe-subscription/components/lists/index.ts +1 -0
  217. package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +95 -0
  218. package/src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx +110 -0
  219. package/src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx +41 -0
  220. package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +60 -0
  221. package/src/features/billing/stripe-subscription/components/widgets/index.ts +4 -0
  222. package/src/features/billing/stripe-subscription/data/index.ts +3 -0
  223. package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +66 -0
  224. package/src/features/billing/stripe-subscription/data/stripe-subscription.service.ts +193 -0
  225. package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +135 -0
  226. package/src/features/billing/stripe-subscription/hooks/index.ts +1 -0
  227. package/src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts +111 -0
  228. package/src/features/billing/stripe-subscription/index.ts +5 -0
  229. package/src/features/billing/stripe-subscription/stripe-subscription.module.ts +9 -0
  230. package/src/features/billing/stripe-usage/components/containers/UsageContainer.tsx +109 -0
  231. package/src/features/billing/stripe-usage/components/containers/index.ts +1 -0
  232. package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +90 -0
  233. package/src/features/billing/stripe-usage/components/details/index.ts +1 -0
  234. package/src/features/billing/stripe-usage/components/index.ts +4 -0
  235. package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +72 -0
  236. package/src/features/billing/stripe-usage/components/lists/index.ts +1 -0
  237. package/src/features/billing/stripe-usage/components/widgets/UsageSummaryCards.tsx +19 -0
  238. package/src/features/billing/stripe-usage/components/widgets/index.ts +1 -0
  239. package/src/features/billing/stripe-usage/data/index.ts +3 -0
  240. package/src/features/billing/stripe-usage/data/stripe-usage.interface.ts +55 -0
  241. package/src/features/billing/stripe-usage/data/stripe-usage.service.ts +129 -0
  242. package/src/features/billing/stripe-usage/data/stripe-usage.ts +70 -0
  243. package/src/features/billing/stripe-usage/index.ts +2 -0
  244. package/src/features/billing/stripe-usage/stripe-usage.module.ts +9 -0
  245. package/src/features/company/components/forms/CompanyEditor.tsx +2 -2
  246. package/src/features/company/contexts/CompanyContext.tsx +2 -2
  247. package/src/features/feature/components/forms/FormFeatures.tsx +13 -106
  248. package/src/features/feature/data/feature.interface.ts +1 -1
  249. package/src/features/feature/data/feature.ts +4 -4
  250. package/src/features/index.ts +7 -0
  251. package/src/features/module/data/module.interface.ts +0 -1
  252. package/src/features/module/data/module.ts +0 -6
  253. package/src/features/user/components/lists/ContributorsList.tsx +2 -2
  254. package/src/features/user/components/widgets/UserAvatar.tsx +1 -1
  255. package/src/index.ts +1 -1
  256. package/src/shadcnui/custom/link.tsx +16 -6
  257. package/src/utils/blocknote-diff.util.ts +2 -1
  258. package/src/utils/blocknote-word-diff-renderer.util.ts +8 -7
  259. package/dist/AuthComponent-hxOPs9o8.d.mts +0 -11
  260. package/dist/AuthComponent-hxOPs9o8.d.ts +0 -11
  261. package/dist/JsonApiRequest-FXZCYIER.js +0 -24
  262. package/dist/chunk-6YD42BP6.js.map +0 -1
  263. package/dist/chunk-C6QXZGL7.js.map +0 -1
  264. package/dist/chunk-FPZPD4JI.js.map +0 -1
  265. package/dist/chunk-JGVXZS7M.mjs.map +0 -1
  266. package/dist/chunk-PK5DRSUD.js.map +0 -1
  267. package/dist/chunk-SJIVGCNM.mjs.map +0 -1
  268. package/dist/chunk-TGBXBUWM.mjs.map +0 -1
  269. package/dist/chunk-WAFOKMKT.mjs.map +0 -1
  270. /package/dist/{BlockNoteEditor-ITJLAOXC.mjs.map → BlockNoteEditor-HFX7Z5BQ.mjs.map} +0 -0
  271. /package/dist/{JsonApiRequest-HFWXMKMA.mjs.map → JsonApiRequest-6IPS3DZJ.mjs.map} +0 -0
@@ -0,0 +1,41 @@
1
+ "use client";
2
+
3
+ import { ProrationPreviewInterface } from "../../../stripe-invoice/data/stripe-invoice.interface";
4
+ import { formatCurrency, formatDate } from "../../../components/utils";
5
+
6
+ type ProrationPreviewProps = {
7
+ preview: ProrationPreviewInterface;
8
+ };
9
+
10
+ export function ProrationPreview({ preview }: ProrationPreviewProps) {
11
+ return (
12
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
13
+ <h4 className="font-semibold text-blue-900 mb-3">Proration Breakdown</h4>
14
+
15
+ <div className="space-y-2">
16
+ {preview.lineItems.map((item, index) => (
17
+ <div key={index} className="flex justify-between text-sm">
18
+ <span className="text-blue-800">{item.description}</span>
19
+ <span className={`font-medium ${item.amount < 0 ? "text-green-600" : "text-blue-900"}`}>
20
+ {formatCurrency(item.amount, preview.currency)}
21
+ </span>
22
+ </div>
23
+ ))}
24
+
25
+ <div className="border-t border-blue-200 pt-2 mt-2">
26
+ <div className="flex justify-between font-semibold">
27
+ <span className="text-blue-900">Net Due Today</span>
28
+ <span className="text-blue-900">{formatCurrency(preview.immediateCharge, preview.currency)}</span>
29
+ </div>
30
+ </div>
31
+
32
+ {preview.lineItems.length > 0 && preview.lineItems[0].period && (
33
+ <div className="text-xs text-blue-700 mt-2">
34
+ Next invoice on {formatDate(preview.lineItems[0].period.end)} for{" "}
35
+ {formatCurrency(preview.amountDue, preview.currency)}
36
+ </div>
37
+ )}
38
+ </div>
39
+ </div>
40
+ );
41
+ }
@@ -0,0 +1,60 @@
1
+ "use client";
2
+
3
+ import { SubscriptionStatus } from "../../data";
4
+
5
+ type SubscriptionStatusBadgeProps = {
6
+ status: SubscriptionStatus;
7
+ cancelAtPeriodEnd?: boolean;
8
+ };
9
+
10
+ type StatusConfig = {
11
+ label: string;
12
+ color: string;
13
+ };
14
+
15
+ const statusConfig: Record<SubscriptionStatus, StatusConfig> = {
16
+ [SubscriptionStatus.ACTIVE]: {
17
+ label: "Active",
18
+ color: "bg-green-100 text-green-800",
19
+ },
20
+ [SubscriptionStatus.TRIALING]: {
21
+ label: "Trial",
22
+ color: "bg-blue-100 text-blue-800",
23
+ },
24
+ [SubscriptionStatus.PAST_DUE]: {
25
+ label: "Past Due",
26
+ color: "bg-red-100 text-red-800",
27
+ },
28
+ [SubscriptionStatus.CANCELED]: {
29
+ label: "Canceled",
30
+ color: "bg-gray-100 text-gray-800",
31
+ },
32
+ [SubscriptionStatus.PAUSED]: {
33
+ label: "Paused",
34
+ color: "bg-yellow-100 text-yellow-800",
35
+ },
36
+ [SubscriptionStatus.UNPAID]: {
37
+ label: "Unpaid",
38
+ color: "bg-orange-100 text-orange-800",
39
+ },
40
+ [SubscriptionStatus.INCOMPLETE]: {
41
+ label: "Incomplete",
42
+ color: "bg-gray-100 text-gray-800",
43
+ },
44
+ [SubscriptionStatus.INCOMPLETE_EXPIRED]: {
45
+ label: "Expired",
46
+ color: "bg-gray-100 text-gray-800",
47
+ },
48
+ };
49
+
50
+ const cancelingConfig: StatusConfig = {
51
+ label: "Canceling",
52
+ color: "bg-amber-100 text-amber-800",
53
+ };
54
+
55
+ export function SubscriptionStatusBadge({ status, cancelAtPeriodEnd }: SubscriptionStatusBadgeProps) {
56
+ // Show "Canceling" when subscription is set to cancel at period end
57
+ const config = cancelAtPeriodEnd ? cancelingConfig : statusConfig[status] || statusConfig[SubscriptionStatus.CANCELED];
58
+
59
+ return <span className={`${config.color} text-xs px-2 py-1 rounded-full font-medium`}>{config.label}</span>;
60
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./PricingCard";
2
+ export * from "./PricingCardsGrid";
3
+ export * from "./ProrationPreview";
4
+ export * from "./SubscriptionStatusBadge";
@@ -0,0 +1,3 @@
1
+ export * from "./stripe-subscription";
2
+ export * from "./stripe-subscription.interface";
3
+ export * from "./stripe-subscription.service";
@@ -0,0 +1,66 @@
1
+ // ============================================================================
2
+ // Subscription Enums
3
+ // ============================================================================
4
+
5
+ import { ApiDataInterface, StripePriceInterface } from "../../../../core";
6
+
7
+ export enum SubscriptionStatus {
8
+ ACTIVE = "active",
9
+ PAST_DUE = "past_due",
10
+ UNPAID = "unpaid",
11
+ CANCELED = "canceled",
12
+ INCOMPLETE = "incomplete",
13
+ INCOMPLETE_EXPIRED = "incomplete_expired",
14
+ TRIALING = "trialing",
15
+ PAUSED = "paused",
16
+ }
17
+
18
+ // ============================================================================
19
+ // Subscription Interfaces
20
+ // ============================================================================
21
+
22
+ export interface StripeSubscriptionInterface extends ApiDataInterface {
23
+ get stripeSubscriptionId(): string;
24
+ get status(): SubscriptionStatus;
25
+ get currentPeriodStart(): Date;
26
+ get currentPeriodEnd(): Date;
27
+ get cancelAtPeriodEnd(): boolean;
28
+ get canceledAt(): Date | undefined;
29
+ get trialStart(): Date | undefined;
30
+ get trialEnd(): Date | undefined;
31
+ get price(): StripePriceInterface | undefined;
32
+ }
33
+
34
+ // ============================================================================
35
+ // Subscription Input DTOs
36
+ // ============================================================================
37
+
38
+ export type StripeSubscriptionInput = {
39
+ id: string;
40
+ // For CREATE - goes to relationships.stripePrice
41
+ priceId?: string;
42
+ // For CHANGE-PLAN - goes to attributes.priceId
43
+ newPriceId?: string;
44
+ // For CANCEL - goes to attributes.cancelImmediately
45
+ cancelImmediately?: boolean;
46
+ // Shared optional fields
47
+ quantity?: number;
48
+ trialPeriodDays?: number;
49
+ paymentMethodId?: string;
50
+ metadata?: Record<string, any>;
51
+ };
52
+
53
+ // ============================================================================
54
+ // Subscription Response Types (for SCA payment confirmation)
55
+ // ============================================================================
56
+
57
+ export interface StripeSubscriptionCreateMeta {
58
+ clientSecret: string | null;
59
+ paymentIntentId: string | null;
60
+ requiresAction: boolean;
61
+ }
62
+
63
+ export interface StripeSubscriptionCreateResponse {
64
+ subscription: StripeSubscriptionInterface;
65
+ meta: StripeSubscriptionCreateMeta;
66
+ }
@@ -0,0 +1,193 @@
1
+ import { AbstractService, EndpointCreator, HttpMethod, Modules, NextRef, PreviousRef } from "../../../../core";
2
+ import { ProrationPreviewInterface } from "../../stripe-invoice/data/stripe-invoice.interface";
3
+ import {
4
+ StripeSubscriptionCreateMeta,
5
+ StripeSubscriptionCreateResponse,
6
+ StripeSubscriptionInput,
7
+ StripeSubscriptionInterface,
8
+ } from "./stripe-subscription.interface";
9
+
10
+ /**
11
+ * Customer-facing billing service for managing subscriptions, payments, and usage
12
+ */
13
+ export class StripeSubscriptionService extends AbstractService {
14
+ // ============================================================================
15
+ // Subscription Methods
16
+ // ============================================================================
17
+
18
+ /**
19
+ * List all subscriptions for the current user
20
+ */
21
+ static async listSubscriptions(params?: {
22
+ next?: NextRef;
23
+ prev?: PreviousRef;
24
+ }): Promise<StripeSubscriptionInterface[]> {
25
+ const endpoint = new EndpointCreator({
26
+ endpoint: Modules.StripeSubscription,
27
+ });
28
+
29
+ return this.callApi({
30
+ type: Modules.StripeSubscription,
31
+ method: HttpMethod.GET,
32
+ endpoint: endpoint.generate(),
33
+ next: params?.next,
34
+ previous: params?.prev,
35
+ });
36
+ }
37
+
38
+ /**
39
+ * Get a specific subscription by ID
40
+ */
41
+ static async getSubscription(params: { subscriptionId: string }): Promise<StripeSubscriptionInterface> {
42
+ const endpoint = new EndpointCreator({
43
+ endpoint: Modules.StripeSubscription,
44
+ id: params.subscriptionId,
45
+ });
46
+
47
+ return this.callApi<StripeSubscriptionInterface>({
48
+ type: Modules.StripeSubscription,
49
+ method: HttpMethod.GET,
50
+ endpoint: endpoint.generate(),
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Create a new subscription
56
+ * Returns subscription data along with meta containing SCA payment confirmation details
57
+ */
58
+ static async createSubscription(params: StripeSubscriptionInput): Promise<StripeSubscriptionCreateResponse> {
59
+ const endpoint = new EndpointCreator({
60
+ endpoint: Modules.StripeSubscription,
61
+ });
62
+
63
+ const result = await this.callApiWithMeta<StripeSubscriptionInterface>({
64
+ type: Modules.StripeSubscription,
65
+ method: HttpMethod.POST,
66
+ endpoint: endpoint.generate(),
67
+ input: params,
68
+ });
69
+
70
+ return {
71
+ subscription: result.data,
72
+ meta: (result.meta as StripeSubscriptionCreateMeta) ?? {
73
+ clientSecret: null,
74
+ paymentIntentId: null,
75
+ requiresAction: false,
76
+ },
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Change the plan of an existing subscription
82
+ */
83
+ static async changePlan(params: StripeSubscriptionInput): Promise<StripeSubscriptionInterface> {
84
+ const endpoint = new EndpointCreator({
85
+ endpoint: Modules.StripeSubscription,
86
+ id: params.id,
87
+ childEndpoint: "change-plan",
88
+ });
89
+
90
+ return this.callApi<StripeSubscriptionInterface>({
91
+ type: Modules.StripeSubscription,
92
+ method: HttpMethod.PUT,
93
+ endpoint: endpoint.generate(),
94
+ input: params,
95
+ });
96
+ }
97
+
98
+ /**
99
+ * Get a proration preview for a plan change
100
+ */
101
+ static async getProrationPreview(params: {
102
+ subscriptionId: string;
103
+ newPriceId: string;
104
+ quantity?: number;
105
+ }): Promise<ProrationPreviewInterface> {
106
+ const endpoint = new EndpointCreator({
107
+ endpoint: Modules.StripeSubscription,
108
+ id: params.subscriptionId,
109
+ childEndpoint: "proration-preview",
110
+ });
111
+
112
+ endpoint.addAdditionalParam("newPriceId", params.newPriceId);
113
+ if (params.quantity) {
114
+ endpoint.addAdditionalParam("quantity", params.quantity.toString());
115
+ }
116
+
117
+ return this.callApi({
118
+ type: Modules.StripeSubscription,
119
+ method: HttpMethod.GET,
120
+ endpoint: endpoint.generate(),
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Cancel a subscription
126
+ */
127
+ static async cancelSubscription(params: StripeSubscriptionInput): Promise<StripeSubscriptionInterface> {
128
+ const endpoint = new EndpointCreator({
129
+ endpoint: Modules.StripeSubscription,
130
+ id: params.id,
131
+ childEndpoint: "cancel",
132
+ });
133
+
134
+ return this.callApi<StripeSubscriptionInterface>({
135
+ type: Modules.StripeSubscription,
136
+ method: HttpMethod.POST,
137
+ endpoint: endpoint.generate(),
138
+ input: params,
139
+ });
140
+ }
141
+
142
+ /**
143
+ * Pause a subscription
144
+ */
145
+ static async pauseSubscription(params: { subscriptionId: string }): Promise<StripeSubscriptionInterface> {
146
+ const endpoint = new EndpointCreator({
147
+ endpoint: Modules.StripeSubscription,
148
+ id: params.subscriptionId,
149
+ childEndpoint: "pause",
150
+ });
151
+
152
+ return this.callApi<StripeSubscriptionInterface>({
153
+ type: Modules.StripeSubscription,
154
+ method: HttpMethod.POST,
155
+ endpoint: endpoint.generate(),
156
+ });
157
+ }
158
+
159
+ /**
160
+ * Resume a paused subscription
161
+ */
162
+ static async resumeSubscription(params: { subscriptionId: string }): Promise<StripeSubscriptionInterface> {
163
+ const endpoint = new EndpointCreator({
164
+ endpoint: Modules.StripeSubscription,
165
+ id: params.subscriptionId,
166
+ childEndpoint: "resume",
167
+ });
168
+
169
+ return this.callApi<StripeSubscriptionInterface>({
170
+ type: Modules.StripeSubscription,
171
+ method: HttpMethod.POST,
172
+ endpoint: endpoint.generate(),
173
+ });
174
+ }
175
+
176
+ /**
177
+ * Sync a subscription with the latest data from Stripe
178
+ * This is useful after payment confirmation to get the updated status
179
+ */
180
+ static async syncSubscription(params: { subscriptionId: string }): Promise<StripeSubscriptionInterface> {
181
+ const endpoint = new EndpointCreator({
182
+ endpoint: Modules.StripeSubscription,
183
+ id: params.subscriptionId,
184
+ childEndpoint: "sync",
185
+ });
186
+
187
+ return this.callApi<StripeSubscriptionInterface>({
188
+ type: Modules.StripeSubscription,
189
+ method: HttpMethod.POST,
190
+ endpoint: endpoint.generate(),
191
+ });
192
+ }
193
+ }
@@ -0,0 +1,135 @@
1
+ import { AbstractApiData, JsonApiHydratedDataInterface, Modules } from "../../../../core";
2
+ import { StripePriceInterface } from "../../stripe-price";
3
+ import {
4
+ StripeSubscriptionInput,
5
+ StripeSubscriptionInterface,
6
+ SubscriptionStatus,
7
+ } from "./stripe-subscription.interface";
8
+
9
+ export class StripeSubscription extends AbstractApiData implements StripeSubscriptionInterface {
10
+ private _stripeSubscriptionId?: string;
11
+ private _status?: SubscriptionStatus;
12
+ private _currentPeriodStart?: Date;
13
+ private _currentPeriodEnd?: Date;
14
+ private _cancelAtPeriodEnd: boolean = false;
15
+ private _canceledAt?: Date;
16
+ private _trialStart?: Date;
17
+ private _trialEnd?: Date;
18
+ private _price?: StripePriceInterface;
19
+
20
+ get stripeSubscriptionId(): string {
21
+ if (!this._stripeSubscriptionId) throw new Error("stripeSubscriptionId is not defined");
22
+ return this._stripeSubscriptionId;
23
+ }
24
+
25
+ get status(): SubscriptionStatus {
26
+ if (!this._status) throw new Error("status is not defined");
27
+ return this._status;
28
+ }
29
+
30
+ get currentPeriodStart(): Date {
31
+ if (!this._currentPeriodStart) throw new Error("currentPeriodStart is not defined");
32
+ return this._currentPeriodStart;
33
+ }
34
+
35
+ get currentPeriodEnd(): Date {
36
+ if (!this._currentPeriodEnd) throw new Error("currentPeriodEnd is not defined");
37
+ return this._currentPeriodEnd;
38
+ }
39
+
40
+ get cancelAtPeriodEnd(): boolean {
41
+ return this._cancelAtPeriodEnd;
42
+ }
43
+
44
+ get canceledAt(): Date | undefined {
45
+ return this._canceledAt;
46
+ }
47
+
48
+ get trialStart(): Date | undefined {
49
+ return this._trialStart;
50
+ }
51
+
52
+ get trialEnd(): Date | undefined {
53
+ return this._trialEnd;
54
+ }
55
+
56
+ get price(): StripePriceInterface | undefined {
57
+ return this._price;
58
+ }
59
+
60
+ rehydrate(data: JsonApiHydratedDataInterface): this {
61
+ super.rehydrate(data);
62
+
63
+ this._stripeSubscriptionId = data.jsonApi.attributes.stripeSubscriptionId;
64
+ this._status = data.jsonApi.attributes.status;
65
+
66
+ this._currentPeriodStart = data.jsonApi.attributes.currentPeriodStart
67
+ ? new Date(data.jsonApi.attributes.currentPeriodStart)
68
+ : undefined;
69
+ this._currentPeriodEnd = data.jsonApi.attributes.currentPeriodEnd
70
+ ? new Date(data.jsonApi.attributes.currentPeriodEnd)
71
+ : undefined;
72
+
73
+ this._cancelAtPeriodEnd = data.jsonApi.attributes.cancelAtPeriodEnd ?? false;
74
+ this._canceledAt = data.jsonApi.attributes.canceledAt ? new Date(data.jsonApi.attributes.canceledAt) : undefined;
75
+
76
+ this._trialStart = data.jsonApi.attributes.trialStart ? new Date(data.jsonApi.attributes.trialStart) : undefined;
77
+ this._trialEnd = data.jsonApi.attributes.trialEnd ? new Date(data.jsonApi.attributes.trialEnd) : undefined;
78
+
79
+ // Hydrate price relationship
80
+ this._price = this._readIncluded(data, "price", Modules.StripePrice) as StripePriceInterface;
81
+
82
+ return this;
83
+ }
84
+
85
+ createJsonApi(data: StripeSubscriptionInput): any {
86
+ const response: any = {
87
+ data: {
88
+ type: Modules.StripeSubscription.name,
89
+ id: data.id,
90
+ attributes: {},
91
+ },
92
+ };
93
+
94
+ // CREATE: priceId goes to relationships
95
+ if (data.priceId) {
96
+ response.data.relationships = {
97
+ stripePrice: {
98
+ data: {
99
+ type: Modules.StripePrice.name,
100
+ id: data.priceId,
101
+ },
102
+ },
103
+ };
104
+ }
105
+
106
+ // CHANGE-PLAN: newPriceId goes to attributes.priceId
107
+ if (data.newPriceId) {
108
+ response.data.attributes.priceId = data.newPriceId;
109
+ }
110
+
111
+ // CANCEL: cancelImmediately goes to attributes
112
+ if (data.cancelImmediately !== undefined) {
113
+ response.data.attributes.cancelImmediately = data.cancelImmediately;
114
+ }
115
+
116
+ // Shared optional fields
117
+ if (data.quantity !== undefined) {
118
+ response.data.attributes.quantity = data.quantity;
119
+ }
120
+
121
+ if (data.trialPeriodDays !== undefined) {
122
+ response.data.attributes.trialPeriodDays = data.trialPeriodDays;
123
+ }
124
+
125
+ if (data.paymentMethodId) {
126
+ response.data.attributes.paymentMethodId = data.paymentMethodId;
127
+ }
128
+
129
+ if (data.metadata) {
130
+ response.data.attributes.metadata = data.metadata;
131
+ }
132
+
133
+ return response;
134
+ }
135
+ }
@@ -0,0 +1 @@
1
+ export * from "./useConfirmSubscriptionPayment";
@@ -0,0 +1,111 @@
1
+ "use client";
2
+
3
+ import { useStripe } from "@stripe/react-stripe-js";
4
+ import { useCallback, useState } from "react";
5
+
6
+ export interface ConfirmPaymentResult {
7
+ success: boolean;
8
+ error?: string;
9
+ }
10
+
11
+ export interface UseConfirmSubscriptionPaymentReturn {
12
+ confirmPayment: (clientSecret: string) => Promise<ConfirmPaymentResult>;
13
+ isConfirming: boolean;
14
+ }
15
+
16
+ /**
17
+ * Hook for confirming subscription payments using Stripe's SCA-compliant flow.
18
+ *
19
+ * This hook wraps stripe.confirmCardPayment() and handles:
20
+ * - Loading state during confirmation
21
+ * - Error handling for Stripe errors
22
+ * - 3D Secure authentication popups (handled automatically by Stripe)
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * const { confirmPayment, isConfirming } = useConfirmSubscriptionPayment();
27
+ *
28
+ * const handleCreateSubscription = async () => {
29
+ * const result = await StripeSubscriptionService.createSubscription({ priceId });
30
+ *
31
+ * if (result.meta.requiresAction && result.meta.clientSecret) {
32
+ * const confirmation = await confirmPayment(result.meta.clientSecret);
33
+ * if (!confirmation.success) {
34
+ * setError(confirmation.error);
35
+ * return;
36
+ * }
37
+ * }
38
+ *
39
+ * // Subscription is now active
40
+ * };
41
+ * ```
42
+ */
43
+ export function useConfirmSubscriptionPayment(): UseConfirmSubscriptionPaymentReturn {
44
+ const stripe = useStripe();
45
+ const [isConfirming, setIsConfirming] = useState(false);
46
+
47
+ const confirmPayment = useCallback(
48
+ async (clientSecret: string): Promise<ConfirmPaymentResult> => {
49
+ if (!stripe) {
50
+ console.error("[useConfirmSubscriptionPayment] Stripe not initialized");
51
+ return {
52
+ success: false,
53
+ error: "Payment system not initialized. Please refresh the page and try again.",
54
+ };
55
+ }
56
+
57
+ if (!clientSecret) {
58
+ console.error("[useConfirmSubscriptionPayment] No client secret provided");
59
+ return {
60
+ success: false,
61
+ error: "Payment confirmation failed. Missing payment details.",
62
+ };
63
+ }
64
+
65
+ setIsConfirming(true);
66
+
67
+ try {
68
+ const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(clientSecret);
69
+
70
+ if (stripeError) {
71
+ console.error("[useConfirmSubscriptionPayment] Stripe error:", stripeError);
72
+ return {
73
+ success: false,
74
+ error: stripeError.message || "Payment confirmation failed. Please try again.",
75
+ };
76
+ }
77
+
78
+ if (paymentIntent?.status === "succeeded") {
79
+ return { success: true };
80
+ }
81
+
82
+ if (paymentIntent?.status === "requires_action") {
83
+ // This shouldn't happen as Stripe handles 3DS inline, but handle it just in case
84
+ return {
85
+ success: false,
86
+ error: "Additional authentication required. Please complete the verification.",
87
+ };
88
+ }
89
+
90
+ return {
91
+ success: false,
92
+ error: "Payment could not be completed. Please try again.",
93
+ };
94
+ } catch (err: any) {
95
+ console.error("[useConfirmSubscriptionPayment] Unexpected error:", err);
96
+ return {
97
+ success: false,
98
+ error: err.message || "An unexpected error occurred during payment confirmation.",
99
+ };
100
+ } finally {
101
+ setIsConfirming(false);
102
+ }
103
+ },
104
+ [stripe],
105
+ );
106
+
107
+ return {
108
+ confirmPayment,
109
+ isConfirming,
110
+ };
111
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./data";
2
+ export * from "./stripe-subscription.module";
3
+
4
+ // Note: hooks are not exported from barrel to avoid bundling client code into server components.
5
+ // Import hooks directly: import { useConfirmSubscriptionPayment } from "./hooks";
@@ -0,0 +1,9 @@
1
+ import { ModuleFactory } from "../../../permissions";
2
+ import { StripeSubscription } from "./data";
3
+
4
+ export const StripeSubscriptionModule = (factory: ModuleFactory) =>
5
+ factory({
6
+ name: "stripe-subscriptions",
7
+ model: StripeSubscription,
8
+ moduleId: "5e8797ef-650b-4dd5-ac79-a2e530a6c7ba",
9
+ });