All files / client/components HeaderNotification.tsx

0% Statements 0/30
0% Branches 0/13
0% Functions 0/10
0% Lines 0/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                                                                                                                                                                                                           
import React from 'react'
import { Dropdown, DropdownToggle } from 'reactstrap'
import DropdownMenu from './HeaderNotification/DropdownMenu'
import Icon from './Common/Icon'
import Crowi from 'client/util/Crowi'
import { Notification } from 'client/types/crowi'
 
interface Props {
  crowi: Crowi
  me: string
}
 
interface State {
  count: number
  loaded: boolean
  notifications: Notification[]
  open: boolean
}
 
export default class HeaderNotification extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props)
 
    this.state = {
      count: 0,
      loaded: false,
      notifications: [],
      open: false,
    }
  }
 
  componentDidMount() {
    this.initializeSocket()
    this.fetchList()
    this.fetchStatus()
  }
 
  initializeSocket() {
    this.props.crowi.getWebSocket().on('notification updated', (data: { user: string }) => {
      if (this.props.me === data.user) {
        this.fetchList()
        this.fetchStatus()
      }
    })
  }
 
  async fetchStatus() {
    try {
      const { count = null } = await this.props.crowi.apiGet('/notification.status')
      if (count !== null && count !== this.state.count) {
        this.setState({ count })
      }
    } catch (err) {
      // TODO: error handling
    }
  }
 
  async updateStatus() {
    try {
      await this.props.crowi.apiPost('/notification.read')
      this.setState({ count: 0 })
    } catch (err) {
      // TODO: error handling
    }
  }
 
  async fetchList() {
    const limit = 6
    try {
      const { notifications } = await this.props.crowi.apiGet('/notification.list', { limit })
      this.setState({ loaded: true, notifications })
    } catch (err) {
      // TODO: error handling
    }
  }
 
  toggle() {
    const { open, count } = this.state
    if (!open && count > 0) {
      this.updateStatus()
    }
    this.setState({ open: !open })
  }
 
  async handleNotificationOnClick(notification: Notification) {
    try {
      await this.props.crowi.apiPost('/notification.open', { id: notification._id })
      // jump to target page
      window.location.href = notification.target.path
    } catch (err) {
      // TODO: error handling
    }
  }
 
  render() {
    const { count, open, loaded, notifications } = this.state
 
    const badge = count > 0 ? <span className="badge badge-pill badge-danger notification-badge">{count}</span> : ''
 
    return (
      <Dropdown className="notification-wrapper" isOpen={open} toggle={this.toggle.bind(this)}>
        <DropdownToggle tag="a" className="nav-link">
          <Icon name="bell" /> {badge}
        </DropdownToggle>
        <DropdownMenu loaded={loaded} notifications={notifications} notificationClickHandler={this.handleNotificationOnClick.bind(this)} />
      </Dropdown>
    )
  }
}