calendi/app/components/ui/Calendar/CalendarView.js
2025-05-01 19:15:36 +02:00

216 lines
5.5 KiB
JavaScript

import React, { useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from 'react-native';
import { FontAwesome } from '@expo/vector-icons';
import Colors from '../../../constants';
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const months = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
const CalendarView = ({ onSelectDate, events = [] }) => {
const [currentMonth, setCurrentMonth] = useState(new Date());
const today = new Date();
const getDaysInMonth = (date) => {
const year = date.getFullYear();
const month = date.getMonth();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const firstDay = new Date(year, month, 1).getDay();
const days = [];
// Add empty days for the start of the month
for (let i = 0; i < firstDay; i++) {
days.push({ day: '', date: null });
}
// Add days of the month
for (let i = 1; i <= daysInMonth; i++) {
const date = new Date(year, month, i);
const hasEvent = events.some(event => {
const eventDate = new Date(event.startDate);
return eventDate.getDate() === i &&
eventDate.getMonth() === month &&
eventDate.getFullYear() === year;
});
const isToday = today.getDate() === i &&
today.getMonth() === month &&
today.getFullYear() === year;
days.push({
day: i,
date,
hasEvent,
isToday
});
}
return days;
};
const handlePrevMonth = () => {
const prevMonth = new Date(currentMonth);
prevMonth.setMonth(prevMonth.getMonth() - 1);
setCurrentMonth(prevMonth);
};
const handleNextMonth = () => {
const nextMonth = new Date(currentMonth);
nextMonth.setMonth(nextMonth.getMonth() + 1);
setCurrentMonth(nextMonth);
};
const calendarDays = getDaysInMonth(currentMonth);
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
onPress={handlePrevMonth}
style={styles.navButton}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<FontAwesome name="chevron-left" size={14} color={Colors.primary} />
</TouchableOpacity>
<Text style={styles.monthYear}>
{months[currentMonth.getMonth()]} {currentMonth.getFullYear()}
</Text>
<TouchableOpacity
onPress={handleNextMonth}
style={styles.navButton}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<FontAwesome name="chevron-right" size={14} color={Colors.primary} />
</TouchableOpacity>
</View>
<View style={styles.daysHeader}>
{days.map(day => (
<Text key={day} style={styles.dayHeader}>{day}</Text>
))}
</View>
<View style={styles.calendarGrid}>
{calendarDays.map((item, index) => (
<TouchableOpacity
key={index}
style={[
styles.day,
!item.date && styles.emptyDay,
item.isToday && styles.todayDay,
item.hasEvent && styles.eventDay
]}
onPress={() => item.date && onSelectDate(item.date)}
disabled={!item.date}
activeOpacity={item.date ? 0.7 : 1}
>
<Text style={[
styles.dayText,
item.isToday && styles.todayText
]}>
{item.day}
</Text>
{item.hasEvent && <View style={styles.eventDot} />}
</TouchableOpacity>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: Colors.card,
borderRadius: 10,
padding: 14,
margin: 16,
shadowColor: Colors.cardShadow,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 3,
borderWidth: 1,
borderColor: Colors.border,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
paddingHorizontal: 8,
},
navButton: {
width: 28,
height: 28,
borderRadius: 14,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Colors.background,
borderWidth: 1,
borderColor: Colors.border,
},
monthYear: {
fontSize: 16,
fontWeight: '600',
color: Colors.text,
},
daysHeader: {
flexDirection: 'row',
justifyContent: 'space-around',
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: Colors.divider,
paddingBottom: 8,
},
dayHeader: {
width: 36,
textAlign: 'center',
fontWeight: '600',
fontSize: 12,
color: Colors.secondary,
},
calendarGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
},
day: {
width: '14.28%',
height: 44,
justifyContent: 'center',
alignItems: 'center',
marginVertical: 2,
position: 'relative',
},
emptyDay: {
backgroundColor: 'transparent',
},
todayDay: {
backgroundColor: Colors.primary,
borderRadius: 22,
},
todayText: {
color: '#fff',
fontWeight: '600',
},
eventDay: {
position: 'relative',
},
dayText: {
textAlign: 'center',
fontSize: 14,
color: Colors.text,
},
eventDot: {
position: 'absolute',
bottom: 6,
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: Colors.accent,
},
});
export default CalendarView;