detach-context.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {
  2. createContext,
  3. useContext,
  4. useCallback,
  5. useMemo,
  6. useEffect,
  7. useState,
  8. } from 'react'
  9. import PropTypes from 'prop-types'
  10. import sysend from 'sysend'
  11. import getMeta from '../../utils/meta'
  12. import { buildUrlWithDetachRole } from '../utils/url-helper'
  13. import useCallbackHandlers from '../hooks/use-callback-handlers'
  14. export const DetachContext = createContext()
  15. DetachContext.Provider.propTypes = {
  16. value: PropTypes.shape({
  17. role: PropTypes.oneOf(['detacher', 'detached', null]),
  18. setRole: PropTypes.func.isRequired,
  19. broadcastEvent: PropTypes.func.isRequired,
  20. addEventHandler: PropTypes.func.isRequired,
  21. deleteEventHandler: PropTypes.func.isRequired,
  22. }).isRequired,
  23. }
  24. const debugPdfDetach = getMeta('ol-debugPdfDetach')
  25. const SYSEND_CHANNEL = `detach-${getMeta('ol-project_id')}`
  26. export function DetachProvider({ children }) {
  27. const [role, setRole] = useState(() => getMeta('ol-detachRole') || null)
  28. const {
  29. addHandler: addEventHandler,
  30. deleteHandler: deleteEventHandler,
  31. callHandlers: callEventHandlers,
  32. } = useCallbackHandlers()
  33. useEffect(() => {
  34. if (debugPdfDetach) {
  35. console.log('Effect', { role })
  36. }
  37. window.history.replaceState({}, '', buildUrlWithDetachRole(role).toString())
  38. }, [role])
  39. useEffect(() => {
  40. sysend.on(SYSEND_CHANNEL, message => {
  41. if (debugPdfDetach) {
  42. console.log(`Receiving:`, message)
  43. }
  44. callEventHandlers(message)
  45. })
  46. return () => sysend.off(SYSEND_CHANNEL)
  47. }, [callEventHandlers])
  48. const broadcastEvent = useCallback(
  49. (event, data) => {
  50. if (!role) {
  51. if (debugPdfDetach) {
  52. console.log('Not Broadcasting (no role)', {
  53. role,
  54. event,
  55. data,
  56. })
  57. }
  58. return
  59. }
  60. if (debugPdfDetach) {
  61. console.log('Broadcasting', {
  62. role,
  63. event,
  64. data,
  65. })
  66. }
  67. const message = {
  68. role,
  69. event,
  70. }
  71. if (data) {
  72. message.data = data
  73. }
  74. sysend.broadcast(SYSEND_CHANNEL, message)
  75. },
  76. [role]
  77. )
  78. useEffect(() => {
  79. broadcastEvent('connected')
  80. }, [broadcastEvent])
  81. useEffect(() => {
  82. const onBeforeUnload = () => broadcastEvent('closed')
  83. window.addEventListener('beforeunload', onBeforeUnload)
  84. return () => window.removeEventListener('beforeunload', onBeforeUnload)
  85. }, [broadcastEvent])
  86. const value = useMemo(
  87. () => ({
  88. role,
  89. setRole,
  90. broadcastEvent,
  91. addEventHandler,
  92. deleteEventHandler,
  93. }),
  94. [role, setRole, broadcastEvent, addEventHandler, deleteEventHandler]
  95. )
  96. return (
  97. <DetachContext.Provider value={value}>{children}</DetachContext.Provider>
  98. )
  99. }
  100. DetachProvider.propTypes = {
  101. children: PropTypes.any,
  102. }
  103. export function useDetachContext(propTypes) {
  104. const data = useContext(DetachContext)
  105. PropTypes.checkPropTypes(propTypes, data, 'data', 'DetachContext.Provider')
  106. return data
  107. }