detach-context.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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))
  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. sysend.broadcast(SYSEND_CHANNEL, {
  68. role,
  69. event,
  70. data,
  71. })
  72. },
  73. [role]
  74. )
  75. useEffect(() => {
  76. broadcastEvent('connected')
  77. }, [broadcastEvent])
  78. useEffect(() => {
  79. const onBeforeUnload = () => broadcastEvent('closed')
  80. window.addEventListener('beforeunload', onBeforeUnload)
  81. return () => window.removeEventListener('beforeunload', onBeforeUnload)
  82. }, [broadcastEvent])
  83. const value = useMemo(
  84. () => ({
  85. role,
  86. setRole,
  87. broadcastEvent,
  88. addEventHandler,
  89. deleteEventHandler,
  90. }),
  91. [role, setRole, broadcastEvent, addEventHandler, deleteEventHandler]
  92. )
  93. return (
  94. <DetachContext.Provider value={value}>{children}</DetachContext.Provider>
  95. )
  96. }
  97. DetachProvider.propTypes = {
  98. children: PropTypes.any,
  99. }
  100. export function useDetachContext(propTypes) {
  101. const data = useContext(DetachContext)
  102. PropTypes.checkPropTypes(propTypes, data, 'data', 'DetachContext.Provider')
  103. return data
  104. }