@bigfishtv/cockpit
Version:
116 lines (99 loc) • 3.13 kB
JavaScript
import { Component } from 'react'
import { connect } from 'react-redux'
import deepEqual from 'deep-equal'
import { xhrUtils, modalHandler, viewerActions, windowVisible, LoginModal } from '../index'
const CHECK_INTERVAL = 5 * 60 * 1000 // refresh every 5 minutes
const LAST_FETCH_TIME_STORAGE_KEY = 'COCKPIT_0_viewerLastFetchTime'
const VIEWER_URL = '/admin/tank/users/viewer.json'
const LOGIN_URL = '/admin/tank/users/login.json'
export default class ViewerState extends Component {
state = {
valid: true,
windowVisible: windowVisible.windowVisible(),
}
componentDidMount() {
// listen to visibility change
this.unsubscribeWindowVisible = windowVisible.onVisibilityChange(windowVisible => {
this.setState({ windowVisible })
})
// listen to requests on same site
this.removeInterceptor = xhrUtils.interceptResponse(undefined, res => {
if (res.status === 401 && res.config.url.match(/^\//) && res.config.url !== LOGIN_URL) {
this.setState({ valid: false })
}
return Promise.reject(res)
})
this.timeout = window.setTimeout(this.fetchViewer, CHECK_INTERVAL)
}
componentDidUpdate(prevProps, prevState) {
// show or hide login modal
if (this.state.valid !== prevState.valid) {
if (!this.state.valid) {
this.modal = modalHandler.add({
Component: LoginModal,
props: {},
closable: false,
})
} else {
modalHandler.remove(this.modal)
}
}
// don't bother checking if user has logged in again
// if the window isn't visible
if (!this.state.valid && !this.state.windowVisible) {
clearTimeout(this.timeout)
}
// if window becomes visible and the state is invalid, then fetch again
// to see if user has logged in another window
if (this.state.windowVisible !== prevState.windowVisible) {
if (this.state.windowVisible && !this.state.valid) {
this.fetchViewer()
}
}
}
componentWillUnmount() {
this.removeInterceptor()
this.unsubscribeWindowVisible()
clearTimeout(this.timeout)
}
fetchViewer = () => {
// schedule the next fetch
clearTimeout(this.timeout)
this.timeout = window.setTimeout(this.fetchViewer, CHECK_INTERVAL)
// don't bother fetching if another window has fetched recently
if (!this.state.windowVisible && hasFetchedRecently()) {
return
}
try {
window.localStorage.setItem(LAST_FETCH_TIME_STORAGE_KEY, `${Date.now()}`)
} catch (e) {}
xhrUtils.get({
url: VIEWER_URL,
quietError: !this.state.valid,
failureMessage: 'You have been logged out! Please login again',
callback: data => {
if (!deepEqual(data, this.props.viewer)) {
this.props.dispatch(viewerActions.setViewer(data))
}
this.setState({ valid: true })
},
callbackError: response => {
if (response.status === 401) {
this.setState({ valid: false })
}
},
})
}
render() {
return null
}
}
function hasFetchedRecently() {
try {
const lastFetchedTime = parseInt(window.localStorage.getItem(LAST_FETCH_TIME_STORAGE_KEY) || '-1')
return lastFetchedTime + CHECK_INTERVAL >= Date.now()
} catch (e) {
return false
}
}