Merge pull request #9584 from overleaf/jel-copy-modal-wrapper

[web] Add wrapper for copy modal

GitOrigin-RevId: 8291f953e418815797e8474a69de8f15c39af7b5
This commit is contained in:
Davinder Singh 2022-09-15 10:59:11 +01:00 committed by Copybot
parent 70e63ca0e3
commit 9cde88a9e8
5 changed files with 65 additions and 24 deletions

View file

@ -9,16 +9,16 @@ import {
FormControl, FormControl,
FormGroup, FormGroup,
} from 'react-bootstrap' } from 'react-bootstrap'
import { useProjectContext } from '../../../shared/context/project-context'
import { postJSON } from '../../../infrastructure/fetch-json' import { postJSON } from '../../../infrastructure/fetch-json'
export default function CloneProjectModalContent({ export default function CloneProjectModalContent({
handleHide, handleHide,
inFlight, inFlight,
setInFlight, setInFlight,
openProject, handleAfterCloned,
projectId,
projectName,
}) { }) {
const { _id: projectId, name: projectName } = useProjectContext()
const { t } = useTranslation() const { t } = useTranslation()
const [error, setError] = useState() const [error, setError] = useState()
@ -49,7 +49,7 @@ export default function CloneProjectModalContent({
}) })
.then(data => { .then(data => {
// open the cloned project // open the cloned project
openProject(data.project_id) handleAfterCloned(data)
}) })
.catch(({ response, data }) => { .catch(({ response, data }) => {
if (response?.status === 400) { if (response?.status === 400) {
@ -115,5 +115,7 @@ CloneProjectModalContent.propTypes = {
handleHide: PropTypes.func.isRequired, handleHide: PropTypes.func.isRequired,
inFlight: PropTypes.bool, inFlight: PropTypes.bool,
setInFlight: PropTypes.func.isRequired, setInFlight: PropTypes.func.isRequired,
openProject: PropTypes.func.isRequired, handleAfterCloned: PropTypes.func.isRequired,
projectId: PropTypes.string,
projectName: PropTypes.string,
} }

View file

@ -1,13 +1,14 @@
import React, { useCallback, useState } from 'react' import React, { memo, useCallback, useState } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import CloneProjectModalContent from './clone-project-modal-content' import CloneProjectModalContent from './clone-project-modal-content'
import AccessibleModal from '../../../shared/components/accessible-modal' import AccessibleModal from '../../../shared/components/accessible-modal'
import withErrorBoundary from '../../../infrastructure/error-boundary'
const CloneProjectModal = React.memo(function CloneProjectModal({ function CloneProjectModal({
show, show,
handleHide, handleHide,
openProject, handleAfterCloned,
projectId,
projectName,
}) { }) {
const [inFlight, setInFlight] = useState(false) const [inFlight, setInFlight] = useState(false)
@ -29,16 +30,20 @@ const CloneProjectModal = React.memo(function CloneProjectModal({
handleHide={onHide} handleHide={onHide}
inFlight={inFlight} inFlight={inFlight}
setInFlight={setInFlight} setInFlight={setInFlight}
openProject={openProject} handleAfterCloned={handleAfterCloned}
projectId={projectId}
projectName={projectName}
/> />
</AccessibleModal> </AccessibleModal>
) )
}) }
CloneProjectModal.propTypes = { CloneProjectModal.propTypes = {
handleHide: PropTypes.func.isRequired, handleHide: PropTypes.func.isRequired,
show: PropTypes.bool.isRequired, show: PropTypes.bool.isRequired,
openProject: PropTypes.func.isRequired, handleAfterCloned: PropTypes.func.isRequired,
projectId: PropTypes.string,
projectName: PropTypes.string,
} }
export default withErrorBoundary(CloneProjectModal) export default memo(CloneProjectModal)

View file

@ -0,0 +1,34 @@
import React from 'react'
import PropTypes from 'prop-types'
import { useProjectContext } from '../../../shared/context/project-context'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import CloneProjectModal from './clone-project-modal'
const EditorCloneProjectModalWrapper = React.memo(
function EditorCloneProjectModalWrapper({ show, handleHide, openProject }) {
const { _id: projectId, name: projectName } = useProjectContext()
if (!projectName) {
// wait for useProjectContext
return null
} else {
return (
<CloneProjectModal
handleHide={handleHide}
show={show}
handleAfterCloned={openProject}
projectId={projectId}
projectName={projectName}
/>
)
}
}
)
EditorCloneProjectModalWrapper.propTypes = {
handleHide: PropTypes.func.isRequired,
show: PropTypes.bool.isRequired,
openProject: PropTypes.func.isRequired,
}
export default withErrorBoundary(EditorCloneProjectModalWrapper)

View file

@ -1,6 +1,6 @@
import App from '../../../base' import App from '../../../base'
import { react2angular } from 'react2angular' import { react2angular } from 'react2angular'
import CloneProjectModal from '../components/clone-project-modal' import EditorCloneProjectModalWrapper from '../components/editor-clone-project-modal-wrapper'
import { rootContext } from '../../../shared/context/root-context' import { rootContext } from '../../../shared/context/root-context'
export default App.controller( export default App.controller(
@ -20,8 +20,8 @@ export default App.controller(
}) })
} }
$scope.openProject = projectId => { $scope.openProject = project => {
window.location.assign(`/project/${projectId}`) window.location.assign(`/project/${project.project_id}`)
} }
} }
) )
@ -29,7 +29,7 @@ export default App.controller(
App.component( App.component(
'cloneProjectModal', 'cloneProjectModal',
react2angular( react2angular(
rootContext.use(CloneProjectModal), rootContext.use(EditorCloneProjectModalWrapper),
Object.keys(CloneProjectModal.propTypes) Object.keys(EditorCloneProjectModalWrapper.propTypes)
) )
) )

View file

@ -2,10 +2,10 @@ import { fireEvent, screen, waitFor } from '@testing-library/react'
import { expect } from 'chai' import { expect } from 'chai'
import sinon from 'sinon' import sinon from 'sinon'
import fetchMock from 'fetch-mock' import fetchMock from 'fetch-mock'
import CloneProjectModal from '../../../../../frontend/js/features/clone-project-modal/components/clone-project-modal' import EditorCloneProjectModalWrapper from '../../../../../frontend/js/features/clone-project-modal/components/editor-clone-project-modal-wrapper'
import { renderWithEditorContext } from '../../../helpers/render-with-context' import { renderWithEditorContext } from '../../../helpers/render-with-context'
describe('<CloneProjectModal />', function () { describe('<EditorCloneProjectModalWrapper />', function () {
beforeEach(function () { beforeEach(function () {
fetchMock.reset() fetchMock.reset()
}) })
@ -24,7 +24,7 @@ describe('<CloneProjectModal />', function () {
const openProject = sinon.stub() const openProject = sinon.stub()
renderWithEditorContext( renderWithEditorContext(
<CloneProjectModal <EditorCloneProjectModalWrapper
handleHide={handleHide} handleHide={handleHide}
openProject={openProject} openProject={openProject}
show show
@ -49,7 +49,7 @@ describe('<CloneProjectModal />', function () {
const openProject = sinon.stub() const openProject = sinon.stub()
renderWithEditorContext( renderWithEditorContext(
<CloneProjectModal <EditorCloneProjectModalWrapper
handleHide={handleHide} handleHide={handleHide}
openProject={openProject} openProject={openProject}
show show
@ -112,7 +112,7 @@ describe('<CloneProjectModal />', function () {
const openProject = sinon.stub() const openProject = sinon.stub()
renderWithEditorContext( renderWithEditorContext(
<CloneProjectModal <EditorCloneProjectModalWrapper
handleHide={handleHide} handleHide={handleHide}
openProject={openProject} openProject={openProject}
show show
@ -149,7 +149,7 @@ describe('<CloneProjectModal />', function () {
const openProject = sinon.stub() const openProject = sinon.stub()
renderWithEditorContext( renderWithEditorContext(
<CloneProjectModal <EditorCloneProjectModalWrapper
handleHide={handleHide} handleHide={handleHide}
openProject={openProject} openProject={openProject}
show show