Source

features/selectedDate.js

import { createSlice } from "@reduxjs/toolkit";
import { getLimitYear, transformToNumber } from "../utils/date";


const dateObject = { day: false, month: false, year: false}
const timeObject = { hour: false, minute: false}

/**
 * @param {object} draft 
 * @param {string} id 
 * @param {string} type - accept date, datePeriod, dateTime, dateTimePeriod, time, timePeriod  
 */
function setInitialDateState(draft, id, type) { 
    let timeAttributes = type.indexOf("date") >= 0 ? type.indexOf("ime") >= 0 ? {...dateObject, ...timeObject} 
                        : dateObject : timeObject
    if( type.indexOf("Period") > 0 ){ 
        timeAttributes = { start: timeAttributes, end: timeAttributes, calendar: timeAttributes }
    } else { timeAttributes = { calendar: timeAttributes, ...timeAttributes } }
    draft.dates[id] = {
        status: "default", 
        type,
        ...timeAttributes
    }
}

const initialState = { 
    status: "empty", 
    dates: {}
}

/**
 * @typedef {object} selectedDate 
 * @component 
 * @description Redux component in charge of selected dates state - 
 * state : { status: {string}, dates: {object} } - 
 * state.dates : { selectedDate1Id, selectedDate2Id, ... }
 * state.dates.selectedDate1Id : { day: {number}, month: {number}, year: {number}, hour: {number}, minute: {number} } 
 * @property {function} init - Initializes selected dates state of element corresponding to id passed as parameter
 * @property {function} initCalendar - Initializes calendars state of element corresponding to id passed as parameter
 * @property {function} setCalendarDay - Set day displayed to calendar 
 * @property {function} setCalendarHour - Set hour displayed to calendar
 * @property {function} setCalendarMinute - Set minute displayed to calendar
 * @property {function} setCalendarMonth - Set month displayed to calendar
 * @property {function} setCalendarYear - Set year displayed to calendar
 * @property {function} setDay - Set selected day 
 * @property {function} setHour - Set selected hour 
 * @property {function} setMinute - Set selected minute 
 * @property {function} setMonth - Set selected month 
 * @property {function} setYear - Set selected year
 */
