Yaltopia-Tickets-App/components/CalendarGrid.tsx

161 lines
4.9 KiB
TypeScript

import React, { useState } from "react";
import { View, Pressable, StyleSheet } from "react-native";
import { Text } from "@/components/ui/text";
import { ArrowLeft, ArrowRight, ChevronDown } from "@/lib/icons";
import { useColorScheme } from "nativewind";
const MONTHS = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const WEEKDAYS = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
interface CalendarGridProps {
onSelect: (v: string) => void;
selectedDate: string;
}
export function CalendarGrid({ onSelect, selectedDate }: CalendarGridProps) {
const { colorScheme } = useColorScheme();
const isDark = colorScheme === "dark";
const initialDate = selectedDate ? new Date(selectedDate) : new Date();
const [viewDate, setViewDate] = useState(
new Date(initialDate.getFullYear(), initialDate.getMonth(), 1),
);
const year = viewDate.getFullYear();
const month = viewDate.getMonth();
// Days in current month
const daysInMonth = new Date(year, month + 1, 0).getDate();
// Starting day of the week (0-6), where 0 is Sunday
let firstDayOfMonth = new Date(year, month, 1).getDay();
// Adjust for Monday start: Mon=0 ... Sun=6
firstDayOfMonth = firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1;
// Days in previous month to fill the start
const prevMonthLastDay = new Date(year, month, 0).getDate();
const changeMonth = (delta: number) => {
setViewDate(new Date(year, month + delta, 1));
};
const days = [];
// Fill previous month days (muted)
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
days.push({
date: new Date(year, month - 1, prevMonthLastDay - i),
currentMonth: false,
});
}
// Fill current month days
for (let i = 1; i <= daysInMonth; i++) {
days.push({
date: new Date(year, month, i),
currentMonth: true,
});
}
// Fill next month days (muted) to complete the grid (usually 42 cells for 6 weeks)
const remaining = 42 - days.length;
for (let i = 1; i <= remaining; i++) {
days.push({
date: new Date(year, month + 1, i),
currentMonth: false,
});
}
return (
<View className="bg-card px-2 pb-6">
<View className="flex-row justify-between items-center mb-10 mt-2">
<Pressable
onPress={() => changeMonth(-1)}
className="h-12 w-12 bg-white rounded-[12px] items-center justify-center border border-border"
style={isDark ? { backgroundColor: "#1e1e1e" } : undefined}
>
<ArrowLeft size={18} color="#64748b" strokeWidth={2} />
</Pressable>
<View className="flex-row items-center gap-2">
<Text className="text-foreground text-base font-medium tracking-tight">
{MONTHS[month]} {year}
</Text>
</View>
<Pressable
onPress={() => changeMonth(1)}
className="h-12 w-12 bg-white rounded-[12px] items-center justify-center border border-border"
style={isDark ? { backgroundColor: "#1e1e1e" } : undefined}
>
<ArrowRight size={18} color="#64748b" strokeWidth={2} />
</Pressable>
</View>
{/* WeekDays Header: Mo Tu We Th Fr Sa Su */}
<View className="flex-row mb-6">
{WEEKDAYS.map((day, idx) => (
<View key={idx} className="w-[14.28%] items-center">
<Text className="text-[13px] font-semibold text-slate-400 opacity-80">
{day}
</Text>
</View>
))}
</View>
{/* Grid */}
<View className="flex-row flex-wrap">
{days.map((item, i) => {
const d = item.date;
const iso = d.toISOString().split("T")[0];
const isSelected = iso === selectedDate && item.currentMonth;
const isToday = iso === new Date().toISOString().split("T")[0];
return (
<View
key={i}
className="w-[14.28%] aspect-square items-center justify-center mb-1"
>
<Pressable
onPress={() => onSelect(iso)}
className={`w-11 h-11 items-center justify-center rounded-full ${
isSelected ? "bg-primary" : ""
}`}
>
<Text
className={`text-[15px] ${
isSelected
? "text-white font-bold"
: item.currentMonth
? "text-foreground font-medium"
: "text-slate-300 font-medium"
} ${isToday && !isSelected ? "text-primary" : ""}`}
>
{d.getDate()}
</Text>
{isToday && !isSelected && (
<View className="absolute bottom-1 w-2 h-2 bg-primary rounded-full" />
)}
</Pressable>
</View>
);
})}
</View>
</View>
);
}