RightContent.js 7.27 KB
Newer Older
jim's avatar
jim committed
1
import React, { PureComponent } from 'react';
2
import { FormattedMessage, formatMessage } from 'umi/locale';
3
import { Spin, Tag, Menu, Icon, Avatar, Tooltip } from 'antd';
jim's avatar
jim committed
4 5
import moment from 'moment';
import groupBy from 'lodash/groupBy';
6
import NoticeIcon from 'ant-design-pro/lib/NoticeIcon';
jim's avatar
jim committed
7
import HeaderSearch from '../HeaderSearch';
8
import HeaderDropdown from '../HeaderDropdown';
9
import SelectLang from '../SelectLang';
jim's avatar
jim committed
10 11 12 13 14 15 16 17
import styles from './index.less';

export default class GlobalHeaderRight extends PureComponent {
  getNoticeData() {
    const { notices = [] } = this.props;
    if (notices.length === 0) {
      return {};
    }
jim's avatar
jim committed
18
    const newNotices = notices.map(notice => {
jim's avatar
jim committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
      const newNotice = { ...notice };
      if (newNotice.datetime) {
        newNotice.datetime = moment(notice.datetime).fromNow();
      }
      if (newNotice.id) {
        newNotice.key = newNotice.id;
      }
      if (newNotice.extra && newNotice.status) {
        const color = {
          todo: '',
          processing: 'blue',
          urgent: 'red',
          doing: 'gold',
        }[newNotice.status];
        newNotice.extra = (
          <Tag color={color} style={{ marginRight: 0 }}>
            {newNotice.extra}
          </Tag>
        );
      }
      return newNotice;
    });
    return groupBy(newNotices, 'type');
  }
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
  getUnreadData = noticeData => {
    const unreadMsg = {};
    Object.entries(noticeData).forEach(([key, value]) => {
      if (!unreadMsg[key]) {
        unreadMsg[key] = 0;
      }
      if (Array.isArray(value)) {
        unreadMsg[key] = value.filter(item => !item.read).length;
      }
    });
    return unreadMsg;
  };

