Merge pull request #35452 from overleaf/tm-commons-ai-label

[WEB] Show "Commons AI" label when the AI assist bundle is active

GitOrigin-RevId: f49722b94be9b12c7ed5f031dc98182e3a761273
This commit is contained in:
Thomas
2026-09-17 11:27:03 +00:00
committed by Copybot
parent 68b36a8cc6
commit e0d77271c2
14 changed files with 100 additions and 11 deletions
@@ -333,6 +333,7 @@
"comment_only_upgrade_to_enable_track_changes": "",
"common": "",
"commons": "",
"commons_ai": "",
"commons_plan_tooltip": "",
"compact": "",
"company_name": "",
@@ -22,6 +22,9 @@ function CommonsPlan({ featuresPageURL, subscription }: CommonsPlanProps) {
<span className="current-plan-label d-md-none">{currentPlanLabel}</span>
<OLTooltip
description={t('commons_plan_tooltip', {
plan: subscription.writefullCommonsAccount
? t('commons_ai')
: t('commons'),
institution: subscription.name,
})}
id="commons-plan"
@@ -25,6 +25,9 @@ function Email({ userEmailData }: EmailProps) {
userEmailData.confirmedAt &&
userEmailData.affiliation?.institution.confirmed &&
userEmailData.affiliation.licence !== 'free'
const hasCommonsAI =
hasInstitutionalSubscription &&
userEmailData.affiliation?.institution.writefullCommonsAccount === true
const hasBadges = isPrimary || hasInstitutionalSubscription
return (
@@ -53,7 +56,9 @@ function Email({ userEmailData }: EmailProps) {
</>
)}
{hasInstitutionalSubscription && (
<OLBadge bg="primary">{t('commons')}</OLBadge>
<OLBadge bg="primary">
{hasCommonsAI ? t('commons_ai') : t('commons')}
</OLBadge>
)}
</div>
)}
@@ -1,9 +1,10 @@
import { Trans } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import { Institution } from '../../../../../../types/institution'
import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
import Notification from '@/shared/components/notification'
function InstitutionMemberships() {
const { t } = useTranslation()
const { institutionMemberships } = useSubscriptionDashboardContext()
// memberships is undefined when data failed to load. If user has no memberships, then an empty array is returned
@@ -34,7 +35,9 @@ function InstitutionMemberships() {
<Trans
i18nKey="you_are_on_x_plan_as_a_confirmed_member_of_institution_y"
values={{
planName: 'Commons',
planName: institution.writefullCommonsAccount
? t('commons_ai')
: t('commons'),
institutionName: institution.name || '',
}}
shouldUnescape
@@ -56,7 +56,9 @@ export function ActiveSubscription({
if (onStandalonePlan) {
planName = 'Overleaf Free'
if (institutionMemberships && institutionMemberships.length > 0) {
planName = 'Overleaf Commons'
planName = institutionMemberships.some(m => m.writefullCommonsAccount)
? `Overleaf ${t('commons_ai')}`
: `Overleaf ${t('commons')}`
}
if (memberGroupSubscriptions.length > 0) {
if (memberGroupSubscriptions.some(s => s.planLevelName === 'Pro')) {
+1 -1
View File
@@ -266,7 +266,7 @@
"column_width_is_x_click_to_resize": "Kolonnebredden er __width__. Klik for at ændre",
"comment": "Kommentar",
"common": "Almindelig",
"commons_plan_tooltip": "Du er på Commons abonnementet gennem din tilknytning til __institution__. Klik for at finde ud af hvordan du bedst udnytter dine Overlaf Premium-funktioner.",
"commons_plan_tooltip": "Du er på __plan__ abonnementet gennem din tilknytning til __institution__. Klik for at finde ud af hvordan du bedst udnytter dine Overlaf Premium-funktioner.",
"compact": "Kompakt",
"company_name": "Virksomhedsnavn",
"compare": "Sammenlign",
+1 -1
View File
@@ -306,7 +306,7 @@
"comment": "Kommentar",
"comment_only": "Nur Kommentare",
"common": "Häufige",
"commons_plan_tooltip": "Du hast Zugriff auf ein Commons Abonnement über deine Angehörigkeit bei __institution__. Klicke hier um herauszufinden was die Overleaf Premiumfunktionen Dir ermöglichen.",
"commons_plan_tooltip": "Du hast Zugriff auf ein __plan__ Abonnement über deine Angehörigkeit bei __institution__. Klicke hier um herauszufinden was die Overleaf Premiumfunktionen Dir ermöglichen.",
"compact": "Kompakt",
"company_name": "Firmenname",
"compare": "Vergleichen",
+2 -1
View File
@@ -431,7 +431,8 @@
"comment_only_upgrade_to_enable_track_changes": "Comment only. <0>Upgrade</0> to enable track changes.",
"common": "Common",
"commons": "Commons",
"commons_plan_tooltip": "You’re on the Commons plan provided by __institution__. Click to find out how to make the most of your Overleaf premium features.",
"commons_ai": "Commons AI",
"commons_plan_tooltip": "You’re on the __plan__ plan provided by __institution__. Click to find out how to make the most of your Overleaf premium features.",
"community_articles": "Community articles",
"community_articles_lowercase": "community articles",
"compact": "Compact",
+1 -1
View File
@@ -222,7 +222,7 @@
"column_width_is_x_click_to_resize": "La largeur de la colonne est __width__. Cliquez pour redimensionner",
"comment": "Commentaire",
"common": "Commun",
"commons_plan_tooltip": "Vous bénéficiez de l’offre Commons en raison de votre affiliation avec __institution__. Cliquez pour découvrir comment profiter au mieux de vos fonctionnalités Overleaf premium.",
"commons_plan_tooltip": "Vous bénéficiez de l’offre __plan__ en raison de votre affiliation avec __institution__. Cliquez pour découvrir comment profiter au mieux de vos fonctionnalités Overleaf premium.",
"compact": "Compact",
"company_name": "Nom de l’entreprise",
"comparing_from_x_to_y": "Différence entre <0>__startTime__</0> et <0>__endTime__</0>",
+1 -1
View File
@@ -310,7 +310,7 @@
"comment_only_upgrade_for_track_changes": "仅评论。升级可跟踪更改。",
"comment_only_upgrade_to_enable_track_changes": "仅评论。<0>升级</0>以启用跟踪更改。",
"common": "通用",
"commons_plan_tooltip": "由于您与 __institution__ 的隶属关系,您加入了 Commons 计划。 单击以了解如何充分利用 Overleaf 高级功能。",
"commons_plan_tooltip": "由于您与 __institution__ 的隶属关系,您加入了 __plan__ 计划。 单击以了解如何充分利用 Overleaf 高级功能。",
"community_articles": "社区文章",
"community_articles_lowercase": "社区文章",
"compact": "紧凑的",
@@ -295,6 +295,38 @@ describe('<CurrentPlanWidget />', function () {
})
await screen.findByRole('tooltip', { name: paidPlanTooltipMessage })
})
it('shows the Commons AI label when institution has writefull commons', async function () {
const subscription = {
type: 'commons',
plan: {
name: 'Abc',
},
subscription: {
name: 'Example Name',
writefullCommonsAccount: true,
},
} as DeepReadonly<CommonsPlanSubscription>
window.metaAttributesCache.set('ol-usersBestSubscription', {
...subscription,
})
render(<CurrentPlanWidget />)
const link = screen.getByRole('link', {
name: /you’re using overleaf premium/i,
})
fireEvent.mouseOver(link)
await screen.findByRole('tooltip', {
name: new RegExp(
`on the Commons AI plan provided by ${subscription.subscription.name}`,
'i'
),
})
await screen.findByRole('tooltip', { name: paidPlanTooltipMessage })
})
})
})
@@ -118,7 +118,27 @@ describe('<EmailsSection />', function () {
const node = await screen.findByText(professionalUserData.email, {
exact: false,
})
expect(within(node).getByText(/commons/i)).to.exist
expect(within(node).getByText('Commons')).to.exist
})
it('renders commons AI label when institution has writefull commons', async function () {
const commonsAIUserData = {
...professionalUserData,
affiliation: {
...professionalUserData.affiliation,
institution: {
...professionalUserData.affiliation.institution,
writefullCommonsAccount: true,
},
},
}
fetchMock.get('/user/emails?ensureAffiliation=true', [commonsAIUserData])
renderEmailsSection()
const node = await screen.findByText(commonsAIUserData.email, {
exact: false,
})
expect(within(node).getByText('Commons AI')).to.exist
})
it('shows loader when resending email', async function () {
@@ -58,6 +58,25 @@ describe('<InstitutionMemberships />', function () {
)
})
it('renders the Commons AI label when the institution has writefull commons', function () {
const commonsAIMemberships: Institution[] = [
{ ...memberships[0], writefullCommonsAccount: true },
]
renderWithSubscriptionDashContext(<InstitutionMemberships />, {
metaTags: [
{
name: 'ol-currentInstitutionsWithLicence',
value: commonsAIMemberships,
},
],
})
const element = screen.getByText('You are on our', { exact: false })
expect(element.textContent).to.equal(
'You are on our Commons AI plan as a confirmed member of Test University'
)
})
it('renders error message when failed to check commons licenses', function () {
renderWithSubscriptionDashContext(<InstitutionMemberships />)
screen.getByText(
@@ -41,7 +41,10 @@ export type GroupPlanSubscription = {
export type CommonsPlanSubscription = {
type: 'commons'
} & PaidSubscriptionBase
subscription: PaidSubscriptionBase['subscription'] & {
writefullCommonsAccount?: boolean
}
} & Omit<PaidSubscriptionBase, 'subscription'>
type PaidSubscription =
| IndividualPlanSubscription