PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.3
Yatra – Travel Booking & Tour Operator Software v3.0.3
3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 All 83 releases
yatra / resources / js / components / ui / calendar.tsx

calendar.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.3, at resources/js/components/ui/calendar.tsx

131 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import * as React from "react";
2 import { ChevronLeft, ChevronRight } from "lucide-react";
3 import {
4 format,
5 startOfMonth,
6 endOfMonth,
7 startOfWeek,
8 endOfWeek,
9 eachDayOfInterval,
10 isSameMonth,
11 isSameDay,
12 addMonths,
13 subMonths,
14 isToday,
15 } from "date-fns";
16
17 export interface CalendarProps {
18 selected?: Date;
19 onSelect?: (date: Date | undefined) => void;
20 disabled?: (date: Date) => boolean;
21 minDate?: Date;
22 maxDate?: Date;
23 className?: string;
24 }
25
26 export const Calendar: React.FC<CalendarProps> = ({
27 selected,
28 onSelect,
29 disabled,
30 minDate,
31 maxDate,
32 className = "",
33 }) => {
34 const [currentMonth, setCurrentMonth] = React.useState(new Date());
35
36 const monthStart = startOfMonth(currentMonth);
37 const monthEnd = endOfMonth(currentMonth);
38 const calendarStart = startOfWeek(monthStart, { weekStartsOn: 0 });
39 const calendarEnd = endOfWeek(monthEnd, { weekStartsOn: 0 });
40 const days = eachDayOfInterval({ start: calendarStart, end: calendarEnd });
41
42 const isDateDisabled = (date: Date) => {
43 if (disabled && disabled(date)) return true;
44 if (minDate && date < minDate) return true;
45 if (maxDate && date > maxDate) return true;
46 return false;
47 };
48
49 const handleDateClick = (date: Date) => {
50 if (isDateDisabled(date)) return;
51 onSelect?.(date);
52 };
53
54 const previousMonth = () => {
55 setCurrentMonth(subMonths(currentMonth, 1));
56 };
57
58 const nextMonth = () => {
59 setCurrentMonth(addMonths(currentMonth, 1));
60 };
61
62 const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
63
64 return (
65 <div className={`p-3 ${className}`}>
66 <div className="flex items-center justify-between mb-4">
67 <button
68 type="button"
69 onClick={previousMonth}
70 className="p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors"
71 >
72 <ChevronLeft className="w-4 h-4" />
73 </button>
74 <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
75 {format(currentMonth, "MMMM yyyy")}
76 </h3>
77 <button
78 type="button"
79 onClick={nextMonth}
80 className="p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors"
81 >
82 <ChevronRight className="w-4 h-4" />
83 </button>
84 </div>
85
86 <div className="grid grid-cols-7 gap-1 mb-2">
87 {weekDays.map((day) => (
88 <div
89 key={day}
90 className="text-xs font-medium text-gray-500 dark:text-gray-400 text-center py-2"
91 >
92 {day}
93 </div>
94 ))}
95 </div>
96
97 <div className="grid grid-cols-7 gap-1">
98 {days.map((day, dayIdx) => {
99 const isCurrentMonth = isSameMonth(day, currentMonth);
100 const isSelected = selected && isSameDay(day, selected);
101 const isTodayDate = isToday(day);
102 const isDisabled = isDateDisabled(day);
103
104 return (
105 <button
106 key={dayIdx}
107 type="button"
108 onClick={() => handleDateClick(day)}
109 disabled={isDisabled}
110 className={`
111 h-9 w-9 text-sm rounded-md transition-colors
112 ${isCurrentMonth ? "text-gray-900 dark:text-white" : "text-gray-400 dark:text-gray-600"}
113 ${
114 isSelected
115 ? "bg-blue-600 text-white hover:bg-blue-700"
116 : isTodayDate
117 ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-semibold"
118 : "hover:bg-gray-100 dark:hover:bg-gray-700"
119 }
120 ${isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
121 `}
122 >
123 {format(day, "d")}
124 </button>
125 );
126 })}
127 </div>
128 </div>
129 );
130 };
131