Просмотр исходного кода

Add upgrade prompt for track changes in share modal (#24572)

* Add upgrade prompt for track changes in share modal

* remove message from invite.jsx

* Fix itemToDisabled in Select

GitOrigin-RevId: 5ba9e2b063c7e26a4c39b9e973eddce36a5b4733
Domagoj Kriskovic 1 год назад
Родитель
Сommit
1fb18b092d

+ 1 - 0
services/web/frontend/extracted-translations.json

@@ -267,6 +267,7 @@
   "comment": "",
   "comment": "",
   "comment_only": "",
   "comment_only": "",
   "comment_only_upgrade_for_track_changes": "",
   "comment_only_upgrade_for_track_changes": "",
+  "comment_only_upgrade_to_enable_track_changes": "",
   "common": "",
   "common": "",
   "common_causes_of_compile_timeouts_include": "",
   "common_causes_of_compile_timeouts_include": "",
   "commons_plan_tooltip": "",
   "commons_plan_tooltip": "",

+ 1 - 1
services/web/frontend/js/features/share-project-modal/components/add-collaborators.jsx

@@ -194,7 +194,7 @@ export default function AddCollaborators({ readOnly }) {
             itemToKey={item => item.key}
             itemToKey={item => item.key}
             itemToString={item => item.label}
             itemToString={item => item.label}
             itemToSubtitle={item => item.description || ''}
             itemToSubtitle={item => item.description || ''}
-            itemToDisabled={item => readOnly && item.key === 'readAndWrite'}
+            itemToDisabled={item => readOnly && item.key !== 'readOnly'}
             selected={privilegeOptions.find(
             selected={privilegeOptions.find(
               option => option.key === privileges
               option => option.key === privileges
             )}
             )}

+ 21 - 3
services/web/frontend/js/features/share-project-modal/components/edit-member.tsx

@@ -1,6 +1,6 @@
 import { useState, useEffect, useMemo } from 'react'
 import { useState, useEffect, useMemo } from 'react'
 import PropTypes from 'prop-types'
 import PropTypes from 'prop-types'
-import { useTranslation } from 'react-i18next'
+import { Trans, useTranslation } from 'react-i18next'
 import { useShareProjectContext } from './share-project-modal'
 import { useShareProjectContext } from './share-project-modal'
 import TransferOwnershipModal from './transfer-ownership-modal'
 import TransferOwnershipModal from './transfer-ownership-modal'
 import { removeMemberFromProject, updateMember } from '../utils/api'
 import { removeMemberFromProject, updateMember } from '../utils/api'
@@ -17,6 +17,7 @@ import MaterialIcon from '@/shared/components/material-icon'
 import getMeta from '@/utils/meta'
 import getMeta from '@/utils/meta'
 import { useUserContext } from '@/shared/context/user-context'
 import { useUserContext } from '@/shared/context/user-context'
 import { isSplitTestEnabled } from '@/utils/splitTestUtils'
 import { isSplitTestEnabled } from '@/utils/splitTestUtils'
+import { upgradePlan } from '@/main/account-upgrade'
 
 
 type PermissionsOption = PermissionsLevel | 'removeAccess' | 'downgraded'
 type PermissionsOption = PermissionsLevel | 'removeAccess' | 'downgraded'
 
 
@@ -25,6 +26,7 @@ type EditMemberProps = {
   hasExceededCollaboratorLimit: boolean
   hasExceededCollaboratorLimit: boolean
   hasBeenDowngraded: boolean
   hasBeenDowngraded: boolean
   canAddCollaborators: boolean
   canAddCollaborators: boolean
+  isReviewerOnFreeProject?: boolean
 }
 }
 
 
 type Privilege = {
 type Privilege = {
@@ -37,6 +39,7 @@ export default function EditMember({
   hasExceededCollaboratorLimit,
   hasExceededCollaboratorLimit,
   hasBeenDowngraded,
   hasBeenDowngraded,
   canAddCollaborators,
   canAddCollaborators,
+  isReviewerOnFreeProject,
 }: EditMemberProps) {
 }: EditMemberProps) {
   const [privileges, setPrivileges] = useState<PermissionsOption>(
   const [privileges, setPrivileges] = useState<PermissionsOption>(
     member.privileges
     member.privileges
@@ -144,7 +147,7 @@ export default function EditMember({
       }}
       }}
     >
     >
       <OLFormGroup className="project-member row">
       <OLFormGroup className="project-member row">
-        <OLCol xs={7}>
+        <OLCol xs={8}>
           <div className="project-member-email-icon">
           <div className="project-member-email-icon">
             <MaterialIcon
             <MaterialIcon
               type={
               type={
@@ -179,11 +182,26 @@ export default function EditMember({
                   })}
                   })}
                 </div>
                 </div>
               )}
               )}
