Skip to content

Commit 212802c

Browse files
committed
fix: disable past days on calendar and fix start date to now
1 parent dee58a4 commit 212802c

File tree

7 files changed

+94
-92
lines changed

7 files changed

+94
-92
lines changed

components/DateTimePicker/CalendarDay.tsx

+13-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,18 @@ export const CalendarDay = ({
99
isRangeEnd,
1010
isFirstInWeek,
1111
isLastInWeek,
12+
isDisabled,
1213
onClick,
1314
}: CalendarDayProps) => {
1415
const { day, month, year } = dateObj;
1516

17+
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
18+
e.preventDefault();
19+
if (!isDisabled) {
20+
onClick(day, month, year);
21+
}
22+
};
23+
1624
return (
1725
<div
1826
className={cn(
@@ -25,12 +33,15 @@ export const CalendarDay = ({
2533
)}
2634
>
2735
<button
36+
type="button"
2837
className={cn(
2938
"flex items-center justify-center w-12 h-12 relative rounded-full transition-colors",
3039
(isRangeStart || isRangeEnd) && "bg-gray-900 text-white",
31-
!isCurrentMonth && "text-gray-300"
40+
!isCurrentMonth && "text-gray-300",
41+
isDisabled && "cursor-not-allowed"
3242
)}
33-
onClick={() => onClick(day, month, year)}
43+
onClick={handleClick}
44+
disabled={isDisabled}
3445
aria-label={`${day} ${new Intl.DateTimeFormat("en-US", {
3546
month: "long",
3647
}).format(new Date(year, month, 1))}, ${year}`}

components/DateTimePicker/DateTimePicker.tsx

+55-68
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { useState } from "react";
2-
import { ChevronLeftIcon, ChevronRightIcon } from "../icon-components";
2+
import {
3+
ChevronLeftIcon,
4+
ChevronRightIcon,
5+
ClockIcon,
6+
} from "../icon-components";
37
import { Button } from "../ui/Button";
48
import { Modal } from "../ui/Modal";
59
import {
@@ -21,6 +25,7 @@ export default function DateTimePicker({
2125
initialStartTime = "13:00",
2226
initialEndTime = "18:00",
2327
}: DateTimePickerProps) {
28+
const today = new Date();
2429
const [currentDate, setCurrentDate] = useState(new Date());
2530

2631
// Selected date range
@@ -31,15 +36,8 @@ export default function DateTimePicker({
3136
endTime: initialEndTime,
3237
});
3338

34-
// Selection mode (start or end date)
35-
const [selectionMode, setSelectionMode] = useState<"start" | "end" | null>(
36-
null
37-
);
38-
3939
// Time picker state
40-
const [timePickerOpen, setTimePickerOpen] = useState<"start" | "end" | null>(
41-
null
42-
);
40+
const [timePickerOpen, setTimePickerOpen] = useState<"end" | null>(null);
4341

4442
// Navigate to previous month
4543
const previousMonth = () => {
@@ -63,50 +61,25 @@ export default function DateTimePicker({
6361
const handleDateClick = (day: number, month: number, year: number) => {
6462
const clickedDate = new Date(year, month, day);
6563

66-
if (
67-
!dateRange.startDate ||
68-
selectionMode === "start" ||
69-
(dateRange.startDate && dateRange.endDate)
70-
) {
71-
// Start new selection
72-
setDateRange({
73-
...dateRange,
74-
startDate: clickedDate,
75-
endDate: null,
76-
});
77-
setSelectionMode("end");
78-
} else {
79-
// Complete selection
80-
if (clickedDate < dateRange.startDate) {
81-
// If clicked date is before start date, swap them
82-
setDateRange({
83-
...dateRange,
84-
startDate: clickedDate,
85-
endDate: dateRange.startDate,
86-
});
87-
} else {
88-
setDateRange({
89-
...dateRange,
90-
endDate: clickedDate,
91-
});
92-
}
93-
setSelectionMode(null);
64+
if (clickedDate <= today) {
65+
return;
9466
}
67+
68+
setDateRange({
69+
...dateRange,
70+
endDate: clickedDate,
71+
});
9572
};
9673

9774
// Handle time selection
98-
const handleTimeChange = (
99-
type: "start" | "end",
100-
hours: number,
101-
minutes: number
102-
) => {
75+
const handleTimeChange = (hours: number, minutes: number) => {
10376
const formattedHours = hours.toString().padStart(2, "0");
10477
const formattedMinutes = minutes.toString().padStart(2, "0");
10578
const timeString = `${formattedHours}:${formattedMinutes}`;
10679

10780
setDateRange((prev) => ({
10881
...prev,
109-
[type === "start" ? "startTime" : "endTime"]: timeString,
82+
endTime: timeString,
11083
}));
11184
};
11285

@@ -192,6 +165,17 @@ export default function DateTimePicker({
192165
return date.getTime() === compareDate.getTime();
193166
};
194167

168+
// Check if a date should be disabled (current date or past dates)
169+
const isDateDisabled = (
170+
day: number,
171+
month: number,
172+
year: number
173+
): boolean => {
174+
const date = new Date(year, month, day);
175+
date.setHours(0, 0, 0, 0);
176+
return date <= today;
177+
};
178+
195179
// Get current month and year for display
196180
const currentMonthName = new Intl.DateTimeFormat("en-US", {
197181
month: "long",
@@ -208,8 +192,10 @@ export default function DateTimePicker({
208192
{/* Month navigation */}
209193
<div className="flex items-center justify-between mb-6">
210194
<button
195+
type="button"
211196
onClick={previousMonth}
212-
className="p-2 rounded-full"
197+
className="p-2 rounded-full disabled:opacity-25"
198+
disabled={currentDate.getMonth() === today.getMonth()}
213199
aria-label="Previous month"
214200
>
215201
<ChevronLeftIcon />
@@ -218,6 +204,7 @@ export default function DateTimePicker({
218204
{currentMonthName} {currentYear}
219205
</h2>
220206
<button
207+
type="button"
221208
onClick={nextMonth}
222209
className="p-2 rounded-full"
223210
aria-label="Next month"
@@ -229,50 +216,43 @@ export default function DateTimePicker({
229216
{/* Date range inputs */}
230217
<div className="flex items-center mb-6">
231218
<div className="flex-1">
232-
<button
233-
className="w-full border border-gray-300 rounded-lg p-4 bg-transparent text-left"
234-
onClick={() => setSelectionMode("start")}
235-
>
236-
<div className="text-gray-900 text-sm">
237-
{dateRange.startDate ? formatDate(dateRange.startDate) : ""}
219+
<div className="w-full border border-gray-300 rounded-lg p-4 bg-gray-100 text-left cursor-not-allowed">
220+
<div className="text-gray-500 text-sm">
221+
{formatDate(dateRange.startDate)}
238222
</div>
239-
</button>
223+
</div>
240224
</div>
241225
<div className="mx-2 text-gray-400"></div>
242226
<div className="flex-1">
243227
<button
228+
type="button"
244229
className="w-full border border-gray-300 rounded-lg p-4 bg-transparent text-left"
245-
onClick={() => dateRange.startDate && setSelectionMode("end")}
246230
disabled={!dateRange.startDate}
247231
>
248232
<div className="text-gray-900 text-sm">
249-
{dateRange.endDate ? formatDate(dateRange.endDate) : ""}
233+
{dateRange.endDate
234+
? formatDate(dateRange.endDate)
235+
: "Select end date"}
250236
</div>
251237
</button>
252238
</div>
253239
</div>
254240

255241
{/* Time range inputs */}
256242
<div className="flex items-center mb-8">
257-
<TimePicker
258-
time={dateRange.startTime}
259-
isOpen={timePickerOpen === "start"}
260-
onTimeChange={(hours, minutes) =>
261-
handleTimeChange("start", hours, minutes)
262-
}
263-
onToggle={() =>
264-
setTimePickerOpen((prev) => (prev === "start" ? null : "start"))
265-
}
266-
/>
243+
<div className="flex-1">
244+
<div className="w-full border border-gray-300 rounded-lg p-4 bg-gray-100 text-left cursor-not-allowed flex items-center gap-2">
245+
<ClockIcon />
246+
<div className="text-gray-500 text-sm">{dateRange.startTime}</div>
247+
</div>
248+
</div>
267249

268250
<div className="mx-2 text-gray-400"></div>
269251

270252
<TimePicker
271253
time={dateRange.endTime}
272254
isOpen={timePickerOpen === "end"}
273-
onTimeChange={(hours, minutes) =>
274-
handleTimeChange("end", hours, minutes)
275-
}
255+
onTimeChange={(hours, minutes) => handleTimeChange(hours, minutes)}
276256
onToggle={() =>
277257
setTimePickerOpen((prev) => (prev === "end" ? null : "end"))
278258
}
@@ -320,6 +300,11 @@ export default function DateTimePicker({
320300
)}
321301
isFirstInWeek={dayIndex === 0}
322302
isLastInWeek={dayIndex === 6}
303+
isDisabled={isDateDisabled(
304+
dateObj.day,
305+
dateObj.month,
306+
dateObj.year
307+
)}
323308
onClick={handleDateClick}
324309
/>
325310
))}
@@ -331,16 +316,18 @@ export default function DateTimePicker({
331316
{/* Footer */}
332317
<div className="flex border-t border-gray-300 justify-evenly items-center py-4">
333318
<Button
319+
type="button"
334320
variant="outline"
335321
className="w-5/12"
336322
onClick={() => onOpenChange(false)}
337323
>
338324
Cancel
339325
</Button>
340326
<Button
341-
className="w-5/12"
327+
type="button"
328+
className="w-5/12 disabled:opacity-50"
342329
onClick={handleApply}
343-
disabled={!dateRange.startDate || !dateRange.endDate}
330+
disabled={!dateRange.endDate}
344331
>
345332
Apply
346333
</Button>

components/DateTimePicker/TimePicker.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const TimePicker = ({
3737
return (
3838
<div className={cn("flex-1 relative", className)} ref={timePickerRef}>
3939
<button
40+
type="button"
4041
className={cn(
4142
"w-full border rounded-lg p-4 bg-transparent flex items-center gap-2",
4243
isOpen ? "border-gray-500" : "border-gray-300"
@@ -58,6 +59,7 @@ export const TimePicker = ({
5859
<div className="h-48 overflow-y-auto flex flex-col items-center">
5960
{HOURS.map((hour) => (
6061
<button
62+
type="button"
6163
key={hour}
6264
className={cn(
6365
"w-full py-2 text-center rounded-md",
@@ -84,6 +86,7 @@ export const TimePicker = ({
8486
<div className="h-48 overflow-y-auto flex flex-col items-center">
8587
{MINUTES.map((minute) => (
8688
<button
89+
type="button"
8790
key={minute}
8891
className={cn(
8992
"w-full py-2 text-center rounded-md",

components/Poll/PollList.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ export default function PollList({ filters, filterParam }: PollListProps) {
3636
}, [filters]);
3737

3838
const checkIsActive = () => {
39-
if (filters.livePolls && filters.finishedPolls) return undefined;
39+
if (filters.livePolls && filters.finishedPolls) return "none";
40+
if (!filters.livePolls && !filters.finishedPolls) return undefined;
4041
if (filters.livePolls && !filters.finishedPolls) return true;
4142
if (!filters.livePolls && filters.finishedPolls) return false;
42-
if (!filters.livePolls && !filters.finishedPolls) return undefined;
4343
return undefined;
4444
};
4545

hooks/usePoll.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const POLLS_LIMIT = 10;
1111
interface IUsePollParams {
1212
page?: number;
1313
limit?: number;
14-
isActive?: boolean;
14+
isActive?: boolean | "none";
1515
userVoted?: boolean;
1616
userCreated?: boolean;
1717
sortBy?: "creationDate" | "endDate" | "participantCount";
@@ -37,6 +37,13 @@ export const useGetPolls = (
3737
return useQuery({
3838
queryKey: ["polls", filters],
3939
queryFn: async () => {
40+
if (filters.isActive === "none") {
41+
return {
42+
polls: [],
43+
total: 0,
44+
};
45+
}
46+
4047
const params: IUsePollParams = {
4148
page: filters.page || 1,
4249
limit: filters.limit || POLLS_LIMIT,

0 commit comments

Comments
 (0)