mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Add new Link sharing upgrade prompt in project page (#8775)
GitOrigin-RevId: 984ab0770b3b920daa945ed8b190e7debf9e4a1d
This commit is contained in:
parent
d0d1791b04
commit
a2e2dcccda
7 changed files with 132 additions and 29 deletions
|
@ -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,
|
||||
|
|
|
@ -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": "",
|
||||
|
|
|
@ -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> </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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue