@carlonicora/nextjs-jsonapi 1.15.0 → 1.17.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 (321) hide show
  1. package/dist/ApiData-DPKNfY-9.d.mts +10 -0
  2. package/dist/ApiData-DPKNfY-9.d.ts +10 -0
  3. package/dist/ApiRequestDataTypeInterface-DIEOFn9s.d.mts +40 -0
  4. package/dist/ApiRequestDataTypeInterface-DIEOFn9s.d.ts +40 -0
  5. package/dist/{ApiResponseInterface-QLDnxLA9.d.ts → ApiResponseInterface-BKyod24U.d.ts} +3 -11
  6. package/dist/{ApiResponseInterface-B4QdWh-y.d.mts → ApiResponseInterface-Dqvu09tz.d.mts} +3 -11
  7. package/dist/{BlockNoteEditor-FGXYUAWI.js → BlockNoteEditor-34T5CY27.js} +17 -16
  8. package/dist/BlockNoteEditor-34T5CY27.js.map +1 -0
  9. package/dist/{BlockNoteEditor-ITJLAOXC.mjs → BlockNoteEditor-4Z6TZBJE.mjs} +7 -6
  10. package/dist/{BlockNoteEditor-ITJLAOXC.mjs.map → BlockNoteEditor-4Z6TZBJE.mjs.map} +1 -1
  11. package/dist/JsonApiContext-Bsm_Q2oe.d.mts +41 -0
  12. package/dist/JsonApiContext-Bsm_Q2oe.d.ts +41 -0
  13. package/dist/JsonApiRequest-54ZBO7WQ.js +24 -0
  14. package/dist/{JsonApiRequest-FXZCYIER.js.map → JsonApiRequest-54ZBO7WQ.js.map} +1 -1
  15. package/dist/{JsonApiRequest-HFWXMKMA.mjs → JsonApiRequest-XWQWTFEQ.mjs} +2 -2
  16. package/dist/chunk-3EPNHTMH.js +26 -0
  17. package/dist/chunk-3EPNHTMH.js.map +1 -0
  18. package/dist/{chunk-TGBXBUWM.mjs → chunk-3VM3WAOV.mjs} +8 -1
  19. package/dist/chunk-3VM3WAOV.mjs.map +1 -0
  20. package/dist/{chunk-6YD42BP6.js → chunk-7DTKRMYW.js} +31 -19
  21. package/dist/chunk-7DTKRMYW.js.map +1 -0
  22. package/dist/{chunk-PK5DRSUD.js → chunk-D7H7SRWB.js} +4104 -793
  23. package/dist/chunk-D7H7SRWB.js.map +1 -0
  24. package/dist/{chunk-JGVXZS7M.mjs → chunk-KUFWHMMY.mjs} +1592 -133
  25. package/dist/chunk-KUFWHMMY.mjs.map +1 -0
  26. package/dist/{chunk-SJIVGCNM.mjs → chunk-KX7YG6LY.mjs} +27 -15
  27. package/dist/chunk-KX7YG6LY.mjs.map +1 -0
  28. package/dist/{chunk-FPZPD4JI.js → chunk-LI6CPNJI.js} +17 -10
  29. package/dist/chunk-LI6CPNJI.js.map +1 -0
  30. package/dist/{chunk-WAFOKMKT.mjs → chunk-SXPXC2TY.mjs} +3729 -418
  31. package/dist/chunk-SXPXC2TY.mjs.map +1 -0
  32. package/dist/{chunk-C6QXZGL7.js → chunk-UYY34W7R.js} +1622 -163
  33. package/dist/chunk-UYY34W7R.js.map +1 -0
  34. package/dist/chunk-VOXD3ZLY.mjs +26 -0
  35. package/dist/chunk-VOXD3ZLY.mjs.map +1 -0
  36. package/dist/client/index.d.mts +11 -45
  37. package/dist/client/index.d.ts +11 -45
  38. package/dist/client/index.js +10 -6
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/client/index.mjs +13 -9
  41. package/dist/components/index.d.mts +254 -9
  42. package/dist/components/index.d.ts +254 -9
  43. package/dist/components/index.js +85 -6
  44. package/dist/components/index.js.map +1 -1
  45. package/dist/components/index.mjs +84 -5
  46. package/dist/{config-C5tGGrYf.d.mts → config--nwiW74Z.d.ts} +7 -2
  47. package/dist/{config-eceYM5kN.d.ts → config-BKSQmUWU.d.mts} +7 -2
  48. package/dist/{content.interface-CxBBC7ec.d.mts → content.interface-4VICFRA0.d.ts} +2 -1
  49. package/dist/{content.interface-TB2MfJGs.d.ts → content.interface-CFc97-Cj.d.mts} +2 -1
  50. package/dist/contexts/index.d.mts +3 -2
  51. package/dist/contexts/index.d.ts +3 -2
  52. package/dist/contexts/index.js +7 -6
  53. package/dist/contexts/index.js.map +1 -1
  54. package/dist/contexts/index.mjs +6 -5
  55. package/dist/core/index.d.mts +524 -18
  56. package/dist/core/index.d.ts +524 -18
  57. package/dist/core/index.js +54 -4
  58. package/dist/core/index.js.map +1 -1
  59. package/dist/core/index.mjs +53 -3
  60. package/dist/index.d.mts +16 -12
  61. package/dist/index.d.ts +16 -12
  62. package/dist/index.js +57 -5
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +58 -6
  65. package/dist/{notification.interface-lG6UpTpt.d.mts → notification.interface-BGaPiCUM.d.mts} +3 -42
  66. package/dist/{notification.interface-lG6UpTpt.d.ts → notification.interface-CqwaOIgM.d.ts} +3 -42
  67. package/dist/{s3.service-DP_hsssD.d.mts → s3.service-BYs88XEE.d.ts} +21 -2
  68. package/dist/{s3.service-Dq-PTUNa.d.ts → s3.service-C0BjOdvn.d.mts} +21 -2
  69. package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
  70. package/dist/scripts/generate-web-module/generator.js +66 -0
  71. package/dist/scripts/generate-web-module/generator.js.map +1 -1
  72. package/dist/scripts/generate-web-module/templates/index.d.ts +8 -0
  73. package/dist/scripts/generate-web-module/templates/index.d.ts.map +1 -1
  74. package/dist/scripts/generate-web-module/templates/index.js +18 -1
  75. package/dist/scripts/generate-web-module/templates/index.js.map +1 -1
  76. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts +7 -0
  77. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts.map +1 -0
  78. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js +141 -0
  79. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js.map +1 -0
  80. package/dist/scripts/generate-web-module/templates/project/env.template.d.ts +7 -0
  81. package/dist/scripts/generate-web-module/templates/project/env.template.d.ts.map +1 -0
  82. package/dist/scripts/generate-web-module/templates/project/env.template.js +110 -0
  83. package/dist/scripts/generate-web-module/templates/project/env.template.js.map +1 -0
  84. package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts +7 -0
  85. package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts.map +1 -0
  86. package/dist/scripts/generate-web-module/templates/project/main-layout.template.js +101 -0
  87. package/dist/scripts/generate-web-module/templates/project/main-layout.template.js.map +1 -0
  88. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts +7 -0
  89. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts.map +1 -0
  90. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js +66 -0
  91. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js.map +1 -0
  92. package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts +7 -0
  93. package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts.map +1 -0
  94. package/dist/scripts/generate-web-module/templates/project/settings-container.template.js +257 -0
  95. package/dist/scripts/generate-web-module/templates/project/settings-container.template.js.map +1 -0
  96. package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts +7 -0
  97. package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts.map +1 -0
  98. package/dist/scripts/generate-web-module/templates/project/settings-context.template.js +124 -0
  99. package/dist/scripts/generate-web-module/templates/project/settings-context.template.js.map +1 -0
  100. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts +7 -0
  101. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts.map +1 -0
  102. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js +78 -0
  103. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js.map +1 -0
  104. package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts +7 -0
  105. package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts.map +1 -0
  106. package/dist/scripts/generate-web-module/templates/project/settings-page.template.js +75 -0
  107. package/dist/scripts/generate-web-module/templates/project/settings-page.template.js.map +1 -0
  108. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +1 -1
  109. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -1
  110. package/dist/server/index.d.mts +6 -4
  111. package/dist/server/index.d.ts +6 -4
  112. package/dist/server/index.js +13 -13
  113. package/dist/server/index.js.map +1 -1
  114. package/dist/server/index.mjs +3 -3
  115. package/dist/stripe-subscription.interface-B-TM40Io.d.ts +226 -0
  116. package/dist/stripe-subscription.interface-DDxnpj0F.d.mts +226 -0
  117. package/dist/testing/index.d.mts +338 -0
  118. package/dist/testing/index.d.ts +338 -0
  119. package/dist/testing/index.js +323 -0
  120. package/dist/testing/index.js.map +1 -0
  121. package/dist/testing/index.mjs +323 -0
  122. package/dist/testing/index.mjs.map +1 -0
  123. package/dist/{useSocket-Bua6MwLi.d.mts → useSocket-BNj9PrRw.d.mts} +1 -1
  124. package/dist/{useSocket-D5dhUp4m.d.ts → useSocket-Dwt8cz1x.d.ts} +1 -1
  125. package/package.json +29 -3
  126. package/scripts/generate-web-module/generator.ts +83 -0
  127. package/scripts/generate-web-module/templates/index.ts +10 -0
  128. package/scripts/generate-web-module/templates/project/bootstrapper.template.ts +108 -0
  129. package/scripts/generate-web-module/templates/project/env.template.ts +77 -0
  130. package/scripts/generate-web-module/templates/project/main-layout.template.tsx +68 -0
  131. package/scripts/generate-web-module/templates/project/middleware-env.template.ts +33 -0
  132. package/scripts/generate-web-module/templates/project/settings-container.template.tsx +224 -0
  133. package/scripts/generate-web-module/templates/project/settings-context.template.tsx +91 -0
  134. package/scripts/generate-web-module/templates/project/settings-module-page.template.tsx +45 -0
  135. package/scripts/generate-web-module/templates/project/settings-page.template.tsx +42 -0
  136. package/scripts/generate-web-module/types/template-data.interface.ts +1 -1
  137. package/src/client/config.ts +9 -0
  138. package/src/client/hooks/__tests__/useJsonApiGet.test.tsx +229 -0
  139. package/src/client/hooks/__tests__/useJsonApiMutation.test.tsx +348 -0
  140. package/src/client/hooks/__tests__/useRehydration.test.ts +188 -0
  141. package/src/components/forms/__tests__/FormCheckbox.test.tsx +238 -0
  142. package/src/components/forms/__tests__/FormDate.test.tsx +212 -0
  143. package/src/components/forms/__tests__/FormInput.test.tsx +292 -0
  144. package/src/components/forms/__tests__/FormSelect.test.tsx +173 -0
  145. package/src/components/index.ts +7 -0
  146. package/src/components/tables/__tests__/ContentListTable.test.tsx +411 -0
  147. package/src/core/abstracts/AbstractService.ts +104 -0
  148. package/src/core/endpoint/EndpointCreator.ts +7 -4
  149. package/src/core/endpoint/__tests__/EndpointCreator.test.ts +168 -0
  150. package/src/core/factories/__tests__/JsonApiDataFactory.test.ts +109 -0
  151. package/src/core/factories/__tests__/RehydrationFactory.test.ts +151 -0
  152. package/src/core/index.ts +12 -4
  153. package/src/core/interfaces/ApiResponseInterface.ts +1 -0
  154. package/src/core/registry/ModuleRegistry.ts +11 -2
  155. package/src/core/registry/__tests__/DataClassRegistry.test.ts +136 -0
  156. package/src/core/registry/__tests__/ModuleRegistrar.test.ts +159 -0
  157. package/src/core/utils/translateResponse.ts +17 -0
  158. package/src/features/auth/components/details/LandingComponent.tsx +14 -12
  159. package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +97 -0
  160. package/src/features/billing/components/cards/CustomerInfoCard.tsx +112 -0
  161. package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +114 -0
  162. package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +119 -0
  163. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +146 -0
  164. package/src/features/billing/components/cards/index.ts +5 -0
  165. package/src/features/billing/components/containers/BillingDashboardContainer.tsx +427 -0
  166. package/src/features/billing/components/containers/index.ts +1 -0
  167. package/src/features/billing/components/index.ts +6 -0
  168. package/src/features/billing/components/modals/BillingDetailModal.tsx +36 -0
  169. package/src/features/billing/components/modals/index.ts +1 -0
  170. package/src/features/billing/components/providers/StripeProvider.tsx +48 -0
  171. package/src/features/billing/components/providers/index.ts +1 -0
  172. package/src/features/billing/components/utils/currency.ts +49 -0
  173. package/src/features/billing/components/utils/date.ts +21 -0
  174. package/src/features/billing/components/utils/index.ts +2 -0
  175. package/src/features/billing/components/widgets/BillingAlertBanner.tsx +63 -0
  176. package/src/features/billing/components/widgets/index.ts +1 -0
  177. package/src/features/billing/data/Billing.ts +17 -0
  178. package/src/features/billing/data/billing.service.ts +58 -0
  179. package/src/features/billing/data/index.ts +5 -0
  180. package/src/features/billing/index.ts +3 -0
  181. package/src/features/billing/modules/billing.module.ts +9 -0
  182. package/src/features/billing/modules/index.ts +1 -0
  183. package/src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx +79 -0
  184. package/src/features/billing/stripe-customer/components/containers/index.ts +1 -0
  185. package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +151 -0
  186. package/src/features/billing/stripe-customer/components/details/index.ts +1 -0
  187. package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +186 -0
  188. package/src/features/billing/stripe-customer/components/forms/index.ts +1 -0
  189. package/src/features/billing/stripe-customer/components/index.ts +4 -0
  190. package/src/features/billing/stripe-customer/components/lists/PaymentMethodsList.tsx +19 -0
  191. package/src/features/billing/stripe-customer/components/lists/index.ts +1 -0
  192. package/src/features/billing/stripe-customer/data/index.ts +5 -0
  193. package/src/features/billing/stripe-customer/data/payment-method.interface.ts +27 -0
  194. package/src/features/billing/stripe-customer/data/payment-method.ts +119 -0
  195. package/src/features/billing/stripe-customer/data/stripe-customer.interface.ts +16 -0
  196. package/src/features/billing/stripe-customer/data/stripe-customer.service.ts +128 -0
  197. package/src/features/billing/stripe-customer/data/stripe-customer.ts +71 -0
  198. package/src/features/billing/stripe-customer/index.ts +3 -0
  199. package/src/features/billing/stripe-customer/stripe-customer.module.ts +9 -0
  200. package/src/features/billing/stripe-customer/stripe-payment-method.module.ts +9 -0
  201. package/src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx +66 -0
  202. package/src/features/billing/stripe-invoice/components/containers/index.ts +1 -0
  203. package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +172 -0
  204. package/src/features/billing/stripe-invoice/components/details/index.ts +1 -0
  205. package/src/features/billing/stripe-invoice/components/index.ts +4 -0
  206. package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +84 -0
  207. package/src/features/billing/stripe-invoice/components/lists/index.ts +1 -0
  208. package/src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx +41 -0
  209. package/src/features/billing/stripe-invoice/components/widgets/index.ts +1 -0
  210. package/src/features/billing/stripe-invoice/data/index.ts +3 -0
  211. package/src/features/billing/stripe-invoice/data/stripe-invoice.interface.ts +65 -0
  212. package/src/features/billing/stripe-invoice/data/stripe-invoice.service.ts +64 -0
  213. package/src/features/billing/stripe-invoice/data/stripe-invoice.ts +177 -0
  214. package/src/features/billing/stripe-invoice/index.ts +2 -0
  215. package/src/features/billing/stripe-invoice/stripe-invoice.module.ts +9 -0
  216. package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +304 -0
  217. package/src/features/billing/stripe-price/components/forms/index.ts +1 -0
  218. package/src/features/billing/stripe-price/components/index.ts +2 -0
  219. package/src/features/billing/stripe-price/components/lists/PricesList.tsx +283 -0
  220. package/src/features/billing/stripe-price/components/lists/index.ts +1 -0
  221. package/src/features/billing/stripe-price/data/index.ts +3 -0
  222. package/src/features/billing/stripe-price/data/stripe-price.interface.ts +48 -0
  223. package/src/features/billing/stripe-price/data/stripe-price.service.ts +123 -0
  224. package/src/features/billing/stripe-price/data/stripe-price.ts +156 -0
  225. package/src/features/billing/stripe-price/index.ts +2 -0
  226. package/src/features/billing/stripe-price/stripe-price.module.ts +9 -0
  227. package/src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx +86 -0
  228. package/src/features/billing/stripe-product/components/containers/index.ts +1 -0
  229. package/src/features/billing/stripe-product/components/forms/ProductEditor.tsx +100 -0
  230. package/src/features/billing/stripe-product/components/forms/index.ts +1 -0
  231. package/src/features/billing/stripe-product/components/index.ts +3 -0
  232. package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +206 -0
  233. package/src/features/billing/stripe-product/components/lists/index.ts +1 -0
  234. package/src/features/billing/stripe-product/data/index.ts +3 -0
  235. package/src/features/billing/stripe-product/data/stripe-product.interface.ts +18 -0
  236. package/src/features/billing/stripe-product/data/stripe-product.service.ts +112 -0
  237. package/src/features/billing/stripe-product/data/stripe-product.ts +74 -0
  238. package/src/features/billing/stripe-product/index.ts +2 -0
  239. package/src/features/billing/stripe-product/stripe-product.module.ts +9 -0
  240. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +304 -0
  241. package/src/features/billing/stripe-subscription/components/containers/index.ts +1 -0
  242. package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +223 -0
  243. package/src/features/billing/stripe-subscription/components/details/index.ts +1 -0
  244. package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +116 -0
  245. package/src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx +331 -0
  246. package/src/features/billing/stripe-subscription/components/forms/index.ts +2 -0
  247. package/src/features/billing/stripe-subscription/components/index.ts +5 -0
  248. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +104 -0
  249. package/src/features/billing/stripe-subscription/components/lists/index.ts +1 -0
  250. package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +95 -0
  251. package/src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx +110 -0
  252. package/src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx +41 -0
  253. package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +60 -0
  254. package/src/features/billing/stripe-subscription/components/widgets/index.ts +4 -0
  255. package/src/features/billing/stripe-subscription/data/index.ts +3 -0
  256. package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +66 -0
  257. package/src/features/billing/stripe-subscription/data/stripe-subscription.service.ts +193 -0
  258. package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +135 -0
  259. package/src/features/billing/stripe-subscription/hooks/index.ts +1 -0
  260. package/src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts +111 -0
  261. package/src/features/billing/stripe-subscription/index.ts +5 -0
  262. package/src/features/billing/stripe-subscription/stripe-subscription.module.ts +9 -0
  263. package/src/features/billing/stripe-usage/components/containers/UsageContainer.tsx +109 -0
  264. package/src/features/billing/stripe-usage/components/containers/index.ts +1 -0
  265. package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +90 -0
  266. package/src/features/billing/stripe-usage/components/details/index.ts +1 -0
  267. package/src/features/billing/stripe-usage/components/index.ts +4 -0
  268. package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +72 -0
  269. package/src/features/billing/stripe-usage/components/lists/index.ts +1 -0
  270. package/src/features/billing/stripe-usage/components/widgets/UsageSummaryCards.tsx +19 -0
  271. package/src/features/billing/stripe-usage/components/widgets/index.ts +1 -0
  272. package/src/features/billing/stripe-usage/data/index.ts +3 -0
  273. package/src/features/billing/stripe-usage/data/stripe-usage.interface.ts +55 -0
  274. package/src/features/billing/stripe-usage/data/stripe-usage.service.ts +129 -0
  275. package/src/features/billing/stripe-usage/data/stripe-usage.ts +70 -0
  276. package/src/features/billing/stripe-usage/index.ts +2 -0
  277. package/src/features/billing/stripe-usage/stripe-usage.module.ts +9 -0
  278. package/src/features/company/components/forms/CompanyEditor.tsx +2 -2
  279. package/src/features/company/contexts/CompanyContext.tsx +2 -2
  280. package/src/features/feature/components/forms/FormFeatures.tsx +13 -106
  281. package/src/features/feature/data/feature.interface.ts +1 -1
  282. package/src/features/feature/data/feature.ts +4 -4
  283. package/src/features/index.ts +7 -0
  284. package/src/features/module/data/module.interface.ts +0 -1
  285. package/src/features/module/data/module.ts +0 -6
  286. package/src/features/user/components/lists/ContributorsList.tsx +2 -2
  287. package/src/features/user/components/widgets/UserAvatar.tsx +1 -1
  288. package/src/hooks/__tests__/useDataListRetriever.test.ts +321 -0
  289. package/src/hooks/__tests__/useDebounce.test.ts +170 -0
  290. package/src/index.ts +5 -2
  291. package/src/login/config.ts +27 -0
  292. package/src/login/index.ts +2 -0
  293. package/src/shadcnui/custom/link.tsx +16 -6
  294. package/src/testing/factories/createMockApiData.ts +143 -0
  295. package/src/testing/factories/createMockModule.ts +32 -0
  296. package/src/testing/factories/createMockResponse.ts +93 -0
  297. package/src/testing/factories/createMockService.ts +79 -0
  298. package/src/testing/index.ts +70 -0
  299. package/src/testing/matchers/jsonApiMatchers.ts +174 -0
  300. package/src/testing/providers/MockJsonApiProvider.tsx +58 -0
  301. package/src/testing/utils/renderWithProviders.tsx +76 -0
  302. package/src/utils/__tests__/date-formatter.test.ts +161 -0
  303. package/src/utils/__tests__/exists.test.ts +100 -0
  304. package/src/utils/blocknote-diff.util.ts +2 -1
  305. package/src/utils/blocknote-word-diff-renderer.util.ts +8 -7
  306. package/src/utils/cn.test.ts +44 -0
  307. package/dist/AuthComponent-hxOPs9o8.d.mts +0 -11
  308. package/dist/AuthComponent-hxOPs9o8.d.ts +0 -11
  309. package/dist/BlockNoteEditor-FGXYUAWI.js.map +0 -1
  310. package/dist/JsonApiRequest-FXZCYIER.js +0 -24
  311. package/dist/chunk-6YD42BP6.js.map +0 -1
  312. package/dist/chunk-C6QXZGL7.js.map +0 -1
  313. package/dist/chunk-FPZPD4JI.js.map +0 -1
  314. package/dist/chunk-JGVXZS7M.mjs.map +0 -1
  315. package/dist/chunk-PK5DRSUD.js.map +0 -1
  316. package/dist/chunk-SJIVGCNM.mjs.map +0 -1
  317. package/dist/chunk-TGBXBUWM.mjs.map +0 -1
  318. package/dist/chunk-WAFOKMKT.mjs.map +0 -1
  319. package/src/discord/config.ts +0 -15
  320. package/src/discord/index.ts +0 -1
  321. /package/dist/{JsonApiRequest-HFWXMKMA.mjs.map → JsonApiRequest-XWQWTFEQ.mjs.map} +0 -0
