import { MouseEvent, memo, useMemo } from 'react'; import { startOfWeek, isSameDay } from 'date-fns'; import { addDaysToDate, isSameDate } from '../../utils/helperUtil'; import { MousePos, YearCalendarData, YearsCalendarConfig } from './YearConfigs'; import styled from '@emotion/styled'; const StyledCalendarBox = styled('div')((props: any) => ({ display: 'flex', padding: '10px', minHeight: 120, '& .year-box': { div: { fontWeight: 'bold', fontSize: 'x-large', transform: `translateY(${props.cellSize * 4}px) rotate(-90deg)`, }, }, '& .calendars-box': { flex: 1, display: 'flex', minWidth: 0, 'div.weeks': { '.item': { minWidth: `${props.cellSize}px !important`, minHeight: `${props.cellSize}px !important`, border: `1px solid ${props.borderColor}`, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '12px', userSelect: 'none', '&.week': { fontWeight: 'bold', border: `1px solid transparent`, }, }, }, 'div.calendars': { minWidth: 0, overflowX: 'auto', overflowY: 'hidden', paddingBottom: 5, 'div.calendar-months': { flex: 1, display: 'flex', flexDirection: 'column', cursor: 'pointer', width: 'fit-content', 'div.month-names': { display: 'grid', justifyItems: 'center', gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: '1fr', minHeight: `${props.cellSize}px !important`, div: { flex: 1, textAlign: 'center' }, }, 'div.month-calendars': { flex: 1, display: 'grid', justifyItems: 'center', gridTemplateColumns: 'repeat(53, 1fr)', gridTemplateRows: 'repeat(7, 1fr)', gridAutoFlow: 'column', '.item': { minWidth: `${props.cellSize}px !important`, minHeight: `${props.cellSize}px !important`, width: '100%', height: '100%', border: `1px solid ${props.borderColor}`, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '12px', userSelect: 'none', position: 'relative', span: { position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%, -50%)', }, '.items': { flex: 1, display: 'flex', flexWrap: 'wrap', }, '&.week': { fontWeight: 'bold', border: `1px solid transparent`, '&:hover': { backgroundColor: 'inherit', color: 'inherit', }, }, '&.odd-month': { backgroundColor: props.defaultBgColor, color: props.textColor, }, '&.even-month': { backgroundColor: props.alternateBgColor, color: props.textColor, }, '&.today': { backgroundColor: props.todayBgColor, color: props.todayColor, }, '&:hover': { backgroundColor: props.hoverBgColor, color: props.hoverColor, }, }, }, }, }, }, })); type DayData = { date: Date; data?: YearCalendarData[]; otherYear?: boolean; }; const getDayClassName = (d: DayData) => { const cls = []; if (d.otherYear) { cls.push('week'); } else { if (isSameDate(new Date(), d.date)) { cls.push('today'); } else { if (d.date.getMonth() % 2 === 0) { cls.push('odd-month'); } else { cls.push('even-month'); } } } return cls.reduce((p, c) => `${p} ${c}`, 'item'); }; const getDayStyle = (d: YearCalendarData) => { return { backgroundColor: d.bgColor, width: '4px', height: '4px' }; }; const WeeksDisplay = () => (
{[' ', 'S', 'M', 'T', 'W', 'T', 'F', 'S'].map((a, i) => (
{a}
))}
); const MonthsDisplay = () => (
{[ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ].map((a, i) => (
{a}
))}
); const CalendarsDisplay = memo( ({ year, items, onClick, onHover, config, }: { year: number; items: Array; config: YearsCalendarConfig; onClick?: (item: YearCalendarData) => void; onHover?: (item: YearCalendarData, pos: MousePos) => void; }) => { const days = useMemo(() => { let theDate = startOfWeek(new Date(year, 0, 1)); const daysArray: Array = []; const theYear = parseInt(`${year}`); while (theDate.getFullYear() <= theYear) { const x = theDate; const data = items.filter((y) => isSameDay(y.date, x)); daysArray.push({ date: theDate, otherYear: theDate.getFullYear() !== theYear, data, }); theDate = addDaysToDate(theDate, 1); } return daysArray; }, [year, items]); return (
{days.map((d, i) => (
{d.data?.map((d1, j) => (
onClick?.(d1)} onMouseEnter={(e: MouseEvent) => { onHover?.(d1, { x: e.clientX, y: e.clientY }); }} >
))}
{d.otherYear ? '' : d.date.getDate()}
))}
); } ); export function YearBox(props: { year: number; items: Array; config: YearsCalendarConfig; onClick?: (item: YearCalendarData) => void; onHover?: (item: YearCalendarData, pos: MousePos) => void; }) { const { year, config } = props; return (
{year}
); }