IyiKuyoro/slack-block-msg-kit

View on GitHub
src/BlockElements/DatePickerElement.ts

Summary

Maintainability
A
0 mins
Test Coverage
import ConfirmationDialog from '../CompositionObjects/ConfirmationDialog';
import Text, { TextType } from '../CompositionObjects/Text';
import { Helpers } from '../helpers';
import BlockElement, { BlockElementType } from './BlockElement';

/**
 * @description This is the date picker element class.
 * For more info regarding this, kindly visit https://api.slack.com/reference/messaging/block-elements#datepicker
 */
export default class DatePickerElement extends BlockElement {
  public placeholder?: Text;
  public initial_date?: string;
  public confirm?: ConfirmationDialog;

  /**
   * @description Create a new instance of the date picker class
   * @param  {string} actionId The action id of this element
   */
  constructor(actionId: string) {
    super(BlockElementType.datePicker, actionId);
  }

  /**
   * @description Add a placeholder text
   * @param  {string} placeholder The placeholder text
   * @returns DatePickerElement
   */
  public addPlaceholder(placeholder: string): DatePickerElement {
    Helpers.validateString(placeholder, 'placeholder', 150);

    this.placeholder = new Text(TextType.plainText, placeholder);
    return this;
  }

  /**
   * @description Add an initially selected date to the date picker
   * @param  {number} year The date to be pre selected
   * @param  {number} month The date to be pre selected
   * @param  {number} day The date to be pre selected
   * @returns DatePickerElement
   */
  public addInitialDate(year: number, month: number, day: number): DatePickerElement {
    this.validateRegex(/^[0-9]{4}$/, year.toString(), 'Year must have four digits');
    this.validateRegex(/(^1[0-2]$)|(^[1-9]{1}$)/, month.toString(), 'Month out of range');
    this.validateRegex(/(^[1-9]$)|(^[1-2][0-9]?$)|(^3[0-1]$)/, day.toString(), 'Day out of range');

    this.validateDay(year, month, day);

    this.initial_date = `${year}-${month < 10 ? 0 : ''}${month}-${day < 10 ? 0 : ''}${day}`;
    return this;
  }

  /**
   * @description Add a confirmation dialog by providing the parameters that is displayed when an option is selected.
   * This method will create the confirmation dialog.
   * @param  {string} dialogTitle The dialog title
   * @param  {Text} dialogText The message to be displayed in the dialog
   * @param  {string} confirmButton The confirm button label text
   * @param  {string} denyButton The deny button text
   * @returns ButtonElement
   */
  public addConfirmationDialogByParameters(
    dialogTitle: string,
    dialogText: Text,
    confirmButton: string,
    denyButton: string,
  ): DatePickerElement {
    this.confirm = new ConfirmationDialog(dialogTitle, dialogText, confirmButton, denyButton);

    return this;
  }

  /**
   * @description validate a regular expression
   * @param  {RegExp} regex The regex pattern
   * @param  {string} param The parameter to be validated
   * @param  {string} error The error message to display
   */
  private validateRegex(regex: RegExp, param: string, error: string) {
    if (!regex.test(param)) {
      throw new Error(error);
    }
  }

  /**
   * @description validate a day in the year
   * @param  {number} year The year
   * @param  {number} month The month
   * @param  {number} day The day
   */
  private validateDay(year: number, month: number, day: number) {
    this.validateLongMonths(day, month);
    this.validateLeapYear(year, month, day);
  }

  /**
   * @description validate last february day in leap year
   * @param  {number} year The year
   * @param  {number} month The month
   * @param  {number} day The day
   */
  private validateLeapYear(year: number, month: number, day: number) {
    const yearDiff = year - 2020;

    if (yearDiff % 4 !== 0 && month === 2 && day === 29) {
      throw new Error('Only leap years have 29 days in February');
    }
  }

  /**
   * @description Validate last day of long months
   * @param  {number} day The day
   * @param  {number} month The month
   */
  private validateLongMonths(day: number, month: number) {
    const longMonths = [1, 3, 5, 7, 8, 10, 12];
    if (day > 30 && longMonths.indexOf(month) < 0) {
      throw new Error('Day out of month range');
    }
  }
}