1

I would like to ask or gather some important suggestions for this situation.

I wan't to create my own Datetimepicker react component. I was searching some codes for easily constructing a calendar. Now I found some Regular Class which makes the calendar and I want to re-use it for creating my Datetimepicker component.

Now I would like to ask/open for suggestion for better or good practice that would be logical for my component.

In the code below, I have a functional component with a stateless class Day inside of it and I tried to instantiate it for future use. For me it works fine. Since I don't want to look my code very messy or make it fewer lines, Is there anyway to separate this Day stateless class to import it in my Functional component? or any suggestions for this?. Or Can anyone explain to me if what am I doing is logically wrong or not, since I was using a Functional based component and putting a class inside of it. I would like to hear some good advice for this to implement in much better way.

import React, {useState} from "react";
import styles from "./Datetimepicker.module.scss";
import classNames from "classnames";
import CalendarSVG from "../../../styles/icons/Calendar/Calendar"

const Datetimepicker = (props) => {
  const {
    style,
    name,    
    color,
    size,    
    inputRef,
    errorMsg,
    helperMsg,
    placeholder,
    disabled,
    ...others
  } = props;

  
  const [addVisibility, setAddVisibility] = useState(false);

  const showCalendar = () => {
    setAddVisibility((prevState) => (!prevState));
  }

  const getWeekNumber = (date) => {
    const firstDayOfTheYear = new Date(date.getFullYear(), 0, 1);
    const pastDaysOfYear = (date - firstDayOfTheYear) / 86400000;
    
    return Math.ceil((pastDaysOfYear + firstDayOfTheYear.getDay() + 1) / 7)
  }

  class Day {
    constructor(date = null, lang = 'default') {
      date = date ?? new Date();    
      this.Date = date;
      this.date = date.getDate();
      this.day = date.toLocaleString(lang, { weekday: 'long'});
      this.dayNumber = date.getDay() + 1;
      this.dayShort = date.toLocaleString(lang, { weekday: 'short'});
      this.year = date.getFullYear();
      this.yearShort = date.toLocaleString(lang, { year: '2-digit'});
      this.month = date.toLocaleString(lang, { month: 'long'});
      this.monthShort = date.toLocaleString(lang, { month: 'short'});
      this.monthNumber = date.getMonth() + 1;
      this.timestamp = date.getTime();
      this.week = getWeekNumber(date);
    }
    
    get isToday() {
      return this.isEqualTo(new Date());
    }
    
    isEqualTo(date) {
      date = date instanceof Day ? date.Date : date;
      
      return date.getDate() === this.date &&
        date.getMonth() === this.monthNumber - 1 &&
        date.getFullYear() === this.year;
    }
    
    format(formatStr) {
      return formatStr
        .replace(/\bYYYY\b/, this.year)
        .replace(/\bYYY\b/, this.yearShort)
        .replace(/\bWW\b/, this.week.toString().padStart(2, '0'))
        .replace(/\bW\b/, this.week)
        .replace(/\bDDDD\b/, this.day)
        .replace(/\bDDD\b/, this.dayShort)
        .replace(/\bDD\b/, this.date.toString().padStart(2, '0'))
        .replace(/\bD\b/, this.date)
        .replace(/\bMMMM\b/, this.month)
        .replace(/\bMMM\b/, this.monthShort)
        .replace(/\bMM\b/, this.monthNumber.toString().padStart(2, '0'))
        .replace(/\bM\b/, this.monthNumber)
    }
  }

  const day = new Day();

  console.log('--day', day);

  return (
    <div className={styles.DatetimepickerWrapper}>
      <input
        className={classNames(
          styles.InputText,                
          errorMsg && styles.InputError,
          style ?? ""
        )}
        type="text"
        name={name}        
        placeholder={placeholder ?? "mm/dd/yyyy"}
        {...inputRef}
        {...others}
        disabled={disabled}        
      />
      <div className={addVisibility ? `${styles.CalendarVisible} ${styles.CalendarDropDown}` : `${styles.CalendarHidden}`}>
        <div className={styles.CalendarContainer}>
          <div className={styles.CalendarHeaderYear}>            
              <p>2022</p>            
          </div>
          <div className={styles.CalendarHeaderMonth}>
          <button type="button" className="prev-month" aria-label="previous month"></button>
            <h4 tabIndex="0" aria-label="current month">
              January
            </h4>
            <button type="button" className="prev-month" aria-label="next month"></button>
          </div>
          <div className={styles.CalendarDaysContainer}>
            <p>Test</p>
            <p>Test</p>
            <p>Test</p>
            <p>Test</p>
          </div>          
        </div>        
      </div>
      <CalendarSVG width={23} fill="#294197" className={styles.CalendarDateTimePickerIcon} onClick={() => showCalendar()}/>  
      {errorMsg && <span className={styles.ErrorMessage}>{errorMsg}</span>}
      {!errorMsg && helperMsg && (
        <span className={styles.HelperMessage}>{helperMsg}</span>
      )}
    </div>
  );
};

export default Datetimepicker;

1 Answer 1

1

A class should not be dynamically created when possible. You'll get lots of individual instances tied to their own classes which are actually different despite having the same name.

Here, the only identifier Day uses from the outer scope of the functional component is the getWeekNumber, which is called in the constructor. But getWeekNumber doesn't reference anything particular to a particular render either, so it can be moved out too - either to its own standalone function, or to the inside of Day. You can do

class Day {
    constructor(date = null, lang = 'default') {
        date = date ?? new Date();
        this.Date = date;
        this.date = date.getDate();
        this.day = date.toLocaleString(lang, { weekday: 'long' });
        this.dayNumber = date.getDay() + 1;
        this.dayShort = date.toLocaleString(lang, { weekday: 'short' });
        this.year = date.getFullYear();
        this.yearShort = date.toLocaleString(lang, { year: '2-digit' });
        this.month = date.toLocaleString(lang, { month: 'long' });
        this.monthShort = date.toLocaleString(lang, { month: 'short' });
        this.monthNumber = date.getMonth() + 1;
        this.timestamp = date.getTime();
        this.week = this.getWeekNumber(date); // change this line
    }
    getWeekNumber(date) { // add this method
        const firstDayOfTheYear = new Date(date.getFullYear(), 0, 1);
        const pastDaysOfYear = (date - firstDayOfTheYear) / 86400000;
        return Math.ceil((pastDaysOfYear + firstDayOfTheYear.getDay() + 1) / 7)
    }
    // all the other code in Day is the same

and then remove Day and getWeekNumber from the functional component.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for responding. Since I am still a beginner, Is there a way that I can separate this file and Import this in Functional component then Instantiate this inside the Functional component? Is my question sounds logically wrong ?
Absolutely, once the Day has been moved outside the functional component, you're free to extract it into another file (which would be a good idea, since it's doing something pretty separate from your Datetimepicker).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.