import { ThemedText } from "@/components/themed-text"; import { IconSymbol } from "@/components/ui/icon-symbol"; import { Colors } from "@/constants/theme"; import { useTheme } from "@/context/ThemeContext"; import React, { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { Modal, Pressable, StyleSheet, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; interface CalendarModalProps { visible: boolean; onClose: () => void; selectedDate: Date; onSelectDate: (date: Date) => void; } export function CalendarModal({ visible, onClose, selectedDate, onSelectDate, }: CalendarModalProps) { const { theme } = useTheme(); const { i18n } = useTranslation(); const isDark = theme === "dark"; const bg = isDark ? "#1C1C1E" : "#FFFFFF"; const textColor = isDark ? "#FFFFFF" : "#000000"; const subTextColor = isDark ? "#8E8E93" : "#8E8E93"; const [currentMonth, setCurrentMonth] = useState(new Date(selectedDate)); const today = useMemo(() => new Date(), []); const minDate = useMemo( () => new Date(today.getFullYear() - 1, today.getMonth(), 1), [today] ); const maxDate = useMemo( () => new Date(today.getFullYear() + 1, today.getMonth(), 1), [today] ); const daysInMonth = useMemo(() => { const year = currentMonth.getFullYear(); const month = currentMonth.getMonth(); const date = new Date(year, month, 1); const days = []; while (date.getMonth() === month) { days.push(new Date(date)); date.setDate(date.getDate() + 1); } return days; }, [currentMonth]); const weekDays = i18n.language.startsWith("zh") ? ["周日", "周一", "周二", "周三", "周四", "周五", "周六"] : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; // Add empty slots for start of month const startDay = daysInMonth[0]?.getDay() || 0; const blanks = Array(startDay).fill(null); // Calculate padding cells to keep 6 rows (42 cells total) const totalCells = 42; const paddingBlanks = useMemo(() => { const spaceLeft = totalCells - (blanks.length + daysInMonth.length); return spaceLeft > 0 ? Array(spaceLeft).fill(null) : []; }, [blanks.length, daysInMonth.length]); const handleDayPress = (date: Date) => { onSelectDate(new Date(date)); onClose(); }; const monthTitle = currentMonth.toLocaleString(i18n.language, { month: "long", year: "numeric", }); const canGoBack = currentMonth > minDate; const canGoForward = currentMonth < maxDate; return ( setCurrentMonth( new Date( currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1 ) ) } > {monthTitle} setCurrentMonth( new Date( currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1 ) ) } > {weekDays.map((day) => ( {day} ))} {blanks.map((_, index) => ( ))} {daysInMonth.map((date) => { const isSelected = date.getDate() === selectedDate.getDate() && date.getMonth() === selectedDate.getMonth() && date.getFullYear() === selectedDate.getFullYear(); const isToday = today.toDateString() === date.toDateString(); // Check if date is in the past (before today) const isPast = !isToday && date < new Date( today.getFullYear(), today.getMonth(), today.getDate() ); return ( handleDayPress(date)} > {date.getDate()} ); })} {/* Add padding blanks to keep constant height (6 rows) */} {paddingBlanks.map((_, index) => ( ))} ); } const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.4)", justifyContent: "flex-end", }, dismissArea: { flex: 1, }, sheet: { borderTopLeftRadius: 20, borderTopRightRadius: 20, paddingHorizontal: 16, paddingTop: 12, paddingBottom: 20, }, header: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 20, height: 44, }, titleText: { fontSize: 18, fontWeight: "600", }, headerRight: { flexDirection: "row", alignItems: "center", gap: 12, }, navBtn: { padding: 8, }, closeBtn: { padding: 8, }, weekRow: { flexDirection: "row", justifyContent: "space-around", marginBottom: 16, }, weekDayText: { color: "#8E8E93", width: 44, textAlign: "center", fontSize: 14, }, daysGrid: { flexDirection: "row", flexWrap: "wrap", paddingBottom: 20, }, dayCell: { width: "14.28%", aspectRatio: 1, justifyContent: "center", alignItems: "center", marginBottom: 4, }, dayText: { fontSize: 16, }, });