  changeReadState = clickedItem => {
    const { id } = clickedItem;
    const { dispatch } = this.props;
    dispatch({
      type: 'global/changeNoticeReadState',
      payload: id,
    });
  };

何乐's avatar
何乐 committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79
  fetchMoreNotices = tabProps => {
    const { list, name } = tabProps;
    const { dispatch, notices = [] } = this.props;
    const lastItemId = notices[notices.length - 1].id;
    dispatch({
      type: 'global/fetchMoreNotices',
      payload: {
        lastItemId,
        type: name,
        offset: list.length,
      },
    });
  };

jim's avatar
jim committed
80 81 82
  render() {
    const {
      currentUser,
何乐's avatar
何乐 committed
83
      fetchingMoreNotices,
jim's avatar
jim committed
84
      fetchingNotices,
何乐's avatar
何乐 committed
85
      loadedAllNotices,
jim's avatar
jim committed
86 87 88
      onNoticeVisibleChange,
      onMenuClick,
      onNoticeClear,
何乐's avatar
何乐 committed
89
      skeletonCount,
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
90
      theme,
jim's avatar
jim committed
91 92 93 94
    } = this.props;
    const menu = (
      <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
        <Menu.Item key="userCenter">
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
95 96
          <Icon type="user" />
          <FormattedMessage id="menu.account.center" defaultMessage="account center" />
jim's avatar
jim committed
97 98
        </Menu.Item>
        <Menu.Item key="userinfo">
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
99 100
          <Icon type="setting" />
          <FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
jim's avatar
jim committed
101 102
        </Menu.Item>
        <Menu.Item key="triggerError">
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
103 104
          <Icon type="close-circle" />
          <FormattedMessage id="menu.account.trigger" defaultMessage="Trigger Error" />
jim's avatar
jim committed
105 106 107
        </Menu.Item>
        <Menu.Divider />
        <Menu.Item key="logout">
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
108
          <Icon type="logout" />
109
          <FormattedMessage id="menu.account.logout" defaultMessage="logout" />
jim's avatar
jim committed
110 111 112
        </Menu.Item>
      </Menu>
    );
何乐's avatar
何乐 committed
113 114 115 116 117
    const loadMoreProps = {
      skeletonCount,
      loadedAll: loadedAllNotices,
      loading: fetchingMoreNotices,
    };
jim's avatar
jim committed
118
    const noticeData = this.getNoticeData();
119
    const unreadMsg = this.getUnreadData(noticeData);
jim's avatar
jim committed
120
    let className = styles.right;
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
121
    if (theme === 'dark') {
jim's avatar
jim committed
122
      className = `${styles.right}  ${styles.dark}`;
jim's avatar
jim committed
123 124
    }
    return (
jim's avatar
jim committed
125
      <div className={className}>
jim's avatar
jim committed
126 127
        <HeaderSearch
          className={`${styles.action} ${styles.search}`}
128
          placeholder={formatMessage({ id: 'component.globalHeader.search' })}
129 130 131 132 133
          dataSource={[
            formatMessage({ id: 'component.globalHeader.search.example1' }),
            formatMessage({ id: 'component.globalHeader.search.example2' }),
            formatMessage({ id: 'component.globalHeader.search.example3' }),
          ]}
jim's avatar
jim committed
134
          onSearch={value => {
jim's avatar
jim committed
135 136
            console.log('input', value); // eslint-disable-line
          }}
jim's avatar
jim committed
137
          onPressEnter={value => {
jim's avatar
jim committed
138 139 140
            console.log('enter', value); // eslint-disable-line
          }}
        />
141
        <Tooltip title={formatMessage({ id: 'component.globalHeader.help' })}>
jim's avatar
jim committed
142 143
          <a
            target="_blank"
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
144
            href="https://pro.ant.design/docs/getting-started"
jim's avatar
jim committed
145 146 147 148 149 150 151 152
            rel="noopener noreferrer"
            className={styles.action}
          >
            <Icon type="question-circle-o" />
          </a>
        </Tooltip>
        <NoticeIcon
          className={styles.action}
153
          count={currentUser.unreadCount}
jim's avatar
jim committed
154 155
          onItemClick={(item, tabProps) => {
            console.log(item, tabProps); // eslint-disable-line
156
            this.changeReadState(item, tabProps);
jim's avatar
jim committed
157
          }}
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
158 159 160
          locale={{
            emptyText: formatMessage({ id: 'component.noticeIcon.empty' }),
            clear: formatMessage({ id: 'component.noticeIcon.clear' }),
何乐's avatar
何乐 committed
161 162
            loadedAll: formatMessage({ id: 'component.noticeIcon.loaded' }),
            loadMore: formatMessage({ id: 'component.noticeIcon.loading-more' }),
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
163
          }}
jim's avatar
jim committed
164
          onClear={onNoticeClear}
何乐's avatar
何乐 committed
165
          onLoadMore={this.fetchMoreNotices}
jim's avatar
jim committed
166 167
          onPopupVisibleChange={onNoticeVisibleChange}
          loading={fetchingNotices}
wingsico's avatar
wingsico committed
168
          clearClose
jim's avatar
jim committed
169 170
        >
          <NoticeIcon.Tab
171
            count={unreadMsg.notification}
172
            list={noticeData.notification}
173
            title={formatMessage({ id: 'component.globalHeader.notification' })}
174
            name="notification"
175
            emptyText={formatMessage({ id: 'component.globalHeader.notification.empty' })}
jim's avatar
jim committed
176
            emptyImage="https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg"
何乐's avatar
何乐 committed
177
            {...loadMoreProps}
jim's avatar
jim committed
178 179
          />
          <NoticeIcon.Tab
180
            count={unreadMsg.message}
181
            list={noticeData.message}
182
            title={formatMessage({ id: 'component.globalHeader.message' })}
183
            name="message"
184
            emptyText={formatMessage({ id: 'component.globalHeader.message.empty' })}
jim's avatar
jim committed
185
            emptyImage="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
何乐's avatar
何乐 committed
186
            {...loadMoreProps}
jim's avatar
jim committed
187 188
          />
          <NoticeIcon.Tab
189
            count={unreadMsg.event}
190
            list={noticeData.event}
191
            title={formatMessage({ id: 'component.globalHeader.event' })}
192
            name="event"
193
            emptyText={formatMessage({ id: 'component.globalHeader.event.empty' })}
jim's avatar
jim committed
194
            emptyImage="https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg"
何乐's avatar
何乐 committed
195
            {...loadMoreProps}
jim's avatar
jim committed
196 197 198
          />
        </NoticeIcon>
        {currentUser.name ? (
199
          <HeaderDropdown overlay={menu}>
jim's avatar
jim committed
200
            <span className={`${styles.action} ${styles.account}`}>
jim's avatar
jim committed
201 202 203 204 205 206
              <Avatar
                size="small"
                className={styles.avatar}
                src={currentUser.avatar}
                alt="avatar"
              />
jim's avatar
jim committed
207 208
              <span className={styles.name}>{currentUser.name}</span>
            </span>
209
          </HeaderDropdown>
jim's avatar
jim committed
210
        ) : (
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
211
          <Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
jim's avatar
jim committed
212
        )}
213
        <SelectLang className={styles.action} />
jim's avatar
jim committed
214 215 216 217
      </div>
    );
  }
}