notification.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import classNames from 'classnames'
  2. import React, { ReactElement, useState } from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import MaterialIcon from './material-icon'
  5. export type NotificationType =
  6. | 'info'
  7. | 'success'
  8. | 'warning'
  9. | 'error'
  10. | 'offer'
  11. type NotificationProps = {
  12. action?: React.ReactElement
  13. ariaLive?: 'polite' | 'off' | 'assertive'
  14. className?: string
  15. content: React.ReactElement | string
  16. customIcon?: React.ReactElement
  17. isDismissible?: boolean
  18. isActionBelowContent?: boolean
  19. onDismiss?: () => void
  20. title?: string
  21. type: NotificationType
  22. }
  23. function NotificationIcon({
  24. notificationType,
  25. customIcon,
  26. }: {
  27. notificationType: NotificationType
  28. customIcon?: ReactElement
  29. }) {
  30. let icon = <MaterialIcon type="info" />
  31. if (customIcon) {
  32. icon = customIcon
  33. } else if (notificationType === 'success') {
  34. icon = <MaterialIcon type="check_circle" />
  35. } else if (notificationType === 'warning') {
  36. icon = <MaterialIcon type="warning" />
  37. } else if (notificationType === 'error') {
  38. icon = <MaterialIcon type="error" />
  39. } else if (notificationType === 'offer') {
  40. icon = <MaterialIcon type="campaign" />
  41. }
  42. return <div className="notification-icon">{icon}</div>
  43. }
  44. function Notification({
  45. action,
  46. ariaLive,
  47. className = '',
  48. content,
  49. customIcon,
  50. isActionBelowContent,
  51. isDismissible,
  52. onDismiss,
  53. title,
  54. type,
  55. }: NotificationProps) {
  56. type = type || 'info'
  57. const { t } = useTranslation()
  58. const [show, setShow] = useState(true)
  59. const notificationClassName = classNames(
  60. 'notification',
  61. `notification-type-${type}`,
  62. isActionBelowContent ? 'notification-cta-below-content' : '',
  63. className
  64. )
  65. const handleDismiss = () => {
  66. setShow(false)
  67. if (onDismiss) onDismiss()
  68. }
  69. if (!show) {
  70. return null
  71. }
  72. return (
  73. <div
  74. className={notificationClassName}
  75. aria-live={ariaLive || 'off'}
  76. role="alert"
  77. >
  78. <NotificationIcon notificationType={type} customIcon={customIcon} />
  79. <div className="notification-content-and-cta">
  80. <div className="notification-content">
  81. {title && (
  82. <p>
  83. <b>{title}</b>
  84. </p>
  85. )}
  86. {content}
  87. </div>
  88. {action && <div className="notification-cta">{action}</div>}
  89. </div>
  90. {isDismissible && (
  91. <div className="notification-close-btn">
  92. <button aria-label={t('close')} onClick={handleDismiss}>
  93. <MaterialIcon type="close" />
  94. </button>
  95. </div>
  96. )}
  97. </div>
  98. )
  99. }
  100. export default Notification