Add new Link sharing upgrade prompt in project page (#8775)

GitOrigin-RevId: 984ab0770b3b920daa945ed8b190e7debf9e4a1d
This commit is contained in:
M Fahru 2022-07-15 09:44:47 -04:00 committed by Copybot
parent d0d1791b04
commit a2e2dcccda
7 changed files with 132 additions and 29 deletions

View file

@ -968,6 +968,21 @@ const ProjectController = {
}
},
],
linkSharingUpgradePromptAssignment(cb) {
SplitTestHandler.getAssignment(
req,
res,
'link-sharing-upgrade-prompt',
(error, assignment) => {
// do not fail editor load if assignment fails
if (error) {
cb(null, { variant: 'default' })
} else {
cb(null, assignment)
}
}
)
},
},
(
err,

View file

@ -347,6 +347,7 @@
"please_set_main_file": "",
"plus_upgraded_accounts_receive": "",
"premium_feature": "",
"premium_makes_collab_easier_with_features": "",
"press_shortcut_to_open_advanced_reference_search": "",
"private": "",
"processing": "",
@ -485,6 +486,7 @@
"too_recently_compiled": "",
"total_words": "",
"try_again": "",
"try_for_free": "",
"try_it_for_free": "",
"try_premium_for_free": "",
"try_recompile_project_or_troubleshoot": "",

View file

@ -1,7 +1,7 @@
import { useCallback, useState } from 'react'
import PropTypes from 'prop-types'
import { Button, Col, Row } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import Tooltip from '../../../shared/components/tooltip'
import Icon from '../../../shared/components/icon'
import { useShareProjectContext } from './share-project-modal'
@ -10,8 +10,10 @@ import CopyLink from '../../../shared/components/copy-link'
import { useProjectContext } from '../../../shared/context/project-context'
import * as eventTracking from '../../../infrastructure/event-tracking'
import { useUserContext } from '../../../shared/context/user-context'
import StartFreeTrialButton from '../../../shared/components/start-free-trial-button'
import { useSplitTestContext } from '../../../shared/context/split-test-context'
export default function LinkSharing() {
export default function LinkSharing({ canAddCollaborators }) {
const [inflight, setInflight] = useState(false)
const { monitorRequest } = useShareProjectContext()
@ -51,6 +53,7 @@ export default function LinkSharing() {
<TokenBasedSharing
setAccessLevel={setAccessLevel}
inflight={inflight}
canAddCollaborators={canAddCollaborators}
/>
)
@ -70,6 +73,10 @@ export default function LinkSharing() {
}
}
LinkSharing.propTypes = {
canAddCollaborators: PropTypes.bool,
}
function PrivateSharing({ setAccessLevel, inflight }) {
return (
<Row className="public-access-level">
@ -100,7 +107,7 @@ PrivateSharing.propTypes = {
inflight: PropTypes.bool,
}
function TokenBasedSharing({ setAccessLevel, inflight }) {
function TokenBasedSharing({ setAccessLevel, inflight, canAddCollaborators }) {
const { tokens } = useProjectContext()
return (
@ -121,6 +128,7 @@ function TokenBasedSharing({ setAccessLevel, inflight }) {
<span>&nbsp;&nbsp;</span>
<LinkSharingInfo />
</Col>
<LinkSharingUpgradePrompt canAddCollaborators={canAddCollaborators} />
<Col xs={12} className="access-token-display-area">
<div className="access-token-wrapper">
<strong>
@ -150,6 +158,7 @@ function TokenBasedSharing({ setAccessLevel, inflight }) {
TokenBasedSharing.propTypes = {
setAccessLevel: PropTypes.func.isRequired,
inflight: PropTypes.bool,
canAddCollaborators: PropTypes.bool,
}
function LegacySharing({ accessLevel, setAccessLevel, inflight }) {
@ -257,3 +266,51 @@ function LinkSharingInfo() {
</Tooltip>
)
}
function LinkSharingUpgradePrompt({ canAddCollaborators }) {
const [startedFreeTrial, setStartedFreeTrial] = useState(false)
const { t } = useTranslation()
const { splitTestVariants } = useSplitTestContext()
const linkSharingUpgradePromptActive =
splitTestVariants['link-sharing-upgrade-prompt'] === 'active'
const user = useUserContext({
allowedFreeTrial: PropTypes.bool,
})
const showLinkSharingUpgradePrompt =
linkSharingUpgradePromptActive &&
user.allowedFreeTrial &&
canAddCollaborators
if (!showLinkSharingUpgradePrompt) {
return null
}
return (
<>
<Col xs={12} className="link-sharing-upgrade-prompt">
<p>
<Trans
i18nKey="premium_makes_collab_easier_with_features"
components={[<b />, <b />, <b />]} // eslint-disable-line react/jsx-key
/>
</p>
<StartFreeTrialButton
buttonStyle="success"
setStartedFreeTrial={setStartedFreeTrial}
source="link-sharing"
/>
</Col>
{startedFreeTrial && (
<p className="small teaser-refresh-label">
{t('refresh_page_after_starting_free_trial')}
</p>
)}
</>
)
}
LinkSharingUpgradePrompt.propTypes = {
canAddCollaborators: PropTypes.bool,
}

View file

@ -1,29 +1,16 @@
import { useMemo } from 'react'
import { Row } from 'react-bootstrap'
import AddCollaborators from './add-collaborators'
import AddCollaboratorsUpgrade from './add-collaborators-upgrade'
import { useProjectContext } from '../../../shared/context/project-context'
export default function SendInvites() {
const { members, invites, features } = useProjectContext()
// whether the project has not reached the collaborator limit
const canAddCollaborators = useMemo(() => {
if (!features) {
return false
}
if (features.collaborators === -1) {
// infinite collaborators
return true
}
return members.length + invites.length < features.collaborators
}, [members, invites, features])
import PropTypes from 'prop-types'
export default function SendInvites({ canAddCollaborators }) {
return (
<Row className="invite-controls">
{canAddCollaborators ? <AddCollaborators /> : <AddCollaboratorsUpgrade />}
</Row>
)
}
SendInvites.propTypes = {
canAddCollaborators: PropTypes.bool,
}

View file

@ -8,6 +8,7 @@ import SendInvitesNotice from './send-invites-notice'
import { useEditorContext } from '../../../shared/context/editor-context'
import { useProjectContext } from '../../../shared/context/project-context'
import { useSplitTestContext } from '../../../shared/context/split-test-context'
import { useMemo } from 'react'
import { Row } from 'react-bootstrap'
import PropTypes from 'prop-types'
import RecaptchaConditions from '../../../shared/components/recaptcha-conditions'
@ -17,8 +18,22 @@ export default function ShareModalBody() {
splitTestVariants: PropTypes.object,
})
const { members, invites, features } = useProjectContext()
const { isProjectOwner } = useEditorContext()
const { invites, members } = useProjectContext()
// whether the project has not reached the collaborator limit
const canAddCollaborators = useMemo(() => {
if (!isProjectOwner || !features) {
return false
}
if (features.collaborators === -1) {
// infinite collaborators
return true
}
return members.length + invites.length < features.collaborators
}, [members, invites, features, isProjectOwner])
switch (splitTestVariants['project-share-modal-paywall']) {
case 'new-copy-top':
@ -26,7 +41,7 @@ export default function ShareModalBody() {
<>
{isProjectOwner ? (
<>
<SendInvites />
<SendInvites canAddCollaborators={canAddCollaborators} />
<Row className="public-access-level" />
</>
) : (
@ -54,7 +69,7 @@ export default function ShareModalBody() {
{isProjectOwner && (
<>
<br />
<LinkSharing />
<LinkSharing canAddCollaborators={canAddCollaborators} />
</>
)}
@ -84,12 +99,16 @@ export default function ShareModalBody() {
/>
))}
{isProjectOwner ? <SendInvites /> : <SendInvitesNotice />}
{isProjectOwner ? (
<SendInvites canAddCollaborators={canAddCollaborators} />
) : (
<SendInvitesNotice />
)}
{isProjectOwner && (
<>
<br />
<LinkSharing />
<LinkSharing canAddCollaborators={canAddCollaborators} />
</>
)}
@ -103,7 +122,9 @@ export default function ShareModalBody() {
default:
return (
<>
{isProjectOwner && <LinkSharing />}
{isProjectOwner && (
<LinkSharing canAddCollaborators={canAddCollaborators} />
)}
<OwnerInfo />
@ -123,7 +144,11 @@ export default function ShareModalBody() {
/>
))}
{isProjectOwner ? <SendInvites /> : <SendInvitesNotice />}
{isProjectOwner ? (
<SendInvites canAddCollaborators={canAddCollaborators} />
) : (
<SendInvitesNotice />
)}
{!window.ExposedSettings.recaptchaDisabled?.invite && (
<RecaptchaConditions />

View file

@ -45,6 +45,22 @@
}
}
}
.link-sharing-upgrade-prompt {
background-color: @ol-blue-gray-0;
margin-top: @margin-sm;
padding: @padding-sm 15px;
display: flex;
align-items: center;
border-radius: 3px;
p {
margin-bottom: 0;
margin-right: 15px;
color: @ol-blue-gray-3;
font-size: 14px;
line-height: 23px;
}
}
}
.public-access-level.public-access-level--notice {

View file

@ -1790,6 +1790,7 @@
"trial_last_day": "This is the last day of your <b>Overleaf Premium</b> trial",
"trial_remaining_days": "__days__ more days on your <b>Overleaf Premium</b> trial",
"get_most_subscription_by_checking_premium_features": "Get the most out of your __appName__ subscription by checking out the list of <0>__appName__s premium features</0>.",
"premium_makes_collab_easier_with_features": "<0>Overleaf Premium</0> makes collaboration with others easier with features such as <1>track changes</1> and <2>full document history.</2>",
"would_you_like_to_see_a_university_subscription": "Would you like to see a university-wide __appName__ subscription at your university?",
"student_and_faculty_support_make_difference": "Student and faculty support make a difference! We can share this information with our contacts at your university when discussing an Overleaf institutional account.",
"show_your_support": "Show your support",