2021-11-30 09:54:14 -05:00
|
|
|
import { useCallback, useState, useEffect, useRef } from 'react'
|
2021-11-15 11:33:57 -05:00
|
|
|
import { useDetachContext } from '../context/detach-context'
|
|
|
|
import getMeta from '../../utils/meta'
|
|
|
|
import { buildUrlWithDetachRole } from '../utils/url-helper'
|
2021-11-30 09:54:14 -05:00
|
|
|
import * as eventTracking from '../../infrastructure/event-tracking'
|
|
|
|
import usePreviousValue from './use-previous-value'
|
2021-11-15 11:33:57 -05:00
|
|
|
|
|
|
|
const debugPdfDetach = getMeta('ol-debugPdfDetach')
|
|
|
|
|
2021-11-30 09:54:14 -05:00
|
|
|
const LINKING_TIMEOUT = 60000
|
|
|
|
const RELINK_TIMEOUT = 10000
|
|
|
|
|
2021-11-15 11:33:57 -05:00
|
|
|
export default function useDetachLayout() {
|
|
|
|
const {
|
|
|
|
role,
|
|
|
|
setRole,
|
|
|
|
broadcastEvent,
|
|
|
|
addEventHandler,
|
|
|
|
deleteEventHandler,
|
|
|
|
} = useDetachContext()
|
|
|
|
|
2021-11-30 09:54:14 -05:00
|
|
|
// isLinking: when the tab expects to be linked soon (e.g. on detach)
|
|
|
|
const [isLinking, setIsLinking] = useState(false)
|
|
|
|
|
|
|
|
// isLinked: when the tab is linked to another tab (of different role)
|
|
|
|
const [isLinked, setIsLinked] = useState(false)
|
|
|
|
|
|
|
|
const uiTimeoutRef = useRef()
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (debugPdfDetach) {
|
|
|
|
console.log('Effect', { isLinked })
|
|
|
|
}
|
|
|
|
setIsLinking(false)
|
|
|
|
}, [isLinked, setIsLinking])
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (uiTimeoutRef.current) {
|
|
|
|
clearTimeout(uiTimeoutRef.current)
|
2021-11-15 11:33:57 -05:00
|
|
|
}
|
2021-11-30 09:54:14 -05:00
|
|
|
if (role === 'detacher' && isLinked === false) {
|
|
|
|
// the detacher tab either a) disconnected from its detached tab(s), b)is
|
|
|
|
// loading and no detached tab(s) is connected yet or c) is detaching and
|
|
|
|
// waiting for the detached tab to connect. Start a timeout to put
|
|
|
|
// the tab back in non-detacher role in case no detached tab are connected
|
|
|
|
uiTimeoutRef.current = setTimeout(
|
|
|
|
() => {
|
|
|
|
setRole(null)
|
|
|
|
},
|
|
|
|
isLinking ? LINKING_TIMEOUT : RELINK_TIMEOUT
|
|
|
|
)
|
2021-11-15 11:33:57 -05:00
|
|
|
}
|
2021-11-30 09:54:14 -05:00
|
|
|
}, [role, isLinking, isLinked, setRole])
|
2021-11-15 11:33:57 -05:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (debugPdfDetach) {
|
2021-11-30 09:54:14 -05:00
|
|
|
console.log('Effect', { isLinking })
|
|
|
|
}
|
|
|
|
}, [isLinking])
|
|
|
|
|
|
|
|
const previousRole = usePreviousValue(role)
|
|
|
|
useEffect(() => {
|
|
|
|
if (previousRole && !role) {
|
|
|
|
eventTracking.sendMB('project-layout-reattached')
|
2021-11-15 11:33:57 -05:00
|
|
|
}
|
2021-11-30 09:54:14 -05:00
|
|
|
}, [previousRole, role])
|
2021-11-15 11:33:57 -05:00
|
|
|
|
|
|
|
const reattach = useCallback(() => {
|
|
|
|
broadcastEvent('reattach')
|
|
|
|
setRole(null)
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(false)
|
|
|
|
}, [setRole, setIsLinked, broadcastEvent])
|
2021-11-15 11:33:57 -05:00
|
|
|
|
|
|
|
const detach = useCallback(() => {
|
|
|
|
setRole('detacher')
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinking(true)
|
2021-11-15 11:33:57 -05:00
|
|
|
|
|
|
|
window.open(buildUrlWithDetachRole('detached'), '_blank')
|
2021-11-30 09:54:14 -05:00
|
|
|
}, [setRole, setIsLinking])
|
2021-11-15 11:33:57 -05:00
|
|
|
|
|
|
|
const handleEventForDetacherFromDetached = useCallback(
|
|
|
|
message => {
|
|
|
|
switch (message.event) {
|
|
|
|
case 'connected':
|
|
|
|
broadcastEvent('up')
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(true)
|
2021-11-15 11:33:57 -05:00
|
|
|
break
|
|
|
|
case 'up':
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(true)
|
2021-11-15 11:33:57 -05:00
|
|
|
break
|
|
|
|
case 'closed':
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(false)
|
2021-11-15 11:33:57 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
},
|
2021-11-30 09:54:14 -05:00
|
|
|
[setIsLinked, broadcastEvent]
|
2021-11-15 11:33:57 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const handleEventForDetachedFromDetacher = useCallback(
|
|
|
|
message => {
|
|
|
|
switch (message.event) {
|
|
|
|
case 'connected':
|
|
|
|
broadcastEvent('up')
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(true)
|
2021-11-15 11:33:57 -05:00
|
|
|
break
|
|
|
|
case 'up':
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(true)
|
2021-11-15 11:33:57 -05:00
|
|
|
break
|
|
|
|
case 'closed':
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(false)
|
2021-11-15 11:33:57 -05:00
|
|
|
break
|
|
|
|
case 'reattach':
|
2021-11-30 09:54:14 -05:00
|
|
|
setIsLinked(false) // set as unlinked, in case closing is not allowed
|
2021-11-15 11:33:57 -05:00
|
|
|
window.close()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
},
|
2021-11-30 09:54:14 -05:00
|
|
|
[setIsLinked, broadcastEvent]
|
2021-11-15 11:33:57 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const handleEventFromSelf = useCallback(
|
|
|
|
message => {
|
|
|
|
switch (message.event) {
|
|
|
|
case 'closed':
|
|
|
|
broadcastEvent('up')
|
|
|
|
break
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[broadcastEvent]
|
|
|
|
)
|
|
|
|
|
|
|
|
const handleEvent = useCallback(
|
|
|
|
message => {
|
|
|
|
if (role === 'detacher') {
|
|
|
|
if (message.role === 'detacher') {
|
|
|
|
handleEventFromSelf(message)
|
|
|
|
} else if (message.role === 'detached') {
|
|
|
|
handleEventForDetacherFromDetached(message)
|
|
|
|
}
|
|
|
|
} else if (role === 'detached') {
|
|
|
|
if (message.role === 'detacher') {
|
|
|
|
handleEventForDetachedFromDetacher(message)
|
|
|
|
} else if (message.role === 'detached') {
|
|
|
|
handleEventFromSelf(message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[
|
|
|
|
role,
|
|
|
|
handleEventForDetacherFromDetached,
|
|
|
|
handleEventForDetachedFromDetacher,
|
|
|
|
handleEventFromSelf,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
addEventHandler(handleEvent)
|
|
|
|
return () => deleteEventHandler(handleEvent)
|
|
|
|
}, [addEventHandler, deleteEventHandler, handleEvent])
|
|
|
|
|
|
|
|
return {
|
|
|
|
reattach,
|
|
|
|
detach,
|
2021-11-30 09:54:14 -05:00
|
|
|
isLinked,
|
|
|
|
isLinking,
|
2021-11-15 11:33:57 -05:00
|
|
|
role,
|
|
|
|
}
|
|
|
|
}
|