<repo_name>kovalchuk-mykhailo/test-schedule-app<file_sep>/src/selectors/index.js
import { createSelector } from "reselect";
import { STATUS_BOOKED } from "../constants/LessonStatus";

export const scheduleSelector = (state) => state.scheduleData.schedule;

export const lessonsSelector = createSelector(scheduleSelector, (schedule) => {
  const initLessons = [...new Array(24)].map(() =>
    [...new Array(7)].map(() => ({
      status: null,
    }))
  );
  for (let val of schedule) {
    const hour = +val.start;
    const day = +val.day;
    initLessons[hour - 1][day - 1] = {
      status: `${val.status}`,
    };
  }
  return initLessons;
});

export const countSelector = createSelector(scheduleSelector, (schedule) =>
  schedule.reduce(
    (acc, value) => (value.status === STATUS_BOOKED ? acc + 1 : acc),
    0
  )
);
<file_sep>/src/reducers/index.js
import { combineReducers } from "redux";

import { scheduleReducer } from "./sheduleReducer";

const allReducers = combineReducers({
  scheduleData: scheduleReducer,
});

export default allReducers;
<file_sep>/src/pages/HomePage/index.js
import React, { useEffect } from "react";
import { connect } from "react-redux";

import { getScheduleAsyncRequest } from "../../actions/schedule";
import ListSchedule from "./components/ListSchedule";
import ScheduleTableContainer from "./components/ScheduleTableContainer";
import { scheduleSelector } from "../../selectors";

import styles from "./styles.module.css";

const HomePage = ({ schedule, getScheduleAsyncRequest }) => {
  useEffect(() => {
    getScheduleAsyncRequest();
  }, []);

  return (
    <div className={styles.homePage}>
      <ListSchedule schedule={schedule} />
      <ScheduleTableContainer schedule={schedule} />
    </div>
  );
};

const mapStateToProps = (state) => ({
  schedule: scheduleSelector(state),
});

const mapDispatchToProps = (dispatch) => ({
  getScheduleAsyncRequest: () => {
    dispatch(getScheduleAsyncRequest());
  },
});

export default connect(mapStateToProps, mapDispatchToProps)(HomePage);
<file_sep>/src/pages/HomePage/components/ListScheduleLesson/index.js
import React from "react";

import { STATUS_FREE } from "../../../../constants/LessonStatus";
import { DAY_TEXT, HOUR_TEXT, START_TEXT } from "../../../../constants/Texts";

import styles from "./styles.module.css";

const ListScheduleLesson = ({ lesson }) => {
  if (lesson.status === STATUS_FREE) {
    return (
      <li className={styles.listItem}>
        <p>
          {DAY_TEXT}: {lesson.day}
        </p>
        <p>
          {START_TEXT}: {lesson.start} {HOUR_TEXT}
        </p>
      </li>
    );
  } else return null;
};

export default ListScheduleLesson;
<file_sep>/src/constants/LessonStatus.js
export const STATUS_FREE = "free";
export const STATUS_BOOKED = "booked";
<file_sep>/src/constants/Schedule.js
export const GET_SCHEDULE_ASYNC_REQUEST = "GET_CURRENCIES_ASYNC_REQUEST";

export const GET_SCHEDULE_SUCCESS = "GET_SCHEDULE_SUCCESS";
export const GET_SCHEDULE_FAILURE = "GET_SCHEDULE_FAILURE";
export const GET_SCHEDULE_REQUEST = "GET_SCHEDULE_REQUEST";

export const SET_SCHEDULE = "SET_SCHEDULE";
<file_sep>/src/pages/HomePage/components/ScheduleTable/index.js
import React from "react";

import TableBody from "./components/TableBody";
import TableHead from "./components/TableHead";

import styles from "./styles.module.css";

const ScheduleTable = () => {
  return (
    <table className={styles.tableContainer}>
      <TableHead />
      <TableBody />
    </table>
  );
};

export default ScheduleTable;
<file_sep>/src/actions/schedule.js
import {
  GET_SCHEDULE_ASYNC_REQUEST,
  GET_SCHEDULE_FAILURE,
  GET_SCHEDULE_REQUEST,
  GET_SCHEDULE_SUCCESS,
  SET_SCHEDULE,
} from "../constants/Schedule";

export const getScheduleAsyncRequest = () => ({
  type: GET_SCHEDULE_ASYNC_REQUEST,
});

export const getScheduleRequest = () => ({
  type: GET_SCHEDULE_REQUEST,
});

export const getScheduleSuccess = (schedule) => ({
  type: GET_SCHEDULE_SUCCESS,
  schedule,
});

export const getScheduleFailure = (error) => ({
  type: GET_SCHEDULE_FAILURE,
  error,
});

export const setSchedule = (schedule) => ({
  type: SET_SCHEDULE,
  schedule,
});
<file_sep>/src/pages/HomePage/components/ScheduleTable/components/TableHead/index.js
import React from "react";

const TableHead = () => (
  <thead>
    <tr>
      <th scope="col"></th>
      <th scope="col">Пон. 19</th>
      <th scope="col">Вт. 20</th>
      <th scope="col">Ср. 21</th>
      <th scope="col">Чт. 22</th>
      <th scope="col">Пт. 23</th>
      <th scope="col">Сб. 24</th>
      <th scope="col">Нд. 25</th>
    </tr>
  </thead>
);

export default TableHead;
<file_sep>/src/pages/HomePage/components/ScheduleTable/components/TableBody/index.js
import React from "react";
import { connect } from "react-redux";

import TableRow from "./components/TableRow";

import { lessonsSelector } from "../../../../../../selectors";

const TableBody = ({ lessons }) => (
  <tbody>
    {lessons.map((row, index) => {
      const hour = index + 1;
      const header = hour < 10 ? `0${hour}:00` : `${hour}:00`;
      return <TableRow key={index} items={row} header={header} hour={hour} />;
    })}
  </tbody>
);

const mapStateToProps = (state) => ({
  lessons: lessonsSelector(state),
});

export default connect(mapStateToProps)(TableBody);
<file_sep>/src/reducers/sheduleReducer.js
import {
  GET_SCHEDULE_ASYNC_REQUEST,
  GET_SCHEDULE_FAILURE,
  GET_SCHEDULE_REQUEST,
  GET_SCHEDULE_SUCCESS,
  SET_SCHEDULE,
} from "../constants/Schedule";

const initialState = {
  schedule: [],
  isLoading: false,
  error: "",
};

export const scheduleReducer = (state = initialState, action) => {
  switch (action.type) {
    case GET_SCHEDULE_ASYNC_REQUEST: {
      return {
        ...state,
        isLoading: true,
      };
    }

    case GET_SCHEDULE_REQUEST: {
      return {
        ...state,
        isLoading: true,
      };
    }

    case GET_SCHEDULE_SUCCESS:
      return {
        ...state,
        schedule: action.schedule,
        isLoading: false,
      };

    case GET_SCHEDULE_FAILURE:
      return {
        ...state,
        isLoading: false,
        error: action.error,
      };

    case SET_SCHEDULE:
      return {
        ...state,
        schedule: action.schedule,
      };

    default:
      return state;
  }
};
