import React from 'react'; import {getAllBroadcasts, markBroadcastsAsSeen} from 'app/actionCreators/broadcasts'; import {Client} from 'app/api'; import DemoModeGate from 'app/components/acl/demoModeGate'; import LoadingIndicator from 'app/components/loadingIndicator'; import BroadcastSdkUpdates from 'app/components/sidebar/broadcastSdkUpdates'; import SidebarItem from 'app/components/sidebar/sidebarItem'; import SidebarPanel from 'app/components/sidebar/sidebarPanel'; import SidebarPanelEmpty from 'app/components/sidebar/sidebarPanelEmpty'; import SidebarPanelItem from 'app/components/sidebar/sidebarPanelItem'; import {IconBroadcast} from 'app/icons'; import {t} from 'app/locale'; import {Broadcast, Organization} from 'app/types'; import withApi from 'app/utils/withApi'; import {CommonSidebarProps, SidebarPanelKey} from './types'; const MARK_SEEN_DELAY = 1000; const POLLER_DELAY = 600000; // 10 minute poll (60 * 10 * 1000) type Props = CommonSidebarProps & { api: Client; organization: Organization; }; type State = { broadcasts: Broadcast[]; loading: boolean; error: boolean; }; class Broadcasts extends React.Component { state: State = { broadcasts: [], loading: true, error: false, }; componentDidMount() { this.fetchData(); document.addEventListener('visibilitychange', this.handleVisibilityChange); } componentWillUnmount() { if (this.timer) { window.clearTimeout(this.timer); this.timer = null; } if (this.poller) { this.stopPoll(); } document.removeEventListener('visibilitychange', this.handleVisibilityChange); } poller: number | null = null; timer: number | null = null; startPoll() { this.poller = window.setTimeout(this.fetchData, POLLER_DELAY); } stopPoll() { if (this.poller) { window.clearTimeout(this.poller); this.poller = null; } } fetchData = async () => { if (this.poller) { this.stopPoll(); } try { const data = await getAllBroadcasts(this.props.api, this.props.organization.slug); this.setState({loading: false, broadcasts: data || []}); } catch { this.setState({loading: false, error: true}); } this.startPoll(); }; /** * If tab/window loses visibility (note: this is different than focus), stop * polling for broadcasts data, otherwise, if it gains visibility, start * polling again. */ handleVisibilityChange = () => (document.hidden ? this.stopPoll() : this.startPoll()); handleShowPanel = () => { this.timer = window.setTimeout(this.markSeen, MARK_SEEN_DELAY); this.props.onShowPanel(); }; markSeen = async () => { const unseenBroadcastIds = this.unseenIds; if (unseenBroadcastIds.length === 0) { return; } await markBroadcastsAsSeen(this.props.api, unseenBroadcastIds); this.setState(state => ({ broadcasts: state.broadcasts.map(item => ({...item, hasSeen: true})), })); }; get unseenIds() { return this.state.broadcasts ? this.state.broadcasts.filter(item => !item.hasSeen).map(item => item.id) : []; } render() { const {orientation, collapsed, currentPanel, hidePanel} = this.props; const {broadcasts, loading} = this.state; const unseenPosts = this.unseenIds; return ( } label={t("What's new")} onClick={this.handleShowPanel} id="broadcasts" /> {currentPanel === SidebarPanelKey.Broadcasts && ( {loading ? ( ) : broadcasts.length === 0 ? ( {t('No recent updates from the Sentry team.')} ) : ( broadcasts.map(item => ( )) )} )} ); } } export default withApi(Broadcasts);