+              {isReviewerOnFreeProject && (
+                <div className="small">
+                  <Trans
+                    i18nKey="comment_only_upgrade_to_enable_track_changes"
+                    components={[
+                      // eslint-disable-next-line react/jsx-key
+                      <OLButton
+                        variant="link"
+                        className="btn-inline-link"
+                        onClick={() => upgradePlan('track-changes')}
+                      />,
+                    ]}
+                  />
+                </div>
+              )}
             </div>
             </div>
           </div>
           </div>
         </OLCol>
         </OLCol>
 
 
-        <OLCol xs={5} className="project-member-actions">
+        <OLCol xs={4} className="project-member-actions">
           {confirmRemoval && (
           {confirmRemoval && (
             <ChangePrivilegesActions
             <ChangePrivilegesActions
               handleReset={() => setPrivileges(member.privileges)}
               handleReset={() => setPrivileges(member.privileges)}

+ 3 - 0
services/web/frontend/js/features/share-project-modal/components/share-modal-body.tsx

@@ -117,6 +117,9 @@ export default function ShareModalBody() {
               member.pendingEditor || member.pendingReviewer
               member.pendingEditor || member.pendingReviewer
             )}
             )}
             canAddCollaborators={canAddCollaborators}
             canAddCollaborators={canAddCollaborators}
+            isReviewerOnFreeProject={
+              member.privileges === 'review' && !features.trackChanges
+            }
           />
           />
         ) : (
         ) : (
           <ViewMember key={member._id} member={member} />
           <ViewMember key={member._id} member={member} />

+ 1 - 0
services/web/locales/en.json

@@ -348,6 +348,7 @@
   "comment": "Comment",
   "comment": "Comment",
   "comment_only": "Comment only",
   "comment_only": "Comment only",
   "comment_only_upgrade_for_track_changes": "Comment only. Upgrade for track changes.",
   "comment_only_upgrade_for_track_changes": "Comment only. Upgrade for track changes.",
+  "comment_only_upgrade_to_enable_track_changes": "Comment only. <0>Upgrade</0> to enable track changes.",
   "common": "Common",
   "common": "Common",
   "common_causes_of_compile_timeouts_include": "Common causes of compile timeouts include",
   "common_causes_of_compile_timeouts_include": "Common causes of compile timeouts include",
   "commons_plan_tooltip": "You’re on the __plan__ plan because of your affiliation with __institution__. Click to find out how to make the most of your Overleaf premium features.",
   "commons_plan_tooltip": "You’re on the __plan__ plan because of your affiliation with __institution__. Click to find out how to make the most of your Overleaf premium features.",

+ 2 - 2
services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx

@@ -700,7 +700,7 @@ describe('<ShareProjectModal/>', function () {
     const viewerOption = screen.getByText('Viewer').closest('button')
     const viewerOption = screen.getByText('Viewer').closest('button')
 
 
     expect(editorOption.classList.contains('disabled')).to.be.true
     expect(editorOption.classList.contains('disabled')).to.be.true
-    expect(reviewerOption.classList.contains('disabled')).to.be.false
+    expect(reviewerOption.classList.contains('disabled')).to.be.true
     expect(viewerOption.classList.contains('disabled')).to.be.false
     expect(viewerOption.classList.contains('disabled')).to.be.false
 
 
     screen.getByText(
     screen.getByText(
@@ -737,7 +737,7 @@ describe('<ShareProjectModal/>', function () {
     const viewerOption = screen.getByText('Viewer').closest('button')
     const viewerOption = screen.getByText('Viewer').closest('button')
 
 
     expect(editorOption.classList.contains('disabled')).to.be.true
     expect(editorOption.classList.contains('disabled')).to.be.true
-    expect(reviewerOption.classList.contains('disabled')).to.be.false
+    expect(reviewerOption.classList.contains('disabled')).to.be.true
     expect(viewerOption.classList.contains('disabled')).to.be.false
     expect(viewerOption.classList.contains('disabled')).to.be.false
 
 
     screen.getByText(
     screen.getByText(