@greatapps/common 1.1.781 → 1.1.784
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/layouts/NavBar.mjs +2 -0
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/ui/form/PhoneInput.mjs +1 -1
- package/dist/components/ui/form/PhoneInput.mjs.map +1 -1
- package/dist/handlers.mjs +2 -0
- package/dist/handlers.mjs.map +1 -1
- package/dist/index.mjs +9 -1
- package/dist/index.mjs.map +1 -1
- package/dist/infra/api/client.mjs +5 -1
- package/dist/infra/api/client.mjs.map +1 -1
- package/dist/infra/api/types.mjs +1 -1
- package/dist/infra/api/types.mjs.map +1 -1
- package/dist/infra/route/safe-route-handler.mjs +4 -1
- package/dist/infra/route/safe-route-handler.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-account-not-frozen.mjs +6 -5
- package/dist/modules/auth/utils/assert-account-not-frozen.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-management-subscription.mjs +7 -14
- package/dist/modules/auth/utils/assert-management-subscription.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-paid-subscription.mjs +7 -12
- package/dist/modules/auth/utils/assert-paid-subscription.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-subscription-addon.mjs +2 -10
- package/dist/modules/auth/utils/assert-subscription-addon.mjs.map +1 -1
- package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/actions/get-current-subscription.action.mjs +10 -0
- package/dist/modules/subscriptions/actions/get-current-subscription.action.mjs.map +1 -0
- package/dist/modules/subscriptions/constants/subscription.constants.mjs +2 -0
- package/dist/modules/subscriptions/constants/subscription.constants.mjs.map +1 -1
- package/dist/modules/subscriptions/handlers/current-subscription.handler.mjs +17 -0
- package/dist/modules/subscriptions/handlers/current-subscription.handler.mjs.map +1 -0
- package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs +2 -13
- package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/hooks/use-current-subscription.hook.mjs +28 -0
- package/dist/modules/subscriptions/hooks/use-current-subscription.hook.mjs.map +1 -0
- package/dist/modules/subscriptions/services/subscriptions.service.mjs +26 -0
- package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -1
- package/dist/modules/subscriptions/types/subscription.type.mjs.map +1 -1
- package/dist/modules/subscriptions/utils/group-subscriptions-by-product.mjs +16 -0
- package/dist/modules/subscriptions/utils/group-subscriptions-by-product.mjs.map +1 -0
- package/dist/modules/subscriptions/utils/has-active-paid-subscription.mjs +1 -1
- package/dist/modules/subscriptions/utils/has-active-paid-subscription.mjs.map +1 -1
- package/dist/modules/subscriptions/utils/has-paid-subscription.mjs +1 -1
- package/dist/modules/subscriptions/utils/has-paid-subscription.mjs.map +1 -1
- package/dist/modules/subscriptions/utils/read-current-subscription.mjs +21 -0
- package/dist/modules/subscriptions/utils/read-current-subscription.mjs.map +1 -0
- package/dist/server.mjs +4 -0
- package/dist/server.mjs.map +1 -1
- package/dist/store/useMdSidebarStore.mjs +17 -4
- package/dist/store/useMdSidebarStore.mjs.map +1 -1
- package/dist/utils/safeServerAction.mjs +4 -1
- package/dist/utils/safeServerAction.mjs.map +1 -1
- package/dist/utils/withAction.mjs +2 -1
- package/dist/utils/withAction.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/NavBar.tsx +2 -0
- package/src/components/ui/form/PhoneInput.tsx +1 -1
- package/src/handlers.ts +1 -0
- package/src/index.ts +7 -1
- package/src/infra/api/client.ts +11 -3
- package/src/infra/api/types.ts +7 -5
- package/src/infra/route/safe-route-handler.ts +4 -1
- package/src/modules/auth/utils/assert-account-not-frozen.ts +7 -6
- package/src/modules/auth/utils/assert-management-subscription.ts +15 -23
- package/src/modules/auth/utils/assert-paid-subscription.ts +7 -15
- package/src/modules/auth/utils/assert-subscription-addon.ts +2 -12
- package/src/modules/plans/hooks/use-plan-by-id.hook.ts +1 -1
- package/src/modules/subscriptions/actions/get-current-subscription.action.ts +8 -0
- package/src/modules/subscriptions/constants/subscription.constants.ts +3 -0
- package/src/modules/subscriptions/handlers/current-subscription.handler.ts +16 -0
- package/src/modules/subscriptions/hooks/find-active-subscription.hook.ts +7 -17
- package/src/modules/subscriptions/hooks/use-current-subscription.hook.ts +38 -0
- package/src/modules/subscriptions/services/subscriptions.service.ts +34 -0
- package/src/modules/subscriptions/types/subscription.type.ts +2 -0
- package/src/modules/subscriptions/utils/group-subscriptions-by-product.ts +23 -0
- package/src/modules/subscriptions/utils/has-active-paid-subscription.ts +1 -2
- package/src/modules/subscriptions/utils/has-paid-subscription.ts +1 -2
- package/src/modules/subscriptions/utils/read-current-subscription.ts +34 -0
- package/src/server.ts +2 -0
- package/src/store/useMdSidebarStore.ts +20 -5
- package/src/utils/safeServerAction.ts +4 -6
- package/src/utils/withAction.ts +2 -1
package/dist/server.mjs
CHANGED
|
@@ -22,6 +22,8 @@ import { findUserById } from "./modules/users/action/find-user-by-id.action";
|
|
|
22
22
|
import { findCurrentAccount } from "./modules/accounts/actions/find-current-account.action";
|
|
23
23
|
import { getAccountTokenAction } from "./modules/accounts/actions/get-account-token.action";
|
|
24
24
|
import { listSubscriptionsAction } from "./modules/subscriptions/actions/list-subscriptions.action";
|
|
25
|
+
import { getCurrentSubscriptionAction } from "./modules/subscriptions/actions/get-current-subscription.action";
|
|
26
|
+
import { readCurrentSubscription } from "./modules/subscriptions/utils/read-current-subscription";
|
|
25
27
|
import { ackFreezeNoticeAction } from "./modules/subscriptions/actions/ack-freeze-notice.action";
|
|
26
28
|
import { calculateSubscriptionAction } from "./modules/subscriptions/actions/calculate-subscription.action";
|
|
27
29
|
import { updateSubscriptionPlanAction } from "./modules/subscriptions/actions/update-subscription-plan.action";
|
|
@@ -110,6 +112,7 @@ export {
|
|
|
110
112
|
generateTwoFactorAction,
|
|
111
113
|
getAccountTokenAction,
|
|
112
114
|
getClientInfoFromRequest,
|
|
115
|
+
getCurrentSubscriptionAction,
|
|
113
116
|
getUserContext,
|
|
114
117
|
hasActivePaidSubscription,
|
|
115
118
|
hasSubscriptionExpired,
|
|
@@ -123,6 +126,7 @@ export {
|
|
|
123
126
|
processImageAction,
|
|
124
127
|
projectUsersService,
|
|
125
128
|
projectsService,
|
|
129
|
+
readCurrentSubscription,
|
|
126
130
|
removeProjectUserAction,
|
|
127
131
|
requestEmailChangeAction,
|
|
128
132
|
requestPhoneChangeAction,
|
package/dist/server.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { ApiClient, api, apiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\nexport { revalidateWhitelabelAction } from './modules/whitelabel/actions/revalidate-whitelabel.action';\r\nexport { assertManagementPermission } from './modules/auth/utils/assert-management-permission';\r\nexport { assertManagementSubscription } from './modules/auth/utils/assert-management-subscription';\r\nexport { assertSubscriptionAddon } from './modules/auth/utils/assert-subscription-addon';\r\nexport { assertPaidSubscription } from './modules/auth/utils/assert-paid-subscription';\r\nexport { assertAccountNotFrozen } from './modules/auth/utils/assert-account-not-frozen';\r\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\r\nexport { plansService } from './modules/plans/services/plans.service';\r\nexport { cardsService } from './modules/cards/services/cards.service';\r\nexport { chargesService } from './modules/charges/services/charges.service';\r\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\nexport { socialGoogleLoginAction } from './modules/auth/actions/social-google-login.action';\r\nexport { socialGoogleOnboardingAction } from './modules/auth/actions/social-google-onboarding.action';\r\nexport { unlinkGoogleAction } from './modules/auth/actions/unlink-google.action';\r\nexport { findUserById } from './modules/users/action/find-user-by-id.action';\r\nexport { findCurrentAccount } from './modules/accounts/actions/find-current-account.action';\r\nexport { getAccountTokenAction } from './modules/accounts/actions/get-account-token.action';\r\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\r\nexport { ackFreezeNoticeAction } from './modules/subscriptions/actions/ack-freeze-notice.action';\r\nexport { calculateSubscriptionAction } from './modules/subscriptions/actions/calculate-subscription.action';\r\nexport { updateSubscriptionPlanAction } from './modules/subscriptions/actions/update-subscription-plan.action';\r\nexport { updateSubscriptionPaymentAction } from './modules/subscriptions/actions/update-subscription-payment.action';\r\nexport { createCardAction } from './modules/cards/actions/create-card.action';\r\nexport { createSetupIntentAction } from './modules/cards/actions/create-setup-intent.action';\r\nexport { chargeActionAction } from './modules/charges/actions/charge-action.action';\r\nexport { resolvePlanExtrasPrices } from './modules/subscriptions/utils/resolve-plan-extras-prices';\r\nexport { hasSubscriptionExpired } from './modules/subscriptions/utils/has-subscription-expired';\r\nexport { hasActivePaidSubscription } from './modules/subscriptions/utils/has-active-paid-subscription';\r\n\r\n// Project Services & Actions (server-only)\r\nexport { projectsService } from './modules/projects/services/projects.service';\r\nexport { listProjectsAction } from './modules/projects/actions/list-projects.action';\r\nexport { findProjectAction } from './modules/projects/actions/find-project.action';\r\nexport { createProjectAction } from './modules/projects/actions/create-project.action';\r\nexport { updateProjectAction } from './modules/projects/actions/update-project.action';\r\nexport { deleteProjectAction } from './modules/projects/actions/delete-project.action';\r\n\r\n// Project Users Services & Actions (server-only)\r\nexport { projectUsersService } from './modules/projects/services/project-users.service';\r\nexport { listProjectUsersAction } from './modules/projects/actions/list-project-users.action';\r\nexport { addProjectUserAction } from './modules/projects/actions/add-project-user.action';\r\nexport { removeProjectUserAction } from './modules/projects/actions/remove-project-user.action';\r\n\r\n// Account Services & Actions (server-only)\r\nexport { accountService } from './modules/accounts/services/account.service';\r\nexport { twoFactorService } from './modules/accounts/services/two-factor.service';\r\nexport {\r\n listAccountUsersAction,\r\n updateUserAction,\r\n updateAccountAction,\r\n updateAccountUserByIdAction,\r\n updateBillingDataAction,\r\n deleteAccountUserAction,\r\n deleteAccountAction,\r\n createAccountUserAction,\r\n changePasswordAction,\r\n requestEmailChangeAction,\r\n confirmEmailChangeAction,\r\n requestPhoneChangeAction,\r\n confirmPhoneChangeAction,\r\n generateTwoFactorAction,\r\n confirmTwoFactorAction,\r\n disableTwoFactorAction,\r\n} from './modules/accounts/actions/account-management.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\nexport { getUserContext } from './modules/auth/utils/get-user-context';\r\nexport { resolveLocale } from './i18n/resolve-locale';\r\nexport type { ResolveLocaleOptions } from './i18n/resolve-locale';\r\nexport { requireValidSession } from './modules/auth/utils/require-valid-session';\r\nexport { requireTokenNotExpired } from './modules/auth/utils/require-token-not-expired';\r\nexport { buildWlOverride, buildWlOverrideFromJwt } from './modules/auth/utils/build-wl-override';\r\nexport { safeServerAction } from './utils/safeServerAction';\r\nexport { safeMutationAction } from './utils/safeMutationAction';\r\n\r\n// Image Processing (server-side)\r\nexport { processImageAction } from './modules/images/actions/process-image.action';\r\nexport { processImage } from './modules/images/services/image-processing.service';\r\nexport type {\r\n ProcessImageInput,\r\n ProcessImageOutput,\r\n ProcessImageActionInput,\r\n ProcessImageActionOutput,\r\n} from './modules/images/types/image.type';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kCAAkC;AAC3C,SAAS,kCAAkC;AAC3C,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,6BAA6B;AACtC,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,uCAAuC;AAChD,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,iCAAiC;AAG1C,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAGpC,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AAGxC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAE9B,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,iBAAiB,8BAA8B;AACxD,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAGnC,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { ApiClient, api, apiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\nexport { revalidateWhitelabelAction } from './modules/whitelabel/actions/revalidate-whitelabel.action';\r\nexport { assertManagementPermission } from './modules/auth/utils/assert-management-permission';\r\nexport { assertManagementSubscription } from './modules/auth/utils/assert-management-subscription';\r\nexport { assertSubscriptionAddon } from './modules/auth/utils/assert-subscription-addon';\r\nexport { assertPaidSubscription } from './modules/auth/utils/assert-paid-subscription';\r\nexport { assertAccountNotFrozen } from './modules/auth/utils/assert-account-not-frozen';\r\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\r\nexport { plansService } from './modules/plans/services/plans.service';\r\nexport { cardsService } from './modules/cards/services/cards.service';\r\nexport { chargesService } from './modules/charges/services/charges.service';\r\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\nexport { socialGoogleLoginAction } from './modules/auth/actions/social-google-login.action';\r\nexport { socialGoogleOnboardingAction } from './modules/auth/actions/social-google-onboarding.action';\r\nexport { unlinkGoogleAction } from './modules/auth/actions/unlink-google.action';\r\nexport { findUserById } from './modules/users/action/find-user-by-id.action';\r\nexport { findCurrentAccount } from './modules/accounts/actions/find-current-account.action';\r\nexport { getAccountTokenAction } from './modules/accounts/actions/get-account-token.action';\r\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\r\nexport { getCurrentSubscriptionAction } from './modules/subscriptions/actions/get-current-subscription.action';\r\nexport { readCurrentSubscription } from './modules/subscriptions/utils/read-current-subscription';\r\nexport { ackFreezeNoticeAction } from './modules/subscriptions/actions/ack-freeze-notice.action';\r\nexport { calculateSubscriptionAction } from './modules/subscriptions/actions/calculate-subscription.action';\r\nexport { updateSubscriptionPlanAction } from './modules/subscriptions/actions/update-subscription-plan.action';\r\nexport { updateSubscriptionPaymentAction } from './modules/subscriptions/actions/update-subscription-payment.action';\r\nexport { createCardAction } from './modules/cards/actions/create-card.action';\r\nexport { createSetupIntentAction } from './modules/cards/actions/create-setup-intent.action';\r\nexport { chargeActionAction } from './modules/charges/actions/charge-action.action';\r\nexport { resolvePlanExtrasPrices } from './modules/subscriptions/utils/resolve-plan-extras-prices';\r\nexport { hasSubscriptionExpired } from './modules/subscriptions/utils/has-subscription-expired';\r\nexport { hasActivePaidSubscription } from './modules/subscriptions/utils/has-active-paid-subscription';\r\n\r\n// Project Services & Actions (server-only)\r\nexport { projectsService } from './modules/projects/services/projects.service';\r\nexport { listProjectsAction } from './modules/projects/actions/list-projects.action';\r\nexport { findProjectAction } from './modules/projects/actions/find-project.action';\r\nexport { createProjectAction } from './modules/projects/actions/create-project.action';\r\nexport { updateProjectAction } from './modules/projects/actions/update-project.action';\r\nexport { deleteProjectAction } from './modules/projects/actions/delete-project.action';\r\n\r\n// Project Users Services & Actions (server-only)\r\nexport { projectUsersService } from './modules/projects/services/project-users.service';\r\nexport { listProjectUsersAction } from './modules/projects/actions/list-project-users.action';\r\nexport { addProjectUserAction } from './modules/projects/actions/add-project-user.action';\r\nexport { removeProjectUserAction } from './modules/projects/actions/remove-project-user.action';\r\n\r\n// Account Services & Actions (server-only)\r\nexport { accountService } from './modules/accounts/services/account.service';\r\nexport { twoFactorService } from './modules/accounts/services/two-factor.service';\r\nexport {\r\n listAccountUsersAction,\r\n updateUserAction,\r\n updateAccountAction,\r\n updateAccountUserByIdAction,\r\n updateBillingDataAction,\r\n deleteAccountUserAction,\r\n deleteAccountAction,\r\n createAccountUserAction,\r\n changePasswordAction,\r\n requestEmailChangeAction,\r\n confirmEmailChangeAction,\r\n requestPhoneChangeAction,\r\n confirmPhoneChangeAction,\r\n generateTwoFactorAction,\r\n confirmTwoFactorAction,\r\n disableTwoFactorAction,\r\n} from './modules/accounts/actions/account-management.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\nexport { getUserContext } from './modules/auth/utils/get-user-context';\r\nexport { resolveLocale } from './i18n/resolve-locale';\r\nexport type { ResolveLocaleOptions } from './i18n/resolve-locale';\r\nexport { requireValidSession } from './modules/auth/utils/require-valid-session';\r\nexport { requireTokenNotExpired } from './modules/auth/utils/require-token-not-expired';\r\nexport { buildWlOverride, buildWlOverrideFromJwt } from './modules/auth/utils/build-wl-override';\r\nexport { safeServerAction } from './utils/safeServerAction';\r\nexport { safeMutationAction } from './utils/safeMutationAction';\r\n\r\n// Image Processing (server-side)\r\nexport { processImageAction } from './modules/images/actions/process-image.action';\r\nexport { processImage } from './modules/images/services/image-processing.service';\r\nexport type {\r\n ProcessImageInput,\r\n ProcessImageOutput,\r\n ProcessImageActionInput,\r\n ProcessImageActionOutput,\r\n} from './modules/images/types/image.type';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kCAAkC;AAC3C,SAAS,kCAAkC;AAC3C,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,6BAA6B;AACtC,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,uCAAuC;AAChD,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,iCAAiC;AAG1C,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAGpC,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AAGxC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAE9B,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,iBAAiB,8BAA8B;AACxD,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAGnC,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;","names":[]}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { create } from "zustand";
|
|
2
|
+
import { useEffect } from "react";
|
|
2
3
|
import { readStorage, writeStorage } from "../utils/browser/safe-storage";
|
|
3
4
|
const STORAGE_KEY = "md-sidebar-expanded";
|
|
4
|
-
function getInitialState() {
|
|
5
|
-
return readStorage(STORAGE_KEY) === "true";
|
|
6
|
-
}
|
|
7
5
|
const useMdSidebarStore = create((set) => ({
|
|
8
|
-
isExpanded:
|
|
6
|
+
isExpanded: false,
|
|
7
|
+
_hydrated: false,
|
|
9
8
|
toggle: () => set((state) => {
|
|
10
9
|
const next = !state.isExpanded;
|
|
11
10
|
writeStorage(STORAGE_KEY, String(next));
|
|
@@ -18,9 +17,23 @@ const useMdSidebarStore = create((set) => ({
|
|
|
18
17
|
collapse: () => {
|
|
19
18
|
writeStorage(STORAGE_KEY, "false");
|
|
20
19
|
return set({ isExpanded: false });
|
|
20
|
+
},
|
|
21
|
+
_hydrate: () => {
|
|
22
|
+
const value = readStorage(STORAGE_KEY) === "true";
|
|
23
|
+
set({ isExpanded: value, _hydrated: true });
|
|
21
24
|
}
|
|
22
25
|
}));
|
|
26
|
+
function useMdSidebarHydration() {
|
|
27
|
+
const hydrate = useMdSidebarStore((s) => s._hydrate);
|
|
28
|
+
const hydrated = useMdSidebarStore((s) => s._hydrated);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!hydrated) {
|
|
31
|
+
hydrate();
|
|
32
|
+
}
|
|
33
|
+
}, [hydrate, hydrated]);
|
|
34
|
+
}
|
|
23
35
|
export {
|
|
36
|
+
useMdSidebarHydration,
|
|
24
37
|
useMdSidebarStore
|
|
25
38
|
};
|
|
26
39
|
//# sourceMappingURL=useMdSidebarStore.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/store/useMdSidebarStore.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { readStorage, writeStorage } from \"../utils/browser/safe-storage\";\n\nconst STORAGE_KEY = \"md-sidebar-expanded\";\n\
|
|
1
|
+
{"version":3,"sources":["../../src/store/useMdSidebarStore.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { useEffect } from \"react\";\nimport { readStorage, writeStorage } from \"../utils/browser/safe-storage\";\n\nconst STORAGE_KEY = \"md-sidebar-expanded\";\n\ntype MdSidebarStore = {\n isExpanded: boolean;\n _hydrated: boolean;\n toggle: () => void;\n expand: () => void;\n collapse: () => void;\n _hydrate: () => void;\n};\n\nexport const useMdSidebarStore = create<MdSidebarStore>((set) => ({\n isExpanded: false,\n _hydrated: false,\n toggle: () => set((state) => {\n const next = !state.isExpanded;\n writeStorage(STORAGE_KEY, String(next));\n return { isExpanded: next };\n }),\n expand: () => {\n writeStorage(STORAGE_KEY, \"true\");\n return set({ isExpanded: true });\n },\n collapse: () => {\n writeStorage(STORAGE_KEY, \"false\");\n return set({ isExpanded: false });\n },\n _hydrate: () => {\n const value = readStorage(STORAGE_KEY) === \"true\";\n set({ isExpanded: value, _hydrated: true });\n },\n}));\n\nexport function useMdSidebarHydration() {\n const hydrate = useMdSidebarStore((s) => s._hydrate);\n const hydrated = useMdSidebarStore((s) => s._hydrated);\n\n useEffect(() => {\n if (!hydrated) {\n hydrate();\n }\n }, [hydrate, hydrated]);\n}\n"],"mappings":"AAAA,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAC1B,SAAS,aAAa,oBAAoB;AAE1C,MAAM,cAAc;AAWb,MAAM,oBAAoB,OAAuB,CAAC,SAAS;AAAA,EAC9D,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,QAAQ,MAAM,IAAI,CAAC,UAAU;AACzB,UAAM,OAAO,CAAC,MAAM;AACpB,iBAAa,aAAa,OAAO,IAAI,CAAC;AACtC,WAAO,EAAE,YAAY,KAAK;AAAA,EAC9B,CAAC;AAAA,EACD,QAAQ,MAAM;AACV,iBAAa,aAAa,MAAM;AAChC,WAAO,IAAI,EAAE,YAAY,KAAK,CAAC;AAAA,EACnC;AAAA,EACA,UAAU,MAAM;AACZ,iBAAa,aAAa,OAAO;AACjC,WAAO,IAAI,EAAE,YAAY,MAAM,CAAC;AAAA,EACpC;AAAA,EACA,UAAU,MAAM;AACZ,UAAM,QAAQ,YAAY,WAAW,MAAM;AAC3C,QAAI,EAAE,YAAY,OAAO,WAAW,KAAK,CAAC;AAAA,EAC9C;AACJ,EAAE;AAEK,SAAS,wBAAwB;AACpC,QAAM,UAAU,kBAAkB,CAAC,MAAM,EAAE,QAAQ;AACnD,QAAM,WAAW,kBAAkB,CAAC,MAAM,EAAE,SAAS;AAErD,YAAU,MAAM;AACZ,QAAI,CAAC,UAAU;AACX,cAAQ;AAAA,IACZ;AAAA,EACJ,GAAG,CAAC,SAAS,QAAQ,CAAC;AAC1B;","names":[]}
|
|
@@ -6,7 +6,10 @@ async function safeServerAction(fn) {
|
|
|
6
6
|
return { success: true, data };
|
|
7
7
|
} catch (error) {
|
|
8
8
|
if (isRedirectError(error)) throw error;
|
|
9
|
-
|
|
9
|
+
if (error instanceof ApiError) {
|
|
10
|
+
return { success: false, error: error.message, code: error.code, statusCode: error.statusCode };
|
|
11
|
+
}
|
|
12
|
+
const message = error instanceof Error ? error.message : "Erro desconhecido";
|
|
10
13
|
return { success: false, error: message };
|
|
11
14
|
}
|
|
12
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/safeServerAction.ts"],"sourcesContent":["import { isRedirectError } from 'next/dist/client/components/redirect-error';\nimport { ApiError } from '../infra/api/types';\nimport type { ActionResult } from '../infra/api/types';\n\nexport async function safeServerAction<T>(\n fn: () => Promise<T>\n): Promise<ActionResult<T>> {\n try {\n const data = await fn();\n return { success: true, data };\n } catch (error) {\n if (isRedirectError(error)) throw error;\n
|
|
1
|
+
{"version":3,"sources":["../../src/utils/safeServerAction.ts"],"sourcesContent":["import { isRedirectError } from 'next/dist/client/components/redirect-error';\nimport { ApiError } from '../infra/api/types';\nimport type { ActionResult } from '../infra/api/types';\n\nexport async function safeServerAction<T>(\n fn: () => Promise<T>\n): Promise<ActionResult<T>> {\n try {\n const data = await fn();\n return { success: true, data };\n } catch (error) {\n if (isRedirectError(error)) throw error;\n if (error instanceof ApiError) {\n return { success: false, error: error.message, code: error.code, statusCode: error.statusCode };\n }\n const message = error instanceof Error ? error.message : 'Erro desconhecido';\n return { success: false, error: message };\n }\n}\n"],"mappings":"AAAA,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AAGzB,eAAsB,iBACpB,IAC0B;AAC1B,MAAI;AACF,UAAM,OAAO,MAAM,GAAG;AACtB,WAAO,EAAE,SAAS,MAAM,KAAK;AAAA,EAC/B,SAAS,OAAO;AACd,QAAI,gBAAgB,KAAK,EAAG,OAAM;AAClC,QAAI,iBAAiB,UAAU;AAC7B,aAAO,EAAE,SAAS,OAAO,OAAO,MAAM,SAAS,MAAM,MAAM,MAAM,YAAY,MAAM,WAAW;AAAA,IAChG;AACA,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,WAAO,EAAE,SAAS,OAAO,OAAO,QAAQ;AAAA,EAC1C;AACF;","names":[]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { ApiError } from "../infra/api/types";
|
|
1
2
|
function withAction(action) {
|
|
2
3
|
return async (...args) => {
|
|
3
4
|
const result = await action(...args);
|
|
4
5
|
if (!result.success) {
|
|
5
|
-
throw new
|
|
6
|
+
throw new ApiError(result.error, result.code, result.statusCode);
|
|
6
7
|
}
|
|
7
8
|
return result.data;
|
|
8
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/withAction.ts"],"sourcesContent":["import type { ActionResult } from '../infra/api/types';\n\nexport function withAction<TArgs extends any[], TData>(\n action: (...args: TArgs) => Promise<ActionResult<TData>>\n): (...args: TArgs) => Promise<TData> {\n return async (...args) => {\n const result = await action(...args);\n if (!result.success) {\n throw new
|
|
1
|
+
{"version":3,"sources":["../../src/utils/withAction.ts"],"sourcesContent":["import { ApiError } from '../infra/api/types';\nimport type { ActionResult } from '../infra/api/types';\n\nexport function withAction<TArgs extends any[], TData>(\n action: (...args: TArgs) => Promise<ActionResult<TData>>\n): (...args: TArgs) => Promise<TData> {\n return async (...args) => {\n const result = await action(...args);\n if (!result.success) {\n throw new ApiError(result.error, result.code, result.statusCode);\n }\n return result.data as TData;\n };\n}\n"],"mappings":"AAAA,SAAS,gBAAgB;AAGlB,SAAS,WACd,QACoC;AACpC,SAAO,UAAU,SAAS;AACxB,UAAM,SAAS,MAAM,OAAO,GAAG,IAAI;AACnC,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,SAAS,OAAO,OAAO,OAAO,MAAM,OAAO,UAAU;AAAA,IACjE;AACA,WAAO,OAAO;AAAA,EAChB;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
useDesktopSidebarStore,
|
|
13
13
|
useDesktopSidebarHydration,
|
|
14
14
|
} from "../../store/useDesktopSidebarStore";
|
|
15
|
+
import { useMdSidebarHydration } from "../../store/useMdSidebarStore";
|
|
15
16
|
import {
|
|
16
17
|
useWhitelabel,
|
|
17
18
|
useIsDefaultWhitelabel,
|
|
@@ -44,6 +45,7 @@ function NavBar({
|
|
|
44
45
|
const { isExpanded: isDesktopExpanded, toggle: toggleDesktop } =
|
|
45
46
|
useDesktopSidebarStore();
|
|
46
47
|
useDesktopSidebarHydration();
|
|
48
|
+
useMdSidebarHydration();
|
|
47
49
|
const { whitelabel } = useWhitelabel();
|
|
48
50
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
49
51
|
const primaryColor = whitelabel?.general?.primary_color;
|
|
@@ -45,7 +45,7 @@ export default function PhoneInput({
|
|
|
45
45
|
const translate = useTranslations();
|
|
46
46
|
const parsed = parsePhoneValue(value ?? '');
|
|
47
47
|
const [selectedCountry, setSelectedCountry] = useState<Country>(parsed.country);
|
|
48
|
-
const [phoneNumber, setPhoneNumber] = useState(parsed.number);
|
|
48
|
+
const [phoneNumber, setPhoneNumber] = useState(formatNational(parsed.number, parsed.country.iso));
|
|
49
49
|
const [search, setSearch] = useState('');
|
|
50
50
|
const [open, setOpen] = useState(false);
|
|
51
51
|
const prevValueRef = useRef(value);
|
package/src/handlers.ts
CHANGED
|
@@ -20,6 +20,7 @@ export { createListAvailableUsersHandler } from './modules/projects/handlers/lis
|
|
|
20
20
|
export { createListAllAccountUsersHandler } from './modules/projects/handlers/list-all-account-users.handler';
|
|
21
21
|
|
|
22
22
|
export { createListSubscriptionsHandler } from './modules/subscriptions/handlers/list-subscriptions.handler';
|
|
23
|
+
export { createCurrentSubscriptionHandler } from './modules/subscriptions/handlers/current-subscription.handler';
|
|
23
24
|
export { createFreezeNoticeHandler } from './modules/subscriptions/handlers/freeze-notice.handler';
|
|
24
25
|
|
|
25
26
|
export { createListMessagesHandler } from './modules/users/handlers/list-messages.handler';
|
package/src/index.ts
CHANGED
|
@@ -86,6 +86,8 @@ export {
|
|
|
86
86
|
CHARGES_QUERY_KEY,
|
|
87
87
|
FREEZE_NOTICE_QUERY_KEY,
|
|
88
88
|
} from "./modules/subscriptions/constants/query-keys.constants";
|
|
89
|
+
export { useCurrentSubscription } from "./modules/subscriptions/hooks/use-current-subscription.hook";
|
|
90
|
+
/** @deprecated Use `useCurrentSubscription`. Sai na 1.1.784. */
|
|
89
91
|
export { useActiveSubscription } from "./modules/subscriptions/hooks/find-active-subscription.hook";
|
|
90
92
|
export { useCancelledSubscriptionGuard } from "./modules/subscriptions/hooks/use-cancelled-subscription-guard";
|
|
91
93
|
export { useAccountFreeze } from "./modules/subscriptions/hooks/use-account-freeze.hook";
|
|
@@ -221,7 +223,11 @@ export {
|
|
|
221
223
|
confirmPaymentIfRequired,
|
|
222
224
|
PaymentAuthenticationError,
|
|
223
225
|
} from "./modules/subscriptions/utils/confirm-payment-if-required";
|
|
224
|
-
export {
|
|
226
|
+
export {
|
|
227
|
+
SUBSCRIPTION_GRACE_PERIOD_DAYS,
|
|
228
|
+
FREE_PLAN_ID,
|
|
229
|
+
} from "./modules/subscriptions/constants/subscription.constants";
|
|
230
|
+
export { groupSubscriptionsByProduct } from "./modules/subscriptions/utils/group-subscriptions-by-product";
|
|
225
231
|
export { getSubscriptionCancellationState } from "./modules/subscriptions/utils/get-subscription-cancellation-state";
|
|
226
232
|
export type { SubscriptionCancellationState } from "./modules/subscriptions/utils/get-subscription-cancellation-state";
|
|
227
233
|
export {
|
package/src/infra/api/client.ts
CHANGED
|
@@ -31,6 +31,11 @@ export interface ApiClientOptions {
|
|
|
31
31
|
emitLogs?: boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
interface ApiErrorResponseBody {
|
|
35
|
+
message?: string | { message?: string };
|
|
36
|
+
code?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
export interface RequestConfig extends RequestInit {
|
|
35
40
|
timeout?: number;
|
|
36
41
|
/** Padrão `json`. Use `text` quando a API devolve corpo não-JSON. */
|
|
@@ -169,9 +174,12 @@ class ApiClient {
|
|
|
169
174
|
let message = `HTTP error ${response.status} ${response.statusText} ${errBody}`;
|
|
170
175
|
let code = "HTTP_ERROR";
|
|
171
176
|
try {
|
|
172
|
-
const errorData = JSON.parse(errBody)
|
|
173
|
-
|
|
174
|
-
|
|
177
|
+
const errorData: ApiErrorResponseBody = JSON.parse(errBody);
|
|
178
|
+
if (typeof errorData.message === "string") {
|
|
179
|
+
message = errorData.message;
|
|
180
|
+
} else if (errorData.message?.message) {
|
|
181
|
+
message = errorData.message.message;
|
|
182
|
+
}
|
|
175
183
|
if (typeof errorData.code === "string") code = errorData.code;
|
|
176
184
|
} catch {
|
|
177
185
|
if (errBody.trim()) message = errBody.trim();
|
package/src/infra/api/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
|
|
3
|
-
export const PaginationParamsSchema = z.object({
|
|
4
|
-
page: z.number().min(1).optional().default(1),
|
|
5
|
-
limit: z.number().optional().default(20),
|
|
6
|
-
});
|
|
3
|
+
export const PaginationParamsSchema = z.object({
|
|
4
|
+
page: z.number().min(1).optional().default(1),
|
|
5
|
+
limit: z.number().optional().default(20),
|
|
6
|
+
});
|
|
7
7
|
|
|
8
8
|
export interface PaginationParams extends z.infer<typeof PaginationParamsSchema> {}
|
|
9
9
|
|
|
@@ -51,6 +51,8 @@ export interface PaginatedSuccessResult<T> extends Omit<SuccessResult<T>, 'data'
|
|
|
51
51
|
export interface ErrorResult {
|
|
52
52
|
success: false;
|
|
53
53
|
error?: string;
|
|
54
|
+
code?: string;
|
|
55
|
+
statusCode?: number;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export type ActionResult<T> = SuccessResult<T> | ErrorResult;
|
|
@@ -60,7 +62,7 @@ export class ApiError extends Error {
|
|
|
60
62
|
public readonly code: string;
|
|
61
63
|
public readonly statusCode: number;
|
|
62
64
|
|
|
63
|
-
constructor(message: string, code: string = 'UNKNOWN_ERROR', statusCode: number = 500) {
|
|
65
|
+
constructor(message: string = 'Erro desconhecido', code: string = 'UNKNOWN_ERROR', statusCode: number = 500) {
|
|
64
66
|
super(message);
|
|
65
67
|
this.name = 'ApiError';
|
|
66
68
|
this.code = code;
|
|
@@ -8,7 +8,10 @@ export async function safeRouteHandler<T>(fn: () => Promise<T>): Promise<Respons
|
|
|
8
8
|
return Response.json({ success: true, data });
|
|
9
9
|
} catch (error) {
|
|
10
10
|
if (error instanceof ApiError) {
|
|
11
|
-
return Response.json(
|
|
11
|
+
return Response.json(
|
|
12
|
+
{ success: false, error: error.message, code: error.code },
|
|
13
|
+
{ status: error.statusCode },
|
|
14
|
+
);
|
|
12
15
|
}
|
|
13
16
|
console.error('[safeRouteHandler] erro inesperado', error);
|
|
14
17
|
return Response.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
|
|
3
3
|
import { ApiError } from "../../../infra/api/types";
|
|
4
|
-
import {
|
|
4
|
+
import { readCurrentSubscription } from "../../subscriptions/utils/read-current-subscription";
|
|
5
5
|
import { getAccountFreezeState } from "../../subscriptions/utils/get-account-freeze-state";
|
|
6
|
+
import type { Subscription } from "../../subscriptions/types/subscription.type";
|
|
6
7
|
|
|
7
8
|
export async function assertAccountNotFrozen(): Promise<void> {
|
|
8
|
-
|
|
9
|
+
let subscription: Subscription | null;
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
try {
|
|
12
|
+
subscription = await readCurrentSubscription();
|
|
13
|
+
} catch (error) {
|
|
11
14
|
console.error(
|
|
12
15
|
"[assertAccountNotFrozen] failed to read subscription context:",
|
|
13
|
-
|
|
16
|
+
error,
|
|
14
17
|
);
|
|
15
18
|
return;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
const subscription = result.data?.data?.[0];
|
|
19
|
-
|
|
20
21
|
if (!subscription) return;
|
|
21
22
|
|
|
22
23
|
if (getAccountFreezeState(subscription) !== "frozen") return;
|
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
|
|
3
|
-
import { cache } from "react";
|
|
4
|
-
|
|
5
3
|
import { ApiError } from "../../../infra/api/types";
|
|
6
|
-
import {
|
|
4
|
+
import { readCurrentSubscription } from "../../subscriptions/utils/read-current-subscription";
|
|
5
|
+
import { getSubscriptionCancellationState } from "../../subscriptions/utils/get-subscription-cancellation-state";
|
|
7
6
|
import { getSubscriptionExpiryDate } from "../../subscriptions/utils/get-subscription-expiry-date";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
9
|
+
* A leitura por trás (`readCurrentSubscription`) já é deduplicada por request via
|
|
10
|
+
* React.cache, então não precisa de outra camada aqui: em produção (26/08) o mesmo
|
|
11
|
+
* carregamento disparava até quatro cópias da mesma pergunta em paralelo, com 727 ms,
|
|
12
|
+
* 4,2 s, 5,0 s e 7,0 s, contra um p50 de 528 ms; agora é uma leitura só,
|
|
13
|
+
* compartilhada pelos quatro gates.
|
|
11
14
|
*
|
|
12
|
-
* A
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* p50 de 528 ms para o endpoint. Elas se atrasam entre si: são cópias da mesma pergunta disputando
|
|
16
|
-
* a mesma fila.
|
|
15
|
+
* A checagem de cancelamento é obrigatória além da de vencimento: a corrente pode
|
|
16
|
+
* vir com `active: false` (baixa por falha de pagamento) com `date_due` ainda no
|
|
17
|
+
* futuro, caso que só `getSubscriptionExpiryDate` não cobre.
|
|
17
18
|
*/
|
|
18
|
-
export
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
if (!result.success) {
|
|
22
|
-
throw new ApiError(
|
|
23
|
-
result.error || "Não foi possível validar a assinatura atual",
|
|
24
|
-
"SUBSCRIPTION_CONTEXT_FAILED",
|
|
25
|
-
403,
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const subscription = result.data?.data?.[0];
|
|
19
|
+
export async function assertManagementSubscription(): Promise<void> {
|
|
20
|
+
const subscription = await readCurrentSubscription();
|
|
30
21
|
|
|
31
22
|
if (!subscription) {
|
|
32
23
|
throw new ApiError(
|
|
@@ -36,14 +27,15 @@ export const assertManagementSubscription = cache(async () => {
|
|
|
36
27
|
);
|
|
37
28
|
}
|
|
38
29
|
|
|
30
|
+
const isCancelled = getSubscriptionCancellationState(subscription) === "cancelled";
|
|
39
31
|
const expiryDate = getSubscriptionExpiryDate(subscription);
|
|
40
32
|
const isExpired = !!expiryDate && Date.now() >= expiryDate.getTime();
|
|
41
33
|
|
|
42
|
-
if (isExpired) {
|
|
34
|
+
if (isCancelled || isExpired) {
|
|
43
35
|
throw new ApiError(
|
|
44
36
|
"Sua assinatura está vencida. Assine um novo plano para continuar.",
|
|
45
37
|
"SUBSCRIPTION_EXPIRED",
|
|
46
38
|
403,
|
|
47
39
|
);
|
|
48
40
|
}
|
|
49
|
-
}
|
|
41
|
+
}
|
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
|
|
3
3
|
import { ApiError } from "../../../infra/api/types";
|
|
4
|
-
import {
|
|
4
|
+
import { readCurrentSubscription } from "../../subscriptions/utils/read-current-subscription";
|
|
5
|
+
import { getSubscriptionCancellationState } from "../../subscriptions/utils/get-subscription-cancellation-state";
|
|
5
6
|
import { getSubscriptionExpiryDate } from "../../subscriptions/utils/get-subscription-expiry-date";
|
|
7
|
+
import { FREE_PLAN_ID } from "../../subscriptions/constants/subscription.constants";
|
|
6
8
|
|
|
7
9
|
export async function assertPaidSubscription() {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
if (!result.success) {
|
|
11
|
-
throw new ApiError(
|
|
12
|
-
result.error || "Não foi possível validar a assinatura atual",
|
|
13
|
-
"SUBSCRIPTION_CONTEXT_FAILED",
|
|
14
|
-
403,
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const subscription = result.data?.data?.[0];
|
|
10
|
+
const subscription = await readCurrentSubscription();
|
|
19
11
|
|
|
20
12
|
if (!subscription) {
|
|
21
13
|
throw new ApiError(
|
|
@@ -25,10 +17,11 @@ export async function assertPaidSubscription() {
|
|
|
25
17
|
);
|
|
26
18
|
}
|
|
27
19
|
|
|
20
|
+
const isCancelled = getSubscriptionCancellationState(subscription) === "cancelled";
|
|
28
21
|
const expiryDate = getSubscriptionExpiryDate(subscription);
|
|
29
22
|
const isExpired = !!expiryDate && Date.now() >= expiryDate.getTime();
|
|
30
23
|
|
|
31
|
-
if (isExpired) {
|
|
24
|
+
if (isCancelled || isExpired) {
|
|
32
25
|
throw new ApiError(
|
|
33
26
|
"Sua assinatura está vencida. Assine um novo plano para continuar.",
|
|
34
27
|
"SUBSCRIPTION_EXPIRED",
|
|
@@ -36,8 +29,7 @@ export async function assertPaidSubscription() {
|
|
|
36
29
|
);
|
|
37
30
|
}
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
if (subscription.type === 'free' || subscription.id_plan === 5) {
|
|
32
|
+
if (subscription.type === 'free' || subscription.id_plan === FREE_PLAN_ID) {
|
|
41
33
|
throw new ApiError(
|
|
42
34
|
"Este recurso está disponível apenas para planos pagos. Faça upgrade do seu plano para continuar.",
|
|
43
35
|
"PAID_SUBSCRIPTION_REQUIRED",
|
|
@@ -1,24 +1,14 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
|
|
3
3
|
import { ApiError } from "../../../infra/api/types";
|
|
4
|
-
import {
|
|
4
|
+
import { readCurrentSubscription } from "../../subscriptions/utils/read-current-subscription";
|
|
5
5
|
import type { AddonKindEnum } from "../../subscriptions/constants/addons.constants";
|
|
6
6
|
|
|
7
7
|
export async function assertSubscriptionAddon(
|
|
8
8
|
addonId: AddonKindEnum,
|
|
9
9
|
addonLabel: string,
|
|
10
10
|
) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
if (!result.success) {
|
|
14
|
-
throw new ApiError(
|
|
15
|
-
result.error || "Não foi possível validar a assinatura atual",
|
|
16
|
-
"SUBSCRIPTION_CONTEXT_FAILED",
|
|
17
|
-
403,
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const subscription = result.data?.data?.[0];
|
|
11
|
+
const subscription = await readCurrentSubscription();
|
|
22
12
|
|
|
23
13
|
if (!subscription) {
|
|
24
14
|
throw new ApiError(
|
|
@@ -11,7 +11,7 @@ export function usePlanById(idPlan?: number | string | null) {
|
|
|
11
11
|
const queryClient = useQueryClient();
|
|
12
12
|
const plansKey = useAuthQueryKey([...PLANS_QUERY_KEY]);
|
|
13
13
|
|
|
14
|
-
return useQuery({
|
|
14
|
+
return useQuery<SuccessResult<Plan>>({
|
|
15
15
|
queryKey: [...plansKey, idPlan],
|
|
16
16
|
queryFn: ({ signal }) =>
|
|
17
17
|
apiFetch<SuccessResult<Plan>>(`/api/plans/${idPlan}`, { signal }),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { safeServerAction } from '../../../utils/safeServerAction';
|
|
4
|
+
import { subscriptionsService } from '../services/subscriptions.service';
|
|
5
|
+
|
|
6
|
+
export async function getCurrentSubscriptionAction(params?: { id_product?: number }) {
|
|
7
|
+
return safeServerAction(() => subscriptionsService.getCurrentSubscription(params));
|
|
8
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
|
|
3
|
+
import type { NextRequest } from 'next/server';
|
|
4
|
+
import { safeRouteHandler } from '../../../infra/route/safe-route-handler';
|
|
5
|
+
import { searchParamsToParams } from '../../../infra/route/search-params';
|
|
6
|
+
import { subscriptionsService } from '../services/subscriptions.service';
|
|
7
|
+
|
|
8
|
+
export function createCurrentSubscriptionHandler() {
|
|
9
|
+
return async function GET(req: NextRequest) {
|
|
10
|
+
return safeRouteHandler(() =>
|
|
11
|
+
subscriptionsService.getCurrentSubscription(
|
|
12
|
+
searchParamsToParams<{ id_product?: number }>(req.nextUrl.searchParams),
|
|
13
|
+
),
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { apiFetch } from "../../../infra/http/api-fetch";
|
|
5
|
-
import type { PaginatedSuccessResult } from "../../../infra/api/types";
|
|
6
|
-
import type { Subscription } from "../types/subscription.type";
|
|
7
|
-
import { SUBSCRIPTIONS_QUERY_KEY } from "../constants/query-keys.constants";
|
|
8
|
-
import { useAuthQueryKey } from "../../../hooks/useAuthQueryKey";
|
|
3
|
+
import { useCurrentSubscription } from "./use-current-subscription.hook";
|
|
9
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated Use `useCurrentSubscription`, mesma leitura (mesma chave de
|
|
7
|
+
* cache, uma única requisição); só o nome muda para o vocabulário certo
|
|
8
|
+
* ("corrente", não "ativa"). Sai na 1.1.784.
|
|
9
|
+
*/
|
|
10
10
|
export function useActiveSubscription() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return useQuery({
|
|
14
|
-
queryKey,
|
|
15
|
-
queryFn: ({ signal }) =>
|
|
16
|
-
apiFetch<PaginatedSuccessResult<Subscription>>('/api/subscriptions', {
|
|
17
|
-
params: { limit: 1 },
|
|
18
|
-
signal,
|
|
19
|
-
}),
|
|
20
|
-
staleTime: 10_000,
|
|
21
|
-
});
|
|
11
|
+
return useCurrentSubscription();
|
|
22
12
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useQuery } from '@tanstack/react-query';
|
|
4
|
+
import { apiFetch } from '../../../infra/http/api-fetch';
|
|
5
|
+
import { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';
|
|
6
|
+
import type { PaginatedSuccessResult, SuccessResult } from '../../../infra/api/types';
|
|
7
|
+
import type { Subscription } from '../types/subscription.type';
|
|
8
|
+
import { SUBSCRIPTIONS_QUERY_KEY } from '../constants/query-keys.constants';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A assinatura corrente do plano da conta, pela regra única do backend
|
|
12
|
+
* (contrato de domínio nunca é corrente; encerrada é decidida por `active`).
|
|
13
|
+
*
|
|
14
|
+
* Devolvida na mesma forma paginada de `useSubscriptions`/`useActiveSubscription`
|
|
15
|
+
* (`{ data: [sub] }`) para não exigir mudança nos call sites que já leem
|
|
16
|
+
* `data?.[0]`: só a URL e a regra por trás mudam.
|
|
17
|
+
*/
|
|
18
|
+
export function useCurrentSubscription() {
|
|
19
|
+
const queryKey = useAuthQueryKey([...SUBSCRIPTIONS_QUERY_KEY, 'current']);
|
|
20
|
+
|
|
21
|
+
return useQuery({
|
|
22
|
+
queryKey,
|
|
23
|
+
queryFn: async ({ signal }): Promise<PaginatedSuccessResult<Subscription>> => {
|
|
24
|
+
const result = await apiFetch<SuccessResult<Subscription | null>>(
|
|
25
|
+
'/api/subscriptions/current',
|
|
26
|
+
{ signal },
|
|
27
|
+
);
|
|
28
|
+
const subscription = result.data ?? null;
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
success: true,
|
|
32
|
+
data: subscription ? [subscription] : [],
|
|
33
|
+
total: subscription ? 1 : 0,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
staleTime: 10_000,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -85,6 +85,40 @@ class SubscriptionsService {
|
|
|
85
85
|
} satisfies PaginatedSuccessResult<Subscription>;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* A assinatura corrente do plano da conta, pela regra única do backend
|
|
90
|
+
* (`GET .../subscriptions/action/current`): contrato de domínio nunca é
|
|
91
|
+
* corrente, encerrada é decidida por `active`. Sem `id_product`, paridade
|
|
92
|
+
* com hoje (melhor rank entre todos os produtos, nunca item/domínio).
|
|
93
|
+
*/
|
|
94
|
+
async getCurrentSubscription(
|
|
95
|
+
params?: { id_product?: number },
|
|
96
|
+
): Promise<SuccessResult<Subscription | null>> {
|
|
97
|
+
const { id_account } = await getUserContext();
|
|
98
|
+
|
|
99
|
+
const query = buildQueryParams(
|
|
100
|
+
params as Record<string, string | number | undefined>,
|
|
101
|
+
);
|
|
102
|
+
const url = `/accounts/${id_account}/subscriptions/action/current${query ? `?${query}` : ""}`;
|
|
103
|
+
|
|
104
|
+
const response = await api.apps.get<ApiPaginatedActionResult<Subscription>>(url);
|
|
105
|
+
|
|
106
|
+
if (response.status === 0) {
|
|
107
|
+
throw new ApiError(
|
|
108
|
+
response.message || "Erro ao consultar assinatura corrente",
|
|
109
|
+
"GET_CURRENT_SUBSCRIPTION_FAILED",
|
|
110
|
+
400,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const raw = response.data[0];
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
success: true,
|
|
118
|
+
data: raw ? SubscriptionSchema.parse(raw) : null,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
88
122
|
async calculateSubscription(
|
|
89
123
|
data: CalculateSubscriptionRequest,
|
|
90
124
|
): Promise<SuccessResult<CalculateSubscriptionResponse>> {
|