diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index 60bb51d57d..7ef572091f 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -125,6 +125,7 @@ async function projectListPage(req, res, next) { let usersBestSubscription let usersIndividualSubscription let usersGroupSubscriptions = [] + let usersManagedGroupSubscriptions = [] let survey let userIsMemberOfGroupSubscription = false let groupSubscriptionsPendingEnrollment = [] @@ -186,6 +187,7 @@ async function projectListPage(req, res, next) { bestSubscription: usersBestSubscription, individualSubscription: usersIndividualSubscription, memberGroupSubscriptions: usersGroupSubscriptions, + managedGroupSubscriptions: usersManagedGroupSubscriptions, } = await SubscriptionViewModelBuilder.promises.getUsersSubscriptionDetails( { _id: userId } )) @@ -195,20 +197,16 @@ async function projectListPage(req, res, next) { "Failed to get user's best subscription" ) } - try { - userIsMemberOfGroupSubscription = usersGroupSubscriptions?.length > 0 - // TODO use helper function - if (!user.enrollment?.managedBy) { - groupSubscriptionsPendingEnrollment = usersGroupSubscriptions.filter( - subscription => - subscription.groupPlan && subscription.managedUsersEnabled - ) - } - } catch (error) { - logger.error( - { err: error }, - 'Failed to check whether user is a member of group subscription' + userIsMemberOfGroupSubscription = + usersGroupSubscriptions.length > 0 || + usersManagedGroupSubscriptions.length > 0 + + // TODO use helper function + if (!user.enrollment?.managedBy) { + groupSubscriptionsPendingEnrollment = usersGroupSubscriptions.filter( + subscription => + subscription.groupPlan && subscription.managedUsersEnabled ) } @@ -447,14 +445,13 @@ async function projectListPage(req, res, next) { let showInrGeoBanner = false let showLATAMBanner = false let recommendedCurrency + const { countryCode, currencyCode } = + await GeoIpLookup.promises.getCurrencyCode(req.ip) if ( usersBestSubscription?.type === 'free' || usersBestSubscription?.type === 'standalone-ai-add-on' ) { - const { countryCode, currencyCode } = - await GeoIpLookup.promises.getCurrencyCode(req.ip) - if (countryCode === 'IN') { showInrGeoBanner = true } @@ -478,9 +475,9 @@ async function projectListPage(req, res, next) { } const affiliations = userAffiliations || [] - const inEnterpriseCommons = affiliations.some( - affiliation => affiliation.institution?.enterpriseCommons - ) + const commonsInstitution = affiliations.find( + affiliation => affiliation.institution?.commonsAccount + )?.institution?.name let onboardingDataCollection let subjectArea @@ -493,10 +490,9 @@ async function projectListPage(req, res, next) { let customerIoEnabled = false const aiBlocked = !(await _canUseAIAssist(user)) const hasAiAssist = await _userHasAIAssist(user) - if (!userIsMemberOfGroupSubscription && !inEnterpriseCommons && isSaas) { + + if (!userIsMemberOfGroupSubscription && !commonsInstitution && isSaas) { try { - const ip = req.ip - const { countryCode } = await GeoIpLookup.promises.getCurrencyCode(ip) const excludedCountries = ['IN', 'CN'] if (!excludedCountries.includes(countryCode)) { @@ -548,6 +544,13 @@ async function projectListPage(req, res, next) { user ) + const groupRole = userIsMemberOfGroupSubscription + ? usersManagedGroupSubscriptions?.length > 0 || + usersGroupSubscriptions.some(sub => sub.userIsGroupManager) + ? 'admin' + : 'member' + : undefined + res.render('project/list-react', { title: 'your_projects', usersBestSubscription, @@ -595,6 +598,10 @@ async function projectListPage(req, res, next) { role, usedLatex, inactiveTutorials, + countryCode, + commonsInstitution, + groupRole, + isManagedUser: Boolean(user.enrollment?.managedBy), }) } diff --git a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs index 422628f0eb..15f5257a99 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs @@ -393,16 +393,18 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') { /** * @param {{_id: string}} user - * @returns {Promise<{bestSubscription:Subscription,individualSubscription:DBSubscription|null,memberGroupSubscriptions:DBSubscription[]}>} + * @returns {Promise<{bestSubscription:Subscription,individualSubscription:DBSubscription|null,memberGroupSubscriptions:DBSubscription[],managedGroupSubscriptions:DBSubscription[]}>} */ async function getUsersSubscriptionDetails(user) { let [ individualSubscription, memberGroupSubscriptions, + managedGroupSubscriptions, currentInstitutionsWithLicence, ] = await Promise.all([ SubscriptionLocator.promises.getUsersSubscription(user), SubscriptionLocator.promises.getMemberSubscriptions(user), + SubscriptionLocator.promises.getManagedGroupSubscriptions(user), InstitutionsGetter.promises.getCurrentInstitutionsWithLicence(user._id), ]) if ( @@ -483,7 +485,12 @@ async function getUsersSubscriptionDetails(user) { } } } - return { bestSubscription, individualSubscription, memberGroupSubscriptions } + return { + bestSubscription, + individualSubscription, + memberGroupSubscriptions, + managedGroupSubscriptions, + } } function buildPlansList(currentPlan, isInTrial) { diff --git a/services/web/app/views/_customer_io.pug b/services/web/app/views/_customer_io.pug index c8361a001f..2b17d93fb3 100644 --- a/services/web/app/views/_customer_io.pug +++ b/services/web/app/views/_customer_io.pug @@ -3,7 +3,7 @@ if(customerIoEnabled && ExposedSettings.cioWriteKey && ExposedSettings.cioSiteId function boolAttr(value) { return value !== undefined ? String(value) : null; } - script(type="text/javascript", id="cio-loader", nonce=scriptNonce, data-best-subscription=(usersBestSubscription && usersBestSubscription.type), data-ai-blocked=boolAttr(aiBlocked), data-has-ai-assist=boolAttr(hasAiAssist), data-cio-write-key=ExposedSettings.cioWriteKey, data-cio-site-id=ExposedSettings.cioSiteId, data-session-analytics-id=getSessionAnalyticsId(), data-user-id=getLoggedInUserId(), data-last-active=lastActive, data-sign-up-date=signUpDate, data-subject-area=subjectArea, data-role=role, data-used-latex=usedLatex, data-primary-occupation=primaryOccupation). + script(type="text/javascript", id="cio-loader", nonce=scriptNonce, data-best-subscription=(usersBestSubscription && usersBestSubscription.type), data-ai-blocked=boolAttr(aiBlocked), data-has-ai-assist=boolAttr(hasAiAssist), data-cio-write-key=ExposedSettings.cioWriteKey, data-cio-site-id=ExposedSettings.cioSiteId, data-session-analytics-id=getSessionAnalyticsId(), data-user-id=getLoggedInUserId(), data-last-active=lastActive, data-sign-up-date=signUpDate, data-subject-area=subjectArea, data-role=role, data-used-latex=usedLatex, data-primary-occupation=primaryOccupation, data-country=countryCode, data-commons-institution=commonsInstitution, data-group-role=groupRole, data-features=user.features, data-is-managed-user=boolAttr(isManagedUser)). function parseBool(value) { return value === 'true' ? true : value === 'false' ? false : undefined; @@ -23,6 +23,13 @@ if(customerIoEnabled && ExposedSettings.cioWriteKey && ExposedSettings.cioSiteId var role = cioSettings.role; var primaryOccupation = cioSettings.primaryOccupation; var usedLatex = cioSettings.usedLatex; + var features = cioSettings.features; + + var countryCode = cioSettings.country; + var commonsInstitution = cioSettings.commonsInstitution; + var groupRole = cioSettings.groupRole; + var isManagedUser = parseBool(cioSettings.isManagedUser); + !function(){var i="cioanalytics", analytics=(window[i]=window[i]||[]);if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e