diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index 827c78418a..e94002a580 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -45,6 +45,9 @@ const OnboardingDataCollectionManager = require('../OnboardingDataCollection/Onb const UserUpdater = require('../User/UserUpdater') const Modules = require('../../infrastructure/Modules') const UserGetter = require('../User/UserGetter') +const { + isStandaloneAiAddOnPlanCode, +} = require('../Subscription/RecurlyEntities') /** * @import { GetProjectsRequest, GetProjectsResponse, Project } from "./types" @@ -612,12 +615,15 @@ const _ProjectController = { const userInNonIndividualSub = userIsMemberOfGroupSubscription || userHasInstitutionLicence + const userHasPremiumSub = + subscription && !isStandaloneAiAddOnPlanCode(subscription.planCode) + // Persistent upgrade prompts // in header & in share project modal const showUpgradePrompt = Features.hasFeature('saas') && userId && - !subscription && + !userHasPremiumSub && !userInNonIndividualSub let aiFeaturesAllowed = false diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index 4f7b0cb567..e3e7f6cfe6 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -392,7 +392,10 @@ async function projectListPage(req, res, next) { let showLATAMBanner = false let recommendedCurrency - if (usersBestSubscription?.type === 'free') { + if ( + usersBestSubscription?.type === 'free' || + usersBestSubscription?.type === 'standalone-ai-add-on' + ) { const latamGeoPricingAssignment = await SplitTestHandler.promises.getAssignment( req, diff --git a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js index 30ae83b675..393bd2d2fc 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js +++ b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js @@ -2,6 +2,7 @@ const Settings = require('@overleaf/settings') const RecurlyWrapper = require('./RecurlyWrapper') const PlansLocator = require('./PlansLocator') +const { isStandaloneAiAddOnPlanCode } = require('./RecurlyEntities') const SubscriptionFormatters = require('./SubscriptionFormatters') const SubscriptionLocator = require('./SubscriptionLocator') const SubscriptionUpdater = require('./SubscriptionUpdater') @@ -419,16 +420,22 @@ async function getBestSubscription(user) { } } if (individualSubscription && !individualSubscription.groupPlan) { - const plan = PlansLocator.findLocalPlanInSettings( - individualSubscription.planCode - ) - if (_isPlanEqualOrBetter(plan, bestSubscription.plan)) { - const remainingTrialDays = _getRemainingTrialDays(individualSubscription) - bestSubscription = { - type: 'individual', - subscription: individualSubscription, - plan, - remainingTrialDays, + if (isStandaloneAiAddOnPlanCode(individualSubscription.planCode)) { + bestSubscription = { type: 'standalone-ai-add-on' } + } else { + const plan = PlansLocator.findLocalPlanInSettings( + individualSubscription.planCode + ) + if (_isPlanEqualOrBetter(plan, bestSubscription.plan)) { + const remainingTrialDays = _getRemainingTrialDays( + individualSubscription + ) + bestSubscription = { + type: 'individual', + subscription: individualSubscription, + plan, + remainingTrialDays, + } } } } diff --git a/services/web/app/views/layout-react.pug b/services/web/app/views/layout-react.pug index e03d70e41b..c64b768ab9 100644 --- a/services/web/app/views/layout-react.pug +++ b/services/web/app/views/layout-react.pug @@ -19,7 +19,7 @@ block append meta - const staffAccess = sessionUser?.staffAccess - const canDisplaySplitTestMenu = hasFeature('saas') && (canDisplayAdminMenu || staffAccess?.splitTestMetrics || staffAccess?.splitTestManagement) - const canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu - - const enableUpgradeButton = projectDashboardReact && usersBestSubscription && usersBestSubscription.type === 'free' + - const enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on') - const showSignUpLink = hasFeature('registration-page') meta(name="ol-navbar" data-type="json" content={ diff --git a/services/web/app/views/layout/navbar-marketing-bootstrap-5.pug b/services/web/app/views/layout/navbar-marketing-bootstrap-5.pug index c2e3bb1c74..ec16744a44 100644 --- a/services/web/app/views/layout/navbar-marketing-bootstrap-5.pug +++ b/services/web/app/views/layout/navbar-marketing-bootstrap-5.pug @@ -12,7 +12,7 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={ else a(href='/', aria-label=settings.appName).navbar-brand - - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && usersBestSubscription.type === 'free' + - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on') if (enableUpgradeButton) a.btn.btn-primary.me-2.d-md-none( href="/user/subscription/plans" diff --git a/services/web/app/views/layout/navbar-marketing.pug b/services/web/app/views/layout/navbar-marketing.pug index bd8db5bc6c..01676bbfe7 100644 --- a/services/web/app/views/layout/navbar-marketing.pug +++ b/services/web/app/views/layout/navbar-marketing.pug @@ -9,7 +9,7 @@ nav.navbar.navbar-default.navbar-main aria-label="Toggle " + translate('navigation') ) i.fa.fa-bars(aria-hidden="true") - - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && usersBestSubscription.type === 'free' + - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on') if (enableUpgradeButton) a.btn.btn-primary.pull-right.me-2.visible-xs( href="/user/subscription/plans" diff --git a/services/web/app/views/layout/navbar-website-redesign.pug b/services/web/app/views/layout/navbar-website-redesign.pug index 82f34991e5..58616f9c3e 100644 --- a/services/web/app/views/layout/navbar-website-redesign.pug +++ b/services/web/app/views/layout/navbar-website-redesign.pug @@ -9,7 +9,7 @@ nav.navbar.navbar-default.navbar-main.website-redesign-navbar aria-label="Toggle " + translate('navigation') ) i.fa.fa-bars(aria-hidden="true") - - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && usersBestSubscription.type === 'free' + - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on') if (enableUpgradeButton) a.btn.btn-primary.pull-right.me-2.visible-xs( href="/user/subscription/plans" diff --git a/services/web/frontend/js/features/project-list/components/current-plan-widget/current-plan-widget.tsx b/services/web/frontend/js/features/project-list/components/current-plan-widget/current-plan-widget.tsx index ffc20f6f82..aae2053b19 100644 --- a/services/web/frontend/js/features/project-list/components/current-plan-widget/current-plan-widget.tsx +++ b/services/web/frontend/js/features/project-list/components/current-plan-widget/current-plan-widget.tsx @@ -12,7 +12,7 @@ function CurrentPlanWidget() { } const { type } = usersBestSubscription - const isFreePlan = type === 'free' + const isFreePlan = type === 'free' || type === 'standalone-ai-add-on' const isIndividualPlan = type === 'individual' const isGroupPlan = type === 'group' const isCommonsPlan = type === 'commons' diff --git a/services/web/frontend/js/features/project-list/components/notifications/groups/confirm-email.tsx b/services/web/frontend/js/features/project-list/components/notifications/groups/confirm-email.tsx index 737286255e..6a3f2d6e33 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/groups/confirm-email.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/groups/confirm-email.tsx @@ -61,7 +61,9 @@ function isOnFreeOrIndividualPlan() { return false } const { type } = subscription - return type === 'free' || type === 'individual' + return ( + type === 'free' || type === 'individual' || type === 'standalone-ai-add-on' + ) } const showConfirmEmail = (userEmail: UserEmailData) => { diff --git a/services/web/test/unit/src/Project/ProjectControllerTests.js b/services/web/test/unit/src/Project/ProjectControllerTests.js index 72153e25e3..06d475ce3b 100644 --- a/services/web/test/unit/src/Project/ProjectControllerTests.js +++ b/services/web/test/unit/src/Project/ProjectControllerTests.js @@ -28,6 +28,8 @@ describe('ProjectController', function () { }, siteUrl: 'https://overleaf.com', algolia: {}, + plans: [], + features: {}, } this.brandVariationDetails = { id: '12', diff --git a/services/web/types/project/dashboard/subscription.ts b/services/web/types/project/dashboard/subscription.ts index 2b708f5c3a..4f430cbfc2 100644 --- a/services/web/types/project/dashboard/subscription.ts +++ b/services/web/types/project/dashboard/subscription.ts @@ -37,4 +37,11 @@ type PaidSubscription = | GroupPlanSubscription | CommonsPlanSubscription -export type Subscription = FreeSubscription | PaidSubscription +export type StandaloneAiAddOnSubscription = { + type: 'standalone-ai-add-on' +} + +export type Subscription = + | FreeSubscription + | PaidSubscription + | StandaloneAiAddOnSubscription