Vitron-Front/app/components/PersianDatePicker.tsx
2026-04-29 01:44:16 +03:30

206 lines
6.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import { Calendar, ChevronLeft, ChevronRight, X } from "lucide-react";
import { Button } from "./ui/button";
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "./ui/drawer";
import jMoment from "moment-jalaali";
interface PersianDatePickerProps {
value?: string; // Format: YYYY/MM/DD
onChange: (date: string) => void;
placeholder?: string;
label?: string;
}
const PersianDatePicker = ({
value,
onChange,
placeholder = "انتخاب تاریخ",
label,
}: PersianDatePickerProps) => {
const [isOpen, setIsOpen] = useState(false);
const [currentDate, setCurrentDate] = useState(jMoment());
const [selectedDate, setSelectedDate] = useState<string | null>(
value || null
);
const persianMonths = [
"فروردین",
"اردیبهشت",
"خرداد",
"تیر",
"مرداد",
"شهریور",
"مهر",
"آبان",
"آذر",
"دی",
"بهمن",
"اسفند",
];
const persianDaysOfWeek = ["ش", "ی", "د", "س", "چ", "پ", "ج"];
// Generate calendar days
const generateCalendarDays = () => {
const startOfMonth = currentDate.clone().startOf("jMonth");
const endOfMonth = currentDate.clone().endOf("jMonth");
const startOfWeek = startOfMonth.clone().startOf("week");
const endOfWeek = endOfMonth.clone().endOf("week");
const days = [];
const currentDay = startOfWeek.clone();
while (currentDay.isSameOrBefore(endOfWeek)) {
days.push(currentDay.clone());
currentDay.add(1, "day");
}
return days;
};
const handleDateSelect = (date: typeof jMoment) => {
const dateString = date.format("jYYYY/jMM/jDD");
setSelectedDate(dateString);
onChange(dateString);
setIsOpen(false);
};
const goToPreviousMonth = () => {
setCurrentDate(currentDate.clone().subtract(1, "jMonth"));
};
const goToNextMonth = () => {
setCurrentDate(currentDate.clone().add(1, "jMonth"));
};
const calendarDays = generateCalendarDays();
return (
<>
{label && <p className="text-R14 font-bold mb-2">{label}</p>}
<Button
variant="outline"
size="xl"
onClick={() => setIsOpen(true)}
className={`${!selectedDate && "text-GRAY"} w-full bg-WHITE relative justify-start text-right h-12 px-4`}
>
<div className="flex px-2 items-center justify-between absolute left-0 bg-BLACK h-full rounded-l-md">
<Calendar size={24} className="text-WHITE" />
</div>
{selectedDate || placeholder}
</Button>
<Drawer open={isOpen} onOpenChange={setIsOpen}>
<DrawerContent className="w-full pb-6">
<DrawerHeader className="flex flex-col py-3">
<div className="flex relative pt-2 text-B12 font-bold items-center justify-center w-full">
<X
className="absolute right-4 cursor-pointer"
size={24}
onClick={() => setIsOpen(false)}
/>
<DrawerTitle className="text-B16 font-bold">
انتخاب تاریخ
</DrawerTitle>
</div>
</DrawerHeader>
<div className="px-4">
{/* Month/Year Header */}
<div className="flex items-center justify-between mb-4">
<Button
variant="ghost"
size="sm"
onClick={goToPreviousMonth}
className="p-2"
>
<ChevronRight className="w-4 h-4" />
</Button>
<div className="text-center">
<p className="text-lg font-bold">
{persianMonths[currentDate.jMonth()]} {currentDate.jYear()}
</p>
</div>
<Button
variant="ghost"
size="sm"
onClick={goToNextMonth}
className="p-2"
>
<ChevronLeft className="w-4 h-4" />
</Button>
</div>
{/* Days of Week Header */}
<div className="grid grid-cols-7 gap-1 mb-2">
{persianDaysOfWeek.map((day) => (
<div
key={day}
className="text-center text-sm font-bold text-GRAY py-2"
>
{day}
</div>
))}
</div>
{/* Calendar Days */}
<div className="grid grid-cols-7 gap-1">
{calendarDays.map((day, index) => {
const isCurrentMonth = day.jMonth() === currentDate.jMonth();
const isSelected = selectedDate === day.format("jYYYY/jMM/jDD");
const isToday = day.isSame(jMoment(), "day");
return (
<Button
key={index}
variant={isSelected ? "dark" : "ghost"}
size="sm"
onClick={() => handleDateSelect(day)}
className={`
h-10 w-full p-0 text-sm
${!isCurrentMonth ? "text-GRAY2" : ""}
${isToday && !isSelected ? "bg-blue-50 text-blue-600" : ""}
`}
disabled={!isCurrentMonth}
>
{day.jDate()}
</Button>
);
})}
</div>
{/* Action Buttons */}
<div className="flex gap-3 mt-6">
<Button
variant="outline"
onClick={() => setIsOpen(false)}
className="flex-1"
size="xl"
>
انصراف
</Button>
<Button
onClick={() => {
const today = jMoment().format("jYYYY/jMM/jDD");
setSelectedDate(today);
onChange(today);
setIsOpen(false);
}}
className="flex-1"
variant="secondary"
size="xl"
>
امروز
</Button>
</div>
</div>
</DrawerContent>
</Drawer>
</>
);
};
export default PersianDatePicker;