Merge pull request #27620 from overleaf/mj-remove-ai-assistant-notification

[web] Remove AI Assist notification

GitOrigin-RevId: e3ffcac233eb77d215bff8af7e35f7fdecacf29a
This commit is contained in:
Mathias Jakobsen
2025-08-08 08:07:00 +00:00
committed by Copybot
parent e27da3bfd8
commit 9839dc57b3
8 changed files with 3 additions and 194 deletions
@@ -28,7 +28,6 @@ import SplitTestSessionHandler from '../SplitTests/SplitTestSessionHandler.js'
import TutorialHandler from '../Tutorial/TutorialHandler.js'
import SubscriptionHelper from '../Subscription/SubscriptionHelper.js'
import PermissionsManager from '../Authorization/PermissionsManager.js'
import SubscriptionLocator from '../Subscription/SubscriptionLocator.js'
import AnalyticsManager from '../Analytics/AnalyticsManager.js'
/**
@@ -403,18 +402,6 @@ async function projectListPage(req, res, next) {
logger.error({ err: error }, 'Failed to get individual subscription')
}
const aiAssistNotificationAssignment =
await SplitTestHandler.promises.getAssignment(
req,
res,
'ai-assist-notification'
)
let showAiAssistNotification = false
if (aiAssistNotificationAssignment.variant !== 'default') {
showAiAssistNotification = await _showAiAssistNotification(user)
}
const affiliations = userAffiliations || []
const inEnterpriseCommons = affiliations.some(
affiliation => affiliation.institution?.enterpriseCommons
@@ -488,7 +475,6 @@ async function projectListPage(req, res, next) {
hasIndividualPaidSubscription,
userRestrictions: Array.from(req.userRestrictions || []),
customerIoEnabled,
showAiAssistNotification,
aiBlocked,
hasAiAssist,
})
@@ -804,33 +790,6 @@ async function _canUseAIAssist(user) {
])
}
async function _showAiAssistNotification(user) {
// Check if the assistant has been manually disabled by the user
if (user.aiErrorAssistant?.enabled === false) {
return false
}
// Check if the user can use AI features (policy check)
const canUseAi = await PermissionsManager.promises.checkUserPermissions(
user,
['use-ai']
)
if (!canUseAi) {
return false
}
// Check if the user has a subscription with manually collected group admins (#22822)
const subscription = await SubscriptionLocator.promises.getUsersSubscription(
user._id
)
if (subscription?.collectionMethod === 'manual') {
return false
}
const userHasAiAssist = await _userHasAIAssist(user)
return !userHasAiAssist
}
export default {
projectListPage: expressify(projectListPage),
getProjectsJson: expressify(getProjectsJson),
@@ -87,11 +87,6 @@ block append meta
data-type='string'
content=usGovBannerVariant
)
meta(
name='ol-showAiAssistNotification'
data-type='boolean'
content=showAiAssistNotification
)
block content
#project-list-root
@@ -428,8 +428,6 @@
"disconnected": "",
"discount": "",
"discount_of": "",
"discover_research_writing_toolkit": "",
"discover_research_writing_toolkit_description": "",
"discover_the_fastest_way_to_search_and_cite": "",
"display": "",
"display_deleted_user": "",
@@ -2134,13 +2132,9 @@
"work_in_vim_or_emacs_emulation_mode": "",
"work_offline": "",
"work_offline_pull_to_overleaf": "",
"work_smarter_with_ai_assist": "",
"work_smarter_with_ai_assist_description": "",
"work_with_non_overleaf_users": "",
"work_with_other_github_users": "",
"write_faster_smarter_with_overleaf_and_writefull_ai_tools": "",
"write_smarter_right_now": "",
"write_smarter_right_now_description": "",
"writefull": "",
"writefull_loading_error_body": "",
"writefull_loading_error_title": "",
@@ -1,128 +0,0 @@
import { memo, useCallback, useEffect } from 'react'
import Notification from './notification'
import { useTranslation } from 'react-i18next'
import OLButton from '@/features/ui/components/ol/ol-button'
import { sendMB } from '@/infrastructure/event-tracking'
import sparkle from '@/shared/svgs/sparkle-2-stars.svg'
import { useSplitTest } from '@/shared/context/split-test-context'
import { useProjectListContext } from '../../context/project-list-context'
import getMeta from '@/utils/meta'
import usePersistedState from '@/shared/hooks/use-persisted-state'
function AiAssistBanner() {
const { title, description, cta } = useTitleDescription()
const { totalProjectsCount } = useProjectListContext()
const [dismissed, setDismissed] = usePersistedState(
'ai-assist-notification-banner-dismissed',
false
)
const { variant } = useSplitTest('ai-assist-notification')
const { t } = useTranslation()
useEffect(() => {
if (!dismissed) {
sendMB('promo-prompt', {
location: 'dashboard-banner',
name: 'ai-assist',
variant,
})
}
}, [dismissed, variant])
const handleClose = useCallback(() => {
sendMB('promo-dismiss', {
location: 'dashboard-banner',
name: 'ai-assist',
variant,
})
setDismissed(true)
}, [setDismissed, variant])
const handleUpgradeClick = useCallback(() => {
sendMB('promo-click', {
location: 'dashboard-banner',
name: 'ai-assist',
variant,
type: 'click-upgrade',
})
}, [variant])
const handleLearnMoreClick = useCallback(() => {
sendMB('promo-click', {
location: 'dashboard-banner',
name: 'ai-assist',
type: 'click-learn-more',
variant,
})
}, [variant])
if (
!title ||
dismissed ||
totalProjectsCount === 0 ||
!getMeta('ol-showAiAssistNotification')
) {
return null
}
return (
<Notification
type="offer"
customIcon={<img aria-hidden="true" alt="" src={sparkle} width={32} />}
iconPlacement="center"
title={title}
onDismiss={handleClose}
content={
<p>
{description}{' '}
<a onClick={handleLearnMoreClick} href="/about/ai-features">
{t('learn_more')}
</a>
.
</p>
}
action={
<OLButton
variant="secondary"
href="/user/subscription/plans#ai-assist"
onClick={handleUpgradeClick}
>
{cta}
</OLButton>
}
/>
)
}
function useTitleDescription() {
const { variant } = useSplitTest('ai-assist-notification')
const { t } = useTranslation()
switch (variant) {
case 'work-smarter':
return {
title: t('work_smarter_with_ai_assist'),
description: t('work_smarter_with_ai_assist_description'),
cta: t('add_ai_assist'),
}
case 'discover-toolkit':
return {
title: t('discover_research_writing_toolkit'),
description: t('discover_research_writing_toolkit_description'),
cta: t('add_ai_assist'),
}
case 'write-smarter':
return {
title: t('write_smarter_right_now'),
description: t('write_smarter_right_now_description'),
cta: t('add_ai_assist'),
}
default:
return {
title: null,
description: null,
cta: null,
}
}
}
export default memo(AiAssistBanner)
@@ -14,7 +14,6 @@ import {
DeprecatedBrowser,
isDeprecatedBrowser,
} from '@/shared/components/deprecated-browser'
import AiAssistBanner from './ai-assist-banner'
const [enrollmentNotificationModule] = importOverleafModules(
'managedGroupSubscriptionEnrollmentNotification'
@@ -57,10 +56,7 @@ function UserNotifications() {
<GeoBanners />
<GroupsAndEnterpriseBanner />
{USGovBanner && <USGovBanner />}
<AiAssistBanner />
<AccessibilitySurveyBanner />
{isDeprecatedBrowser() && <DeprecatedBrowser />}
</ul>
</section>
-1
View File
@@ -233,7 +233,6 @@ export interface Meta {
'ol-settingsPlans': Plan[]
'ol-shouldAllowEditingDetails': boolean
'ol-shouldLoadHotjar': boolean
'ol-showAiAssistNotification': boolean
'ol-showAiErrorAssistant': boolean
'ol-showBrlGeoBanner': boolean
'ol-showCouponField': boolean
-6
View File
@@ -555,8 +555,6 @@
"discount": "Discount",
"discount_of": "Discount of __amount__",
"discover_latex_templates_and_examples": "Discover LaTeX templates and examples to help with everything from writing a journal article to using a specific LaTeX package.",
"discover_research_writing_toolkit": "NEW: Discover the ultimate research writing toolkit",
"discover_research_writing_toolkit_description": "Add AI Assist to get unlimited access to LaTeX-tailored AI tools from Overleaf and Writefull.",
"discover_the_fastest_way_to_search_and_cite": "Discover the fastest way to search and cite",
"discover_why_over_people_worldwide_trust_overleaf": "Discover why over __count__ million people worldwide trust Overleaf with their work.",
"display": "Display",
@@ -2685,13 +2683,9 @@
"work_offline": "Work offline",
"work_offline_pull_to_overleaf": "Work offline, then pull to __appName__",
"work_or_university_sso": "Work/university single sign-on",
"work_smarter_with_ai_assist": "Work smarter with AI Assist: AI tools built by TeXperts, for LaTeX",
"work_smarter_with_ai_assist_description": "Get help with everything from language suggestions and writing support to generating LaTeX tables and fixing errors.",
"work_with_non_overleaf_users": "Work with non Overleaf users",
"work_with_other_github_users": "Work with other GitHub users",
"write_faster_smarter_with_overleaf_and_writefull_ai_tools": "Write faster, smarter, and with confidence with Overleaf and Writefull AI tools",
"write_smarter_right_now": "Write smarter, right now",
"write_smarter_right_now_description": "Write faster and with confidence with AI Assist—LaTeX-tailored AI tools from Overleaf and Writefull.",
"writefull": "Writefull",
"writefull_loading_error_body": "Try refreshing the page. If this doesnt work, try disabling any active browser extensions to check they arent blocking Writefull from loading.",
"writefull_loading_error_title": "Writefull didnt load correctly",
@@ -875,7 +875,7 @@ describe('<ProjectListRoot />', function () {
const modals = await screen.findAllByRole('dialog')
const modal = modals[0]
expect(sendMBSpy).to.have.been.calledThrice
expect(sendMBSpy).to.have.been.calledTwice
expect(sendMBSpy).to.have.been.calledWith('loads_v2_dash')
expect(sendMBSpy).to.have.been.calledWith(
'project-list-page-interaction',
@@ -1014,7 +1014,7 @@ describe('<ProjectListRoot />', function () {
)
).to.be.true
expect(sendMBSpy).to.have.been.calledThrice
expect(sendMBSpy).to.have.been.calledTwice
expect(sendMBSpy).to.have.been.calledWith('loads_v2_dash')
expect(sendMBSpy).to.have.been.calledWith(
'project-list-page-interaction',
@@ -1179,7 +1179,7 @@ describe('<ProjectListRoot />', function () {
await fetchMock.callHistory.flush(true)
expect(sendMBSpy).to.have.been.calledThrice
expect(sendMBSpy).to.have.been.calledTwice
expect(sendMBSpy).to.have.been.calledWith('loads_v2_dash')
expect(sendMBSpy).to.have.been.calledWith(
'project-list-page-interaction',