import React, { useState, useEffect } from 'react'; import { useTheme } from '@emotion/react'; import { StyledCalendar } from '../style'; import cx from 'classnames'; import { BnBack, BnForward } from '../../../icons'; import dayjs, { Dayjs } from 'dayjs'; export interface DateProps { value?: string | Dayjs; defaultValue?: Dayjs; disabledDates?: (day: Dayjs) => boolean; mode?: string; onChange?: (value: Dayjs | undefined) => void; } export interface WeekDay { date: string; dayOfMonth: number; isCurrentMonth: boolean; isDisabled: boolean; } export const Date = ({ defaultValue, disabledDates, mode = 'date', value, onChange, }: DateProps) => { const getValueFormat = () => { if (mode === 'date') { return 'DD / MM / YYYY'; } else if (mode === 'datetime') { return 'DD / MM / YYYY HH:mm'; } else { return 'HH:mm'; } }; const colors = useTheme(); const currentDate = dayjs(); const [selectedMonth, setSelectedMonth] = useState<{ month: number; year: number; }>({ month: defaultValue ? dayjs(defaultValue).month() : dayjs().month(), year: defaultValue ? dayjs(defaultValue).year() : dayjs().year(), }); const [weeksAndDays, setWeeksAndDays] = useState([]); const [hoverPlaceholder, setHoverPlaceholder] = useState( undefined ); const [selectedDay, setSelectedDay] = useState( defaultValue ? dayjs(defaultValue) : dayjs() ); const [inputValue, setInputValue] = useState( value ? dayjs(value).format(getValueFormat()) : undefined ); const [isOptionsOpen, setIsOptionsOpen] = useState(false); const weekDays = [ dayjs().day(1).format('dd').slice(0, 1), dayjs().day(2).format('dd').slice(0, 1), dayjs().day(3).format('dd').slice(0, 1), dayjs().day(4).format('dd').slice(0, 1), dayjs().day(5).format('dd').slice(0, 1), dayjs().day(6).format('dd').slice(0, 1), dayjs().day(0).format('dd').slice(0, 1), ]; const getWeekday = (date: string) => { return dayjs(date).day(); }; const createCalendar = () => { let currentMonthDays = [ ...Array( dayjs( `${selectedMonth.year}-${selectedMonth.month + 1}-01` ).daysInMonth() ), ].map((_, index) => { return { date: dayjs( `${selectedMonth.year}-${selectedMonth.month + 1}-${index + 1}` ).format('YYYY-MM-DD'), dayOfMonth: index + 1, isCurrentMonth: true, isDisabled: disabledDates && disabledDates( dayjs( `${selectedMonth.year}-${selectedMonth.month + 1}-${index + 1}` ) ), }; }); const currentMonthFirstDay = getWeekday(currentMonthDays[0].date); const previousMonth = dayjs( `${selectedMonth.year}-${selectedMonth.month + 1}-01` ).subtract(1, 'month'); const daysOfPreviousMonth = currentMonthFirstDay ? currentMonthFirstDay - 1 : 6; const lastMondayOfPreviousMonth = dayjs(currentMonthDays[0].date) .subtract(daysOfPreviousMonth, 'day') .date(); let previousMonthDays = [...Array(daysOfPreviousMonth)].map((_, index) => { return { date: dayjs( `${previousMonth.year()}-${previousMonth.month() + 1}-${ lastMondayOfPreviousMonth + index }` ).format('YYYY-MM-DD'), dayOfMonth: lastMondayOfPreviousMonth + index, isCurrentMonth: false, isDisabled: disabledDates && disabledDates( dayjs( `${previousMonth.year()}-${previousMonth.month() + 1}-${ lastMondayOfPreviousMonth + index }` ) ), }; }); const currentMonthLastDay = getWeekday( `${selectedMonth.year}-${selectedMonth.month + 1}-${ currentMonthDays.length }` ); const nextMonth = dayjs( `${selectedMonth.year}-${selectedMonth.month + 1}-01` ).add(1, 'month'); const daysOfNextMonth = currentMonthLastDay ? 7 - currentMonthLastDay : currentMonthLastDay; let nextMonthDays = [...Array(daysOfNextMonth)].map((_, index) => { return { date: dayjs( `${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}` ).format('YYYY-MM-DD'), dayOfMonth: index + 1, isCurrentMonth: false, isDisabled: disabledDates && disabledDates( dayjs(`${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`) ), }; }); let days = [...previousMonthDays, ...currentMonthDays, ...nextMonthDays]; return days; }; const goBack = () => { setSelectedMonth({ month: dayjs( dayjs() .month(selectedMonth.month) .year(selectedMonth.year) .subtract(1, 'month') ).month(), year: dayjs( dayjs() .month(selectedMonth.month) .year(selectedMonth.year) .subtract(1, 'month') ).year(), }); }; const goForward = () => { setSelectedMonth({ month: dayjs( dayjs() .month(selectedMonth.month) .year(selectedMonth.year) .add(1, 'month') ).month(), year: dayjs( dayjs() .month(selectedMonth.month) .year(selectedMonth.year) .add(1, 'month') ).year(), }); }; useEffect(() => { let days = createCalendar(); const chunkDays = () => { let results = []; while (days.length) { results.push(days.splice(0, 7)); } return results; }; setWeeksAndDays(chunkDays()); }, [selectedMonth]); return (
{`${dayjs().month(selectedMonth.month).format('MMMM')} ${dayjs() .year(selectedMonth.year) .format('YYYY')}`}
{weekDays.map((weekDay: string, key: number) => ( ))} {weeksAndDays?.map((week: WeekDay[], i: number) => ( {week.map((day: WeekDay, a: number) => ( ))} ))}
{weekDay}
!day.isDisabled && setHoverPlaceholder( dayjs(day.date) .set('hour', selectedDay.get('hour')) .set('minute', selectedDay.get('minute')) .format(getValueFormat()) ) } onMouseOut={() => setHoverPlaceholder(undefined)} onClick={() => { if (!day.isDisabled) { setInputValue( dayjs(day.date) .set('hour', selectedDay.get('hour')) .set('minute', selectedDay.get('minute')) .format(getValueFormat()) ); if (onChange) { onChange( dayjs(day.date, 'YYYY-MM-DD') .set('hour', selectedDay.get('hour')) .set('minute', selectedDay.get('minute')) ); } setSelectedDay(dayjs(day.date)); // selectedDay.set( // 'date', // dayjs(day.date, 'YYYY-MM-DD').get('date') // ) // ); if (!day.isCurrentMonth) { setSelectedMonth({ month: dayjs(day.date).month(), year: dayjs(day.date).year(), }); } setIsOptionsOpen(false); } }} > {dayjs(day.date).format('D')}
); };