mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #18910 from overleaf/rh-editor-warning-over-limit
[web] Show warning modal to editors opening a project over collaborator limit GitOrigin-RevId: d9868c021d0aaf04bffd8afbd8c1c96fbf548755
This commit is contained in:
parent
cbda6b0bcc
commit
d16fee1afe
9 changed files with 167 additions and 11 deletions
|
@ -307,6 +307,7 @@
|
|||
"discount_of": "",
|
||||
"dismiss_error_popup": "",
|
||||
"display_deleted_user": "",
|
||||
"do_you_need_edit_access": "",
|
||||
"do_you_want_to_change_your_primary_email_address_to": "",
|
||||
"do_you_want_to_overwrite_it": "",
|
||||
"do_you_want_to_overwrite_it_plural": "",
|
||||
|
@ -451,6 +452,7 @@
|
|||
"free_plan_label": "",
|
||||
"free_plan_tooltip": "",
|
||||
"from_another_project": "",
|
||||
"from_enforcement_date": "",
|
||||
"from_external_url": "",
|
||||
"from_project_files": "",
|
||||
"from_provider": "",
|
||||
|
@ -710,6 +712,7 @@
|
|||
"license_for_educational_purposes": "",
|
||||
"limited_offer": "",
|
||||
"limited_to_n_editors_per_project": "",
|
||||
"limited_to_n_editors_per_project_plural": "",
|
||||
"line_height": "",
|
||||
"line_width_is_the_width_of_the_line_in_the_current_environment": "",
|
||||
"link": "",
|
||||
|
@ -1388,6 +1391,7 @@
|
|||
"this_grants_access_to_features_2": "",
|
||||
"this_is_a_labs_experiment": "",
|
||||
"this_project_exceeded_compile_timeout_limit_on_free_plan": "",
|
||||
"this_project_has_more_than_max_collabs": "",
|
||||
"this_project_is_public": "",
|
||||
"this_project_is_public_read_only": "",
|
||||
"this_project_will_appear_in_your_dropbox_folder_at": "",
|
||||
|
@ -1406,6 +1410,7 @@
|
|||
"to_fix_this_you_can": "",
|
||||
"to_fix_this_you_can_ask_the_github_repository_owner": "",
|
||||
"to_insert_or_move_a_caption_make_sure_tabular_is_directly_within_table": "",
|
||||
"to_keep_edit_access": "",
|
||||
"to_modify_your_subscription_go_to": "",
|
||||
"to_use_text_wrapping_in_your_table_make_sure_you_include_the_array_package": "",
|
||||
"toggle_compile_options_menu": "",
|
||||
|
@ -1646,6 +1651,7 @@
|
|||
"you_can_now_enable_sso": "",
|
||||
"you_can_now_log_in_sso": "",
|
||||
"you_can_only_add_n_people_to_edit_a_project": "",
|
||||
"you_can_only_add_n_people_to_edit_a_project_plural": "",
|
||||
"you_can_request_a_maximum_of_limit_fixes_per_day": "",
|
||||
"you_cant_add_or_change_password_due_to_sso": "",
|
||||
"you_cant_join_this_group_subscription": "",
|
||||
|
@ -1678,6 +1684,7 @@
|
|||
"your_plan": "",
|
||||
"your_plan_is_changing_at_term_end": "",
|
||||
"your_plan_is_limited_to_n_editors": "",
|
||||
"your_plan_is_limited_to_n_editors_plural": "",
|
||||
"your_project_exceeded_compile_timeout_limit_on_free_plan": "",
|
||||
"your_project_near_compile_timeout_limit": "",
|
||||
"your_projects": "",
|
||||
|
|
|
@ -5,6 +5,8 @@ import * as eventTracking from '@/infrastructure/event-tracking'
|
|||
import EditorNavigationToolbarRoot from '@/features/editor-navigation-toolbar/components/editor-navigation-toolbar-root'
|
||||
import NewShareProjectModal from '@/features/share-project-modal/components/restricted-link-sharing/share-project-modal'
|
||||
import ShareProjectModal from '@/features/share-project-modal/components/share-project-modal'
|
||||
import EditorOverLimitModal from '@/features/share-project-modal/components/restricted-link-sharing/editor-over-limit-modal'
|
||||
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
function EditorNavigationToolbar() {
|
||||
|
@ -31,10 +33,13 @@ function EditorNavigationToolbar() {
|
|||
openShareProjectModal={handleOpenShareModal}
|
||||
/>
|
||||
{showNewShareModal ? (
|
||||
<NewShareProjectModal
|
||||
show={showShareModal}
|
||||
handleHide={handleHideShareModal}
|
||||
/>
|
||||
<>
|
||||
<EditorOverLimitModal />
|
||||
<NewShareProjectModal
|
||||
show={showShareModal}
|
||||
handleHide={handleHideShareModal}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<ShareProjectModal
|
||||
show={showShareModal}
|
||||
|
|
|
@ -2,16 +2,28 @@ import { useTranslation } from 'react-i18next'
|
|||
import { Button } from 'react-bootstrap'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { upgradePlan } from '../../../../main/account-upgrade'
|
||||
import { linkSharingEnforcementDate } from '../../utils/link-sharing'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
|
||||
export default function AddCollaboratorsUpgrade() {
|
||||
const { t } = useTranslation()
|
||||
const { features } = useProjectContext()
|
||||
|
||||
return (
|
||||
<div className="add-collaborators-upgrade">
|
||||
<Notification
|
||||
type="warning"
|
||||
title={t('editor_limit_exceeded_in_this_project')}
|
||||
content={<p>{t('your_plan_is_limited_to_n_editors')}</p>}
|
||||
content={
|
||||
<p>
|
||||
{t('your_plan_is_limited_to_n_editors', {
|
||||
count: features.collaborators,
|
||||
})}{' '}
|
||||
{t('from_enforcement_date', {
|
||||
enforcementDate: linkSharingEnforcementDate,
|
||||
})}
|
||||
</p>
|
||||
}
|
||||
action={
|
||||
<div className="upgrade-actions">
|
||||
<Button
|
||||
|
|
|
@ -2,9 +2,11 @@ import { Button } from 'react-bootstrap'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { upgradePlan } from '@/main/account-upgrade'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
|
||||
export default function CollaboratorsLimitUpgrade() {
|
||||
const { t } = useTranslation()
|
||||
const { features } = useProjectContext()
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -12,7 +14,13 @@ export default function CollaboratorsLimitUpgrade() {
|
|||
type="info"
|
||||
customIcon={<div />}
|
||||
title={t('upgrade_to_add_more_editors')}
|
||||
content={<p>{t('you_can_only_add_n_people_to_edit_a_project')}</p>}
|
||||
content={
|
||||
<p>
|
||||
{t('you_can_only_add_n_people_to_edit_a_project', {
|
||||
count: features.collaborators,
|
||||
})}
|
||||
</p>
|
||||
}
|
||||
action={
|
||||
<Button
|
||||
bsSize="sm"
|
||||
|
|
|
@ -11,6 +11,7 @@ import { sendMB } from '@/infrastructure/event-tracking'
|
|||
import { Select } from '@/shared/components/select'
|
||||
import type { ProjectContextMember } from '@/shared/context/types/project-context'
|
||||
import { PermissionsLevel } from '@/features/ide-react/types/permissions'
|
||||
import { linkSharingEnforcementDate } from '../../utils/link-sharing'
|
||||
|
||||
type PermissionsOption = PermissionsLevel | 'removeAccess'
|
||||
|
||||
|
@ -129,7 +130,7 @@ export default function EditMember({
|
|||
{shouldWarnMember() && (
|
||||
<div className="subtitle">
|
||||
{t('will_lose_edit_access_on_date', {
|
||||
date: '[date]',
|
||||
date: linkSharingEnforcementDate,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
@ -180,6 +181,7 @@ function SelectPrivilege({
|
|||
canAddCollaborators,
|
||||
}: SelectPrivilegeProps) {
|
||||
const { t } = useTranslation()
|
||||
const { features } = useProjectContext()
|
||||
|
||||
const privileges = useMemo(
|
||||
(): Privilege[] => [
|
||||
|
@ -195,7 +197,7 @@ function SelectPrivilege({
|
|||
return !canAddCollaborators &&
|
||||
privilege === 'readAndWrite' &&
|
||||
value !== 'readAndWrite'
|
||||
? t('limited_to_n_editors_per_project')
|
||||
? t('limited_to_n_editors_per_project', { count: features.collaborators })
|
||||
: ''
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { Button, Modal } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { linkSharingEnforcementDate } from '../../utils/link-sharing'
|
||||
|
||||
type EditorOverLimitModalContentProps = {
|
||||
handleHide: () => void
|
||||
}
|
||||
|
||||
export default function EditorOverLimitModalContent({
|
||||
handleHide,
|
||||
}: EditorOverLimitModalContentProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>{t('do_you_need_edit_access')}</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
<p>
|
||||
{t('this_project_has_more_than_max_collabs', {
|
||||
linkSharingDate: linkSharingEnforcementDate,
|
||||
})}
|
||||
</p>
|
||||
<p>{t('to_keep_edit_access')}</p>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button
|
||||
bsStyle={null}
|
||||
className="btn-secondary"
|
||||
href="/blog/changes-to-project-sharing"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t('learn_more')}
|
||||
</Button>
|
||||
<Button className="btn-primary" onClick={handleHide}>
|
||||
{t('ok')}
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import AccessibleModal from '@/shared/components/accessible-modal'
|
||||
import EditorOverLimitModalContent from './editor-over-limit-modal-content'
|
||||
import customLocalStorage from '@/infrastructure/local-storage'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
|
||||
const EditorOverLimitModal = () => {
|
||||
const [show, setShow] = useState(false)
|
||||
|
||||
const { isProjectOwner, permissionsLevel } = useEditorContext()
|
||||
const { members, features, _id: projectId } = useProjectContext()
|
||||
|
||||
const handleHide = () => {
|
||||
setShow(false)
|
||||
}
|
||||
|
||||
// split test: link-sharing-warning
|
||||
// show the over-limit warning if user
|
||||
// is editor on a project over
|
||||
// collaborator limit (once every 24 hours)
|
||||
useEffect(() => {
|
||||
const showModalCooldownHours = 24
|
||||
const hasExceededCollaboratorLimit = () => {
|
||||
if (isProjectOwner || !features || permissionsLevel === 'readOnly') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (features.collaborators === -1) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
members.filter(member => member.privileges === 'readAndWrite').length >
|
||||
(features.collaborators ?? 1)
|
||||
)
|
||||
}
|
||||
|
||||
if (hasExceededCollaboratorLimit()) {
|
||||
const localStorageKey = `last-shown-need-edit-modal.${projectId}`
|
||||
const lastShownNeedEditModalTime =
|
||||
customLocalStorage.getItem(localStorageKey)
|
||||
if (
|
||||
!lastShownNeedEditModalTime ||
|
||||
lastShownNeedEditModalTime + showModalCooldownHours * 60 * 60 * 1000 <
|
||||
Date.now()
|
||||
) {
|
||||
setShow(true)
|
||||
customLocalStorage.setItem(localStorageKey, Date.now())
|
||||
}
|
||||
}
|
||||
}, [features, isProjectOwner, members, permissionsLevel, projectId])
|
||||
|
||||
return show ? (
|
||||
<AccessibleModal
|
||||
animation
|
||||
show={show}
|
||||
onHide={handleHide}
|
||||
id="editor-over-limit-modal"
|
||||
>
|
||||
<EditorOverLimitModalContent handleHide={handleHide} />
|
||||
</AccessibleModal>
|
||||
) : null
|
||||
}
|
||||
|
||||
export default EditorOverLimitModal
|
|
@ -0,0 +1,6 @@
|
|||
import { formatDate } from '@/utils/dates'
|
||||
|
||||
export const linkSharingEnforcementDate = formatDate(
|
||||
new Date(2024, 6, 29),
|
||||
'MMMM Do'
|
||||
) // July 29th 2024
|
|
@ -435,6 +435,7 @@
|
|||
"display_deleted_user": "Display deleted users",
|
||||
"do_not_have_acct_or_do_not_want_to_link": "If you don’t have an <b>__appName__</b> account, or if you don’t want to link to your <b>__institutionName__</b> account, please click <b>__clickText__</b>.",
|
||||
"do_not_link_accounts": "Don’t link accounts",
|
||||
"do_you_need_edit_access": "Do you need edit access?",
|
||||
"do_you_want_to_change_your_primary_email_address_to": "Do you want to change your primary email address to <b>__email__</b>?",
|
||||
"do_you_want_to_overwrite_it": "Do you want to overwrite it?",
|
||||
"do_you_want_to_overwrite_it_plural": "Do you want to overwrite them?",
|
||||
|
@ -676,6 +677,7 @@
|
|||
"free_plan_tooltip": "Click to find out how you could benefit from Overleaf premium features.",
|
||||
"frequently_asked_questions": "frequently asked questions",
|
||||
"from_another_project": "From another project",
|
||||
"from_enforcement_date": "From __enforcementDate__ any additional editors on this project will be made viewers.",
|
||||
"from_external_url": "From external URL",
|
||||
"from_project_files": "From project files",
|
||||
"from_provider": "From __provider__",
|
||||
|
@ -1040,7 +1042,8 @@
|
|||
"license": "License",
|
||||
"license_for_educational_purposes": "This license is for educational purposes (applies to students or faculty using __appName__ for teaching)",
|
||||
"limited_offer": "Limited offer",
|
||||
"limited_to_n_editors_per_project": "Limited to n editors per project",
|
||||
"limited_to_n_editors_per_project": "Limited to __count__ editor per project",
|
||||
"limited_to_n_editors_per_project_plural": "Limited to __count__ editors per project",
|
||||
"line_height": "Line Height",
|
||||
"line_width_is_the_width_of_the_line_in_the_current_environment": "Line width is the width of the line in the current environment. e.g. a full page width in single-column layout or half a page width in a two-column layout.",
|
||||
"link": "Link",
|
||||
|
@ -1987,6 +1990,7 @@
|
|||
"this_is_a_labs_experiment": "This is a Labs experiment",
|
||||
"this_is_your_template": "This is your template from your project",
|
||||
"this_project_exceeded_compile_timeout_limit_on_free_plan": "This project exceeded the compile timeout limit on our free plan.",
|
||||
"this_project_has_more_than_max_collabs": "This project has more than the maximum number of collaborators allowed on the project owner’s Overleaf plan. This means you could lose edit access from __linkSharingDate__.",
|
||||
"this_project_is_public": "This project is public and can be edited by anyone with the URL.",
|
||||
"this_project_is_public_read_only": "This project is public and can be viewed but not edited by anyone with the URL",
|
||||
"this_project_will_appear_in_your_dropbox_folder_at": "This project will appear in your Dropbox folder at ",
|
||||
|
@ -2009,6 +2013,7 @@
|
|||
"to_fix_this_you_can": "To fix this, you can:",
|
||||
"to_fix_this_you_can_ask_the_github_repository_owner": "To fix this, you can ask the GitHub repository owner (<0>__repoOwnerEmail__</0>) to renew their __appName__ subscription and reconnect the project.",
|
||||
"to_insert_or_move_a_caption_make_sure_tabular_is_directly_within_table": "To insert or move a caption, make sure \\begin{tabular} is directly within a table environment",
|
||||
"to_keep_edit_access": "To keep edit access, ask the project owner to upgrade their plan or reduce the number of people with edit access.",
|
||||
"to_many_login_requests_2_mins": "This account has had too many login requests. Please wait 2 minutes before trying to log in again",
|
||||
"to_modify_your_subscription_go_to": "To modify your subscription go to",
|
||||
"to_use_text_wrapping_in_your_table_make_sure_you_include_the_array_package": "<0>Please note:</0> To use text wrapping in your table, make sure you include the <1>array</1> package in your document preamble:",
|
||||
|
@ -2297,7 +2302,8 @@
|
|||
"you_can_also_choose_to_view_anonymously_or_leave_the_project": "You can also choose to <0>view anonymously</0> (you will lose edit access) or <1>leave the project</1>.",
|
||||
"you_can_now_enable_sso": "You can now enable SSO on your Group settings page.",
|
||||
"you_can_now_log_in_sso": "You can now log in through your institution and if eligible you will receive <0>__appName__ Professional features</0>.",
|
||||
"you_can_only_add_n_people_to_edit_a_project": "You can only add X people to edit a project with you on your current plan. Upgrade to add more.",
|
||||
"you_can_only_add_n_people_to_edit_a_project": "You can only add __count__ person to edit a project with you on your current plan. Upgrade to add more.",
|
||||
"you_can_only_add_n_people_to_edit_a_project_plural": "You can only add __count__ people to edit a project with you on your current plan. Upgrade to add more.",
|
||||
"you_can_opt_in_and_out_of_the_program_at_any_time_on_this_page": "You can <0>opt in and out</0> of the program at any time on this page",
|
||||
"you_can_request_a_maximum_of_limit_fixes_per_day": "You can request a maximum of __limit__ fixes per day. Please try again tomorrow.",
|
||||
"you_cant_add_or_change_password_due_to_sso": "You can’t add or change your password because your group or organization uses <0>single sign-on (SSO)</0>.",
|
||||
|
@ -2339,7 +2345,8 @@
|
|||
"your_password_was_detected": "Your password is on a <0>public list of known compromised passwords</0>. Keep your account safe by changing your password now.",
|
||||
"your_plan": "Your plan",
|
||||
"your_plan_is_changing_at_term_end": "Your plan is changing to <0>__pendingPlanName__</0> at the end of the current billing period.",
|
||||
"your_plan_is_limited_to_n_editors": "Your plan allows [n] collaborators with edit access and unlimited viewers. From [date] any additional editors on this project will be made viewers.",
|
||||
"your_plan_is_limited_to_n_editors": "Your plan allows __count__ collaborator with edit access and unlimited viewers.",
|
||||
"your_plan_is_limited_to_n_editors_plural": "Your plan allows __count__ collaborators with edit access and unlimited viewers.",
|
||||
"your_project_exceeded_compile_timeout_limit_on_free_plan": "Your project exceeded the compile timeout limit on our free plan.",
|
||||
"your_project_near_compile_timeout_limit": "Your project is near the compile timeout limit for our free plan.",
|
||||
"your_projects": "Your Projects",
|
||||
|
|
Loading…
Reference in a new issue