project-context.js 2.9 KB

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