import { createContext, useContext, useMemo } from 'react' import PropTypes from 'prop-types' import useScopeValue from '../hooks/use-scope-value' import getMeta from '@/utils/meta' const ProjectContext = createContext() export const projectShape = { _id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, rootDocId: PropTypes.string, members: PropTypes.arrayOf( PropTypes.shape({ _id: PropTypes.string.isRequired, }) ), invites: PropTypes.arrayOf( PropTypes.shape({ _id: PropTypes.string.isRequired, }) ), features: PropTypes.shape({ collaborators: PropTypes.number, compileGroup: PropTypes.oneOf(['alpha', 'standard', 'priority']), trackChangesVisible: PropTypes.bool, references: PropTypes.bool, mendeley: PropTypes.bool, zotero: PropTypes.bool, versioning: PropTypes.bool, gitBridge: PropTypes.bool, }), publicAccessLevel: PropTypes.string, owner: PropTypes.shape({ _id: PropTypes.string.isRequired, email: PropTypes.string.isRequired, }), useNewCompileTimeoutUI: PropTypes.string, tags: PropTypes.arrayOf( PropTypes.shape({ _id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, color: PropTypes.string, }) ).isRequired, } ProjectContext.Provider.propTypes = { value: PropTypes.shape(projectShape), } export function useProjectContext(propTypes) { const context = useContext(ProjectContext) if (!context) { throw new Error( 'useProjectContext is only available inside ProjectProvider' ) } PropTypes.checkPropTypes( propTypes, context, 'data', 'ProjectContext.Provider' ) return context } // when the provider is created the project is still not added to the Angular // scope. A few props are populated to prevent errors in existing React // components const projectFallback = { _id: window.project_id, name: '', features: {}, } export function ProjectProvider({ children }) { const [project] = useScopeValue('project', true) const { _id, name, rootDoc_id: rootDocId, members, invites, features, publicAccesLevel: publicAccessLevel, owner, showNewCompileTimeoutUI, trackChangesState, } = project || projectFallback const tags = useMemo( () => getMeta('ol-projectTags', []) // `tag.name` data may be null for some old users .map(tag => ({ ...tag, name: tag.name ?? '' })), [] ) // temporary override for new compile timeout const forceNewCompileTimeout = new URLSearchParams( window.location.search ).get('force_new_compile_timeout') const newCompileTimeoutOverride = forceNewCompileTimeout === 'active' ? 'active' : forceNewCompileTimeout === 'changing' ? 'changing' : undefined const value = useMemo(() => { return { _id, name, rootDocId, members, invites, features, publicAccessLevel, owner, showNewCompileTimeoutUI: newCompileTimeoutOverride || showNewCompileTimeoutUI, tags, trackChangesState, } }, [ _id, name, rootDocId, members, invites, features, publicAccessLevel, owner, showNewCompileTimeoutUI, newCompileTimeoutOverride, tags, trackChangesState, ]) return ( {children} ) } ProjectProvider.propTypes = { children: PropTypes.any, }