Commit d1739806 by tungnq

TODO: Đã hoàn thiện giao diện

parent a10f7f83
import React from 'react';
import {Text, View, StyleSheet} from 'react-native';
import React, {useState, useRef, useEffect} from 'react';
import {DeviceEventEmitter, PanResponder} from 'react-native';
import FilterDayView from './view';
const FilterDay = (props) => {
const FilterDay = ({navigation}) => {
const [currentDate, setCurrentDate] = useState(new Date());
const [selectedDate, setSelectedDate] = useState(new Date());
const [showMonthPicker, setShowMonthPicker] = useState(false);
const scrollViewRef = useRef(null);
useEffect(() => {
DeviceEventEmitter.emit('onDateChange', selectedDate);
}, [selectedDate]);
const createMockEvents = () => {
return [
{
id: '1',
title: 'Lịch vào trực lớp TTCĐT 445.T1',
subtitle: 'CS Địa lý 4D',
time: '07:00',
endTime: '09:00',
date: '2025-08-25',
type: 'class',
},
{
id: '2',
title: 'Meeting team development',
subtitle: 'Phòng họp A1',
time: '10:00',
endTime: '11:30',
date: '2025-07-24',
type: 'meeting',
},
{
id: '3',
title: 'Training React Native',
subtitle: 'Online Zoom',
time: '14:00',
endTime: '16:00',
date: '2025-07-25',
type: 'training',
},
];
};
const mockEvents = createMockEvents();
const formatDateToString = (date) => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
};
const getEventsForDate = (date) => {
const dateStr = formatDateToString(date);
return mockEvents.filter(event => event.date === dateStr);
};
const getDayName = (date) => {
const days = ['CN', 'Thứ 2', 'Thứ 3', 'Thứ 4', 'Thứ 5', 'Thứ 6', 'Thứ 7'];
return days[date.getDay()];
};
const getMonthName = (monthIndex) => {
const months = [
'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6',
'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12',
];
return months[monthIndex];
};
const handleMonthSelect = (monthIndex) => {
const newDate = new Date(currentDate);
newDate.setMonth(monthIndex);
setCurrentDate(newDate);
setSelectedDate(newDate);
setShowMonthPicker(false);
DeviceEventEmitter.emit('onDateChange', newDate);
};
const swipeToNextDay = () => {
const nextDay = new Date(selectedDate);
nextDay.setDate(selectedDate.getDate() + 1);
setSelectedDate(nextDay);
setCurrentDate(nextDay);
DeviceEventEmitter.emit('onDateChange', nextDay);
};
const swipeToPrevDay = () => {
const prevDay = new Date(selectedDate);
prevDay.setDate(selectedDate.getDate() - 1);
setSelectedDate(prevDay);
setCurrentDate(prevDay);
DeviceEventEmitter.emit('onDateChange', prevDay);
};
const toggleMonthPicker = () => {
setShowMonthPicker(!showMonthPicker);
};
const panResponder = PanResponder.create({
onMoveShouldSetPanResponder: (evt, gestureState) => {
return Math.abs(gestureState.dx) > 30 && Math.abs(gestureState.dy) < 100;
},
onPanResponderMove: (evt, gestureState) => {},
onPanResponderRelease: (evt, gestureState) => {
if (gestureState.dx > 50) {
swipeToPrevDay();
} else if (gestureState.dx < -50) {
swipeToNextDay();
}
},
});
const calculateEventPosition = (startTime, endTime) => {
const [startHour, startMinute] = startTime.split(':').map(Number);
const [endHour, endMinute] = endTime.split(':').map(Number);
const startTotalMinutes = startHour * 60 + startMinute;
const endTotalMinutes = endHour * 60 + endMinute;
const durationMinutes = endTotalMinutes - startTotalMinutes;
const HOUR_HEIGHT = 80;
const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT;
const height = (durationMinutes / 60) * HOUR_HEIGHT;
return { topPosition, height };
};
return (
<FilterDayView />
<FilterDayView
navigation={navigation}
currentDate={currentDate}
selectedDate={selectedDate}
showMonthPicker={showMonthPicker}
scrollViewRef={scrollViewRef}
panResponder={panResponder}
getEventsForDate={getEventsForDate}
getDayName={getDayName}
getMonthName={getMonthName}
handleMonthSelect={handleMonthSelect}
toggleMonthPicker={toggleMonthPicker}
calculateEventPosition={calculateEventPosition}
/>
);
};
......
import React from 'react';
import {Text, View, TouchableOpacity, StyleSheet} from 'react-native';
import {
View,
Text,
TouchableOpacity,
ScrollView,
StyleSheet,
Dimensions,
SafeAreaView,
} from 'react-native';
import R from '../../../assets/R';
const {width: screenWidth, height: screenHeight} = Dimensions.get('window');
const HOUR_HEIGHT = 80;
const FilterDayView = (props) => {
const { } = props;
const { navigation,
currentDate,
selectedDate,
showMonthPicker,
scrollViewRef,
panResponder,
getEventsForDate,
getDayName,
getMonthName,
handleMonthSelect,
toggleMonthPicker,
calculateEventPosition, } = props;
const isToday = (date) => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear()
);
};
const renderMonthPicker = () => {
if (!showMonthPicker) return null;
}
const renderDateInfo = () => {
return (
<View style={{backgroundColor: R.colors.grayBorderInputTextHeader}}>
<View style={styles.dateInfoContainer}>
<Text style={styles.dayName}>{getDayName(selectedDate)}</Text>
<Text style={
isToday(selectedDate)
? styles.dayNumberToday
: styles.dayNumber
}>{selectedDate.getDate()}</Text>
</View>
</View>
);
};
const renderTimeSlots = () => {
const hours = Array.from({length: 24}, (_, i) => i);
const selectedEvents = getEventsForDate(selectedDate);
return (
<View style={styles.timeSlotsContainer} {...panResponder.panHandlers}>
<ScrollView
ref={scrollViewRef}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}>
<View style={styles.timelineContainer}>
<View style={styles.timeLabelsColumn}>
{hours.map((hour) => {
const timeStr = hour.toString().padStart(2, '0') + ':00';
return (
<View key={hour} style={styles.timeSlot}>
<Text style={styles.timeText}>{timeStr}</Text>
</View>
);
})}
</View>
<View style={styles.eventsColumn}>
{hours.map((hour) => (
<View key={hour} style={styles.gridLine} />
))}
{selectedEvents.map((event) => {
const { topPosition, height } = calculateEventPosition(event.time, event.endTime);
return (
<TouchableOpacity
key={event.id}
style={[
styles.eventCard,
{
position: 'absolute',
top: topPosition,
height: Math.max(height, 40),
left: 5,
right: 15,
zIndex: 10,
backgroundColor: R.colors.blue,
}
]}
activeOpacity={0.7}>
<Text style={styles.eventTitle} numberOfLines={height > 60 ? 2 : 1}>
{event.title}
</Text>
{height > 40 && (
<Text style={styles.eventSubtitle} numberOfLines={1}>
{event.subtitle}
</Text>
)}
<Text style={styles.eventTime}>
{event.time} - {event.endTime}
</Text>
</TouchableOpacity>
);
})}
</View>
</View>
</ScrollView>
</View>
);
};
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<TouchableOpacity>
<Text>FilterDay</Text>
</TouchableOpacity>
</View>
<View style={styles.container}>
{renderMonthPicker()}
{renderDateInfo()}
{renderTimeSlots()}
</View>
);
};
export default FilterDayView;
const styles = StyleSheet.create({})
\ No newline at end of file
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: R.colors.white,
},
monthPickerContainer: {
backgroundColor: R.colors.white,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
paddingVertical: 10,
},
monthPickerContent: {
paddingHorizontal: 15,
},
monthItem: {
paddingHorizontal: 20,
paddingVertical: 8,
marginRight: 10,
borderRadius: 20,
backgroundColor: R.colors.gray,
},
dateInfoContainer: {
paddingHorizontal: 15,
paddingVertical: 12,
alignItems: 'center',
justifyContent:'center',
maxWidth:70,
borderRightWidth:1,
borderRightColor:R.colors.gray,
},
dayName: {
fontSize: R.sizes.xs,
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
marginBottom: 2,
},
dayNumber: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
timeSlotsContainer: {
flex: 1,
backgroundColor: R.colors.white,
},
scrollContent: {
paddingBottom: 50,
},
timelineContainer: {
flexDirection: 'row',
position: 'relative',
},
timeLabelsColumn: {
minWidth: 70,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
eventsColumn: {
flex: 1,
position: 'relative',
minHeight: 24 * HOUR_HEIGHT,
},
timeSlot: {
height: HOUR_HEIGHT,
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
},
gridLine: {
height: HOUR_HEIGHT,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
width: '100%',
},
timeText: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
eventCard: {
borderRadius: 15,
paddingLeft: 15,
paddingTop: 10,
},
eventTitle: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.white,
fontWeight: '400',
marginBottom: 5,
},
eventSubtitle: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.white,
marginBottom: 5,
},
dayNumberToday: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.white,
fontWeight: '400',
backgroundColor: R.colors.blue,
borderRadius: 15,
paddingHorizontal: 4,
paddingVertical: 3,
},
eventTime: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.white,
fontWeight: '400',
},
})
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment