@greatapps/common 1.1.744 → 1.1.745

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 (67) hide show
  1. package/dist/components/modals/AccountFrozenModal.mjs +48 -0
  2. package/dist/components/modals/AccountFrozenModal.mjs.map +1 -0
  3. package/dist/components/navigation/FreezeWarningBanner.mjs +47 -0
  4. package/dist/components/navigation/FreezeWarningBanner.mjs.map +1 -0
  5. package/dist/components/navigation/FrozenAccountBanner.mjs +38 -0
  6. package/dist/components/navigation/FrozenAccountBanner.mjs.map +1 -0
  7. package/dist/components/navigation/SubscriptionBanner.mjs +17 -0
  8. package/dist/components/navigation/SubscriptionBanner.mjs.map +1 -1
  9. package/dist/handlers.mjs +2 -0
  10. package/dist/handlers.mjs.map +1 -1
  11. package/dist/i18n/messages/en-us.mjs +17 -0
  12. package/dist/i18n/messages/en-us.mjs.map +1 -1
  13. package/dist/i18n/messages/es-es.mjs +17 -0
  14. package/dist/i18n/messages/es-es.mjs.map +1 -1
  15. package/dist/i18n/messages/pt-br.mjs +19 -0
  16. package/dist/i18n/messages/pt-br.mjs.map +1 -1
  17. package/dist/index.mjs +59 -37
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/modules/auth/utils/assert-account-not-frozen.mjs +26 -0
  20. package/dist/modules/auth/utils/assert-account-not-frozen.mjs.map +1 -0
  21. package/dist/modules/projects/services/projects.service.mjs +3 -0
  22. package/dist/modules/projects/services/projects.service.mjs.map +1 -1
  23. package/dist/modules/subscriptions/actions/ack-freeze-notice.action.mjs +10 -0
  24. package/dist/modules/subscriptions/actions/ack-freeze-notice.action.mjs.map +1 -0
  25. package/dist/modules/subscriptions/constants/query-keys.constants.mjs +2 -0
  26. package/dist/modules/subscriptions/constants/query-keys.constants.mjs.map +1 -1
  27. package/dist/modules/subscriptions/constants/subscription.constants.mjs +6 -0
  28. package/dist/modules/subscriptions/constants/subscription.constants.mjs.map +1 -1
  29. package/dist/modules/subscriptions/handlers/freeze-notice.handler.mjs +12 -0
  30. package/dist/modules/subscriptions/handlers/freeze-notice.handler.mjs.map +1 -0
  31. package/dist/modules/subscriptions/hooks/use-account-freeze.hook.mjs +42 -0
  32. package/dist/modules/subscriptions/hooks/use-account-freeze.hook.mjs.map +1 -0
  33. package/dist/modules/subscriptions/hooks/use-freeze-notice.hook.mjs +33 -0
  34. package/dist/modules/subscriptions/hooks/use-freeze-notice.hook.mjs.map +1 -0
  35. package/dist/modules/subscriptions/services/subscriptions.service.mjs +29 -0
  36. package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -1
  37. package/dist/modules/subscriptions/types/freeze-notice.type.mjs +1 -0
  38. package/dist/modules/subscriptions/types/freeze-notice.type.mjs.map +1 -0
  39. package/dist/modules/subscriptions/utils/get-account-freeze-date.mjs +19 -0
  40. package/dist/modules/subscriptions/utils/get-account-freeze-date.mjs.map +1 -0
  41. package/dist/modules/subscriptions/utils/get-account-freeze-state.mjs +21 -0
  42. package/dist/modules/subscriptions/utils/get-account-freeze-state.mjs.map +1 -0
  43. package/dist/server.mjs +4 -0
  44. package/dist/server.mjs.map +1 -1
  45. package/package.json +1 -1
  46. package/src/components/modals/AccountFrozenModal.tsx +58 -0
  47. package/src/components/navigation/FreezeWarningBanner.tsx +57 -0
  48. package/src/components/navigation/FrozenAccountBanner.tsx +49 -0
  49. package/src/components/navigation/SubscriptionBanner.tsx +19 -0
  50. package/src/handlers.ts +1 -0
  51. package/src/i18n/messages/en-us.ts +17 -0
  52. package/src/i18n/messages/es-es.ts +17 -0
  53. package/src/i18n/messages/pt-br.ts +20 -0
  54. package/src/index.ts +14 -0
  55. package/src/modules/auth/utils/assert-account-not-frozen.ts +38 -0
  56. package/src/modules/projects/services/projects.service.ts +3 -0
  57. package/src/modules/subscriptions/actions/ack-freeze-notice.action.ts +8 -0
  58. package/src/modules/subscriptions/constants/query-keys.constants.ts +2 -0
  59. package/src/modules/subscriptions/constants/subscription.constants.ts +8 -0
  60. package/src/modules/subscriptions/handlers/freeze-notice.handler.ts +10 -0
  61. package/src/modules/subscriptions/hooks/use-account-freeze.hook.ts +44 -0
  62. package/src/modules/subscriptions/hooks/use-freeze-notice.hook.ts +42 -0
  63. package/src/modules/subscriptions/services/subscriptions.service.ts +39 -0
  64. package/src/modules/subscriptions/types/freeze-notice.type.ts +5 -0
  65. package/src/modules/subscriptions/utils/get-account-freeze-date.ts +40 -0
  66. package/src/modules/subscriptions/utils/get-account-freeze-state.ts +43 -0
  67. package/src/server.ts +2 -0
