mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-16 02:52:31 -04:00
Merge pull request #11147 from overleaf/ii-subscriptions-pages-react-split-test
[web] React subscription split test GitOrigin-RevId: 6656b3895030bc677483a3e30d5e998f5f7d1458
This commit is contained in:
parent
7d661ee573
commit
7e68b4f0d5
22 changed files with 529 additions and 54 deletions
|
@ -104,8 +104,106 @@ async function plansPage(req, res) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// get to show the recurly.js page
|
|
||||||
async function paymentPage(req, res) {
|
async function paymentPage(req, res) {
|
||||||
|
try {
|
||||||
|
const assignment = await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'subscription-pages-react'
|
||||||
|
)
|
||||||
|
// get to show the recurly.js page
|
||||||
|
if (assignment.variant === 'active') {
|
||||||
|
await _paymentReactPage(req, res)
|
||||||
|
} else {
|
||||||
|
await _paymentAngularPage(req, res)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn(
|
||||||
|
{ err: error },
|
||||||
|
'failed to get "subscription-pages-react" split test assignment'
|
||||||
|
)
|
||||||
|
await _paymentAngularPage(req, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("express").Request} req
|
||||||
|
* @param {import("express").Response} res
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function _paymentReactPage(req, res) {
|
||||||
|
const user = SessionManager.getSessionUser(req.session)
|
||||||
|
const plan = PlansLocator.findLocalPlanInSettings(req.query.planCode)
|
||||||
|
if (!plan) {
|
||||||
|
return HttpErrorHandler.unprocessableEntity(req, res, 'Plan not found')
|
||||||
|
}
|
||||||
|
const hasSubscription =
|
||||||
|
await LimitationsManager.promises.userHasV1OrV2Subscription(user)
|
||||||
|
if (hasSubscription) {
|
||||||
|
res.redirect('/user/subscription?hasSubscription=true')
|
||||||
|
} else {
|
||||||
|
// LimitationsManager.userHasV2Subscription only checks Mongo. Double check with
|
||||||
|
// Recurly as well at this point (we don't do this most places for speed).
|
||||||
|
const valid =
|
||||||
|
await SubscriptionHandler.promises.validateNoSubscriptionInRecurly(
|
||||||
|
user._id
|
||||||
|
)
|
||||||
|
if (!valid) {
|
||||||
|
res.redirect('/user/subscription?hasSubscription=true')
|
||||||
|
} else {
|
||||||
|
let currency = null
|
||||||
|
if (req.query.currency) {
|
||||||
|
const queryCurrency = req.query.currency.toUpperCase()
|
||||||
|
if (GeoIpLookup.isValidCurrencyParam(queryCurrency)) {
|
||||||
|
currency = queryCurrency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { currencyCode: recommendedCurrency, countryCode } =
|
||||||
|
await GeoIpLookup.promises.getCurrencyCode(
|
||||||
|
(req.query ? req.query.ip : undefined) || req.ip
|
||||||
|
)
|
||||||
|
if (recommendedCurrency && currency == null) {
|
||||||
|
currency = recommendedCurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshedPaymentPageAssignment =
|
||||||
|
await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'payment-page-refresh'
|
||||||
|
)
|
||||||
|
const useRefreshedPaymentPage =
|
||||||
|
refreshedPaymentPageAssignment &&
|
||||||
|
refreshedPaymentPageAssignment.variant === 'refreshed-payment-page'
|
||||||
|
|
||||||
|
await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'student-check-modal'
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
const template = useRefreshedPaymentPage
|
||||||
|
? 'subscriptions/new-react'
|
||||||
|
: 'subscriptions/new-react'
|
||||||
|
|
||||||
|
res.render(template, {
|
||||||
|
title: 'subscribe',
|
||||||
|
currency,
|
||||||
|
countryCode,
|
||||||
|
plan,
|
||||||
|
recurlyConfig: JSON.stringify({
|
||||||
|
currency,
|
||||||
|
subdomain: Settings.apis.recurly.subdomain,
|
||||||
|
}),
|
||||||
|
showCouponField: !!req.query.scf,
|
||||||
|
showVatField: !!req.query.svf,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _paymentAngularPage(req, res) {
|
||||||
const user = SessionManager.getSessionUser(req.session)
|
const user = SessionManager.getSessionUser(req.session)
|
||||||
const plan = PlansLocator.findLocalPlanInSettings(req.query.planCode)
|
const plan = PlansLocator.findLocalPlanInSettings(req.query.planCode)
|
||||||
if (!plan) {
|
if (!plan) {
|
||||||
|
@ -177,6 +275,84 @@ async function paymentPage(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function userSubscriptionPage(req, res) {
|
async function userSubscriptionPage(req, res) {
|
||||||
|
try {
|
||||||
|
const assignment = await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'subscription-pages-react'
|
||||||
|
)
|
||||||
|
if (assignment.variant === 'active') {
|
||||||
|
await _userSubscriptionReactPage(req, res)
|
||||||
|
} else {
|
||||||
|
await _userSubscriptionAngularPage(req, res)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn(
|
||||||
|
{ err: error },
|
||||||
|
'failed to get "subscription-pages-react" split test assignment'
|
||||||
|
)
|
||||||
|
await _userSubscriptionAngularPage(req, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("express").Request} req
|
||||||
|
* @param {import("express").Response} res
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function _userSubscriptionReactPage(req, res) {
|
||||||
|
const user = SessionManager.getSessionUser(req.session)
|
||||||
|
const results =
|
||||||
|
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||||
|
user
|
||||||
|
)
|
||||||
|
const {
|
||||||
|
personalSubscription,
|
||||||
|
memberGroupSubscriptions,
|
||||||
|
managedGroupSubscriptions,
|
||||||
|
currentInstitutionsWithLicence,
|
||||||
|
managedInstitutions,
|
||||||
|
managedPublishers,
|
||||||
|
v1SubscriptionStatus,
|
||||||
|
} = results
|
||||||
|
const hasSubscription =
|
||||||
|
await LimitationsManager.promises.userHasV1OrV2Subscription(user)
|
||||||
|
const fromPlansPage = req.query.hasSubscription
|
||||||
|
const plans = SubscriptionViewModelBuilder.buildPlansList(
|
||||||
|
personalSubscription ? personalSubscription.plan : undefined
|
||||||
|
)
|
||||||
|
|
||||||
|
AnalyticsManager.recordEventForSession(req.session, 'subscription-page-view')
|
||||||
|
|
||||||
|
const cancelButtonAssignment = await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'subscription-cancel-button'
|
||||||
|
)
|
||||||
|
|
||||||
|
const cancelButtonNewCopy = cancelButtonAssignment?.variant === 'new-copy'
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
title: 'your_subscription',
|
||||||
|
plans,
|
||||||
|
groupPlans: GroupPlansData,
|
||||||
|
user,
|
||||||
|
hasSubscription,
|
||||||
|
fromPlansPage,
|
||||||
|
personalSubscription,
|
||||||
|
memberGroupSubscriptions,
|
||||||
|
managedGroupSubscriptions,
|
||||||
|
managedInstitutions,
|
||||||
|
managedPublishers,
|
||||||
|
v1SubscriptionStatus,
|
||||||
|
currentInstitutionsWithLicence,
|
||||||
|
groupPlanModalOptions,
|
||||||
|
cancelButtonNewCopy,
|
||||||
|
}
|
||||||
|
res.render('subscriptions/dashboard-react', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _userSubscriptionAngularPage(req, res) {
|
||||||
const user = SessionManager.getSessionUser(req.session)
|
const user = SessionManager.getSessionUser(req.session)
|
||||||
const results =
|
const results =
|
||||||
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||||
|
@ -302,6 +478,32 @@ async function createSubscription(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function successfulSubscription(req, res) {
|
async function successfulSubscription(req, res) {
|
||||||
|
try {
|
||||||
|
const assignment = await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'subscription-pages-react'
|
||||||
|
)
|
||||||
|
if (assignment.variant === 'active') {
|
||||||
|
await _successfulSubscriptionReact(req, res)
|
||||||
|
} else {
|
||||||
|
await _successfulSubscriptionAngular(req, res)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn(
|
||||||
|
{ err: error },
|
||||||
|
'failed to get "subscription-pages-react" split test assignment'
|
||||||
|
)
|
||||||
|
await _successfulSubscriptionAngular(req, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("express").Request} req
|
||||||
|
* @param {import("express").Response} res
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function _successfulSubscriptionReact(req, res) {
|
||||||
const user = SessionManager.getSessionUser(req.session)
|
const user = SessionManager.getSessionUser(req.session)
|
||||||
const { personalSubscription } =
|
const { personalSubscription } =
|
||||||
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||||
|
@ -313,7 +515,27 @@ async function successfulSubscription(req, res) {
|
||||||
if (!personalSubscription) {
|
if (!personalSubscription) {
|
||||||
res.redirect('/user/subscription/plans')
|
res.redirect('/user/subscription/plans')
|
||||||
} else {
|
} else {
|
||||||
res.render('subscriptions/successful_subscription', {
|
res.render('subscriptions/successful-subscription-react', {
|
||||||
|
title: 'thank_you',
|
||||||
|
personalSubscription,
|
||||||
|
postCheckoutRedirect,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _successfulSubscriptionAngular(req, res) {
|
||||||
|
const user = SessionManager.getSessionUser(req.session)
|
||||||
|
const { personalSubscription } =
|
||||||
|
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||||
|
user
|
||||||
|
)
|
||||||
|
|
||||||
|
const postCheckoutRedirect = req.session?.postCheckoutRedirect
|
||||||
|
|
||||||
|
if (!personalSubscription) {
|
||||||
|
res.redirect('/user/subscription/plans')
|
||||||
|
} else {
|
||||||
|
res.render('subscriptions/successful-subscription', {
|
||||||
title: 'thank_you',
|
title: 'thank_you',
|
||||||
personalSubscription,
|
personalSubscription,
|
||||||
postCheckoutRedirect,
|
postCheckoutRedirect,
|
||||||
|
@ -337,8 +559,41 @@ function cancelSubscription(req, res, next) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function canceledSubscription(req, res, next) {
|
async function canceledSubscription(req, res, next) {
|
||||||
return res.render('subscriptions/canceled_subscription', {
|
try {
|
||||||
|
const assignment = await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'subscription-pages-react'
|
||||||
|
)
|
||||||
|
if (assignment.variant === 'active') {
|
||||||
|
await _canceledSubscriptionReact(req, res, next)
|
||||||
|
} else {
|
||||||
|
await _canceledSubscriptionAngular(req, res, next)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn(
|
||||||
|
{ err: error },
|
||||||
|
'failed to get "subscription-pages-react" split test assignment'
|
||||||
|
)
|
||||||
|
await _canceledSubscriptionAngular(req, res, next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("express").Request} req
|
||||||
|
* @param {import("express").Response} res
|
||||||
|
* @param {import("express").NextFunction} next
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
function _canceledSubscriptionReact(req, res, next) {
|
||||||
|
return res.render('subscriptions/canceled-subscription-react', {
|
||||||
|
title: 'subscription_canceled',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function _canceledSubscriptionAngular(req, res, next) {
|
||||||
|
return res.render('subscriptions/canceled-subscription', {
|
||||||
title: 'subscription_canceled',
|
title: 'subscription_canceled',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,65 @@ const Errors = require('../Errors/Errors')
|
||||||
const EmailHelper = require('../Helpers/EmailHelper')
|
const EmailHelper = require('../Helpers/EmailHelper')
|
||||||
const { csvAttachment } = require('../../infrastructure/Response')
|
const { csvAttachment } = require('../../infrastructure/Response')
|
||||||
const { UserIsManagerError } = require('./UserMembershipErrors')
|
const { UserIsManagerError } = require('./UserMembershipErrors')
|
||||||
|
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||||
const CSVParser = require('json2csv').Parser
|
const CSVParser = require('json2csv').Parser
|
||||||
|
const logger = require('@overleaf/logger')
|
||||||
|
|
||||||
module.exports = {
|
async function index(req, res, next) {
|
||||||
index(req, res, next) {
|
try {
|
||||||
|
const assignment = await SplitTestHandler.promises.getAssignment(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
'subscription-pages-react'
|
||||||
|
)
|
||||||
|
if (assignment.variant === 'active') {
|
||||||
|
await _indexReact(req, res, next)
|
||||||
|
} else {
|
||||||
|
await _indexAngular(req, res, next)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn(
|
||||||
|
{ err: error },
|
||||||
|
'failed to get "subscription-pages-react" split test assignment'
|
||||||
|
)
|
||||||
|
await _indexAngular(req, res, next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _indexReact(req, res, next) {
|
||||||
|
const { entity, entityConfig } = req
|
||||||
|
return entity.fetchV1Data(function (error, entity) {
|
||||||
|
if (error != null) {
|
||||||
|
return next(error)
|
||||||
|
}
|
||||||
|
return UserMembershipHandler.getUsers(
|
||||||
|
entity,
|
||||||
|
entityConfig,
|
||||||
|
function (error, users) {
|
||||||
|
let entityName
|
||||||
|
if (error != null) {
|
||||||
|
return next(error)
|
||||||
|
}
|
||||||
|
const entityPrimaryKey =
|
||||||
|
entity[entityConfig.fields.primaryKey].toString()
|
||||||
|
if (entityConfig.fields.name) {
|
||||||
|
entityName = entity[entityConfig.fields.name]
|
||||||
|
}
|
||||||
|
return res.render('user_membership/index-react', {
|
||||||
|
name: entityName,
|
||||||
|
users,
|
||||||
|
groupSize: entityConfig.hasMembersLimit
|
||||||
|
? entity.membersLimit
|
||||||
|
: undefined,
|
||||||
|
translations: entityConfig.translations,
|
||||||
|
paths: entityConfig.pathsFor(entityPrimaryKey),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function _indexAngular(req, res, next) {
|
||||||
const { entity, entityConfig } = req
|
const { entity, entityConfig } = req
|
||||||
return entity.fetchV1Data(function (error, entity) {
|
return entity.fetchV1Data(function (error, entity) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
@ -50,8 +105,10 @@ module.exports = {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
index,
|
||||||
add(req, res, next) {
|
add(req, res, next) {
|
||||||
const { entity, entityConfig } = req
|
const { entity, entityConfig } = req
|
||||||
const email = EmailHelper.parseEmail(req.body.email)
|
const email = EmailHelper.parseEmail(req.body.email)
|
||||||
|
@ -96,7 +153,6 @@ module.exports = {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
remove(req, res, next) {
|
remove(req, res, next) {
|
||||||
const { entity, entityConfig } = req
|
const { entity, entityConfig } = req
|
||||||
const { userId } = req.params
|
const { userId } = req.params
|
||||||
|
@ -135,7 +191,6 @@ module.exports = {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
exportCsv(req, res, next) {
|
exportCsv(req, res, next) {
|
||||||
const { entity, entityConfig } = req
|
const { entity, entityConfig } = req
|
||||||
const fields = ['email', 'last_logged_in_at', 'last_active_at']
|
const fields = ['email', 'last_logged_in_at', 'last_active_at']
|
||||||
|
@ -152,14 +207,12 @@ module.exports = {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
new(req, res, next) {
|
new(req, res, next) {
|
||||||
return res.render('user_membership/new', {
|
return res.render('user_membership/new', {
|
||||||
entityName: req.params.name,
|
entityName: req.params.name,
|
||||||
entityId: req.params.id,
|
entityId: req.params.id,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
create(req, res, next) {
|
create(req, res, next) {
|
||||||
const entityId = req.params.id
|
const entityId = req.params.id
|
||||||
const entityConfig = req.entityConfig
|
const entityConfig = req.entityConfig
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
extends ../layout-marketing
|
||||||
|
|
||||||
|
block entrypointVar
|
||||||
|
- entrypoint = 'pages/user/subscription/canceled-subscription'
|
||||||
|
|
||||||
|
block content
|
||||||
|
main.content.content-alt#subscription-canceled-root
|
17
services/web/app/views/subscriptions/dashboard-react.pug
Normal file
17
services/web/app/views/subscriptions/dashboard-react.pug
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
extends ../layout-marketing
|
||||||
|
|
||||||
|
block entrypointVar
|
||||||
|
- entrypoint = 'pages/user/subscription/dashboard'
|
||||||
|
|
||||||
|
block append meta
|
||||||
|
meta(name="ol-managedInstitutions", data-type="json", content=managedInstitutions)
|
||||||
|
meta(name="ol-planCodesChangingAtTermEnd", data-type="json", content=plans.planCodesChangingAtTermEnd)
|
||||||
|
if (personalSubscription && personalSubscription.recurly)
|
||||||
|
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
|
||||||
|
meta(name="ol-subscription" data-type="json" content=personalSubscription)
|
||||||
|
meta(name="ol-recommendedCurrency" content=personalSubscription.recurly.currency)
|
||||||
|
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
|
||||||
|
meta(name="ol-groupPlanModalOptions" data-type="json" content=groupPlanModalOptions)
|
||||||
|
|
||||||
|
block content
|
||||||
|
main.content.content-alt#subscription-dashboard-root
|
14
services/web/app/views/subscriptions/new-react.pug
Normal file
14
services/web/app/views/subscriptions/new-react.pug
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
extends ../layout-marketing
|
||||||
|
|
||||||
|
include ./_new_mixins
|
||||||
|
|
||||||
|
block entrypointVar
|
||||||
|
- entrypoint = 'pages/user/subscription/new'
|
||||||
|
|
||||||
|
block append meta
|
||||||
|
meta(name="ol-countryCode" content=countryCode)
|
||||||
|
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
|
||||||
|
meta(name="ol-recommendedCurrency" content=String(currency).slice(0,3))
|
||||||
|
|
||||||
|
block content
|
||||||
|
main.content.content-alt#subscription-new-root
|
|
@ -0,0 +1,7 @@
|
||||||
|
extends ../layout-marketing
|
||||||
|
|
||||||
|
block entrypointVar
|
||||||
|
- entrypoint = 'pages/user/subscription/successful-subscription'
|
||||||
|
|
||||||
|
block content
|
||||||
|
main.content.content-alt#subscription-success-root
|
12
services/web/app/views/user_membership/index-react.pug
Normal file
12
services/web/app/views/user_membership/index-react.pug
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
extends ../layout-marketing
|
||||||
|
|
||||||
|
block entrypointVar
|
||||||
|
- entrypoint = 'pages/user/membership/groups'
|
||||||
|
|
||||||
|
block append meta
|
||||||
|
meta(name="ol-users", data-type="json", content=users)
|
||||||
|
meta(name="ol-paths", data-type="json", content=paths)
|
||||||
|
meta(name="ol-groupSize", data-type="json", content=groupSize)
|
||||||
|
|
||||||
|
block content
|
||||||
|
main.content.content-alt#subscription-manage-groups-root
|
|
@ -0,0 +1,5 @@
|
||||||
|
function Root() {
|
||||||
|
return <h2>React Manage Group Subscription</h2>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root
|
|
@ -0,0 +1,13 @@
|
||||||
|
import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n'
|
||||||
|
|
||||||
|
function Root() {
|
||||||
|
const { isReady } = useWaitForI18n()
|
||||||
|
|
||||||
|
if (!isReady) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <h2>React Subscription Canceled</h2>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root
|
|
@ -0,0 +1,13 @@
|
||||||
|
import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n'
|
||||||
|
|
||||||
|
function Root() {
|
||||||
|
const { isReady } = useWaitForI18n()
|
||||||
|
|
||||||
|
if (!isReady) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <h2>React Subscription Dashboard</h2>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root
|
|
@ -0,0 +1,13 @@
|
||||||
|
import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n'
|
||||||
|
|
||||||
|
function Root() {
|
||||||
|
const { isReady } = useWaitForI18n()
|
||||||
|
|
||||||
|
if (!isReady) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <h2>React Subscription New</h2>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root
|
|
@ -0,0 +1,13 @@
|
||||||
|
import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n'
|
||||||
|
|
||||||
|
function Root() {
|
||||||
|
const { isReady } = useWaitForI18n()
|
||||||
|
|
||||||
|
if (!isReady) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <h2>React Subscription Success</h2>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root
|
7
services/web/frontend/js/pages/user/membership/groups.js
Normal file
7
services/web/frontend/js/pages/user/membership/groups.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import Root from '../../../features/membership/components/groups-root'
|
||||||
|
|
||||||
|
const element = document.getElementById('subscription-manage-groups-root')
|
||||||
|
if (element) {
|
||||||
|
ReactDOM.render(<Root />, element)
|
||||||
|
}
|
11
services/web/frontend/js/pages/user/subscription/base.js
Normal file
11
services/web/frontend/js/pages/user/subscription/base.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import 'jquery'
|
||||||
|
import 'bootstrap'
|
||||||
|
import './../../../utils/meta'
|
||||||
|
import './../../../utils/webpack-public-path'
|
||||||
|
import './../../../infrastructure/error-reporter'
|
||||||
|
import './../../../i18n'
|
||||||
|
import '../../../cdn-load-test'
|
||||||
|
import '../../../features/contact-form'
|
||||||
|
import '../../../features/event-tracking'
|
||||||
|
import '../../../features/cookie-banner'
|
||||||
|
import '../../../features/link-helpers/slow-link'
|
|
@ -0,0 +1,8 @@
|
||||||
|
import './base'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import Root from '../../../features/subscription/components/canceled-subscription/root'
|
||||||
|
|
||||||
|
const element = document.getElementById('subscription-canceled-root')
|
||||||
|
if (element) {
|
||||||
|
ReactDOM.render(<Root />, element)
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import './base'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import Root from '../../../features/subscription/components/dashboard/root'
|
||||||
|
|
||||||
|
const element = document.getElementById('subscription-dashboard-root')
|
||||||
|
if (element) {
|
||||||
|
ReactDOM.render(<Root />, element)
|
||||||
|
}
|
8
services/web/frontend/js/pages/user/subscription/new.js
Normal file
8
services/web/frontend/js/pages/user/subscription/new.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import './base'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import Root from '../../../features/subscription/components/new/root'
|
||||||
|
|
||||||
|
const element = document.getElementById('subscription-new-root')
|
||||||
|
if (element) {
|
||||||
|
ReactDOM.render(<Root />, element)
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import './base'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import Root from '../../../features/subscription/components/successful-subscription/root'
|
||||||
|
|
||||||
|
const element = document.getElementById('subscription-success-root')
|
||||||
|
if (element) {
|
||||||
|
ReactDOM.render(<Root />, element)
|
||||||
|
}
|
|
@ -399,7 +399,7 @@ describe('SubscriptionController', function () {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
this.res.render = (url, variables) => {
|
this.res.render = (url, variables) => {
|
||||||
url.should.equal('subscriptions/successful_subscription')
|
url.should.equal('subscriptions/successful-subscription')
|
||||||
assert.deepEqual(variables, {
|
assert.deepEqual(variables, {
|
||||||
title: 'thank_you',
|
title: 'thank_you',
|
||||||
personalSubscription: 'foo',
|
personalSubscription: 'foo',
|
||||||
|
|
|
@ -70,12 +70,19 @@ describe('UserMembershipController', function () {
|
||||||
addUser: sinon.stub().yields(null, this.newUser),
|
addUser: sinon.stub().yields(null, this.newUser),
|
||||||
removeUser: sinon.stub().yields(null),
|
removeUser: sinon.stub().yields(null),
|
||||||
}
|
}
|
||||||
|
this.SplitTestHandler = {
|
||||||
|
promises: {
|
||||||
|
getAssignment: sinon.stub().resolves({ variant: 'default' }),
|
||||||
|
},
|
||||||
|
getAssignment: sinon.stub().yields(null, { variant: 'default' }),
|
||||||
|
}
|
||||||
return (this.UserMembershipController = SandboxedModule.require(
|
return (this.UserMembershipController = SandboxedModule.require(
|
||||||
modulePath,
|
modulePath,
|
||||||
{
|
{
|
||||||
requires: {
|
requires: {
|
||||||
'./UserMembershipErrors': { UserIsManagerError },
|
'./UserMembershipErrors': { UserIsManagerError },
|
||||||
'../Authentication/SessionManager': this.SessionManager,
|
'../Authentication/SessionManager': this.SessionManager,
|
||||||
|
'../SplitTests/SplitTestHandler': this.SplitTestHandler,
|
||||||
'./UserMembershipHandler': this.UserMembershipHandler,
|
'./UserMembershipHandler': this.UserMembershipHandler,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -88,21 +95,20 @@ describe('UserMembershipController', function () {
|
||||||
return (this.req.entityConfig = EntityConfigs.group)
|
return (this.req.entityConfig = EntityConfigs.group)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('get users', function (done) {
|
it('get users', async function () {
|
||||||
return this.UserMembershipController.index(this.req, {
|
return await this.UserMembershipController.index(this.req, {
|
||||||
render: () => {
|
render: () => {
|
||||||
sinon.assert.calledWithMatch(
|
sinon.assert.calledWithMatch(
|
||||||
this.UserMembershipHandler.getUsers,
|
this.UserMembershipHandler.getUsers,
|
||||||
this.subscription,
|
this.subscription,
|
||||||
{ modelName: 'Subscription' }
|
{ modelName: 'Subscription' }
|
||||||
)
|
)
|
||||||
return done()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('render group view', function (done) {
|
it('render group view', async function () {
|
||||||
return this.UserMembershipController.index(this.req, {
|
return await this.UserMembershipController.index(this.req, {
|
||||||
render: (viewPath, viewParams) => {
|
render: (viewPath, viewParams) => {
|
||||||
expect(viewPath).to.equal('user_membership/index')
|
expect(viewPath).to.equal('user_membership/index')
|
||||||
expect(viewParams.users).to.deep.equal(this.users)
|
expect(viewParams.users).to.deep.equal(this.users)
|
||||||
|
@ -111,14 +117,13 @@ describe('UserMembershipController', function () {
|
||||||
expect(viewParams.paths.addMember).to.equal(
|
expect(viewParams.paths.addMember).to.equal(
|
||||||
`/manage/groups/${this.subscription._id}/invites`
|
`/manage/groups/${this.subscription._id}/invites`
|
||||||
)
|
)
|
||||||
return done()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('render group managers view', function (done) {
|
it('render group managers view', async function () {
|
||||||
this.req.entityConfig = EntityConfigs.groupManagers
|
this.req.entityConfig = EntityConfigs.groupManagers
|
||||||
return this.UserMembershipController.index(this.req, {
|
return await this.UserMembershipController.index(this.req, {
|
||||||
render: (viewPath, viewParams) => {
|
render: (viewPath, viewParams) => {
|
||||||
expect(viewPath).to.equal('user_membership/index')
|
expect(viewPath).to.equal('user_membership/index')
|
||||||
expect(viewParams.groupSize).to.equal(undefined)
|
expect(viewParams.groupSize).to.equal(undefined)
|
||||||
|
@ -127,22 +132,20 @@ describe('UserMembershipController', function () {
|
||||||
'managers_management'
|
'managers_management'
|
||||||
)
|
)
|
||||||
expect(viewParams.paths.exportMembers).to.be.undefined
|
expect(viewParams.paths.exportMembers).to.be.undefined
|
||||||
return done()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('render institution view', function (done) {
|
it('render institution view', async function () {
|
||||||
this.req.entity = this.institution
|
this.req.entity = this.institution
|
||||||
this.req.entityConfig = EntityConfigs.institution
|
this.req.entityConfig = EntityConfigs.institution
|
||||||
return this.UserMembershipController.index(this.req, {
|
return await this.UserMembershipController.index(this.req, {
|
||||||
render: (viewPath, viewParams) => {
|
render: (viewPath, viewParams) => {
|
||||||
expect(viewPath).to.equal('user_membership/index')
|
expect(viewPath).to.equal('user_membership/index')
|
||||||
expect(viewParams.name).to.equal('Test Institution Name')
|
expect(viewParams.name).to.equal('Test Institution Name')
|
||||||
expect(viewParams.groupSize).to.equal(undefined)
|
expect(viewParams.groupSize).to.equal(undefined)
|
||||||
expect(viewParams.translations.title).to.equal('institution_account')
|
expect(viewParams.translations.title).to.equal('institution_account')
|
||||||
expect(viewParams.paths.exportMembers).to.be.undefined
|
expect(viewParams.paths.exportMembers).to.be.undefined
|
||||||
return done()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue