Source

components/AlertBar/AlertBar.js

  1. // NPM module imports
  2. import React, { Component } from "react";
  3. import PropTypes from "prop-types";
  4. // File imports
  5. import * as alertBarTypes from "./alertBarTypes";
  6. import * as transitionOptions from "./alertBarTransitionOptions";
  7. // Image imports
  8. import closeIconWhite from "../../assets/icons/close-icon-white.svg";
  9. // Style imports
  10. import styles from "./AlertBar.module.scss";
  11. /**
  12. * Renders the AlertBar component.
  13. * This component is an alert that dismisses itself.
  14. * @extends {Component}
  15. * @component
  16. * @category AlertBar
  17. * @author Dan Levy <danlevy124@gmail.com>
  18. */
  19. class AlertBar extends Component {
  20. /**
  21. * AlertBar component state
  22. * @property {module:alertBarTransitionOptions} transition - The current CSS transition
  23. */
  24. state = {
  25. transition: null,
  26. };
  27. /**
  28. * The amount of time that the AlertBar component is displayed (no including transition time).
  29. * Time is in ms.
  30. * @type {number}
  31. */
  32. _DISPLAY_TIME_MS = 5000;
  33. /**
  34. * The amount of time that the AlertBar component takes to transition.
  35. * Time is in ms.
  36. * If this constant is changed, be sure to change the equivalent time in the SCSS file for this component.
  37. * @type {number}
  38. */
  39. _TRANSITION_TIME_MS = 1000;
  40. /**
  41. * Timeout ids for all of the AlertBar positions/transitions
  42. * @type {object}
  43. */
  44. _transitionTimeoutIds = {};
  45. /**
  46. * Starts AlertBar component timeouts
  47. */
  48. componentDidMount() {
  49. this.createComponentTimeouts();
  50. }
  51. /**
  52. * Stops asynchronous tasks
  53. */
  54. componentWillUnmount() {
  55. this.clearComponentTimeouts();
  56. }
  57. /**
  58. * Creates timeouts for AlertBar positions/transitions
  59. * @function
  60. */
  61. createComponentTimeouts = () => {
  62. // Timeout that waits to slide the AlertBar down
  63. // Fixes bug (assuming React bug) where transition down is instant rather than animated
  64. const waitToSlideDownTimerId = setTimeout(() => {
  65. delete this._transitionTimeoutIds[waitToSlideDownTimerId];
  66. this.setState({ transition: transitionOptions.DOWN });
  67. }, 10);
  68. this._transitionTimeoutIds.waitToSlideDownTimerId = waitToSlideDownTimerId;
  69. // Timeout that waits to slide the AlertBar back up
  70. const waitToSlideUpTimerId = setTimeout(() => {
  71. delete this._transitionTimeoutIds[waitToSlideUpTimerId];
  72. this.setState({ transition: transitionOptions.UP });
  73. }, this._TRANSITION_TIME_MS + this._DISPLAY_TIME_MS);
  74. this._transitionTimeoutIds.waitToSlideUpTimerId = waitToSlideUpTimerId;
  75. // Timeout that waits to call done (remove the component from the DOM)
  76. const waitToFinishTimerId = setTimeout(() => {
  77. delete this._transitionTimeoutIds[waitToFinishTimerId];
  78. this.props.done();
  79. }, this._TRANSITION_TIME_MS * 2 + this._DISPLAY_TIME_MS);
  80. this._transitionTimeoutIds.waitToFinishTimerId = waitToFinishTimerId;
  81. };
  82. /**
  83. * Clears all timeouts for AlertBar positions/transitions
  84. * @function
  85. */
  86. clearComponentTimeouts = () => {
  87. for (const timout in this._transitionTimeoutIds) {
  88. clearTimeout(this._transitionTimeoutIds[timout]);
  89. }
  90. // Clears the transitionTimeoutIds object
  91. this._transitionTimeoutIds = {};
  92. };
  93. /**
  94. * Slides the AlertBar up before the display time has passed
  95. * @function
  96. */
  97. closeButttonClickedHandler = () => {
  98. // Clears the necessary timouts in order to override the slide up
  99. if (this._transitionTimeoutIds.waitToSlideUpTimerId) {
  100. clearTimeout(this._transitionTimeoutIds.slideUpTimerId);
  101. }
  102. if (this._transitionTimeoutIds.waitToFinishTimerId) {
  103. clearTimeout(this._transitionTimeoutIds.isDoneTimerId);
  104. }
  105. // Tells state to to have the AlertBar slide up
  106. this.setState({ transition: transitionOptions.UP });
  107. // Timeout that waits to call done (remove the component from the DOM)
  108. const waitToFinishOverrideTimerId = setTimeout(() => {
  109. this.props.done();
  110. }, this._TRANSITION_TIME_MS);
  111. this._transitionTimeoutIds.waitToFinishOverrideTimerId = waitToFinishOverrideTimerId;
  112. };
  113. /**
  114. * Gets the CSS background color class name
  115. * @function
  116. * @returns {string} The background color class name
  117. */
  118. getBackgroundColorStyle = () => {
  119. switch (this.props.type) {
  120. case alertBarTypes.SUCCESS:
  121. return styles.alertBarSuccess;
  122. case alertBarTypes.WARNING:
  123. return styles.alertBarWarning;
  124. case alertBarTypes.ERROR:
  125. return styles.alertBarError;
  126. default:
  127. return styles.alertBarInfo;
  128. }
  129. };
  130. /**
  131. * Gets the CSS current transition class name
  132. * @function
  133. * @returns {string} The transition class name
  134. */
  135. getTransitionStyle = () => {
  136. switch (this.state.transition) {
  137. case transitionOptions.DOWN:
  138. return styles.alertBarSlideDown;
  139. case transitionOptions.UP:
  140. return styles.alertBarSlideUp;
  141. default:
  142. return null;
  143. }
  144. };
  145. /**
  146. * Renders the AlertBar component
  147. */
  148. render() {
  149. return (
  150. <div
  151. className={`${
  152. styles.alertBar
  153. } ${this.getBackgroundColorStyle()} ${this.getTransitionStyle()}`}
  154. >
  155. <div className={styles.alertBarTopGrid}>
  156. {/* Empty container div for the left-hand side of the top grid */}
  157. <div></div>
  158. <h1 className={styles.alertBarHeading}>
  159. {this.props.heading}
  160. </h1>
  161. <button
  162. className={styles.alertBarCloseButton}
  163. onClick={this.closeButttonClickedHandler}
  164. type="button"
  165. >
  166. <img
  167. className={styles.alertBarCloseButtonImg}
  168. src={closeIconWhite}
  169. alt="Close Alert"
  170. />
  171. </button>
  172. </div>
  173. <h2 className={styles.alertBarMessage}>{this.props.message}</h2>
  174. </div>
  175. );
  176. }
  177. }
  178. // Prop types for the AlertBar component
  179. AlertBar.propTypes = {
  180. /**
  181. * The type of AlertBar to display (determines the color).
  182. * See [types]{@link module:alertBarTypes}.
  183. */
  184. type: PropTypes.oneOf([
  185. alertBarTypes.SUCCESS,
  186. alertBarTypes.WARNING,
  187. alertBarTypes.ERROR,
  188. alertBarTypes.INFO,
  189. ]).isRequired,
  190. /**
  191. * The heading to display
  192. */
  193. heading: PropTypes.string.isRequired,
  194. /**
  195. * The message to display
  196. */
  197. message: PropTypes.string.isRequired,
  198. /**
  199. * Tells Redux that this component is no longer needed (i.e. done)
  200. */
  201. done: PropTypes.func.isRequired,
  202. };
  203. export default AlertBar;