phx-react
Version:
PHX REACT
153 lines • 8.77 kB
JavaScript
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid';
import React, { useState, useMemo, useCallback, useEffect } from 'react';
const getMonthName = (month) => {
const monthNames = [
'Tháng 1',
'Tháng 2',
'Tháng 3',
'Tháng 4',
'Tháng 5',
'Tháng 6',
'Tháng 7',
'Tháng 8',
'Tháng 9',
'Tháng 10',
'Tháng 11',
'Tháng 12',
];
return monthNames[month];
};
// Mảng tên các ngày trong tuần (T2 -> CN)
const weekdays = ['T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN'];
export function classNames(...classes) {
return classes.filter(Boolean).join(' ');
}
export const PHXCalendar = ({ defaultEndDate, defaultStartDate, max, onChange }) => {
const [currentYear, setCurrentYear] = useState(new Date().getFullYear());
const [currentMonth, setCurrentMonth] = useState(new Date().getMonth());
const [startDate, setStartDate] = useState(defaultStartDate);
const [endDate, setEndDate] = useState(defaultEndDate);
const calendar = useMemo(() => {
const createCalendar = (year, month) => {
const firstDayOfMonth = new Date(year, month, 1);
const daysInMonth = new Date(year, month + 1, 0).getDate();
const today = new Date();
const calendarData = [];
// Tính thứ của ngày đầu tháng (T2 = 0, ..., CN = 6)
const firstDayIndex = (firstDayOfMonth.getDay() + 6) % 7; // Chuyển Chủ Nhật (0) thành 6, Thứ Hai (1) thành 0
// Chỉ thêm các ngày trong tháng hiện tại
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(year, month, day);
const dayOfWeek = (firstDayIndex + day - 1) % 7; // T2 = 0, T3 = 1, ..., CN = 6
calendarData.push({
date,
dayOfWeek,
isCurrentMonth: true,
isToday: date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear(),
currentMonth: month + 1,
});
}
return calendarData;
};
return {
left: createCalendar(currentYear, currentMonth),
right: createCalendar(currentMonth === 11 ? currentYear + 1 : currentYear, currentMonth === 11 ? 0 : currentMonth + 1),
};
}, [currentYear, currentMonth]);
const handleChangeMonth = useCallback((type) => {
switch (type) {
case 'next':
if (max) {
const rightMonthYear = currentMonth === 11 ? currentYear + 1 : currentYear;
const rightMonth = currentMonth === 11 ? 0 : currentMonth + 1;
const nextMonthYear = rightMonth === 11 ? rightMonthYear + 1 : rightMonthYear;
const nextMonth = (rightMonth + 1) % 12;
if (new Date(nextMonthYear, nextMonth, 1) <= max) {
setCurrentMonth((prev) => (prev + 1) % 12);
setCurrentYear((prev) => prev + (currentMonth === 11 ? 1 : 0));
}
}
else {
setCurrentMonth((prev) => (prev + 1) % 12);
setCurrentYear((prev) => prev + (currentMonth === 11 ? 1 : 0));
}
break;
case 'prev':
setCurrentMonth((prev) => (prev - 1 + 12) % 12);
setCurrentYear((prev) => prev - (currentMonth === 0 ? 1 : 0));
break;
default:
break;
}
}, [currentMonth, max]);
const handleSelectDate = useCallback((day) => {
if (max && day.date > max)
return;
const selectedDate = day.date;
if (!startDate || (startDate && endDate)) {
setStartDate(selectedDate);
setEndDate(undefined);
}
else {
if (selectedDate < startDate) {
setStartDate(selectedDate);
setEndDate(startDate);
}
else {
setEndDate(selectedDate);
const selectedMonth = selectedDate.getMonth();
const selectedYear = selectedDate.getFullYear();
const isSameMonthAsLeft = selectedMonth === currentMonth && selectedYear === currentYear;
const isSameMonthAsRight = selectedMonth === (currentMonth + 1) % 12 &&
selectedYear === (currentMonth === 11 ? currentYear + 1 : currentYear);
if (!isSameMonthAsLeft && !isSameMonthAsRight) {
// Đặt currentMonth là tháng trước của endDate
const newMonth = selectedMonth === 0 ? 11 : selectedMonth - 1;
const newYear = selectedMonth === 0 ? selectedYear - 1 : selectedYear;
setCurrentMonth(newMonth);
setCurrentYear(newYear);
}
}
}
}, [startDate, endDate, currentMonth, currentYear, max]);
useEffect(() => {
onChange(startDate, endDate);
}, [startDate, endDate, onChange]);
useEffect(() => {
if (defaultStartDate)
setStartDate(defaultStartDate);
if (defaultEndDate)
setEndDate(defaultEndDate);
}, [defaultStartDate, defaultEndDate]);
return (React.createElement("div", { className: 'mt-4 flex gap-4' }, [calendar.left, calendar.right].map((monthData, calIdx) => {
var _a;
return (React.createElement("div", { key: calIdx, className: 'flex-1' },
React.createElement("div", { className: 'relative mb-4 flex items-center justify-center' },
calIdx === 0 && (React.createElement("button", { className: 'absolute left-0 rounded-lg p-1 text-gray-500 hover:bg-gray-200', onClick: () => handleChangeMonth('prev'), type: 'button' },
React.createElement(ArrowLeftIcon, { className: 'h-5 w-5' }))),
React.createElement("span", { className: 'text-xs font-medium' },
getMonthName(currentMonth + calIdx),
' ',
calIdx === 0 ? currentYear : currentMonth === 11 ? currentYear + 1 : currentYear),
calIdx === 1 && (React.createElement("button", { className: classNames('absolute right-0 rounded-lg p-1 text-gray-500 hover:bg-gray-200', max &&
new Date(currentMonth === 11 ? currentYear + 1 : currentYear, currentMonth === 11 ? 0 : currentMonth + 1, 1) > max &&
'cursor-not-allowed opacity-50'), disabled: max &&
new Date(currentMonth === 11 ? currentYear + 1 : currentYear, currentMonth === 11 ? 0 : currentMonth + 1, 1) > max, onClick: () => handleChangeMonth('next'), type: 'button' },
React.createElement(ArrowRightIcon, { className: 'h-5 w-5' })))),
React.createElement("div", { className: 'mb-4 grid grid-cols-7 gap-0 border-gray-200' }, weekdays.map((day, index) => (React.createElement("div", { key: index, className: 'py-2 text-center text-xs font-medium text-gray-600' }, day)))),
React.createElement("div", { className: 'grid grid-cols-7 gap-0' },
Array.from({ length: ((_a = monthData[0]) === null || _a === void 0 ? void 0 : _a.dayOfWeek) || 0 }).map((_, index) => (React.createElement("div", { key: `empty-${index}`, className: 'py-2' }) // Ô trống trước ngày 1
)),
monthData.map((day, index) => {
const isStart = startDate && day.date.getTime() === startDate.getTime();
const isEnd = endDate && day.date.getTime() === endDate.getTime();
const isInRange = startDate && endDate && day.date > startDate && day.date < endDate;
const isSingleDay = startDate && !endDate && day.date.getTime() === startDate.getTime();
const isDisabled = max && day.date > max;
return (React.createElement("button", { key: index, className: classNames('relative py-2 text-xs text-gray-800 ', day.isToday && 'font-semibold text-gray-900', isInRange && 'bg-gray-300', isStart && 'rounded-l-lg bg-gray-800 text-white', isEnd && 'rounded-r-lg bg-gray-800 text-white', isSingleDay && 'rounded-lg bg-gray-800 text-white', isDisabled ? 'cursor-not-allowed opacity-50' : isInRange ? '' : 'hover:bg-gray-200'), disabled: isDisabled, onClick: () => handleSelectDate(day), type: 'button' }, day.date.getDate()));
}))));
})));
};
//# sourceMappingURL=Calendar.js.map