Explorar o código

Merge pull request #18891 from overleaf/rh-share-modal-when-over-limit

[web]: Show share modal when over collaborator limit

GitOrigin-RevId: 6f5594310f21e481d5837ff8d7f098668ecd2957
roo hutton %!s(int64=2) %!d(string=hai) anos
pai
achega
853c1153e1

+ 3 - 2
services/web/frontend/js/features/ide-react/components/editor-navigation-toolbar.tsx

@@ -14,10 +14,10 @@ function EditorNavigationToolbar() {
   const { onlineUsersArray } = useOnlineUsersContext()
   const { openDoc } = useEditorManagerContext()
 
-  const handleOpenShareModal = () => {
+  const handleOpenShareModal = useCallback(() => {
     eventTracking.sendMBOnce('ide-open-share-modal-once')
     setShowShareModal(true)
-  }
+  }, [])
 
   const handleHideShareModal = useCallback(() => {
     setShowShareModal(false)
@@ -37,6 +37,7 @@ function EditorNavigationToolbar() {
           <EditorOverLimitModal />
           <NewShareProjectModal
             show={showShareModal}
+            handleOpen={handleOpenShareModal}
             handleHide={handleHideShareModal}
           />
         </>

+ 39 - 0
services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/share-project-modal.tsx

@@ -10,6 +10,8 @@ import { useProjectContext } from '@/shared/context/project-context'
 import { useSplitTestContext } from '@/shared/context/split-test-context'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { ProjectContextUpdateValue } from '@/shared/context/types/project-context'
+import { useEditorContext } from '@/shared/context/editor-context'
+import customLocalStorage from '@/infrastructure/local-storage'
 
 type ShareProjectContextValue = {
   updateProject: (project: ProjectContextUpdateValue) => void
@@ -24,6 +26,8 @@ type ShareProjectContextValue = {
   >
 }
 
+const SHOW_MODAL_COOLDOWN_PERIOD = 24 * 60 * 60 * 1000 // 24 hours
+
 const ShareProjectContext = createContext<ShareProjectContextValue | undefined>(
   undefined
 )
@@ -43,12 +47,14 @@ export function useShareProjectContext() {
 type ShareProjectModalProps = {
   handleHide: () => void
   show: boolean
+  handleOpen: () => void
   animation?: boolean
 }
 
 const ShareProjectModal = React.memo(function ShareProjectModal({
   handleHide,
   show,
+  handleOpen,
   animation = true,
 }: ShareProjectModalProps) {
   const [inFlight, setInFlight] =
@@ -56,9 +62,42 @@ const ShareProjectModal = React.memo(function ShareProjectModal({
   const [error, setError] = useState<ShareProjectContextValue['error']>()
 
   const project = useProjectContext()
+  const { isProjectOwner } = useEditorContext()
 
   const { splitTestVariants } = useSplitTestContext()
 
+  // split test: link-sharing-warning
+  // show the new share modal if project owner
+  // is over collaborator limit (once every 24 hours)
+  useEffect(() => {
+    const hasExceededCollaboratorLimit = () => {
+      if (!isProjectOwner || !project.features) {
+        return false
+      }
+
+      if (project.features.collaborators === -1) {
+        return false
+      }
+      return (
+        project.members.filter(member => member.privileges === 'readAndWrite')
+          .length > (project.features.collaborators ?? 1)
+      )
+    }
+
+    if (hasExceededCollaboratorLimit()) {
+      const localStorageKey = `last-shown-share-modal.${project._id}`
+      const lastShownShareModalTime =
+        customLocalStorage.getItem(localStorageKey)
+      if (
+        !lastShownShareModalTime ||
+        lastShownShareModalTime + SHOW_MODAL_COOLDOWN_PERIOD < Date.now()
+      ) {
+        handleOpen()
+        customLocalStorage.setItem(localStorageKey, Date.now())
+      }
+    }
+  }, [project, isProjectOwner, handleOpen])
+
   // send tracking event when the modal is opened
   useEffect(() => {
     if (show) {