diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index f401898a12..ef265607df 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -49,6 +49,8 @@ const UserGetter = require('../User/UserGetter') const { isStandaloneAiAddOnPlanCode, } = require('../Subscription/RecurlyEntities') +const SubscriptionController = require('../Subscription/SubscriptionController.js') +const { formatCurrency } = require('../../util/currency') /** * @import { GetProjectsRequest, GetProjectsResponse, Project } from "./types" @@ -741,6 +743,14 @@ const _ProjectController = { chatEnabled = Features.hasFeature('chat') } + const isPaywallChangeCompileTimeoutEnabled = + splitTestAssignments['paywall-change-compile-timeout']?.variant === + 'enabled' + + const paywallPlans = + isPaywallChangeCompileTimeoutEnabled && + (await ProjectController._getPaywallPlansPrices(req, res)) + res.render(template, { title: project.name, priority_title: true, @@ -841,9 +851,8 @@ const _ProjectController = { isReviewerRoleEnabled: reviewerRoleAssignment?.variant === 'enabled' || Object.keys(project.reviewer_refs || {}).length > 0, - isPaywallChangeCompileTimeoutEnabled: - splitTestAssignments['paywall-change-compile-timeout']?.variant === - 'enabled', + isPaywallChangeCompileTimeoutEnabled, + paywallPlans, }) timer.done() } catch (err) { @@ -852,6 +861,32 @@ const _ProjectController = { } }, + async _getPaywallPlansPrices( + req, + res, + paywallPlans = ['collaborator', 'student'] + ) { + const plansData = {} + + const locale = req.i18n.language + const { currency } = await SubscriptionController.getRecommendedCurrency( + req, + res + ) + + paywallPlans.forEach(plan => { + const planPrice = Settings.localizedPlanPricing[currency][plan].monthly + const formattedPlanPrice = formatCurrency( + planPrice, + currency, + locale, + true + ) + plansData[plan] = formattedPlanPrice + }) + return plansData + }, + async _refreshFeatures(req, user) { // If the feature refresh has failed in this session, don't retry // it - require the user to log in again. @@ -1154,6 +1189,7 @@ const ProjectController = { _injectProjectUsers: _ProjectController._injectProjectUsers, _isInPercentageRollout: _ProjectController._isInPercentageRollout, _refreshFeatures: _ProjectController._refreshFeatures, + _getPaywallPlansPrices: _ProjectController._getPaywallPlansPrices, } module.exports = ProjectController diff --git a/services/web/app/views/project/editor/_meta.pug b/services/web/app/views/project/editor/_meta.pug index ba25e75637..48dae61334 100644 --- a/services/web/app/views/project/editor/_meta.pug +++ b/services/web/app/views/project/editor/_meta.pug @@ -42,6 +42,9 @@ meta(name="ol-shouldLoadHotjar" data-type="boolean" content=shouldLoadHotjar) meta(name="ol-isReviewerRoleEnabled" data-type="boolean" content=isReviewerRoleEnabled) meta(name="ol-odcRole" data-type="string" content=odcRole) meta(name="ol-isPaywallChangeCompileTimeoutEnabled" data-type="boolean" content=isPaywallChangeCompileTimeoutEnabled) +if(isPaywallChangeCompileTimeoutEnabled) + //- expose plans info to show prices in paywall-change-compile-timeout test + meta(name="ol-paywallPlans", data-type="json" content=paywallPlans) // translations for the loading page, before i18n has loaded in the client meta(name="ol-loadingText", data-type="string" content=translate("loading")) diff --git a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-paywall-prompt.tsx b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-paywall-prompt.tsx index 2a56a76774..37b7756757 100644 --- a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-paywall-prompt.tsx +++ b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-paywall-prompt.tsx @@ -12,11 +12,14 @@ const studentRoles = [ // We can display TimeoutMessageAfterPaywallDismissal after the user has dismissed the paywall. That logic can be implemented in this file or somewhere else? function TimeoutUpgradePaywallPrompt() { const odcRole = getMeta('ol-odcRole') + const planPrices = getMeta('ol-paywallPlans') const isStudent = useMemo(() => studentRoles.includes(odcRole), [odcRole]) return (

Current user is {!isStudent && 'not'} a student.

+

Student plan: {planPrices.student} per month

+

Standard plan: {planPrices.collaborator} per month

) diff --git a/services/web/frontend/js/utils/meta.ts b/services/web/frontend/js/utils/meta.ts index c077bbfa00..20f46f634e 100644 --- a/services/web/frontend/js/utils/meta.ts +++ b/services/web/frontend/js/utils/meta.ts @@ -160,6 +160,7 @@ export interface Meta { 'ol-odcRole': string 'ol-overallThemes': OverallThemeMeta[] 'ol-passwordStrengthOptions': PasswordStrengthOptions + 'ol-paywallPlans': { [key: string]: string } 'ol-personalAccessTokens': AccessToken[] | undefined 'ol-plan': Plan 'ol-planCode': string diff --git a/services/web/test/unit/src/Project/ProjectControllerTests.js b/services/web/test/unit/src/Project/ProjectControllerTests.js index ef85b4c0ed..431cb22da6 100644 --- a/services/web/test/unit/src/Project/ProjectControllerTests.js +++ b/services/web/test/unit/src/Project/ProjectControllerTests.js @@ -62,6 +62,11 @@ describe('ProjectController', function () { getUsersSubscription: sinon.stub().resolves(), }, } + this.SubscriptionController = { + promises: { + getRecommendedCurrency: sinon.stub().resolves({ currency: 'USD' }), + }, + } this.LimitationsManager = { hasPaidSubscription: sinon.stub(), promises: { @@ -231,6 +236,7 @@ describe('ProjectController', function () { '../User/UserController': this.UserController, './ProjectHelper': this.ProjectHelper, '../Subscription/SubscriptionLocator': this.SubscriptionLocator, + '../Subscription/SubscriptionController': this.SubscriptionController, '../Subscription/LimitationsManager': this.LimitationsManager, '../Tags/TagsHandler': this.TagsHandler, '../../models/User': { User: this.UserModel },