mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
eebeffc1c5
Improve React performance by memoizing components and values GitOrigin-RevId: 805278b8b7ac04c3dc4b078fa53cc0e3770d261b
172 lines
3.7 KiB
JavaScript
172 lines
3.7 KiB
JavaScript
import React, {
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useState,
|
|
} from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import ShareProjectModalContent from './share-project-modal-content'
|
|
import useScopeValue from '../../../shared/context/util/scope-value-hook'
|
|
|
|
const ShareProjectContext = createContext()
|
|
|
|
ShareProjectContext.Provider.propTypes = {
|
|
value: PropTypes.shape({
|
|
isAdmin: PropTypes.bool.isRequired,
|
|
updateProject: PropTypes.func.isRequired,
|
|
monitorRequest: PropTypes.func.isRequired,
|
|
inFlight: PropTypes.bool,
|
|
setInFlight: PropTypes.func,
|
|
error: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
setError: PropTypes.func,
|
|
}),
|
|
}
|
|
|
|
export function useShareProjectContext() {
|
|
const context = useContext(ShareProjectContext)
|
|
|
|
if (!context) {
|
|
throw new Error(
|
|
'useShareProjectContext is only available inside ShareProjectProvider'
|
|
)
|
|
}
|
|
|
|
return context
|
|
}
|
|
|
|
const projectShape = PropTypes.shape({
|
|
_id: PropTypes.string.isRequired,
|
|
members: PropTypes.arrayOf(
|
|
PropTypes.shape({
|
|
_id: PropTypes.string.isRequired,
|
|
})
|
|
),
|
|
invites: PropTypes.arrayOf(
|
|
PropTypes.shape({
|
|
_id: PropTypes.string.isRequired,
|
|
})
|
|
),
|
|
name: PropTypes.string,
|
|
features: PropTypes.shape({
|
|
collaborators: PropTypes.number,
|
|
}),
|
|
publicAccesLevel: PropTypes.string,
|
|
tokens: PropTypes.shape({
|
|
readOnly: PropTypes.string,
|
|
readAndWrite: PropTypes.string,
|
|
}),
|
|
owner: PropTypes.shape({
|
|
email: PropTypes.string,
|
|
}),
|
|
})
|
|
|
|
const ProjectContext = createContext()
|
|
|
|
ProjectContext.Provider.propTypes = {
|
|
value: projectShape,
|
|
}
|
|
|
|
export function useProjectContext() {
|
|
const context = useContext(ProjectContext)
|
|
|
|
if (!context) {
|
|
throw new Error(
|
|
'useProjectContext is only available inside ShareProjectProvider'
|
|
)
|
|
}
|
|
|
|
return context
|
|
}
|
|
|
|
const ShareProjectModal = React.memo(function ShareProjectModal({
|
|
handleHide,
|
|
show,
|
|
animation = true,
|
|
isAdmin,
|
|
}) {
|
|
const [inFlight, setInFlight] = useState(false)
|
|
const [error, setError] = useState()
|
|
|
|
const [project, setProject] = useScopeValue('project', true)
|
|
|
|
// reset error when the modal is opened
|
|
useEffect(() => {
|
|
if (show) {
|
|
setError(undefined)
|
|
}
|
|
}, [show])
|
|
|
|
// close the modal if not in flight
|
|
const cancel = useCallback(() => {
|
|
if (!inFlight) {
|
|
handleHide()
|
|
}
|
|
}, [handleHide, inFlight])
|
|
|
|
// update `error` and `inFlight` while sending a request
|
|
const monitorRequest = useCallback(request => {
|
|
setError(undefined)
|
|
setInFlight(true)
|
|
|
|
const promise = request()
|
|
|
|
promise.catch(error => {
|
|
setError(
|
|
error.data?.errorReason ||
|
|
error.data?.error ||
|
|
'generic_something_went_wrong'
|
|
)
|
|
})
|
|
|
|
promise.finally(() => {
|
|
setInFlight(false)
|
|
})
|
|
|
|
return promise
|
|
}, [])
|
|
|
|
// merge the new data with the old project data
|
|
const updateProject = useCallback(
|
|
data => {
|
|
setProject(project => Object.assign(project, data))
|
|
},
|
|
[setProject]
|
|
)
|
|
|
|
if (!project) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<ShareProjectContext.Provider
|
|
value={{
|
|
isAdmin,
|
|
updateProject,
|
|
monitorRequest,
|
|
inFlight,
|
|
setInFlight,
|
|
error,
|
|
setError,
|
|
}}
|
|
>
|
|
<ProjectContext.Provider value={project}>
|
|
<ShareProjectModalContent
|
|
animation={animation}
|
|
cancel={cancel}
|
|
error={error}
|
|
inFlight={inFlight}
|
|
show={show}
|
|
/>
|
|
</ProjectContext.Provider>
|
|
</ShareProjectContext.Provider>
|
|
)
|
|
})
|
|
ShareProjectModal.propTypes = {
|
|
animation: PropTypes.bool,
|
|
handleHide: PropTypes.func.isRequired,
|
|
isAdmin: PropTypes.bool.isRequired,
|
|
show: PropTypes.bool.isRequired,
|
|
}
|
|
|
|
export default ShareProjectModal
|