ManageIQ/manageiq-ui-classic

View on GitHub
app/javascript/components/notification-drawer/notification-drawer.jsx

Summary

Maintainability
A
1 hr
Test Coverage
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { useDispatch, useSelector } from 'react-redux';
import { ChevronLeft16, ChevronRight16, Close16 } from '@carbon/icons-react';
import classNames from 'classnames';
import {
  Button, Accordion, AccordionItem, InlineNotification, OverflowMenu, OverflowMenuItem,
} from 'carbon-components-react';
import { getNotficationStatusIconName, newCountText, viewDetails } from './helpers';
import { maxNotifications as maxNotificationsConstant } from '../../notifications/backend';
import {
  toggleDrawerVisibility, markNotificationRead, markAllRead, clearNotification, clearAll, toggleMaxNotifications,
} from '../../miq-redux/actions/notifications-actions';

import initNotifications from '../../notifications/init';

const NotificationDrawer = ({ jsRequest }) => {
  const dispatch = useDispatch();
  const drawerTitle = __('Notifications');
  const [isDrawerExpanded, setDrawerExpanded] = useState(false);
  const {
    isDrawerVisible, unreadCount, notifications, totalNotificationsCount, maxNotifications,
  } = useSelector(({ notificationReducer }) => notificationReducer);
  useEffect(() => {
    if (!jsRequest) {
      initNotifications();
    }
  }, []);
  return (
    isDrawerVisible ? (
      <div id="miq-notifications-drawer-container">
        <div className={`notification-drawer ${isDrawerExpanded ? 'notification-drawer-expanded' : ''}`}>
          <div className="panel-header">
            <Button
              hasIconOnly
              renderIcon={!isDrawerExpanded ? ChevronLeft16 : ChevronRight16}
              className={!isDrawerExpanded ? 'collapsed heading-icon' : 'expanded  heading-icon'}
              iconDescription={!isDrawerExpanded ? 'collapsed' : 'expanded'}
              onClick={() => setDrawerExpanded(!isDrawerExpanded)}
              onKeyPress={() => setDrawerExpanded(!isDrawerExpanded)}
            />
            <h3 className="notification-title">{drawerTitle}</h3>
            <Button
              hasIconOnly
              renderIcon={Close16}
              className="heading-icon closeIcon"
              description={__('Close')}
              iconDescription={__('Close')}
              onClick={() => dispatch(toggleDrawerVisibility())}
              onKeyPress={() => dispatch(toggleDrawerVisibility())}
            />
          </div>
          <div className="notification-content">
            <div>
              {' '}
              <Accordion align="start" className="Notification-accordion">
                <AccordionItem
                  title={(
                    <div className="events-count">
                      <span>{__('Events') }</span>
                      <span>{newCountText(unreadCount)}</span>
                    </div>
                  )}
                >
                  <div className="notification-accordion-content">
                    <div className="notification-content-messages">
                      {notifications.slice(0, maxNotifications).map((notification) => (
                        <InlineNotification
                          kind={getNotficationStatusIconName(notification)}
                          role="alert"
                          key={notification.id}
                          className={classNames('notification-item-wrapper', !notification.unread ? 'read' : 'unread')}
                          title={notification.message}
                          statusIconDescription={getNotficationStatusIconName(notification)}
                          lowContrast
                          hideCloseButton
                          subtitle={(
                            <div className="subtitle-div">
                              <div className="subtitle-div-notification-menu">
                                <OverflowMenu
                                  ariaLabel={__('open and close options')}
                                  id={notification.id}
                                  floatingmenu="true"
                                  flipped
                                  title={__('open and close options')}
                                >

                                  <OverflowMenuItem
                                    className={`overflow-options details-${notification.id}`}
                                    aria-label={__('View details')}
                                    itemText={__('View details')}
                                    disabled={!notification.data.link}
                                    onKeyDown={() => viewDetails(notification)}
                                    requireTitle
                                    onClick={() => viewDetails(notification)}
                                  />
                                  <OverflowMenuItem
                                    className={`overflow-options markasread-${notification.id}`}
                                    aria-label={__('Mark as read')}
                                    itemText={__('Mark as read')}
                                    disabled={!notification.unread}
                                    onKeyDown={
                                      () => notification.unread && dispatch(markNotificationRead(notification))
                                    }
                                    requireTitle
                                    onClick={
                                      () => notification.unread && dispatch(markNotificationRead(notification))
                                    }
                                    hasDivider
                                  />
                                  <OverflowMenuItem
                                    className={`overflow-options remove-${notification.id}`}
                                    aria-label={__('Remove')}
                                    itemText={__('Remove')}
                                    onKeyDown={
                                      () => dispatch(clearNotification(notification, !!maxNotifications))
                                    }
                                    requireTitle
                                    onClick={
                                      () => dispatch(clearNotification(notification, !!maxNotifications))
                                    }
                                    isDelete
                                  />
                                </OverflowMenu>
                              </div>
                              <div className="subtitle-div-notification-time">
                                <span className="notification-time">
                                  {moment(notification.timeStamp).format('MM/DD/YYYY')}
                                  {' '}
                                  {'|'}
                                  {' '}
                                  {moment(notification.timeStamp).format('h:mm:ss A')}
                                </span>
                              </div>

                            </div>
                          )}

                        />

                      ))}
                      { maxNotificationsConstant < totalNotificationsCount && (
                        <div className="maxnotifications-text">
                          <span>
                            { maxNotifications ? sprintf(__('Showing %s items out of %s total.'), maxNotifications, totalNotificationsCount)
                              : sprintf(__('Showing all %s items.'), notifications.length) }
                          </span>
                          <Button
                            id="toggleMaxNotifications"
                            kind="ghost"
                            onClick={() =>
                              dispatch(toggleMaxNotifications())}
                          >
                            { maxNotifications ? __('Show all (may take a while)') : sprintf(__('Show only the first %s'), maxNotificationsConstant)}
                          </Button>
                        </div>
                      )}
                    </div>
                    <div className="notification-footer">
                      <Button
                        id="markAllReadBtn"
                        disabled={unreadCount === 0}
                        kind="ghost"
                        onClick={
                          () => {
                            dispatch(markAllRead(notifications));
                          }
                        }
                      >
                        {__('Mark All Read')}
                      </Button>
                      <Button
                        id="clearAllBtn"
                        kind="ghost"
                        disabled={notifications.length === 0}
                        onClick={
                          () => dispatch(clearAll(notifications, !!maxNotifications))
                        }
                      >
                        {__('Clear All')}
                      </Button>
                    </div>
                  </div>

                </AccordionItem>
              </Accordion>
            </div>

          </div>
        </div>
      </div>
    )
      : null
  );
};

export default NotificationDrawer;

NotificationDrawer.propTypes = {
  jsRequest: PropTypes.bool,
};

NotificationDrawer.defaultProps = {
  jsRequest: false,
};