const { actions, reducer } = createSlice({

    name: "selectedDate", 
    initialState, 

    reducers: {

        /**
         * Initializes selected dates state of element corresponding to id passed as parameter
         * @memberof selectedDate 
         * @param {string} id 
         * @param {string} type - accept date, datePeriod, dateTime, dateTimePeriod, time, timePeriod 
         * @example `selectedDateAction.init( {string} id, {string} type )` 
         */
        init: {

            prepare: (id, type) => ({
                payload: {id, type}
            }),

            reducer: (draft, action) => {
                if(draft.dates[action.payload.id] && draft.dates[action.payload.id].status === "default"){ return }
                setInitialDateState(draft, action.payload.id, action.payload.type)
                draft.status = draft.status === "empty" ? 1 : draft.status+1
                return
            }
        },

        /**
         * Initializes calendars state of element corresponding to id passed as parameter
         * @memberof selectedDate 
         * @memberof selectedDate.initCalendar
         * @param {string} id 
         * @example `selectedDateAction.initCalendar( {string} id )` 
         */
        initCalendar: {

            prepare: (id) => ({
                payload: {id}
            }),

            reducer: (draft, action) => {
                const id = action.payload.id
                draft.dates[id].status = "default"
                if(draft.dates[id].type.indexOf("date") === 0){
                    draft.dates[id].calendar.day = false
                    draft.dates[id].calendar.month = false
                    draft.dates[id].calendar.year = false
                }
                return
            }
        },

        /**
         * Set day displayed to calendar
         * @memberof selectedDate 
         * @param {number} day 
         * @param {string} inputId 
         * @example `selectedDateAction.setCalendarDay( {string} id, {number} day )` 
         */
        setCalendarDay: {

            prepare: (day, inputId) => ({
                payload: {day, inputId}
            }),

            reducer: (draft, action) => {
                const day = parseInt(action.payload.day)
                if(day < 1 || day > 31){ return }
                const inputId = action.payload.inputId 
                draft.dates[inputId].calendar.day = day 
                return
            }
        },

        /**
         * Set hour displayed to calendar
         * @memberof selectedDate 
         * @param {number} hour 
         * @param {string} inputId 
         * @example `selectedDateAction.setCalendarHour( {string} id, {number} hour )` 
         */
        setCalendarHour: {

            prepare: (hour, inputId) => ({
                payload: {hour, inputId}
            }),

            reducer: (draft, action) => {
                const hour = parseInt(action.payload.hour)
                if(hour < 0 || hour >= 24){ return }
                const inputId = action.payload.inputId 
                draft.dates[inputId].calendar.hour = hour
                return
            }
        },

        /**
         * Set minutes displayed to calendar
         * @memberof selectedDate 
         * @param {number} minute 
         * @param {string} inputId 
         * @example `selectedDateAction.setCalendarMinute( {string} id, {number} minute )`
         */
        setCalendarMinute: {

            prepare: (minute, inputId) => ({
                payload: {minute, inputId}
            }),

            reducer: (draft, action) => {
                const minute = parseInt(action.payload.minute)
                if(minute < 0 || minute > 59){ return }
                const inputId = action.payload.inputId 
                draft.dates[inputId].calendar.minute = minute 
                return
            }
        },

        /**
         * Set month displayed to calendar
         * @memberof selectedDate 
         * @param {number} month 
         * @param {string} inputId 
         * @example `selectedDateAction.setCalendarMonth( {string} id, {number} month )` 
         */
        setCalendarMonth: {

            prepare: (month, inputId) => ({
                payload: {month, inputId}
            }),

            reducer: (draft, action) => {
                const month = parseInt(action.payload.month)
                if(month < 1 || month > 12){ return }
                const inputId = action.payload.inputId 
                draft.dates[inputId].calendar.month = month 
                return
            }
        },

        /**
         * Set year displayed to calendar
         * @memberof selectedDate 
         * @param {number} year 
         * @param {string} inputId 
         * @example `selectedDateAction.setCalendarYear( {string} id, {number} year )` 
         */
        setCalendarYear: {

            prepare: (year, inputId) => ({
                payload: {year, inputId}
            }),

            reducer: (draft, action) => {
                const year = parseInt(action.payload.year)
                if(year < getLimitYear("min") || year > getLimitYear("max")){ return }
                const inputId = action.payload.inputId 
                draft.dates[inputId].calendar.year = year 
                return
            }
        },

        /**
         * Set selected day
         * @memberof selectedDate 
         * @param {number} day 
         * @param {string} inputId 
         * @param {string | boolean} typeDate - accept start, end or false 
         * @example `selectedDateAction.setDay( {string} id, {number} day, {string | boolean} typeDate )` 
         */
        setDay: {

            prepare: (day, inputId, typeDate) => ({
                payload: {day, inputId, typeDate}
            }),

            reducer: (draft, action) => {
                const day = parseInt(action.payload.day)
                if(day < 1 || day > 31){ return }
                const inputId = action.payload.inputId 
                const typeDate = action.payload.typeDate
                if(typeDate){
                    draft.dates[inputId][typeDate].day = transformToNumber(day)
                    if(typeDate === "start"){ draft.dates[inputId].calendar.day = day }
                } else { 
                    draft.dates[inputId].day = transformToNumber(day) 
                    draft.dates[inputId].calendar.day = day 
                }
                if(draft.dates[inputId].status !== "selected" && (
                    draft.dates[inputId].type.indexOf("Period") < 0 || ( 
                        typeDate === "end" && draft.dates[inputId].start.day !== draft.dates[inputId].end.day
                    ))){ draft.dates[inputId].status = "selected" 
                } else if(typeDate === "start"){ draft.dates[inputId].status = "pending" }
                return
            }
        },

        /**
         * Set selected hour
         * @memberof selectedDate 
         * @param {number} hour 
         * @param {string} inputId 
         * @param {string | boolean} typeDate - accept start, end or false 
         * @example `selectedDateAction.setHour( {string} id, {number} hour, {string | boolean} typeDate )` 
         */
        setHour: {

            prepare: (hour, inputId, typeDate) => ({
                payload: {hour, inputId, typeDate}
            }),

            reducer: (draft, action) => {
                const hour = parseInt(action.payload.hour)
                if(hour < 0 || hour >= 24){ return }
                const inputId = action.payload.inputId 
                const typeDate = action.payload.typeDate
                if(typeDate){
                    draft.dates[inputId][typeDate].hour = transformToNumber(hour)
                    if(typeDate === "start"){ draft.dates[inputId].calendar.hour = hour }
                } else { 
                    draft.dates[inputId].hour = transformToNumber(hour) 
                    draft.dates[inputId].calendar.hour = hour 
                }
                if(draft.dates[inputId].status !== "selected" && (
                    draft.dates[inputId].type.indexOf("Period") < 0 || ( 
                        typeDate === "end" && draft.dates[inputId].start.hour !== draft.dates[inputId].end.hour
                    ))){ draft.dates[inputId].status = "selected"}
                return
            }
        },

        /**
         * Set selected minute
         * @memberof selectedDate 
         * @param {number} minute 
         * @param {string} inputId 
         * @param {string | boolean} typeDate - accept start, end or false 
         * @example `selectedDateAction.setMinute( {string} id, {number} minute, {string | boolean} typeDate )` 
         */
        setMinute: {

            prepare: (minute, inputId, typeDate) => ({
                payload: {minute, inputId, typeDate}
            }),

            reducer: (draft, action) => {
                const minute = parseInt(action.payload.minute)
                if(minute < 0 || minute > 59){ return }
                const inputId = action.payload.inputId 
                const typeDate = action.payload.typeDate
                if(typeDate){
                    draft.dates[inputId][typeDate].minute = transformToNumber(minute)
                    if(typeDate === "start"){ draft.dates[inputId].calendar.minute = minute }
                } else { 
                    draft.dates[inputId].minute = transformToNumber(minute) 
                    draft.dates[inputId].calendar.minute = minute 
                }
                if(draft.dates[inputId].status !== "selected" && (
                    draft.dates[inputId].type.indexOf("Period") < 0 || ( 
                        typeDate === "end" && draft.dates[inputId].start.minute !== draft.dates[inputId].end.minute
                    ))){ draft.dates[inputId].status = "selected"}
                return
            }
        },

        /**
         * Set selected Month
         * @memberof selectedDate 
         * @param {number} month 
         * @param {string} inputId 
         * @param {string | boolean} typeDate - accept start, end or false 
         * @example `selectedDateAction.setMonth( {string} id, {number} month, {string | boolean} typeDate )` 
         */
        setMonth: {

            prepare: (month, inputId, typeDate) => ({
                payload: {month, inputId, typeDate}
            }),

            reducer: (draft, action) => {
                const month = parseInt(action.payload.month)
                if(month < 1 || month > 12){ return }
                const inputId = action.payload.inputId 
                const typeDate = action.payload.typeDate
                if(typeDate){
                    draft.dates[inputId][typeDate].month = transformToNumber(month)
                    if(typeDate === "start"){ draft.dates[inputId].calendar.month = month }
                } else { 
                    draft.dates[inputId].month = transformToNumber(month)
                    draft.dates[inputId].calendar.month = month 
                }
                if(draft.dates[inputId].status !== "selected" && (
                    draft.dates[inputId].type.indexOf("Period") < 0 || ( 
                        typeDate === "end" && draft.dates[inputId].start.month !== draft.dates[inputId].end.month
                    ))){ draft.dates[inputId].status = "selected"}
                return
            }
        },

        /**
         * Set selected year
         * @memberof selectedDate 
         * @param {number} year 
         * @param {string} inputId 
         * @param {string | boolean} typeDate - accept start, end or false 
         * @example `selectedDateAction.setYear( {string} id, {number} year, {string | boolean} typeDate )` 
         */
        setYear: {

            prepare: (year, inputId, typeDate) => ({
                payload: {year, inputId, typeDate}
            }),

            reducer: (draft, action) => {
                const year = parseInt(action.payload.year)
                if(year < getLimitYear("min") || year > getLimitYear("max")){ return }
                const inputId = action.payload.inputId 
                const typeDate = action.payload.typeDate
                if(typeDate){
                    draft.dates[inputId][typeDate].year = transformToNumber(year)
                    if(typeDate === "start"){ draft.dates[inputId].calendar.year = year }
                } else { 
                    draft.dates[inputId].year = transformToNumber(year) 
                    draft.dates[inputId].calendar.year = year 
                }
                if(draft.dates[inputId].status !== "selected" && (
                    draft.dates[inputId].type.indexOf("Period") < 0 || ( 
                        typeDate === "end" && draft.dates[inputId].start.year !== draft.dates[inputId].end.year
                    ))){ draft.dates[inputId].status = "selected"}
                return
            }
        }
    }
})

export const { 
    init, 
    initCalendar, 
    set, 
    setCalendarDay, 
    setCalendarHour, 
    setCalendarMinute, 
    setCalendarMonth, 
    setCalendarYear, 
    setDay, 
    setHour, 
    setMinute, 
    setMonth, 
    setYear 
} = actions

export default reducer