@@ -448,6 +448,26 @@ const messages = {
448
448
  },
449
449
  },
450
450
 
451
+ // Congelamento por falta de pagamento (date_due + 7d) — banner, aviso de
452
+ // véspera e modal única entre as 3 aplicações.
453
+ subscription: {
454
+ frozen: {
455
+ banner: {
456
+ message: 'Sua conta está com os recursos bloqueados por falta de pagamento.',
457
+ regularize: 'Regularizar assinatura',
458
+ },
459
+ warningBanner: {
460
+ message: 'Pagamento em atraso: sua conta será bloqueada em {freezeDate}. Regularize para não perder o acesso.',
461
+ details: 'Detalhes',
462
+ },
463
+ modal: {
464
+ title: 'Conta bloqueada por falta de pagamento',
465
+ description: 'Sua conta está com os recursos bloqueados por falta de pagamento. Regularize a assinatura para liberar.',
466
+ cta: 'Regularizar assinatura',
467
+ },
468
+ },
469
+ },
470
+
451
471
  // Nomes dos idiomas exibidos no seletor.
452
472
  // Planos: features e main features (mapApiPlanToUiPlan).
453
473
  plans: {
package/src/index.ts CHANGED
@@ -84,9 +84,12 @@ export { useSubscriptions } from "./modules/subscriptions/hooks/list-subscriptio
84
84
  export {
85
85
  SUBSCRIPTIONS_QUERY_KEY,
86
86
  CHARGES_QUERY_KEY,
87
+ FREEZE_NOTICE_QUERY_KEY,
87
88
  } from "./modules/subscriptions/constants/query-keys.constants";
88
89
  export { useActiveSubscription } from "./modules/subscriptions/hooks/find-active-subscription.hook";
89
90
  export { useCancelledSubscriptionGuard } from "./modules/subscriptions/hooks/use-cancelled-subscription-guard";
91
+ export { useAccountFreeze } from "./modules/subscriptions/hooks/use-account-freeze.hook";
92
+ export { useFreezeNotice } from "./modules/subscriptions/hooks/use-freeze-notice.hook";
90
93
  export { usePlanById } from "./modules/plans/hooks/use-plan-by-id.hook";
91
94
  export { useHasPlanAddon } from "./modules/plans/hooks/use-has-plan-addon.hook";
92
95
  export { useCalculateSubscription } from "./modules/subscriptions/hooks/calculate-subscription.hook";
@@ -199,6 +202,14 @@ export {
199
202
  export { SUBSCRIPTION_GRACE_PERIOD_DAYS } from "./modules/subscriptions/constants/subscription.constants";
200
203
  export { getSubscriptionCancellationState } from "./modules/subscriptions/utils/get-subscription-cancellation-state";
201
204
  export type { SubscriptionCancellationState } from "./modules/subscriptions/utils/get-subscription-cancellation-state";
205
+ export {
206
+ ACCOUNT_FREEZE_AFTER_DAYS,
207
+ FREEZE_WARNING_DAYS_BEFORE,
208
+ } from "./modules/subscriptions/constants/subscription.constants";
209
+ export { getAccountFreezeState } from "./modules/subscriptions/utils/get-account-freeze-state";
210
+ export type { AccountFreezeState } from "./modules/subscriptions/utils/get-account-freeze-state";
211
+ export { getAccountFreezeDate } from "./modules/subscriptions/utils/get-account-freeze-date";
212
+ export type { FreezeNotice } from "./modules/subscriptions/types/freeze-notice.type";
202
213
  export {
203
214
  useCountPages,
204
215
  COUNT_PAGES_QUERY_KEY,
@@ -216,6 +227,7 @@ export { useAccountDeletionWarningModal } from "./store/useAccountDeletionWarnin
216
227
  export { default as BuyCreditsModal } from "./components/modals/BuyCreditsModal";
217
228
  export { default as CreditsDisabledModal } from "./components/modals/CreditsDisabledModal";
218
229
  export { default as PaidPlanRequiredModal } from "./components/modals/PaidPlanRequiredModal";
230
+ export { default as AccountFrozenModal } from "./components/modals/AccountFrozenModal";
219
231
  export { default as AccountDeletionWarningModal } from "./components/modals/AccountDeletionWarningModal";
220
232
  export { default as RequiredBillingDataModal } from "./components/modals/billing/RequiredBillingDataModal";
221
233
  export { default as AddCardModal } from "./components/modals/cards/AddCardModal";
@@ -294,6 +306,8 @@ export { SubscriptionBanner } from "./components/navigation/SubscriptionBanner";
294
306
  export { OverdueInvoiceBanner } from "./components/navigation/OverdueInvoiceBanner";
295
307
  export { UpcomingInvoiceBanner } from "./components/navigation/UpcomingInvoiceBanner";
296
308
  export { TrialBanner } from "./components/navigation/TrialBanner";
309
+ export { FrozenAccountBanner } from "./components/navigation/FrozenAccountBanner";
310
+ export { FreezeWarningBanner } from "./components/navigation/FreezeWarningBanner";
297
311
  export type { NavItemConfig } from "./components/navigation/subcomponents/NavItems";
298
312
  export { useMobileNavbarSheet } from "./store/useMobileNavbarSheet";
299
313
 
@@ -0,0 +1,38 @@
1
+ import "server-only";
2
+
3
+ import { ApiError } from "../../../infra/api/types";
4
+ import { listSubscriptionsAction } from "../../subscriptions/actions/list-subscriptions.action";
5
+ import { getAccountFreezeState } from "../../subscriptions/utils/get-account-freeze-state";
6
+
7
+ /**
8
+ * Bloqueia mutações de conta congelada por falta de pagamento (date_due + 7d).
9
+ *
10
+ * Fail-OPEN na leitura: falha de rede/payload ao consultar billing não pode
11
+ * travar cliente adimplente. Diferente do assertManagementSubscription
12
+ * (default-deny) porque ali o risco é liberar entitlement não contratado; aqui
13
+ * o gate primário já é este server action, e o caso vencido (expired) continua
14
+ * coberto pelo assertManagementSubscription rodando ao lado.
15
+ */
16
+ export async function assertAccountNotFrozen(): Promise<void> {
17
+ const result = await listSubscriptionsAction({ active: true });
18
+
19
+ if (!result.success) {
20
+ console.error(
21
+ "[assertAccountNotFrozen] failed to read subscription context:",
22
+ result.error,
23
+ );
24
+ return;
25
+ }
26
+
27
+ const subscription = result.data?.data?.[0];
28
+
29
+ if (!subscription) return;
30
+
31
+ if (getAccountFreezeState(subscription) !== "frozen") return;
32
+
33
+ throw new ApiError(
34
+ "Sua conta está com os recursos bloqueados por falta de pagamento. Regularize a assinatura para liberar.",
35
+ "ACCOUNT_FROZEN",
36
+ 403,
37
+ );
38
+ }
@@ -5,6 +5,7 @@ import { ApiError } from '../../../infra/api/types';
5
5
  import { buildQueryParams } from '../../../infra/utils/params';
6
6
  import { getUserContext } from '../../auth/utils/get-user-context';
7
7
  import { assertManagementSubscription } from '../../auth/utils/assert-management-subscription';
8
+ import { assertAccountNotFrozen } from '../../auth/utils/assert-account-not-frozen';
8
9
  import {
9
10
  Project,
10
11
  ProjectSchema,
@@ -80,6 +81,7 @@ class ProjectsService {
80
81
 
81
82
  async create(data: CreateProjectRequest): Promise<Project> {
82
83
  await assertManagementSubscription();
84
+ await assertAccountNotFrozen();
83
85
  const { id_account, id_user } = await getUserContext();
84
86
  const url = `/account/${id_account}/user/${id_user}/projects`;
85
87
 
@@ -102,6 +104,7 @@ class ProjectsService {
102
104
 
103
105
  async update(projectId: number, data: UpdateProjectRequest): Promise<Project> {
104
106
  await assertManagementSubscription();
107
+ await assertAccountNotFrozen();
105
108
  const { id_account, id_user } = await getUserContext();
106
109
  const url = `/account/${id_account}/user/${id_user}/projects/${projectId}`;
107
110
 
@@ -0,0 +1,8 @@
1
+ 'use server';
2
+
3
+ import { safeMutationAction } from '../../../utils/safeMutationAction';
4
+ import { subscriptionsService } from '../services/subscriptions.service';
5
+
6
+ export async function ackFreezeNoticeAction(cycle: string) {
7
+ return safeMutationAction(() => subscriptionsService.ackFreezeNotice(cycle));
8
+ }
@@ -1,3 +1,5 @@
1
1
  export const SUBSCRIPTIONS_QUERY_KEY = ['subscriptions'] as const;
2
2
 
3
3
  export const CHARGES_QUERY_KEY = ['charges'] as const;
4
+
5
+ export const FREEZE_NOTICE_QUERY_KEY = ['freeze-notice'] as const;
@@ -1,5 +1,13 @@
1
1
  export const SUBSCRIPTION_GRACE_PERIOD_DAYS = 15;
2
2
 
3
+ export const ACCOUNT_FREEZE_AFTER_DAYS = 7;
4
+ export const FREEZE_WARNING_DAYS_BEFORE = 1;
5
+
6
+ /* Congelamento só vale para a wl 1: o aviso de véspera e o e-mail de bloqueio saem do
7
+ * cron `dailyNotifications` do gapps-r3-api, que só roda para ela. Congelar as demais
8
+ * seria bloquear sem avisar. Espelhado nos gates dos dois backends. */
9
+ export const FREEZE_ELIGIBLE_WHITELABEL_ID = 1;
10
+
3
11
  /* Stripe Smart Retries (dunning): até 8 tentativas de cobrança no cartão antes
4
12
  * do cancelamento automático. `tentativas restantes = MAX - attempt_count`. */
5
13
  export const MAX_PAYMENT_ATTEMPTS = 8;
@@ -0,0 +1,10 @@
1
+ import 'server-only';
2
+
3
+ import { safeRouteHandler } from '../../../infra/route/safe-route-handler';
4
+ import { subscriptionsService } from '../services/subscriptions.service';
5
+
6
+ export function createFreezeNoticeHandler() {
7
+ return async function GET() {
8
+ return safeRouteHandler(() => subscriptionsService.getFreezeNotice());
9
+ };
10
+ }
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+
3
+ import { useCallback } from 'react';
4
+ import { UserProfile } from '../../users/schema';
5
+ import { useAuth } from '../../../providers/auth.provider';
6
+ import { useModalManager } from '../../../store/useModalManager';
7
+ import { useActiveSubscription } from './find-active-subscription.hook';
8
+ import { getAccountFreezeState } from '../utils/get-account-freeze-state';
9
+ import { getAccountFreezeDate } from '../utils/get-account-freeze-date';
10
+
11
+ export function useAccountFreeze() {
12
+ const { user } = useAuth();
13
+ const { openModal } = useModalManager();
14
+ const {
15
+ data: { data: [subscription] = [] } = {},
16
+ } = useActiveSubscription();
17
+
18
+ const isViewer = user?.profile === UserProfile.viewer;
19
+ const state = getAccountFreezeState(subscription);
20
+ const isFrozen = state === 'frozen';
21
+ const isWarning = state === 'warning';
22
+ const freezeDate = getAccountFreezeDate(subscription);
23
+
24
+ const guardAction = useCallback(
25
+ (action?: () => void) => {
26
+ if (!isViewer && isFrozen) {
27
+ openModal('accountFrozenModal');
28
+ return false;
29
+ }
30
+
31
+ action?.();
32
+ return true;
33
+ },
34
+ [openModal, isViewer, isFrozen]
35
+ );
36
+
37
+ return {
38
+ state,
39
+ isFrozen,
40
+ isWarning,
41
+ freezeDate,
42
+ guardAction,
43
+ };
44
+ }
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ import { useCallback } from 'react';
4
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
5
+ import { apiFetch } from '../../../infra/http/api-fetch';
6
+ import { withAction } from '../../../utils/withAction';
7
+ import { ackFreezeNoticeAction } from '../actions/ack-freeze-notice.action';
8
+ import { FREEZE_NOTICE_QUERY_KEY } from '../constants/query-keys.constants';
9
+ import { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';
10
+ import type { FreezeNotice } from '../types/freeze-notice.type';
11
+
12
+ /**
13
+ * Modal única do congelamento (D4): pending quando `frozen && !acknowledged`.
14
+ * ack() marca o episódio (id_subscription + date_due) como visto no gapps-r3-api
15
+ * — reaparece só se um novo ciclo congelar de novo.
16
+ */
17
+ export function useFreezeNotice() {
18
+ const queryClient = useQueryClient();
19
+ const queryKey = useAuthQueryKey([...FREEZE_NOTICE_QUERY_KEY]);
20
+
21
+ const query = useQuery({
22
+ queryKey,
23
+ queryFn: ({ signal }) => apiFetch<FreezeNotice>('/api/notices/freeze', { signal }),
24
+ staleTime: 10_000,
25
+ });
26
+
27
+ const mutation = useMutation({
28
+ mutationFn: (cycle: string) => withAction(ackFreezeNoticeAction)(cycle),
29
+ onSuccess: () => {
30
+ queryClient.invalidateQueries({ queryKey });
31
+ },
32
+ });
33
+
34
+ const pending = !!query.data?.frozen && !query.data?.acknowledged;
35
+ const cycle = query.data?.cycle ?? null;
36
+
37
+ const ack = useCallback(() => {
38
+ if (cycle) mutation.mutate(cycle);
39
+ }, [cycle, mutation]);
40
+
41
+ return { pending, cycle, ack };
42
+ }
@@ -26,6 +26,7 @@ import {
26
26
  SubscriptionPendingPixResponseSchema,
27
27
  type SubscriptionPendingPixResponse,
28
28
  } from "../types/pix-pending.type";
29
+ import type { FreezeNotice } from "../types/freeze-notice.type";
29
30
 
30
31
  /**
31
32
  * Timeout das mutations de assinatura que ESCREVEM (action/plan e action/payment).
@@ -181,6 +182,44 @@ class SubscriptionsService {
181
182
 
182
183
  return { success: true };
183
184
  }
185
+
186
+ async getFreezeNotice(): Promise<FreezeNotice> {
187
+ const { id_account } = await getUserContext();
188
+
189
+ const response = await api.apps.get<ApiActionResult<FreezeNotice>>(
190
+ `/accounts/${id_account}/notices/freeze`,
191
+ );
192
+
193
+ if (response.status === 0 || !response.data) {
194
+ throw new ApiError(
195
+ (response.status === 0 ? response.message : "") ||
196
+ "Erro ao consultar aviso de congelamento",
197
+ "GET_FREEZE_NOTICE_FAILED",
198
+ 400,
199
+ );
200
+ }
201
+
202
+ return response.data;
203
+ }
204
+
205
+ async ackFreezeNotice(cycle: string): Promise<SuccessResult<void>> {
206
+ const { id_account } = await getUserContext();
207
+
208
+ const response = await api.apps.post<ApiActionResult<void>>(
209
+ `/accounts/${id_account}/notices/freeze/ack`,
210
+ { cycle },
211
+ );
212
+
213
+ if (response.status === 0) {
214
+ throw new ApiError(
215
+ response.message || "Erro ao confirmar aviso de congelamento",
216
+ "ACK_FREEZE_NOTICE_FAILED",
217
+ 400,
218
+ );
219
+ }
220
+
221
+ return { success: true };
222
+ }
184
223
  }
185
224
 
186
225
  export const subscriptionsService = new SubscriptionsService();
@@ -0,0 +1,5 @@
1
+ export interface FreezeNotice {
2
+ frozen: boolean;
3
+ cycle: string | null;
4
+ acknowledged: boolean;
5
+ }
@@ -0,0 +1,40 @@
1
+ import {
2
+ ACCOUNT_FREEZE_AFTER_DAYS,
3
+ FREEZE_ELIGIBLE_WHITELABEL_ID,
4
+ } from "../constants/subscription.constants";
5
+ import { toCalendarDate } from "../../../infra/utils/date";
6
+ import type { Subscription } from "../types/subscription.type";
7
+
8
+ /**
9
+ * Data em que a conta é congelada por falta de pagamento: date_due + ACCOUNT_FREEZE_AFTER_DAYS.
10
+ *
11
+ * Só congela assinatura `client` da whitelabel 1 — MESMA régua do
12
+ * `isSubscriptionFrozen` (gapps-r3-api) e do `isAccountFrozen` (gpages-r3-api).
13
+ * Se as três divergirem, o usuário é bloqueado por uma camada e liberado por outra.
14
+ *
15
+ * - `type !== "client"` cobre free, trial, partner e whitelabel de uma vez (a coluna
16
+ * aceita mais valores do que a lista que o SubscriptionBanner enumera).
17
+ * - `id_wl !== 1`: o pipeline de aviso (cron `dailyNotifications` do gapps-r3-api) só
18
+ * existe para a wl 1. Congelar conta de whitelabel seria bloquear sem nunca avisar —
19
+ * o defeito do ID-5029 que este card existe para não repetir.
20
+ */
21
+ export function getAccountFreezeDate(
22
+ subscription:
23
+ | Pick<Subscription, "type" | "date_due" | "id_wl">
24
+ | undefined
25
+ | null,
26
+ ): Date | null {
27
+ if (!subscription) return null;
28
+
29
+ if (subscription.type !== "client") return null;
30
+
31
+ if (Number(subscription.id_wl) !== FREEZE_ELIGIBLE_WHITELABEL_ID) return null;
32
+
33
+ const dueDate = toCalendarDate(subscription.date_due);
34
+
35
+ if (!dueDate) return null;
36
+
37
+ const result = new Date(dueDate);
38
+ result.setDate(result.getDate() + ACCOUNT_FREEZE_AFTER_DAYS);
39
+ return result;
40
+ }
@@ -0,0 +1,43 @@
1
+ import { FREEZE_WARNING_DAYS_BEFORE } from "../constants/subscription.constants";
2
+ import { toCalendarDate } from "../../../infra/utils/date";
3
+ import { getAccountFreezeDate } from "./get-account-freeze-date";
4
+ import { getSubscriptionCancellationState } from "./get-subscription-cancellation-state";
5
+ import type { Subscription } from "../types/subscription.type";
6
+
7
+ export type AccountFreezeState = "none" | "warning" | "frozen";
8
+
9
+ /**
10
+ * Estado de congelamento por falta de pagamento (date_due + ACCOUNT_FREEZE_AFTER_DAYS).
11
+ *
12
+ * Conta cancelada/pendente de cancelamento é tratada pelos ramos de cancelamento
13
+ * (mesma ordem do SubscriptionBanner) — aqui sempre "none" nesse caso, pra não
14
+ * disputar mensagem com o CancelledSubscriptionBanner/PendingCancellationBanner.
15
+ */
16
+ export function getAccountFreezeState(
17
+ subscription:
18
+ | Pick<
19
+ Subscription,
20
+ "type" | "active" | "date_due" | "date_cancellation" | "id_wl"
21
+ >
22
+ | undefined
23
+ | null,
24
+ ): AccountFreezeState {
25
+ if (!subscription) return "none";
26
+
27
+ if (getSubscriptionCancellationState(subscription) !== "none") return "none";
28
+
29
+ const freezeDate = getAccountFreezeDate(subscription);
30
+ if (!freezeDate) return "none";
31
+
32
+ const today = toCalendarDate(new Date());
33
+ if (!today) return "none";
34
+
35
+ if (today.getTime() >= freezeDate.getTime()) return "frozen";
36
+
37
+ const warningDate = new Date(freezeDate);
38
+ warningDate.setDate(warningDate.getDate() - FREEZE_WARNING_DAYS_BEFORE);
39
+
40
+ if (today.getTime() >= warningDate.getTime()) return "warning";
41
+
42
+ return "none";
43
+ }
package/src/server.ts CHANGED
@@ -11,6 +11,7 @@ export { assertManagementPermission } from './modules/auth/utils/assert-manageme
11
11
  export { assertManagementSubscription } from './modules/auth/utils/assert-management-subscription';
12
12
  export { assertSubscriptionAddon } from './modules/auth/utils/assert-subscription-addon';
13
13
  export { assertPaidSubscription } from './modules/auth/utils/assert-paid-subscription';
14
+ export { assertAccountNotFrozen } from './modules/auth/utils/assert-account-not-frozen';
14
15
  export { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';
15
16
  export { plansService } from './modules/plans/services/plans.service';
16
17
  export { cardsService } from './modules/cards/services/cards.service';
@@ -27,6 +28,7 @@ export { findUserById } from './modules/users/action/find-user-by-id.action';
27
28
  export { findCurrentAccount } from './modules/accounts/actions/find-current-account.action';
28
29
  export { getAccountTokenAction } from './modules/accounts/actions/get-account-token.action';
29
30
  export { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';
31
+ export { ackFreezeNoticeAction } from './modules/subscriptions/actions/ack-freeze-notice.action';
30
32
  export { calculateSubscriptionAction } from './modules/subscriptions/actions/calculate-subscription.action';
31
33
  export { updateSubscriptionPlanAction } from './modules/subscriptions/actions/update-subscription-plan.action';
32
34
  export { updateSubscriptionPaymentAction } from './modules/subscriptions/actions/update-subscription-payment.action';