From 1a3db52d689d9cd80a299c1c334c15cd2d7b6475 Mon Sep 17 00:00:00 2001 From: Jimmy Domagala-Tang Date: Tue, 2 Jul 2024 08:10:22 -0400 Subject: [PATCH] Merge pull request #19150 from overleaf/jdt-ai-promo feat: add labs ai experiment promo GitOrigin-RevId: 9bf039635b487339caa277b501a8cd99c7c7613f --- .../Features/Project/ProjectListController.js | 3 +- services/web/app/src/router.js | 1 + .../web/frontend/extracted-translations.json | 1 + .../notifications/labs-ai-promo-banner.tsx | 66 +++++++++++++++++++ .../notifications/user-notifications.tsx | 2 + services/web/locales/en.json | 1 + 6 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 services/web/frontend/js/features/project-list/components/notifications/labs-ai-promo-banner.tsx diff --git a/services/web/app/src/Features/Project/ProjectListController.js b/services/web/app/src/Features/Project/ProjectListController.js index 4144143844..a8be77ab74 100644 --- a/services/web/app/src/Features/Project/ProjectListController.js +++ b/services/web/app/src/Features/Project/ProjectListController.js @@ -117,7 +117,7 @@ async function projectListPage(req, res, next) { }) const user = await User.findById( userId, - `email emails features alphaProgram betaProgram lastPrimaryEmailCheck signUpDate${ + `email emails features alphaProgram betaProgram lastPrimaryEmailCheck labsProgram signUpDate${ isSaas ? ' enrollment writefull' : '' }` ) @@ -462,6 +462,7 @@ async function projectListPage(req, res, next) { groupName: subscription.teamName, })), hasIndividualRecurlySubscription, + userRestrictions: Array.from(req.userRestrictions || []), }) } diff --git a/services/web/app/src/router.js b/services/web/app/src/router.js index 5c8f090d6c..d48900bda9 100644 --- a/services/web/app/src/router.js +++ b/services/web/app/src/router.js @@ -483,6 +483,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { '/project', AuthenticationController.requireLogin(), RateLimiterMiddleware.rateLimit(rateLimiters.openDashboard), + PermissionsController.useCapabilities(), ProjectListController.projectListPage ) webRouter.post( diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 4ff969693f..171ed25d90 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -468,6 +468,7 @@ "get_collaborative_benefits": "", "get_discounted_plan": "", "get_dropbox_sync": "", + "get_early_access_to_ai": "", "get_exclusive_access_to_labs": "", "get_full_project_history": "", "get_git_integration": "", diff --git a/services/web/frontend/js/features/project-list/components/notifications/labs-ai-promo-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/labs-ai-promo-banner.tsx new file mode 100644 index 0000000000..f8d382be58 --- /dev/null +++ b/services/web/frontend/js/features/project-list/components/notifications/labs-ai-promo-banner.tsx @@ -0,0 +1,66 @@ +import { memo, useCallback, useState } from 'react' +import Notification from './notification' +import customLocalStorage from '@/infrastructure/local-storage' +import OLButton from '@/features/ui/components/ol/ol-button' +import getMeta from '@/utils/meta' +import * as eventTracking from '../../../../infrastructure/event-tracking' +import { useTranslation } from 'react-i18next' + +function LabsAiPromoBanner() { + const user = getMeta('ol-user') + const cannotUseAi = getMeta('ol-cannot-use-ai') + const { t } = useTranslation() + + const [show, setShow] = useState(() => { + const dismissed = customLocalStorage.getItem( + 'has_dismissed_labs_ai_promo_banner' + ) + if (dismissed || cannotUseAi) { + return false + } + + const show = user?.labsProgram === true && !user?.features?.aiErrorAssistant + return show + }) + + const handleClose = useCallback(() => { + eventTracking.sendMB('promo-dismiss', { + name: 'labs-ai-experiment-promo', + }) + customLocalStorage.setItem('has_dismissed_labs_ai_promo_banner', true) + setShow(false) + }, [setShow]) + + const handleClick = useCallback(() => { + eventTracking.sendMB('promo-click', { + name: 'labs-ai-experiment-promo', + content: 'try-now', + }) + customLocalStorage.setItem('has_dismissed_labs_ai_promo_banner', true) + }, []) + + if (!show) { + return null + } + + return ( +
+ {t('get_early_access_to_ai')}} + action={ + + {t('try_now')} + + } + /> +
+ ) +} + +export default memo(LabsAiPromoBanner) diff --git a/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx b/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx index f77a949264..9aab99d0b5 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx @@ -12,6 +12,7 @@ import customLocalStorage from '../../../../infrastructure/local-storage' import { sendMB } from '../../../../infrastructure/event-tracking' import GeoBanners from './geo-banners' import AccessibilitySurveyBanner from './accessibility-survey-banner' +import LabsAiPromoBanner from './labs-ai-promo-banner' const [enrollmentNotificationModule] = importOverleafModules( 'managedGroupSubscriptionEnrollmentNotification' @@ -79,6 +80,7 @@ function UserNotifications() { setDismissedWritefull(true) }} /> + ) diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 3a73ca3950..ca2c8596d5 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -702,6 +702,7 @@ "get_collaborative_benefits": "Get the collaborative benefits from __appName__, even if you prefer to work offline", "get_discounted_plan": "Get discounted plan", "get_dropbox_sync": "Get Dropbox Sync", + "get_early_access_to_ai": "Get early access to the new AI Error Assistant in Overleaf Labs", "get_exclusive_access_to_labs": "Get exclusive access to early-stage experiments when you join Overleaf Labs. All we ask in return is your honest feedback to help us develop and improve.", "get_full_project_history": "Get full project history", "get_git_integration": "Get Git integration",