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 ( +