diff --git a/backend/.eslintrc b/backend/.eslintrc index 64b049ea7..172e72d4b 100644 --- a/backend/.eslintrc +++ b/backend/.eslintrc @@ -1,21 +1,44 @@ { "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "unused-imports"], + "plugins": [ + "@typescript-eslint", + "unused-imports" + ], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended" ], "rules": { + "@typescript-eslint/no-empty-function": "off", "no-console": 2, - "quotes": ["error", "double", { "avoidEscape": true }], - "comma-dangle": ["error", "only-multiline"], + "quotes": [ + "error", + "double", + { + "avoidEscape": true + } + ], + "comma-dangle": [ + "error", + "only-multiline" + ], "@typescript-eslint/no-unused-vars": "off", "unused-imports/no-unused-imports": "error", "unused-imports/no-unused-vars": [ "warn", - { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } ], - "sort-imports": ["error", { "ignoreDeclarationSort": true }] + "sort-imports": [ + "error", + { + "ignoreDeclarationSort": true + } + ] } -} +} \ No newline at end of file diff --git a/backend/src/ee/services/EELicenseService.ts b/backend/src/ee/services/EELicenseService.ts index 9e3416583..b4bb97753 100644 --- a/backend/src/ee/services/EELicenseService.ts +++ b/backend/src/ee/services/EELicenseService.ts @@ -30,6 +30,8 @@ interface FeatureSet { customRateLimits: boolean; customAlerts: boolean; auditLogs: boolean; + status: 'incomplete' | 'incomplete_expired' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid' | null; + trial_end: number | null; } /** @@ -60,6 +62,8 @@ class EELicenseService { customRateLimits: true, customAlerts: true, auditLogs: false, + status: null, + trial_end: null } public localFeatureSet: NodeCache; diff --git a/backend/src/helpers/organization.ts b/backend/src/helpers/organization.ts index 2e9189e11..3748f18fe 100644 --- a/backend/src/helpers/organization.ts +++ b/backend/src/helpers/organization.ts @@ -45,6 +45,7 @@ export const createOrganization = async ({ name, customerId }).save(); + } else { organization = await new Organization({ name, diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index e9cec0e24..8fe8e0cb9 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -70,6 +70,7 @@ module.exports = { ], "@typescript-eslint/no-non-null-assertion": "off", "simple-import-sort/exports": "warn", + "@typescript-eslint/no-empty-function": "off", "simple-import-sort/imports": [ "warn", { diff --git a/frontend/src/hooks/api/subscriptions/types.ts b/frontend/src/hooks/api/subscriptions/types.ts index af1b315d1..ca50255c8 100644 --- a/frontend/src/hooks/api/subscriptions/types.ts +++ b/frontend/src/hooks/api/subscriptions/types.ts @@ -13,4 +13,6 @@ export type SubscriptionPlan = { workspaceLimit: number; workspacesUsed: number; environmentLimit: number; + status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null; + trial_end: number | null; }; diff --git a/frontend/src/layouts/AppLayout/components/NavBar/NavBar.tsx b/frontend/src/layouts/AppLayout/components/NavBar/NavBar.tsx index c1d134eae..946bda408 100644 --- a/frontend/src/layouts/AppLayout/components/NavBar/NavBar.tsx +++ b/frontend/src/layouts/AppLayout/components/NavBar/NavBar.tsx @@ -64,7 +64,7 @@ export interface IUser { export const Navbar = () => { const router = useRouter(); const { subscription } = useSubscription(); - + const { currentOrg, orgs } = useOrganization(); const { user } = useUser(); @@ -95,17 +95,47 @@ export const Navbar = () => { } }; + function formatPlanSlug(slug: string) { + return slug + .replace(/(\b[a-z])/g, match => match.toUpperCase()) + .replace(/-/g, " "); + } + + const calculateRemainingDays = (date: number) => { + const now = new Date(); + const endDate = new Date(date * 1000); + + const differenceInTime = endDate.getTime() - now.getTime(); + const differenceInDays = Math.ceil(differenceInTime / (1000 * 3600 * 24)); + + return differenceInDays; + } + + const formatDate = (date: number) => { + const endDate = new Date(date * 1000); + const day: number = endDate.getDate(); + const month: number = endDate.getMonth() + 1; + const year: number = endDate.getFullYear(); + + const formattedDate: string = `${day}/${month}/${year}`; + const remainingDays: number = calculateRemainingDays(date); + + return { + formattedDate, + remainingDays + }; + } + return ( -
+ {`You are currently trialing the ${formatPlanSlug(subscription.slug)} plan until ${formatDate(subscription.trial_end).formattedDate} when you'll be downgraded to the Starter plan - You still have ${formatDate(subscription.trial_end).remainingDays} day(s) left.`} +
+Current plan
-- {formatPlanSlug(subscription.slug)} +
+ {`${formatPlanSlug(subscription.slug)} ${subscription.status === "trialing" ? "(Trial)" : ""}`}