project-context.jsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { createContext, useContext, useMemo } from 'react'
  2. import PropTypes from 'prop-types'
  3. import useScopeValue from '../hooks/use-scope-value'
  4. import getMeta from '@/utils/meta'
  5. const ProjectContext = createContext()
  6. export const projectShape = {
  7. _id: PropTypes.string.isRequired,
  8. name: PropTypes.string.isRequired,
  9. rootDocId: PropTypes.string,
  10. members: PropTypes.arrayOf(
  11. PropTypes.shape({
  12. _id: PropTypes.string.isRequired,
  13. })
  14. ),
  15. invites: PropTypes.arrayOf(
  16. PropTypes.shape({
  17. _id: PropTypes.string.isRequired,
  18. })
  19. ),
  20. features: PropTypes.shape({
  21. collaborators: PropTypes.number,
  22. compileGroup: PropTypes.oneOf(['alpha', 'standard', 'priority']),
  23. trackChangesVisible: PropTypes.bool,
  24. references: PropTypes.bool,
  25. mendeley: PropTypes.bool,
  26. zotero: PropTypes.bool,
  27. versioning: PropTypes.bool,
  28. gitBridge: PropTypes.bool,
  29. }),
  30. publicAccessLevel: PropTypes.string,
  31. owner: PropTypes.shape({
  32. _id: PropTypes.string.isRequired,
  33. email: PropTypes.string.isRequired,
  34. }),
  35. useNewCompileTimeoutUI: PropTypes.string,
  36. tags: PropTypes.arrayOf(
  37. PropTypes.shape({
  38. _id: PropTypes.string.isRequired,
  39. name: PropTypes.string.isRequired,
  40. color: PropTypes.string,
  41. })
  42. ).isRequired,
  43. }
  44. ProjectContext.Provider.propTypes = {
  45. value: PropTypes.shape(projectShape),
  46. }
  47. export function useProjectContext(propTypes) {
  48. const context = useContext(ProjectContext)
  49. if (!context) {
  50. throw new Error(
  51. 'useProjectContext is only available inside ProjectProvider'
  52. )
  53. }
  54. PropTypes.checkPropTypes(
  55. propTypes,
  56. context,
  57. 'data',
  58. 'ProjectContext.Provider'
  59. )
  60. return context
  61. }
  62. // when the provider is created the project is still not added to the Angular
  63. // scope. A few props are populated to prevent errors in existing React
  64. // components
  65. const projectFallback = {
  66. _id: window.project_id,
  67. name: '',
  68. features: {},
  69. }
  70. export function ProjectProvider({ children }) {
  71. const [project] = useScopeValue('project', true)
  72. const {
  73. _id,
  74. name,
  75. rootDoc_id: rootDocId,
  76. members,
  77. invites,
  78. features,
  79. publicAccesLevel: publicAccessLevel,
  80. owner,
  81. showNewCompileTimeoutUI,
  82. trackChangesState,
  83. } = project || projectFallback
  84. const tags = useMemo(
  85. () =>
  86. getMeta('ol-projectTags', [])
  87. // `tag.name` data may be null for some old users
  88. .map(tag => ({ ...tag, name: tag.name ?? '' })),
  89. []
  90. )
  91. // temporary override for new compile timeout
  92. const forceNewCompileTimeout = new URLSearchParams(
  93. window.location.search
  94. ).get('force_new_compile_timeout')
  95. const newCompileTimeoutOverride =
  96. forceNewCompileTimeout === 'active'
  97. ? 'active'
  98. : forceNewCompileTimeout === 'changing'
  99. ? 'changing'
  100. : undefined
  101. const value = useMemo(() => {
  102. return {
  103. _id,
  104. name,
  105. rootDocId,
  106. members,
  107. invites,
  108. features,
  109. publicAccessLevel,
  110. owner,
  111. showNewCompileTimeoutUI:
  112. newCompileTimeoutOverride || showNewCompileTimeoutUI,
  113. tags,
  114. trackChangesState,
  115. }
  116. }, [
  117. _id,
  118. name,
  119. rootDocId,
  120. members,
  121. invites,
  122. features,
  123. publicAccessLevel,
  124. owner,
  125. showNewCompileTimeoutUI,
  126. newCompileTimeoutOverride,
  127. tags,
  128. trackChangesState,
  129. ])
  130. return (
  131. <ProjectContext.Provider value={value}>{children}</ProjectContext.Provider>
  132. )
  133. }
  134. ProjectProvider.propTypes = {
  135. children: PropTypes.any,
  136. }