@@ -1,15 +1,18 @@
1
1
  import {
2
2
  getApiUrl,
3
3
  getAppUrl,
4
+ getI18nLink,
4
5
  getRoleId,
6
+ getStripePublishableKey,
5
7
  getTrackablePages,
6
- isDiscordConfigured,
7
- isInternalAuthConfigured,
8
+ isDiscordAuthEnabled,
9
+ isInternalAuthEnabled,
10
+ isRegistrationAllowed,
8
11
  useI18nDateFnsLocale,
9
12
  useI18nLocale,
10
13
  useI18nRouter,
11
14
  useI18nTranslations
12
- } from "./chunk-SJIVGCNM.mjs";
15
+ } from "./chunk-KX7YG6LY.mjs";
13
16
  import {
14
17
  AuthService,
15
18
  ClientAbstractService,
@@ -22,6 +25,12 @@ import {
22
25
  RehydrationFactory,
23
26
  RoleService,
24
27
  S3Service,
28
+ StripeCustomerService,
29
+ StripeInvoiceService,
30
+ StripePriceService,
31
+ StripeProductService,
32
+ StripeSubscriptionService,
33
+ StripeUsageService,
25
34
  UserService,
26
35
  checkPermissions,
27
36
  cn,
@@ -30,7 +39,10 @@ import {
30
39
  rehydrate,
31
40
  useComposedRefs,
32
41
  useIsMobile
33
- } from "./chunk-JGVXZS7M.mjs";
42
+ } from "./chunk-KUFWHMMY.mjs";
43
+ import {
44
+ JsonApiContext
45
+ } from "./chunk-VOXD3ZLY.mjs";
34
46
  import {
35
47
  __name
36
48
  } from "./chunk-PAWJFY3S.mjs";
@@ -4792,11 +4804,11 @@ function KanbanOverlay(props) {
4792
4804
  __name(KanbanOverlay, "KanbanOverlay");
4793
4805
 
4794
4806
  // src/shadcnui/custom/link.tsx
4795
- import NextLink from "next/link";
4796
4807
  import * as React33 from "react";
4797
4808
  import { jsx as jsx46 } from "react/jsx-runtime";
4798
- var Link2 = React33.forwardRef(({ className, ...props }, ref) => {
4799
- return /* @__PURE__ */ jsx46(NextLink, { ref, className: cn(`font-medium`, className), ...props });
4809
+ var Link2 = React33.forwardRef(({ className, href, children, ...props }, ref) => {
4810
+ const NextIntlLink = getI18nLink();
4811
+ return /* @__PURE__ */ jsx46(NextIntlLink, { prefetch: false, ref, href, className: cn(`font-medium`, className), ...props, children });
4800
4812
  });
4801
4813
  Link2.displayName = "Link";
4802
4814
 
@@ -5175,7 +5187,7 @@ function UserEditorInternal({ user, propagateChanges, adminCreated, trigger, onR
5175
5187
  useEffect9(() => {
5176
5188
  if (!companyFromContext && userCompany) setCompany(userCompany);
5177
5189
  }, [company]);
5178
- const formSchema = z.object({
5190
+ const formSchema2 = z.object({
5179
5191
  id: z.uuidv4(),
5180
5192
  name: z.string().min(1, { message: t(`foundations.user.fields.name.error`) }),
5181
5193
  email: z.string().min(1, { message: t(`generic.fields.email.error`) }),
@@ -5188,7 +5200,7 @@ function UserEditorInternal({ user, propagateChanges, adminCreated, trigger, onR
5188
5200
  avatar: z.string().optional()
5189
5201
  });
5190
5202
  const form = useForm({
5191
- resolver: zodResolver(formSchema),
5203
+ resolver: zodResolver(formSchema2),
5192
5204
  defaultValues: {
5193
5205
  id: user?.id || v4(),
5194
5206
  name: user?.name || "",
@@ -6331,12 +6343,12 @@ function CompanyConfigurationEditorInternal({ company }) {
6331
6343
  setOpen(false);
6332
6344
  form.reset();
6333
6345
  }, "close");
6334
- const formSchema = z2.object({
6346
+ const formSchema2 = z2.object({
6335
6347
  isManagedKnowledge: z2.boolean().optional(),
6336
6348
  allowPublicBot: z2.boolean().optional()
6337
6349
  });
6338
6350
  const form = useForm2({
6339
- resolver: zodResolver2(formSchema),
6351
+ resolver: zodResolver2(formSchema2),
6340
6352
  defaultValues,
6341
6353
  shouldUnregister: false
6342
6354
  });
@@ -6510,7 +6522,7 @@ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }) {
6510
6522
  const [contentType, setContentType] = useState16(null);
6511
6523
  const t = useTranslations22();
6512
6524
  const generateUrl = usePageUrlGenerator();
6513
- const formSchema = z3.object({
6525
+ const formSchema2 = z3.object({
6514
6526
  id: z3.uuidv4(),
6515
6527
  name: z3.string().min(1, {
6516
6528
  message: t(`foundations.company.fields.name.error`)
@@ -6520,7 +6532,7 @@ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }) {
6520
6532
  logo: z3.string().optional()
6521
6533
  });
6522
6534
  const form = useForm3({
6523
- resolver: zodResolver3(formSchema),
6535
+ resolver: zodResolver3(formSchema2),
6524
6536
  defaultValues: {
6525
6537
  id: company?.id || v42(),
6526
6538
  name: company?.name || "",
@@ -6574,7 +6586,7 @@ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }) {
6574
6586
  if (hasRole(getRoleId().Administrator)) {
6575
6587
  setFeatures(allfeatures);
6576
6588
  } else {
6577
- setFeatures(allfeatures.filter((feature) => feature.isProduction));
6589
+ setFeatures(allfeatures.filter((feature) => feature.isCore));
6578
6590
  }
6579
6591
  }
6580
6592
  __name(fetchFeatures, "fetchFeatures");
@@ -6735,7 +6747,6 @@ var CompanyProvider = /* @__PURE__ */ __name(({ children, dehydratedCompany }) =
6735
6747
  if (company && hasRole(getRoleId().Administrator) && hasPermissionToModule({ module: Modules.Company, action: "delete" /* Delete */ }))
6736
6748
  functions.push(/* @__PURE__ */ jsx79(CompanyDeleter, { company }, "companyDeleter"));
6737
6749
  if (hasRole(getRoleId().Administrator) || hasPermissionToModule({ module: Modules.Company, action: "update" /* Update */ })) {
6738
- if (company) functions.push(/* @__PURE__ */ jsx79(CompanyConfigurationEditor, { company }, "companyConfigurationEditor"));
6739
6750
  functions.push(/* @__PURE__ */ jsx79(CompanyEditor, { company, propagateChanges: setCompany }, "companyEditor"));
6740
6751
  }
6741
6752
  if (functions.length > 0) response.functions = functions;
@@ -7664,7 +7675,7 @@ __name(AllowedUsersDetails, "AllowedUsersDetails");
7664
7675
  import dynamic from "next/dynamic";
7665
7676
  import React38 from "react";
7666
7677
  import { jsx as jsx97 } from "react/jsx-runtime";
7667
- var BlockNoteEditor = dynamic(() => import("./BlockNoteEditor-ITJLAOXC.mjs"), {
7678
+ var BlockNoteEditor = dynamic(() => import("./BlockNoteEditor-4Z6TZBJE.mjs"), {
7668
7679
  ssr: false
7669
7680
  });
7670
7681
  var BlockNoteEditorContainer = React38.memo(/* @__PURE__ */ __name(function EditorContainer(props) {
@@ -7951,7 +7962,7 @@ var DatePickerPopover = /* @__PURE__ */ __name(({
7951
7962
  () => new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric" }),
7952
7963
  [locale]
7953
7964
  );
7954
- const formatDate = /* @__PURE__ */ __name((date) => dateFormatter.format(date), "formatDate");
7965
+ const formatDate5 = /* @__PURE__ */ __name((date) => dateFormatter.format(date), "formatDate");
7955
7966
  const datePlaceholder = useMemo7(() => {
7956
7967
  const parts = dateFormatter.formatToParts(new Date(2e3, 0, 1));
7957
7968
  return parts.map((part) => {
@@ -7970,7 +7981,7 @@ var DatePickerPopover = /* @__PURE__ */ __name(({
7970
7981
  return part.value;
7971
7982
  }).join("");
7972
7983
  }, [dateFormatter]);
7973
- const [inputValue, setInputValue] = useState28(() => value ? formatDate(value) : "");
7984
+ const [inputValue, setInputValue] = useState28(() => value ? formatDate5(value) : "");
7974
7985
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
7975
7986
  const yearOptions = Array.from({ length: currentYear - 1900 + 11 }, (_, i) => 1900 + i);
7976
7987
  const monthNames = useMemo7(() => {
@@ -7993,7 +8004,7 @@ var DatePickerPopover = /* @__PURE__ */ __name(({
7993
8004
  const handleCalendarSelect = /* @__PURE__ */ __name((selectedDate) => {
7994
8005
  onSelect(selectedDate);
7995
8006
  if (selectedDate) {
7996
- setInputValue(formatDate(selectedDate));
8007
+ setInputValue(formatDate5(selectedDate));
7997
8008
  setDisplayMonth(selectedDate);
7998
8009
  } else {
7999
8010
  setInputValue("");
@@ -8528,7 +8539,7 @@ function FormDate({
8528
8539
  () => new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric" }),
8529
8540
  [locale]
8530
8541
  );
8531
- const formatDate = /* @__PURE__ */ __name((date) => dateFormatter.format(date), "formatDate");
8542
+ const formatDate5 = /* @__PURE__ */ __name((date) => dateFormatter.format(date), "formatDate");
8532
8543
  const datePlaceholder = useMemo8(() => {
8533
8544
  const parts = dateFormatter.formatToParts(new Date(2e3, 0, 1));
8534
8545
  return parts.map((part) => {
@@ -8549,7 +8560,7 @@ function FormDate({
8549
8560
  }, [dateFormatter]);
8550
8561
  const [inputValue, setInputValue] = useState31(() => {
8551
8562
  const currentValue = form.getValues(id);
8552
- return currentValue ? formatDate(currentValue) : "";
8563
+ return currentValue ? formatDate5(currentValue) : "";
8553
8564
  });
8554
8565
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
8555
8566
  const yearOptions = Array.from({ length: currentYear - 1900 + 1 }, (_, i) => 1900 + i);
@@ -8575,7 +8586,7 @@ function FormDate({
8575
8586
  const handleCalendarSelect = /* @__PURE__ */ __name((selectedDate, field) => {
8576
8587
  field.onChange(selectedDate);
8577
8588
  if (selectedDate) {
8578
- setInputValue(formatDate(selectedDate));
8589
+ setInputValue(formatDate5(selectedDate));
8579
8590
  setDisplayMonth(selectedDate);
8580
8591
  } else {
8581
8592
  setInputValue("");
@@ -8712,7 +8723,7 @@ function FormDateTime({
8712
8723
  }),
8713
8724
  [locale]
8714
8725
  );
8715
- const formatDateTime = /* @__PURE__ */ __name((date) => dateTimeFormatter.format(date), "formatDateTime");
8726
+ const formatDateTime2 = /* @__PURE__ */ __name((date) => dateTimeFormatter.format(date), "formatDateTime");
8716
8727
  const [selectedHours, setSelectedHours] = useState32((/* @__PURE__ */ new Date()).getHours());
8717
8728
  const [selectedMinutes, setSelectedMinutes] = useState32(roundToNearestFiveMinutes((/* @__PURE__ */ new Date()).getMinutes()));
8718
8729
  const hoursOptions = Array.from({ length: 24 }, (_, i) => {
@@ -8758,7 +8769,7 @@ function FormDateTime({
8758
8769
  variant: "outline",
8759
8770
  className: cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground"),
8760
8771
  children: [
8761
- field.value ? formatDateTime(field.value) : /* @__PURE__ */ jsx110("span", { children: t(`generic.pick_date_time`) }),
8772
+ field.value ? formatDateTime2(field.value) : /* @__PURE__ */ jsx110("span", { children: t(`generic.pick_date_time`) }),
8762
8773
  /* @__PURE__ */ jsx110(CalendarIcon4, { className: "ml-auto h-4 w-4 opacity-50" })
8763
8774
  ]
8764
8775
  }
@@ -9371,118 +9382,35 @@ var dropzone = {
9371
9382
 
9372
9383
  // src/features/feature/components/forms/FormFeatures.tsx
9373
9384
  import { jsx as jsx120, jsxs as jsxs72 } from "react/jsx-runtime";
9374
- function FormFeatures({
9375
- form,
9376
- name,
9377
- features,
9378
- featureField = "featureIds",
9379
- moduleField = "moduleIds"
9380
- }) {
9385
+ function FormFeatures({ form, name, features, featureField = "featureIds" }) {
9381
9386
  const selectedFeatures = form.watch(featureField);
9382
- const selectedModules = form.watch(moduleField);
9383
9387
  const toggleFeature = /* @__PURE__ */ __name((feature, checked) => {
9384
9388
  let newFeatureIds = [...selectedFeatures];
9385
- let newModuleIds = [...selectedModules];
9386
9389
  if (checked) {
9387
9390
  if (!newFeatureIds.includes(feature.id)) {
9388
9391
  newFeatureIds.push(feature.id);
9389
9392
  }
9390
- feature.modules.forEach((module) => {
9391
- if (!newModuleIds.includes(module.id)) {
9392
- newModuleIds.push(module.id);
9393
- }
9394
- });
9395
9393
  } else {
9396
9394
  newFeatureIds = newFeatureIds.filter((id) => id !== feature.id);
9397
- feature.modules.forEach((module) => {
9398
- newModuleIds = newModuleIds.filter((id) => id !== module.id);
9399
- });
9400
9395
  }
9401
9396
  form.setValue(featureField, newFeatureIds);
9402
- form.setValue(moduleField, newModuleIds);
9403
9397
  }, "toggleFeature");
9404
- const toggleModule = /* @__PURE__ */ __name((feature, module, checked) => {
9405
- const modulesForFeature = feature.modules.map((m) => m.id);
9406
- let newModuleIds = [...selectedModules];
9407
- if (checked) {
9408
- if (!selectedFeatures.includes(feature.id)) {
9409
- newModuleIds = newModuleIds.filter((id) => !modulesForFeature.includes(id));
9410
- newModuleIds.push(module.id);
9411
- form.setValue(featureField, [...selectedFeatures, feature.id]);
9412
- } else {
9413
- if (!newModuleIds.includes(module.id)) {
9414
- newModuleIds.push(module.id);
9415
- }
9416
- }
9417
- } else {
9418
- newModuleIds = newModuleIds.filter((id) => id !== module.id);
9419
- const remaining = feature.modules.filter((m) => newModuleIds.includes(m.id));
9420
- if (remaining.length === 0) {
9421
- form.setValue(
9422
- featureField,
9423
- selectedFeatures.filter((id) => id !== feature.id)
9424
- );
9425
- }
9426
- }
9427
- form.setValue(moduleField, newModuleIds);
9428
- }, "toggleModule");
9429
- const isFeatureChecked = /* @__PURE__ */ __name((feature) => selectedFeatures.includes(feature.id) || feature.modules.every((module) => selectedModules.includes(module.id)), "isFeatureChecked");
9398
+ const isFeatureChecked = /* @__PURE__ */ __name((feature) => selectedFeatures.includes(feature.id), "isFeatureChecked");
9430
9399
  return /* @__PURE__ */ jsxs72("div", { className: "flex w-full flex-col", children: [
9431
- name && /* @__PURE__ */ jsx120("h2", { className: "mb-5 font-semibold", children: name }),
9432
- features.map((feature) => /* @__PURE__ */ jsx120(
9433
- Accordion,
9434
- {
9435
- type: "single",
9436
- collapsible: true,
9437
- className: `w-full p-0`,
9438
- children: /* @__PURE__ */ jsxs72(AccordionItem, { value: feature.id, className: "p-0", children: [
9439
- /* @__PURE__ */ jsxs72(
9440
- "div",
9441
- {
9442
- className: `flex items-center justify-between p-0 ${feature.modules.filter((module) => !module.isCore).length === 0 ? "py-4" : ""}`,
9443
- children: [
9444
- /* @__PURE__ */ jsxs72("div", { className: "flex items-center", onClick: (e) => e.stopPropagation(), children: [
9445
- /* @__PURE__ */ jsx120(
9446
- Checkbox,
9447
- {
9448
- id: feature.id,
9449
- checked: isFeatureChecked(feature),
9450
- onCheckedChange: (val) => {
9451
- toggleFeature(feature, val === true);
9452
- }
9453
- }
9454
- ),
9455
- /* @__PURE__ */ jsx120(FormLabel, { htmlFor: feature.id, className: "ml-3 cursor-pointer font-normal", children: feature.name })
9456
- ] }),
9457
- feature.modules.filter((module) => !module.isCore).length > 0 && /* @__PURE__ */ jsx120(AccordionTrigger, { asChild: true, children: /* @__PURE__ */ jsx120("div", { className: "w-full" }) })
9458
- ]
9459
- }
9460
- ),
9461
- feature.modules.filter((module) => !module.isCore).length > 0 && /* @__PURE__ */ jsx120(AccordionContent, { className: "pl-6", children: feature.modules.filter((module) => !module.isCore).sort((a, b) => a.name.localeCompare(b.name)).map((module) => /* @__PURE__ */ jsxs72(
9462
- "div",
9463
- {
9464
- className: "flex items-center border-t py-2",
9465
- onClick: (e) => e.stopPropagation(),
9466
- children: [
9467
- /* @__PURE__ */ jsx120(
9468
- Checkbox,
9469
- {
9470
- id: module.id,
9471
- checked: selectedModules.includes(module.id),
9472
- onCheckedChange: (val) => {
9473
- toggleModule(feature, module, val === true);
9474
- }
9475
- }
9476
- ),
9477
- /* @__PURE__ */ jsx120(FormLabel, { htmlFor: module.id, className: "ml-3 cursor-pointer font-normal", children: module.name })
9478
- ]
9479
- },
9480
- module.id
9481
- )) })
9482
- ] })
9483
- },
9484
- feature.id
9485
- )),
9400
+ name && /* @__PURE__ */ jsx120("h2", { className: "mb-4 border-b text-lg font-semibold", children: name }),
9401
+ /* @__PURE__ */ jsx120(ScrollArea, { className: "h-[40vh]", children: /* @__PURE__ */ jsx120("div", { className: "flex flex-col gap-y-2 pr-4", children: features.filter((feature) => !feature.isCore).map((feature) => /* @__PURE__ */ jsxs72("div", { className: "flex items-center", children: [
9402
+ /* @__PURE__ */ jsx120(
9403
+ Checkbox,
9404
+ {
9405
+ id: feature.id,
9406
+ checked: isFeatureChecked(feature),
9407
+ onCheckedChange: (val) => {
9408
+ toggleFeature(feature, val === true);
9409
+ }
9410
+ }
9411
+ ),
9412
+ /* @__PURE__ */ jsx120(FormLabel, { htmlFor: feature.id, className: "ml-3 cursor-pointer font-normal", children: feature.name })
9413
+ ] }, feature.id)) }) }),
9486
9414
  /* @__PURE__ */ jsx120(FormMessage, {})
9487
9415
  ] });
9488
9416
  }
@@ -9645,22 +9573,6 @@ var cellUrl = /* @__PURE__ */ __name((params) => {
9645
9573
  };
9646
9574
  }, "cellUrl");
9647
9575
 
9648
- // src/client/context/JsonApiContext.ts
9649
- import { createContext as createContext15, useContext as useContext16 } from "react";
9650
- var JsonApiContext = createContext15(null);
9651
- function useJsonApiConfig() {
9652
- const config = useContext16(JsonApiContext);
9653
- if (!config) {
9654
- throw new Error("useJsonApiConfig must be used within a JsonApiProvider");
9655
- }
9656
- return config;
9657
- }
9658
- __name(useJsonApiConfig, "useJsonApiConfig");
9659
- function useJsonApiConfigOptional() {
9660
- return useContext16(JsonApiContext);
9661
- }
9662
- __name(useJsonApiConfigOptional, "useJsonApiConfigOptional");
9663
-
9664
9576
  // src/client/context/JsonApiProvider.tsx
9665
9577
  import { useEffect as useEffect30, useMemo as useMemo10 } from "react";
9666
9578
  import { jsx as jsx127 } from "react/jsx-runtime";
@@ -9688,7 +9600,7 @@ function useJsonApiGet(params) {
9688
9600
  setLoading(true);
9689
9601
  setError(null);
9690
9602
  try {
9691
- const { JsonApiGet } = await import("./JsonApiRequest-HFWXMKMA.mjs");
9603
+ const { JsonApiGet } = await import("./JsonApiRequest-XWQWTFEQ.mjs");
9692
9604
  const language = navigator.language.split("-")[0] || "en";
9693
9605
  const apiResponse = await JsonApiGet({
9694
9606
  classKey: params.classKey,
@@ -9793,7 +9705,7 @@ function useJsonApiMutation(config) {
9793
9705
  setLoading(true);
9794
9706
  setError(null);
9795
9707
  try {
9796
- const { JsonApiPost, JsonApiPut, JsonApiPatch, JsonApiDelete } = await import("./JsonApiRequest-HFWXMKMA.mjs");
9708
+ const { JsonApiPost, JsonApiPut, JsonApiPatch, JsonApiDelete } = await import("./JsonApiRequest-XWQWTFEQ.mjs");
9797
9709
  const language = navigator.language.split("-")[0] || "en";
9798
9710
  let apiResponse;
9799
9711
  switch (config.method) {
@@ -10440,7 +10352,7 @@ var ContentListTable = memo(/* @__PURE__ */ __name(function ContentListTable2(pr
10440
10352
  import Image10 from "next/image";
10441
10353
 
10442
10354
  // src/features/auth/contexts/AuthContext.tsx
10443
- import { createContext as createContext16, useContext as useContext17, useMemo as useMemo17, useState as useState43 } from "react";
10355
+ import { createContext as createContext15, useContext as useContext16, useMemo as useMemo17, useState as useState43 } from "react";
10444
10356
 
10445
10357
  // src/features/auth/components/forms/Register.tsx
10446
10358
  import { zodResolver as zodResolver5 } from "@hookform/resolvers/zod";
@@ -10455,7 +10367,7 @@ function Register() {
10455
10367
  const t = useTranslations46();
10456
10368
  const { setComponentType } = useAuthContext();
10457
10369
  const [showConfirmation, setShowConfirmation] = useState42(false);
10458
- const formSchema = z5.object({
10370
+ const formSchema2 = z5.object({
10459
10371
  company: z5.string().min(1, {
10460
10372
  message: t(`generic.errors.missing_company_name`)
10461
10373
  }),
@@ -10470,7 +10382,7 @@ function Register() {
10470
10382
  })
10471
10383
  });
10472
10384
  const form = useForm5({
10473
- resolver: zodResolver5(formSchema),
10385
+ resolver: zodResolver5(formSchema2),
10474
10386
  defaultValues: {
10475
10387
  company: "",
10476
10388
  name: "",
@@ -10572,7 +10484,7 @@ __name(Register, "Register");
10572
10484
 
10573
10485
  // src/features/auth/contexts/AuthContext.tsx
10574
10486
  import { jsx as jsx135 } from "react/jsx-runtime";
10575
- var AuthContext = createContext16(void 0);
10487
+ var AuthContext = createContext15(void 0);
10576
10488
  var AuthContextProvider = /* @__PURE__ */ __name(({
10577
10489
  children,
10578
10490
  initialComponentType,
@@ -10613,7 +10525,7 @@ var AuthContextProvider = /* @__PURE__ */ __name(({
10613
10525
  );
10614
10526
  }, "AuthContextProvider");
10615
10527
  var useAuthContext = /* @__PURE__ */ __name(() => {
10616
- const context = useContext17(AuthContext);
10528
+ const context = useContext16(AuthContext);
10617
10529
  if (context === void 0) {
10618
10530
  throw new Error("useAuthContext must be used within a AuthComponentProvider");
10619
10531
  }
@@ -10650,8 +10562,8 @@ function LandingComponent() {
10650
10562
  /* @__PURE__ */ jsx137(CardDescription, { className: "flex w-full justify-center text-center text-sm", children: t(`generic.description`) })
10651
10563
  ] }),
10652
10564
  /* @__PURE__ */ jsxs80(CardFooter, { className: "mt-4 flex w-full flex-col justify-between gap-y-4", children: [
10653
- isInternalAuthConfigured() && /* @__PURE__ */ jsxs80(Fragment21, { children: [
10654
- /* @__PURE__ */ jsx137(
10565
+ isInternalAuthEnabled() && /* @__PURE__ */ jsxs80(Fragment21, { children: [
10566
+ isRegistrationAllowed() && /* @__PURE__ */ jsx137(
10655
10567
  Link2,
10656
10568
  {
10657
10569
  href: "#",
@@ -10662,7 +10574,7 @@ function LandingComponent() {
10662
10574
  ),
10663
10575
  /* @__PURE__ */ jsx137(Link2, { href: "#", className: "flex w-full justify-end", onClick: () => setComponentType(0 /* Login */), children: /* @__PURE__ */ jsx137(Button, { className: "w-full", variant: `outline`, "data-testid": "page-login-button-initial-login", children: t(`foundations.auth.buttons.login`) }) })
10664
10576
  ] }),
10665
- isDiscordConfigured() && /* @__PURE__ */ jsx137(Link2, { href: `${getApiUrl()}auth/discord`, className: "flex w-full justify-end", children: /* @__PURE__ */ jsx137(Button, { className: "w-full", variant: `outline`, "data-testid": "page-login-button-initial-login", children: "Login with Discord" }) })
10577
+ isDiscordAuthEnabled() && /* @__PURE__ */ jsx137(Link2, { href: `${getApiUrl()}auth/discord`, className: "flex w-full justify-end", children: /* @__PURE__ */ jsx137(Button, { className: "w-full", variant: `outline`, "data-testid": "page-login-button-initial-login", children: "Login with Discord" }) })
10666
10578
  ] })
10667
10579
  ] });
10668
10580
  }
@@ -10701,7 +10613,7 @@ function AcceptInvitation() {
10701
10613
  setError(t(`foundations.auth.errors.invalid_invitation_code`));
10702
10614
  }
10703
10615
  }, []);
10704
- const formSchema = z6.object({
10616
+ const formSchema2 = z6.object({
10705
10617
  password: z6.string().min(1, {
10706
10618
  message: t(`foundations.user.fields.password.error`)
10707
10619
  }),
@@ -10713,7 +10625,7 @@ function AcceptInvitation() {
10713
10625
  path: ["passwordRetype"]
10714
10626
  });
10715
10627
  const form = useForm6({
10716
- resolver: zodResolver6(formSchema),
10628
+ resolver: zodResolver6(formSchema2),
10717
10629
  defaultValues: {
10718
10630
  password: "",
10719
10631
  passwordRetype: ""
@@ -10860,13 +10772,13 @@ function ForgotPassword() {
10860
10772
  const t = useTranslations50();
10861
10773
  const { setComponentType } = useAuthContext();
10862
10774
  const [showConfirmation, setShowConfirmation] = useState47(false);
10863
- const formSchema = z7.object({
10775
+ const formSchema2 = z7.object({
10864
10776
  email: z7.string().email({
10865
10777
  message: t(`generic.errors.invalid_email`)
10866
10778
  })
10867
10779
  });
10868
10780
  const form = useForm7({
10869
- resolver: zodResolver7(formSchema),
10781
+ resolver: zodResolver7(formSchema2),
10870
10782
  defaultValues: {
10871
10783
  email: ""
10872
10784
  }
@@ -10932,14 +10844,14 @@ function Login() {
10932
10844
  const { setComponentType } = useAuthContext();
10933
10845
  const generateUrl = usePageUrlGenerator();
10934
10846
  const router = useI18nRouter();
10935
- const formSchema = z8.object({
10847
+ const formSchema2 = z8.object({
10936
10848
  email: z8.string().email({
10937
10849
  message: t(`generic.errors.invalid_email`)
10938
10850
  }),
10939
10851
  password: z8.string().min(3, { message: t(`foundations.auth.errors.password_too_short`) })
10940
10852
  });
10941
10853
  const form = useForm8({
10942
- resolver: zodResolver8(formSchema),
10854
+ resolver: zodResolver8(formSchema2),
10943
10855
  defaultValues: {
10944
10856
  email: "",
10945
10857
  password: ""
@@ -11099,7 +11011,7 @@ function ResetPassword() {
11099
11011
  setError(t(`foundations.auth.errors.invalid_password_reset_code`));
11100
11012
  }
11101
11013
  }, []);
11102
- const formSchema = z9.object({
11014
+ const formSchema2 = z9.object({
11103
11015
  password: z9.string().min(1, {
11104
11016
  message: t(`foundations.user.fields.password.error`)
11105
11017
  }),
@@ -11111,7 +11023,7 @@ function ResetPassword() {
11111
11023
  path: ["passwordRetype"]
11112
11024
  });
11113
11025
  const form = useForm9({
11114
- resolver: zodResolver9(formSchema),
11026
+ resolver: zodResolver9(formSchema2),
11115
11027
  defaultValues: {
11116
11028
  password: "",
11117
11029
  passwordRetype: ""
@@ -11154,217 +11066,3580 @@ function ResetPassword() {
11154
11066
  }
11155
11067
  __name(ResetPassword, "ResetPassword");
11156
11068
 
11157
- // src/features/content/components/lists/ContentsList.tsx
11158
- import { useTranslations as useTranslations53 } from "next-intl";
11069
+ // src/features/billing/components/cards/SubscriptionSummaryCard.tsx
11070
+ import { ChevronRight, CreditCard } from "lucide-react";
11159
11071
  import { jsx as jsx144, jsxs as jsxs86 } from "react/jsx-runtime";
11160
- function ContentsList({ contentList }) {
11161
- const t = useTranslations53();
11162
- return /* @__PURE__ */ jsxs86("div", { className: "flex min-h-0 w-full flex-col overflow-y-auto", children: [
11163
- /* @__PURE__ */ jsx144("h2", { className: "text-xl font-semibold", children: t(`foundations.content.news`) }),
11164
- /* @__PURE__ */ jsx144("div", { className: "flex flex-col", children: contentList.map((content) => /* @__PURE__ */ jsx144(ContentsListElement, { content }, content.id)) })
11165
- ] });
11166
- }
11167
- __name(ContentsList, "ContentsList");
11168
- function ContentsListElement({ content }) {
11169
- const generateUrl = usePageUrlGenerator();
11170
- const contentModule = content.contentType ? Modules.findByModelName(content.contentType) : void 0;
11171
- const link = contentModule ? generateUrl({ page: contentModule, id: content.id }) : "#";
11172
- return /* @__PURE__ */ jsx144("div", { className: "hover:bg-muted flex w-full flex-col gap-y-2 border-b p-2 py-4", children: /* @__PURE__ */ jsxs86("div", { className: "flex w-full justify-between gap-x-2", children: [
11173
- /* @__PURE__ */ jsxs86(HoverCard, { children: [
11174
- /* @__PURE__ */ jsx144(HoverCardTrigger, { asChild: true, children: /* @__PURE__ */ jsxs86(Link2, { href: link, className: "flex w-full items-center justify-start gap-2 font-semibold", children: [
11175
- contentModule && getIconByModule({ module: contentModule, className: "h-4 w-4" }),
11176
- content.name
11177
- ] }) }),
11178
- /* @__PURE__ */ jsxs86(HoverCardContent, { className: "flex max-h-96 w-96 flex-col gap-y-4 overflow-y-auto", children: [
11179
- /* @__PURE__ */ jsx144(Link2, { href: link, className: "font-semibold", children: content.name }),
11180
- /* @__PURE__ */ jsx144("div", { className: "text-xs", children: content.abstract })
11181
- ] })
11182
- ] }),
11183
- /* @__PURE__ */ jsx144(ContributorsList, { content })
11184
- ] }) });
11185
- }
11186
- __name(ContentsListElement, "ContentsListElement");
11187
-
11188
- // src/features/content/components/lists/ContentsListById.tsx
11189
- import { useTranslations as useTranslations54 } from "next-intl";
11190
- import { jsx as jsx145 } from "react/jsx-runtime";
11191
- function ContentsListById({ contentIds }) {
11192
- const t = useTranslations54();
11193
- const data = useDataListRetriever({
11194
- module: Modules.Content,
11195
- retriever: /* @__PURE__ */ __name((params) => ContentService.findMany(params), "retriever"),
11196
- retrieverParams: { contentIds }
11072
+ function getStatusBadgeVariant(status) {
11073
+ switch (status) {
11074
+ case "active" /* ACTIVE */:
11075
+ return "default";
11076
+ case "trialing" /* TRIALING */:
11077
+ return "secondary";
11078
+ case "past_due" /* PAST_DUE */:
11079
+ case "unpaid" /* UNPAID */:
11080
+ case "canceled" /* CANCELED */:
11081
+ return "destructive";
11082
+ default:
11083
+ return "outline";
11084
+ }
11085
+ }
11086
+ __name(getStatusBadgeVariant, "getStatusBadgeVariant");
11087
+ function formatDate(date) {
11088
+ return new Date(date).toLocaleDateString(void 0, {
11089
+ year: "numeric",
11090
+ month: "short",
11091
+ day: "numeric"
11197
11092
  });
11198
- return /* @__PURE__ */ jsx145(
11199
- ContentListTable,
11200
- {
11201
- data,
11202
- fields: ["name" /* name */, "authors" /* authors */, "updatedAt" /* updatedAt */],
11203
- tableGeneratorType: Modules.Content,
11204
- title: t(`generic.relevant`)
11205
- }
11206
- );
11207
11093
  }
11208
- __name(ContentsListById, "ContentsListById");
11209
-
11210
- // src/features/content/components/lists/RelevantContentsList.tsx
11211
- import { useTranslations as useTranslations55 } from "next-intl";
11212
- import { jsx as jsx146 } from "react/jsx-runtime";
11213
- function RelevantContentsList({ id }) {
11214
- const t = useTranslations55();
11215
- const data = useDataListRetriever({
11216
- module: Modules.Content,
11217
- retriever: /* @__PURE__ */ __name((params) => ContentService.findRelevant(params), "retriever"),
11218
- retrieverParams: { id }
11219
- });
11220
- return /* @__PURE__ */ jsx146(
11221
- ContentListTable,
11222
- {
11223
- data,
11224
- fields: ["name" /* name */, "authors" /* authors */, "relevance" /* relevance */, "updatedAt" /* updatedAt */],
11225
- tableGeneratorType: Modules.Content,
11226
- title: t(`generic.relevant`)
11227
- }
11094
+ __name(formatDate, "formatDate");
11095
+ function formatPrice(amount, currency) {
11096
+ if (amount === void 0) return "N/A";
11097
+ const currencyCode = currency?.toUpperCase() || "USD";
11098
+ return new Intl.NumberFormat(void 0, {
11099
+ style: "currency",
11100
+ currency: currencyCode
11101
+ }).format(amount / 100);
11102
+ }
11103
+ __name(formatPrice, "formatPrice");
11104
+ function formatPlanName(subscription) {
11105
+ const productName = subscription.price?.product?.name || "";
11106
+ const nickname = subscription.price?.nickname || "";
11107
+ if (productName && nickname) {
11108
+ return `${productName} - ${nickname}`;
11109
+ }
11110
+ return productName || nickname || "Subscription";
11111
+ }
11112
+ __name(formatPlanName, "formatPlanName");
11113
+ function SubscriptionSummaryCard({
11114
+ subscriptions,
11115
+ loading,
11116
+ error,
11117
+ onManageClick
11118
+ }) {
11119
+ if (loading) {
11120
+ return /* @__PURE__ */ jsxs86(Card, { children: [
11121
+ /* @__PURE__ */ jsxs86(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11122
+ /* @__PURE__ */ jsx144(CardTitle, { className: "text-sm font-medium", children: "Subscriptions" }),
11123
+ /* @__PURE__ */ jsx144(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
11124
+ ] }),
11125
+ /* @__PURE__ */ jsxs86(CardContent, { children: [
11126
+ /* @__PURE__ */ jsx144(Skeleton, { className: "h-6 w-32 mb-2" }),
11127
+ /* @__PURE__ */ jsx144(Skeleton, { className: "h-4 w-24 mb-1" }),
11128
+ /* @__PURE__ */ jsx144(Skeleton, { className: "h-4 w-40" })
11129
+ ] })
11130
+ ] });
11131
+ }
11132
+ if (error) {
11133
+ return /* @__PURE__ */ jsxs86(Card, { children: [
11134
+ /* @__PURE__ */ jsxs86(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11135
+ /* @__PURE__ */ jsx144(CardTitle, { className: "text-sm font-medium", children: "Subscriptions" }),
11136
+ /* @__PURE__ */ jsx144(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
11137
+ ] }),
11138
+ /* @__PURE__ */ jsx144(CardContent, { children: /* @__PURE__ */ jsx144("p", { className: "text-sm text-destructive", children: error }) })
11139
+ ] });
11140
+ }
11141
+ const activeSubscriptions = subscriptions.filter(
11142
+ (sub) => sub.status === "active" /* ACTIVE */ || sub.status === "trialing" /* TRIALING */
11228
11143
  );
11144
+ const primarySubscription = activeSubscriptions[0];
11145
+ return /* @__PURE__ */ jsxs86(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onManageClick, children: [
11146
+ /* @__PURE__ */ jsxs86(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11147
+ /* @__PURE__ */ jsx144(CardTitle, { className: "text-sm font-medium", children: "Subscriptions" }),
11148
+ /* @__PURE__ */ jsx144(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
11149
+ ] }),
11150
+ /* @__PURE__ */ jsx144(CardContent, { children: subscriptions.length === 0 ? /* @__PURE__ */ jsxs86("div", { className: "space-y-2", children: [
11151
+ /* @__PURE__ */ jsx144("p", { className: "text-xl font-bold text-muted-foreground", children: "No active plan" }),
11152
+ /* @__PURE__ */ jsx144("p", { className: "text-xs text-muted-foreground", children: "Subscribe to get started" }),
11153
+ /* @__PURE__ */ jsxs86(
11154
+ Button,
11155
+ {
11156
+ variant: "outline",
11157
+ size: "sm",
11158
+ className: "mt-2",
11159
+ onClick: (e) => {
11160
+ e.stopPropagation();
11161
+ onManageClick();
11162
+ },
11163
+ children: [
11164
+ "View Plans",
11165
+ /* @__PURE__ */ jsx144(ChevronRight, { className: "h-4 w-4 ml-1" })
11166
+ ]
11167
+ }
11168
+ )
11169
+ ] }) : primarySubscription ? /* @__PURE__ */ jsxs86("div", { className: "space-y-2", children: [
11170
+ /* @__PURE__ */ jsxs86("div", { className: "flex items-center gap-2", children: [
11171
+ /* @__PURE__ */ jsx144("p", { className: "text-xl font-bold", children: formatPlanName(primarySubscription) }),
11172
+ /* @__PURE__ */ jsx144(Badge, { variant: primarySubscription.cancelAtPeriodEnd ? "secondary" : getStatusBadgeVariant(primarySubscription.status), children: primarySubscription.cancelAtPeriodEnd ? "Canceling" : primarySubscription.status })
11173
+ ] }),
11174
+ /* @__PURE__ */ jsxs86("p", { className: "text-sm text-muted-foreground", children: [
11175
+ formatPrice(primarySubscription.price?.unitAmount, primarySubscription.price?.currency),
11176
+ primarySubscription.price?.recurring && /* @__PURE__ */ jsxs86("span", { children: [
11177
+ "/",
11178
+ primarySubscription.price.recurring.interval
11179
+ ] })
11180
+ ] }),
11181
+ /* @__PURE__ */ jsx144("p", { className: "text-xs text-muted-foreground", children: primarySubscription.cancelAtPeriodEnd ? `Cancels on ${formatDate(primarySubscription.currentPeriodEnd)}` : `Renews on ${formatDate(primarySubscription.currentPeriodEnd)}` }),
11182
+ activeSubscriptions.length > 1 && /* @__PURE__ */ jsxs86("p", { className: "text-xs text-muted-foreground", children: [
11183
+ "+",
11184
+ activeSubscriptions.length - 1,
11185
+ " more subscription(s)"
11186
+ ] })
11187
+ ] }) : null })
11188
+ ] });
11229
11189
  }
11230
- __name(RelevantContentsList, "RelevantContentsList");
11231
-
11232
- // src/features/notification/components/common/NotificationErrorBoundary.tsx
11233
- import { Component } from "react";
11234
- import { jsx as jsx147, jsxs as jsxs87 } from "react/jsx-runtime";
11235
- var NotificationErrorBoundary = class extends Component {
11236
- static {
11237
- __name(this, "NotificationErrorBoundary");
11190
+ __name(SubscriptionSummaryCard, "SubscriptionSummaryCard");
11191
+
11192
+ // src/features/billing/components/cards/PaymentMethodSummaryCard.tsx
11193
+ import { Wallet, ChevronRight as ChevronRight2 } from "lucide-react";
11194
+ import { jsx as jsx145, jsxs as jsxs87 } from "react/jsx-runtime";
11195
+ function getCardBrandIcon(brand) {
11196
+ const brandMap = {
11197
+ visa: "Visa",
11198
+ mastercard: "Mastercard",
11199
+ amex: "Amex",
11200
+ discover: "Discover",
11201
+ diners: "Diners",
11202
+ jcb: "JCB",
11203
+ unionpay: "UnionPay"
11204
+ };
11205
+ return brandMap[brand.toLowerCase()] || brand;
11206
+ }
11207
+ __name(getCardBrandIcon, "getCardBrandIcon");
11208
+ function PaymentMethodSummaryCard({
11209
+ paymentMethods,
11210
+ defaultPaymentMethodId,
11211
+ loading,
11212
+ error,
11213
+ onManageClick
11214
+ }) {
11215
+ if (loading) {
11216
+ return /* @__PURE__ */ jsxs87(Card, { children: [
11217
+ /* @__PURE__ */ jsxs87(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11218
+ /* @__PURE__ */ jsx145(CardTitle, { className: "text-sm font-medium", children: "Payment Method" }),
11219
+ /* @__PURE__ */ jsx145(Wallet, { className: "h-4 w-4 text-muted-foreground" })
11220
+ ] }),
11221
+ /* @__PURE__ */ jsxs87(CardContent, { children: [
11222
+ /* @__PURE__ */ jsx145(Skeleton, { className: "h-6 w-32 mb-2" }),
11223
+ /* @__PURE__ */ jsx145(Skeleton, { className: "h-4 w-24" })
11224
+ ] })
11225
+ ] });
11238
11226
  }
11239
- constructor(props) {
11240
- super(props);
11241
- this.state = { hasError: false };
11227
+ if (error) {
11228
+ return /* @__PURE__ */ jsxs87(Card, { children: [
11229
+ /* @__PURE__ */ jsxs87(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11230
+ /* @__PURE__ */ jsx145(CardTitle, { className: "text-sm font-medium", children: "Payment Method" }),
11231
+ /* @__PURE__ */ jsx145(Wallet, { className: "h-4 w-4 text-muted-foreground" })
11232
+ ] }),
11233
+ /* @__PURE__ */ jsx145(CardContent, { children: /* @__PURE__ */ jsx145("p", { className: "text-sm text-destructive", children: error }) })
11234
+ ] });
11242
11235
  }
11243
- static getDerivedStateFromError(error) {
11244
- return { hasError: true, error };
11236
+ const defaultMethod = paymentMethods.find((pm) => pm.id === defaultPaymentMethodId) || paymentMethods[0];
11237
+ return /* @__PURE__ */ jsxs87(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onManageClick, children: [
11238
+ /* @__PURE__ */ jsxs87(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11239
+ /* @__PURE__ */ jsx145(CardTitle, { className: "text-sm font-medium", children: "Payment Method" }),
11240
+ /* @__PURE__ */ jsx145(Wallet, { className: "h-4 w-4 text-muted-foreground" })
11241
+ ] }),
11242
+ /* @__PURE__ */ jsx145(CardContent, { children: paymentMethods.length === 0 ? /* @__PURE__ */ jsxs87("div", { className: "space-y-2", children: [
11243
+ /* @__PURE__ */ jsx145("p", { className: "text-xl font-bold text-muted-foreground", children: "No payment method" }),
11244
+ /* @__PURE__ */ jsx145("p", { className: "text-xs text-muted-foreground", children: "Add a card to enable subscriptions" }),
11245
+ /* @__PURE__ */ jsxs87(Button, { variant: "outline", size: "sm", className: "mt-2", onClick: (e) => {
11246
+ e.stopPropagation();
11247
+ onManageClick();
11248
+ }, children: [
11249
+ "Add Card",
11250
+ /* @__PURE__ */ jsx145(ChevronRight2, { className: "h-4 w-4 ml-1" })
11251
+ ] })
11252
+ ] }) : defaultMethod?.card ? /* @__PURE__ */ jsxs87("div", { className: "space-y-2", children: [
11253
+ /* @__PURE__ */ jsxs87("p", { className: "text-xl font-bold", children: [
11254
+ getCardBrandIcon(defaultMethod.card.brand),
11255
+ " ****",
11256
+ defaultMethod.card.last4
11257
+ ] }),
11258
+ /* @__PURE__ */ jsxs87("p", { className: "text-sm text-muted-foreground", children: [
11259
+ "Expires ",
11260
+ String(defaultMethod.card.expMonth).padStart(2, "0"),
11261
+ "/",
11262
+ defaultMethod.card.expYear
11263
+ ] }),
11264
+ paymentMethods.length > 1 && /* @__PURE__ */ jsxs87("p", { className: "text-xs text-muted-foreground", children: [
11265
+ "+",
11266
+ paymentMethods.length - 1,
11267
+ " more card(s)"
11268
+ ] })
11269
+ ] }) : /* @__PURE__ */ jsxs87("div", { className: "space-y-2", children: [
11270
+ /* @__PURE__ */ jsx145("p", { className: "text-xl font-bold", children: defaultMethod?.type || "Payment Method" }),
11271
+ paymentMethods.length > 1 && /* @__PURE__ */ jsxs87("p", { className: "text-xs text-muted-foreground", children: [
11272
+ "+",
11273
+ paymentMethods.length - 1,
11274
+ " more method(s)"
11275
+ ] })
11276
+ ] }) })
11277
+ ] });
11278
+ }
11279
+ __name(PaymentMethodSummaryCard, "PaymentMethodSummaryCard");
11280
+
11281
+ // src/features/billing/components/cards/CustomerInfoCard.tsx
11282
+ import { ExternalLink, User } from "lucide-react";
11283
+ import { useState as useState49 } from "react";
11284
+ import { jsx as jsx146, jsxs as jsxs88 } from "react/jsx-runtime";
11285
+ function formatBalance(balance, currency) {
11286
+ if (balance === void 0 || balance === 0) return "$0.00";
11287
+ const currencyCode = currency?.toUpperCase() || "USD";
11288
+ const displayBalance = -balance;
11289
+ return new Intl.NumberFormat(void 0, {
11290
+ style: "currency",
11291
+ currency: currencyCode
11292
+ }).format(displayBalance / 100);
11293
+ }
11294
+ __name(formatBalance, "formatBalance");
11295
+ function CustomerInfoCard({ customer, loading, error }) {
11296
+ const [portalLoading, setPortalLoading] = useState49(false);
11297
+ const handlePortalClick = /* @__PURE__ */ __name(async (e) => {
11298
+ e.stopPropagation();
11299
+ setPortalLoading(true);
11300
+ try {
11301
+ const { url } = await StripeCustomerService.createPortalSession();
11302
+ window.open(url, "_blank");
11303
+ } catch (err) {
11304
+ console.error("[CustomerInfoCard] Failed to create portal session:", err);
11305
+ } finally {
11306
+ setPortalLoading(false);
11307
+ }
11308
+ }, "handlePortalClick");
11309
+ if (loading) {
11310
+ return /* @__PURE__ */ jsxs88(Card, { children: [
11311
+ /* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11312
+ /* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
11313
+ /* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
11314
+ ] }),
11315
+ /* @__PURE__ */ jsxs88(CardContent, { children: [
11316
+ /* @__PURE__ */ jsx146(Skeleton, { className: "h-6 w-32 mb-2" }),
11317
+ /* @__PURE__ */ jsx146(Skeleton, { className: "h-4 w-48 mb-1" }),
11318
+ /* @__PURE__ */ jsx146(Skeleton, { className: "h-4 w-24" })
11319
+ ] })
11320
+ ] });
11245
11321
  }
11246
- componentDidCatch(error, errorInfo) {
11247
- console.error("\u{1F6A8} [NotificationErrorBoundary] Caught error:", error, errorInfo);
11322
+ if (error) {
11323
+ return /* @__PURE__ */ jsxs88(Card, { children: [
11324
+ /* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11325
+ /* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
11326
+ /* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
11327
+ ] }),
11328
+ /* @__PURE__ */ jsx146(CardContent, { children: /* @__PURE__ */ jsx146("p", { className: "text-sm text-destructive", children: error }) })
11329
+ ] });
11248
11330
  }
11249
- render() {
11250
- if (this.state.hasError) {
11251
- return this.props.fallback || /* @__PURE__ */ jsx147("div", { className: "flex items-center justify-center p-4 text-center", children: /* @__PURE__ */ jsxs87("div", { className: "text-muted-foreground text-sm", children: [
11252
- /* @__PURE__ */ jsx147("p", { children: "Something went wrong with notifications." }),
11253
- /* @__PURE__ */ jsx147(
11254
- "button",
11255
- {
11256
- onClick: () => this.setState({ hasError: false }),
11257
- className: "text-primary mt-2 underline hover:no-underline",
11258
- children: "Try again"
11259
- }
11260
- )
11261
- ] }) });
11262
- }
11263
- return this.props.children;
11331
+ if (!customer) {
11332
+ return /* @__PURE__ */ jsxs88(Card, { children: [
11333
+ /* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11334
+ /* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
11335
+ /* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
11336
+ ] }),
11337
+ /* @__PURE__ */ jsxs88(CardContent, { children: [
11338
+ /* @__PURE__ */ jsx146("p", { className: "text-xl font-bold text-muted-foreground", children: "Not set up" }),
11339
+ /* @__PURE__ */ jsx146("p", { className: "text-xs text-muted-foreground", children: "Billing account will be created when you subscribe" })
11340
+ ] })
11341
+ ] });
11264
11342
  }
11265
- };
11266
-
11267
- // src/features/notification/components/containers/NotificationsListContainer.tsx
11268
- import { useTranslations as useTranslations57 } from "next-intl";
11269
-
11270
- // src/features/notification/components/lists/NotificationsList.tsx
11271
- import { ArchiveIcon } from "lucide-react";
11272
- import { useTranslations as useTranslations56 } from "next-intl";
11273
- import { Fragment as Fragment28, jsx as jsx148, jsxs as jsxs88 } from "react/jsx-runtime";
11274
- function NotificationsList({ archived }) {
11275
- const t = useTranslations56();
11276
- const generateUrl = usePageUrlGenerator();
11277
- const data = useDataListRetriever({
11278
- retriever: /* @__PURE__ */ __name((params) => NotificationService.findMany(params), "retriever"),
11279
- retrieverParams: { isArchived: archived },
11280
- module: Modules.Notification
11343
+ return /* @__PURE__ */ jsxs88(Card, { children: [
11344
+ /* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11345
+ /* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
11346
+ /* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
11347
+ ] }),
11348
+ /* @__PURE__ */ jsx146(CardContent, { children: /* @__PURE__ */ jsxs88("div", { className: "space-y-2", children: [
11349
+ customer.name && /* @__PURE__ */ jsx146("p", { className: "text-xl font-bold", children: customer.name }),
11350
+ customer.email && /* @__PURE__ */ jsx146("p", { className: "text-sm text-muted-foreground", children: customer.email }),
11351
+ customer.balance !== void 0 && customer.balance !== 0 && /* @__PURE__ */ jsxs88("p", { className: "text-sm", children: [
11352
+ /* @__PURE__ */ jsx146("span", { className: "text-muted-foreground", children: "Credit Balance: " }),
11353
+ /* @__PURE__ */ jsx146("span", { className: customer.balance < 0 ? "text-green-600" : "text-destructive", children: formatBalance(customer.balance, customer.currency) })
11354
+ ] }),
11355
+ /* @__PURE__ */ jsxs88(Button, { variant: "outline", size: "sm", className: "mt-2", onClick: handlePortalClick, disabled: portalLoading, children: [
11356
+ portalLoading ? "Loading..." : "Manage in Stripe Portal",
11357
+ /* @__PURE__ */ jsx146(ExternalLink, { className: "h-4 w-4 ml-1" })
11358
+ ] })
11359
+ ] }) })
11360
+ ] });
11361
+ }
11362
+ __name(CustomerInfoCard, "CustomerInfoCard");
11363
+
11364
+ // src/features/billing/components/cards/InvoicesSummaryCard.tsx
11365
+ import { ChevronRight as ChevronRight3, ReceiptIcon } from "lucide-react";
11366
+ import { jsx as jsx147, jsxs as jsxs89 } from "react/jsx-runtime";
11367
+ function getStatusBadgeVariant2(status) {
11368
+ switch (status) {
11369
+ case "paid" /* PAID */:
11370
+ return "default";
11371
+ case "open" /* OPEN */:
11372
+ return "secondary";
11373
+ case "uncollectible" /* UNCOLLECTIBLE */:
11374
+ case "void" /* VOID */:
11375
+ return "destructive";
11376
+ default:
11377
+ return "outline";
11378
+ }
11379
+ }
11380
+ __name(getStatusBadgeVariant2, "getStatusBadgeVariant");
11381
+ function formatDate2(date) {
11382
+ return new Date(date).toLocaleDateString(void 0, {
11383
+ year: "numeric",
11384
+ month: "short",
11385
+ day: "numeric"
11281
11386
  });
11282
- const archiveNotification = /* @__PURE__ */ __name(async (notification) => {
11283
- await NotificationService.archive({ id: notification.id });
11284
- data.removeElement(notification);
11285
- }, "archiveNotification");
11286
- const LoadingSkeleton = /* @__PURE__ */ __name(() => /* @__PURE__ */ jsx148("div", { className: "space-y-4", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx148(Card, { children: /* @__PURE__ */ jsx148(CardContent, { className: "p-2", children: /* @__PURE__ */ jsxs88("div", { className: "flex w-full flex-row items-center", children: [
11287
- /* @__PURE__ */ jsx148(Skeleton, { className: "mr-4 h-8 w-8 rounded-full" }),
11288
- /* @__PURE__ */ jsxs88("div", { className: "flex-1 space-y-2", children: [
11289
- /* @__PURE__ */ jsx148(Skeleton, { className: "h-4 w-3/4" }),
11290
- /* @__PURE__ */ jsx148(Skeleton, { className: "h-3 w-1/2" })
11387
+ }
11388
+ __name(formatDate2, "formatDate");
11389
+ function formatAmount(amount, currency) {
11390
+ const currencyCode = currency?.toUpperCase() || "USD";
11391
+ return new Intl.NumberFormat(void 0, {
11392
+ style: "currency",
11393
+ currency: currencyCode
11394
+ }).format(amount / 100);
11395
+ }
11396
+ __name(formatAmount, "formatAmount");
11397
+ function InvoicesSummaryCard({ invoices, loading, error, onViewAllClick }) {
11398
+ if (loading) {
11399
+ return /* @__PURE__ */ jsxs89(Card, { children: [
11400
+ /* @__PURE__ */ jsxs89(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11401
+ /* @__PURE__ */ jsx147(CardTitle, { className: "text-sm font-medium", children: "Recent Invoices" }),
11402
+ /* @__PURE__ */ jsx147(ReceiptIcon, { className: "h-4 w-4 text-muted-foreground" })
11403
+ ] }),
11404
+ /* @__PURE__ */ jsxs89(CardContent, { children: [
11405
+ /* @__PURE__ */ jsx147(Skeleton, { className: "h-6 w-24 mb-2" }),
11406
+ /* @__PURE__ */ jsx147(Skeleton, { className: "h-4 w-32 mb-1" }),
11407
+ /* @__PURE__ */ jsx147(Skeleton, { className: "h-4 w-20" })
11408
+ ] })
11409
+ ] });
11410
+ }
11411
+ if (error) {
11412
+ return /* @__PURE__ */ jsxs89(Card, { children: [
11413
+ /* @__PURE__ */ jsxs89(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11414
+ /* @__PURE__ */ jsx147(CardTitle, { className: "text-sm font-medium", children: "Recent Invoices" }),
11415
+ /* @__PURE__ */ jsx147(ReceiptIcon, { className: "h-4 w-4 text-muted-foreground" })
11416
+ ] }),
11417
+ /* @__PURE__ */ jsx147(CardContent, { children: /* @__PURE__ */ jsx147("p", { className: "text-sm text-destructive", children: error }) })
11418
+ ] });
11419
+ }
11420
+ const latestInvoice = invoices[0];
11421
+ const paidInvoices = invoices.filter((inv) => inv.status === "paid" /* PAID */);
11422
+ const openInvoices = invoices.filter((inv) => inv.status === "open" /* OPEN */);
11423
+ return /* @__PURE__ */ jsxs89(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onViewAllClick, children: [
11424
+ /* @__PURE__ */ jsxs89(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11425
+ /* @__PURE__ */ jsx147(CardTitle, { className: "text-sm font-medium", children: "Recent Invoices" }),
11426
+ /* @__PURE__ */ jsx147(ReceiptIcon, { className: "h-4 w-4 text-muted-foreground" })
11291
11427
  ] }),
11292
- /* @__PURE__ */ jsx148(Skeleton, { className: "h-8 w-20" })
11293
- ] }) }) }, i)) }), "LoadingSkeleton");
11294
- return /* @__PURE__ */ jsx148("div", { className: "space-y-4", children: data.isLoaded ? data.data?.map((notification) => {
11295
- const notificationData = generateNotificationData({ notification, generateUrl });
11296
- return /* @__PURE__ */ jsx148(Card, { children: /* @__PURE__ */ jsx148(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxs88("div", { className: `flex w-full flex-row items-center p-2`, children: [
11297
- notificationData.actor ? /* @__PURE__ */ jsx148("div", { className: "flex w-12 max-w-12 px-2", children: /* @__PURE__ */ jsx148(Link2, { href: generateUrl({ page: Modules.User, id: notificationData.actor.id }), children: /* @__PURE__ */ jsx148(UserAvatar, { user: notificationData.actor, className: "h-8 w-8" }) }) }) : /* @__PURE__ */ jsx148("div", { className: "flex w-14 max-w-14 px-2" }),
11298
- /* @__PURE__ */ jsxs88("div", { className: "flex w-full flex-col", children: [
11299
- /* @__PURE__ */ jsx148("p", { className: "text-sm", children: t.rich(`foundations.notification.${notification.notificationType}.description`, {
11300
- strong: /* @__PURE__ */ __name((chunks) => /* @__PURE__ */ jsx148("strong", { children: chunks }), "strong"),
11301
- actor: notificationData.actor?.name ?? "",
11302
- title: notificationData.title
11303
- }) }),
11304
- /* @__PURE__ */ jsx148("div", { className: "text-muted-foreground mt-1 w-full text-xs", children: new Date(notification.createdAt).toLocaleString() })
11428
+ /* @__PURE__ */ jsx147(CardContent, { children: invoices.length === 0 ? /* @__PURE__ */ jsxs89("div", { className: "space-y-2", children: [
11429
+ /* @__PURE__ */ jsx147("p", { className: "text-xl font-bold text-muted-foreground", children: "No invoices yet" }),
11430
+ /* @__PURE__ */ jsx147("p", { className: "text-xs text-muted-foreground", children: "Invoices will appear after your first billing cycle" })
11431
+ ] }) : latestInvoice ? /* @__PURE__ */ jsxs89("div", { className: "space-y-2", children: [
11432
+ /* @__PURE__ */ jsxs89("div", { className: "flex items-center gap-2", children: [
11433
+ /* @__PURE__ */ jsx147("p", { className: "text-xl font-bold", children: formatAmount(latestInvoice.total, latestInvoice.currency) }),
11434
+ /* @__PURE__ */ jsx147(Badge, { variant: getStatusBadgeVariant2(latestInvoice.status), children: latestInvoice.status })
11305
11435
  ] }),
11306
- /* @__PURE__ */ jsxs88("div", { className: "flex flex-row items-center", children: [
11307
- notificationData.url ? /* @__PURE__ */ jsx148(Link2, { href: notificationData.url, children: /* @__PURE__ */ jsx148(Button, { variant: `outline`, size: `sm`, onClick: (e) => e.stopPropagation(), children: t(`foundations.notification.${notification.notificationType}.buttons.action`) }) }) : /* @__PURE__ */ jsx148(Fragment28, {}),
11308
- !archived && /* @__PURE__ */ jsxs88(Tooltip2, { children: [
11309
- /* @__PURE__ */ jsx148(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx148(
11310
- Button,
11311
- {
11312
- variant: `link`,
11313
- onClick: (e) => {
11314
- e.preventDefault();
11315
- e.stopPropagation();
11316
- archiveNotification(notification);
11317
- },
11318
- className: "text-muted-foreground hover:text-destructive ml-2",
11319
- children: /* @__PURE__ */ jsx148(ArchiveIcon, { className: "h-4 w-4 cursor-pointer" })
11320
- }
11321
- ) }),
11322
- /* @__PURE__ */ jsx148(TooltipContent, { children: t(`foundations.notification.buttons.archive`) })
11436
+ /* @__PURE__ */ jsx147("p", { className: "text-sm text-muted-foreground", children: latestInvoice.stripeInvoiceNumber || `Invoice from ${formatDate2(latestInvoice.periodStart)}` }),
11437
+ /* @__PURE__ */ jsxs89("div", { className: "flex items-center gap-4 text-xs text-muted-foreground", children: [
11438
+ paidInvoices.length > 0 && /* @__PURE__ */ jsxs89("span", { children: [
11439
+ paidInvoices.length,
11440
+ " paid"
11441
+ ] }),
11442
+ openInvoices.length > 0 && /* @__PURE__ */ jsxs89("span", { className: "text-orange-600", children: [
11443
+ openInvoices.length,
11444
+ " open"
11445
+ ] }),
11446
+ /* @__PURE__ */ jsxs89("span", { className: "flex items-center", children: [
11447
+ "View all",
11448
+ /* @__PURE__ */ jsx147(ChevronRight3, { className: "h-3 w-3 ml-1" })
11323
11449
  ] })
11324
11450
  ] })
11325
- ] }) }) }, notification.id);
11326
- }) : /* @__PURE__ */ jsx148(LoadingSkeleton, {}) });
11451
+ ] }) : null })
11452
+ ] });
11327
11453
  }
11328
- __name(NotificationsList, "NotificationsList");
11329
-
11330
- // src/features/notification/components/containers/NotificationsListContainer.tsx
11331
- import { jsx as jsx149, jsxs as jsxs89 } from "react/jsx-runtime";
11332
- function NotificationsListContainerContent() {
11333
- const t = useTranslations57();
11334
- const { notifications, isLoading, error } = useNotificationContext();
11454
+ __name(InvoicesSummaryCard, "InvoicesSummaryCard");
11455
+
11456
+ // src/features/billing/components/cards/BillingUsageSummaryCard.tsx
11457
+ import { Activity, ChevronRight as ChevronRight4 } from "lucide-react";
11458
+ import { jsx as jsx148, jsxs as jsxs90 } from "react/jsx-runtime";
11459
+ function formatNumber(value) {
11460
+ return new Intl.NumberFormat(void 0, {
11461
+ notation: "compact",
11462
+ compactDisplay: "short"
11463
+ }).format(value);
11464
+ }
11465
+ __name(formatNumber, "formatNumber");
11466
+ function BillingUsageSummaryCard({
11467
+ meters,
11468
+ summaries,
11469
+ loading,
11470
+ error,
11471
+ onViewDetailsClick
11472
+ }) {
11473
+ if (loading) {
11474
+ return /* @__PURE__ */ jsxs90(Card, { children: [
11475
+ /* @__PURE__ */ jsxs90(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11476
+ /* @__PURE__ */ jsx148(CardTitle, { className: "text-sm font-medium", children: "Usage This Month" }),
11477
+ /* @__PURE__ */ jsx148(Activity, { className: "h-4 w-4 text-muted-foreground" })
11478
+ ] }),
11479
+ /* @__PURE__ */ jsxs90(CardContent, { children: [
11480
+ /* @__PURE__ */ jsx148(Skeleton, { className: "h-6 w-24 mb-2" }),
11481
+ /* @__PURE__ */ jsx148(Skeleton, { className: "h-4 w-32" })
11482
+ ] })
11483
+ ] });
11484
+ }
11335
11485
  if (error) {
11336
- return /* @__PURE__ */ jsx149("div", { className: "flex items-center justify-center p-8 text-center", children: /* @__PURE__ */ jsxs89("div", { className: "text-destructive text-sm", children: [
11337
- /* @__PURE__ */ jsxs89("p", { children: [
11338
- "Error loading notifications: ",
11339
- error
11486
+ return /* @__PURE__ */ jsxs90(Card, { children: [
11487
+ /* @__PURE__ */ jsxs90(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11488
+ /* @__PURE__ */ jsx148(CardTitle, { className: "text-sm font-medium", children: "Usage This Month" }),
11489
+ /* @__PURE__ */ jsx148(Activity, { className: "h-4 w-4 text-muted-foreground" })
11340
11490
  ] }),
11341
- /* @__PURE__ */ jsx149("p", { className: "text-muted-foreground mt-2", children: "Please try refreshing the page." })
11342
- ] }) });
11491
+ /* @__PURE__ */ jsx148(CardContent, { children: /* @__PURE__ */ jsx148("p", { className: "text-sm text-destructive", children: error }) })
11492
+ ] });
11343
11493
  }
11344
- const tabs = [
11345
- {
11346
- label: t(`foundations.notification.inbox`),
11347
- content: /* @__PURE__ */ jsx149(NotificationsList, { archived: false })
11348
- },
11349
- {
11350
- label: t(`foundations.notification.archived`),
11351
- content: /* @__PURE__ */ jsx149(NotificationsList, { archived: true })
11494
+ const totalUsage = Object.values(summaries).reduce((acc, summary) => {
11495
+ return acc + (summary?.aggregatedValue || 0);
11496
+ }, 0);
11497
+ const primaryMeter = meters.find((m) => summaries[m.id]?.aggregatedValue);
11498
+ const primarySummary = primaryMeter ? summaries[primaryMeter.id] : null;
11499
+ return /* @__PURE__ */ jsxs90(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onViewDetailsClick, children: [
11500
+ /* @__PURE__ */ jsxs90(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
11501
+ /* @__PURE__ */ jsx148(CardTitle, { className: "text-sm font-medium", children: "Usage This Month" }),
11502
+ /* @__PURE__ */ jsx148(Activity, { className: "h-4 w-4 text-muted-foreground" })
11503
+ ] }),
11504
+ /* @__PURE__ */ jsx148(CardContent, { children: meters.length === 0 ? /* @__PURE__ */ jsxs90("div", { className: "space-y-2", children: [
11505
+ /* @__PURE__ */ jsx148("p", { className: "text-xl font-bold text-muted-foreground", children: "No meters" }),
11506
+ /* @__PURE__ */ jsx148("p", { className: "text-xs text-muted-foreground", children: "No usage meters are configured" })
11507
+ ] }) : /* @__PURE__ */ jsxs90("div", { className: "space-y-2", children: [
11508
+ /* @__PURE__ */ jsxs90("p", { className: "text-xl font-bold", children: [
11509
+ formatNumber(totalUsage),
11510
+ " units"
11511
+ ] }),
11512
+ primaryMeter && primarySummary && /* @__PURE__ */ jsxs90("p", { className: "text-sm text-muted-foreground", children: [
11513
+ primaryMeter.displayName,
11514
+ ": ",
11515
+ formatNumber(primarySummary.aggregatedValue)
11516
+ ] }),
11517
+ meters.length > 1 && /* @__PURE__ */ jsxs90("p", { className: "text-xs text-muted-foreground", children: [
11518
+ "Across ",
11519
+ meters.length,
11520
+ " meters"
11521
+ ] }),
11522
+ /* @__PURE__ */ jsxs90("span", { className: "flex items-center text-xs text-muted-foreground", children: [
11523
+ "View details",
11524
+ /* @__PURE__ */ jsx148(ChevronRight4, { className: "h-3 w-3 ml-1" })
11525
+ ] })
11526
+ ] }) })
11527
+ ] });
11528
+ }
11529
+ __name(BillingUsageSummaryCard, "BillingUsageSummaryCard");
11530
+
11531
+ // src/features/billing/components/containers/BillingDashboardContainer.tsx
11532
+ import { CreditCard as CreditCard4, Loader2 as Loader24, Wallet as Wallet2 } from "lucide-react";
11533
+ import { useCallback as useCallback18, useEffect as useEffect47, useState as useState62 } from "react";
11534
+
11535
+ // src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx
11536
+ import { CreditCard as CreditCard2 } from "lucide-react";
11537
+ import { useEffect as useEffect42, useState as useState52 } from "react";
11538
+
11539
+ // src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx
11540
+ import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
11541
+ import { useEffect as useEffect40, useState as useState50 } from "react";
11542
+ import { jsx as jsx149, jsxs as jsxs91 } from "react/jsx-runtime";
11543
+ function PaymentMethodEditor({ open, onOpenChange, onSuccess }) {
11544
+ const stripe = useStripe();
11545
+ const elements = useElements();
11546
+ const [setupIntent, setSetupIntent] = useState50(null);
11547
+ const [loading, setLoading] = useState50(true);
11548
+ const [isSubmitting, setIsSubmitting] = useState50(false);
11549
+ const [error, setError] = useState50(null);
11550
+ const [setAsDefault, setSetAsDefault] = useState50(true);
11551
+ useEffect40(() => {
11552
+ const fetchSetupIntent = /* @__PURE__ */ __name(async () => {
11553
+ setLoading(true);
11554
+ try {
11555
+ const intent = await StripeCustomerService.createSetupIntent();
11556
+ setSetupIntent(intent);
11557
+ } catch (err) {
11558
+ console.error("[PaymentMethodEditor] Failed to create setup intent:", err);
11559
+ setError("Failed to initialize payment form. Please try again.");
11560
+ } finally {
11561
+ setLoading(false);
11562
+ }
11563
+ }, "fetchSetupIntent");
11564
+ if (open) {
11565
+ fetchSetupIntent();
11566
+ }
11567
+ }, [open]);
11568
+ const handleSubmit = /* @__PURE__ */ __name(async (e) => {
11569
+ e.preventDefault();
11570
+ if (!stripe || !elements || !setupIntent) {
11571
+ return;
11572
+ }
11573
+ setIsSubmitting(true);
11574
+ setError(null);
11575
+ try {
11576
+ const cardElement = elements.getElement(CardElement);
11577
+ if (!cardElement) {
11578
+ throw new Error("Card element not found");
11579
+ }
11580
+ const { error: stripeError, setupIntent: confirmedSetupIntent } = await stripe.confirmCardSetup(
11581
+ setupIntent.clientSecret,
11582
+ {
11583
+ payment_method: {
11584
+ card: cardElement
11585
+ }
11586
+ }
11587
+ );
11588
+ if (stripeError) {
11589
+ console.error("[PaymentMethodEditor] Stripe error:", stripeError);
11590
+ setError(stripeError.message || "Failed to add payment method. Please check your card details.");
11591
+ setIsSubmitting(false);
11592
+ return;
11593
+ }
11594
+ if (setAsDefault && confirmedSetupIntent?.payment_method) {
11595
+ await StripeCustomerService.setDefaultPaymentMethod({
11596
+ paymentMethodId: typeof confirmedSetupIntent.payment_method === "string" ? confirmedSetupIntent.payment_method : confirmedSetupIntent.payment_method.id
11597
+ });
11598
+ }
11599
+ onSuccess();
11600
+ onOpenChange(false);
11601
+ } catch (err) {
11602
+ console.error("[PaymentMethodEditor] Error:", err);
11603
+ setError(err.message || "An unexpected error occurred. Please try again.");
11604
+ } finally {
11605
+ setIsSubmitting(false);
11606
+ }
11607
+ }, "handleSubmit");
11608
+ return /* @__PURE__ */ jsx149(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs91(DialogContent, { className: "max-w-md", children: [
11609
+ /* @__PURE__ */ jsxs91(DialogHeader, { children: [
11610
+ /* @__PURE__ */ jsx149(DialogTitle, { children: "Add Payment Method" }),
11611
+ /* @__PURE__ */ jsx149(DialogDescription, { children: "Add a new payment method to your account. Your card information is securely processed by Stripe." })
11612
+ ] }),
11613
+ loading && /* @__PURE__ */ jsx149("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx149("p", { className: "text-muted-foreground", children: "Loading payment form..." }) }),
11614
+ !loading && setupIntent && /* @__PURE__ */ jsxs91("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
11615
+ /* @__PURE__ */ jsx149("div", { className: "rounded-md border border-gray-300 p-3", children: /* @__PURE__ */ jsx149(
11616
+ CardElement,
11617
+ {
11618
+ options: {
11619
+ style: {
11620
+ base: {
11621
+ fontSize: "16px",
11622
+ color: "#424770",
11623
+ "::placeholder": {
11624
+ color: "#aab7c4"
11625
+ }
11626
+ },
11627
+ invalid: {
11628
+ color: "#9e2146"
11629
+ }
11630
+ }
11631
+ }
11632
+ }
11633
+ ) }),
11634
+ /* @__PURE__ */ jsxs91("div", { className: "flex items-center gap-x-2", children: [
11635
+ /* @__PURE__ */ jsx149(
11636
+ Checkbox,
11637
+ {
11638
+ id: "setAsDefault",
11639
+ checked: setAsDefault,
11640
+ onCheckedChange: (checked) => setSetAsDefault(!!checked)
11641
+ }
11642
+ ),
11643
+ /* @__PURE__ */ jsx149(Label3, { htmlFor: "setAsDefault", className: "text-sm font-normal", children: "Set as default payment method" })
11644
+ ] }),
11645
+ error && /* @__PURE__ */ jsx149(Alert, { variant: "destructive", className: "bg-red-50 border-red-200", children: /* @__PURE__ */ jsx149(AlertDescription, { children: error }) }),
11646
+ /* @__PURE__ */ jsxs91("div", { className: "flex justify-end gap-x-2", children: [
11647
+ /* @__PURE__ */ jsx149(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Cancel" }),
11648
+ /* @__PURE__ */ jsx149(Button, { type: "submit", disabled: !stripe || isSubmitting, children: isSubmitting ? "Processing..." : "Add Card" })
11649
+ ] })
11650
+ ] }),
11651
+ !loading && !setupIntent && error && /* @__PURE__ */ jsx149(Alert, { variant: "destructive", className: "bg-red-50 border-red-200", children: /* @__PURE__ */ jsx149(AlertDescription, { children: error }) })
11652
+ ] }) });
11653
+ }
11654
+ __name(PaymentMethodEditor, "PaymentMethodEditor");
11655
+
11656
+ // src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx
11657
+ import { MoreVertical } from "lucide-react";
11658
+ import { useEffect as useEffect41, useState as useState51 } from "react";
11659
+ import { Fragment as Fragment28, jsx as jsx150, jsxs as jsxs92 } from "react/jsx-runtime";
11660
+ var brandIcons = {
11661
+ visa: "\u{1F4B3}",
11662
+ mastercard: "\u{1F4B3}",
11663
+ amex: "\u{1F4B3}",
11664
+ discover: "\u{1F4B3}"
11665
+ };
11666
+ function PaymentMethodCard({ paymentMethod, onUpdate }) {
11667
+ const [loading, setLoading] = useState51(false);
11668
+ const [customer, setCustomer] = useState51(null);
11669
+ const [showRemoveDialog, setShowRemoveDialog] = useState51(false);
11670
+ useEffect41(() => {
11671
+ const loadCustomer = /* @__PURE__ */ __name(async () => {
11672
+ try {
11673
+ const fetchedCustomer = await StripeCustomerService.getCustomer();
11674
+ setCustomer(fetchedCustomer);
11675
+ } catch (error) {
11676
+ console.error("[PaymentMethodCard] Failed to load customer:", error);
11677
+ }
11678
+ }, "loadCustomer");
11679
+ loadCustomer();
11680
+ }, []);
11681
+ const isDefault = customer?.defaultPaymentMethodId === paymentMethod.id;
11682
+ const brand = paymentMethod.card?.brand || "card";
11683
+ const last4 = paymentMethod.card?.last4 || "****";
11684
+ const expMonth = paymentMethod.card?.expMonth || 0;
11685
+ const expYear = paymentMethod.card?.expYear || 0;
11686
+ const brandIcon = brandIcons[brand.toLowerCase()] || "\u{1F4B3}";
11687
+ const handleSetDefault = /* @__PURE__ */ __name(async () => {
11688
+ setLoading(true);
11689
+ try {
11690
+ await StripeCustomerService.setDefaultPaymentMethod({ paymentMethodId: paymentMethod.id });
11691
+ onUpdate();
11692
+ } catch (error) {
11693
+ console.error("[PaymentMethodCard] Failed to set as default:", error);
11694
+ } finally {
11695
+ setLoading(false);
11696
+ }
11697
+ }, "handleSetDefault");
11698
+ const handleRemove = /* @__PURE__ */ __name(async () => {
11699
+ setLoading(true);
11700
+ try {
11701
+ await StripeCustomerService.removePaymentMethod({ paymentMethodId: paymentMethod.id });
11702
+ setShowRemoveDialog(false);
11703
+ onUpdate();
11704
+ } catch (error) {
11705
+ console.error("[PaymentMethodCard] Failed to remove:", error);
11706
+ setLoading(false);
11707
+ }
11708
+ }, "handleRemove");
11709
+ return /* @__PURE__ */ jsxs92(Fragment28, { children: [
11710
+ /* @__PURE__ */ jsxs92(Card, { className: "relative", children: [
11711
+ isDefault && /* @__PURE__ */ jsx150(Badge, { className: "absolute right-2 top-2 bg-green-100 text-green-800 hover:bg-green-100", children: "Default" }),
11712
+ /* @__PURE__ */ jsxs92(CardHeader, { className: "flex flex-row items-center justify-between pb-2", children: [
11713
+ /* @__PURE__ */ jsxs92("div", { className: "flex items-center gap-x-2", children: [
11714
+ /* @__PURE__ */ jsx150("span", { className: "text-2xl", children: brandIcon }),
11715
+ /* @__PURE__ */ jsx150("span", { className: "text-sm font-medium capitalize", children: brand })
11716
+ ] }),
11717
+ /* @__PURE__ */ jsxs92(DropdownMenu, { children: [
11718
+ /* @__PURE__ */ jsx150(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx150(Button, { variant: "ghost", size: "sm", disabled: loading, className: "h-8 w-8 p-0", children: /* @__PURE__ */ jsx150(MoreVertical, { className: "h-4 w-4" }) }) }),
11719
+ /* @__PURE__ */ jsxs92(DropdownMenuContent, { align: "end", children: [
11720
+ !isDefault && /* @__PURE__ */ jsx150(DropdownMenuItem, { onClick: handleSetDefault, disabled: loading, children: "Set as Default" }),
11721
+ /* @__PURE__ */ jsx150(DropdownMenuItem, { onClick: () => setShowRemoveDialog(true), disabled: loading, className: "text-red-600", children: "Remove" })
11722
+ ] })
11723
+ ] })
11724
+ ] }),
11725
+ /* @__PURE__ */ jsx150(CardContent, { children: /* @__PURE__ */ jsxs92("div", { className: "flex flex-col gap-y-1", children: [
11726
+ /* @__PURE__ */ jsxs92("p", { className: "text-lg font-semibold", children: [
11727
+ "\u2022\u2022\u2022\u2022 ",
11728
+ last4
11729
+ ] }),
11730
+ /* @__PURE__ */ jsxs92("p", { className: "text-sm text-muted-foreground", children: [
11731
+ "Expires ",
11732
+ String(expMonth).padStart(2, "0"),
11733
+ "/",
11734
+ expYear
11735
+ ] })
11736
+ ] }) })
11737
+ ] }),
11738
+ /* @__PURE__ */ jsx150(AlertDialog, { open: showRemoveDialog, onOpenChange: setShowRemoveDialog, children: /* @__PURE__ */ jsxs92(AlertDialogContent, { children: [
11739
+ /* @__PURE__ */ jsxs92(AlertDialogHeader, { children: [
11740
+ /* @__PURE__ */ jsx150(AlertDialogTitle, { children: "Remove Payment Method" }),
11741
+ /* @__PURE__ */ jsxs92(AlertDialogDescription, { children: [
11742
+ "Are you sure you want to remove this payment method? This action cannot be undone.",
11743
+ isDefault && " This is your default payment method."
11744
+ ] })
11745
+ ] }),
11746
+ /* @__PURE__ */ jsxs92(AlertDialogFooter, { children: [
11747
+ /* @__PURE__ */ jsx150(AlertDialogCancel, { disabled: loading, children: "Cancel" }),
11748
+ /* @__PURE__ */ jsx150(AlertDialogAction, { onClick: handleRemove, disabled: loading, className: "bg-red-600 hover:bg-red-700", children: loading ? "Removing..." : "Remove" })
11749
+ ] })
11750
+ ] }) })
11751
+ ] });
11752
+ }
11753
+ __name(PaymentMethodCard, "PaymentMethodCard");
11754
+
11755
+ // src/features/billing/stripe-customer/components/lists/PaymentMethodsList.tsx
11756
+ import { jsx as jsx151 } from "react/jsx-runtime";
11757
+ function PaymentMethodsList({ paymentMethods, onUpdate }) {
11758
+ return /* @__PURE__ */ jsx151("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3", children: paymentMethods.map((paymentMethod) => /* @__PURE__ */ jsx151(PaymentMethodCard, { paymentMethod, onUpdate }, paymentMethod.id)) });
11759
+ }
11760
+ __name(PaymentMethodsList, "PaymentMethodsList");
11761
+
11762
+ // src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx
11763
+ import { jsx as jsx152, jsxs as jsxs93 } from "react/jsx-runtime";
11764
+ function PaymentMethodsContainer() {
11765
+ const [paymentMethods, setPaymentMethods] = useState52([]);
11766
+ const [loading, setLoading] = useState52(true);
11767
+ const [showAddPaymentMethod, setShowAddPaymentMethod] = useState52(false);
11768
+ const loadPaymentMethods = /* @__PURE__ */ __name(async () => {
11769
+ setLoading(true);
11770
+ try {
11771
+ const fetchedPaymentMethods = await StripeCustomerService.listPaymentMethods();
11772
+ setPaymentMethods(fetchedPaymentMethods);
11773
+ } catch (error) {
11774
+ console.error("[PaymentMethodsContainer] Failed to load payment methods:", error);
11775
+ } finally {
11776
+ setLoading(false);
11777
+ }
11778
+ }, "loadPaymentMethods");
11779
+ useEffect42(() => {
11780
+ loadPaymentMethods();
11781
+ }, []);
11782
+ if (loading) {
11783
+ return /* @__PURE__ */ jsx152("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx152("p", { className: "text-muted-foreground", children: "Loading payment methods..." }) });
11784
+ }
11785
+ return /* @__PURE__ */ jsxs93("div", { className: "flex w-full flex-col gap-y-6", children: [
11786
+ /* @__PURE__ */ jsxs93("div", { className: "flex items-center justify-between", children: [
11787
+ /* @__PURE__ */ jsxs93("div", { className: "flex items-center gap-x-3", children: [
11788
+ /* @__PURE__ */ jsx152(CreditCard2, { className: "h-8 w-8" }),
11789
+ /* @__PURE__ */ jsx152("h1", { className: "text-3xl font-bold", children: "Payment Methods" })
11790
+ ] }),
11791
+ /* @__PURE__ */ jsx152(Button, { onClick: () => setShowAddPaymentMethod(true), children: "Add Payment Method" })
11792
+ ] }),
11793
+ paymentMethods.length === 0 && /* @__PURE__ */ jsxs93("div", { className: "flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed border-gray-300 bg-muted/50 p-12", children: [
11794
+ /* @__PURE__ */ jsx152(CreditCard2, { className: "h-16 w-16 text-muted-foreground" }),
11795
+ /* @__PURE__ */ jsxs93("div", { className: "text-center", children: [
11796
+ /* @__PURE__ */ jsx152("h3", { className: "mb-2 text-xl font-semibold", children: "No payment methods" }),
11797
+ /* @__PURE__ */ jsx152("p", { className: "mb-4 text-muted-foreground", children: "Add a payment method to enable subscriptions and secure checkout." }),
11798
+ /* @__PURE__ */ jsx152(Button, { onClick: () => setShowAddPaymentMethod(true), children: "Add Your First Card" })
11799
+ ] })
11800
+ ] }),
11801
+ paymentMethods.length > 0 && /* @__PURE__ */ jsx152(PaymentMethodsList, { paymentMethods, onUpdate: loadPaymentMethods }),
11802
+ showAddPaymentMethod && /* @__PURE__ */ jsx152(
11803
+ PaymentMethodEditor,
11804
+ {
11805
+ open: showAddPaymentMethod,
11806
+ onOpenChange: setShowAddPaymentMethod,
11807
+ onSuccess: loadPaymentMethods
11808
+ }
11809
+ )
11810
+ ] });
11811
+ }
11812
+ __name(PaymentMethodsContainer, "PaymentMethodsContainer");
11813
+
11814
+ // src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx
11815
+ import { useEffect as useEffect43, useState as useState54 } from "react";
11816
+
11817
+ // src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx
11818
+ import { useState as useState53 } from "react";
11819
+
11820
+ // src/features/billing/components/utils/currency.ts
11821
+ function formatInterval(price) {
11822
+ if (price.priceType === "one_time" || !price.recurring) {
11823
+ return "one-time";
11824
+ }
11825
+ const { interval, intervalCount } = price.recurring;
11826
+ if (intervalCount === 1) {
11827
+ return `/${interval}`;
11828
+ }
11829
+ const pluralInterval = interval === "day" ? "days" : interval === "week" ? "weeks" : interval === "month" ? "months" : "years";
11830
+ return `/${intervalCount} ${pluralInterval}`;
11831
+ }
11832
+ __name(formatInterval, "formatInterval");
11833
+ function formatCurrency(amount, currency) {
11834
+ if (amount === void 0) return "$0.00";
11835
+ const dollars = amount / 100;
11836
+ try {
11837
+ return new Intl.NumberFormat("en-US", {
11838
+ style: "currency",
11839
+ currency: currency.toUpperCase(),
11840
+ minimumFractionDigits: 2,
11841
+ maximumFractionDigits: 2
11842
+ }).format(dollars);
11843
+ } catch (error) {
11844
+ console.error("Error formatting currency:", error);
11845
+ return `$${dollars.toFixed(2)}`;
11846
+ }
11847
+ }
11848
+ __name(formatCurrency, "formatCurrency");
11849
+
11850
+ // src/features/billing/components/utils/date.ts
11851
+ function formatDate3(date) {
11852
+ if (!date) return "N/A";
11853
+ const dateObj = typeof date === "string" ? new Date(date) : date;
11854
+ try {
11855
+ return new Intl.DateTimeFormat("en-US", {
11856
+ month: "short",
11857
+ day: "numeric",
11858
+ year: "numeric"
11859
+ }).format(dateObj);
11860
+ } catch (error) {
11861
+ console.error("Error formatting date:", error);
11862
+ return "Invalid Date";
11863
+ }
11864
+ }
11865
+ __name(formatDate3, "formatDate");
11866
+
11867
+ // src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx
11868
+ import { Download, ExternalLink as ExternalLink2, RefreshCw as RefreshCw2 } from "lucide-react";
11869
+
11870
+ // src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx
11871
+ import { jsx as jsx153 } from "react/jsx-runtime";
11872
+ var statusConfig = {
11873
+ ["draft" /* DRAFT */]: {
11874
+ label: "Draft",
11875
+ color: "bg-gray-100 text-gray-800"
11876
+ },
11877
+ ["open" /* OPEN */]: {
11878
+ label: "Open",
11879
+ color: "bg-blue-100 text-blue-800"
11880
+ },
11881
+ ["paid" /* PAID */]: {
11882
+ label: "Paid",
11883
+ color: "bg-green-100 text-green-800"
11884
+ },
11885
+ ["void" /* VOID */]: {
11886
+ label: "Void",
11887
+ color: "bg-gray-100 text-gray-800"
11888
+ },
11889
+ ["uncollectible" /* UNCOLLECTIBLE */]: {
11890
+ label: "Uncollectible",
11891
+ color: "bg-red-100 text-red-800"
11892
+ }
11893
+ };
11894
+ function InvoiceStatusBadge({ status }) {
11895
+ const config = statusConfig[status] || statusConfig["draft" /* DRAFT */];
11896
+ return /* @__PURE__ */ jsx153("span", { className: `${config.color} text-xs px-2 py-1 rounded-full font-medium`, children: config.label });
11897
+ }
11898
+ __name(InvoiceStatusBadge, "InvoiceStatusBadge");
11899
+
11900
+ // src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx
11901
+ import { jsx as jsx154, jsxs as jsxs94 } from "react/jsx-runtime";
11902
+ function InvoiceDetails({ invoice, open, onOpenChange, onInvoiceChange }) {
11903
+ const handleDownloadPDF = /* @__PURE__ */ __name(() => {
11904
+ if (invoice.stripePdfUrl) {
11905
+ window.open(invoice.stripePdfUrl, "_blank");
11906
+ }
11907
+ }, "handleDownloadPDF");
11908
+ const handleRetryPayment = /* @__PURE__ */ __name(async () => {
11909
+ }, "handleRetryPayment");
11910
+ const handleViewInStripe = /* @__PURE__ */ __name(() => {
11911
+ if (invoice.stripeHostedInvoiceUrl) {
11912
+ window.open(invoice.stripeHostedInvoiceUrl, "_blank");
11913
+ }
11914
+ }, "handleViewInStripe");
11915
+ const getInvoiceNumber = /* @__PURE__ */ __name(() => {
11916
+ if (invoice.stripeInvoiceNumber) {
11917
+ return invoice.stripeInvoiceNumber;
11918
+ }
11919
+ return invoice.stripeInvoiceId.slice(-8);
11920
+ }, "getInvoiceNumber");
11921
+ const productName = invoice.subscription?.price?.product?.name || "Subscription";
11922
+ return /* @__PURE__ */ jsx154(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs94(DialogContent, { className: "max-w-2xl", children: [
11923
+ /* @__PURE__ */ jsxs94(DialogHeader, { children: [
11924
+ /* @__PURE__ */ jsxs94(DialogTitle, { children: [
11925
+ "Invoice ",
11926
+ getInvoiceNumber()
11927
+ ] }),
11928
+ /* @__PURE__ */ jsx154(DialogDescription, { children: formatDate3(invoice.periodStart) })
11929
+ ] }),
11930
+ /* @__PURE__ */ jsxs94("div", { className: "space-y-6", children: [
11931
+ /* @__PURE__ */ jsxs94("div", { className: "flex items-center gap-x-3", children: [
11932
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Status:" }),
11933
+ /* @__PURE__ */ jsx154(InvoiceStatusBadge, { status: invoice.status })
11934
+ ] }),
11935
+ /* @__PURE__ */ jsxs94("div", { className: "grid grid-cols-2 gap-4", children: [
11936
+ /* @__PURE__ */ jsxs94("div", { children: [
11937
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Billing Period:" }),
11938
+ /* @__PURE__ */ jsxs94("p", { className: "font-medium", children: [
11939
+ formatDate3(invoice.periodStart),
11940
+ " - ",
11941
+ formatDate3(invoice.periodEnd)
11942
+ ] })
11943
+ ] }),
11944
+ invoice.dueDate && /* @__PURE__ */ jsxs94("div", { children: [
11945
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Due Date:" }),
11946
+ /* @__PURE__ */ jsx154("p", { className: "font-medium", children: formatDate3(invoice.dueDate) })
11947
+ ] }),
11948
+ invoice.paidAt && /* @__PURE__ */ jsxs94("div", { children: [
11949
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Paid Date:" }),
11950
+ /* @__PURE__ */ jsx154("p", { className: "font-medium", children: formatDate3(invoice.paidAt) })
11951
+ ] }),
11952
+ /* @__PURE__ */ jsxs94("div", { children: [
11953
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Attempt Count:" }),
11954
+ /* @__PURE__ */ jsx154("p", { className: "font-medium", children: invoice.attemptCount })
11955
+ ] })
11956
+ ] }),
11957
+ /* @__PURE__ */ jsxs94("div", { children: [
11958
+ /* @__PURE__ */ jsx154("h4", { className: "text-sm font-medium text-muted-foreground mb-2", children: "Line Items" }),
11959
+ /* @__PURE__ */ jsx154("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs94("table", { className: "w-full", children: [
11960
+ /* @__PURE__ */ jsx154("thead", { className: "bg-muted", children: /* @__PURE__ */ jsxs94("tr", { children: [
11961
+ /* @__PURE__ */ jsx154("th", { className: "text-left p-3 text-sm font-medium", children: "Description" }),
11962
+ /* @__PURE__ */ jsx154("th", { className: "text-right p-3 text-sm font-medium", children: "Amount" })
11963
+ ] }) }),
11964
+ /* @__PURE__ */ jsx154("tbody", { children: /* @__PURE__ */ jsxs94("tr", { className: "border-t", children: [
11965
+ /* @__PURE__ */ jsx154("td", { className: "p-3", children: productName }),
11966
+ /* @__PURE__ */ jsx154("td", { className: "p-3 text-right", children: formatCurrency(invoice.subtotal, invoice.currency) })
11967
+ ] }) })
11968
+ ] }) })
11969
+ ] }),
11970
+ /* @__PURE__ */ jsxs94("div", { className: "space-y-2 border-t pt-4", children: [
11971
+ /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
11972
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Subtotal:" }),
11973
+ /* @__PURE__ */ jsx154("span", { className: "font-medium", children: formatCurrency(invoice.subtotal, invoice.currency) })
11974
+ ] }),
11975
+ invoice.tax !== void 0 && invoice.tax > 0 && /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
11976
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Tax:" }),
11977
+ /* @__PURE__ */ jsx154("span", { className: "font-medium", children: formatCurrency(invoice.tax, invoice.currency) })
11978
+ ] }),
11979
+ /* @__PURE__ */ jsxs94("div", { className: "flex justify-between text-lg font-semibold border-t pt-2", children: [
11980
+ /* @__PURE__ */ jsx154("span", { children: "Total:" }),
11981
+ /* @__PURE__ */ jsx154("span", { children: formatCurrency(invoice.total, invoice.currency) })
11982
+ ] }),
11983
+ invoice.amountPaid > 0 && /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
11984
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Amount Paid:" }),
11985
+ /* @__PURE__ */ jsx154("span", { className: "font-medium text-green-600", children: formatCurrency(invoice.amountPaid, invoice.currency) })
11986
+ ] }),
11987
+ invoice.amountRemaining > 0 && /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
11988
+ /* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Amount Due:" }),
11989
+ /* @__PURE__ */ jsx154("span", { className: "font-medium text-red-600", children: formatCurrency(invoice.amountRemaining, invoice.currency) })
11990
+ ] })
11991
+ ] }),
11992
+ /* @__PURE__ */ jsxs94("div", { className: "flex flex-wrap gap-2 pt-4 border-t", children: [
11993
+ invoice.stripePdfUrl && /* @__PURE__ */ jsxs94(Button, { variant: "outline", onClick: handleDownloadPDF, children: [
11994
+ /* @__PURE__ */ jsx154(Download, { className: "mr-2 h-4 w-4" }),
11995
+ "Download PDF"
11996
+ ] }),
11997
+ invoice.status === "open" /* OPEN */ && invoice.attempted && /* @__PURE__ */ jsxs94(Button, { variant: "default", onClick: handleRetryPayment, children: [
11998
+ /* @__PURE__ */ jsx154(RefreshCw2, { className: "mr-2 h-4 w-4" }),
11999
+ "Retry Payment"
12000
+ ] }),
12001
+ invoice.stripeHostedInvoiceUrl && /* @__PURE__ */ jsxs94(Button, { variant: "outline", onClick: handleViewInStripe, children: [
12002
+ /* @__PURE__ */ jsx154(ExternalLink2, { className: "mr-2 h-4 w-4" }),
12003
+ "View in Stripe"
12004
+ ] })
12005
+ ] })
12006
+ ] })
12007
+ ] }) });
12008
+ }
12009
+ __name(InvoiceDetails, "InvoiceDetails");
12010
+
12011
+ // src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx
12012
+ import { Fragment as Fragment29, jsx as jsx155, jsxs as jsxs95 } from "react/jsx-runtime";
12013
+ function InvoicesList({ invoices, onInvoicesChange }) {
12014
+ const [selectedInvoice, setSelectedInvoice] = useState53(null);
12015
+ const handleRowClick = /* @__PURE__ */ __name((invoice) => {
12016
+ setSelectedInvoice(invoice);
12017
+ }, "handleRowClick");
12018
+ const getInvoiceNumber = /* @__PURE__ */ __name((invoice) => {
12019
+ if (invoice.stripeInvoiceNumber) {
12020
+ return invoice.stripeInvoiceNumber;
12021
+ }
12022
+ return invoice.stripeInvoiceId.slice(-8);
12023
+ }, "getInvoiceNumber");
12024
+ return /* @__PURE__ */ jsxs95(Fragment29, { children: [
12025
+ /* @__PURE__ */ jsx155("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs95(Table, { children: [
12026
+ /* @__PURE__ */ jsx155(TableHeader, { className: "bg-muted", children: /* @__PURE__ */ jsxs95(TableRow, { children: [
12027
+ /* @__PURE__ */ jsx155(TableHead, { children: "Invoice #" }),
12028
+ /* @__PURE__ */ jsx155(TableHead, { children: "Date" }),
12029
+ /* @__PURE__ */ jsx155(TableHead, { children: "Status" }),
12030
+ /* @__PURE__ */ jsx155(TableHead, { className: "text-right", children: "Amount" }),
12031
+ /* @__PURE__ */ jsx155(TableHead, { children: "Period" })
12032
+ ] }) }),
12033
+ /* @__PURE__ */ jsx155(TableBody, { children: invoices.map((invoice) => {
12034
+ const invoiceNumber = getInvoiceNumber(invoice);
12035
+ const date = formatDate3(invoice.periodStart);
12036
+ const amount = formatCurrency(invoice.total, invoice.currency);
12037
+ const period = `${formatDate3(invoice.periodStart)} - ${formatDate3(invoice.periodEnd)}`;
12038
+ return /* @__PURE__ */ jsxs95(
12039
+ TableRow,
12040
+ {
12041
+ onClick: () => handleRowClick(invoice),
12042
+ className: "cursor-pointer hover:bg-muted/50",
12043
+ children: [
12044
+ /* @__PURE__ */ jsx155(TableCell, { className: "font-medium", children: invoiceNumber }),
12045
+ /* @__PURE__ */ jsx155(TableCell, { className: "text-muted-foreground text-sm", children: date }),
12046
+ /* @__PURE__ */ jsx155(TableCell, { children: /* @__PURE__ */ jsx155(InvoiceStatusBadge, { status: invoice.status }) }),
12047
+ /* @__PURE__ */ jsx155(TableCell, { className: "text-right font-medium", children: amount }),
12048
+ /* @__PURE__ */ jsx155(TableCell, { className: "text-muted-foreground text-sm", children: period })
12049
+ ]
12050
+ },
12051
+ invoice.id
12052
+ );
12053
+ }) })
12054
+ ] }) }),
12055
+ selectedInvoice && /* @__PURE__ */ jsx155(
12056
+ InvoiceDetails,
12057
+ {
12058
+ invoice: selectedInvoice,
12059
+ open: !!selectedInvoice,
12060
+ onOpenChange: (open) => !open && setSelectedInvoice(null),
12061
+ onInvoiceChange: () => {
12062
+ onInvoicesChange();
12063
+ setSelectedInvoice(null);
12064
+ }
12065
+ }
12066
+ )
12067
+ ] });
12068
+ }
12069
+ __name(InvoicesList, "InvoicesList");
12070
+
12071
+ // src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx
12072
+ import { jsx as jsx156, jsxs as jsxs96 } from "react/jsx-runtime";
12073
+ function InvoicesContainer() {
12074
+ const [invoices, setInvoices] = useState54([]);
12075
+ const [loading, setLoading] = useState54(true);
12076
+ const [statusFilter, setStatusFilter] = useState54("all");
12077
+ const loadInvoices = /* @__PURE__ */ __name(async () => {
12078
+ setLoading(true);
12079
+ try {
12080
+ const params = statusFilter !== "all" ? { status: statusFilter } : void 0;
12081
+ const data = await StripeInvoiceService.listInvoices(params);
12082
+ setInvoices(data);
12083
+ } catch (error) {
12084
+ console.error("[InvoicesContainer] Failed to load invoices:", error);
12085
+ setInvoices([]);
12086
+ } finally {
12087
+ setLoading(false);
12088
+ }
12089
+ }, "loadInvoices");
12090
+ useEffect43(() => {
12091
+ loadInvoices();
12092
+ }, [statusFilter]);
12093
+ const handleFilterChange = /* @__PURE__ */ __name((value) => {
12094
+ setStatusFilter(value);
12095
+ }, "handleFilterChange");
12096
+ return /* @__PURE__ */ jsxs96("div", { className: "space-y-4", children: [
12097
+ /* @__PURE__ */ jsx156(Tabs, { value: statusFilter, onValueChange: handleFilterChange, children: /* @__PURE__ */ jsxs96(TabsList, { children: [
12098
+ /* @__PURE__ */ jsx156(TabsTrigger, { value: "all", children: "All" }),
12099
+ /* @__PURE__ */ jsx156(TabsTrigger, { value: "paid" /* PAID */, children: "Paid" }),
12100
+ /* @__PURE__ */ jsx156(TabsTrigger, { value: "open" /* OPEN */, children: "Open" }),
12101
+ /* @__PURE__ */ jsx156(TabsTrigger, { value: "void" /* VOID */, children: "Void" }),
12102
+ /* @__PURE__ */ jsx156(TabsTrigger, { value: "uncollectible" /* UNCOLLECTIBLE */, children: "Uncollectible" })
12103
+ ] }) }),
12104
+ loading && /* @__PURE__ */ jsx156("div", { className: "text-center py-8 text-muted-foreground", children: "Loading invoices..." }),
12105
+ !loading && invoices.length === 0 && /* @__PURE__ */ jsxs96("div", { className: "border border-dashed border-gray-300 rounded-lg p-8 text-center", children: [
12106
+ /* @__PURE__ */ jsx156("p", { className: "text-lg font-medium text-muted-foreground mb-2", children: "No invoices yet" }),
12107
+ /* @__PURE__ */ jsx156("p", { className: "text-sm text-muted-foreground", children: "Invoices will appear here after your first billing cycle" })
12108
+ ] }),
12109
+ !loading && invoices.length > 0 && /* @__PURE__ */ jsx156(InvoicesList, { invoices, onInvoicesChange: loadInvoices })
12110
+ ] });
12111
+ }
12112
+ __name(InvoicesContainer, "InvoicesContainer");
12113
+
12114
+ // src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx
12115
+ import { CheckCircle as CheckCircle2, CreditCard as CreditCard3, Loader2 as Loader23 } from "lucide-react";
12116
+ import { useEffect as useEffect45, useState as useState60 } from "react";
12117
+ import { v4 as v46 } from "uuid";
12118
+
12119
+ // src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts
12120
+ import { useStripe as useStripe2 } from "@stripe/react-stripe-js";
12121
+ import { useCallback as useCallback17, useState as useState55 } from "react";
12122
+ function useConfirmSubscriptionPayment() {
12123
+ const stripe = useStripe2();
12124
+ const [isConfirming, setIsConfirming] = useState55(false);
12125
+ const confirmPayment = useCallback17(
12126
+ async (clientSecret) => {
12127
+ if (!stripe) {
12128
+ console.error("[useConfirmSubscriptionPayment] Stripe not initialized");
12129
+ return {
12130
+ success: false,
12131
+ error: "Payment system not initialized. Please refresh the page and try again."
12132
+ };
12133
+ }
12134
+ if (!clientSecret) {
12135
+ console.error("[useConfirmSubscriptionPayment] No client secret provided");
12136
+ return {
12137
+ success: false,
12138
+ error: "Payment confirmation failed. Missing payment details."
12139
+ };
12140
+ }
12141
+ setIsConfirming(true);
12142
+ try {
12143
+ const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(clientSecret);
12144
+ if (stripeError) {
12145
+ console.error("[useConfirmSubscriptionPayment] Stripe error:", stripeError);
12146
+ return {
12147
+ success: false,
12148
+ error: stripeError.message || "Payment confirmation failed. Please try again."
12149
+ };
12150
+ }
12151
+ if (paymentIntent?.status === "succeeded") {
12152
+ return { success: true };
12153
+ }
12154
+ if (paymentIntent?.status === "requires_action") {
12155
+ return {
12156
+ success: false,
12157
+ error: "Additional authentication required. Please complete the verification."
12158
+ };
12159
+ }
12160
+ return {
12161
+ success: false,
12162
+ error: "Payment could not be completed. Please try again."
12163
+ };
12164
+ } catch (err) {
12165
+ console.error("[useConfirmSubscriptionPayment] Unexpected error:", err);
12166
+ return {
12167
+ success: false,
12168
+ error: err.message || "An unexpected error occurred during payment confirmation."
12169
+ };
12170
+ } finally {
12171
+ setIsConfirming(false);
12172
+ }
12173
+ },
12174
+ [stripe]
12175
+ );
12176
+ return {
12177
+ confirmPayment,
12178
+ isConfirming
12179
+ };
12180
+ }
12181
+ __name(useConfirmSubscriptionPayment, "useConfirmSubscriptionPayment");
12182
+
12183
+ // src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx
12184
+ import { zodResolver as zodResolver10 } from "@hookform/resolvers/zod";
12185
+ import { useState as useState56 } from "react";
12186
+ import { useForm as useForm10 } from "react-hook-form";
12187
+ import { z as z10 } from "zod";
12188
+ import { jsx as jsx157, jsxs as jsxs97 } from "react/jsx-runtime";
12189
+ var formSchema = z10.object({
12190
+ cancelImmediately: z10.boolean(),
12191
+ reason: z10.string().optional()
12192
+ });
12193
+ function CancelSubscriptionDialog({
12194
+ subscription,
12195
+ open,
12196
+ onOpenChange,
12197
+ onSuccess
12198
+ }) {
12199
+ const [isSubmitting, setIsSubmitting] = useState56(false);
12200
+ const form = useForm10({
12201
+ resolver: zodResolver10(formSchema),
12202
+ defaultValues: {
12203
+ cancelImmediately: false,
12204
+ reason: ""
12205
+ }
12206
+ });
12207
+ const cancelImmediately = form.watch("cancelImmediately");
12208
+ const onSubmit = /* @__PURE__ */ __name(async (values) => {
12209
+ setIsSubmitting(true);
12210
+ try {
12211
+ await StripeSubscriptionService.cancelSubscription({
12212
+ id: subscription.id,
12213
+ cancelImmediately: values.cancelImmediately
12214
+ });
12215
+ onSuccess();
12216
+ onOpenChange(false);
12217
+ } catch (error) {
12218
+ console.error("[CancelSubscriptionDialog] Failed to cancel subscription:", error);
12219
+ } finally {
12220
+ setIsSubmitting(false);
12221
+ }
12222
+ }, "onSubmit");
12223
+ const periodEndDate = formatDate3(subscription.currentPeriodEnd);
12224
+ return /* @__PURE__ */ jsx157(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs97(DialogContent, { className: "max-w-md", children: [
12225
+ /* @__PURE__ */ jsxs97(DialogHeader, { children: [
12226
+ /* @__PURE__ */ jsx157(DialogTitle, { children: "Cancel Subscription" }),
12227
+ /* @__PURE__ */ jsx157(DialogDescription, { children: "Are you sure you want to cancel this subscription? This action cannot be undone." })
12228
+ ] }),
12229
+ /* @__PURE__ */ jsx157(Form, { ...form, children: /* @__PURE__ */ jsxs97("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-col gap-y-4", children: [
12230
+ /* @__PURE__ */ jsx157(FormCheckbox, { form, id: "cancelImmediately", name: "Cancel Immediately" }),
12231
+ cancelImmediately ? /* @__PURE__ */ jsx157("div", { className: "bg-red-50 border border-red-200 rounded-lg p-3 text-sm text-red-800", children: "Your subscription will be canceled immediately and you will lose access right away." }) : /* @__PURE__ */ jsxs97("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-3 text-sm text-blue-800", children: [
12232
+ "Your subscription will remain active until ",
12233
+ periodEndDate,
12234
+ ". You can continue using the service until then."
12235
+ ] }),
12236
+ /* @__PURE__ */ jsx157(
12237
+ FormTextarea,
12238
+ {
12239
+ form,
12240
+ id: "reason",
12241
+ name: "Reason (Optional)",
12242
+ placeholder: "Let us know why you're canceling...",
12243
+ className: "min-h-24"
12244
+ }
12245
+ ),
12246
+ /* @__PURE__ */ jsxs97("div", { className: "flex gap-x-2 justify-end pt-2", children: [
12247
+ /* @__PURE__ */ jsx157(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Keep Subscription" }),
12248
+ /* @__PURE__ */ jsx157(Button, { type: "submit", variant: "destructive", disabled: isSubmitting, children: isSubmitting ? "Canceling..." : "Confirm Cancellation" })
12249
+ ] })
12250
+ ] }) })
12251
+ ] }) });
12252
+ }
12253
+ __name(CancelSubscriptionDialog, "CancelSubscriptionDialog");
12254
+
12255
+ // src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx
12256
+ import { CheckCircle, Loader2 as Loader22 } from "lucide-react";
12257
+ import { useEffect as useEffect44, useState as useState57 } from "react";
12258
+ import { v4 as v45 } from "uuid";
12259
+
12260
+ // src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx
12261
+ import { Check } from "lucide-react";
12262
+ import { jsx as jsx158, jsxs as jsxs98 } from "react/jsx-runtime";
12263
+ function PricingCard({ price, isCurrentPlan = false, isSelected = false, isDisabled = false, isLoading = false, onSelect }) {
12264
+ const description = price.description || price.nickname || "Standard";
12265
+ const features = price.features || [];
12266
+ const formattedPrice = formatCurrency(price.unitAmount, price.currency);
12267
+ const interval = formatInterval(price);
12268
+ const handleKeyDown = /* @__PURE__ */ __name((e) => {
12269
+ if ((e.key === "Enter" || e.key === " ") && !isDisabled && !isCurrentPlan) {
12270
+ e.preventDefault();
12271
+ onSelect(price);
12272
+ }
12273
+ }, "handleKeyDown");
12274
+ const handleClick = /* @__PURE__ */ __name(() => {
12275
+ if (!isDisabled && !isCurrentPlan && !isLoading) {
12276
+ onSelect(price);
12277
+ }
12278
+ }, "handleClick");
12279
+ return /* @__PURE__ */ jsxs98(
12280
+ Card,
12281
+ {
12282
+ role: "radio",
12283
+ "aria-checked": isSelected,
12284
+ "aria-label": `${description} plan at ${formattedPrice} ${interval}`,
12285
+ tabIndex: isDisabled ? -1 : 0,
12286
+ onKeyDown: handleKeyDown,
12287
+ onClick: handleClick,
12288
+ className: cn(
12289
+ "relative cursor-pointer transition-all duration-200 flex flex-col h-full",
12290
+ "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
12291
+ isCurrentPlan && "bg-muted/30",
12292
+ isSelected && !isCurrentPlan && "ring-2 ring-primary",
12293
+ !isDisabled && !isCurrentPlan && "hover:shadow-md hover:border-primary/50",
12294
+ isDisabled && "opacity-50 pointer-events-none",
12295
+ isLoading && "pointer-events-none"
12296
+ ),
12297
+ children: [
12298
+ isCurrentPlan && /* @__PURE__ */ jsx158(Badge, { variant: "secondary", className: "absolute top-2 right-2", children: "Current" }),
12299
+ /* @__PURE__ */ jsx158(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsx158("h3", { className: "font-semibold text-lg", children: description }) }),
12300
+ /* @__PURE__ */ jsxs98(CardContent, { className: "pb-4 grow", children: [
12301
+ /* @__PURE__ */ jsxs98("div", { className: "mb-4", children: [
12302
+ /* @__PURE__ */ jsx158("span", { className: "text-3xl font-bold", children: formattedPrice }),
12303
+ /* @__PURE__ */ jsx158("span", { className: "text-muted-foreground ml-1", children: interval })
12304
+ ] }),
12305
+ features.length > 0 && /* @__PURE__ */ jsx158("ul", { className: "space-y-2", children: features.map((feature, index) => /* @__PURE__ */ jsxs98("li", { className: "flex items-start gap-2", children: [
12306
+ /* @__PURE__ */ jsx158(Check, { className: "h-4 w-4 text-green-500 mt-0.5 shrink-0" }),
12307
+ /* @__PURE__ */ jsx158("span", { className: "text-sm text-muted-foreground", children: feature })
12308
+ ] }, index)) })
12309
+ ] }),
12310
+ /* @__PURE__ */ jsx158(CardFooter, { children: /* @__PURE__ */ jsx158(
12311
+ Button,
12312
+ {
12313
+ variant: isCurrentPlan ? "secondary" : isSelected ? "default" : "outline",
12314
+ className: "w-full",
12315
+ disabled: isDisabled || isCurrentPlan || isLoading,
12316
+ children: isLoading ? "Processing..." : isCurrentPlan ? "Current Plan" : isSelected ? "Selected" : "Select Plan"
12317
+ }
12318
+ ) })
12319
+ ]
12320
+ }
12321
+ );
12322
+ }
12323
+ __name(PricingCard, "PricingCard");
12324
+
12325
+ // src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx
12326
+ import { jsx as jsx159, jsxs as jsxs99 } from "react/jsx-runtime";
12327
+ function PricingCardsGrid({
12328
+ products,
12329
+ pricesByProduct,
12330
+ currentPriceId,
12331
+ selectedPriceId,
12332
+ loadingPriceId,
12333
+ loading = false,
12334
+ onSelectPrice
12335
+ }) {
12336
+ if (loading) {
12337
+ return /* @__PURE__ */ jsx159(PricingCardsGridSkeleton, {});
12338
+ }
12339
+ if (products.length === 0) {
12340
+ return /* @__PURE__ */ jsx159("div", { className: "text-center py-8 text-muted-foreground", children: "No plans available" });
12341
+ }
12342
+ return /* @__PURE__ */ jsx159("div", { className: "space-y-8", role: "radiogroup", "aria-label": "Available pricing plans", children: products.map((product) => {
12343
+ const prices = pricesByProduct.get(product.id) || [];
12344
+ if (prices.length === 0) return null;
12345
+ const sortedPrices = [...prices].sort((a, b) => (a.unitAmount ?? 0) - (b.unitAmount ?? 0));
12346
+ return /* @__PURE__ */ jsxs99("div", { className: "space-y-4", children: [
12347
+ /* @__PURE__ */ jsx159("h3", { className: "text-lg font-semibold", children: product.name }),
12348
+ /* @__PURE__ */ jsx159("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: sortedPrices.map((price) => /* @__PURE__ */ jsx159(
12349
+ PricingCard,
12350
+ {
12351
+ price,
12352
+ isCurrentPlan: price.stripePriceId === currentPriceId,
12353
+ isSelected: price.stripePriceId === selectedPriceId,
12354
+ isLoading: price.stripePriceId === loadingPriceId,
12355
+ onSelect: onSelectPrice
12356
+ },
12357
+ price.stripePriceId
12358
+ )) })
12359
+ ] }, product.id);
12360
+ }) });
12361
+ }
12362
+ __name(PricingCardsGrid, "PricingCardsGrid");
12363
+ function PricingCardsGridSkeleton() {
12364
+ return /* @__PURE__ */ jsx159("div", { className: "space-y-8", children: [1, 2].map((productIndex) => /* @__PURE__ */ jsxs99("div", { className: "space-y-4", children: [
12365
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-6 w-32" }),
12366
+ /* @__PURE__ */ jsx159("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [1, 2, 3].map((cardIndex) => /* @__PURE__ */ jsxs99(Card, { className: "animate-pulse", children: [
12367
+ /* @__PURE__ */ jsx159(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsx159(Skeleton, { className: "h-5 w-24" }) }),
12368
+ /* @__PURE__ */ jsxs99(CardContent, { className: "pb-4", children: [
12369
+ /* @__PURE__ */ jsxs99("div", { className: "mb-4", children: [
12370
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-9 w-20 inline-block" }),
12371
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-12 inline-block ml-2" })
12372
+ ] }),
12373
+ /* @__PURE__ */ jsxs99("div", { className: "space-y-2", children: [
12374
+ /* @__PURE__ */ jsxs99("div", { className: "flex items-center gap-2", children: [
12375
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-4 rounded-full" }),
12376
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-32" })
12377
+ ] }),
12378
+ /* @__PURE__ */ jsxs99("div", { className: "flex items-center gap-2", children: [
12379
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-4 rounded-full" }),
12380
+ /* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-28" })
12381
+ ] })
12382
+ ] })
12383
+ ] }),
12384
+ /* @__PURE__ */ jsx159(CardFooter, { children: /* @__PURE__ */ jsx159(Skeleton, { className: "h-9 w-full" }) })
12385
+ ] }, cardIndex)) })
12386
+ ] }, productIndex)) });
12387
+ }
12388
+ __name(PricingCardsGridSkeleton, "PricingCardsGridSkeleton");
12389
+
12390
+ // src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx
12391
+ import { jsx as jsx160, jsxs as jsxs100 } from "react/jsx-runtime";
12392
+ function ProrationPreview({ preview }) {
12393
+ return /* @__PURE__ */ jsxs100("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4", children: [
12394
+ /* @__PURE__ */ jsx160("h4", { className: "font-semibold text-blue-900 mb-3", children: "Proration Breakdown" }),
12395
+ /* @__PURE__ */ jsxs100("div", { className: "space-y-2", children: [
12396
+ preview.lineItems.map((item, index) => /* @__PURE__ */ jsxs100("div", { className: "flex justify-between text-sm", children: [
12397
+ /* @__PURE__ */ jsx160("span", { className: "text-blue-800", children: item.description }),
12398
+ /* @__PURE__ */ jsx160("span", { className: `font-medium ${item.amount < 0 ? "text-green-600" : "text-blue-900"}`, children: formatCurrency(item.amount, preview.currency) })
12399
+ ] }, index)),
12400
+ /* @__PURE__ */ jsx160("div", { className: "border-t border-blue-200 pt-2 mt-2", children: /* @__PURE__ */ jsxs100("div", { className: "flex justify-between font-semibold", children: [
12401
+ /* @__PURE__ */ jsx160("span", { className: "text-blue-900", children: "Net Due Today" }),
12402
+ /* @__PURE__ */ jsx160("span", { className: "text-blue-900", children: formatCurrency(preview.immediateCharge, preview.currency) })
12403
+ ] }) }),
12404
+ preview.lineItems.length > 0 && preview.lineItems[0].period && /* @__PURE__ */ jsxs100("div", { className: "text-xs text-blue-700 mt-2", children: [
12405
+ "Next invoice on ",
12406
+ formatDate3(preview.lineItems[0].period.end),
12407
+ " for",
12408
+ " ",
12409
+ formatCurrency(preview.amountDue, preview.currency)
12410
+ ] })
12411
+ ] })
12412
+ ] });
12413
+ }
12414
+ __name(ProrationPreview, "ProrationPreview");
12415
+
12416
+ // src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx
12417
+ import { jsx as jsx161, jsxs as jsxs101 } from "react/jsx-runtime";
12418
+ function SubscriptionEditor({
12419
+ subscription,
12420
+ open,
12421
+ onOpenChange,
12422
+ onSuccess,
12423
+ onAddPaymentMethod
12424
+ }) {
12425
+ const { confirmPayment, isConfirming } = useConfirmSubscriptionPayment();
12426
+ const [products, setProducts] = useState57([]);
12427
+ const [pricesByProduct, setPricesByProduct] = useState57(/* @__PURE__ */ new Map());
12428
+ const [loading, setLoading] = useState57(true);
12429
+ const [selectedPriceId, setSelectedPriceId] = useState57(null);
12430
+ const [loadingPriceId, setLoadingPriceId] = useState57(null);
12431
+ const [prorationPreview, setProrationPreview] = useState57(null);
12432
+ const [loadingProration, setLoadingProration] = useState57(false);
12433
+ const [hasPaymentMethod, setHasPaymentMethod] = useState57(true);
12434
+ const [loadingPaymentMethods, setLoadingPaymentMethods] = useState57(true);
12435
+ const [paymentRequiredError, setPaymentRequiredError] = useState57(false);
12436
+ const [paymentConfirmationState, setPaymentConfirmationState] = useState57("idle");
12437
+ const [paymentError, setPaymentError] = useState57(null);
12438
+ const currentPriceId = subscription?.price?.id;
12439
+ const isEditMode = !!subscription;
12440
+ useEffect44(() => {
12441
+ const checkPaymentMethods = /* @__PURE__ */ __name(async () => {
12442
+ if (subscription) {
12443
+ setLoadingPaymentMethods(false);
12444
+ return;
12445
+ }
12446
+ setLoadingPaymentMethods(true);
12447
+ try {
12448
+ const paymentMethods = await StripeCustomerService.listPaymentMethods();
12449
+ const hasMethod = paymentMethods.length > 0;
12450
+ setHasPaymentMethod(hasMethod);
12451
+ } catch (error) {
12452
+ console.error("[SubscriptionEditor] Failed to check payment methods:", error);
12453
+ setHasPaymentMethod(false);
12454
+ } finally {
12455
+ setLoadingPaymentMethods(false);
12456
+ }
12457
+ }, "checkPaymentMethods");
12458
+ if (open) {
12459
+ checkPaymentMethods();
12460
+ }
12461
+ }, [open, subscription]);
12462
+ useEffect44(() => {
12463
+ const loadData = /* @__PURE__ */ __name(async () => {
12464
+ setLoading(true);
12465
+ try {
12466
+ const fetchedProducts = await StripeProductService.listProducts({ active: true });
12467
+ const grouped = /* @__PURE__ */ new Map();
12468
+ for (const product of fetchedProducts) {
12469
+ if (product.stripePrices && product.stripePrices.length > 0) {
12470
+ grouped.set(product.id, product.stripePrices);
12471
+ }
12472
+ }
12473
+ setProducts(fetchedProducts);
12474
+ setPricesByProduct(grouped);
12475
+ } catch (error) {
12476
+ console.error("[SubscriptionEditor] Failed to load products/prices:", error);
12477
+ } finally {
12478
+ setLoading(false);
12479
+ }
12480
+ }, "loadData");
12481
+ if (open) {
12482
+ loadData();
12483
+ }
12484
+ }, [open]);
12485
+ useEffect44(() => {
12486
+ const loadProration = /* @__PURE__ */ __name(async () => {
12487
+ if (!subscription || !selectedPriceId || selectedPriceId === currentPriceId) {
12488
+ setProrationPreview(null);
12489
+ return;
12490
+ }
12491
+ setLoadingProration(true);
12492
+ try {
12493
+ const preview = await StripeSubscriptionService.getProrationPreview({
12494
+ subscriptionId: subscription.id,
12495
+ newPriceId: selectedPriceId
12496
+ });
12497
+ setProrationPreview(preview);
12498
+ } catch (error) {
12499
+ console.error("[SubscriptionEditor] Failed to load proration preview:", error);
12500
+ setProrationPreview(null);
12501
+ } finally {
12502
+ setLoadingProration(false);
12503
+ }
12504
+ }, "loadProration");
12505
+ loadProration();
12506
+ }, [selectedPriceId, subscription, currentPriceId]);
12507
+ const handleSelectPrice = /* @__PURE__ */ __name(async (price) => {
12508
+ const priceId = price.id;
12509
+ if (isEditMode) {
12510
+ setSelectedPriceId(priceId);
12511
+ } else {
12512
+ setLoadingPriceId(priceId);
12513
+ setSelectedPriceId(priceId);
12514
+ setPaymentError(null);
12515
+ setPaymentConfirmationState("idle");
12516
+ try {
12517
+ const result = await StripeSubscriptionService.createSubscription({
12518
+ id: v45(),
12519
+ priceId
12520
+ });
12521
+ if (result.meta.requiresAction && result.meta.clientSecret) {
12522
+ setPaymentConfirmationState("confirming");
12523
+ const confirmation = await confirmPayment(result.meta.clientSecret);
12524
+ if (!confirmation.success) {
12525
+ console.error("[SubscriptionEditor] Payment confirmation failed:", confirmation.error);
12526
+ setPaymentConfirmationState("error");
12527
+ setPaymentError(confirmation.error || "Payment confirmation failed");
12528
+ setLoadingPriceId(null);
12529
+ return;
12530
+ }
12531
+ await StripeSubscriptionService.syncSubscription({
12532
+ subscriptionId: result.subscription.id
12533
+ });
12534
+ }
12535
+ setPaymentConfirmationState("success");
12536
+ setTimeout(() => {
12537
+ onSuccess();
12538
+ onOpenChange(false);
12539
+ }, 1e3);
12540
+ } catch (error) {
12541
+ console.error("[SubscriptionEditor] Failed to create subscription:", error);
12542
+ if (error?.status === 402 || error?.response?.status === 402) {
12543
+ setPaymentRequiredError(true);
12544
+ setHasPaymentMethod(false);
12545
+ } else {
12546
+ setPaymentConfirmationState("error");
12547
+ setPaymentError(error?.message || "Failed to create subscription");
12548
+ }
12549
+ setLoadingPriceId(null);
12550
+ }
12551
+ }
12552
+ }, "handleSelectPrice");
12553
+ const handleConfirmPlanChange = /* @__PURE__ */ __name(async () => {
12554
+ if (!subscription || !selectedPriceId) return;
12555
+ setLoadingPriceId(selectedPriceId);
12556
+ try {
12557
+ await StripeSubscriptionService.changePlan({
12558
+ id: subscription.id,
12559
+ newPriceId: selectedPriceId
12560
+ });
12561
+ onSuccess();
12562
+ onOpenChange(false);
12563
+ } catch (error) {
12564
+ console.error("[SubscriptionEditor] Failed to change plan:", error);
12565
+ } finally {
12566
+ setLoadingPriceId(null);
12567
+ }
12568
+ }, "handleConfirmPlanChange");
12569
+ const handleCancel = /* @__PURE__ */ __name(() => {
12570
+ setSelectedPriceId(null);
12571
+ setProrationPreview(null);
12572
+ }, "handleCancel");
12573
+ return /* @__PURE__ */ jsx161(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs101(DialogContent, { className: "max-w-4xl max-h-[90vh] overflow-y-auto", children: [
12574
+ /* @__PURE__ */ jsxs101(DialogHeader, { children: [
12575
+ /* @__PURE__ */ jsx161(DialogTitle, { children: subscription ? "Change Plan" : "Subscribe to a Plan" }),
12576
+ /* @__PURE__ */ jsx161(DialogDescription, { children: subscription ? "Select a new plan to switch to. You'll see a proration preview before confirming." : "Choose a plan to start your subscription." })
12577
+ ] }),
12578
+ loadingPaymentMethods && !subscription ? /* @__PURE__ */ jsx161("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx161("div", { className: "text-muted-foreground", children: "Checking payment methods..." }) }) : !hasPaymentMethod && !subscription ? /* @__PURE__ */ jsxs101(Alert, { variant: "destructive", children: [
12579
+ /* @__PURE__ */ jsx161(AlertTitle, { children: "Payment Method Required" }),
12580
+ /* @__PURE__ */ jsxs101(AlertDescription, { className: "mt-2", children: [
12581
+ /* @__PURE__ */ jsx161("p", { className: "mb-4", children: paymentRequiredError ? "Your subscription could not be created because no payment method is on file." : "You need to add a payment method before you can subscribe to a plan." }),
12582
+ onAddPaymentMethod && /* @__PURE__ */ jsx161(Button, { onClick: onAddPaymentMethod, variant: "outline", children: "Add Payment Method" })
12583
+ ] })
12584
+ ] }) : paymentConfirmationState === "confirming" || isConfirming ? /* @__PURE__ */ jsxs101("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
12585
+ /* @__PURE__ */ jsx161(Loader22, { className: "h-8 w-8 animate-spin text-primary" }),
12586
+ /* @__PURE__ */ jsxs101("div", { className: "text-center", children: [
12587
+ /* @__PURE__ */ jsx161("p", { className: "font-medium", children: "Processing payment..." }),
12588
+ /* @__PURE__ */ jsx161("p", { className: "text-sm text-muted-foreground", children: "Please complete any verification if prompted." })
12589
+ ] })
12590
+ ] }) : paymentConfirmationState === "success" ? /* @__PURE__ */ jsxs101("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
12591
+ /* @__PURE__ */ jsx161(CheckCircle, { className: "h-12 w-12 text-green-500" }),
12592
+ /* @__PURE__ */ jsxs101("div", { className: "text-center", children: [
12593
+ /* @__PURE__ */ jsx161("p", { className: "font-medium text-green-600", children: "Payment successful!" }),
12594
+ /* @__PURE__ */ jsx161("p", { className: "text-sm text-muted-foreground", children: "Your subscription is now active." })
12595
+ ] })
12596
+ ] }) : paymentConfirmationState === "error" ? /* @__PURE__ */ jsx161("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs101(Alert, { variant: "destructive", children: [
12597
+ /* @__PURE__ */ jsx161(AlertTitle, { children: "Payment Failed" }),
12598
+ /* @__PURE__ */ jsxs101(AlertDescription, { className: "mt-2", children: [
12599
+ /* @__PURE__ */ jsx161("p", { className: "mb-4", children: paymentError || "We couldn't process your payment. Please try again." }),
12600
+ /* @__PURE__ */ jsx161(
12601
+ Button,
12602
+ {
12603
+ onClick: () => {
12604
+ setPaymentConfirmationState("idle");
12605
+ setPaymentError(null);
12606
+ setLoadingPriceId(null);
12607
+ },
12608
+ variant: "outline",
12609
+ children: "Try Again"
12610
+ }
12611
+ )
12612
+ ] })
12613
+ ] }) }) : /* @__PURE__ */ jsxs101("div", { className: "space-y-6", children: [
12614
+ /* @__PURE__ */ jsx161(
12615
+ PricingCardsGrid,
12616
+ {
12617
+ products,
12618
+ pricesByProduct,
12619
+ currentPriceId,
12620
+ selectedPriceId: selectedPriceId ?? void 0,
12621
+ loadingPriceId: loadingPriceId ?? void 0,
12622
+ loading,
12623
+ onSelectPrice: handleSelectPrice
12624
+ }
12625
+ ),
12626
+ isEditMode && loadingProration && /* @__PURE__ */ jsx161("div", { className: "bg-muted/50 rounded-lg p-4 text-sm text-muted-foreground text-center", children: "Loading proration preview..." }),
12627
+ isEditMode && prorationPreview && !loadingProration && /* @__PURE__ */ jsxs101("div", { className: "space-y-4", children: [
12628
+ /* @__PURE__ */ jsx161(ProrationPreview, { preview: prorationPreview }),
12629
+ /* @__PURE__ */ jsxs101("div", { className: "flex justify-end gap-3", children: [
12630
+ /* @__PURE__ */ jsx161(Button, { variant: "outline", onClick: handleCancel, disabled: !!loadingPriceId, children: "Cancel" }),
12631
+ /* @__PURE__ */ jsx161(Button, { onClick: handleConfirmPlanChange, disabled: !!loadingPriceId, children: loadingPriceId ? "Processing..." : "Confirm Plan Change" })
12632
+ ] })
12633
+ ] })
12634
+ ] })
12635
+ ] }) });
12636
+ }
12637
+ __name(SubscriptionEditor, "SubscriptionEditor");
12638
+
12639
+ // src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx
12640
+ import { useState as useState59 } from "react";
12641
+
12642
+ // src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx
12643
+ import { useState as useState58 } from "react";
12644
+
12645
+ // src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx
12646
+ import { jsx as jsx162 } from "react/jsx-runtime";
12647
+ var statusConfig2 = {
12648
+ ["active" /* ACTIVE */]: {
12649
+ label: "Active",
12650
+ color: "bg-green-100 text-green-800"
12651
+ },
12652
+ ["trialing" /* TRIALING */]: {
12653
+ label: "Trial",
12654
+ color: "bg-blue-100 text-blue-800"
12655
+ },
12656
+ ["past_due" /* PAST_DUE */]: {
12657
+ label: "Past Due",
12658
+ color: "bg-red-100 text-red-800"
12659
+ },
12660
+ ["canceled" /* CANCELED */]: {
12661
+ label: "Canceled",
12662
+ color: "bg-gray-100 text-gray-800"
12663
+ },
12664
+ ["paused" /* PAUSED */]: {
12665
+ label: "Paused",
12666
+ color: "bg-yellow-100 text-yellow-800"
12667
+ },
12668
+ ["unpaid" /* UNPAID */]: {
12669
+ label: "Unpaid",
12670
+ color: "bg-orange-100 text-orange-800"
12671
+ },
12672
+ ["incomplete" /* INCOMPLETE */]: {
12673
+ label: "Incomplete",
12674
+ color: "bg-gray-100 text-gray-800"
12675
+ },
12676
+ ["incomplete_expired" /* INCOMPLETE_EXPIRED */]: {
12677
+ label: "Expired",
12678
+ color: "bg-gray-100 text-gray-800"
12679
+ }
12680
+ };
12681
+ var cancelingConfig = {
12682
+ label: "Canceling",
12683
+ color: "bg-amber-100 text-amber-800"
12684
+ };
12685
+ function SubscriptionStatusBadge({ status, cancelAtPeriodEnd }) {
12686
+ const config = cancelAtPeriodEnd ? cancelingConfig : statusConfig2[status] || statusConfig2["canceled" /* CANCELED */];
12687
+ return /* @__PURE__ */ jsx162("span", { className: `${config.color} text-xs px-2 py-1 rounded-full font-medium`, children: config.label });
12688
+ }
12689
+ __name(SubscriptionStatusBadge, "SubscriptionStatusBadge");
12690
+
12691
+ // src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx
12692
+ import { Fragment as Fragment30, jsx as jsx163, jsxs as jsxs102 } from "react/jsx-runtime";
12693
+ function formatPlanName2(price) {
12694
+ if (!price) return "N/A";
12695
+ const productName = price.product?.name || "";
12696
+ const nickname = price.nickname || "";
12697
+ let interval = "";
12698
+ if (price.recurring?.interval) {
12699
+ const intervalMap = {
12700
+ day: "Daily",
12701
+ week: "Weekly",
12702
+ month: "Monthly",
12703
+ year: "Yearly"
12704
+ };
12705
+ interval = intervalMap[price.recurring.interval] || price.recurring.interval;
12706
+ }
12707
+ const parts = [productName, nickname].filter(Boolean);
12708
+ const planLabel = parts.join(" - ");
12709
+ return interval ? `${planLabel} (${interval})` : planLabel || "N/A";
12710
+ }
12711
+ __name(formatPlanName2, "formatPlanName");
12712
+ function formatBillingAmount(price) {
12713
+ if (!price?.unitAmount) return "N/A";
12714
+ return formatCurrency(price.unitAmount, price.currency);
12715
+ }
12716
+ __name(formatBillingAmount, "formatBillingAmount");
12717
+ function SubscriptionDetails({
12718
+ subscription,
12719
+ open,
12720
+ onOpenChange,
12721
+ onSubscriptionChange
12722
+ }) {
12723
+ const [showEdit, setShowEdit] = useState58(false);
12724
+ const [showCancel, setShowCancel] = useState58(false);
12725
+ const [isProcessing, setIsProcessing] = useState58(false);
12726
+ const handlePause = /* @__PURE__ */ __name(async () => {
12727
+ setIsProcessing(true);
12728
+ try {
12729
+ await StripeSubscriptionService.pauseSubscription({ subscriptionId: subscription.id });
12730
+ onSubscriptionChange();
12731
+ } catch (error) {
12732
+ console.error("[SubscriptionDetails] Failed to pause subscription:", error);
12733
+ } finally {
12734
+ setIsProcessing(false);
12735
+ }
12736
+ }, "handlePause");
12737
+ const handleResume = /* @__PURE__ */ __name(async () => {
12738
+ setIsProcessing(true);
12739
+ try {
12740
+ await StripeSubscriptionService.resumeSubscription({ subscriptionId: subscription.id });
12741
+ onSubscriptionChange();
12742
+ } catch (error) {
12743
+ console.error("[SubscriptionDetails] Failed to resume subscription:", error);
12744
+ } finally {
12745
+ setIsProcessing(false);
12746
+ }
12747
+ }, "handleResume");
12748
+ const handleManageViaPortal = /* @__PURE__ */ __name(async () => {
12749
+ try {
12750
+ const { url } = await StripeCustomerService.createPortalSession();
12751
+ window.open(url, "_blank");
12752
+ } catch (error) {
12753
+ console.error("[SubscriptionDetails] Failed to create portal session:", error);
12754
+ }
12755
+ }, "handleManageViaPortal");
12756
+ const canPause = subscription.status === "active" /* ACTIVE */;
12757
+ const canResume = subscription.status === "paused" /* PAUSED */;
12758
+ const canCancel = subscription.status === "active" /* ACTIVE */ || subscription.status === "trialing" /* TRIALING */ || subscription.status === "paused" /* PAUSED */;
12759
+ return /* @__PURE__ */ jsxs102(Fragment30, { children: [
12760
+ /* @__PURE__ */ jsx163(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs102(DialogContent, { className: "max-w-2xl", children: [
12761
+ /* @__PURE__ */ jsxs102(DialogHeader, { children: [
12762
+ /* @__PURE__ */ jsx163(DialogTitle, { children: "Subscription Details" }),
12763
+ /* @__PURE__ */ jsx163(DialogDescription, { children: "View and manage your subscription" })
12764
+ ] }),
12765
+ /* @__PURE__ */ jsxs102("div", { className: "space-y-6", children: [
12766
+ /* @__PURE__ */ jsxs102("div", { className: "flex items-center gap-x-3", children: [
12767
+ /* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Status:" }),
12768
+ /* @__PURE__ */ jsx163(SubscriptionStatusBadge, { status: subscription.status, cancelAtPeriodEnd: subscription.cancelAtPeriodEnd })
12769
+ ] }),
12770
+ /* @__PURE__ */ jsxs102("div", { className: "space-y-2", children: [
12771
+ /* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
12772
+ /* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Plan:" }),
12773
+ /* @__PURE__ */ jsx163("span", { className: "font-medium", children: formatPlanName2(subscription.price) })
12774
+ ] }),
12775
+ /* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
12776
+ /* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Billing Amount:" }),
12777
+ /* @__PURE__ */ jsx163("span", { className: "font-medium", children: formatBillingAmount(subscription.price) })
12778
+ ] })
12779
+ ] }),
12780
+ /* @__PURE__ */ jsx163("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
12781
+ /* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Current Period:" }),
12782
+ /* @__PURE__ */ jsxs102("span", { className: "font-medium", children: [
12783
+ formatDate3(subscription.currentPeriodStart),
12784
+ " - ",
12785
+ formatDate3(subscription.currentPeriodEnd)
12786
+ ] })
12787
+ ] }) }),
12788
+ subscription.trialEnd && /* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
12789
+ /* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Trial Ends:" }),
12790
+ /* @__PURE__ */ jsx163("span", { className: "font-medium", children: formatDate3(subscription.trialEnd) })
12791
+ ] }),
12792
+ subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsx163("div", { className: "bg-yellow-50 border border-yellow-200 rounded-lg p-3", children: /* @__PURE__ */ jsxs102("p", { className: "text-sm text-yellow-800", children: [
12793
+ "This subscription will be canceled at the end of the current period on",
12794
+ " ",
12795
+ formatDate3(subscription.currentPeriodEnd),
12796
+ "."
12797
+ ] }) }),
12798
+ /* @__PURE__ */ jsxs102("div", { className: "flex flex-wrap gap-2 pt-4 border-t", children: [
12799
+ /* @__PURE__ */ jsx163(Button, { variant: "default", onClick: () => setShowEdit(true), children: "Change Plan" }),
12800
+ canPause && /* @__PURE__ */ jsx163(Button, { variant: "outline", onClick: handlePause, disabled: isProcessing, children: isProcessing ? "Pausing..." : "Pause" }),
12801
+ canResume && /* @__PURE__ */ jsx163(Button, { variant: "outline", onClick: handleResume, disabled: isProcessing, children: isProcessing ? "Resuming..." : "Resume" }),
12802
+ canCancel && /* @__PURE__ */ jsx163(Button, { variant: "destructive", onClick: () => setShowCancel(true), children: "Cancel" }),
12803
+ /* @__PURE__ */ jsx163(Button, { variant: "outline", onClick: handleManageViaPortal, children: "Manage via Portal" })
12804
+ ] })
12805
+ ] })
12806
+ ] }) }),
12807
+ showEdit && /* @__PURE__ */ jsx163(
12808
+ SubscriptionEditor,
12809
+ {
12810
+ subscription,
12811
+ open: showEdit,
12812
+ onOpenChange: setShowEdit,
12813
+ onSuccess: () => {
12814
+ onSubscriptionChange();
12815
+ setShowEdit(false);
12816
+ }
12817
+ }
12818
+ ),
12819
+ showCancel && /* @__PURE__ */ jsx163(
12820
+ CancelSubscriptionDialog,
12821
+ {
12822
+ subscription,
12823
+ open: showCancel,
12824
+ onOpenChange: setShowCancel,
12825
+ onSuccess: () => {
12826
+ onSubscriptionChange();
12827
+ setShowCancel(false);
12828
+ }
12829
+ }
12830
+ )
12831
+ ] });
12832
+ }
12833
+ __name(SubscriptionDetails, "SubscriptionDetails");
12834
+
12835
+ // src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx
12836
+ import { Fragment as Fragment31, jsx as jsx164, jsxs as jsxs103 } from "react/jsx-runtime";
12837
+ function formatPlanName3(price) {
12838
+ if (!price) return "N/A";
12839
+ const productName = price.product?.name || "";
12840
+ const nickname = price.nickname || "";
12841
+ let interval = "";
12842
+ if (price.recurring?.interval) {
12843
+ const intervalMap = {
12844
+ day: "Daily",
12845
+ week: "Weekly",
12846
+ month: "Monthly",
12847
+ year: "Yearly"
12848
+ };
12849
+ interval = intervalMap[price.recurring.interval] || price.recurring.interval;
12850
+ }
12851
+ const parts = [productName, nickname].filter(Boolean);
12852
+ const planLabel = parts.join(" - ");
12853
+ return interval ? `${planLabel} (${interval})` : planLabel || "N/A";
12854
+ }
12855
+ __name(formatPlanName3, "formatPlanName");
12856
+ function SubscriptionsList({ subscriptions, onSubscriptionsChange }) {
12857
+ const [selectedSub, setSelectedSub] = useState59(null);
12858
+ const handleRowClick = /* @__PURE__ */ __name((subscription) => {
12859
+ setSelectedSub(subscription);
12860
+ }, "handleRowClick");
12861
+ return /* @__PURE__ */ jsxs103(Fragment31, { children: [
12862
+ /* @__PURE__ */ jsx164("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs103(Table, { children: [
12863
+ /* @__PURE__ */ jsx164(TableHeader, { className: "bg-muted", children: /* @__PURE__ */ jsxs103(TableRow, { children: [
12864
+ /* @__PURE__ */ jsx164(TableHead, { children: "Status" }),
12865
+ /* @__PURE__ */ jsx164(TableHead, { children: "Plan" }),
12866
+ /* @__PURE__ */ jsx164(TableHead, { children: "Period" }),
12867
+ /* @__PURE__ */ jsx164(TableHead, { className: "text-right", children: "Amount" })
12868
+ ] }) }),
12869
+ /* @__PURE__ */ jsx164(TableBody, { children: subscriptions.map((subscription) => {
12870
+ const price = subscription.price;
12871
+ const amount = price?.unitAmount ? formatCurrency(price.unitAmount, price.currency) : "N/A";
12872
+ const period = `${formatDate3(subscription.currentPeriodStart)} - ${formatDate3(subscription.currentPeriodEnd)}`;
12873
+ return /* @__PURE__ */ jsxs103(
12874
+ TableRow,
12875
+ {
12876
+ onClick: () => handleRowClick(subscription),
12877
+ className: "cursor-pointer hover:bg-muted/50",
12878
+ children: [
12879
+ /* @__PURE__ */ jsx164(TableCell, { children: /* @__PURE__ */ jsx164(SubscriptionStatusBadge, { status: subscription.status, cancelAtPeriodEnd: subscription.cancelAtPeriodEnd }) }),
12880
+ /* @__PURE__ */ jsx164(TableCell, { className: "font-medium", children: formatPlanName3(price) }),
12881
+ /* @__PURE__ */ jsx164(TableCell, { className: "text-muted-foreground text-sm", children: period }),
12882
+ /* @__PURE__ */ jsx164(TableCell, { className: "text-right font-medium", children: amount })
12883
+ ]
12884
+ },
12885
+ subscription.id
12886
+ );
12887
+ }) })
12888
+ ] }) }),
12889
+ selectedSub && /* @__PURE__ */ jsx164(
12890
+ SubscriptionDetails,
12891
+ {
12892
+ subscription: selectedSub,
12893
+ open: !!selectedSub,
12894
+ onOpenChange: (open) => !open && setSelectedSub(null),
12895
+ onSubscriptionChange: () => {
12896
+ onSubscriptionsChange();
12897
+ setSelectedSub(null);
12898
+ }
12899
+ }
12900
+ )
12901
+ ] });
12902
+ }
12903
+ __name(SubscriptionsList, "SubscriptionsList");
12904
+
12905
+ // src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx
12906
+ import { Fragment as Fragment32, jsx as jsx165, jsxs as jsxs104 } from "react/jsx-runtime";
12907
+ function SubscriptionsContainer() {
12908
+ const { confirmPayment, isConfirming } = useConfirmSubscriptionPayment();
12909
+ const [subscriptions, setSubscriptions] = useState60([]);
12910
+ const [loading, setLoading] = useState60(true);
12911
+ const [showCreateSubscription, setShowCreateSubscription] = useState60(false);
12912
+ const [showPaymentMethodEditor, setShowPaymentMethodEditor] = useState60(false);
12913
+ const [products, setProducts] = useState60([]);
12914
+ const [pricesByProduct, setPricesByProduct] = useState60(/* @__PURE__ */ new Map());
12915
+ const [loadingPricing, setLoadingPricing] = useState60(false);
12916
+ const [hasPaymentMethod, setHasPaymentMethod] = useState60(null);
12917
+ const [pendingPriceId, setPendingPriceId] = useState60(null);
12918
+ const [creatingSubscription, setCreatingSubscription] = useState60(false);
12919
+ const [paymentConfirmationState, setPaymentConfirmationState] = useState60("idle");
12920
+ const [paymentError, setPaymentError] = useState60(null);
12921
+ const loadSubscriptions = /* @__PURE__ */ __name(async () => {
12922
+ setLoading(true);
12923
+ try {
12924
+ const fetchedSubscriptions = await StripeSubscriptionService.listSubscriptions();
12925
+ setSubscriptions(fetchedSubscriptions);
12926
+ } catch (error) {
12927
+ console.error("[SubscriptionsContainer] Failed to load subscriptions:", error);
12928
+ } finally {
12929
+ setLoading(false);
12930
+ }
12931
+ }, "loadSubscriptions");
12932
+ const loadPricingData = /* @__PURE__ */ __name(async () => {
12933
+ setLoadingPricing(true);
12934
+ try {
12935
+ const fetchedProducts = await StripeProductService.listProducts({ active: true });
12936
+ const grouped = /* @__PURE__ */ new Map();
12937
+ for (const product of fetchedProducts) {
12938
+ if (product.stripePrices && product.stripePrices.length > 0) {
12939
+ grouped.set(product.id, product.stripePrices);
12940
+ }
12941
+ }
12942
+ setProducts(fetchedProducts);
12943
+ setPricesByProduct(grouped);
12944
+ } catch (error) {
12945
+ console.error("[SubscriptionsContainer] Failed to load pricing data:", error);
12946
+ } finally {
12947
+ setLoadingPricing(false);
12948
+ }
12949
+ }, "loadPricingData");
12950
+ const checkPaymentMethod = /* @__PURE__ */ __name(async () => {
12951
+ try {
12952
+ const paymentMethods = await StripeCustomerService.listPaymentMethods();
12953
+ const hasMethod = paymentMethods.length > 0;
12954
+ setHasPaymentMethod(hasMethod);
12955
+ } catch (error) {
12956
+ console.error("[SubscriptionsContainer] Failed to check payment methods:", error);
12957
+ setHasPaymentMethod(false);
12958
+ }
12959
+ }, "checkPaymentMethod");
12960
+ const createSubscriptionWithPrice = /* @__PURE__ */ __name(async (priceId) => {
12961
+ setCreatingSubscription(true);
12962
+ setPaymentError(null);
12963
+ setPaymentConfirmationState("idle");
12964
+ try {
12965
+ const result = await StripeSubscriptionService.createSubscription({
12966
+ id: v46(),
12967
+ priceId
12968
+ });
12969
+ if (result.meta.requiresAction && result.meta.clientSecret) {
12970
+ setPaymentConfirmationState("confirming");
12971
+ const confirmation = await confirmPayment(result.meta.clientSecret);
12972
+ if (!confirmation.success) {
12973
+ console.error("[SubscriptionsContainer] Payment confirmation failed:", confirmation.error);
12974
+ setPaymentConfirmationState("error");
12975
+ setPaymentError(confirmation.error || "Payment confirmation failed");
12976
+ setCreatingSubscription(false);
12977
+ return;
12978
+ }
12979
+ await StripeSubscriptionService.syncSubscription({
12980
+ subscriptionId: result.subscription.id
12981
+ });
12982
+ }
12983
+ setPaymentConfirmationState("success");
12984
+ await loadSubscriptions();
12985
+ } catch (error) {
12986
+ console.error("[SubscriptionsContainer] Failed to create subscription:", error);
12987
+ if (error?.status === 402 || error?.response?.status === 402) {
12988
+ setPendingPriceId(priceId);
12989
+ setHasPaymentMethod(false);
12990
+ setShowPaymentMethodEditor(true);
12991
+ } else {
12992
+ setPaymentConfirmationState("error");
12993
+ setPaymentError(error?.message || "Failed to create subscription");
12994
+ }
12995
+ } finally {
12996
+ setCreatingSubscription(false);
12997
+ }
12998
+ }, "createSubscriptionWithPrice");
12999
+ const handleSelectPrice = /* @__PURE__ */ __name(async (price) => {
13000
+ const priceId = price.id;
13001
+ if (!hasPaymentMethod) {
13002
+ setPendingPriceId(priceId);
13003
+ setShowPaymentMethodEditor(true);
13004
+ return;
13005
+ }
13006
+ await createSubscriptionWithPrice(priceId);
13007
+ }, "handleSelectPrice");
13008
+ const handlePaymentMethodSuccess = /* @__PURE__ */ __name(async () => {
13009
+ setShowPaymentMethodEditor(false);
13010
+ setHasPaymentMethod(true);
13011
+ if (pendingPriceId) {
13012
+ await createSubscriptionWithPrice(pendingPriceId);
13013
+ setPendingPriceId(null);
13014
+ }
13015
+ }, "handlePaymentMethodSuccess");
13016
+ useEffect45(() => {
13017
+ loadSubscriptions();
13018
+ }, []);
13019
+ useEffect45(() => {
13020
+ if (!loading && subscriptions.length === 0) {
13021
+ loadPricingData();
13022
+ checkPaymentMethod();
13023
+ }
13024
+ }, [loading, subscriptions.length]);
13025
+ const criticalSubscriptions = subscriptions.filter(
13026
+ (sub) => sub.status === "past_due" /* PAST_DUE */ || sub.status === "trialing" /* TRIALING */ && sub.trialEnd && new Date(sub.trialEnd).getTime() - (/* @__PURE__ */ new Date()).getTime() <= 7 * 24 * 60 * 60 * 1e3
13027
+ );
13028
+ if (loading) {
13029
+ return /* @__PURE__ */ jsx165("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx165("p", { className: "text-muted-foreground", children: "Loading subscriptions..." }) });
13030
+ }
13031
+ return /* @__PURE__ */ jsxs104("div", { className: "flex w-full flex-col gap-y-6", children: [
13032
+ /* @__PURE__ */ jsxs104("div", { className: "flex items-center justify-between", children: [
13033
+ /* @__PURE__ */ jsxs104("div", { className: "flex items-center gap-x-3", children: [
13034
+ /* @__PURE__ */ jsx165(CreditCard3, { className: "h-8 w-8" }),
13035
+ /* @__PURE__ */ jsx165("h1", { className: "text-3xl font-bold", children: "Subscriptions" })
13036
+ ] }),
13037
+ subscriptions.length > 0 && /* @__PURE__ */ jsx165(Button, { onClick: () => setShowCreateSubscription(true), children: "Subscribe to a Plan" })
13038
+ ] }),
13039
+ criticalSubscriptions.map((subscription) => /* @__PURE__ */ jsx165(BillingAlertBanner, { subscription }, subscription.id)),
13040
+ subscriptions.length === 0 && /* @__PURE__ */ jsxs104("div", { className: "space-y-6", children: [
13041
+ (paymentConfirmationState === "confirming" || isConfirming) && /* @__PURE__ */ jsxs104("div", { className: "flex flex-col items-center justify-center py-12 space-y-4 bg-muted/50 rounded-lg", children: [
13042
+ /* @__PURE__ */ jsx165(Loader23, { className: "h-8 w-8 animate-spin text-primary" }),
13043
+ /* @__PURE__ */ jsxs104("div", { className: "text-center", children: [
13044
+ /* @__PURE__ */ jsx165("p", { className: "font-medium", children: "Processing payment..." }),
13045
+ /* @__PURE__ */ jsx165("p", { className: "text-sm text-muted-foreground", children: "Please complete any verification if prompted." })
13046
+ ] })
13047
+ ] }),
13048
+ paymentConfirmationState === "success" && /* @__PURE__ */ jsxs104("div", { className: "flex flex-col items-center justify-center py-8 space-y-4 bg-green-50 rounded-lg border border-green-200", children: [
13049
+ /* @__PURE__ */ jsx165(CheckCircle2, { className: "h-12 w-12 text-green-500" }),
13050
+ /* @__PURE__ */ jsxs104("div", { className: "text-center", children: [
13051
+ /* @__PURE__ */ jsx165("p", { className: "font-medium text-green-600", children: "Payment successful!" }),
13052
+ /* @__PURE__ */ jsx165("p", { className: "text-sm text-muted-foreground", children: "Your subscription is now active." })
13053
+ ] })
13054
+ ] }),
13055
+ paymentConfirmationState === "error" && /* @__PURE__ */ jsxs104(Alert, { variant: "destructive", children: [
13056
+ /* @__PURE__ */ jsx165(AlertTitle, { children: "Payment Failed" }),
13057
+ /* @__PURE__ */ jsxs104(AlertDescription, { className: "mt-2", children: [
13058
+ /* @__PURE__ */ jsx165("p", { className: "mb-4", children: paymentError || "We couldn't process your payment. Please try again." }),
13059
+ /* @__PURE__ */ jsx165(
13060
+ Button,
13061
+ {
13062
+ onClick: () => {
13063
+ setPaymentConfirmationState("idle");
13064
+ setPaymentError(null);
13065
+ },
13066
+ variant: "outline",
13067
+ children: "Try Again"
13068
+ }
13069
+ )
13070
+ ] })
13071
+ ] }),
13072
+ paymentConfirmationState === "idle" && !isConfirming && /* @__PURE__ */ jsxs104(Fragment32, { children: [
13073
+ /* @__PURE__ */ jsxs104("div", { className: "text-center", children: [
13074
+ /* @__PURE__ */ jsx165(CreditCard3, { className: "text-muted-foreground mx-auto h-16 w-16 mb-4" }),
13075
+ /* @__PURE__ */ jsx165("h3", { className: "mb-2 text-xl font-semibold", children: "Choose Your Plan" }),
13076
+ /* @__PURE__ */ jsx165("p", { className: "text-muted-foreground mb-6", children: "Select a subscription plan to get started with our services." })
13077
+ ] }),
13078
+ /* @__PURE__ */ jsx165(
13079
+ PricingCardsGrid,
13080
+ {
13081
+ products,
13082
+ pricesByProduct,
13083
+ loading: loadingPricing,
13084
+ loadingPriceId: creatingSubscription ? pendingPriceId ?? void 0 : void 0,
13085
+ onSelectPrice: handleSelectPrice
13086
+ }
13087
+ )
13088
+ ] })
13089
+ ] }),
13090
+ subscriptions.length > 0 && /* @__PURE__ */ jsx165(SubscriptionsList, { subscriptions, onSubscriptionsChange: loadSubscriptions }),
13091
+ showCreateSubscription && /* @__PURE__ */ jsx165(
13092
+ SubscriptionEditor,
13093
+ {
13094
+ open: showCreateSubscription,
13095
+ onOpenChange: setShowCreateSubscription,
13096
+ onSuccess: loadSubscriptions,
13097
+ onAddPaymentMethod: () => {
13098
+ setShowCreateSubscription(false);
13099
+ setShowPaymentMethodEditor(true);
13100
+ }
13101
+ }
13102
+ ),
13103
+ showPaymentMethodEditor && /* @__PURE__ */ jsx165(
13104
+ PaymentMethodEditor,
13105
+ {
13106
+ open: showPaymentMethodEditor,
13107
+ onOpenChange: (open) => {
13108
+ setShowPaymentMethodEditor(open);
13109
+ if (!open) {
13110
+ setPendingPriceId(null);
13111
+ }
13112
+ },
13113
+ onSuccess: handlePaymentMethodSuccess
13114
+ }
13115
+ )
13116
+ ] });
13117
+ }
13118
+ __name(SubscriptionsContainer, "SubscriptionsContainer");
13119
+
13120
+ // src/features/billing/stripe-usage/components/containers/UsageContainer.tsx
13121
+ import { Activity as Activity3 } from "lucide-react";
13122
+ import { useEffect as useEffect46, useState as useState61 } from "react";
13123
+
13124
+ // src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx
13125
+ import { Activity as Activity2 } from "lucide-react";
13126
+ import { jsx as jsx166, jsxs as jsxs105 } from "react/jsx-runtime";
13127
+ function getProgressColor(percentage) {
13128
+ if (percentage === null) return "bg-blue-500";
13129
+ if (percentage >= 90) return "bg-red-500";
13130
+ if (percentage >= 75) return "bg-orange-500";
13131
+ return "bg-green-500";
13132
+ }
13133
+ __name(getProgressColor, "getProgressColor");
13134
+ function formatDate4(date) {
13135
+ if (!date) return "N/A";
13136
+ try {
13137
+ return new Intl.DateTimeFormat("en-US", {
13138
+ month: "short",
13139
+ day: "numeric"
13140
+ }).format(new Date(date));
13141
+ } catch (error) {
13142
+ return "Invalid Date";
13143
+ }
13144
+ }
13145
+ __name(formatDate4, "formatDate");
13146
+ function UsageSummaryCard({ meter, summary }) {
13147
+ const currentUsage = summary?.aggregatedValue ?? 0;
13148
+ const limit = meter.limit;
13149
+ const percentage = limit && limit > 0 ? currentUsage / limit * 100 : null;
13150
+ const progressColor = getProgressColor(percentage);
13151
+ const progressWidth = percentage !== null ? Math.min(percentage, 100) : 0;
13152
+ const displayName = meter.displayName || meter.eventName;
13153
+ const hasLimit = limit !== null && limit !== void 0;
13154
+ return /* @__PURE__ */ jsxs105(Card, { children: [
13155
+ /* @__PURE__ */ jsxs105(CardHeader, { className: "flex flex-row items-center gap-x-3 pb-3", children: [
13156
+ /* @__PURE__ */ jsx166("div", { className: "flex h-10 w-10 items-center justify-center rounded-lg bg-blue-100 text-blue-600", children: /* @__PURE__ */ jsx166(Activity2, { className: "h-5 w-5" }) }),
13157
+ /* @__PURE__ */ jsxs105("div", { className: "flex flex-col", children: [
13158
+ /* @__PURE__ */ jsx166("h3", { className: "font-semibold", children: displayName }),
13159
+ /* @__PURE__ */ jsx166("p", { className: "text-xs text-gray-500", children: meter.id })
13160
+ ] })
13161
+ ] }),
13162
+ /* @__PURE__ */ jsxs105(CardContent, { className: "flex flex-col gap-y-4", children: [
13163
+ /* @__PURE__ */ jsxs105("div", { children: [
13164
+ /* @__PURE__ */ jsx166("p", { className: "text-3xl font-bold", children: currentUsage.toLocaleString() }),
13165
+ hasLimit && /* @__PURE__ */ jsxs105("p", { className: "text-sm text-gray-500", children: [
13166
+ "of ",
13167
+ limit.toLocaleString(),
13168
+ " used"
13169
+ ] })
13170
+ ] }),
13171
+ hasLimit ? /* @__PURE__ */ jsxs105("div", { className: "flex flex-col gap-y-2", children: [
13172
+ /* @__PURE__ */ jsx166("div", { className: "h-2 w-full overflow-hidden rounded-full bg-gray-200", children: /* @__PURE__ */ jsx166("div", { className: `h-full transition-all ${progressColor}`, style: { width: `${progressWidth}%` } }) }),
13173
+ /* @__PURE__ */ jsxs105("p", { className: "text-sm text-gray-500", children: [
13174
+ percentage?.toFixed(1),
13175
+ "% used"
13176
+ ] })
13177
+ ] }) : /* @__PURE__ */ jsx166("p", { className: "text-sm text-gray-500", children: "No limit set" }),
13178
+ summary && summary.start && summary.end && /* @__PURE__ */ jsx166("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsxs105("p", { className: "text-xs text-gray-500", children: [
13179
+ "Period: ",
13180
+ formatDate4(summary.start),
13181
+ " - ",
13182
+ formatDate4(summary.end)
13183
+ ] }) })
13184
+ ] })
13185
+ ] });
13186
+ }
13187
+ __name(UsageSummaryCard, "UsageSummaryCard");
13188
+
13189
+ // src/features/billing/stripe-usage/components/widgets/UsageSummaryCards.tsx
13190
+ import { jsx as jsx167 } from "react/jsx-runtime";
13191
+ function UsageSummaryCards({ meters, summaries }) {
13192
+ return /* @__PURE__ */ jsx167("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: meters.map((meter) => /* @__PURE__ */ jsx167(UsageSummaryCard, { meter, summary: summaries[meter.id] || null }, meter.id)) });
13193
+ }
13194
+ __name(UsageSummaryCards, "UsageSummaryCards");
13195
+
13196
+ // src/features/billing/stripe-usage/components/containers/UsageContainer.tsx
13197
+ import { jsx as jsx168, jsxs as jsxs106 } from "react/jsx-runtime";
13198
+ function UsageContainer() {
13199
+ const [meters, setMeters] = useState61([]);
13200
+ const [summaries, setSummaries] = useState61({});
13201
+ const [loading, setLoading] = useState61(true);
13202
+ const [subscriptions, setSubscriptions] = useState61([]);
13203
+ useEffect46(() => {
13204
+ loadUsageData();
13205
+ }, []);
13206
+ const loadUsageData = /* @__PURE__ */ __name(async () => {
13207
+ setLoading(true);
13208
+ try {
13209
+ const fetchedSubscriptions = await StripeSubscriptionService.listSubscriptions();
13210
+ setSubscriptions(fetchedSubscriptions);
13211
+ const hasMeteredSubscriptions2 = fetchedSubscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
13212
+ if (!hasMeteredSubscriptions2) {
13213
+ setLoading(false);
13214
+ return;
13215
+ }
13216
+ const fetchedMeters = await StripeUsageService.listMeters();
13217
+ setMeters(fetchedMeters);
13218
+ const summariesMap = {};
13219
+ const now = /* @__PURE__ */ new Date();
13220
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
13221
+ const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
13222
+ for (const meter of fetchedMeters) {
13223
+ try {
13224
+ const meterSummaries = await StripeUsageService.getMeterSummaries({
13225
+ meterId: meter.id,
13226
+ startTime: startOfMonth,
13227
+ endTime: endOfMonth
13228
+ });
13229
+ summariesMap[meter.id] = meterSummaries.length > 0 ? meterSummaries[0] : null;
13230
+ } catch (error) {
13231
+ console.error(`[UsageContainer] Failed to load summaries for meter ${meter.id}:`, error);
13232
+ summariesMap[meter.id] = null;
13233
+ }
13234
+ }
13235
+ setSummaries(summariesMap);
13236
+ } catch (error) {
13237
+ console.error("[UsageContainer] Failed to load usage data:", error);
13238
+ } finally {
13239
+ setLoading(false);
13240
+ }
13241
+ }, "loadUsageData");
13242
+ const hasMeteredSubscriptions = subscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
13243
+ if (!loading && !hasMeteredSubscriptions) {
13244
+ return null;
13245
+ }
13246
+ if (loading) {
13247
+ return /* @__PURE__ */ jsx168("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx168("p", { className: "text-muted-foreground", children: "Loading usage data..." }) });
13248
+ }
13249
+ return /* @__PURE__ */ jsxs106("div", { className: "flex w-full flex-col gap-y-6", children: [
13250
+ /* @__PURE__ */ jsxs106("div", { className: "flex items-center gap-x-3", children: [
13251
+ /* @__PURE__ */ jsx168(Activity3, { className: "h-8 w-8" }),
13252
+ /* @__PURE__ */ jsx168("h1", { className: "text-3xl font-bold", children: "Usage Tracking" })
13253
+ ] }),
13254
+ meters.length === 0 && /* @__PURE__ */ jsxs106("div", { className: "bg-muted/50 flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed border-gray-300 p-12", children: [
13255
+ /* @__PURE__ */ jsx168(Activity3, { className: "text-muted-foreground h-16 w-16" }),
13256
+ /* @__PURE__ */ jsxs106("div", { className: "text-center", children: [
13257
+ /* @__PURE__ */ jsx168("h3", { className: "mb-2 text-xl font-semibold", children: "No usage meters configured" }),
13258
+ /* @__PURE__ */ jsx168("p", { className: "text-muted-foreground", children: "Usage tracking will appear here when you have metered subscriptions with configured meters." })
13259
+ ] })
13260
+ ] }),
13261
+ meters.length > 0 && /* @__PURE__ */ jsx168(UsageSummaryCards, { meters, summaries })
13262
+ ] });
13263
+ }
13264
+ __name(UsageContainer, "UsageContainer");
13265
+
13266
+ // src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx
13267
+ import { jsx as jsx169, jsxs as jsxs107 } from "react/jsx-runtime";
13268
+ function formatDateTime(date) {
13269
+ if (!date) return "N/A";
13270
+ const dateObj = typeof date === "string" ? new Date(date) : date;
13271
+ try {
13272
+ return new Intl.DateTimeFormat("en-US", {
13273
+ month: "short",
13274
+ day: "numeric",
13275
+ year: "numeric",
13276
+ hour: "numeric",
13277
+ minute: "2-digit"
13278
+ }).format(dateObj);
13279
+ } catch (error) {
13280
+ return "Invalid Date";
13281
+ }
13282
+ }
13283
+ __name(formatDateTime, "formatDateTime");
13284
+ function UsageHistoryTable({ usageRecords }) {
13285
+ if (usageRecords.length === 0) {
13286
+ return /* @__PURE__ */ jsx169("div", { className: "rounded-lg border p-8 text-center", children: /* @__PURE__ */ jsx169("p", { className: "text-muted-foreground", children: "No usage history available." }) });
13287
+ }
13288
+ return /* @__PURE__ */ jsxs107("div", { className: "flex w-full flex-col gap-y-4", children: [
13289
+ /* @__PURE__ */ jsx169("h2", { className: "text-xl font-semibold", children: "Usage History" }),
13290
+ /* @__PURE__ */ jsx169("div", { className: "overflow-hidden rounded-lg border", children: /* @__PURE__ */ jsxs107(Table, { children: [
13291
+ /* @__PURE__ */ jsx169(TableHeader, { className: "bg-muted", children: /* @__PURE__ */ jsxs107(TableRow, { children: [
13292
+ /* @__PURE__ */ jsx169(TableHead, { children: "Date & Time" }),
13293
+ /* @__PURE__ */ jsx169(TableHead, { children: "Meter Event" }),
13294
+ /* @__PURE__ */ jsx169(TableHead, { className: "text-right", children: "Quantity" }),
13295
+ /* @__PURE__ */ jsx169(TableHead, { children: "Event ID" })
13296
+ ] }) }),
13297
+ /* @__PURE__ */ jsx169(TableBody, { children: usageRecords.map((record) => {
13298
+ const dateTime = formatDateTime(record.timestamp);
13299
+ const quantity = record.quantity.toLocaleString();
13300
+ return /* @__PURE__ */ jsxs107(TableRow, { children: [
13301
+ /* @__PURE__ */ jsx169(TableCell, { className: "font-medium", children: dateTime }),
13302
+ /* @__PURE__ */ jsx169(TableCell, { className: "text-muted-foreground", children: record.meterEventName }),
13303
+ /* @__PURE__ */ jsx169(TableCell, { className: "text-right font-medium", children: quantity }),
13304
+ /* @__PURE__ */ jsx169(TableCell, { className: "text-muted-foreground text-sm font-mono", children: record.stripeEventId })
13305
+ ] }, record.id);
13306
+ }) })
13307
+ ] }) })
13308
+ ] });
13309
+ }
13310
+ __name(UsageHistoryTable, "UsageHistoryTable");
13311
+
13312
+ // src/features/billing/components/modals/BillingDetailModal.tsx
13313
+ import { jsx as jsx170, jsxs as jsxs108 } from "react/jsx-runtime";
13314
+ function BillingDetailModal({
13315
+ open,
13316
+ onOpenChange,
13317
+ title,
13318
+ children,
13319
+ className
13320
+ }) {
13321
+ return /* @__PURE__ */ jsx170(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs108(DialogContent, { className: className ?? "max-w-4xl max-h-[90vh] overflow-y-auto", children: [
13322
+ /* @__PURE__ */ jsx170(DialogHeader, { children: /* @__PURE__ */ jsx170(DialogTitle, { children: title }) }),
13323
+ children
13324
+ ] }) });
13325
+ }
13326
+ __name(BillingDetailModal, "BillingDetailModal");
13327
+
13328
+ // src/features/billing/components/widgets/BillingAlertBanner.tsx
13329
+ import { AlertCircle } from "lucide-react";
13330
+ import { jsx as jsx171, jsxs as jsxs109 } from "react/jsx-runtime";
13331
+ function BillingAlertBanner({ subscription, onUpdatePayment, onAddPayment }) {
13332
+ if (subscription.status === "past_due" /* PAST_DUE */) {
13333
+ return /* @__PURE__ */ jsxs109("div", { className: "bg-red-50 border border-red-200 rounded-lg p-4 flex items-start gap-x-3", children: [
13334
+ /* @__PURE__ */ jsx171(AlertCircle, { className: "h-5 w-5 text-red-600 mt-0.5" }),
13335
+ /* @__PURE__ */ jsxs109("div", { className: "flex-1", children: [
13336
+ /* @__PURE__ */ jsx171("h3", { className: "font-semibold text-red-900", children: "Payment Failed" }),
13337
+ /* @__PURE__ */ jsx171("p", { className: "text-sm text-red-700 mt-1", children: "Your last payment failed. Please update your payment method to avoid service interruption." })
13338
+ ] }),
13339
+ onUpdatePayment && /* @__PURE__ */ jsx171(Button, { variant: "outline", size: "sm", onClick: onUpdatePayment, className: "border-red-300 text-red-700", children: "Update Payment Method" })
13340
+ ] });
13341
+ }
13342
+ if (subscription.status === "trialing" /* TRIALING */ && subscription.trialEnd) {
13343
+ const trialEnd = new Date(subscription.trialEnd);
13344
+ const now = /* @__PURE__ */ new Date();
13345
+ const daysRemaining = Math.ceil((trialEnd.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24));
13346
+ if (daysRemaining <= 7) {
13347
+ return /* @__PURE__ */ jsxs109("div", { className: "bg-yellow-50 border border-yellow-200 rounded-lg p-4 flex items-start gap-x-3", children: [
13348
+ /* @__PURE__ */ jsx171(AlertCircle, { className: "h-5 w-5 text-yellow-600 mt-0.5" }),
13349
+ /* @__PURE__ */ jsxs109("div", { className: "flex-1", children: [
13350
+ /* @__PURE__ */ jsx171("h3", { className: "font-semibold text-yellow-900", children: "Trial Ending Soon" }),
13351
+ /* @__PURE__ */ jsxs109("p", { className: "text-sm text-yellow-700 mt-1", children: [
13352
+ "Your trial ends in ",
13353
+ daysRemaining,
13354
+ " ",
13355
+ daysRemaining === 1 ? "day" : "days",
13356
+ ". Add a payment method to continue your subscription."
13357
+ ] })
13358
+ ] }),
13359
+ onAddPayment && /* @__PURE__ */ jsx171(Button, { variant: "outline", size: "sm", onClick: onAddPayment, className: "border-yellow-300 text-yellow-700", children: "Add Payment Method" })
13360
+ ] });
13361
+ }
13362
+ }
13363
+ return null;
13364
+ }
13365
+ __name(BillingAlertBanner, "BillingAlertBanner");
13366
+
13367
+ // src/features/billing/components/containers/BillingDashboardContainer.tsx
13368
+ import { Fragment as Fragment33, jsx as jsx172, jsxs as jsxs110 } from "react/jsx-runtime";
13369
+ function BillingDashboardContainer() {
13370
+ const [data, setData] = useState62({
13371
+ customer: null,
13372
+ subscriptions: [],
13373
+ paymentMethods: [],
13374
+ invoices: [],
13375
+ meters: [],
13376
+ meterSummaries: {}
13377
+ });
13378
+ const [loading, setLoading] = useState62({
13379
+ customer: true,
13380
+ subscriptions: true,
13381
+ paymentMethods: true,
13382
+ invoices: true,
13383
+ usage: true
13384
+ });
13385
+ const [errors, setErrors] = useState62({
13386
+ customer: null,
13387
+ subscriptions: null,
13388
+ paymentMethods: null,
13389
+ invoices: null,
13390
+ usage: null
13391
+ });
13392
+ const [activeModal, setActiveModal] = useState62(null);
13393
+ const [noCustomerExists, setNoCustomerExists] = useState62(false);
13394
+ const [creatingCustomer, setCreatingCustomer] = useState62(false);
13395
+ const hasMeteredSubscriptions = useCallback18(() => {
13396
+ return data.subscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
13397
+ }, [data.subscriptions]);
13398
+ const fetchAllData = useCallback18(async () => {
13399
+ setNoCustomerExists(false);
13400
+ let customer = null;
13401
+ try {
13402
+ customer = await StripeCustomerService.getCustomer();
13403
+ setData((prev) => ({ ...prev, customer }));
13404
+ setErrors((prev) => ({ ...prev, customer: null }));
13405
+ setNoCustomerExists(false);
13406
+ } catch (error) {
13407
+ console.error("[BillingDashboard] Failed to load customer:", error);
13408
+ const errorMessage = error instanceof Error ? error.message : String(error);
13409
+ if (errorMessage.includes("Not Found") || errorMessage.includes("not found")) {
13410
+ setNoCustomerExists(true);
13411
+ setLoading({
13412
+ customer: false,
13413
+ subscriptions: false,
13414
+ paymentMethods: false,
13415
+ invoices: false,
13416
+ usage: false
13417
+ });
13418
+ return;
13419
+ }
13420
+ setErrors((prev) => ({ ...prev, customer: "Failed to load billing account" }));
13421
+ } finally {
13422
+ setLoading((prev) => ({ ...prev, customer: false }));
13423
+ }
13424
+ if (customer) {
13425
+ const fetchSubscriptions = /* @__PURE__ */ __name(async () => {
13426
+ try {
13427
+ const subscriptions2 = await StripeSubscriptionService.listSubscriptions();
13428
+ setData((prev) => ({ ...prev, subscriptions: subscriptions2 }));
13429
+ setErrors((prev) => ({ ...prev, subscriptions: null }));
13430
+ return subscriptions2;
13431
+ } catch (error) {
13432
+ console.error("[BillingDashboard] Failed to load subscriptions:", error);
13433
+ setErrors((prev) => ({ ...prev, subscriptions: "Failed to load subscriptions" }));
13434
+ return [];
13435
+ } finally {
13436
+ setLoading((prev) => ({ ...prev, subscriptions: false }));
13437
+ }
13438
+ }, "fetchSubscriptions");
13439
+ const fetchPaymentMethods = /* @__PURE__ */ __name(async () => {
13440
+ try {
13441
+ const paymentMethods = await StripeCustomerService.listPaymentMethods();
13442
+ setData((prev) => ({ ...prev, paymentMethods }));
13443
+ setErrors((prev) => ({ ...prev, paymentMethods: null }));
13444
+ } catch (error) {
13445
+ console.error("[BillingDashboard] Failed to load payment methods:", error);
13446
+ setErrors((prev) => ({ ...prev, paymentMethods: "Failed to load payment methods" }));
13447
+ } finally {
13448
+ setLoading((prev) => ({ ...prev, paymentMethods: false }));
13449
+ }
13450
+ }, "fetchPaymentMethods");
13451
+ const fetchInvoices = /* @__PURE__ */ __name(async () => {
13452
+ try {
13453
+ const invoices = await StripeInvoiceService.listInvoices();
13454
+ setData((prev) => ({ ...prev, invoices }));
13455
+ setErrors((prev) => ({ ...prev, invoices: null }));
13456
+ } catch (error) {
13457
+ console.error("[BillingDashboard] Failed to load invoices:", error);
13458
+ setErrors((prev) => ({ ...prev, invoices: "Failed to load invoices" }));
13459
+ } finally {
13460
+ setLoading((prev) => ({ ...prev, invoices: false }));
13461
+ }
13462
+ }, "fetchInvoices");
13463
+ const [subscriptions] = await Promise.all([fetchSubscriptions(), fetchPaymentMethods(), fetchInvoices()]);
13464
+ const hasMetered = subscriptions.some(
13465
+ (sub) => sub.price?.recurring?.usageType === "metered"
13466
+ );
13467
+ if (hasMetered) {
13468
+ await fetchUsageData();
13469
+ } else {
13470
+ setLoading((prev) => ({ ...prev, usage: false }));
13471
+ }
13472
+ }
13473
+ }, []);
13474
+ const handleCreateCustomer = /* @__PURE__ */ __name(async () => {
13475
+ setCreatingCustomer(true);
13476
+ try {
13477
+ await StripeCustomerService.createCustomer();
13478
+ setNoCustomerExists(false);
13479
+ await fetchAllData();
13480
+ } catch (error) {
13481
+ console.error("[BillingDashboard] Failed to create customer:", error);
13482
+ setErrors((prev) => ({ ...prev, customer: "Failed to set up billing" }));
13483
+ } finally {
13484
+ setCreatingCustomer(false);
13485
+ }
13486
+ }, "handleCreateCustomer");
13487
+ const fetchUsageData = /* @__PURE__ */ __name(async () => {
13488
+ try {
13489
+ const meters = await StripeUsageService.listMeters();
13490
+ setData((prev) => ({ ...prev, meters }));
13491
+ const summariesMap = {};
13492
+ const now = /* @__PURE__ */ new Date();
13493
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
13494
+ const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
13495
+ for (const meter of meters) {
13496
+ try {
13497
+ const meterSummaries = await StripeUsageService.getMeterSummaries({
13498
+ meterId: meter.id,
13499
+ startTime: startOfMonth,
13500
+ endTime: endOfMonth
13501
+ });
13502
+ summariesMap[meter.id] = meterSummaries.length > 0 ? meterSummaries[0] : null;
13503
+ } catch (error) {
13504
+ console.error(`[BillingDashboard] Failed to load summaries for meter ${meter.id}:`, error);
13505
+ summariesMap[meter.id] = null;
13506
+ }
13507
+ }
13508
+ setData((prev) => ({ ...prev, meterSummaries: summariesMap }));
13509
+ setErrors((prev) => ({ ...prev, usage: null }));
13510
+ } catch (error) {
13511
+ console.error("[BillingDashboard] Failed to load usage data:", error);
13512
+ setErrors((prev) => ({ ...prev, usage: "Failed to load usage data" }));
13513
+ } finally {
13514
+ setLoading((prev) => ({ ...prev, usage: false }));
13515
+ }
13516
+ }, "fetchUsageData");
13517
+ const refreshData = useCallback18(async () => {
13518
+ setLoading({
13519
+ customer: true,
13520
+ subscriptions: true,
13521
+ paymentMethods: true,
13522
+ invoices: true,
13523
+ usage: true
13524
+ });
13525
+ await fetchAllData();
13526
+ }, [fetchAllData]);
13527
+ useEffect47(() => {
13528
+ fetchAllData();
13529
+ }, [fetchAllData]);
13530
+ const criticalSubscriptions = data.subscriptions.filter(
13531
+ (sub) => sub.status === "past_due" /* PAST_DUE */ || sub.status === "trialing" /* TRIALING */ && sub.trialEnd && new Date(sub.trialEnd).getTime() - (/* @__PURE__ */ new Date()).getTime() <= 7 * 24 * 60 * 60 * 1e3
13532
+ );
13533
+ const handleModalClose = /* @__PURE__ */ __name((open) => {
13534
+ if (!open) {
13535
+ setActiveModal(null);
13536
+ refreshData();
13537
+ }
13538
+ }, "handleModalClose");
13539
+ const getModalTitle = /* @__PURE__ */ __name((type) => {
13540
+ switch (type) {
13541
+ case "subscriptions":
13542
+ return "Manage Subscriptions";
13543
+ case "payment-methods":
13544
+ return "Payment Methods";
13545
+ case "invoices":
13546
+ return "Invoice History";
13547
+ case "usage":
13548
+ return "Usage Tracking";
13549
+ default:
13550
+ return "";
13551
+ }
13552
+ }, "getModalTitle");
13553
+ const isInitialLoading = loading.customer && !noCustomerExists && !data.customer;
13554
+ return /* @__PURE__ */ jsxs110("div", { className: "flex w-full flex-col gap-y-6", children: [
13555
+ /* @__PURE__ */ jsxs110("div", { className: "flex items-center gap-x-3", children: [
13556
+ /* @__PURE__ */ jsx172(Wallet2, { className: "h-8 w-8" }),
13557
+ /* @__PURE__ */ jsx172("h1", { className: "text-3xl font-bold", children: "Billing" })
13558
+ ] }),
13559
+ isInitialLoading && /* @__PURE__ */ jsx172(Card, { children: /* @__PURE__ */ jsx172(CardContent, { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx172(Loader24, { className: "h-8 w-8 animate-spin text-muted-foreground" }) }) }),
13560
+ noCustomerExists && !isInitialLoading && /* @__PURE__ */ jsxs110(Card, { children: [
13561
+ /* @__PURE__ */ jsxs110(CardHeader, { className: "text-center", children: [
13562
+ /* @__PURE__ */ jsx172("div", { className: "mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx172(CreditCard4, { className: "h-8 w-8 text-primary" }) }),
13563
+ /* @__PURE__ */ jsx172(CardTitle, { children: "Set Up Billing" }),
13564
+ /* @__PURE__ */ jsx172(CardDescription, { children: "Your company doesn't have a billing account yet. Set one up to manage subscriptions, payment methods, and view invoices." })
13565
+ ] }),
13566
+ /* @__PURE__ */ jsx172(CardContent, { className: "flex justify-center pb-8", children: /* @__PURE__ */ jsx172(Button, { onClick: handleCreateCustomer, disabled: creatingCustomer, size: "lg", children: creatingCustomer ? /* @__PURE__ */ jsxs110(Fragment33, { children: [
13567
+ /* @__PURE__ */ jsx172(Loader24, { className: "mr-2 h-4 w-4 animate-spin" }),
13568
+ "Setting up..."
13569
+ ] }) : "Set Up Billing Account" }) }),
13570
+ errors.customer && /* @__PURE__ */ jsx172(CardContent, { className: "pt-0", children: /* @__PURE__ */ jsx172("p", { className: "text-center text-sm text-destructive", children: errors.customer }) })
13571
+ ] }),
13572
+ !noCustomerExists && !isInitialLoading && /* @__PURE__ */ jsxs110(Fragment33, { children: [
13573
+ criticalSubscriptions.map((subscription) => /* @__PURE__ */ jsx172(
13574
+ BillingAlertBanner,
13575
+ {
13576
+ subscription,
13577
+ onUpdatePayment: () => setActiveModal("payment-methods"),
13578
+ onAddPayment: () => setActiveModal("payment-methods")
13579
+ },
13580
+ subscription.id
13581
+ )),
13582
+ /* @__PURE__ */ jsxs110("div", { className: "grid gap-4 md:grid-cols-2", children: [
13583
+ /* @__PURE__ */ jsx172(
13584
+ SubscriptionSummaryCard,
13585
+ {
13586
+ subscriptions: data.subscriptions,
13587
+ loading: loading.subscriptions,
13588
+ error: errors.subscriptions || void 0,
13589
+ onManageClick: () => setActiveModal("subscriptions")
13590
+ }
13591
+ ),
13592
+ /* @__PURE__ */ jsx172(
13593
+ PaymentMethodSummaryCard,
13594
+ {
13595
+ paymentMethods: data.paymentMethods,
13596
+ defaultPaymentMethodId: data.customer?.defaultPaymentMethodId,
13597
+ loading: loading.paymentMethods,
13598
+ error: errors.paymentMethods || void 0,
13599
+ onManageClick: () => setActiveModal("payment-methods")
13600
+ }
13601
+ ),
13602
+ /* @__PURE__ */ jsx172(
13603
+ CustomerInfoCard,
13604
+ {
13605
+ customer: data.customer,
13606
+ loading: loading.customer,
13607
+ error: errors.customer || void 0
13608
+ }
13609
+ ),
13610
+ /* @__PURE__ */ jsx172(
13611
+ InvoicesSummaryCard,
13612
+ {
13613
+ invoices: data.invoices,
13614
+ loading: loading.invoices,
13615
+ error: errors.invoices || void 0,
13616
+ onViewAllClick: () => setActiveModal("invoices")
13617
+ }
13618
+ ),
13619
+ hasMeteredSubscriptions() && /* @__PURE__ */ jsx172(
13620
+ BillingUsageSummaryCard,
13621
+ {
13622
+ meters: data.meters,
13623
+ summaries: data.meterSummaries,
13624
+ loading: loading.usage,
13625
+ error: errors.usage || void 0,
13626
+ onViewDetailsClick: () => setActiveModal("usage")
13627
+ }
13628
+ )
13629
+ ] }),
13630
+ /* @__PURE__ */ jsx172(
13631
+ BillingDetailModal,
13632
+ {
13633
+ open: activeModal === "subscriptions",
13634
+ onOpenChange: handleModalClose,
13635
+ title: getModalTitle("subscriptions"),
13636
+ children: /* @__PURE__ */ jsx172(SubscriptionsContainer, {})
13637
+ }
13638
+ ),
13639
+ /* @__PURE__ */ jsx172(
13640
+ BillingDetailModal,
13641
+ {
13642
+ open: activeModal === "payment-methods",
13643
+ onOpenChange: handleModalClose,
13644
+ title: getModalTitle("payment-methods"),
13645
+ children: /* @__PURE__ */ jsx172(PaymentMethodsContainer, {})
13646
+ }
13647
+ ),
13648
+ /* @__PURE__ */ jsx172(
13649
+ BillingDetailModal,
13650
+ {
13651
+ open: activeModal === "invoices",
13652
+ onOpenChange: handleModalClose,
13653
+ title: getModalTitle("invoices"),
13654
+ children: /* @__PURE__ */ jsx172(InvoicesContainer, {})
13655
+ }
13656
+ ),
13657
+ /* @__PURE__ */ jsx172(
13658
+ BillingDetailModal,
13659
+ {
13660
+ open: activeModal === "usage",
13661
+ onOpenChange: handleModalClose,
13662
+ title: getModalTitle("usage"),
13663
+ children: /* @__PURE__ */ jsx172(UsageContainer, {})
13664
+ }
13665
+ )
13666
+ ] })
13667
+ ] });
13668
+ }
13669
+ __name(BillingDashboardContainer, "BillingDashboardContainer");
13670
+
13671
+ // src/features/billing/components/providers/StripeProvider.tsx
13672
+ import { Elements } from "@stripe/react-stripe-js";
13673
+ import { loadStripe } from "@stripe/stripe-js";
13674
+ import { useMemo as useMemo18 } from "react";
13675
+ import { Fragment as Fragment34, jsx as jsx173 } from "react/jsx-runtime";
13676
+ var stripePromiseCache = null;
13677
+ function getStripePromise(publishableKey) {
13678
+ if (!publishableKey) {
13679
+ return Promise.resolve(null);
13680
+ }
13681
+ if (stripePromiseCache?.key === publishableKey) {
13682
+ return stripePromiseCache.promise;
13683
+ }
13684
+ const promise = loadStripe(publishableKey);
13685
+ stripePromiseCache = { key: publishableKey, promise };
13686
+ return promise;
13687
+ }
13688
+ __name(getStripePromise, "getStripePromise");
13689
+ function StripeProvider({ children }) {
13690
+ const publishableKey = getStripePublishableKey();
13691
+ const stripePromise = useMemo18(() => getStripePromise(publishableKey), [publishableKey]);
13692
+ const options = useMemo18(() => ({}), []);
13693
+ if (!publishableKey) {
13694
+ return /* @__PURE__ */ jsx173(Fragment34, { children });
13695
+ }
13696
+ return /* @__PURE__ */ jsx173(Elements, { stripe: stripePromise, options, children });
13697
+ }
13698
+ __name(StripeProvider, "StripeProvider");
13699
+ function isStripeConfigured() {
13700
+ return !!getStripePublishableKey();
13701
+ }
13702
+ __name(isStripeConfigured, "isStripeConfigured");
13703
+
13704
+ // src/features/billing/stripe-price/components/forms/PriceEditor.tsx
13705
+ import { zodResolver as zodResolver11 } from "@hookform/resolvers/zod";
13706
+ import { AlertCircle as AlertCircle2, PlusIcon, XIcon as XIcon5 } from "lucide-react";
13707
+ import { useState as useState63 } from "react";
13708
+ import { useForm as useForm11 } from "react-hook-form";
13709
+ import { v4 as v47 } from "uuid";
13710
+ import { z as z11 } from "zod";
13711
+ import { jsx as jsx174, jsxs as jsxs111 } from "react/jsx-runtime";
13712
+ function PriceEditor({ productId, price, open, onOpenChange, onSuccess }) {
13713
+ const [isSubmitting, setIsSubmitting] = useState63(false);
13714
+ const formSchema2 = z11.object({
13715
+ unitAmount: z11.preprocess(
13716
+ (val) => typeof val === "string" ? parseFloat(val) : val,
13717
+ z11.number().min(0, { message: "Amount must be 0 or greater" })
13718
+ ),
13719
+ currency: z11.string().min(1, { message: "Currency is required" }),
13720
+ interval: z11.enum(["one_time", "day", "week", "month", "year"]),
13721
+ intervalCount: z11.preprocess(
13722
+ (val) => val === "" || val === void 0 ? void 0 : typeof val === "string" ? parseInt(val, 10) : val,
13723
+ z11.number().min(1).optional()
13724
+ ),
13725
+ usageType: z11.enum(["licensed", "metered"]).optional(),
13726
+ nickname: z11.string().optional(),
13727
+ active: z11.boolean(),
13728
+ description: z11.string().optional(),
13729
+ features: z11.array(z11.string())
13730
+ });
13731
+ const isEditMode = !!price;
13732
+ const defaultUnitAmount = price?.unitAmount ? price.unitAmount / 100 : 0;
13733
+ const form = useForm11({
13734
+ resolver: zodResolver11(formSchema2),
13735
+ defaultValues: {
13736
+ unitAmount: defaultUnitAmount,
13737
+ currency: price?.currency || "usd",
13738
+ interval: price?.priceType === "one_time" ? "one_time" : price?.recurring?.interval || "month",
13739
+ intervalCount: price?.recurring?.intervalCount || 1,
13740
+ usageType: price?.recurring?.usageType || "licensed",
13741
+ nickname: price?.nickname || "",
13742
+ active: price?.active ?? true,
13743
+ description: price?.description || "",
13744
+ features: price?.features || []
13745
+ }
13746
+ });
13747
+ const watchInterval = form.watch("interval");
13748
+ const isRecurring = watchInterval !== "one_time";
13749
+ const onSubmit = /* @__PURE__ */ __name(async (values) => {
13750
+ setIsSubmitting(true);
13751
+ try {
13752
+ const unitAmountInCents = Math.round(values.unitAmount * 100);
13753
+ if (isEditMode) {
13754
+ await StripePriceService.updatePrice({
13755
+ id: price.id,
13756
+ nickname: values.nickname || void 0,
13757
+ description: values.description || void 0,
13758
+ features: values.features.filter((f) => f.trim()) || void 0
13759
+ });
13760
+ } else {
13761
+ const createInput = {
13762
+ id: v47(),
13763
+ productId,
13764
+ currency: values.currency,
13765
+ unitAmount: unitAmountInCents
13766
+ };
13767
+ if (isRecurring) {
13768
+ createInput.recurring = {
13769
+ interval: values.interval,
13770
+ intervalCount: values.intervalCount || 1,
13771
+ usageType: values.usageType || "licensed"
13772
+ };
13773
+ }
13774
+ if (values.nickname) {
13775
+ createInput.nickname = values.nickname;
13776
+ }
13777
+ if (values.description) {
13778
+ createInput.description = values.description;
13779
+ }
13780
+ const filteredFeatures = values.features.filter((f) => f.trim());
13781
+ if (filteredFeatures.length > 0) {
13782
+ createInput.features = filteredFeatures;
13783
+ }
13784
+ await StripePriceService.createPrice(createInput);
13785
+ }
13786
+ onSuccess();
13787
+ onOpenChange(false);
13788
+ } catch (error) {
13789
+ console.error("[PriceEditor] Failed to save price:", error);
13790
+ } finally {
13791
+ setIsSubmitting(false);
13792
+ }
13793
+ }, "onSubmit");
13794
+ const currencyOptions = [
13795
+ { id: "usd", text: "USD ($)" },
13796
+ { id: "eur", text: "EUR (\u20AC)" },
13797
+ { id: "gbp", text: "GBP (\xA3)" }
13798
+ ];
13799
+ const intervalOptions = [
13800
+ { id: "one_time", text: "One-time" },
13801
+ { id: "day", text: "Daily" },
13802
+ { id: "week", text: "Weekly" },
13803
+ { id: "month", text: "Monthly" },
13804
+ { id: "year", text: "Yearly" }
13805
+ ];
13806
+ const usageTypeOptions = [
13807
+ { id: "licensed", text: "Licensed (per unit)" },
13808
+ { id: "metered", text: "Metered (usage-based)" }
13809
+ ];
13810
+ return /* @__PURE__ */ jsx174(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs111(DialogContent, { className: "max-w-2xl", children: [
13811
+ /* @__PURE__ */ jsxs111(DialogHeader, { children: [
13812
+ /* @__PURE__ */ jsx174(DialogTitle, { children: isEditMode ? "Edit Price" : "Create Price" }),
13813
+ /* @__PURE__ */ jsx174(DialogDescription, { children: isEditMode ? "Update the price details. Note: Only nickname and active status can be changed." : "Create a new price for this product" })
13814
+ ] }),
13815
+ isEditMode && /* @__PURE__ */ jsxs111("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4 flex gap-x-3", children: [
13816
+ /* @__PURE__ */ jsx174(AlertCircle2, { className: "h-5 w-5 text-blue-600 flex-shrink-0 mt-0.5" }),
13817
+ /* @__PURE__ */ jsxs111("div", { className: "text-sm text-blue-800", children: [
13818
+ /* @__PURE__ */ jsx174("p", { className: "font-semibold mb-1", children: "Stripe Price Immutability" }),
13819
+ /* @__PURE__ */ jsx174("p", { children: "Due to Stripe's architecture, only the nickname and active status can be modified after creation. To change amount, currency, or billing interval, create a new price." })
13820
+ ] })
13821
+ ] }),
13822
+ /* @__PURE__ */ jsx174(Form, { ...form, children: /* @__PURE__ */ jsxs111("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-col gap-y-4", children: [
13823
+ /* @__PURE__ */ jsxs111("div", { className: "grid grid-cols-2 gap-x-4", children: [
13824
+ /* @__PURE__ */ jsx174(
13825
+ FormInput,
13826
+ {
13827
+ form,
13828
+ id: "unitAmount",
13829
+ name: "Amount (in dollars)",
13830
+ placeholder: "9.99",
13831
+ disabled: isEditMode,
13832
+ isRequired: true
13833
+ }
13834
+ ),
13835
+ /* @__PURE__ */ jsx174(FormSelect, { form, id: "currency", name: "Currency", values: currencyOptions, disabled: isEditMode })
13836
+ ] }),
13837
+ /* @__PURE__ */ jsx174(
13838
+ FormSelect,
13839
+ {
13840
+ form,
13841
+ id: "interval",
13842
+ name: "Billing Interval",
13843
+ values: intervalOptions,
13844
+ disabled: isEditMode
13845
+ }
13846
+ ),
13847
+ isRecurring && /* @__PURE__ */ jsxs111("div", { className: "grid grid-cols-2 gap-x-4", children: [
13848
+ /* @__PURE__ */ jsx174(
13849
+ FormInput,
13850
+ {
13851
+ form,
13852
+ id: "intervalCount",
13853
+ name: "Interval Count",
13854
+ placeholder: "1",
13855
+ type: "number",
13856
+ disabled: isEditMode
13857
+ }
13858
+ ),
13859
+ /* @__PURE__ */ jsx174(
13860
+ FormSelect,
13861
+ {
13862
+ form,
13863
+ id: "usageType",
13864
+ name: "Usage Type",
13865
+ values: usageTypeOptions,
13866
+ disabled: isEditMode
13867
+ }
13868
+ )
13869
+ ] }),
13870
+ /* @__PURE__ */ jsx174(
13871
+ FormInput,
13872
+ {
13873
+ form,
13874
+ id: "nickname",
13875
+ name: "Nickname (optional)",
13876
+ placeholder: "e.g., Standard Plan, Pro Tier"
13877
+ }
13878
+ ),
13879
+ /* @__PURE__ */ jsx174(
13880
+ FormTextarea,
13881
+ {
13882
+ form,
13883
+ id: "description",
13884
+ name: "Description (optional)",
13885
+ placeholder: "Describe what this price tier includes...",
13886
+ className: "min-h-24"
13887
+ }
13888
+ ),
13889
+ /* @__PURE__ */ jsxs111(FormItem, { children: [
13890
+ /* @__PURE__ */ jsx174(FormLabel, { children: "Features (optional)" }),
13891
+ /* @__PURE__ */ jsxs111("div", { className: "space-y-2", children: [
13892
+ form.watch("features").map((_, index) => /* @__PURE__ */ jsxs111("div", { className: "flex gap-2", children: [
13893
+ /* @__PURE__ */ jsx174(FormControl, { children: /* @__PURE__ */ jsx174(
13894
+ Input,
13895
+ {
13896
+ ...form.register(`features.${index}`),
13897
+ placeholder: `Feature ${index + 1}`,
13898
+ className: "flex-1"
13899
+ }
13900
+ ) }),
13901
+ /* @__PURE__ */ jsx174(
13902
+ Button,
13903
+ {
13904
+ type: "button",
13905
+ variant: "outline",
13906
+ size: "icon",
13907
+ onClick: () => {
13908
+ const currentFeatures = form.getValues("features");
13909
+ form.setValue(
13910
+ "features",
13911
+ currentFeatures.filter((_2, i) => i !== index)
13912
+ );
13913
+ },
13914
+ children: /* @__PURE__ */ jsx174(XIcon5, { className: "h-4 w-4" })
13915
+ }
13916
+ )
13917
+ ] }, index)),
13918
+ /* @__PURE__ */ jsxs111(
13919
+ Button,
13920
+ {
13921
+ type: "button",
13922
+ variant: "outline",
13923
+ size: "sm",
13924
+ onClick: () => {
13925
+ const currentFeatures = form.getValues("features");
13926
+ form.setValue("features", [...currentFeatures, ""]);
13927
+ },
13928
+ className: "mt-2",
13929
+ children: [
13930
+ /* @__PURE__ */ jsx174(PlusIcon, { className: "h-4 w-4 mr-2" }),
13931
+ "Add Feature"
13932
+ ]
13933
+ }
13934
+ )
13935
+ ] })
13936
+ ] }),
13937
+ /* @__PURE__ */ jsx174(FormCheckbox, { form, id: "active", name: "Active" }),
13938
+ /* @__PURE__ */ jsx174(CommonEditorButtons, { isEdit: isEditMode, form, disabled: isSubmitting, setOpen: onOpenChange })
13939
+ ] }) })
13940
+ ] }) });
13941
+ }
13942
+ __name(PriceEditor, "PriceEditor");
13943
+
13944
+ // src/features/billing/stripe-price/components/lists/PricesList.tsx
13945
+ import { Archive, DollarSign, Edit, RotateCcw } from "lucide-react";
13946
+ import { useEffect as useEffect48, useState as useState64 } from "react";
13947
+ import { jsx as jsx175, jsxs as jsxs112 } from "react/jsx-runtime";
13948
+ function PricesList({ productId, onPricesChange }) {
13949
+ const [prices, setPrices] = useState64([]);
13950
+ const [loading, setLoading] = useState64(true);
13951
+ const [showCreatePrice, setShowCreatePrice] = useState64(false);
13952
+ const [editingPrice, setEditingPrice] = useState64(null);
13953
+ const [priceToArchive, setPriceToArchive] = useState64(null);
13954
+ const [priceToReactivate, setPriceToReactivate] = useState64(null);
13955
+ const [archivingPriceId, setArchivingPriceId] = useState64(null);
13956
+ const [reactivatingPriceId, setReactivatingPriceId] = useState64(null);
13957
+ const loadPrices = /* @__PURE__ */ __name(async () => {
13958
+ setLoading(true);
13959
+ try {
13960
+ const fetchedPrices = await StripePriceService.listPrices({ productId });
13961
+ setPrices(fetchedPrices);
13962
+ } catch (error) {
13963
+ console.error("[PricesList] Failed to load prices:", error);
13964
+ } finally {
13965
+ setLoading(false);
13966
+ }
13967
+ }, "loadPrices");
13968
+ useEffect48(() => {
13969
+ loadPrices();
13970
+ }, [productId]);
13971
+ const handleArchive = /* @__PURE__ */ __name(async () => {
13972
+ if (!priceToArchive) {
13973
+ return;
13974
+ }
13975
+ setArchivingPriceId(priceToArchive.id);
13976
+ try {
13977
+ await StripePriceService.archivePrice({ id: priceToArchive.id });
13978
+ setPriceToArchive(null);
13979
+ await loadPrices();
13980
+ onPricesChange();
13981
+ } catch (error) {
13982
+ console.error("[PricesList] Failed to archive price:", error);
13983
+ } finally {
13984
+ setArchivingPriceId(null);
13985
+ }
13986
+ }, "handleArchive");
13987
+ const handleReactivate = /* @__PURE__ */ __name(async () => {
13988
+ if (!priceToReactivate) {
13989
+ return;
13990
+ }
13991
+ setReactivatingPriceId(priceToReactivate.id);
13992
+ try {
13993
+ await StripePriceService.reactivatePrice({ id: priceToReactivate.id });
13994
+ setPriceToReactivate(null);
13995
+ await loadPrices();
13996
+ onPricesChange();
13997
+ } catch (error) {
13998
+ console.error("[PricesList] Failed to reactivate price:", error);
13999
+ } finally {
14000
+ setReactivatingPriceId(null);
14001
+ }
14002
+ }, "handleReactivate");
14003
+ const formatInterval2 = /* @__PURE__ */ __name((price) => {
14004
+ if (price.priceType === "one_time") {
14005
+ return "one-time";
14006
+ }
14007
+ if (price.recurring) {
14008
+ const count = price.recurring.intervalCount;
14009
+ const interval = price.recurring.interval;
14010
+ if (count === 1) {
14011
+ return `/ ${interval}`;
14012
+ } else {
14013
+ return `/ ${count} ${interval}s`;
14014
+ }
14015
+ }
14016
+ return "";
14017
+ }, "formatInterval");
14018
+ if (loading) {
14019
+ return /* @__PURE__ */ jsx175("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx175("p", { className: "text-muted-foreground", children: "Loading prices..." }) });
14020
+ }
14021
+ return /* @__PURE__ */ jsxs112("div", { className: "flex flex-col gap-y-4", children: [
14022
+ /* @__PURE__ */ jsxs112("div", { className: "flex items-center justify-between mb-4", children: [
14023
+ /* @__PURE__ */ jsx175("h4", { className: "text-lg font-semibold", children: "Prices" }),
14024
+ /* @__PURE__ */ jsx175(Button, { size: "sm", onClick: () => setShowCreatePrice(true), children: "Add Price" })
14025
+ ] }),
14026
+ prices.length === 0 && /* @__PURE__ */ jsxs112("div", { className: "bg-background flex flex-col items-center justify-center gap-y-3 rounded-lg border border-dashed p-8", children: [
14027
+ /* @__PURE__ */ jsx175(DollarSign, { className: "text-muted-foreground h-12 w-12" }),
14028
+ /* @__PURE__ */ jsx175("p", { className: "text-muted-foreground text-sm", children: "No prices yet. Add a price to enable subscriptions." }),
14029
+ /* @__PURE__ */ jsx175(Button, { size: "sm", onClick: () => setShowCreatePrice(true), children: "Add Price" })
14030
+ ] }),
14031
+ prices.length > 0 && /* @__PURE__ */ jsx175("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: prices.map((price) => {
14032
+ const isArchiving = archivingPriceId === price.id;
14033
+ const isReactivating = reactivatingPriceId === price.id;
14034
+ return /* @__PURE__ */ jsxs112("div", { className: "border rounded-lg bg-white p-4 hover:shadow-sm transition-shadow", children: [
14035
+ /* @__PURE__ */ jsxs112("div", { className: "flex items-start justify-between mb-3", children: [
14036
+ /* @__PURE__ */ jsx175(DollarSign, { className: "h-5 w-5 text-primary" }),
14037
+ /* @__PURE__ */ jsxs112("div", { className: "flex gap-1", children: [
14038
+ /* @__PURE__ */ jsx175(Button, { variant: "ghost", size: "sm", onClick: () => setEditingPrice(price), className: "h-8 w-8 p-0", children: /* @__PURE__ */ jsx175(Edit, { className: "h-4 w-4" }) }),
14039
+ price.active ? /* @__PURE__ */ jsx175(
14040
+ Button,
14041
+ {
14042
+ variant: "ghost",
14043
+ size: "sm",
14044
+ onClick: () => setPriceToArchive(price),
14045
+ className: "h-8 w-8 p-0",
14046
+ disabled: isArchiving,
14047
+ children: /* @__PURE__ */ jsx175(Archive, { className: "h-4 w-4" })
14048
+ }
14049
+ ) : /* @__PURE__ */ jsx175(
14050
+ Button,
14051
+ {
14052
+ variant: "ghost",
14053
+ size: "sm",
14054
+ onClick: () => setPriceToReactivate(price),
14055
+ className: "h-8 w-8 p-0",
14056
+ disabled: isReactivating,
14057
+ children: /* @__PURE__ */ jsx175(RotateCcw, { className: "h-4 w-4" })
14058
+ }
14059
+ )
14060
+ ] })
14061
+ ] }),
14062
+ /* @__PURE__ */ jsx175("div", { className: "mb-2", children: /* @__PURE__ */ jsxs112("div", { className: "text-2xl font-bold", children: [
14063
+ formatCurrency(price.unitAmount, price.currency),
14064
+ " ",
14065
+ /* @__PURE__ */ jsx175("span", { className: "text-muted-foreground text-sm font-normal", children: formatInterval2(price) })
14066
+ ] }) }),
14067
+ price.metadata?.nickname && /* @__PURE__ */ jsx175("p", { className: "text-sm font-medium mb-2", children: price.metadata.nickname }),
14068
+ /* @__PURE__ */ jsxs112("div", { className: "flex flex-wrap gap-2", children: [
14069
+ price.active ? /* @__PURE__ */ jsx175("span", { className: "bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full font-medium", children: "Active" }) : /* @__PURE__ */ jsx175("span", { className: "bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full font-medium", children: "Inactive" }),
14070
+ price.recurring?.usageType === "metered" && /* @__PURE__ */ jsx175("span", { className: "bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full font-medium", children: "Metered" }),
14071
+ /* @__PURE__ */ jsx175("span", { className: "bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full font-medium uppercase", children: price.currency })
14072
+ ] })
14073
+ ] }, price.id);
14074
+ }) }),
14075
+ showCreatePrice && /* @__PURE__ */ jsx175(
14076
+ PriceEditor,
14077
+ {
14078
+ productId,
14079
+ open: showCreatePrice,
14080
+ onOpenChange: setShowCreatePrice,
14081
+ onSuccess: () => {
14082
+ loadPrices();
14083
+ onPricesChange();
14084
+ }
14085
+ }
14086
+ ),
14087
+ editingPrice && /* @__PURE__ */ jsx175(
14088
+ PriceEditor,
14089
+ {
14090
+ productId,
14091
+ price: editingPrice,
14092
+ open: !!editingPrice,
14093
+ onOpenChange: (open) => !open && setEditingPrice(null),
14094
+ onSuccess: () => {
14095
+ loadPrices();
14096
+ onPricesChange();
14097
+ setEditingPrice(null);
14098
+ }
14099
+ }
14100
+ ),
14101
+ /* @__PURE__ */ jsx175(AlertDialog, { open: !!priceToArchive, onOpenChange: (open) => !open && setPriceToArchive(null), children: /* @__PURE__ */ jsxs112(AlertDialogContent, { children: [
14102
+ /* @__PURE__ */ jsxs112(AlertDialogHeader, { children: [
14103
+ /* @__PURE__ */ jsx175(AlertDialogTitle, { children: "Archive Price" }),
14104
+ /* @__PURE__ */ jsxs112(AlertDialogDescription, { children: [
14105
+ "Are you sure you want to archive the price for",
14106
+ " ",
14107
+ priceToArchive && `${formatCurrency(priceToArchive.unitAmount, priceToArchive.currency)} ${formatInterval2(priceToArchive)}`,
14108
+ "? This will prevent new subscriptions but existing ones will continue."
14109
+ ] })
14110
+ ] }),
14111
+ /* @__PURE__ */ jsxs112(AlertDialogFooter, { children: [
14112
+ /* @__PURE__ */ jsx175(AlertDialogCancel, { disabled: !!archivingPriceId, children: "Cancel" }),
14113
+ /* @__PURE__ */ jsx175(
14114
+ AlertDialogAction,
14115
+ {
14116
+ onClick: handleArchive,
14117
+ disabled: !!archivingPriceId,
14118
+ className: "bg-red-600 hover:bg-red-700",
14119
+ children: archivingPriceId ? "Archiving..." : "Archive"
14120
+ }
14121
+ )
14122
+ ] })
14123
+ ] }) }),
14124
+ /* @__PURE__ */ jsx175(AlertDialog, { open: !!priceToReactivate, onOpenChange: (open) => !open && setPriceToReactivate(null), children: /* @__PURE__ */ jsxs112(AlertDialogContent, { children: [
14125
+ /* @__PURE__ */ jsxs112(AlertDialogHeader, { children: [
14126
+ /* @__PURE__ */ jsx175(AlertDialogTitle, { children: "Reactivate Price" }),
14127
+ /* @__PURE__ */ jsxs112(AlertDialogDescription, { children: [
14128
+ "Are you sure you want to reactivate the price for",
14129
+ " ",
14130
+ priceToReactivate && `${formatCurrency(priceToReactivate.unitAmount, priceToReactivate.currency)} ${formatInterval2(priceToReactivate)}`,
14131
+ "? This will allow new subscriptions again."
14132
+ ] })
14133
+ ] }),
14134
+ /* @__PURE__ */ jsxs112(AlertDialogFooter, { children: [
14135
+ /* @__PURE__ */ jsx175(AlertDialogCancel, { disabled: !!reactivatingPriceId, children: "Cancel" }),
14136
+ /* @__PURE__ */ jsx175(
14137
+ AlertDialogAction,
14138
+ {
14139
+ onClick: handleReactivate,
14140
+ disabled: !!reactivatingPriceId,
14141
+ className: "bg-green-600 hover:bg-green-700",
14142
+ children: reactivatingPriceId ? "Reactivating..." : "Reactivate"
14143
+ }
14144
+ )
14145
+ ] })
14146
+ ] }) })
14147
+ ] });
14148
+ }
14149
+ __name(PricesList, "PricesList");
14150
+
14151
+ // src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx
14152
+ import { Package as Package2 } from "lucide-react";
14153
+ import { useEffect as useEffect49, useState as useState67 } from "react";
14154
+
14155
+ // src/features/billing/stripe-product/components/forms/ProductEditor.tsx
14156
+ import { zodResolver as zodResolver12 } from "@hookform/resolvers/zod";
14157
+ import { useState as useState65 } from "react";
14158
+ import { useForm as useForm12 } from "react-hook-form";
14159
+ import { v4 as v48 } from "uuid";
14160
+ import { z as z12 } from "zod";
14161
+ import { jsx as jsx176, jsxs as jsxs113 } from "react/jsx-runtime";
14162
+ function ProductEditor({ product, open, onOpenChange, onSuccess }) {
14163
+ const [isSubmitting, setIsSubmitting] = useState65(false);
14164
+ const formSchema2 = z12.object({
14165
+ name: z12.string().min(1, { message: "Product name is required" }),
14166
+ description: z12.string().optional(),
14167
+ active: z12.boolean()
14168
+ });
14169
+ const form = useForm12({
14170
+ resolver: zodResolver12(formSchema2),
14171
+ defaultValues: {
14172
+ name: product?.name || "",
14173
+ description: product?.description || "",
14174
+ active: product?.active ?? true
14175
+ }
14176
+ });
14177
+ const onSubmit = /* @__PURE__ */ __name(async (values) => {
14178
+ setIsSubmitting(true);
14179
+ try {
14180
+ if (product) {
14181
+ await StripeProductService.updateProduct({
14182
+ id: product.id,
14183
+ name: values.name,
14184
+ description: values.description,
14185
+ active: values.active
14186
+ });
14187
+ } else {
14188
+ await StripeProductService.createProduct({
14189
+ id: v48(),
14190
+ name: values.name,
14191
+ description: values.description,
14192
+ active: values.active
14193
+ });
14194
+ }
14195
+ onSuccess();
14196
+ onOpenChange(false);
14197
+ } catch (error) {
14198
+ console.error("[ProductEditor] Failed to save product:", error);
14199
+ } finally {
14200
+ setIsSubmitting(false);
14201
+ }
14202
+ }, "onSubmit");
14203
+ return /* @__PURE__ */ jsx176(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs113(DialogContent, { className: "max-w-2xl", children: [
14204
+ /* @__PURE__ */ jsxs113(DialogHeader, { children: [
14205
+ /* @__PURE__ */ jsx176(DialogTitle, { children: product ? "Edit Product" : "Create Product" }),
14206
+ /* @__PURE__ */ jsx176(DialogDescription, { children: product ? `Update the details for ${product.name}` : "Create a new product to offer to your customers" })
14207
+ ] }),
14208
+ /* @__PURE__ */ jsx176(Form, { ...form, children: /* @__PURE__ */ jsxs113("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-col gap-y-4", children: [
14209
+ /* @__PURE__ */ jsx176(FormInput, { form, id: "name", name: "Product Name", placeholder: "Enter product name", isRequired: true }),
14210
+ /* @__PURE__ */ jsx176(
14211
+ FormTextarea,
14212
+ {
14213
+ form,
14214
+ id: "description",
14215
+ name: "Description",
14216
+ placeholder: "Enter product description (optional)",
14217
+ className: "min-h-32"
14218
+ }
14219
+ ),
14220
+ /* @__PURE__ */ jsx176(FormCheckbox, { form, id: "active", name: "Active" }),
14221
+ /* @__PURE__ */ jsx176(CommonEditorButtons, { isEdit: !!product, form, disabled: isSubmitting, setOpen: onOpenChange })
14222
+ ] }) })
14223
+ ] }) });
14224
+ }
14225
+ __name(ProductEditor, "ProductEditor");
14226
+
14227
+ // src/features/billing/stripe-product/components/lists/ProductsList.tsx
14228
+ import { Archive as Archive2, ChevronDown as ChevronDown3, ChevronUp as ChevronUp2, Edit as Edit2, Package, RefreshCw as RefreshCw3 } from "lucide-react";
14229
+ import { useState as useState66 } from "react";
14230
+ import { jsx as jsx177, jsxs as jsxs114 } from "react/jsx-runtime";
14231
+ function ProductsList({ products, onProductsChange }) {
14232
+ const [expandedProductId, setExpandedProductId] = useState66(null);
14233
+ const [editingProduct, setEditingProduct] = useState66(null);
14234
+ const [archivingProductId, setArchivingProductId] = useState66(null);
14235
+ const [reactivatingProductId, setReactivatingProductId] = useState66(null);
14236
+ const [productToArchive, setProductToArchive] = useState66(null);
14237
+ const [productToReactivate, setProductToReactivate] = useState66(null);
14238
+ const handleArchive = /* @__PURE__ */ __name(async () => {
14239
+ if (!productToArchive) {
14240
+ return;
14241
+ }
14242
+ setArchivingProductId(productToArchive.id);
14243
+ try {
14244
+ const archivedProduct = await StripeProductService.archiveProduct({ id: productToArchive.id });
14245
+ setProductToArchive(null);
14246
+ onProductsChange();
14247
+ } catch (error) {
14248
+ console.error("[ProductsList] Failed to archive product:", error);
14249
+ } finally {
14250
+ setArchivingProductId(null);
14251
+ }
14252
+ }, "handleArchive");
14253
+ const handleReactivate = /* @__PURE__ */ __name(async () => {
14254
+ if (!productToReactivate) {
14255
+ return;
14256
+ }
14257
+ setReactivatingProductId(productToReactivate.id);
14258
+ try {
14259
+ const reactivatedProduct = await StripeProductService.reactivateProduct({ id: productToReactivate.id });
14260
+ setProductToReactivate(null);
14261
+ onProductsChange();
14262
+ } catch (error) {
14263
+ } finally {
14264
+ setReactivatingProductId(null);
14265
+ }
14266
+ }, "handleReactivate");
14267
+ const toggleExpand = /* @__PURE__ */ __name((productId) => {
14268
+ setExpandedProductId(expandedProductId === productId ? null : productId);
14269
+ }, "toggleExpand");
14270
+ return /* @__PURE__ */ jsxs114("div", { className: "flex flex-col gap-y-4", children: [
14271
+ products.map((product) => {
14272
+ const isExpanded = expandedProductId === product.id;
14273
+ const isArchiving = archivingProductId === product.id;
14274
+ const isReactivating = reactivatingProductId === product.id;
14275
+ return /* @__PURE__ */ jsxs114("div", { className: "border rounded-lg bg-white shadow-sm hover:shadow-md transition-shadow", children: [
14276
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center justify-between p-6", children: [
14277
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-x-4 flex-1", children: [
14278
+ /* @__PURE__ */ jsx177(Package, { className: "h-6 w-6 text-primary" }),
14279
+ /* @__PURE__ */ jsxs114("div", { className: "flex-1", children: [
14280
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-x-3", children: [
14281
+ /* @__PURE__ */ jsx177("h3", { className: "text-lg font-semibold", children: product.name }),
14282
+ product.active ? /* @__PURE__ */ jsx177("span", { className: "bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full font-medium", children: "Active" }) : /* @__PURE__ */ jsx177("span", { className: "bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full font-medium", children: "Inactive" })
14283
+ ] }),
14284
+ product.description && /* @__PURE__ */ jsx177("p", { className: "text-muted-foreground text-sm mt-1", children: product.description })
14285
+ ] })
14286
+ ] }),
14287
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-x-2", children: [
14288
+ /* @__PURE__ */ jsxs114(Button, { variant: "outline", size: "sm", onClick: () => setEditingProduct(product), children: [
14289
+ /* @__PURE__ */ jsx177(Edit2, { className: "h-4 w-4 mr-1" }),
14290
+ "Edit"
14291
+ ] }),
14292
+ product.active ? /* @__PURE__ */ jsxs114(
14293
+ Button,
14294
+ {
14295
+ variant: "outline",
14296
+ size: "sm",
14297
+ onClick: () => setProductToArchive(product),
14298
+ disabled: isArchiving,
14299
+ children: [
14300
+ /* @__PURE__ */ jsx177(Archive2, { className: "h-4 w-4 mr-1" }),
14301
+ isArchiving ? "Archiving..." : "Archive"
14302
+ ]
14303
+ }
14304
+ ) : /* @__PURE__ */ jsxs114(
14305
+ Button,
14306
+ {
14307
+ variant: "outline",
14308
+ size: "sm",
14309
+ onClick: () => setProductToReactivate(product),
14310
+ disabled: isReactivating,
14311
+ children: [
14312
+ /* @__PURE__ */ jsx177(RefreshCw3, { className: "h-4 w-4 mr-1" }),
14313
+ isReactivating ? "Reactivating..." : "Reactivate"
14314
+ ]
14315
+ }
14316
+ ),
14317
+ /* @__PURE__ */ jsx177(Button, { variant: "ghost", size: "sm", onClick: () => toggleExpand(product.id), children: isExpanded ? /* @__PURE__ */ jsx177(ChevronUp2, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx177(ChevronDown3, { className: "h-5 w-5" }) })
14318
+ ] })
14319
+ ] }),
14320
+ isExpanded && /* @__PURE__ */ jsx177("div", { className: "border-t bg-muted/30 p-6", children: /* @__PURE__ */ jsx177(PricesList, { productId: product.id, onPricesChange: onProductsChange }) })
14321
+ ] }, product.id);
14322
+ }),
14323
+ editingProduct && /* @__PURE__ */ jsx177(
14324
+ ProductEditor,
14325
+ {
14326
+ product: editingProduct,
14327
+ open: !!editingProduct,
14328
+ onOpenChange: (open) => !open && setEditingProduct(null),
14329
+ onSuccess: () => {
14330
+ onProductsChange();
14331
+ setEditingProduct(null);
14332
+ }
14333
+ }
14334
+ ),
14335
+ /* @__PURE__ */ jsx177(AlertDialog, { open: !!productToArchive, onOpenChange: (open) => !open && setProductToArchive(null), children: /* @__PURE__ */ jsxs114(AlertDialogContent, { children: [
14336
+ /* @__PURE__ */ jsxs114(AlertDialogHeader, { children: [
14337
+ /* @__PURE__ */ jsx177(AlertDialogTitle, { children: "Archive Product" }),
14338
+ /* @__PURE__ */ jsxs114(AlertDialogDescription, { children: [
14339
+ 'Are you sure you want to archive "',
14340
+ productToArchive?.name,
14341
+ '"? This will deactivate it and it will no longer be available for new subscriptions.'
14342
+ ] })
14343
+ ] }),
14344
+ /* @__PURE__ */ jsxs114(AlertDialogFooter, { children: [
14345
+ /* @__PURE__ */ jsx177(AlertDialogCancel, { disabled: !!archivingProductId, children: "Cancel" }),
14346
+ /* @__PURE__ */ jsx177(
14347
+ AlertDialogAction,
14348
+ {
14349
+ onClick: handleArchive,
14350
+ disabled: !!archivingProductId,
14351
+ className: "bg-red-600 hover:bg-red-700",
14352
+ children: archivingProductId ? "Archiving..." : "Archive"
14353
+ }
14354
+ )
14355
+ ] })
14356
+ ] }) }),
14357
+ /* @__PURE__ */ jsx177(AlertDialog, { open: !!productToReactivate, onOpenChange: (open) => !open && setProductToReactivate(null), children: /* @__PURE__ */ jsxs114(AlertDialogContent, { children: [
14358
+ /* @__PURE__ */ jsxs114(AlertDialogHeader, { children: [
14359
+ /* @__PURE__ */ jsx177(AlertDialogTitle, { children: "Reactivate Product" }),
14360
+ /* @__PURE__ */ jsxs114(AlertDialogDescription, { children: [
14361
+ 'Are you sure you want to reactivate "',
14362
+ productToReactivate?.name,
14363
+ '"? This will make it available for new subscriptions again.'
14364
+ ] })
14365
+ ] }),
14366
+ /* @__PURE__ */ jsxs114(AlertDialogFooter, { children: [
14367
+ /* @__PURE__ */ jsx177(AlertDialogCancel, { disabled: !!reactivatingProductId, children: "Cancel" }),
14368
+ /* @__PURE__ */ jsx177(
14369
+ AlertDialogAction,
14370
+ {
14371
+ onClick: handleReactivate,
14372
+ disabled: !!reactivatingProductId,
14373
+ className: "bg-green-600 hover:bg-green-700",
14374
+ children: reactivatingProductId ? "Reactivating..." : "Reactivate"
14375
+ }
14376
+ )
14377
+ ] })
14378
+ ] }) })
14379
+ ] });
14380
+ }
14381
+ __name(ProductsList, "ProductsList");
14382
+
14383
+ // src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx
14384
+ import { jsx as jsx178, jsxs as jsxs115 } from "react/jsx-runtime";
14385
+ function ProductsAdminContainer() {
14386
+ const { hasRole } = useCurrentUserContext();
14387
+ const [products, setProducts] = useState67([]);
14388
+ const [loading, setLoading] = useState67(true);
14389
+ const [showCreateProduct, setShowCreateProduct] = useState67(false);
14390
+ if (!hasRole(getRoleId().Administrator)) {
14391
+ return /* @__PURE__ */ jsx178("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx178("p", { className: "text-red-600 font-semibold", children: "Permission denied. Administrator access required." }) });
14392
+ }
14393
+ const loadProducts = /* @__PURE__ */ __name(async () => {
14394
+ setLoading(true);
14395
+ try {
14396
+ const fetchedProducts = await StripeProductService.listProducts();
14397
+ setProducts(fetchedProducts);
14398
+ } catch (error) {
14399
+ console.error("[ProductsAdminContainer] Failed to load products:", error);
14400
+ } finally {
14401
+ setLoading(false);
14402
+ }
14403
+ }, "loadProducts");
14404
+ useEffect49(() => {
14405
+ loadProducts();
14406
+ }, []);
14407
+ if (loading) {
14408
+ return /* @__PURE__ */ jsx178("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx178("p", { className: "text-muted-foreground", children: "Loading products..." }) });
14409
+ }
14410
+ return /* @__PURE__ */ jsxs115("div", { className: "flex w-full flex-col gap-y-6", children: [
14411
+ /* @__PURE__ */ jsxs115("div", { className: "flex items-center justify-between", children: [
14412
+ /* @__PURE__ */ jsxs115("div", { className: "flex items-center gap-x-3", children: [
14413
+ /* @__PURE__ */ jsx178(Package2, { className: "h-8 w-8" }),
14414
+ /* @__PURE__ */ jsx178("h1", { className: "text-3xl font-bold", children: "Product & Price Management" })
14415
+ ] }),
14416
+ /* @__PURE__ */ jsx178(Button, { onClick: () => setShowCreateProduct(true), children: "Create Product" })
14417
+ ] }),
14418
+ products.length === 0 && /* @__PURE__ */ jsxs115("div", { className: "bg-muted/50 flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed p-12", children: [
14419
+ /* @__PURE__ */ jsx178(Package2, { className: "text-muted-foreground h-16 w-16" }),
14420
+ /* @__PURE__ */ jsxs115("div", { className: "text-center", children: [
14421
+ /* @__PURE__ */ jsx178("h3", { className: "mb-2 text-xl font-semibold", children: "No products yet" }),
14422
+ /* @__PURE__ */ jsx178("p", { className: "text-muted-foreground mb-4", children: "Create your first product to start offering subscriptions to your customers." }),
14423
+ /* @__PURE__ */ jsx178(Button, { onClick: () => setShowCreateProduct(true), children: "Create Your First Product" })
14424
+ ] })
14425
+ ] }),
14426
+ products.length > 0 && /* @__PURE__ */ jsx178(ProductsList, { products, onProductsChange: loadProducts }),
14427
+ showCreateProduct && /* @__PURE__ */ jsx178(ProductEditor, { open: showCreateProduct, onOpenChange: setShowCreateProduct, onSuccess: loadProducts })
14428
+ ] });
14429
+ }
14430
+ __name(ProductsAdminContainer, "ProductsAdminContainer");
14431
+
14432
+ // src/features/content/components/lists/ContentsList.tsx
14433
+ import { useTranslations as useTranslations53 } from "next-intl";
14434
+ import { jsx as jsx179, jsxs as jsxs116 } from "react/jsx-runtime";
14435
+ function ContentsList({ contentList }) {
14436
+ const t = useTranslations53();
14437
+ return /* @__PURE__ */ jsxs116("div", { className: "flex min-h-0 w-full flex-col overflow-y-auto", children: [
14438
+ /* @__PURE__ */ jsx179("h2", { className: "text-xl font-semibold", children: t(`foundations.content.news`) }),
14439
+ /* @__PURE__ */ jsx179("div", { className: "flex flex-col", children: contentList.map((content) => /* @__PURE__ */ jsx179(ContentsListElement, { content }, content.id)) })
14440
+ ] });
14441
+ }
14442
+ __name(ContentsList, "ContentsList");
14443
+ function ContentsListElement({ content }) {
14444
+ const generateUrl = usePageUrlGenerator();
14445
+ const contentModule = content.contentType ? Modules.findByModelName(content.contentType) : void 0;
14446
+ const link = contentModule ? generateUrl({ page: contentModule, id: content.id }) : "#";
14447
+ return /* @__PURE__ */ jsx179("div", { className: "hover:bg-muted flex w-full flex-col gap-y-2 border-b p-2 py-4", children: /* @__PURE__ */ jsxs116("div", { className: "flex w-full justify-between gap-x-2", children: [
14448
+ /* @__PURE__ */ jsxs116(HoverCard, { children: [
14449
+ /* @__PURE__ */ jsx179(HoverCardTrigger, { asChild: true, children: /* @__PURE__ */ jsxs116(Link2, { href: link, className: "flex w-full items-center justify-start gap-2 font-semibold", children: [
14450
+ contentModule && getIconByModule({ module: contentModule, className: "h-4 w-4" }),
14451
+ content.name
14452
+ ] }) }),
14453
+ /* @__PURE__ */ jsxs116(HoverCardContent, { className: "flex max-h-96 w-96 flex-col gap-y-4 overflow-y-auto", children: [
14454
+ /* @__PURE__ */ jsx179(Link2, { href: link, className: "font-semibold", children: content.name }),
14455
+ /* @__PURE__ */ jsx179("div", { className: "text-xs", children: content.abstract })
14456
+ ] })
14457
+ ] }),
14458
+ /* @__PURE__ */ jsx179(ContributorsList, { content })
14459
+ ] }) });
14460
+ }
14461
+ __name(ContentsListElement, "ContentsListElement");
14462
+
14463
+ // src/features/content/components/lists/ContentsListById.tsx
14464
+ import { useTranslations as useTranslations54 } from "next-intl";
14465
+ import { jsx as jsx180 } from "react/jsx-runtime";
14466
+ function ContentsListById({ contentIds }) {
14467
+ const t = useTranslations54();
14468
+ const data = useDataListRetriever({
14469
+ module: Modules.Content,
14470
+ retriever: /* @__PURE__ */ __name((params) => ContentService.findMany(params), "retriever"),
14471
+ retrieverParams: { contentIds }
14472
+ });
14473
+ return /* @__PURE__ */ jsx180(
14474
+ ContentListTable,
14475
+ {
14476
+ data,
14477
+ fields: ["name" /* name */, "authors" /* authors */, "updatedAt" /* updatedAt */],
14478
+ tableGeneratorType: Modules.Content,
14479
+ title: t(`generic.relevant`)
14480
+ }
14481
+ );
14482
+ }
14483
+ __name(ContentsListById, "ContentsListById");
14484
+
14485
+ // src/features/content/components/lists/RelevantContentsList.tsx
14486
+ import { useTranslations as useTranslations55 } from "next-intl";
14487
+ import { jsx as jsx181 } from "react/jsx-runtime";
14488
+ function RelevantContentsList({ id }) {
14489
+ const t = useTranslations55();
14490
+ const data = useDataListRetriever({
14491
+ module: Modules.Content,
14492
+ retriever: /* @__PURE__ */ __name((params) => ContentService.findRelevant(params), "retriever"),
14493
+ retrieverParams: { id }
14494
+ });
14495
+ return /* @__PURE__ */ jsx181(
14496
+ ContentListTable,
14497
+ {
14498
+ data,
14499
+ fields: ["name" /* name */, "authors" /* authors */, "relevance" /* relevance */, "updatedAt" /* updatedAt */],
14500
+ tableGeneratorType: Modules.Content,
14501
+ title: t(`generic.relevant`)
14502
+ }
14503
+ );
14504
+ }
14505
+ __name(RelevantContentsList, "RelevantContentsList");
14506
+
14507
+ // src/features/notification/components/common/NotificationErrorBoundary.tsx
14508
+ import { Component } from "react";
14509
+ import { jsx as jsx182, jsxs as jsxs117 } from "react/jsx-runtime";
14510
+ var NotificationErrorBoundary = class extends Component {
14511
+ static {
14512
+ __name(this, "NotificationErrorBoundary");
14513
+ }
14514
+ constructor(props) {
14515
+ super(props);
14516
+ this.state = { hasError: false };
14517
+ }
14518
+ static getDerivedStateFromError(error) {
14519
+ return { hasError: true, error };
14520
+ }
14521
+ componentDidCatch(error, errorInfo) {
14522
+ console.error("\u{1F6A8} [NotificationErrorBoundary] Caught error:", error, errorInfo);
14523
+ }
14524
+ render() {
14525
+ if (this.state.hasError) {
14526
+ return this.props.fallback || /* @__PURE__ */ jsx182("div", { className: "flex items-center justify-center p-4 text-center", children: /* @__PURE__ */ jsxs117("div", { className: "text-muted-foreground text-sm", children: [
14527
+ /* @__PURE__ */ jsx182("p", { children: "Something went wrong with notifications." }),
14528
+ /* @__PURE__ */ jsx182(
14529
+ "button",
14530
+ {
14531
+ onClick: () => this.setState({ hasError: false }),
14532
+ className: "text-primary mt-2 underline hover:no-underline",
14533
+ children: "Try again"
14534
+ }
14535
+ )
14536
+ ] }) });
14537
+ }
14538
+ return this.props.children;
14539
+ }
14540
+ };
14541
+
14542
+ // src/features/notification/components/containers/NotificationsListContainer.tsx
14543
+ import { useTranslations as useTranslations57 } from "next-intl";
14544
+
14545
+ // src/features/notification/components/lists/NotificationsList.tsx
14546
+ import { ArchiveIcon } from "lucide-react";
14547
+ import { useTranslations as useTranslations56 } from "next-intl";
14548
+ import { Fragment as Fragment35, jsx as jsx183, jsxs as jsxs118 } from "react/jsx-runtime";
14549
+ function NotificationsList({ archived }) {
14550
+ const t = useTranslations56();
14551
+ const generateUrl = usePageUrlGenerator();
14552
+ const data = useDataListRetriever({
14553
+ retriever: /* @__PURE__ */ __name((params) => NotificationService.findMany(params), "retriever"),
14554
+ retrieverParams: { isArchived: archived },
14555
+ module: Modules.Notification
14556
+ });
14557
+ const archiveNotification = /* @__PURE__ */ __name(async (notification) => {
14558
+ await NotificationService.archive({ id: notification.id });
14559
+ data.removeElement(notification);
14560
+ }, "archiveNotification");
14561
+ const LoadingSkeleton = /* @__PURE__ */ __name(() => /* @__PURE__ */ jsx183("div", { className: "space-y-4", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx183(Card, { children: /* @__PURE__ */ jsx183(CardContent, { className: "p-2", children: /* @__PURE__ */ jsxs118("div", { className: "flex w-full flex-row items-center", children: [
14562
+ /* @__PURE__ */ jsx183(Skeleton, { className: "mr-4 h-8 w-8 rounded-full" }),
14563
+ /* @__PURE__ */ jsxs118("div", { className: "flex-1 space-y-2", children: [
14564
+ /* @__PURE__ */ jsx183(Skeleton, { className: "h-4 w-3/4" }),
14565
+ /* @__PURE__ */ jsx183(Skeleton, { className: "h-3 w-1/2" })
14566
+ ] }),
14567
+ /* @__PURE__ */ jsx183(Skeleton, { className: "h-8 w-20" })
14568
+ ] }) }) }, i)) }), "LoadingSkeleton");
14569
+ return /* @__PURE__ */ jsx183("div", { className: "space-y-4", children: data.isLoaded ? data.data?.map((notification) => {
14570
+ const notificationData = generateNotificationData({ notification, generateUrl });
14571
+ return /* @__PURE__ */ jsx183(Card, { children: /* @__PURE__ */ jsx183(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxs118("div", { className: `flex w-full flex-row items-center p-2`, children: [
14572
+ notificationData.actor ? /* @__PURE__ */ jsx183("div", { className: "flex w-12 max-w-12 px-2", children: /* @__PURE__ */ jsx183(Link2, { href: generateUrl({ page: Modules.User, id: notificationData.actor.id }), children: /* @__PURE__ */ jsx183(UserAvatar, { user: notificationData.actor, className: "h-8 w-8" }) }) }) : /* @__PURE__ */ jsx183("div", { className: "flex w-14 max-w-14 px-2" }),
14573
+ /* @__PURE__ */ jsxs118("div", { className: "flex w-full flex-col", children: [
14574
+ /* @__PURE__ */ jsx183("p", { className: "text-sm", children: t.rich(`foundations.notification.${notification.notificationType}.description`, {
14575
+ strong: /* @__PURE__ */ __name((chunks) => /* @__PURE__ */ jsx183("strong", { children: chunks }), "strong"),
14576
+ actor: notificationData.actor?.name ?? "",
14577
+ title: notificationData.title
14578
+ }) }),
14579
+ /* @__PURE__ */ jsx183("div", { className: "text-muted-foreground mt-1 w-full text-xs", children: new Date(notification.createdAt).toLocaleString() })
14580
+ ] }),
14581
+ /* @__PURE__ */ jsxs118("div", { className: "flex flex-row items-center", children: [
14582
+ notificationData.url ? /* @__PURE__ */ jsx183(Link2, { href: notificationData.url, children: /* @__PURE__ */ jsx183(Button, { variant: `outline`, size: `sm`, onClick: (e) => e.stopPropagation(), children: t(`foundations.notification.${notification.notificationType}.buttons.action`) }) }) : /* @__PURE__ */ jsx183(Fragment35, {}),
14583
+ !archived && /* @__PURE__ */ jsxs118(Tooltip2, { children: [
14584
+ /* @__PURE__ */ jsx183(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx183(
14585
+ Button,
14586
+ {
14587
+ variant: `link`,
14588
+ onClick: (e) => {
14589
+ e.preventDefault();
14590
+ e.stopPropagation();
14591
+ archiveNotification(notification);
14592
+ },
14593
+ className: "text-muted-foreground hover:text-destructive ml-2",
14594
+ children: /* @__PURE__ */ jsx183(ArchiveIcon, { className: "h-4 w-4 cursor-pointer" })
14595
+ }
14596
+ ) }),
14597
+ /* @__PURE__ */ jsx183(TooltipContent, { children: t(`foundations.notification.buttons.archive`) })
14598
+ ] })
14599
+ ] })
14600
+ ] }) }) }, notification.id);
14601
+ }) : /* @__PURE__ */ jsx183(LoadingSkeleton, {}) });
14602
+ }
14603
+ __name(NotificationsList, "NotificationsList");
14604
+
14605
+ // src/features/notification/components/containers/NotificationsListContainer.tsx
14606
+ import { jsx as jsx184, jsxs as jsxs119 } from "react/jsx-runtime";
14607
+ function NotificationsListContainerContent() {
14608
+ const t = useTranslations57();
14609
+ const { notifications, isLoading, error } = useNotificationContext();
14610
+ if (error) {
14611
+ return /* @__PURE__ */ jsx184("div", { className: "flex items-center justify-center p-8 text-center", children: /* @__PURE__ */ jsxs119("div", { className: "text-destructive text-sm", children: [
14612
+ /* @__PURE__ */ jsxs119("p", { children: [
14613
+ "Error loading notifications: ",
14614
+ error
14615
+ ] }),
14616
+ /* @__PURE__ */ jsx184("p", { className: "text-muted-foreground mt-2", children: "Please try refreshing the page." })
14617
+ ] }) });
14618
+ }
14619
+ const tabs = [
14620
+ {
14621
+ label: t(`foundations.notification.inbox`),
14622
+ content: /* @__PURE__ */ jsx184(NotificationsList, { archived: false })
14623
+ },
14624
+ {
14625
+ label: t(`foundations.notification.archived`),
14626
+ content: /* @__PURE__ */ jsx184(NotificationsList, { archived: true })
11352
14627
  }
11353
14628
  ];
11354
- return /* @__PURE__ */ jsx149(TabsContainer, { tabs });
14629
+ return /* @__PURE__ */ jsx184(TabsContainer, { tabs });
11355
14630
  }
11356
14631
  __name(NotificationsListContainerContent, "NotificationsListContainerContent");
11357
14632
  function NotificationsListContainer() {
11358
- return /* @__PURE__ */ jsx149(NotificationErrorBoundary, { children: /* @__PURE__ */ jsx149(NotificationsListContainerContent, {}) });
14633
+ return /* @__PURE__ */ jsx184(NotificationErrorBoundary, { children: /* @__PURE__ */ jsx184(NotificationsListContainerContent, {}) });
11359
14634
  }
11360
14635
  __name(NotificationsListContainer, "NotificationsListContainer");
11361
14636
 
11362
14637
  // src/features/notification/components/modals/NotificationModal.tsx
11363
14638
  import { BellIcon } from "lucide-react";
11364
14639
  import { useTranslations as useTranslations58 } from "next-intl";
11365
- import { Fragment as Fragment29, useCallback as useCallback17, useEffect as useEffect40, useMemo as useMemo18, useRef as useRef16, useState as useState49 } from "react";
14640
+ import { Fragment as Fragment36, useCallback as useCallback19, useEffect as useEffect50, useMemo as useMemo19, useRef as useRef16, useState as useState68 } from "react";
11366
14641
  import { toast as toast10 } from "sonner";
11367
- import { jsx as jsx150, jsxs as jsxs90 } from "react/jsx-runtime";
14642
+ import { jsx as jsx185, jsxs as jsxs120 } from "react/jsx-runtime";
11368
14643
  function NotificationModalContent({ isOpen, setIsOpen }) {
11369
14644
  const instanceId = useRef16(Math.random().toString(36).substr(2, 9));
11370
14645
  const {
@@ -11382,14 +14657,14 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
11382
14657
  const { socketNotifications, removeSocketNotification, clearSocketNotifications } = useSocketContext();
11383
14658
  const t = useTranslations58();
11384
14659
  const generateUrl = usePageUrlGenerator();
11385
- const [newNotifications, setNewNotifications] = useState49(false);
14660
+ const [newNotifications, setNewNotifications] = useState68(false);
11386
14661
  const preventAutoClose = useRef16(false);
11387
14662
  const circuitBreakerRef = useRef16({
11388
14663
  count: 0,
11389
14664
  resetTime: 0,
11390
14665
  isOpen: false
11391
14666
  });
11392
- const checkCircuitBreaker = useCallback17(() => {
14667
+ const checkCircuitBreaker = useCallback19(() => {
11393
14668
  const now = Date.now();
11394
14669
  const breaker = circuitBreakerRef.current;
11395
14670
  if (now > breaker.resetTime) {
@@ -11404,21 +14679,21 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
11404
14679
  }
11405
14680
  return !breaker.isOpen;
11406
14681
  }, []);
11407
- const { unreadCount, unreadIds } = useMemo18(() => {
14682
+ const { unreadCount, unreadIds } = useMemo19(() => {
11408
14683
  const unreadNotifications2 = notifications.filter((notif) => !notif.isRead);
11409
14684
  return {
11410
14685
  unreadCount: unreadNotifications2.length,
11411
14686
  unreadIds: unreadNotifications2.map((notif) => notif.id)
11412
14687
  };
11413
14688
  }, [notifications]);
11414
- useEffect40(() => {
14689
+ useEffect50(() => {
11415
14690
  setNewNotifications(unreadCount > 0);
11416
14691
  }, [unreadCount]);
11417
- useEffect40(() => {
14692
+ useEffect50(() => {
11418
14693
  if (lastLoaded === 0) loadNotifications();
11419
14694
  }, [lastLoaded, loadNotifications]);
11420
14695
  const processSocketNotificationsRef = useRef16(null);
11421
- const processSocketNotifications = useCallback17(() => {
14696
+ const processSocketNotifications = useCallback19(() => {
11422
14697
  if (socketNotifications.length === 0) {
11423
14698
  return;
11424
14699
  }
@@ -11457,7 +14732,7 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
11457
14732
  generateUrl,
11458
14733
  checkCircuitBreaker
11459
14734
  ]);
11460
- useEffect40(() => {
14735
+ useEffect50(() => {
11461
14736
  if (processSocketNotificationsRef.current) {
11462
14737
  clearTimeout(processSocketNotificationsRef.current);
11463
14738
  }
@@ -11494,9 +14769,9 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
11494
14769
  }
11495
14770
  }, "handleOpenChange");
11496
14771
  const unreadNotifications = newNotifications && unreadCount > 0;
11497
- return /* @__PURE__ */ jsxs90(Popover, { open: isOpen, onOpenChange: handleOpenChange, "data-testid": `sidebar-notification button`, children: [
11498
- /* @__PURE__ */ jsx150(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs90(SidebarMenuButton, { className: "text-muted-foreground h-6", disabled: isLoading, children: [
11499
- /* @__PURE__ */ jsx150(
14772
+ return /* @__PURE__ */ jsxs120(Popover, { open: isOpen, onOpenChange: handleOpenChange, "data-testid": `sidebar-notification button`, children: [
14773
+ /* @__PURE__ */ jsx185(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs120(SidebarMenuButton, { className: "text-muted-foreground h-6", disabled: isLoading, children: [
14774
+ /* @__PURE__ */ jsx185(
11500
14775
  BellIcon,
11501
14776
  {
11502
14777
  className: `h-5 w-5 cursor-pointer ${unreadNotifications ? "text-destructive" : ""} ${isLoading ? "animate-pulse" : ""}`
@@ -11504,75 +14779,75 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
11504
14779
  ),
11505
14780
  t(`types.notifications`, { count: 2 })
11506
14781
  ] }) }),
11507
- /* @__PURE__ */ jsx150(PopoverContent, { className: "relative left-10 w-80 border-0 p-0 shadow-none", children: /* @__PURE__ */ jsxs90(Card, { children: [
11508
- /* @__PURE__ */ jsxs90(CardHeader, { className: "p-4", children: [
11509
- /* @__PURE__ */ jsx150(CardTitle, { children: t(`types.notifications`, { count: 2 }) }),
11510
- isLoading && /* @__PURE__ */ jsx150("div", { className: "text-muted-foreground text-xs", children: "Loading..." }),
11511
- error && /* @__PURE__ */ jsxs90("div", { className: "text-destructive text-xs", children: [
14782
+ /* @__PURE__ */ jsx185(PopoverContent, { className: "relative left-10 w-80 border-0 p-0 shadow-none", children: /* @__PURE__ */ jsxs120(Card, { children: [
14783
+ /* @__PURE__ */ jsxs120(CardHeader, { className: "p-4", children: [
14784
+ /* @__PURE__ */ jsx185(CardTitle, { children: t(`types.notifications`, { count: 2 }) }),
14785
+ isLoading && /* @__PURE__ */ jsx185("div", { className: "text-muted-foreground text-xs", children: "Loading..." }),
14786
+ error && /* @__PURE__ */ jsxs120("div", { className: "text-destructive text-xs", children: [
11512
14787
  "Error: ",
11513
14788
  error
11514
14789
  ] })
11515
14790
  ] }),
11516
- /* @__PURE__ */ jsx150(Separator4, {}),
11517
- /* @__PURE__ */ jsx150(ScrollArea, { className: "h-96", children: notifications.length > 0 ? notifications.map((notification) => /* @__PURE__ */ jsx150(Fragment29, { children: generateNotification(notification, () => setIsOpen(false)) }, notification.id)) : /* @__PURE__ */ jsx150("div", { className: "p-4 text-center text-sm text-gray-500", children: t(`foundations.notification.empty`, { count: 2 }) }) })
14791
+ /* @__PURE__ */ jsx185(Separator4, {}),
14792
+ /* @__PURE__ */ jsx185(ScrollArea, { className: "h-96", children: notifications.length > 0 ? notifications.map((notification) => /* @__PURE__ */ jsx185(Fragment36, { children: generateNotification(notification, () => setIsOpen(false)) }, notification.id)) : /* @__PURE__ */ jsx185("div", { className: "p-4 text-center text-sm text-gray-500", children: t(`foundations.notification.empty`, { count: 2 }) }) })
11518
14793
  ] }) })
11519
14794
  ] });
11520
14795
  }
11521
14796
  __name(NotificationModalContent, "NotificationModalContent");
11522
14797
  function NotificationModal(props) {
11523
- return /* @__PURE__ */ jsx150(NotificationErrorBoundary, { children: /* @__PURE__ */ jsx150(NotificationModalContent, { ...props }) });
14798
+ return /* @__PURE__ */ jsx185(NotificationErrorBoundary, { children: /* @__PURE__ */ jsx185(NotificationModalContent, { ...props }) });
11524
14799
  }
11525
14800
  __name(NotificationModal, "NotificationModal");
11526
14801
 
11527
14802
  // src/features/notification/components/notifications/PushNotificationProvider.tsx
11528
- import { Fragment as Fragment30, jsx as jsx151 } from "react/jsx-runtime";
14803
+ import { Fragment as Fragment37, jsx as jsx186 } from "react/jsx-runtime";
11529
14804
  function PushNotificationProvider({ children }) {
11530
14805
  usePushNotifications();
11531
- return /* @__PURE__ */ jsx151(Fragment30, { children });
14806
+ return /* @__PURE__ */ jsx186(Fragment37, { children });
11532
14807
  }
11533
14808
  __name(PushNotificationProvider, "PushNotificationProvider");
11534
14809
 
11535
14810
  // src/features/role/components/details/RoleDetails.tsx
11536
14811
  import { useTranslations as useTranslations59 } from "next-intl";
11537
- import { jsx as jsx152 } from "react/jsx-runtime";
14812
+ import { jsx as jsx187 } from "react/jsx-runtime";
11538
14813
  function RoleDetails() {
11539
14814
  const { role } = useRoleContext();
11540
14815
  const t = useTranslations59();
11541
14816
  if (!role) return null;
11542
- return /* @__PURE__ */ jsx152(Card, { className: "w-full", children: /* @__PURE__ */ jsx152(CardContent, { className: "p-4", children: /* @__PURE__ */ jsx152(AttributeElement, { title: t(`foundations.role.fields.description.label`), value: role.description }) }) });
14817
+ return /* @__PURE__ */ jsx187(Card, { className: "w-full", children: /* @__PURE__ */ jsx187(CardContent, { className: "p-4", children: /* @__PURE__ */ jsx187(AttributeElement, { title: t(`foundations.role.fields.description.label`), value: role.description }) }) });
11543
14818
  }
11544
14819
  __name(RoleDetails, "RoleDetails");
11545
14820
 
11546
14821
  // src/features/role/components/containers/RoleContainer.tsx
11547
- import { Fragment as Fragment31, jsx as jsx153, jsxs as jsxs91 } from "react/jsx-runtime";
14822
+ import { Fragment as Fragment38, jsx as jsx188, jsxs as jsxs121 } from "react/jsx-runtime";
11548
14823
  function RoleContainer() {
11549
14824
  const { role } = useRoleContext();
11550
14825
  if (!role) return null;
11551
- return /* @__PURE__ */ jsxs91(Fragment31, { children: [
11552
- /* @__PURE__ */ jsx153(RoleDetails, {}),
11553
- /* @__PURE__ */ jsx153(RoleUsersList, { role })
14826
+ return /* @__PURE__ */ jsxs121(Fragment38, { children: [
14827
+ /* @__PURE__ */ jsx188(RoleDetails, {}),
14828
+ /* @__PURE__ */ jsx188(RoleUsersList, { role })
11554
14829
  ] });
11555
14830
  }
11556
14831
  __name(RoleContainer, "RoleContainer");
11557
14832
 
11558
14833
  // src/features/role/components/forms/FormRoles.tsx
11559
14834
  import { useTranslations as useTranslations60 } from "next-intl";
11560
- import { jsx as jsx154, jsxs as jsxs92 } from "react/jsx-runtime";
14835
+ import { jsx as jsx189, jsxs as jsxs122 } from "react/jsx-runtime";
11561
14836
  function FormRoles({ form, id, name, roles }) {
11562
14837
  const t = useTranslations60();
11563
14838
  const { hasAccesToFeature } = useCurrentUserContext();
11564
- return /* @__PURE__ */ jsx154("div", { className: "flex w-full flex-col", children: /* @__PURE__ */ jsx154(
14839
+ return /* @__PURE__ */ jsx189("div", { className: "flex w-full flex-col", children: /* @__PURE__ */ jsx189(
11565
14840
  FormField,
11566
14841
  {
11567
14842
  control: form.control,
11568
14843
  name: id,
11569
- render: ({ field }) => /* @__PURE__ */ jsxs92(FormItem, { className: `${name ? "mb-5" : "mb-1"}`, children: [
11570
- /* @__PURE__ */ jsx154(FormControl, { children: /* @__PURE__ */ jsxs92("div", { children: [
11571
- /* @__PURE__ */ jsx154("div", { className: "text-sm font-semibold", children: name }),
14844
+ render: ({ field }) => /* @__PURE__ */ jsxs122(FormItem, { className: `${name ? "mb-5" : "mb-1"}`, children: [
14845
+ /* @__PURE__ */ jsx189(FormControl, { children: /* @__PURE__ */ jsxs122("div", { children: [
14846
+ /* @__PURE__ */ jsx189("div", { className: "text-sm font-semibold", children: name }),
11572
14847
  roles.filter((role) => role.isSelectable).sort((a, b) => a.name.localeCompare(b.name)).map((role) => {
11573
14848
  if (role.requiredFeature && !hasAccesToFeature(role.requiredFeature.id)) return null;
11574
- return /* @__PURE__ */ jsxs92("div", { children: [
11575
- /* @__PURE__ */ jsx154(
14849
+ return /* @__PURE__ */ jsxs122("div", { children: [
14850
+ /* @__PURE__ */ jsx189(
11576
14851
  Checkbox,
11577
14852
  {
11578
14853
  defaultChecked: field.value.some((roleId) => roleId === role.id),
@@ -11588,14 +14863,14 @@ function FormRoles({ form, id, name, roles }) {
11588
14863
  }
11589
14864
  }
11590
14865
  ),
11591
- /* @__PURE__ */ jsxs92(Tooltip2, { children: [
11592
- /* @__PURE__ */ jsx154(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx154(FormLabel, { className: "ml-3 font-normal", children: t(`foundations.role.roles`, { role: role.id.replaceAll(`-`, ``) }) }) }),
11593
- /* @__PURE__ */ jsx154(TooltipContent, { children: t(`foundations.role.roles_descriptions`, { role: role.id.replaceAll(`-`, ``) }) })
14866
+ /* @__PURE__ */ jsxs122(Tooltip2, { children: [
14867
+ /* @__PURE__ */ jsx189(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx189(FormLabel, { className: "ml-3 font-normal", children: t(`foundations.role.roles`, { role: role.id.replaceAll(`-`, ``) }) }) }),
14868
+ /* @__PURE__ */ jsx189(TooltipContent, { children: t(`foundations.role.roles_descriptions`, { role: role.id.replaceAll(`-`, ``) }) })
11594
14869
  ] })
11595
14870
  ] }, role.id);
11596
14871
  })
11597
14872
  ] }) }),
11598
- /* @__PURE__ */ jsx154(FormMessage, {})
14873
+ /* @__PURE__ */ jsx189(FormMessage, {})
11599
14874
  ] })
11600
14875
  }
11601
14876
  ) });
@@ -11604,13 +14879,13 @@ __name(FormRoles, "FormRoles");
11604
14879
 
11605
14880
  // src/features/role/components/forms/RemoveUserFromRole.tsx
11606
14881
  import { useTranslations as useTranslations61 } from "next-intl";
11607
- import { useEffect as useEffect41, useState as useState50 } from "react";
11608
- import { Fragment as Fragment32, jsx as jsx155, jsxs as jsxs93 } from "react/jsx-runtime";
14882
+ import { useEffect as useEffect51, useState as useState69 } from "react";
14883
+ import { Fragment as Fragment39, jsx as jsx190, jsxs as jsxs123 } from "react/jsx-runtime";
11609
14884
  function RemoveUserFromRole({ role, user, refresh }) {
11610
- const [open, setOpen] = useState50(false);
11611
- const [canRemove, setCanRemove] = useState50(false);
14885
+ const [open, setOpen] = useState69(false);
14886
+ const [canRemove, setCanRemove] = useState69(false);
11612
14887
  const t = useTranslations61();
11613
- useEffect41(() => {
14888
+ useEffect51(() => {
11614
14889
  async function checkCompanyAdminDeletability() {
11615
14890
  const roleUsers = await UserService.findAllUsersByRole({
11616
14891
  roleId: role.id
@@ -11637,8 +14912,8 @@ function RemoveUserFromRole({ role, user, refresh }) {
11637
14912
  }
11638
14913
  }, "remove");
11639
14914
  const roleName = t(`foundations.role.roles`, { role: role.id.replaceAll(`-`, ``) });
11640
- return /* @__PURE__ */ jsxs93(Dialog, { open, onOpenChange: setOpen, children: [
11641
- /* @__PURE__ */ jsx155(
14915
+ return /* @__PURE__ */ jsxs123(Dialog, { open, onOpenChange: setOpen, children: [
14916
+ /* @__PURE__ */ jsx190(
11642
14917
  DialogTrigger,
11643
14918
  {
11644
14919
  onClick: (e) => {
@@ -11646,19 +14921,19 @@ function RemoveUserFromRole({ role, user, refresh }) {
11646
14921
  e.preventDefault();
11647
14922
  setOpen(true);
11648
14923
  },
11649
- children: /* @__PURE__ */ jsx155("span", { className: "hover:text-destructive cursor-pointer", children: t(`foundations.role.remove_user.title`) })
14924
+ children: /* @__PURE__ */ jsx190("span", { className: "hover:text-destructive cursor-pointer", children: t(`foundations.role.remove_user.title`) })
11650
14925
  }
11651
14926
  ),
11652
- /* @__PURE__ */ jsxs93(DialogContent, { className: `flex max-h-[70vh] max-w-3xl flex-col overflow-y-auto`, children: [
11653
- /* @__PURE__ */ jsxs93(DialogHeader, { children: [
11654
- /* @__PURE__ */ jsx155(DialogTitle, { children: t(`foundations.role.remove_user.title`) }),
11655
- /* @__PURE__ */ jsx155(DialogDescription, { children: canRemove ? t(`foundations.role.remove_user.subtitle_allowed`) : t(`foundations.role.remove_user.subtitle_not_allowed`) })
14927
+ /* @__PURE__ */ jsxs123(DialogContent, { className: `flex max-h-[70vh] max-w-3xl flex-col overflow-y-auto`, children: [
14928
+ /* @__PURE__ */ jsxs123(DialogHeader, { children: [
14929
+ /* @__PURE__ */ jsx190(DialogTitle, { children: t(`foundations.role.remove_user.title`) }),
14930
+ /* @__PURE__ */ jsx190(DialogDescription, { children: canRemove ? t(`foundations.role.remove_user.subtitle_allowed`) : t(`foundations.role.remove_user.subtitle_not_allowed`) })
11656
14931
  ] }),
11657
- canRemove ? /* @__PURE__ */ jsxs93(Fragment32, { children: [
14932
+ canRemove ? /* @__PURE__ */ jsxs123(Fragment39, { children: [
11658
14933
  t(`foundations.role.remove_user.description_allowed`, { role: roleName, user: user.name }),
11659
- /* @__PURE__ */ jsxs93("div", { className: "flex justify-end", children: [
11660
- /* @__PURE__ */ jsx155(Button, { className: "mr-2", variant: "outline", type: `button`, onClick: () => setOpen(false), children: t(`generic.buttons.cancel`) }),
11661
- /* @__PURE__ */ jsx155(
14934
+ /* @__PURE__ */ jsxs123("div", { className: "flex justify-end", children: [
14935
+ /* @__PURE__ */ jsx190(Button, { className: "mr-2", variant: "outline", type: `button`, onClick: () => setOpen(false), children: t(`generic.buttons.cancel`) }),
14936
+ /* @__PURE__ */ jsx190(
11662
14937
  Button,
11663
14938
  {
11664
14939
  type: "submit",
@@ -11671,7 +14946,7 @@ function RemoveUserFromRole({ role, user, refresh }) {
11671
14946
  }
11672
14947
  )
11673
14948
  ] })
11674
- ] }) : /* @__PURE__ */ jsx155(Fragment32, { children: t(`foundations.role.remove_user.description_not_allowed`, { role: roleName, user: user.name }) })
14949
+ ] }) : /* @__PURE__ */ jsx190(Fragment39, { children: t(`foundations.role.remove_user.description_not_allowed`, { role: roleName, user: user.name }) })
11675
14950
  ] })
11676
14951
  ] });
11677
14952
  }
@@ -11680,14 +14955,14 @@ __name(RemoveUserFromRole, "RemoveUserFromRole");
11680
14955
  // src/features/role/components/forms/UserRoleAdd.tsx
11681
14956
  import { PlusCircle } from "lucide-react";
11682
14957
  import { useTranslations as useTranslations62 } from "next-intl";
11683
- import { useCallback as useCallback18, useEffect as useEffect42, useRef as useRef17, useState as useState51 } from "react";
14958
+ import { useCallback as useCallback20, useEffect as useEffect52, useRef as useRef17, useState as useState70 } from "react";
11684
14959
  import { toast as toast11 } from "sonner";
11685
- import { Fragment as Fragment33, jsx as jsx156, jsxs as jsxs94 } from "react/jsx-runtime";
14960
+ import { Fragment as Fragment40, jsx as jsx191, jsxs as jsxs124 } from "react/jsx-runtime";
11686
14961
  function UserRoleAdd({ user, refresh }) {
11687
- const [open, setOpen] = useState51(false);
14962
+ const [open, setOpen] = useState70(false);
11688
14963
  const inputRef = useRef17(null);
11689
- const [searchTerm, setSearchTerm] = useState51("");
11690
- const [roles, setRoles] = useState51([]);
14964
+ const [searchTerm, setSearchTerm] = useState70("");
14965
+ const [roles, setRoles] = useState70([]);
11691
14966
  const t = useTranslations62();
11692
14967
  const addUserToRole = /* @__PURE__ */ __name(async (role) => {
11693
14968
  await RoleService.addUserToRole({
@@ -11711,7 +14986,7 @@ function UserRoleAdd({ user, refresh }) {
11711
14986
  );
11712
14987
  refresh();
11713
14988
  }, "addUserToRole");
11714
- const searchRoles = useCallback18(
14989
+ const searchRoles = useCallback20(
11715
14990
  async (term) => {
11716
14991
  setRoles(
11717
14992
  await RoleService.findAllRolesUserNotIn({
@@ -11723,32 +14998,32 @@ function UserRoleAdd({ user, refresh }) {
11723
14998
  [searchTerm, user]
11724
14999
  );
11725
15000
  const updateSearchTerm = useDebounce(searchRoles, 500);
11726
- useEffect42(() => {
15001
+ useEffect52(() => {
11727
15002
  if (open) updateSearchTerm(searchTerm);
11728
15003
  }, [open, searchTerm]);
11729
- useEffect42(() => {
15004
+ useEffect52(() => {
11730
15005
  if (open) searchRoles("");
11731
15006
  }, [open]);
11732
- return /* @__PURE__ */ jsxs94(Fragment33, { children: [
11733
- /* @__PURE__ */ jsxs94(Button, { size: "sm", onClick: () => setOpen(true), children: [
11734
- /* @__PURE__ */ jsx156(PlusCircle, { className: "mr-3 h-3.5 w-3.5" }),
15007
+ return /* @__PURE__ */ jsxs124(Fragment40, { children: [
15008
+ /* @__PURE__ */ jsxs124(Button, { size: "sm", onClick: () => setOpen(true), children: [
15009
+ /* @__PURE__ */ jsx191(PlusCircle, { className: "mr-3 h-3.5 w-3.5" }),
11735
15010
  t(`generic.association.label`, {
11736
15011
  source: t(`types.roles`, { count: 1 }),
11737
15012
  destination: t(`types.users`, { count: 1 })
11738
15013
  })
11739
15014
  ] }),
11740
- /* @__PURE__ */ jsxs94(CommandDialog, { open, onOpenChange: setOpen, children: [
11741
- /* @__PURE__ */ jsx156(DialogTitle, { children: t(`generic.association.label`, {
15015
+ /* @__PURE__ */ jsxs124(CommandDialog, { open, onOpenChange: setOpen, children: [
15016
+ /* @__PURE__ */ jsx191(DialogTitle, { children: t(`generic.association.label`, {
11742
15017
  source: t(`types.roles`, { count: 1 }),
11743
15018
  destination: t(`types.users`, { count: 1 })
11744
15019
  }) }),
11745
- /* @__PURE__ */ jsx156(DialogDescription, { children: t(`generic.association.description`, {
15020
+ /* @__PURE__ */ jsx191(DialogDescription, { children: t(`generic.association.description`, {
11746
15021
  source: t(`types.roles`, { count: 1 }),
11747
15022
  destination: t(`types.users`, { count: 1 }),
11748
15023
  destination_name: user.name
11749
15024
  }) }),
11750
- /* @__PURE__ */ jsxs94(Command, { shouldFilter: false, children: [
11751
- /* @__PURE__ */ jsx156(
15025
+ /* @__PURE__ */ jsxs124(Command, { shouldFilter: false, children: [
15026
+ /* @__PURE__ */ jsx191(
11752
15027
  CommandInput,
11753
15028
  {
11754
15029
  placeholder: t(`generic.search.placeholder`, { type: t(`types.roles`, { count: 1 }) }),
@@ -11757,9 +15032,9 @@ function UserRoleAdd({ user, refresh }) {
11757
15032
  ref: inputRef
11758
15033
  }
11759
15034
  ),
11760
- /* @__PURE__ */ jsxs94(CommandList, { className: "mt-3 h-auto max-h-96 min-h-96 max-w-full overflow-x-hidden overflow-y-auto", children: [
11761
- /* @__PURE__ */ jsx156(CommandEmpty, { children: t(`generic.search.no_results`, { type: t(`types.roles`, { count: 1 }) }) }),
11762
- roles.map((role) => /* @__PURE__ */ jsx156(
15035
+ /* @__PURE__ */ jsxs124(CommandList, { className: "mt-3 h-auto max-h-96 min-h-96 max-w-full overflow-x-hidden overflow-y-auto", children: [
15036
+ /* @__PURE__ */ jsx191(CommandEmpty, { children: t(`generic.search.no_results`, { type: t(`types.roles`, { count: 1 }) }) }),
15037
+ roles.map((role) => /* @__PURE__ */ jsx191(
11763
15038
  CommandItem,
11764
15039
  {
11765
15040
  className: "cursor-pointer",
@@ -11778,7 +15053,7 @@ __name(UserRoleAdd, "UserRoleAdd");
11778
15053
 
11779
15054
  // src/features/role/components/lists/RolesList.tsx
11780
15055
  import { useTranslations as useTranslations63 } from "next-intl";
11781
- import { jsx as jsx157 } from "react/jsx-runtime";
15056
+ import { jsx as jsx192 } from "react/jsx-runtime";
11782
15057
  function RolesList() {
11783
15058
  const t = useTranslations63();
11784
15059
  const data = useDataListRetriever({
@@ -11786,7 +15061,7 @@ function RolesList() {
11786
15061
  retrieverParams: {},
11787
15062
  module: Modules.Role
11788
15063
  });
11789
- return /* @__PURE__ */ jsx157(
15064
+ return /* @__PURE__ */ jsx192(
11790
15065
  ContentListTable,
11791
15066
  {
11792
15067
  data,
@@ -11800,7 +15075,7 @@ __name(RolesList, "RolesList");
11800
15075
 
11801
15076
  // src/features/role/components/lists/UserRolesList.tsx
11802
15077
  import { useTranslations as useTranslations64 } from "next-intl";
11803
- import { jsx as jsx158 } from "react/jsx-runtime";
15078
+ import { jsx as jsx193 } from "react/jsx-runtime";
11804
15079
  function UserRolesList({ user }) {
11805
15080
  const t = useTranslations64();
11806
15081
  const data = useDataListRetriever({
@@ -11808,7 +15083,7 @@ function UserRolesList({ user }) {
11808
15083
  retrieverParams: { userId: user.id },
11809
15084
  module: Modules.Role
11810
15085
  });
11811
- return /* @__PURE__ */ jsx158(
15086
+ return /* @__PURE__ */ jsx193(
11812
15087
  ContentListTable,
11813
15088
  {
11814
15089
  data,
@@ -11821,9 +15096,6 @@ function UserRolesList({ user }) {
11821
15096
  __name(UserRolesList, "UserRolesList");
11822
15097
 
11823
15098
  export {
11824
- JsonApiContext,
11825
- useJsonApiConfig,
11826
- useJsonApiConfigOptional,
11827
15099
  JsonApiProvider,
11828
15100
  useJsonApiGet,
11829
15101
  useJsonApiMutation,
@@ -12146,6 +15418,45 @@ export {
12146
15418
  Logout,
12147
15419
  RefreshUser,
12148
15420
  ResetPassword,
15421
+ SubscriptionSummaryCard,
15422
+ PaymentMethodSummaryCard,
15423
+ CustomerInfoCard,
15424
+ InvoicesSummaryCard,
15425
+ BillingUsageSummaryCard,
15426
+ PaymentMethodEditor,
15427
+ PaymentMethodCard,
15428
+ PaymentMethodsList,
15429
+ PaymentMethodsContainer,
15430
+ formatInterval,
15431
+ formatCurrency,
15432
+ formatDate3 as formatDate,
15433
+ InvoiceStatusBadge,
15434
+ InvoiceDetails,
15435
+ InvoicesList,
15436
+ InvoicesContainer,
15437
+ CancelSubscriptionDialog,
15438
+ PricingCard,
15439
+ PricingCardsGrid,
15440
+ ProrationPreview,
15441
+ SubscriptionEditor,
15442
+ SubscriptionStatusBadge,
15443
+ SubscriptionDetails,
15444
+ SubscriptionsList,
15445
+ SubscriptionsContainer,
15446
+ UsageSummaryCard,
15447
+ UsageSummaryCards,
15448
+ UsageContainer,
15449
+ UsageHistoryTable,
15450
+ BillingDetailModal,
15451
+ BillingAlertBanner,
15452
+ BillingDashboardContainer,
15453
+ StripeProvider,
15454
+ isStripeConfigured,
15455
+ PriceEditor,
15456
+ PricesList,
15457
+ ProductEditor,
15458
+ ProductsList,
15459
+ ProductsAdminContainer,
12149
15460
  CompanyDetails,
12150
15461
  AdminCompanyContainer,
12151
15462
  CompanyContainer,
@@ -12201,4 +15512,4 @@ export {
12201
15512
  useUserTableStructure,
12202
15513
  useContentTableStructure
12203
15514
  };
12204
- //# sourceMappingURL=chunk-WAFOKMKT.mjs.map
15515
+ //# sourceMappingURL=chunk-SXPXC2TY.mjs.map