import React, { useCallback } from 'react' import _ from 'lodash' import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { format, isSameDay, isSameMonth, isToday } from 'date-fns' /* Import components here */ import { Body, CellContent, DateMonthWrapper, DayCell, DayPicker, Navigation, PageableNavigation, Picker, StyledCard, } from './calendar.styles' import { HideWhileLoading } from '../hide-while-loading' import { Button } from '../inputs/button' import { DayNames } from './day-names' /* Import interfaces here */ import { CalendarProps, DayProps } from './calendar.interfaces' import { calendarTheme } from './calendar.theme' /* Import utilities here */ import { generateCalendar, monthName } from './calendar.utilities' /** * Generate a string to be used as key in extraInfo * @param d - date to generate key for * @returns the key to be used */ const getExtraInfoKey = (d: Date): string => format(d, 'yyyy-MM-dd') /** * prepare props for the Day component * @remarks This is a curried function * @param value - Current selected value in calendar * @param month - Current selected month in the calendar * @param extraInfo - Extra info dictionrary to fetch extra info from * @param date - generate props for this day * * @returns an object that can be used as props to the Day component */ const prepareItem = _.curry(function (value: Date, month: Date, extraInfo: T, date: Date): DayProps { const key = getExtraInfoKey(date) const info = extraInfo ? (extraInfo as Record)[key] : undefined return { date, isToday: isToday(date), isSelected: isSameDay(value, date), isCurrentMonth: isSameMonth(month, date), extraInfo: info, } }) // TODO: Use correct type and remove eslint disable // eslint-disable-next-line @typescript-eslint/ban-types const DefaultDayComponent = (dayProps: DayProps): JSX.Element => { const { date, extraInfo, ...props } = dayProps return ( {date.getDate()} {extraInfo && ` :  ${extraInfo}`} ) } const Header = ({ month, monthTitleLength, isLoading, onPrevMonthClick, onNextMonthClick, }: { isLoading: boolean onPrevMonthClick: () => void onNextMonthClick: () => void month: Date monthTitleLength?: number }) => { const monthYearTitle = `${monthName(month, monthTitleLength)} ${month.getFullYear()}` return ( {monthYearTitle} ) } export const Calendar = >(props: CalendarProps): JSX.Element => { const { value, month, className, onChangeMonth, onSelectDate, dayComponent, isLoading, error, monthTitleLength, ...styleProps } = props let { extraInfo } = props // Make sure it's not undefined extraInfo = extraInfo || {} const calendar: DayProps[] = Array.from(generateCalendar(month)).map(prepareItem(value, month, extraInfo)) const onNextMonthClick = useCallback((): void => { const monthCopy = new Date(month.getTime()) monthCopy.setMonth(monthCopy.getMonth() + 1) onChangeMonth(monthCopy) }, [onChangeMonth, month]) const onPrevMonthClick = useCallback((): void => { const monthCopy = new Date(month.getTime()) monthCopy.setMonth(monthCopy.getMonth() - 1) onChangeMonth(monthCopy) }, [onChangeMonth, month]) const DayComponent: React.FC> = dayComponent || DefaultDayComponent return (
{calendar.map( (dateProps: DayProps): JSX.Element => ( ), )} {/* TODO: Implement this */} ) } Calendar.defaultTheme = calendarTheme