diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index b00674e5aa..1a96484432 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -183,7 +183,6 @@ "blog": "", "browser": "", "by_subscribing_you_agree_to_our_terms_of_service": "", - "can_add_tracked_changes_and_comments": "", "can_edit": "", "can_edit_content": "", "can_link_institution_email_acct_to_institution_acct": "", @@ -268,6 +267,7 @@ "column_width_is_custom_click_to_resize": "", "column_width_is_x_click_to_resize": "", "comment": "", + "comment_only": "", "commit": "", "common": "", "common_causes_of_compile_timeouts_include": "", @@ -472,6 +472,7 @@ "editor_only": "", "editor_only_hide_pdf": "", "editor_theme": "", + "edits_become_suggestions": "", "educational_disclaimer": "", "educational_disclaimer_heading": "", "educational_percent_discount_applied": "", diff --git a/services/web/frontend/js/features/ide-react/context/permissions-context.tsx b/services/web/frontend/js/features/ide-react/context/permissions-context.tsx index 5398d54e8d..2f8fa65096 100644 --- a/services/web/frontend/js/features/ide-react/context/permissions-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/permissions-context.tsx @@ -9,6 +9,7 @@ import { import useScopeValue from '@/shared/hooks/use-scope-value' import { DeepReadonly } from '../../../../../types/utils' import useViewerPermissions from '@/shared/hooks/use-viewer-permissions' +import { useProjectContext } from '@/shared/context/project-context' export const PermissionsContext = createContext( undefined @@ -71,6 +72,13 @@ const linkSharingWarningPermissionsMap: typeof permissionsMap = { owner: permissionsMap.owner, } +const noTrackChangesPermissionsMap: typeof permissionsMap = { + readOnly: permissionsMap.readOnly, + readAndWrite: permissionsMap.readAndWrite, + review: { ...permissionsMap.review, trackedWrite: false }, + owner: permissionsMap.owner, +} + export const PermissionsProvider: React.FC = ({ children }) => { const [permissions, setPermissions] = useScopeValue>('permissions') @@ -80,18 +88,27 @@ export const PermissionsProvider: React.FC = ({ children }) => { } const hasViewerPermissions = useViewerPermissions() const anonymous = getMeta('ol-anonymous') + const project = useProjectContext() useEffect(() => { let activePermissionsMap if (hasViewerPermissions) { activePermissionsMap = linkSharingWarningPermissionsMap + } else if (anonymous) { + activePermissionsMap = anonymousPermissionsMap + } else if (!project.features.trackChanges) { + activePermissionsMap = noTrackChangesPermissionsMap } else { - activePermissionsMap = anonymous - ? anonymousPermissionsMap - : permissionsMap + activePermissionsMap = permissionsMap } setPermissions(activePermissionsMap[permissionsLevel]) - }, [anonymous, permissionsLevel, setPermissions, hasViewerPermissions]) + }, [ + anonymous, + permissionsLevel, + setPermissions, + hasViewerPermissions, + project.features.trackChanges, + ]) useEffect(() => { if (connectionState.forceDisconnected) { diff --git a/services/web/frontend/js/features/review-panel-new/components/review-mode-switcher.tsx b/services/web/frontend/js/features/review-panel-new/components/review-mode-switcher.tsx index c3cfea132b..275d7ef598 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-mode-switcher.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-mode-switcher.tsx @@ -1,4 +1,4 @@ -import { forwardRef, memo, MouseEventHandler } from 'react' +import { forwardRef, memo, MouseEventHandler, useState } from 'react' import { Dropdown, DropdownMenu, @@ -17,6 +17,8 @@ import { usePermissionsContext } from '@/features/ide-react/context/permissions- import usePersistedState from '@/shared/hooks/use-persisted-state' import { sendMB } from '@/infrastructure/event-tracking' import { useEditorContext } from '@/shared/context/editor-context' +import { useProjectContext } from '@/shared/context/project-context' +import UpgradeTrackChangesModal from '@/features/source-editor/components/review-panel/upgrade-track-changes-modal' type Mode = 'view' | 'review' | 'edit' @@ -26,15 +28,17 @@ const useCurrentMode = (): Mode => { const trackChangesForCurrentUser = trackChanges?.onForEveryone || (user && user.id && trackChanges?.onForMembers[user.id]) - const { write, trackedWrite } = usePermissionsContext() + const { permissionsLevel } = useEditorContext() - if (write && !trackChangesForCurrentUser) { - return 'edit' - } else if (trackedWrite) { + if (permissionsLevel === 'readOnly') { + return 'view' + } else if (permissionsLevel === 'review') { return 'review' + } else if (trackChangesForCurrentUser) { + return 'review' + } else { + return 'edit' } - - return 'view' } function ReviewModeSwitcher() { @@ -43,9 +47,10 @@ function ReviewModeSwitcher() { useTrackChangesStateActionsContext() const mode = useCurrentMode() const { permissionsLevel } = useEditorContext() - const { write, trackedWrite } = usePermissionsContext() - const showViewOption = !trackedWrite + const project = useProjectContext() + const [showUpgradeModal, setShowUpgradeModal] = useState(false) + const showViewOption = permissionsLevel === 'readOnly' return (
@@ -58,6 +63,9 @@ function ReviewModeSwitcher() { { + if (mode === 'edit') { + return + } sendMB('editing-mode-change', { role: permissionsLevel, previousMode: mode, @@ -72,16 +80,27 @@ function ReviewModeSwitcher() { {t('editing')} { - sendMB('editing-mode-change', { - role: permissionsLevel, - previousMode: mode, - newMode: 'review', - }) - saveTrackChangesForCurrentUser(true) + if (mode === 'review') { + return + } + if (!project.features.trackChanges) { + setShowUpgradeModal(true) + } else { + sendMB('editing-mode-change', { + role: permissionsLevel, + previousMode: mode, + newMode: 'review', + }) + saveTrackChangesForCurrentUser(true) + } }} - description={t('can_add_tracked_changes_and_comments')} + description={ + permissionsLevel === 'review' && !trackedWrite + ? t('comment_only') + : t('edits_become_suggestions') + } leadingIcon="rate_review" active={trackedWrite && mode === 'review'} > @@ -89,14 +108,6 @@ function ReviewModeSwitcher() { {showViewOption && ( { - sendMB('editing-mode-change', { - role: permissionsLevel, - previousMode: mode, - newMode: 'view', - }) - saveTrackChangesForCurrentUser(true) - }} description={t('can_view_content')} leadingIcon="visibility" active={mode === 'view'} @@ -106,6 +117,10 @@ function ReviewModeSwitcher() { )} +
) } diff --git a/services/web/locales/en.json b/services/web/locales/en.json index ac502cf088..d91b96f4d2 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -244,7 +244,6 @@ "by_joining_labs": "By joining Labs, you agree to receive occasional emails and updates from Overleaf—for example, to request your feedback. You also agree to our <0>terms of service and <1>privacy notice.", "by_registering_you_agree_to_our_terms_of_service": "By registering, you agree to our <0>terms of service and <1>privacy notice.", "by_subscribing_you_agree_to_our_terms_of_service": "By subscribing, you agree to our <0>terms of service.", - "can_add_tracked_changes_and_comments": "Can add tracked changes and comments", "can_edit": "Can edit", "can_edit_content": "Can edit content", "can_link_institution_email_acct_to_institution_acct": "You can now link your __email__ __appName__ account to your __institutionName__ institutional account.", @@ -349,6 +348,7 @@ "column_width_is_custom_click_to_resize": "Column width is custom. Click to resize", "column_width_is_x_click_to_resize": "Column width is __width__. Click to resize", "comment": "Comment", + "comment_only": "Comment only", "commit": "Commit", "common": "Common", "common_causes_of_compile_timeouts_include": "Common causes of compile timeouts include", @@ -611,6 +611,7 @@ "editor_only": "Editor only", "editor_only_hide_pdf": "Editor only <0>(hide PDF)", "editor_theme": "Editor theme", + "edits_become_suggestions": "Edits become suggestions", "educational_disclaimer": "I confirm that users will be students or faculty using Overleaf primarily for study and teaching, and can provide evidence of this if requested.", "educational_disclaimer_heading": "Educational discount confirmation", "educational_percent_discount_applied": "__percent__% educational discount applied!",