From 4e6749966e491784dd70ab9cfeb42c0715385c0e Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Tue, 9 May 2023 15:45:16 +0100 Subject: [PATCH] Add Writefull promo banner to project list (#12843) GitOrigin-RevId: a41746a29dfba867ff60401cfce1478812358644 --- .../Features/Project/ProjectListController.js | 19 +++++ services/web/app/views/project/list-react.pug | 1 + .../notifications/user-notifications.tsx | 2 + .../notifications/writefull-promo-banner.tsx | 77 +++++++++++++++++++ .../stylesheets/app/project-list.less | 3 + 5 files changed, 102 insertions(+) create mode 100644 services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx diff --git a/services/web/app/src/Features/Project/ProjectListController.js b/services/web/app/src/Features/Project/ProjectListController.js index 24ed4ac0cc..b891f2cbfc 100644 --- a/services/web/app/src/Features/Project/ProjectListController.js +++ b/services/web/app/src/Features/Project/ProjectListController.js @@ -21,6 +21,7 @@ const UserPrimaryEmailCheckHandler = require('../User/UserPrimaryEmailCheckHandl const UserController = require('../User/UserController') const LimitationsManager = require('../Subscription/LimitationsManager') const NotificationsBuilder = require('../Notifications/NotificationsBuilder') +const SplitTestHandler = require('../SplitTests/SplitTestHandler') /** @typedef {import("./types").GetProjectsRequest} GetProjectsRequest */ /** @typedef {import("./types").GetProjectsResponse} GetProjectsResponse */ @@ -319,6 +320,23 @@ async function projectListPage(req, res, next) { showGroupsAndEnterpriseBanner && _.sample(['did-you-know', 'on-premise', 'people', 'FOMO']) + let showWritefullPromoBanner = false + if (Features.hasFeature('saas') && !req.session.justRegistered) { + try { + const { variant } = await SplitTestHandler.promises.getAssignment( + req, + res, + 'writefull-promo-banner' + ) + showWritefullPromoBanner = variant === 'enabled' + } catch (error) { + logger.warn( + { err: error }, + 'failed to get "writefull-promo-banner" split test assignment' + ) + } + } + res.render('project/list-react', { title: 'your_projects', usersBestSubscription, @@ -335,6 +353,7 @@ async function projectListPage(req, res, next) { prefetchedProjectsBlob, showGroupsAndEnterpriseBanner, groupsAndEnterpriseBannerVariant, + showWritefullPromoBanner, projectDashboardReact: true, // used in navbar }) } diff --git a/services/web/app/views/project/list-react.pug b/services/web/app/views/project/list-react.pug index ca30d22469..f223e9acf3 100644 --- a/services/web/app/views/project/list-react.pug +++ b/services/web/app/views/project/list-react.pug @@ -26,6 +26,7 @@ block append meta })) meta(name="ol-currentUrl" data-type="string" content=currentUrl) meta(name="ol-showGroupsAndEnterpriseBanner" data-type="boolean" content=showGroupsAndEnterpriseBanner) + meta(name="ol-showWritefullPromoBanner" data-type="boolean" content=showWritefullPromoBanner) meta(name="ol-groupsAndEnterpriseBannerVariant" data-type="string" content=groupsAndEnterpriseBannerVariant) block content 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 948e9c0613..72f8cba2d2 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 @@ -3,6 +3,7 @@ import Institution from './groups/institution' import ConfirmEmail from './groups/confirm-email' import ReconfirmationInfo from './groups/affiliation/reconfirmation-info' import GroupsAndEnterpriseBanner from './groups-and-enterprise-banner' +import WritefullPromoBanner from './writefull-promo-banner' function UserNotifications() { return ( @@ -13,6 +14,7 @@ function UserNotifications() { + ) diff --git a/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx new file mode 100644 index 0000000000..6f1eb8cfee --- /dev/null +++ b/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx @@ -0,0 +1,77 @@ +import { memo, useCallback, useState } from 'react' +import Notification from './notification' +import { sendMB } from '../../../../infrastructure/event-tracking' +import getMeta from '../../../../utils/meta' +import customLocalStorage from '../../../../infrastructure/local-storage' + +const STORAGE_KEY = 'has_dismissed_writefull_promo_banner' + +const eventSegmentation = { + location: 'dashboard-banner', + page: '/project', + name: 'writefull', +} + +function WritefullPromoBanner() { + const [show, setShow] = useState(() => { + const show = + getMeta('ol-showWritefullPromoBanner') && + !customLocalStorage.getItem(STORAGE_KEY) + + if (show) { + sendMB('promo-prompt', eventSegmentation) + } + + return show + }) + + const handleOpenLink = useCallback(() => { + sendMB('promo-click', eventSegmentation) + }, []) + + const handleClose = useCallback(() => { + customLocalStorage.setItem(STORAGE_KEY, new Date()) + setShow(false) + sendMB('promo-dismiss', eventSegmentation) + }, []) + + if (!show) { + return null + } + + return ( + + + + Get 10% off Writefull premium—AI-based language feedback and + TeXGPT to help you write great papers faster. Use code:{' '} + OVERLEAF10 + + + + + Writefull Logo + Get Writefull for Overleaf + + + + ) +} + +export default memo(WritefullPromoBanner) diff --git a/services/web/frontend/stylesheets/app/project-list.less b/services/web/frontend/stylesheets/app/project-list.less index afffeb558c..ad37c1961d 100644 --- a/services/web/frontend/stylesheets/app/project-list.less +++ b/services/web/frontend/stylesheets/app/project-list.less @@ -248,6 +248,9 @@ input.project-list-table-select-item[type='checkbox'] { flex-wrap: nowrap; } } + &.centered-alert .alert { + align-items: center; + } } } .notification-body {