web/src/components/NoticeIcon/index.tsx (115 lines of code) (raw):

/* * MIT License * Copyright (c) 2019 Alipay.inc * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import { BellOutlined } from '@ant-design/icons'; import { Badge, Spin, Tabs } from 'antd'; import classNames from 'classnames'; import React from 'react'; import useMergeValue from 'use-merge-value'; import HeaderDropdown from '../HeaderDropdown'; import styles from './index.less'; import type { NoticeIconTabProps } from './NoticeList'; import NoticeList from './NoticeList'; const { TabPane } = Tabs; export type NoticeIconProps = { count?: number; bell?: React.ReactNode; className?: string; loading?: boolean; onClear?: (tabName: string, tabKey: string) => void; onItemClick?: (item: API.NoticeIconData, tabProps: NoticeIconTabProps) => void; onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void; onTabChange?: (tabTile: string) => void; style?: React.CSSProperties; onPopupVisibleChange?: (visible: boolean) => void; popupVisible?: boolean; clearText?: string; viewMoreText?: string; clearClose?: boolean; emptyImage?: string; children: React.ReactElement<NoticeIconTabProps>[]; }; const NoticeIcon: React.FC<NoticeIconProps> & { Tab: typeof NoticeList; } = (props) => { const getNotificationBox = (): React.ReactNode => { const { children, loading, onClear, onTabChange, onItemClick, onViewMore, clearText, viewMoreText, } = props; if (!children) { return null; } const panes: React.ReactNode[] = []; React.Children.forEach(children, (child: React.ReactElement<NoticeIconTabProps>): void => { if (!child) { return; } const { list, title, count, tabKey, showClear, showViewMore } = child.props; const len = list && list.length ? list.length : 0; const msgCount = count || count === 0 ? count : len; const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title; panes.push( <TabPane tab={tabTitle} key={tabKey}> <NoticeList clearText={clearText} viewMoreText={viewMoreText} data={list} onClear={(): void => onClear && onClear(title, tabKey)} onClick={(item): void => onItemClick && onItemClick(item, child.props)} onViewMore={(event): void => onViewMore && onViewMore(child.props, event)} showClear={showClear} showViewMore={showViewMore} {...child.props} title={title || child.props.title} /> </TabPane>, ); }); return ( <Spin spinning={loading} delay={300}> <Tabs className={styles.tabs} onChange={onTabChange}> {panes} </Tabs> </Spin> ); }; const { className, count, bell } = props; const [visible, setVisible] = useMergeValue<boolean>(false, { value: props.popupVisible, onChange: props.onPopupVisibleChange, }); const noticeButtonClass = classNames(className, styles.noticeButton); const notificationBox = getNotificationBox(); const NoticeBellIcon = bell || <BellOutlined className={styles.icon} />; const trigger = ( <span className={classNames(noticeButtonClass, { opened: visible })}> <Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}> {NoticeBellIcon} </Badge> </span> ); if (!notificationBox) { return trigger; } return ( <HeaderDropdown placement="bottomRight" overlay={notificationBox} overlayClassName={styles.popover} trigger={['click']} visible={visible} onVisibleChange={setVisible} > {trigger} </HeaderDropdown> ); }; NoticeIcon.defaultProps = { emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg', }; NoticeIcon.Tab = NoticeList; export default NoticeIcon;