@carlonicora/nextjs-jsonapi 1.37.0 → 1.38.1

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 (63) hide show
  1. package/dist/{BlockNoteEditor-GTWR6CPI.mjs → BlockNoteEditor-5CEV5TZT.mjs} +3 -3
  2. package/dist/{BlockNoteEditor-74FHJO7E.js → BlockNoteEditor-VB72JQEO.js} +13 -13
  3. package/dist/{BlockNoteEditor-74FHJO7E.js.map → BlockNoteEditor-VB72JQEO.js.map} +1 -1
  4. package/dist/billing/index.d.mts +12 -2
  5. package/dist/billing/index.d.ts +12 -2
  6. package/dist/billing/index.js +680 -452
  7. package/dist/billing/index.js.map +1 -1
  8. package/dist/billing/index.mjs +588 -360
  9. package/dist/billing/index.mjs.map +1 -1
  10. package/dist/{chunk-53IPQJVH.js → chunk-3EZX4G2E.js} +147 -23
  11. package/dist/chunk-3EZX4G2E.js.map +1 -0
  12. package/dist/{chunk-YVEK3SUS.js → chunk-BYMBRMKS.js} +454 -446
  13. package/dist/chunk-BYMBRMKS.js.map +1 -0
  14. package/dist/{chunk-P7R2DPD6.mjs → chunk-TQ5GRRTM.mjs} +125 -1
  15. package/dist/chunk-TQ5GRRTM.mjs.map +1 -0
  16. package/dist/{chunk-ZUUH4CQC.mjs → chunk-VMK2N3TQ.mjs} +13 -5
  17. package/dist/{chunk-ZUUH4CQC.mjs.map → chunk-VMK2N3TQ.mjs.map} +1 -1
  18. package/dist/client/index.js +3 -3
  19. package/dist/client/index.mjs +2 -2
  20. package/dist/components/index.js +3 -3
  21. package/dist/components/index.mjs +2 -2
  22. package/dist/contexts/index.js +3 -3
  23. package/dist/contexts/index.mjs +2 -2
  24. package/dist/core/index.d.mts +47 -3
  25. package/dist/core/index.d.ts +47 -3
  26. package/dist/core/index.js +8 -2
  27. package/dist/core/index.js.map +1 -1
  28. package/dist/core/index.mjs +7 -1
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +8 -2
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +7 -1
  34. package/dist/server/index.js +3 -3
  35. package/dist/server/index.mjs +1 -1
  36. package/dist/{stripe-subscription.interface-DK7BJaNd.d.ts → stripe-promotion-code.interface-BcJty0rv.d.ts} +18 -1
  37. package/dist/{stripe-subscription.interface-C8uhCYIZ.d.mts → stripe-promotion-code.interface-Dnm2DJKQ.d.mts} +18 -1
  38. package/package.json +1 -1
  39. package/src/billing/index.ts +1 -0
  40. package/src/core/index.ts +1 -0
  41. package/src/core/registry/ModuleRegistry.ts +1 -0
  42. package/src/features/auth/components/forms/Login.tsx +14 -2
  43. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +5 -16
  44. package/src/features/billing/stripe-invoice/data/stripe-invoice.interface.ts +1 -0
  45. package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +108 -0
  46. package/src/features/billing/stripe-promotion-code/components/index.ts +1 -0
  47. package/src/features/billing/stripe-promotion-code/data/index.ts +3 -0
  48. package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.interface.ts +14 -0
  49. package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.service.ts +64 -0
  50. package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.ts +66 -0
  51. package/src/features/billing/stripe-promotion-code/index.ts +2 -0
  52. package/src/features/billing/stripe-promotion-code/stripe-promotion-code.module.ts +9 -0
  53. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +20 -3
  54. package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +6 -0
  55. package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +131 -9
  56. package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +2 -0
  57. package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +8 -0
  58. package/src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts +93 -7
  59. package/src/features/index.ts +1 -0
  60. package/dist/chunk-53IPQJVH.js.map +0 -1
  61. package/dist/chunk-P7R2DPD6.mjs.map +0 -1
  62. package/dist/chunk-YVEK3SUS.js.map +0 -1
  63. /package/dist/{BlockNoteEditor-GTWR6CPI.mjs.map → BlockNoteEditor-5CEV5TZT.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -126,7 +126,10 @@ var _chunk2PHWAL6Qjs = require('./chunk-2PHWAL6Q.js');
126
126
 
127
127
 
128
128
 
129
- var _chunk53IPQJVHjs = require('./chunk-53IPQJVH.js');
129
+
130
+
131
+
132
+ var _chunk3EZX4G2Ejs = require('./chunk-3EZX4G2E.js');
130
133
  require('./chunk-LXKSUWAV.js');
131
134
  require('./chunk-IBS6NI7D.js');
132
135
 
@@ -277,5 +280,8 @@ require('./chunk-7QVYU63E.js');
277
280
 
278
281
 
279
282
 
280
- exports.AVAILABLE_OAUTH_SCOPES = _chunk53IPQJVHjs.AVAILABLE_OAUTH_SCOPES; exports.AbstractApiData = _chunk53IPQJVHjs.AbstractApiData; exports.AbstractService = _chunk53IPQJVHjs.AbstractService; exports.Action = _chunk53IPQJVHjs.Action; exports.Auth = _chunk53IPQJVHjs.Auth; exports.AuthComponent = _chunk53IPQJVHjs.AuthComponent; exports.AuthModule = _chunk53IPQJVHjs.AuthModule; exports.AuthService = _chunk53IPQJVHjs.AuthService; exports.AuthorModule = _chunk53IPQJVHjs.AuthorModule; exports.Billing = _chunk53IPQJVHjs.Billing; exports.BillingModule = _chunk53IPQJVHjs.BillingModule; exports.BillingService = _chunk53IPQJVHjs.BillingService; exports.BlockNoteDiffUtil = _chunk53IPQJVHjs.BlockNoteDiffUtil; exports.BlockNoteWordDiffRendererUtil = _chunk53IPQJVHjs.BlockNoteWordDiffRendererUtil; exports.ClientAbstractService = _chunk53IPQJVHjs.ClientAbstractService; exports.ClientHttpMethod = _chunk53IPQJVHjs.ClientHttpMethod; exports.Company = _chunk53IPQJVHjs.Company; exports.CompanyFields = _chunk53IPQJVHjs.CompanyFields; exports.CompanyModule = _chunk53IPQJVHjs.CompanyModule; exports.CompanyService = _chunk53IPQJVHjs.CompanyService; exports.Content = _chunk53IPQJVHjs.Content; exports.ContentFields = _chunk53IPQJVHjs.ContentFields; exports.ContentModule = _chunk53IPQJVHjs.ContentModule; exports.ContentService = _chunk53IPQJVHjs.ContentService; exports.DEFAULT_GRANT_TYPES = _chunk53IPQJVHjs.DEFAULT_GRANT_TYPES; exports.DataClass = _chunkFM6WRAN5js.DataClassRegistry; exports.DataClassRegistry = _chunkFM6WRAN5js.DataClassRegistry; exports.EndpointCreator = _chunk53IPQJVHjs.EndpointCreator; exports.Feature = _chunk53IPQJVHjs.Feature; exports.FeatureModule = _chunk53IPQJVHjs.FeatureModule; exports.FeatureService = _chunk53IPQJVHjs.FeatureService; exports.HttpMethod = _chunk53IPQJVHjs.HttpMethod; exports.InvoiceStatus = _chunk53IPQJVHjs.InvoiceStatus; exports.JsonApiDataFactory = _chunkFM6WRAN5js.JsonApiDataFactory; exports.Module = _chunk53IPQJVHjs.Module; exports.ModuleModule = _chunk53IPQJVHjs.ModuleModule; exports.ModuleRegistrar = _chunk53IPQJVHjs.ModuleRegistrar; exports.ModuleRegistry = _chunk53IPQJVHjs.ModuleRegistry; exports.Modules = _chunk53IPQJVHjs.Modules; exports.Notification = _chunk53IPQJVHjs.Notification; exports.NotificationFields = _chunk53IPQJVHjs.NotificationFields; exports.NotificationModule = _chunk53IPQJVHjs.NotificationModule; exports.NotificationService = _chunk53IPQJVHjs.NotificationService; exports.OAUTH_SCOPE_DISPLAY = _chunk53IPQJVHjs.OAUTH_SCOPE_DISPLAY; exports.OAuthClient = _chunk53IPQJVHjs.OAuthClient; exports.OAuthModule = _chunk53IPQJVHjs.OAuthModule; exports.OAuthService = _chunk53IPQJVHjs.OAuthService; exports.PaymentMethod = _chunk53IPQJVHjs.PaymentMethod; exports.Push = _chunk53IPQJVHjs.Push; exports.PushModule = _chunk53IPQJVHjs.PushModule; exports.PushService = _chunk53IPQJVHjs.PushService; exports.RehydrationFactory = _chunk53IPQJVHjs.RehydrationFactory; exports.Role = _chunk53IPQJVHjs.Role; exports.RoleFields = _chunk53IPQJVHjs.RoleFields; exports.RoleModule = _chunk53IPQJVHjs.RoleModule; exports.RoleService = _chunk53IPQJVHjs.RoleService; exports.S3 = _chunk53IPQJVHjs.S3; exports.S3Module = _chunk53IPQJVHjs.S3Module; exports.S3Service = _chunk53IPQJVHjs.S3Service; exports.StripeCustomer = _chunk53IPQJVHjs.StripeCustomer; exports.StripeCustomerModule = _chunk53IPQJVHjs.StripeCustomerModule; exports.StripeCustomerService = _chunk53IPQJVHjs.StripeCustomerService; exports.StripeInvoice = _chunk53IPQJVHjs.StripeInvoice; exports.StripeInvoiceModule = _chunk53IPQJVHjs.StripeInvoiceModule; exports.StripeInvoiceService = _chunk53IPQJVHjs.StripeInvoiceService; exports.StripePaymentMethodModule = _chunk53IPQJVHjs.StripePaymentMethodModule; exports.StripePrice = _chunk53IPQJVHjs.StripePrice; exports.StripePriceModule = _chunk53IPQJVHjs.StripePriceModule; exports.StripePriceService = _chunk53IPQJVHjs.StripePriceService; exports.StripeProduct = _chunk53IPQJVHjs.StripeProduct; exports.StripeProductModule = _chunk53IPQJVHjs.StripeProductModule; exports.StripeProductService = _chunk53IPQJVHjs.StripeProductService; exports.StripeSubscription = _chunk53IPQJVHjs.StripeSubscription; exports.StripeSubscriptionModule = _chunk53IPQJVHjs.StripeSubscriptionModule; exports.StripeSubscriptionService = _chunk53IPQJVHjs.StripeSubscriptionService; exports.StripeUsage = _chunk53IPQJVHjs.StripeUsage; exports.StripeUsageModule = _chunk53IPQJVHjs.StripeUsageModule; exports.StripeUsageService = _chunk53IPQJVHjs.StripeUsageService; exports.SubscriptionStatus = _chunk53IPQJVHjs.SubscriptionStatus; exports.TableOptions = _chunk53IPQJVHjs.TableOptions; exports.User = _chunk53IPQJVHjs.User; exports.UserFields = _chunk53IPQJVHjs.UserFields; exports.UserModule = _chunk53IPQJVHjs.UserModule; exports.UserService = _chunk53IPQJVHjs.UserService; exports.checkPermissions = _chunk53IPQJVHjs.checkPermissions; exports.checkPermissionsFromServer = _chunk53IPQJVHjs.checkPermissionsFromServer; exports.clearLastApiTotal = _chunk53IPQJVHjs.clearLastApiTotal; exports.cn = _chunk53IPQJVHjs.cn; exports.composeRefs = _chunk53IPQJVHjs.composeRefs; exports.configureAuth = _chunk53IPQJVHjs.configureAuth; exports.configureI18n = _chunk2PHWAL6Qjs.configureI18n; exports.configureJsonApi = _chunk2PHWAL6Qjs.configureJsonApi; exports.configureLogin = _chunk2PHWAL6Qjs.configureLogin; exports.configureRoles = _chunk2PHWAL6Qjs.configureRoles; exports.createJsonApiInclusion = _chunk53IPQJVHjs.createJsonApiInclusion; exports.dismissToast = _chunk53IPQJVHjs.dismissToast; exports.entityObjectSchema = _chunk53IPQJVHjs.entityObjectSchema; exports.exists = _chunk53IPQJVHjs.exists; exports.formatDate = _chunk53IPQJVHjs.formatDate; exports.getApiUrl = _chunk2PHWAL6Qjs.getApiUrl; exports.getAppUrl = _chunk2PHWAL6Qjs.getAppUrl; exports.getBootstrapper = _chunkFM6WRAN5js.getBootstrapper; exports.getClientGlobalErrorHandler = _chunk53IPQJVHjs.getClientGlobalErrorHandler; exports.getGlobalErrorHandler = _chunk53IPQJVHjs.getGlobalErrorHandler; exports.getIcon = _chunk53IPQJVHjs.getIcon; exports.getIconByModule = _chunk53IPQJVHjs.getIconByModule; exports.getIconByModuleName = _chunk53IPQJVHjs.getIconByModuleName; exports.getLastApiTotal = _chunk53IPQJVHjs.getLastApiTotal; exports.getLucideIcon = _chunk53IPQJVHjs.getLucideIcon; exports.getLucideIconByModule = _chunk53IPQJVHjs.getLucideIconByModule; exports.getLucideIconByModuleName = _chunk53IPQJVHjs.getLucideIconByModuleName; exports.getRoleId = _chunk2PHWAL6Qjs.getRoleId; exports.getStripePublishableKey = _chunk2PHWAL6Qjs.getStripePublishableKey; exports.getTableComponents = _chunk53IPQJVHjs.getTableComponents; exports.getTableOptions = _chunk53IPQJVHjs.getTableOptions; exports.getTokenHandler = _chunk53IPQJVHjs.getTokenHandler; exports.getTrackablePages = _chunk2PHWAL6Qjs.getTrackablePages; exports.getValueFromPath = _chunk53IPQJVHjs.getValueFromPath; exports.hasBootstrapper = _chunkFM6WRAN5js.hasBootstrapper; exports.isRolesConfigured = _chunk2PHWAL6Qjs.isRolesConfigured; exports.rehydrate = _chunk53IPQJVHjs.rehydrate; exports.rehydrateList = _chunk53IPQJVHjs.rehydrateList; exports.resetBootstrapStore = _chunkFM6WRAN5js.resetBootstrapStore; exports.setBootstrapper = _chunkFM6WRAN5js.setBootstrapper; exports.setClientGlobalErrorHandler = _chunk53IPQJVHjs.setClientGlobalErrorHandler; exports.setGlobalErrorHandler = _chunk53IPQJVHjs.setGlobalErrorHandler; exports.showCustomToast = _chunk53IPQJVHjs.showCustomToast; exports.showError = _chunk53IPQJVHjs.showError; exports.showToast = _chunk53IPQJVHjs.showToast; exports.translateData = _chunkFM6WRAN5js.translateData; exports.translateResponse = _chunkFM6WRAN5js.translateResponse; exports.tryBootstrap = _chunkFM6WRAN5js.tryBootstrap; exports.useComposedRefs = _chunk53IPQJVHjs.useComposedRefs; exports.useIsMobile = _chunk53IPQJVHjs.useIsMobile; exports.userObjectSchema = _chunk53IPQJVHjs.userObjectSchema;
283
+
284
+
285
+
286
+ exports.AVAILABLE_OAUTH_SCOPES = _chunk3EZX4G2Ejs.AVAILABLE_OAUTH_SCOPES; exports.AbstractApiData = _chunk3EZX4G2Ejs.AbstractApiData; exports.AbstractService = _chunk3EZX4G2Ejs.AbstractService; exports.Action = _chunk3EZX4G2Ejs.Action; exports.Auth = _chunk3EZX4G2Ejs.Auth; exports.AuthComponent = _chunk3EZX4G2Ejs.AuthComponent; exports.AuthModule = _chunk3EZX4G2Ejs.AuthModule; exports.AuthService = _chunk3EZX4G2Ejs.AuthService; exports.AuthorModule = _chunk3EZX4G2Ejs.AuthorModule; exports.Billing = _chunk3EZX4G2Ejs.Billing; exports.BillingModule = _chunk3EZX4G2Ejs.BillingModule; exports.BillingService = _chunk3EZX4G2Ejs.BillingService; exports.BlockNoteDiffUtil = _chunk3EZX4G2Ejs.BlockNoteDiffUtil; exports.BlockNoteWordDiffRendererUtil = _chunk3EZX4G2Ejs.BlockNoteWordDiffRendererUtil; exports.ClientAbstractService = _chunk3EZX4G2Ejs.ClientAbstractService; exports.ClientHttpMethod = _chunk3EZX4G2Ejs.ClientHttpMethod; exports.Company = _chunk3EZX4G2Ejs.Company; exports.CompanyFields = _chunk3EZX4G2Ejs.CompanyFields; exports.CompanyModule = _chunk3EZX4G2Ejs.CompanyModule; exports.CompanyService = _chunk3EZX4G2Ejs.CompanyService; exports.Content = _chunk3EZX4G2Ejs.Content; exports.ContentFields = _chunk3EZX4G2Ejs.ContentFields; exports.ContentModule = _chunk3EZX4G2Ejs.ContentModule; exports.ContentService = _chunk3EZX4G2Ejs.ContentService; exports.DEFAULT_GRANT_TYPES = _chunk3EZX4G2Ejs.DEFAULT_GRANT_TYPES; exports.DataClass = _chunkFM6WRAN5js.DataClassRegistry; exports.DataClassRegistry = _chunkFM6WRAN5js.DataClassRegistry; exports.EndpointCreator = _chunk3EZX4G2Ejs.EndpointCreator; exports.Feature = _chunk3EZX4G2Ejs.Feature; exports.FeatureModule = _chunk3EZX4G2Ejs.FeatureModule; exports.FeatureService = _chunk3EZX4G2Ejs.FeatureService; exports.HttpMethod = _chunk3EZX4G2Ejs.HttpMethod; exports.InvoiceStatus = _chunk3EZX4G2Ejs.InvoiceStatus; exports.JsonApiDataFactory = _chunkFM6WRAN5js.JsonApiDataFactory; exports.Module = _chunk3EZX4G2Ejs.Module; exports.ModuleModule = _chunk3EZX4G2Ejs.ModuleModule; exports.ModuleRegistrar = _chunk3EZX4G2Ejs.ModuleRegistrar; exports.ModuleRegistry = _chunk3EZX4G2Ejs.ModuleRegistry; exports.Modules = _chunk3EZX4G2Ejs.Modules; exports.Notification = _chunk3EZX4G2Ejs.Notification; exports.NotificationFields = _chunk3EZX4G2Ejs.NotificationFields; exports.NotificationModule = _chunk3EZX4G2Ejs.NotificationModule; exports.NotificationService = _chunk3EZX4G2Ejs.NotificationService; exports.OAUTH_SCOPE_DISPLAY = _chunk3EZX4G2Ejs.OAUTH_SCOPE_DISPLAY; exports.OAuthClient = _chunk3EZX4G2Ejs.OAuthClient; exports.OAuthModule = _chunk3EZX4G2Ejs.OAuthModule; exports.OAuthService = _chunk3EZX4G2Ejs.OAuthService; exports.PaymentMethod = _chunk3EZX4G2Ejs.PaymentMethod; exports.Push = _chunk3EZX4G2Ejs.Push; exports.PushModule = _chunk3EZX4G2Ejs.PushModule; exports.PushService = _chunk3EZX4G2Ejs.PushService; exports.RehydrationFactory = _chunk3EZX4G2Ejs.RehydrationFactory; exports.Role = _chunk3EZX4G2Ejs.Role; exports.RoleFields = _chunk3EZX4G2Ejs.RoleFields; exports.RoleModule = _chunk3EZX4G2Ejs.RoleModule; exports.RoleService = _chunk3EZX4G2Ejs.RoleService; exports.S3 = _chunk3EZX4G2Ejs.S3; exports.S3Module = _chunk3EZX4G2Ejs.S3Module; exports.S3Service = _chunk3EZX4G2Ejs.S3Service; exports.StripeCustomer = _chunk3EZX4G2Ejs.StripeCustomer; exports.StripeCustomerModule = _chunk3EZX4G2Ejs.StripeCustomerModule; exports.StripeCustomerService = _chunk3EZX4G2Ejs.StripeCustomerService; exports.StripeInvoice = _chunk3EZX4G2Ejs.StripeInvoice; exports.StripeInvoiceModule = _chunk3EZX4G2Ejs.StripeInvoiceModule; exports.StripeInvoiceService = _chunk3EZX4G2Ejs.StripeInvoiceService; exports.StripePaymentMethodModule = _chunk3EZX4G2Ejs.StripePaymentMethodModule; exports.StripePrice = _chunk3EZX4G2Ejs.StripePrice; exports.StripePriceModule = _chunk3EZX4G2Ejs.StripePriceModule; exports.StripePriceService = _chunk3EZX4G2Ejs.StripePriceService; exports.StripeProduct = _chunk3EZX4G2Ejs.StripeProduct; exports.StripeProductModule = _chunk3EZX4G2Ejs.StripeProductModule; exports.StripeProductService = _chunk3EZX4G2Ejs.StripeProductService; exports.StripePromotionCode = _chunk3EZX4G2Ejs.StripePromotionCode; exports.StripePromotionCodeModule = _chunk3EZX4G2Ejs.StripePromotionCodeModule; exports.StripePromotionCodeService = _chunk3EZX4G2Ejs.StripePromotionCodeService; exports.StripeSubscription = _chunk3EZX4G2Ejs.StripeSubscription; exports.StripeSubscriptionModule = _chunk3EZX4G2Ejs.StripeSubscriptionModule; exports.StripeSubscriptionService = _chunk3EZX4G2Ejs.StripeSubscriptionService; exports.StripeUsage = _chunk3EZX4G2Ejs.StripeUsage; exports.StripeUsageModule = _chunk3EZX4G2Ejs.StripeUsageModule; exports.StripeUsageService = _chunk3EZX4G2Ejs.StripeUsageService; exports.SubscriptionStatus = _chunk3EZX4G2Ejs.SubscriptionStatus; exports.TableOptions = _chunk3EZX4G2Ejs.TableOptions; exports.User = _chunk3EZX4G2Ejs.User; exports.UserFields = _chunk3EZX4G2Ejs.UserFields; exports.UserModule = _chunk3EZX4G2Ejs.UserModule; exports.UserService = _chunk3EZX4G2Ejs.UserService; exports.checkPermissions = _chunk3EZX4G2Ejs.checkPermissions; exports.checkPermissionsFromServer = _chunk3EZX4G2Ejs.checkPermissionsFromServer; exports.clearLastApiTotal = _chunk3EZX4G2Ejs.clearLastApiTotal; exports.cn = _chunk3EZX4G2Ejs.cn; exports.composeRefs = _chunk3EZX4G2Ejs.composeRefs; exports.configureAuth = _chunk3EZX4G2Ejs.configureAuth; exports.configureI18n = _chunk2PHWAL6Qjs.configureI18n; exports.configureJsonApi = _chunk2PHWAL6Qjs.configureJsonApi; exports.configureLogin = _chunk2PHWAL6Qjs.configureLogin; exports.configureRoles = _chunk2PHWAL6Qjs.configureRoles; exports.createJsonApiInclusion = _chunk3EZX4G2Ejs.createJsonApiInclusion; exports.dismissToast = _chunk3EZX4G2Ejs.dismissToast; exports.entityObjectSchema = _chunk3EZX4G2Ejs.entityObjectSchema; exports.exists = _chunk3EZX4G2Ejs.exists; exports.formatDate = _chunk3EZX4G2Ejs.formatDate; exports.getApiUrl = _chunk2PHWAL6Qjs.getApiUrl; exports.getAppUrl = _chunk2PHWAL6Qjs.getAppUrl; exports.getBootstrapper = _chunkFM6WRAN5js.getBootstrapper; exports.getClientGlobalErrorHandler = _chunk3EZX4G2Ejs.getClientGlobalErrorHandler; exports.getGlobalErrorHandler = _chunk3EZX4G2Ejs.getGlobalErrorHandler; exports.getIcon = _chunk3EZX4G2Ejs.getIcon; exports.getIconByModule = _chunk3EZX4G2Ejs.getIconByModule; exports.getIconByModuleName = _chunk3EZX4G2Ejs.getIconByModuleName; exports.getLastApiTotal = _chunk3EZX4G2Ejs.getLastApiTotal; exports.getLucideIcon = _chunk3EZX4G2Ejs.getLucideIcon; exports.getLucideIconByModule = _chunk3EZX4G2Ejs.getLucideIconByModule; exports.getLucideIconByModuleName = _chunk3EZX4G2Ejs.getLucideIconByModuleName; exports.getRoleId = _chunk2PHWAL6Qjs.getRoleId; exports.getStripePublishableKey = _chunk2PHWAL6Qjs.getStripePublishableKey; exports.getTableComponents = _chunk3EZX4G2Ejs.getTableComponents; exports.getTableOptions = _chunk3EZX4G2Ejs.getTableOptions; exports.getTokenHandler = _chunk3EZX4G2Ejs.getTokenHandler; exports.getTrackablePages = _chunk2PHWAL6Qjs.getTrackablePages; exports.getValueFromPath = _chunk3EZX4G2Ejs.getValueFromPath; exports.hasBootstrapper = _chunkFM6WRAN5js.hasBootstrapper; exports.isRolesConfigured = _chunk2PHWAL6Qjs.isRolesConfigured; exports.rehydrate = _chunk3EZX4G2Ejs.rehydrate; exports.rehydrateList = _chunk3EZX4G2Ejs.rehydrateList; exports.resetBootstrapStore = _chunkFM6WRAN5js.resetBootstrapStore; exports.setBootstrapper = _chunkFM6WRAN5js.setBootstrapper; exports.setClientGlobalErrorHandler = _chunk3EZX4G2Ejs.setClientGlobalErrorHandler; exports.setGlobalErrorHandler = _chunk3EZX4G2Ejs.setGlobalErrorHandler; exports.showCustomToast = _chunk3EZX4G2Ejs.showCustomToast; exports.showError = _chunk3EZX4G2Ejs.showError; exports.showToast = _chunk3EZX4G2Ejs.showToast; exports.translateData = _chunkFM6WRAN5js.translateData; exports.translateResponse = _chunkFM6WRAN5js.translateResponse; exports.tryBootstrap = _chunkFM6WRAN5js.tryBootstrap; exports.useComposedRefs = _chunk3EZX4G2Ejs.useComposedRefs; exports.useIsMobile = _chunk3EZX4G2Ejs.useIsMobile; exports.userObjectSchema = _chunk3EZX4G2Ejs.userObjectSchema;
281
287
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/index.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,qtPAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/index.js"}
1
+ {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/index.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,27PAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/index.js"}
package/dist/index.mjs CHANGED
@@ -80,6 +80,9 @@ import {
80
80
  StripeProduct,
81
81
  StripeProductModule,
82
82
  StripeProductService,
83
+ StripePromotionCode,
84
+ StripePromotionCodeModule,
85
+ StripePromotionCodeService,
83
86
  StripeSubscription,
84
87
  StripeSubscriptionModule,
85
88
  StripeSubscriptionService,
@@ -126,7 +129,7 @@ import {
126
129
  useComposedRefs,
127
130
  useIsMobile,
128
131
  userObjectSchema
129
- } from "./chunk-P7R2DPD6.mjs";
132
+ } from "./chunk-TQ5GRRTM.mjs";
130
133
  import "./chunk-AUXK7QSA.mjs";
131
134
  import "./chunk-C7C7VY4F.mjs";
132
135
  import {
@@ -214,6 +217,9 @@ export {
214
217
  StripeProduct,
215
218
  StripeProductModule,
216
219
  StripeProductService,
220
+ StripePromotionCode,
221
+ StripePromotionCodeModule,
222
+ StripePromotionCodeService,
217
223
  StripeSubscription,
218
224
  StripeSubscriptionModule,
219
225
  StripeSubscriptionService,
@@ -15,7 +15,7 @@ var _chunk3ZPK4QOBjs = require('../chunk-3ZPK4QOB.js');
15
15
 
16
16
 
17
17
 
18
- var _chunk53IPQJVHjs = require('../chunk-53IPQJVH.js');
18
+ var _chunk3EZX4G2Ejs = require('../chunk-3EZX4G2E.js');
19
19
  require('../chunk-LXKSUWAV.js');
20
20
  require('../chunk-IBS6NI7D.js');
21
21
 
@@ -86,7 +86,7 @@ var ServerSession = class {
86
86
  if (!rawModules) return false;
87
87
  const modules = JSON.parse(_pako2.default.ungzip(Buffer.from(rawModules, "base64"), { to: "string" }));
88
88
  const selectedModule = modules.find((module) => module.id === params.module.moduleId);
89
- return _chunk53IPQJVHjs.checkPermissionsFromServer.call(void 0, {
89
+ return _chunk3EZX4G2Ejs.checkPermissionsFromServer.call(void 0, {
90
90
  module: params.module,
91
91
  action: params.action,
92
92
  data: params.data,
@@ -296,5 +296,5 @@ _chunk7QVYU63Ejs.__name.call(void 0, ServerJsonApiDelete, "ServerJsonApiDelete")
296
296
 
297
297
 
298
298
 
299
- exports.ServerAuthService = _chunk53IPQJVHjs.AuthService; exports.ServerCompanyService = _chunk53IPQJVHjs.CompanyService; exports.ServerContentService = _chunk53IPQJVHjs.ContentService; exports.ServerFeatureService = _chunk53IPQJVHjs.FeatureService; exports.ServerJsonApiDelete = ServerJsonApiDelete; exports.ServerJsonApiGet = ServerJsonApiGet; exports.ServerJsonApiPatch = ServerJsonApiPatch; exports.ServerJsonApiPost = ServerJsonApiPost; exports.ServerJsonApiPut = ServerJsonApiPut; exports.ServerNotificationService = _chunk53IPQJVHjs.NotificationService; exports.ServerPushService = _chunk53IPQJVHjs.PushService; exports.ServerRoleService = _chunk53IPQJVHjs.RoleService; exports.ServerS3Service = _chunk53IPQJVHjs.S3Service; exports.ServerSession = ServerSession; exports.ServerUserService = _chunk53IPQJVHjs.UserService; exports.configureServerJsonApi = configureServerJsonApi; exports.getServerApiUrl = getServerApiUrl; exports.getServerAppUrl = getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = getServerTrackablePages; exports.invalidateCacheTag = invalidateCacheTag; exports.invalidateCacheTags = invalidateCacheTags; exports.serverRequest = _chunk3ZPK4QOBjs.serverRequest;
299
+ exports.ServerAuthService = _chunk3EZX4G2Ejs.AuthService; exports.ServerCompanyService = _chunk3EZX4G2Ejs.CompanyService; exports.ServerContentService = _chunk3EZX4G2Ejs.ContentService; exports.ServerFeatureService = _chunk3EZX4G2Ejs.FeatureService; exports.ServerJsonApiDelete = ServerJsonApiDelete; exports.ServerJsonApiGet = ServerJsonApiGet; exports.ServerJsonApiPatch = ServerJsonApiPatch; exports.ServerJsonApiPost = ServerJsonApiPost; exports.ServerJsonApiPut = ServerJsonApiPut; exports.ServerNotificationService = _chunk3EZX4G2Ejs.NotificationService; exports.ServerPushService = _chunk3EZX4G2Ejs.PushService; exports.ServerRoleService = _chunk3EZX4G2Ejs.RoleService; exports.ServerS3Service = _chunk3EZX4G2Ejs.S3Service; exports.ServerSession = ServerSession; exports.ServerUserService = _chunk3EZX4G2Ejs.UserService; exports.configureServerJsonApi = configureServerJsonApi; exports.getServerApiUrl = getServerApiUrl; exports.getServerAppUrl = getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = getServerTrackablePages; exports.invalidateCacheTag = invalidateCacheTag; exports.invalidateCacheTags = invalidateCacheTags; exports.serverRequest = _chunk3ZPK4QOBjs.serverRequest;
300
300
  //# sourceMappingURL=index.js.map
@@ -15,7 +15,7 @@ import {
15
15
  S3Service,
16
16
  UserService,
17
17
  checkPermissionsFromServer
18
- } from "../chunk-P7R2DPD6.mjs";
18
+ } from "../chunk-TQ5GRRTM.mjs";
19
19
  import "../chunk-AUXK7QSA.mjs";
20
20
  import "../chunk-C7C7VY4F.mjs";
21
21
  import {
@@ -110,6 +110,7 @@ interface ProrationPreviewInterface {
110
110
  immediateCharge: number;
111
111
  prorationDate: Date;
112
112
  lineItems: ProrationLineItem[];
113
+ isTrialUpgrade?: boolean;
113
114
  }
114
115
  interface ProrationLineItem {
115
116
  description: string;
@@ -209,6 +210,7 @@ type StripeSubscriptionInput = {
209
210
  trialPeriodDays?: number;
210
211
  paymentMethodId?: string;
211
212
  metadata?: Record<string, any>;
213
+ promotionCode?: string;
212
214
  };
213
215
  interface StripeSubscriptionCreateMeta {
214
216
  clientSecret: string | null;
@@ -220,4 +222,19 @@ interface StripeSubscriptionCreateResponse {
220
222
  meta: StripeSubscriptionCreateMeta;
221
223
  }
222
224
 
223
- export { InvoiceStatus as I, type MeterInterface as M, type PaymentMethodInterface as P, type ReportUsageInput as R, type StripeCustomerInterface as S, type UsageSummaryInterface as U, type StripeInvoiceInterface as a, type ProrationPreviewInterface as b, type ProrationLineItem as c, type StripePriceInterface as d, type PriceRecurring as e, type StripePriceInput as f, type StripeProductInterface as g, type StripeProductInput as h, SubscriptionStatus as i, type StripeSubscriptionInterface as j, type StripeSubscriptionInput as k, type StripeSubscriptionCreateMeta as l, type StripeSubscriptionCreateResponse as m, type StripeUsageInterface as n, type MeterSummaryInterface as o, type UsageRecordInterface as p };
225
+ /**
226
+ * Promotion code validation result from the backend
227
+ */
228
+ interface PromotionCodeValidationResult {
229
+ valid: boolean;
230
+ promotionCodeId?: string;
231
+ code: string;
232
+ discountType?: "percent_off" | "amount_off";
233
+ discountValue?: number;
234
+ currency?: string;
235
+ duration?: "forever" | "once" | "repeating";
236
+ durationInMonths?: number;
237
+ errorMessage?: string;
238
+ }
239
+
240
+ export { InvoiceStatus as I, type MeterInterface as M, type PaymentMethodInterface as P, type ReportUsageInput as R, type StripeCustomerInterface as S, type UsageSummaryInterface as U, type StripeInvoiceInterface as a, type ProrationPreviewInterface as b, type ProrationLineItem as c, type StripePriceInterface as d, type PriceRecurring as e, type StripePriceInput as f, type StripeProductInterface as g, type StripeProductInput as h, SubscriptionStatus as i, type StripeSubscriptionInterface as j, type StripeSubscriptionInput as k, type StripeSubscriptionCreateMeta as l, type StripeSubscriptionCreateResponse as m, type StripeUsageInterface as n, type MeterSummaryInterface as o, type UsageRecordInterface as p, type PromotionCodeValidationResult as q };
@@ -110,6 +110,7 @@ interface ProrationPreviewInterface {
110
110
  immediateCharge: number;
111
111
  prorationDate: Date;
112
112
  lineItems: ProrationLineItem[];
113
+ isTrialUpgrade?: boolean;
113
114
  }
114
115
  interface ProrationLineItem {
115
116
  description: string;
@@ -209,6 +210,7 @@ type StripeSubscriptionInput = {
209
210
  trialPeriodDays?: number;
210
211
  paymentMethodId?: string;
211
212
  metadata?: Record<string, any>;
213
+ promotionCode?: string;
212
214
  };
213
215
  interface StripeSubscriptionCreateMeta {
214
216
  clientSecret: string | null;
@@ -220,4 +222,19 @@ interface StripeSubscriptionCreateResponse {
220
222
  meta: StripeSubscriptionCreateMeta;
221
223
  }
222
224
 
223
- export { InvoiceStatus as I, type MeterInterface as M, type PaymentMethodInterface as P, type ReportUsageInput as R, type StripeCustomerInterface as S, type UsageSummaryInterface as U, type StripeInvoiceInterface as a, type ProrationPreviewInterface as b, type ProrationLineItem as c, type StripePriceInterface as d, type PriceRecurring as e, type StripePriceInput as f, type StripeProductInterface as g, type StripeProductInput as h, SubscriptionStatus as i, type StripeSubscriptionInterface as j, type StripeSubscriptionInput as k, type StripeSubscriptionCreateMeta as l, type StripeSubscriptionCreateResponse as m, type StripeUsageInterface as n, type MeterSummaryInterface as o, type UsageRecordInterface as p };
225
+ /**
226
+ * Promotion code validation result from the backend
227
+ */
228
+ interface PromotionCodeValidationResult {
229
+ valid: boolean;
230
+ promotionCodeId?: string;
231
+ code: string;
232
+ discountType?: "percent_off" | "amount_off";
233
+ discountValue?: number;
234
+ currency?: string;
235
+ duration?: "forever" | "once" | "repeating";
236
+ durationInMonths?: number;
237
+ errorMessage?: string;
238
+ }
239
+
240
+ export { InvoiceStatus as I, type MeterInterface as M, type PaymentMethodInterface as P, type ReportUsageInput as R, type StripeCustomerInterface as S, type UsageSummaryInterface as U, type StripeInvoiceInterface as a, type ProrationPreviewInterface as b, type ProrationLineItem as c, type StripePriceInterface as d, type PriceRecurring as e, type StripePriceInput as f, type StripeProductInterface as g, type StripeProductInput as h, SubscriptionStatus as i, type StripeSubscriptionInterface as j, type StripeSubscriptionInput as k, type StripeSubscriptionCreateMeta as l, type StripeSubscriptionCreateResponse as m, type StripeUsageInterface as n, type MeterSummaryInterface as o, type UsageRecordInterface as p, type PromotionCodeValidationResult as q };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlonicora/nextjs-jsonapi",
3
- "version": "1.37.0",
3
+ "version": "1.38.1",
4
4
  "description": "Next.js JSON:API client with server/client support and caching",
5
5
  "author": "Carlo Nicora",
6
6
  "license": "GPL-3.0-or-later",
@@ -6,3 +6,4 @@ export * from "../features/billing/stripe-price/components";
6
6
  export * from "../features/billing/stripe-product/components";
7
7
  export * from "../features/billing/stripe-subscription/components";
8
8
  export * from "../features/billing/stripe-usage/components";
9
+ export * from "../features/billing/stripe-promotion-code/components";
package/src/core/index.ts CHANGED
@@ -40,6 +40,7 @@ export * from "../features/billing/stripe-price";
40
40
  export * from "../features/billing/stripe-product";
41
41
  export * from "../features/billing/stripe-subscription";
42
42
  export * from "../features/billing/stripe-usage";
43
+ export * from "../features/billing/stripe-promotion-code";
43
44
  export * from "../features/company/company.module";
44
45
  export * from "../features/company/data";
45
46
  export * from "../features/content/content.module";
@@ -26,6 +26,7 @@ export interface FoundationModuleDefinitions {
26
26
  StripeProduct: ModuleWithPermissions;
27
27
  StripePrice: ModuleWithPermissions;
28
28
  StripeUsage: ModuleWithPermissions;
29
+ StripePromotionCode: ModuleWithPermissions;
29
30
  // OAuth modules
30
31
  OAuth: ModuleWithPermissions;
31
32
  }
@@ -3,6 +3,7 @@
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
4
  import { useTranslations } from "next-intl";
5
5
  import Image from "next/image";
6
+ import { useRouter, useSearchParams } from "next/navigation";
6
7
  import { SubmitHandler, useForm } from "react-hook-form";
7
8
  import { z } from "zod";
8
9
  import { getApiUrl } from "../../../../client/config";
@@ -31,7 +32,10 @@ export function Login() {
31
32
  const { setUser } = useCurrentUserContext<UserInterface>();
32
33
  const { setComponentType } = useAuthContext();
33
34
  const generateUrl = usePageUrlGenerator();
34
- const router = useI18nRouter();
35
+ const i18nRouter = useI18nRouter();
36
+ const nativeRouter = useRouter(); // For URLs that already include locale
37
+ const searchParams = useSearchParams();
38
+ const callbackUrl = searchParams.get("callbackUrl");
35
39
 
36
40
  const formSchema = z.object({
37
41
  email: z.string().email({
@@ -56,7 +60,15 @@ export function Login() {
56
60
  })) as UserInterface;
57
61
 
58
62
  setUser(user);
59
- router.replace(generateUrl({ page: `/` }));
63
+
64
+ // Redirect to callback URL if present, otherwise go to home
65
+ // Use native router for callbackUrl since it already includes the locale prefix
66
+ // Use i18n router for normal navigation which adds locale automatically
67
+ if (callbackUrl) {
68
+ nativeRouter.replace(callbackUrl);
69
+ } else {
70
+ i18nRouter.replace(generateUrl({ page: `/` }));
71
+ }
60
72
  } catch (e) {
61
73
  errorToast({
62
74
  title: t(`common.errors.error`),
@@ -34,15 +34,6 @@ function formatDate(date: Date): string {
34
34
  });
35
35
  }
36
36
 
37
- function formatPrice(amount: number | undefined, currency: string | undefined): string {
38
- if (amount === undefined) return "N/A";
39
- const currencyCode = currency?.toUpperCase() || "USD";
40
- return new Intl.NumberFormat(undefined, {
41
- style: "currency",
42
- currency: currencyCode,
43
- }).format(amount / 100);
44
- }
45
-
46
37
  function formatPlanName(subscription: StripeSubscriptionInterface): string {
47
38
  const productName = subscription.price?.product?.name || "";
48
39
  const nickname = subscription.price?.nickname || "";
@@ -132,14 +123,12 @@ export function SubscriptionSummaryCard({
132
123
  {primarySubscription.cancelAtPeriodEnd ? "Canceling" : primarySubscription.status}
133
124
  </Badge>
134
125
  </div>
135
- <p className="text-sm text-muted-foreground">
136
- {formatPrice(primarySubscription.price?.unitAmount, primarySubscription.price?.currency)}
137
- {primarySubscription.price?.recurring && <span>/{primarySubscription.price.recurring.interval}</span>}
138
- </p>
139
126
  <p className="text-xs text-muted-foreground">
140
- {primarySubscription.cancelAtPeriodEnd
141
- ? `Cancels on ${formatDate(primarySubscription.currentPeriodEnd)}`
142
- : `Renews on ${formatDate(primarySubscription.currentPeriodEnd)}`}
127
+ {!primarySubscription.price?.isTrial
128
+ ? `Ends on ${formatDate(primarySubscription.currentPeriodEnd)}`
129
+ : primarySubscription.cancelAtPeriodEnd
130
+ ? `Cancels on ${formatDate(primarySubscription.currentPeriodEnd)}`
131
+ : `Renews on ${formatDate(primarySubscription.currentPeriodEnd)}`}
143
132
  </p>
144
133
  {activeSubscriptions.length > 1 && (
145
134
  <p className="text-xs text-muted-foreground">+{activeSubscriptions.length - 1} more subscription(s)</p>
@@ -52,6 +52,7 @@ export interface ProrationPreviewInterface {
52
52
  immediateCharge: number;
53
53
  prorationDate: Date;
54
54
  lineItems: ProrationLineItem[];
55
+ isTrialUpgrade?: boolean;
55
56
  }
56
57
 
57
58
  export interface ProrationLineItem {
@@ -0,0 +1,108 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { Check, X, Loader2 } from "lucide-react";
5
+ import { Button, Input } from "../../../../shadcnui";
6
+ import { PromotionCodeValidationResult } from "../data/stripe-promotion-code.interface";
7
+
8
+ type PromoCodeInputProps = {
9
+ appliedCode: PromotionCodeValidationResult | null;
10
+ isValidating: boolean;
11
+ error: string | null;
12
+ onApply: (code: string) => void;
13
+ onRemove: () => void;
14
+ disabled?: boolean;
15
+ };
16
+
17
+ export function PromoCodeInput({
18
+ appliedCode,
19
+ isValidating,
20
+ error,
21
+ onApply,
22
+ onRemove,
23
+ disabled = false,
24
+ }: PromoCodeInputProps) {
25
+ const [code, setCode] = useState("");
26
+
27
+ const handleApply = () => {
28
+ if (code.trim()) {
29
+ onApply(code.trim().toUpperCase());
30
+ }
31
+ };
32
+
33
+ const handleKeyDown = (e: React.KeyboardEvent) => {
34
+ if (e.key === "Enter") {
35
+ e.preventDefault();
36
+ handleApply();
37
+ }
38
+ };
39
+
40
+ // Format discount for display
41
+ const formatDiscount = (result: PromotionCodeValidationResult): string => {
42
+ if (result.discountType === "percent_off") {
43
+ return `${result.discountValue}% off`;
44
+ }
45
+ // amount_off is in cents, convert to dollars
46
+ const amount = (result.discountValue || 0) / 100;
47
+ const currency = result.currency?.toUpperCase() || "USD";
48
+ return `${currency} ${amount.toFixed(2)} off`;
49
+ };
50
+
51
+ // Format duration for display
52
+ const formatDuration = (result: PromotionCodeValidationResult): string => {
53
+ switch (result.duration) {
54
+ case "forever":
55
+ return "Applied to all payments";
56
+ case "once":
57
+ return "Applied to first payment only";
58
+ case "repeating":
59
+ return `Applied for ${result.durationInMonths} months`;
60
+ default:
61
+ return "";
62
+ }
63
+ };
64
+
65
+ // Show applied code state
66
+ if (appliedCode?.valid) {
67
+ return (
68
+ <div className="space-y-2">
69
+ <div className="flex items-center justify-between p-3 bg-green-50 border border-green-200 rounded-lg">
70
+ <div className="flex items-center gap-2">
71
+ <Check className="h-4 w-4 text-green-600" />
72
+ <span className="font-medium text-green-800">{appliedCode.code}</span>
73
+ <span className="text-sm text-green-600">{formatDiscount(appliedCode)}</span>
74
+ </div>
75
+ <Button
76
+ variant="ghost"
77
+ size="sm"
78
+ onClick={onRemove}
79
+ disabled={disabled}
80
+ className="text-green-700 hover:text-green-900 hover:bg-green-100"
81
+ >
82
+ <X className="h-4 w-4" />
83
+ </Button>
84
+ </div>
85
+ <p className="text-sm text-green-600">{formatDuration(appliedCode)}</p>
86
+ </div>
87
+ );
88
+ }
89
+
90
+ return (
91
+ <div className="space-y-2">
92
+ <div className="flex gap-2">
93
+ <Input
94
+ placeholder="Enter promo code"
95
+ value={code}
96
+ onChange={(e) => setCode(e.target.value.toUpperCase())}
97
+ onKeyDown={handleKeyDown}
98
+ disabled={disabled || isValidating}
99
+ className="flex-1"
100
+ />
101
+ <Button variant="outline" onClick={handleApply} disabled={disabled || isValidating || !code.trim()}>
102
+ {isValidating ? <Loader2 className="h-4 w-4 animate-spin" /> : "Apply"}
103
+ </Button>
104
+ </div>
105
+ {error && <p className="text-sm text-red-500">{error}</p>}
106
+ </div>
107
+ );
108
+ }
@@ -0,0 +1 @@
1
+ export * from "./PromoCodeInput";
@@ -0,0 +1,3 @@
1
+ export * from "./stripe-promotion-code.interface";
2
+ export * from "./stripe-promotion-code.service";
3
+ export * from "./stripe-promotion-code";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Promotion code validation result from the backend
3
+ */
4
+ export interface PromotionCodeValidationResult {
5
+ valid: boolean;
6
+ promotionCodeId?: string;
7
+ code: string;
8
+ discountType?: "percent_off" | "amount_off";
9
+ discountValue?: number;
10
+ currency?: string;
11
+ duration?: "forever" | "once" | "repeating";
12
+ durationInMonths?: number;
13
+ errorMessage?: string;
14
+ }
@@ -0,0 +1,64 @@
1
+ import { Modules } from "../../../../core";
2
+ import { JsonApiPost } from "../../../../unified/JsonApiRequest";
3
+ import { PromotionCodeValidationResult } from "./stripe-promotion-code.interface";
4
+ import { StripePromotionCode } from "./stripe-promotion-code";
5
+
6
+ const STRIPE_PROMOTION_CODE_ENDPOINT = "stripe-promotion-codes";
7
+
8
+ /**
9
+ * Service for validating Stripe promotion codes
10
+ */
11
+ export class StripePromotionCodeService {
12
+ /**
13
+ * Validate a promotion code against Stripe
14
+ *
15
+ * @param params.code - The promotion code to validate (e.g., "SAVE20")
16
+ * @param params.stripePriceId - Optional price ID to check product restrictions
17
+ * @param params.language - Language code for the request
18
+ * @returns Validation result with discount details if valid
19
+ */
20
+ static async validatePromotionCode(params: {
21
+ code: string;
22
+ stripePriceId?: string;
23
+ language?: string;
24
+ }): Promise<PromotionCodeValidationResult> {
25
+ const response = await JsonApiPost({
26
+ classKey: Modules.StripePromotionCode,
27
+ endpoint: `${STRIPE_PROMOTION_CODE_ENDPOINT}/validate`,
28
+ body: {
29
+ data: {
30
+ type: STRIPE_PROMOTION_CODE_ENDPOINT,
31
+ attributes: {
32
+ code: params.code,
33
+ stripePriceId: params.stripePriceId,
34
+ },
35
+ },
36
+ },
37
+ overridesJsonApiCreation: true,
38
+ language: params.language ?? "en",
39
+ });
40
+
41
+ if (!response.ok) {
42
+ return {
43
+ valid: false,
44
+ code: params.code,
45
+ errorMessage: response.error || "Failed to validate promotion code",
46
+ };
47
+ }
48
+
49
+ // The response is hydrated as a StripePromotionCode model
50
+ const data = response.data as StripePromotionCode;
51
+
52
+ return {
53
+ valid: data.valid,
54
+ promotionCodeId: data.promotionCodeId,
55
+ code: data.code,
56
+ discountType: data.discountType,
57
+ discountValue: data.discountValue,
58
+ currency: data.currency,
59
+ duration: data.duration,
60
+ durationInMonths: data.durationInMonths,
61
+ errorMessage: data.errorMessage,
62
+ };
63
+ }
64
+ }
@@ -0,0 +1,66 @@
1
+ import { AbstractApiData, JsonApiHydratedDataInterface } from "../../../../core";
2
+ import { PromotionCodeValidationResult } from "./stripe-promotion-code.interface";
3
+
4
+ export class StripePromotionCode extends AbstractApiData implements PromotionCodeValidationResult {
5
+ private _valid: boolean = false;
6
+ private _promotionCodeId?: string;
7
+ private _code: string = "";
8
+ private _discountType?: "percent_off" | "amount_off";
9
+ private _discountValue?: number;
10
+ private _currency?: string;
11
+ private _duration?: "forever" | "once" | "repeating";
12
+ private _durationInMonths?: number;
13
+ private _errorMessage?: string;
14
+
15
+ get valid(): boolean {
16
+ return this._valid;
17
+ }
18
+
19
+ get promotionCodeId(): string | undefined {
20
+ return this._promotionCodeId;
21
+ }
22
+
23
+ get code(): string {
24
+ return this._code;
25
+ }
26
+
27
+ get discountType(): "percent_off" | "amount_off" | undefined {
28
+ return this._discountType;
29
+ }
30
+
31
+ get discountValue(): number | undefined {
32
+ return this._discountValue;
33
+ }
34
+
35
+ get currency(): string | undefined {
36
+ return this._currency;
37
+ }
38
+
39
+ get duration(): "forever" | "once" | "repeating" | undefined {
40
+ return this._duration;
41
+ }
42
+
43
+ get durationInMonths(): number | undefined {
44
+ return this._durationInMonths;
45
+ }
46
+
47
+ get errorMessage(): string | undefined {
48
+ return this._errorMessage;
49
+ }
50
+
51
+ rehydrate(data: JsonApiHydratedDataInterface): this {
52
+ super.rehydrate(data);
53
+
54
+ this._valid = data.jsonApi.attributes.valid ?? false;
55
+ this._promotionCodeId = data.jsonApi.attributes.promotionCodeId;
56
+ this._code = data.jsonApi.attributes.code ?? "";
57
+ this._discountType = data.jsonApi.attributes.discountType;
58
+ this._discountValue = data.jsonApi.attributes.discountValue;
59
+ this._currency = data.jsonApi.attributes.currency;
60
+ this._duration = data.jsonApi.attributes.duration;
61
+ this._durationInMonths = data.jsonApi.attributes.durationInMonths;
62
+ this._errorMessage = data.jsonApi.attributes.errorMessage;
63
+
64
+ return this;
65
+ }
66
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./data";
2
+ export * from "./stripe-promotion-code.module";
@@ -0,0 +1,9 @@
1
+ import { ModuleFactory } from "../../../permissions";
2
+ import { StripePromotionCode } from "./data/stripe-promotion-code";
3
+
4
+ export const StripePromotionCodeModule = (factory: ModuleFactory) =>
5
+ factory({
6
+ name: "stripe-promotion-codes",
7
+ model: StripePromotionCode,
8
+ moduleId: "b8e4f6a2-9d0c-5b3f-c7e8-4g2d9f0a5c6e",
9
+ });