Commit df7585d6 by tungnq

TODO: Thêm workaround cho lỗi DeviceEventEmitter.removeListener và đồng bộ tháng ở header Drawer

parent 5cfc51c6
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
*/ */
import React, {useEffect} from 'react'; import React, {useEffect} from 'react';
import {View, Text} from 'react-native'; import {View, Text, DeviceEventEmitter} from 'react-native';
import {Provider} from 'react-redux'; import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux'; import {createStore, applyMiddleware} from 'redux';
import rootReducer from './src/reducers/index'; import rootReducer from './src/reducers/index';
...@@ -16,6 +16,17 @@ import createSagaMiddleware from 'redux-saga'; ...@@ -16,6 +16,17 @@ import createSagaMiddleware from 'redux-saga';
import rootSaga from './src/saga/rootSaga'; import rootSaga from './src/saga/rootSaga';
// import FirebaseNotification from "./src/helper/FirebaseNotification"; // import FirebaseNotification from "./src/helper/FirebaseNotification";
import SplashScreen from 'react-native-splash-screen'; import SplashScreen from 'react-native-splash-screen';
// Workaround for react-native-modal removeListener issue
if (!DeviceEventEmitter.removeListener) {
DeviceEventEmitter.removeListener = function(eventType, listener) {
// Use the new API
const subscription = this.addListener(eventType, () => {});
if (subscription && subscription.remove) {
subscription.remove();
}
};
}
const sagaMiddleware = createSagaMiddleware(); const sagaMiddleware = createSagaMiddleware();
let store = createStore(rootReducer, applyMiddleware(sagaMiddleware)); let store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
......
...@@ -49,11 +49,21 @@ const DrawerNavigatorView = (props) => { ...@@ -49,11 +49,21 @@ const DrawerNavigatorView = (props) => {
} }
); );
const updateHeaderMonthListener = DeviceEventEmitter.addListener(
"updateHeaderMonth",
(monthIndex) => {
const newDate = new Date(currentDate);
newDate.setMonth(monthIndex);
setCurrentDate(newDate);
}
);
return () => { return () => {
setLanguageListener.remove(); setLanguageListener.remove();
dateChangeListener.remove(); dateChangeListener.remove();
updateHeaderMonthListener.remove();
}; };
}, []); }, [currentDate]);
const MenuButton = ({ onPress }) => ( const MenuButton = ({ onPress }) => (
<TouchableOpacity style={styles.menuButton} onPress={onPress}> <TouchableOpacity style={styles.menuButton} onPress={onPress}>
......
import React, {useState, useRef, useEffect} from 'react'; import React, {useState, useRef, useEffect} from 'react';
import {DeviceEventEmitter, PanResponder} from 'react-native'; import {Dimensions, PanResponder} from 'react-native';
import {useNavigation, useFocusEffect} from '@react-navigation/native';
import {DeviceEventEmitter} from 'react-native';
import Filter3DayView from './view'; import Filter3DayView from './view';
// ==================== HẰNG SỐ ====================
const {width: screenWidth, height: screenHeight} = Dimensions.get('window');
const HOUR_HEIGHT = 80;
const DAY_COLUMN_WIDTH = (screenWidth - 70) / 3;
const Filter3Day = ({navigation}) => { const Filter3Day = ({navigation}) => {
const navigationHook = useNavigation();
// ==================== QUẢN LÝ STATE ====================
const [currentDate, setCurrentDate] = useState(new Date()); const [currentDate, setCurrentDate] = useState(new Date());
const [selectedDate, setSelectedDate] = useState(new Date()); const [selectedDate, setSelectedDate] = useState(new Date());
const [showMonthPicker, setShowMonthPicker] = useState(false); const [showMonthPicker, setShowMonthPicker] = useState(false);
const scrollViewRef = useRef(null); const scrollViewRef = useRef(null);
// ==================== EFFECTS ====================
// Reset về ngày hiện tại khi chuyển màn hình
useFocusEffect(
React.useCallback(() => {
const today = new Date();
setCurrentDate(today);
setSelectedDate(today);
DeviceEventEmitter.emit('onDateChange', today);
// Cập nhật header drawer với tháng hiện tại
DeviceEventEmitter.emit('updateHeaderMonth', today.getMonth());
}, [])
);
useEffect(() => { useEffect(() => {
DeviceEventEmitter.emit('onDateChange', selectedDate); DeviceEventEmitter.emit('onDateChange', selectedDate);
}, [selectedDate]); }, [selectedDate]);
useEffect(() => { // ==================== HÀM TIỆN ÍCH ====================
DeviceEventEmitter.emit('onDateChange', currentDate); // T1: Định dạng ngày thành chuỗi
}, [currentDate]);
const createMockEvents = () => {
return [
{
id: '1',
title: 'Lịch vào trực lớp TTCĐT 445.T1',
subtitle: 'CS lớp 4D',
time: '07:00',
endTime: '09:00',
date: '2025-07-24',
type: 'class',
},
{
id: '2',
title: 'Meeting team development',
subtitle: 'Phòng họp A1',
time: '10:00',
endTime: '11:30',
date: '2025-07-25',
type: 'meeting',
},
{
id: '3',
title: 'Training React Native',
subtitle: 'Online Zoom',
time: '14:00',
endTime: '16:00',
date: '2025-07-26',
type: 'training',
},
{
id: '4',
title: 'Code Review Session',
subtitle: 'Dev Team',
time: '09:30',
endTime: '11:30',
date: '2025-08-25',
type: 'review',
},
];
};
const mockEvents = createMockEvents();
const formatDateToString = date => { const formatDateToString = date => {
const year = date.getFullYear(); const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0'); const month = (date.getMonth() + 1).toString().padStart(2, '0');
...@@ -66,24 +44,23 @@ const Filter3Day = ({navigation}) => { ...@@ -66,24 +44,23 @@ const Filter3Day = ({navigation}) => {
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
}; };
const getEventsForDate = date => { // T2: Kiểm tra ngày hôm nay
const dateStr = formatDateToString(date); const isToday = someDate => {
return mockEvents.filter(event => event.date === dateStr); const today = new Date();
return (
someDate.getDate() === today.getDate() &&
someDate.getMonth() === today.getMonth() &&
someDate.getFullYear() === today.getFullYear()
);
}; };
// T3: Lấy tên ngày trong tuần
const getDayName = date => { const getDayName = date => {
const days = [ const days = ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'];
'Chủ nhật',
'Thứ 2',
'Thứ 3',
'Thứ 4',
'Thứ 5',
'Thứ 6',
'Thứ 7',
];
return days[date.getDay()]; return days[date.getDay()];
}; };
// T4: Lấy tên tháng
const getMonthName = monthIndex => { const getMonthName = monthIndex => {
const months = [ const months = [
'Tháng 1', 'Tháng 1',
...@@ -102,54 +79,100 @@ const Filter3Day = ({navigation}) => { ...@@ -102,54 +79,100 @@ const Filter3Day = ({navigation}) => {
return months[monthIndex]; return months[monthIndex];
}; };
// T5: Lấy 3 ngày liên tiếp
const get3DaysDates = date => { const get3DaysDates = date => {
const dates = []; const threeDayDates = [];
for (let i = 0; i < 3; i++) { for (let i = -1; i <= 1; i++) {
const dayDate = new Date(date); const dayDate = new Date(date);
dayDate.setDate(date.getDate() + i); dayDate.setDate(date.getDate() + i);
dates.push(dayDate); threeDayDates.push(dayDate);
} }
return dates; return threeDayDates;
}; };
const isToday = date => { // T6: Tính toán vị trí sự kiện
const today = new Date(); const calculateEventPosition = (startTime, endTime) => {
return ( const [startHour, startMinute] = startTime.split(':').map(Number);
date.getDate() === today.getDate() && const [endHour, endMinute] = endTime.split(':').map(Number);
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear()
);
};
const handleMonthSelect = monthIndex => { const startTotalMinutes = startHour * 60 + startMinute;
const newDate = new Date(currentDate); const endTotalMinutes = endHour * 60 + endMinute;
newDate.setMonth(monthIndex); const durationMinutes = endTotalMinutes - startTotalMinutes;
setCurrentDate(newDate);
setSelectedDate(newDate); const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT;
setShowMonthPicker(false); const height = (durationMinutes / 60) * HOUR_HEIGHT;
DeviceEventEmitter.emit('onDateChange', newDate);
};
const swipeToNext3Days = () => { return {topPosition, height};
const nextDate = new Date(currentDate);
nextDate.setDate(currentDate.getDate() + 3);
setCurrentDate(nextDate);
setSelectedDate(nextDate);
DeviceEventEmitter.emit('onDateChange', nextDate);
}; };
const swipeToPrev3Days = () => { // ==================== QUẢN LÝ DỮ LIỆU ====================
const prevDate = new Date(currentDate); // D1: Tạo dữ liệu sự kiện mẫu
prevDate.setDate(currentDate.getDate() - 3); const createMockEvents = () => {
setCurrentDate(prevDate); const today = new Date();
setSelectedDate(prevDate); const todayStr = formatDateToString(today);
DeviceEventEmitter.emit('onDateChange', prevDate);
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const tomorrowStr = formatDateToString(tomorrow);
const yesterday = new Date(today);
yesterday.setDate(today.getDate() - 1);
const yesterdayStr = formatDateToString(yesterday);
return [
// Sự kiện hôm qua
{
id: '1',
title: 'Họp nội bộ khoa',
subtitle: 'Phòng họp A1',
time: '09:00',
endTime: '11:00',
date: yesterdayStr,
type: 'meeting',
},
// Sự kiện hôm nay
{
id: '2',
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: todayStr,
type: 'class',
},
{
id: '3',
title: 'Training React Native',
subtitle: 'Online Zoom',
time: '14:00',
endTime: '16:00',
date: todayStr,
type: 'training',
},
// Sự kiện ngày mai
{
id: '4',
title: 'Workshop AI trong giáo dục',
subtitle: 'Hội trường lớn',
time: '13:00',
endTime: '17:00',
date: tomorrowStr,
type: 'workshop',
},
];
}; };
const toggleMonthPicker = () => { // D2: Xử lý dữ liệu sự kiện
setShowMonthPicker(!showMonthPicker); const mockEvents = createMockEvents();
// D3: Hàm truy vấn sự kiện
const getEventsForDate = date => {
const dateStr = formatDateToString(date);
return mockEvents.filter(event => event.date === dateStr);
}; };
// ==================== HỆ THỐNG ANIMATION ====================
// A1: Thiết lập PanResponder
const panResponder = PanResponder.create({ const panResponder = PanResponder.create({
onMoveShouldSetPanResponder: (evt, gestureState) => { onMoveShouldSetPanResponder: (evt, gestureState) => {
return Math.abs(gestureState.dx) > 30 && Math.abs(gestureState.dy) < 100; return Math.abs(gestureState.dx) > 30 && Math.abs(gestureState.dy) < 100;
...@@ -157,26 +180,50 @@ const Filter3Day = ({navigation}) => { ...@@ -157,26 +180,50 @@ const Filter3Day = ({navigation}) => {
onPanResponderMove: (evt, gestureState) => {}, onPanResponderMove: (evt, gestureState) => {},
onPanResponderRelease: (evt, gestureState) => { onPanResponderRelease: (evt, gestureState) => {
if (gestureState.dx > 50) { if (gestureState.dx > 50) {
swipeToPrev3Days(); swipeToPrevThreeDay();
} else if (gestureState.dx < -50) { } else if (gestureState.dx < -50) {
swipeToNext3Days(); swipeToNextThreeDay();
} }
}, },
}); });
const calculateEventPosition = (startTime, endTime) => { // ==================== XỬ LÝ SỰ KIỆN ====================
const [startHour, startMinute] = startTime.split(':').map(Number); // X1: Xử lý chọn tháng
const [endHour, endMinute] = endTime.split(':').map(Number); const handleMonthSelect = monthIndex => {
const newDate = new Date(currentDate);
newDate.setMonth(monthIndex);
setCurrentDate(newDate);
setSelectedDate(newDate);
setShowMonthPicker(false);
DeviceEventEmitter.emit('onDateChange', newDate);
// Cập nhật header drawer với tháng mới
DeviceEventEmitter.emit('updateHeaderMonth', monthIndex);
};
const startTotalMinutes = startHour * 60 + startMinute; // X2: Xử lý chuyển 3 ngày
const endTotalMinutes = endHour * 60 + endMinute; const swipeToNextThreeDay = () => {
const durationMinutes = endTotalMinutes - startTotalMinutes; const nextThreeDay = new Date(currentDate);
nextThreeDay.setDate(currentDate.getDate() + 3);
setCurrentDate(nextThreeDay);
setSelectedDate(nextThreeDay);
DeviceEventEmitter.emit('onDateChange', nextThreeDay);
// Cập nhật header drawer nếu tháng thay đổi
DeviceEventEmitter.emit('updateHeaderMonth', nextThreeDay.getMonth());
};
const HOUR_HEIGHT = 80; const swipeToPrevThreeDay = () => {
const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT; const prevThreeDay = new Date(currentDate);
const height = (durationMinutes / 60) * HOUR_HEIGHT; prevThreeDay.setDate(currentDate.getDate() - 3);
setCurrentDate(prevThreeDay);
setSelectedDate(prevThreeDay);
DeviceEventEmitter.emit('onDateChange', prevThreeDay);
// Cập nhật header drawer nếu tháng thay đổi
DeviceEventEmitter.emit('updateHeaderMonth', prevThreeDay.getMonth());
};
return {topPosition, height}; // X3: Xử lý toggle month picker
const toggleMonthPicker = () => {
setShowMonthPicker(!showMonthPicker);
}; };
return ( return (
...@@ -187,14 +234,16 @@ const Filter3Day = ({navigation}) => { ...@@ -187,14 +234,16 @@ const Filter3Day = ({navigation}) => {
showMonthPicker={showMonthPicker} showMonthPicker={showMonthPicker}
scrollViewRef={scrollViewRef} scrollViewRef={scrollViewRef}
panResponder={panResponder} panResponder={panResponder}
getEventsForDate={getEventsForDate} isToday={isToday}
getDayName={getDayName} getDayName={getDayName}
getMonthName={getMonthName} getMonthName={getMonthName}
get3DaysDates={get3DaysDates} get3DaysDates={get3DaysDates}
isToday={isToday} getEventsForDate={getEventsForDate}
calculateEventPosition={calculateEventPosition}
handleMonthSelect={handleMonthSelect} handleMonthSelect={handleMonthSelect}
toggleMonthPicker={toggleMonthPicker} toggleMonthPicker={toggleMonthPicker}
calculateEventPosition={calculateEventPosition} HOUR_HEIGHT={HOUR_HEIGHT}
DAY_COLUMN_WIDTH={DAY_COLUMN_WIDTH}
/> />
); );
}; };
......
import {StyleSheet, Dimensions} from 'react-native'; import {StyleSheet, Dimensions} from 'react-native';
import R from '../../../assets/R'; import R from '../../../assets/R';
// ==================== HẰNG SỐ ====================
const {width: screenWidth, height: screenHeight} = Dimensions.get('window'); const {width: screenWidth, height: screenHeight} = Dimensions.get('window');
const HOUR_HEIGHT = 80; const HOUR_HEIGHT = 80;
const DAY_COLUMN_WIDTH = (screenWidth - 70) / 3; const DAY_COLUMN_WIDTH = (screenWidth - 70) / 3;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
// ==================== CONTAINER CHÍNH ====================
// Container tổng thể của màn hình Filter 3 ngày
container: { container: {
flex: 1, flex: 1,
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
}, },
// ==================== MONTH PICKER SECTION ====================
// Container chứa bộ chọn tháng
monthPickerContainer: { monthPickerContainer: {
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: R.colors.gray, borderBottomColor: R.colors.gray,
paddingVertical: 10, paddingVertical: 10,
}, },
// Nội dung cuộn ngang của bộ chọn tháng
monthPickerContent: { monthPickerContent: {
paddingHorizontal: 15, paddingHorizontal: 15,
}, },
// Item tháng trong bộ chọn
monthItem: { monthItem: {
paddingHorizontal: 20, paddingHorizontal: 20,
paddingVertical: 10, paddingVertical: 10,
...@@ -26,27 +36,40 @@ const styles = StyleSheet.create({ ...@@ -26,27 +36,40 @@ const styles = StyleSheet.create({
borderRadius: 20, borderRadius: 20,
backgroundColor: R.colors.gray, backgroundColor: R.colors.gray,
}, },
// Item tháng được chọn
monthItemSelected: { monthItemSelected: {
backgroundColor: R.colors.black, backgroundColor: R.colors.black,
}, },
// Text của item tháng
monthItemText: { monthItemText: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
color: R.colors.black, color: R.colors.black,
}, },
// Text của item tháng được chọn
monthItemTextSelected: { monthItemTextSelected: {
color: R.colors.white, color: R.colors.white,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
}, },
// ==================== 3 DAYS HEADER SECTION ====================
// Container chứa header 3 ngày
daysHeaderContainer: { daysHeaderContainer: {
flexDirection: 'row', flexDirection: 'row',
backgroundColor: R.colors.grayBorderInputTextHeader, backgroundColor: R.colors.grayBorderInputTextHeader,
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: R.colors.gray2, borderBottomColor: R.colors.gray2,
}, },
// Header cột thời gian (trống)
timeColumnHeader: { timeColumnHeader: {
width: 70, width: 70,
}, },
// Cell header của mỗi ngày
dayHeaderCell: { dayHeaderCell: {
width: DAY_COLUMN_WIDTH, width: DAY_COLUMN_WIDTH,
alignItems: 'center', alignItems: 'center',
...@@ -54,17 +77,23 @@ const styles = StyleSheet.create({ ...@@ -54,17 +77,23 @@ const styles = StyleSheet.create({
borderRightWidth: 1, borderRightWidth: 1,
borderRightColor: R.colors.gray2, borderRightColor: R.colors.gray2,
}, },
// Text tên ngày (Thứ 2, Thứ 3...)
dayHeaderText: { dayHeaderText: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
color: R.colors.black, color: R.colors.black,
fontWeight: '600', fontWeight: '600',
}, },
// Text tên ngày hôm nay
todayHeaderText: { todayHeaderText: {
color: R.colors.black, color: R.colors.black,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
fontWeight: '600', fontWeight: '600',
}, },
// Container chứa số ngày
dayNumberContainer: { dayNumberContainer: {
minWidth: 28, minWidth: 28,
minHeight: 28, minHeight: 28,
...@@ -73,43 +102,64 @@ const styles = StyleSheet.create({ ...@@ -73,43 +102,64 @@ const styles = StyleSheet.create({
justifyContent: 'center', justifyContent: 'center',
marginVertical: 5, marginVertical: 5,
}, },
// Container số ngày hôm nay (có background xanh)
todayNumberContainer: { todayNumberContainer: {
backgroundColor: R.colors.blue, backgroundColor: R.colors.blue,
}, },
// Text số ngày
dayHeaderNumber: { dayHeaderNumber: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
color: R.colors.black, color: R.colors.black,
fontWeight: '400', fontWeight: '400',
}, },
// Text số ngày hôm nay (màu trắng)
todayHeaderNumber: { todayHeaderNumber: {
color: R.colors.white, color: R.colors.white,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
}, },
// ==================== TIME SLOTS SECTION ====================
// Container chứa các khung thời gian
timeSlotsContainer: { timeSlotsContainer: {
flex: 1, flex: 1,
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
}, },
// Nội dung cuộn dọc
scrollContent: {}, scrollContent: {},
// Container timeline tổng thể
timelineContainer: { timelineContainer: {
flexDirection: 'row', flexDirection: 'row',
position: 'relative', position: 'relative',
}, },
// Cột nhãn thời gian bên trái
timeLabelsColumn: { timeLabelsColumn: {
width: 70, width: 70,
borderRightWidth: 1, borderRightWidth: 1,
borderRightColor: R.colors.gray2, borderRightColor: R.colors.gray2,
}, },
// Container chứa grid 3 ngày
daysGridContainer: { daysGridContainer: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
}, },
// Cột của mỗi ngày
dayColumn: { dayColumn: {
width: DAY_COLUMN_WIDTH, width: DAY_COLUMN_WIDTH,
position: 'relative', position: 'relative',
borderRightWidth: 1, borderRightWidth: 1,
borderRightColor: R.colors.gray2, borderRightColor: R.colors.gray2,
}, },
// Khung thời gian (1 giờ)
timeSlot: { timeSlot: {
height: HOUR_HEIGHT, height: HOUR_HEIGHT,
alignItems: 'center', alignItems: 'center',
...@@ -117,35 +167,48 @@ const styles = StyleSheet.create({ ...@@ -117,35 +167,48 @@ const styles = StyleSheet.create({
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: R.colors.gray2, borderBottomColor: R.colors.gray2,
}, },
// Cell grid của mỗi giờ trong ngày
gridCell: { gridCell: {
height: HOUR_HEIGHT, height: HOUR_HEIGHT,
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: R.colors.gray2, borderBottomColor: R.colors.gray2,
width: '100%', width: '100%',
}, },
// Text hiển thị giờ (07:00, 08:00...)
timeText: { timeText: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
color: R.colors.black, color: R.colors.black,
fontWeight: '400', fontWeight: '400',
}, },
// ==================== EVENT CARD SECTION ====================
// Card hiển thị sự kiện
eventCard: { eventCard: {
borderRadius: 8, borderRadius: 8,
paddingHorizontal: 6, paddingHorizontal: 6,
paddingVertical: 4, paddingVertical: 4,
}, },
// Tiêu đề sự kiện
eventTitle: { eventTitle: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
color: R.colors.white, color: R.colors.white,
marginBottom: 2, marginBottom: 2,
}, },
// Phụ đề sự kiện
eventSubtitle: { eventSubtitle: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
color: R.colors.white, color: R.colors.white,
fontWeight: '400', fontWeight: '400',
}, },
// Thời gian sự kiện
eventTime: { eventTime: {
fontSize: R.fontsize.fontSizeLabel, fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
......
import React, {useState, useRef, useEffect} from 'react'; import React, {useState, useRef, useEffect} from 'react';
import {Dimensions, DeviceEventEmitter, PanResponder} from 'react-native'; import {Dimensions, PanResponder} from 'react-native';
import {useNavigation, useFocusEffect} from '@react-navigation/native';
import {DeviceEventEmitter} from 'react-native';
import FilterWeekView from './view'; import FilterWeekView from './view';
// ==================== HẰNG SỐ ==================== // ==================== HẰNG SỐ ====================
...@@ -8,6 +10,8 @@ const HOUR_HEIGHT = 80; ...@@ -8,6 +10,8 @@ const HOUR_HEIGHT = 80;
const DAY_COLUMN_WIDTH = (screenWidth - 70) / 7; const DAY_COLUMN_WIDTH = (screenWidth - 70) / 7;
const FilterWeek = ({navigation}) => { const FilterWeek = ({navigation}) => {
const navigationHook = useNavigation();
// ==================== QUẢN LÝ STATE ==================== // ==================== QUẢN LÝ STATE ====================
// B1: State ngày tháng và lịch // B1: State ngày tháng và lịch
const [currentDate, setCurrentDate] = useState(new Date()); const [currentDate, setCurrentDate] = useState(new Date());
...@@ -20,6 +24,18 @@ const FilterWeek = ({navigation}) => { ...@@ -20,6 +24,18 @@ const FilterWeek = ({navigation}) => {
const scrollViewRef = useRef(null); const scrollViewRef = useRef(null);
// ==================== EFFECTS ==================== // ==================== EFFECTS ====================
// Reset về ngày hiện tại khi chuyển màn hình
useFocusEffect(
React.useCallback(() => {
const today = new Date();
setCurrentDate(today);
setSelectedDate(today);
DeviceEventEmitter.emit('onDateChange', today);
// Cập nhật header drawer với tháng hiện tại
DeviceEventEmitter.emit('updateHeaderMonth', today.getMonth());
}, [])
);
useEffect(() => { useEffect(() => {
DeviceEventEmitter.emit('onDateChange', selectedDate); DeviceEventEmitter.emit('onDateChange', selectedDate);
}, [selectedDate]); }, [selectedDate]);
...@@ -107,7 +123,7 @@ const FilterWeek = ({navigation}) => { ...@@ -107,7 +123,7 @@ const FilterWeek = ({navigation}) => {
subtitle: 'CS Địa lý 4D', subtitle: 'CS Địa lý 4D',
time: '07:00', time: '07:00',
endTime: '09:00', endTime: '09:00',
date: '2025-08-26', date: '2025-01-08',
type: 'class', type: 'class',
}, },
{ {
...@@ -116,7 +132,7 @@ const FilterWeek = ({navigation}) => { ...@@ -116,7 +132,7 @@ const FilterWeek = ({navigation}) => {
subtitle: 'Phòng họp A1', subtitle: 'Phòng họp A1',
time: '10:00', time: '10:00',
endTime: '11:30', endTime: '11:30',
date: '2025-07-22', date: '2025-01-09',
type: 'meeting', type: 'meeting',
}, },
{ {
...@@ -125,34 +141,7 @@ const FilterWeek = ({navigation}) => { ...@@ -125,34 +141,7 @@ const FilterWeek = ({navigation}) => {
subtitle: 'Online Zoom', subtitle: 'Online Zoom',
time: '14:00', time: '14:00',
endTime: '16:00', endTime: '16:00',
date: '2025-07-23', date: '2025-01-10',
type: 'training',
},
{
id: '4',
title: 'Code Review Session',
subtitle: 'Dev Team',
time: '09:00',
endTime: '10:30',
date: '2025-07-24',
type: 'review',
},
{
id: '5',
title: 'Sprint Planning',
subtitle: 'Scrum Team',
time: '15:00',
endTime: '17:00',
date: '2025-07-25',
type: 'meeting',
},
{
id: '6',
title: 'Tech Talk',
subtitle: 'Conference Room',
time: '11:00',
endTime: '12:00',
date: '2025-07-26',
type: 'training', type: 'training',
}, },
]; ];
...@@ -192,6 +181,8 @@ const FilterWeek = ({navigation}) => { ...@@ -192,6 +181,8 @@ const FilterWeek = ({navigation}) => {
setSelectedDate(newDate); setSelectedDate(newDate);
setShowMonthPicker(false); setShowMonthPicker(false);
DeviceEventEmitter.emit('onDateChange', newDate); DeviceEventEmitter.emit('onDateChange', newDate);
// Cập nhật header drawer với tháng mới
DeviceEventEmitter.emit('updateHeaderMonth', monthIndex);
}; };
// X2: Xử lý chuyển tuần // X2: Xử lý chuyển tuần
...@@ -201,6 +192,8 @@ const FilterWeek = ({navigation}) => { ...@@ -201,6 +192,8 @@ const FilterWeek = ({navigation}) => {
setCurrentDate(nextWeek); setCurrentDate(nextWeek);
setSelectedDate(nextWeek); setSelectedDate(nextWeek);
DeviceEventEmitter.emit('onDateChange', nextWeek); DeviceEventEmitter.emit('onDateChange', nextWeek);
// Cập nhật header drawer nếu tháng thay đổi
DeviceEventEmitter.emit('updateHeaderMonth', nextWeek.getMonth());
}; };
const swipeToPrevWeek = () => { const swipeToPrevWeek = () => {
...@@ -209,6 +202,8 @@ const FilterWeek = ({navigation}) => { ...@@ -209,6 +202,8 @@ const FilterWeek = ({navigation}) => {
setCurrentDate(prevWeek); setCurrentDate(prevWeek);
setSelectedDate(prevWeek); setSelectedDate(prevWeek);
DeviceEventEmitter.emit('onDateChange', prevWeek); DeviceEventEmitter.emit('onDateChange', prevWeek);
// Cập nhật header drawer nếu tháng thay đổi
DeviceEventEmitter.emit('updateHeaderMonth', prevWeek.getMonth());
}; };
// X3: Xử lý toggle month picker // X3: Xử lý toggle month picker
......
...@@ -5,10 +5,24 @@ const {width} = Dimensions.get('window'); ...@@ -5,10 +5,24 @@ const {width} = Dimensions.get('window');
const DAY_COLUMN_WIDTH = (width - 70) / 7; const DAY_COLUMN_WIDTH = (width - 70) / 7;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
// ==================== CONTAINER CHÍNH ====================
// Tương ứng với View chính trong FilterWeekView (dòng 166)
container: { container: {
flex: 1, flex: 1,
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
}, },
// ==================== MONTH PICKER ====================
// Tương ứng với renderMonthPicker() (dòng 19-49)
monthPickerContainer: {
backgroundColor: R.colors.white,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
paddingVertical: 10,
},
monthPickerContent: {
paddingHorizontal: 15,
},
monthItem: { monthItem: {
paddingHorizontal: 20, paddingHorizontal: 20,
paddingVertical: 8, paddingVertical: 8,
...@@ -28,6 +42,9 @@ const styles = StyleSheet.create({ ...@@ -28,6 +42,9 @@ const styles = StyleSheet.create({
color: R.colors.white, color: R.colors.white,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
}, },
// ==================== WEEK HEADER ====================
// Tương ứng với renderWeekHeader() (dòng 51-87)
weekHeaderContainer: { weekHeaderContainer: {
flexDirection: 'row', flexDirection: 'row',
backgroundColor: R.colors.grayBorderInputTextHeader, backgroundColor: R.colors.grayBorderInputTextHeader,
...@@ -57,7 +74,6 @@ const styles = StyleSheet.create({ ...@@ -57,7 +74,6 @@ const styles = StyleSheet.create({
color: R.colors.black, color: R.colors.black,
fontWeight: '600', fontWeight: '600',
}, },
dayHeaderNumberContainerToday: { dayHeaderNumberContainerToday: {
borderRadius: 15, borderRadius: 15,
justifyContent: 'center', justifyContent: 'center',
...@@ -71,8 +87,15 @@ const styles = StyleSheet.create({ ...@@ -71,8 +87,15 @@ const styles = StyleSheet.create({
backgroundColor: R.colors.blue, backgroundColor: R.colors.blue,
borderRadius: 15, borderRadius: 15,
paddingHorizontal: 8, paddingHorizontal: 8,
paddingVertical: 2, paddingVertical: 4,
},
dayHeaderTextToday: {
color: R.colors.blue,
fontWeight: '700',
}, },
// ==================== TIME SLOTS CONTAINER ====================
// Tương ứng với renderTimeSlots() (dòng 89-163)
timeSlotsContainer: { timeSlotsContainer: {
flex: 1, flex: 1,
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
...@@ -84,11 +107,30 @@ const styles = StyleSheet.create({ ...@@ -84,11 +107,30 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
position: 'relative', position: 'relative',
}, },
// ==================== TIME LABELS COLUMN ====================
// Tương ứng với timeLabelsColumn (dòng 100-109)
timeLabelsColumn: { timeLabelsColumn: {
width: 70, width: 70,
borderRightWidth: 1, borderRightWidth: 1,
borderRightColor: R.colors.gray, borderRightColor: R.colors.gray,
}, },
timeSlot: {
height: 80,
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
},
timeText: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
// ==================== WEEK GRID CONTAINER ====================
// Tương ứng với weekGridContainer (dòng 111-158)
weekGridContainer: { weekGridContainer: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
...@@ -99,34 +141,15 @@ const styles = StyleSheet.create({ ...@@ -99,34 +141,15 @@ const styles = StyleSheet.create({
borderRightWidth: 1, borderRightWidth: 1,
borderRightColor: R.colors.gray, borderRightColor: R.colors.gray,
}, },
timeSlot: {
height: 80,
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
},
gridCell: { gridCell: {
height: 80, height: 80,
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: R.colors.gray, borderBottomColor: R.colors.gray,
width: '100%', width: '100%',
}, },
monthPickerContainer: {
backgroundColor: R.colors.white, // ==================== EVENT CARDS ====================
borderBottomWidth: 1, // Tương ứng với event rendering (dòng 118-155)
borderBottomColor: R.colors.gray,
paddingVertical: 10,
},
monthPickerContent: {
paddingHorizontal: 15,
},
timeText: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
eventCard: { eventCard: {
borderRadius: 10, borderRadius: 10,
paddingHorizontal: 4, paddingHorizontal: 4,
......
import React, {useState, useRef, useEffect} from 'react'; import React, {useState, useRef, useEffect} from 'react';
import {useNavigation, useFocusEffect} from '@react-navigation/native';
import {DeviceEventEmitter, PanResponder} from 'react-native'; import {DeviceEventEmitter, PanResponder} from 'react-native';
import FilterDayView from './view'; import FilterDayView from './view';
...@@ -12,15 +13,45 @@ const FilterDay = ({navigation}) => { ...@@ -12,15 +13,45 @@ const FilterDay = ({navigation}) => {
DeviceEventEmitter.emit('onDateChange', selectedDate); DeviceEventEmitter.emit('onDateChange', selectedDate);
}, [selectedDate]); }, [selectedDate]);
// Reset về ngày hiện tại khi chuyển màn hình
useFocusEffect(
React.useCallback(() => {
const today = new Date();
setCurrentDate(today);
setSelectedDate(today);
DeviceEventEmitter.emit('onDateChange', today);
// Cập nhật header drawer với tháng hiện tại
DeviceEventEmitter.emit('updateHeaderMonth', today.getMonth());
}, [])
);
const createMockEvents = () => { const createMockEvents = () => {
const today = new Date();
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 todayStr = formatDateToString(today);
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const tomorrowStr = formatDateToString(tomorrow);
const yesterday = new Date(today);
yesterday.setDate(today.getDate() - 1);
const yesterdayStr = formatDateToString(yesterday);
return [ return [
// Sự kiện hôm nay
{ {
id: '1', id: '1',
title: 'Lịch vào trực lớp TTCĐT 445.T1', title: 'Lịch vào trực lớp TTCĐT 445.T1',
subtitle: 'CS Địa lý 4D', subtitle: 'CS Địa lý 4D',
time: '07:00', time: '07:00',
endTime: '09:00', endTime: '09:00',
date: '2025-08-25', date: todayStr,
type: 'class', type: 'class',
}, },
{ {
...@@ -29,18 +60,141 @@ const FilterDay = ({navigation}) => { ...@@ -29,18 +60,141 @@ const FilterDay = ({navigation}) => {
subtitle: 'Phòng họp A1', subtitle: 'Phòng họp A1',
time: '10:00', time: '10:00',
endTime: '11:30', endTime: '11:30',
date: '2025-07-24', date: todayStr,
type: 'meeting', type: 'meeting',
}, },
{ {
id: '3', id: '3',
title: 'Nghỉ giải lao',
subtitle: 'Thư giãn',
time: '11:30',
endTime: '12:30',
date: todayStr,
type: 'break',
},
{
id: '3',
title: 'Đang ngủ',
subtitle: 'Thư giãn',
time: '12:30',
endTime: '13:30',
date: todayStr,
type: 'break',
},
{
id: '4',
title: 'Ăn trưa',
subtitle: 'Căng tin trường',
time: '12:00',
endTime: '13:00',
date: todayStr,
type: 'meal',
},
{
id: '5',
title: 'Training React Native', title: 'Training React Native',
subtitle: 'Online Zoom', subtitle: 'Online Zoom',
time: '14:00', time: '14:00',
endTime: '16:00', endTime: '16:00',
date: '2025-07-25', date: todayStr,
type: 'training', type: 'training',
}, },
{
id: '6',
title: 'Code Review Session',
subtitle: 'Dev Team',
time: '16:30',
endTime: '17:30',
date: todayStr,
type: 'review',
},
// Sự kiện ngày mai
{
id: '7',
title: 'Họp nội bộ khoa CNTT',
subtitle: 'Phòng họp B2',
time: '08:00',
endTime: '10:00',
date: tomorrowStr,
type: 'meeting',
},
{
id: '8',
title: 'Lịch học lớp EWC45.364.L1',
subtitle: 'Tiếng Anh chuyên ngành',
time: '10:30',
endTime: '12:00',
date: tomorrowStr,
type: 'class',
},
{
id: '9',
title: 'Workshop AI trong giáo dục',
subtitle: 'Hội trường lớn',
time: '13:30',
endTime: '17:00',
date: tomorrowStr,
type: 'workshop',
},
// Sự kiện hôm qua
{
id: '10',
title: 'Seminar Công nghệ mới',
subtitle: 'Phòng 301',
time: '09:00',
endTime: '11:00',
date: yesterdayStr,
type: 'seminar',
},
{
id: '11',
title: 'Chấm bài thi cuối kỳ',
subtitle: 'Văn phòng giảng viên',
time: '14:00',
endTime: '17:00',
date: yesterdayStr,
type: 'grading',
},
// Sự kiện ngày cố định
{
id: '12',
title: 'Lịch vào trực lớp IT47.8F7',
subtitle: 'Môn học chuyên ngành',
time: '07:30',
endTime: '09:00',
date: '2025-01-15',
type: 'class',
},
{
id: '13',
title: 'Hội nghị khoa học sinh viên',
subtitle: 'Hội trường A',
time: '08:30',
endTime: '14:00',
date: '2025-01-20',
type: 'conference',
},
{
id: '14',
title: 'Bảo vệ đồ án tốt nghiệp',
subtitle: 'Phòng 205',
time: '13:00',
endTime: '17:30',
date: '2025-01-25',
type: 'defense',
},
{
id: '15',
title: 'Tổng kết học kỳ',
subtitle: 'Phòng họp khoa',
time: '15:00',
endTime: '18:00',
date: '2025-01-30',
type: 'summary',
},
]; ];
}; };
...@@ -88,6 +242,8 @@ const FilterDay = ({navigation}) => { ...@@ -88,6 +242,8 @@ const FilterDay = ({navigation}) => {
setSelectedDate(newDate); setSelectedDate(newDate);
setShowMonthPicker(false); setShowMonthPicker(false);
DeviceEventEmitter.emit('onDateChange', newDate); DeviceEventEmitter.emit('onDateChange', newDate);
// Cập nhật header drawer với tháng mới
DeviceEventEmitter.emit('updateHeaderMonth', monthIndex);
}; };
const swipeToNextDay = () => { const swipeToNextDay = () => {
...@@ -96,6 +252,8 @@ const FilterDay = ({navigation}) => { ...@@ -96,6 +252,8 @@ const FilterDay = ({navigation}) => {
setSelectedDate(nextDay); setSelectedDate(nextDay);
setCurrentDate(nextDay); setCurrentDate(nextDay);
DeviceEventEmitter.emit('onDateChange', nextDay); DeviceEventEmitter.emit('onDateChange', nextDay);
// Cập nhật header drawer nếu tháng thay đổi
DeviceEventEmitter.emit('updateHeaderMonth', nextDay.getMonth());
}; };
const swipeToPrevDay = () => { const swipeToPrevDay = () => {
...@@ -104,6 +262,8 @@ const FilterDay = ({navigation}) => { ...@@ -104,6 +262,8 @@ const FilterDay = ({navigation}) => {
setSelectedDate(prevDay); setSelectedDate(prevDay);
setCurrentDate(prevDay); setCurrentDate(prevDay);
DeviceEventEmitter.emit('onDateChange', prevDay); DeviceEventEmitter.emit('onDateChange', prevDay);
// Cập nhật header drawer nếu tháng thay đổi
DeviceEventEmitter.emit('updateHeaderMonth', prevDay.getMonth());
}; };
const toggleMonthPicker = () => { const toggleMonthPicker = () => {
...@@ -139,6 +299,26 @@ const FilterDay = ({navigation}) => { ...@@ -139,6 +299,26 @@ const FilterDay = ({navigation}) => {
return {topPosition, height}; return {topPosition, height};
}; };
const calculateEventLayout = (events) => {
return events.map((event, index) => {
const {topPosition, height} = calculateEventPosition(event.time, event.endTime);
// Simple stacking - each subsequent event gets slightly offset
const stackOffset = index * 8; // 8px offset for each event
const leftOffset = 5 + stackOffset;
const rightOffset = 15 + stackOffset;
return {
...event,
topPosition,
height,
leftOffset,
rightOffset,
zIndex: 10 + index // Higher z-index for later events
};
});
};
return ( return (
<FilterDayView <FilterDayView
navigation={navigation} navigation={navigation}
...@@ -153,6 +333,7 @@ const FilterDay = ({navigation}) => { ...@@ -153,6 +333,7 @@ const FilterDay = ({navigation}) => {
handleMonthSelect={handleMonthSelect} handleMonthSelect={handleMonthSelect}
toggleMonthPicker={toggleMonthPicker} toggleMonthPicker={toggleMonthPicker}
calculateEventPosition={calculateEventPosition} calculateEventPosition={calculateEventPosition}
calculateEventLayout={calculateEventLayout}
/> />
); );
}; };
......
...@@ -5,10 +5,15 @@ const {width: screenWidth, height: screenHeight} = Dimensions.get('window'); ...@@ -5,10 +5,15 @@ const {width: screenWidth, height: screenHeight} = Dimensions.get('window');
const HOUR_HEIGHT = 80; const HOUR_HEIGHT = 80;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
// ==================== CONTAINER CHÍNH ====================
// Tương ứng với View chính trong FilterDayView dòng 117
container: { container: {
flex: 1, flex: 1,
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
}, },
// ==================== MONTH PICKER ====================
// Tương ứng với renderMonthPicker dòng 25-27
monthPickerContainer: { monthPickerContainer: {
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
borderBottomWidth: 1, borderBottomWidth: 1,
...@@ -25,6 +30,9 @@ const styles = StyleSheet.create({ ...@@ -25,6 +30,9 @@ const styles = StyleSheet.create({
borderRadius: 20, borderRadius: 20,
backgroundColor: R.colors.gray, backgroundColor: R.colors.gray,
}, },
// ==================== DATE INFO CONTAINER ====================
// Tương ứng với renderDateInfo dòng 29-43
dateInfoContainer: { dateInfoContainer: {
paddingHorizontal: 15, paddingHorizontal: 15,
paddingVertical: 12, paddingVertical: 12,
...@@ -47,6 +55,19 @@ const styles = StyleSheet.create({ ...@@ -47,6 +55,19 @@ const styles = StyleSheet.create({
color: R.colors.black, color: R.colors.black,
fontWeight: '400', fontWeight: '400',
}, },
dayNumberToday: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.white,
fontWeight: '400',
backgroundColor: R.colors.blue,
borderRadius: 15,
paddingHorizontal: 8,
paddingVertical: 4,
},
// ==================== TIME SLOTS CONTAINER ====================
// Tương ứng với renderTimeSlots dòng 45-115
timeSlotsContainer: { timeSlotsContainer: {
flex: 1, flex: 1,
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
...@@ -58,16 +79,14 @@ const styles = StyleSheet.create({ ...@@ -58,16 +79,14 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
position: 'relative', position: 'relative',
}, },
// ==================== TIME LABELS COLUMN ====================
// Tương ứng với timeLabelsColumn dòng 56-65
timeLabelsColumn: { timeLabelsColumn: {
minWidth: 70, minWidth: 70,
borderRightWidth: 1, borderRightWidth: 1,
borderRightColor: R.colors.gray, borderRightColor: R.colors.gray,
}, },
eventsColumn: {
flex: 1,
position: 'relative',
minHeight: 24 * HOUR_HEIGHT,
},
timeSlot: { timeSlot: {
height: HOUR_HEIGHT, height: HOUR_HEIGHT,
alignItems: 'center', alignItems: 'center',
...@@ -75,22 +94,34 @@ const styles = StyleSheet.create({ ...@@ -75,22 +94,34 @@ const styles = StyleSheet.create({
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: R.colors.gray, borderBottomColor: R.colors.gray,
}, },
gridLine: {
height: HOUR_HEIGHT,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
width: '100%',
},
timeText: { timeText: {
fontSize: R.fontsize.fontSizeContent, fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
color: R.colors.black, color: R.colors.black,
fontWeight: '400', fontWeight: '400',
}, },
// ==================== EVENTS COLUMN ====================
// Tương ứng với eventsColumn dòng 67-110
eventsColumn: {
flex: 1,
position: 'relative',
height: 24 * HOUR_HEIGHT,
},
gridLine: {
height: HOUR_HEIGHT,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
width: '100%',
},
// ==================== EVENT CARDS ====================
// Tương ứng với event rendering dòng 72-109
eventCard: { eventCard: {
borderRadius: 15, borderRadius: 15,
paddingLeft: 15, paddingHorizontal: 8,
paddingTop: 10, paddingVertical: 4,
justifyContent: 'flex-start',
}, },
eventTitle: { eventTitle: {
fontSize: R.fontsize.fontSizeContent, fontSize: R.fontsize.fontSizeContent,
...@@ -106,16 +137,6 @@ const styles = StyleSheet.create({ ...@@ -106,16 +137,6 @@ const styles = StyleSheet.create({
color: R.colors.white, color: R.colors.white,
marginBottom: 5, marginBottom: 5,
}, },
dayNumberToday: {
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular,
color: R.colors.white,
fontWeight: '400',
backgroundColor: R.colors.blue,
borderRadius: 15,
paddingHorizontal: 8,
paddingVertical: 2,
},
eventTime: { eventTime: {
fontSize: R.fontsize.fontSizeContent, fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontRegular, fontFamily: R.fonts.fontRegular,
......
...@@ -5,13 +5,18 @@ import styles from './style'; ...@@ -5,13 +5,18 @@ import styles from './style';
const FilterDayView = props => { const FilterDayView = props => {
const { const {
currentDate,
selectedDate, selectedDate,
showMonthPicker, showMonthPicker,
scrollViewRef, scrollViewRef,
panResponder, panResponder,
getEventsForDate, getEventsForDate,
getDayName, getDayName,
getMonthName,
handleMonthSelect,
toggleMonthPicker,
calculateEventPosition, calculateEventPosition,
calculateEventLayout,
} = props; } = props;
const isToday = date => { const isToday = date => {
...@@ -69,12 +74,7 @@ const FilterDayView = props => { ...@@ -69,12 +74,7 @@ const FilterDayView = props => {
<View key={hour} style={styles.gridLine} /> <View key={hour} style={styles.gridLine} />
))} ))}
{selectedEvents.map(event => { {calculateEventLayout(selectedEvents).map(event => {
const {topPosition, height} = calculateEventPosition(
event.time,
event.endTime,
);
return ( return (
<TouchableOpacity <TouchableOpacity
key={event.id} key={event.id}
...@@ -82,21 +82,21 @@ const FilterDayView = props => { ...@@ -82,21 +82,21 @@ const FilterDayView = props => {
styles.eventCard, styles.eventCard,
{ {
position: 'absolute', position: 'absolute',
top: topPosition, top: event.topPosition,
height: Math.max(height, 40), height: event.height,
left: 5, left: event.leftOffset,
right: 15, right: event.rightOffset,
zIndex: 10, zIndex: event.zIndex,
backgroundColor: R.colors.blue, backgroundColor: R.colors.blue,
}, },
]} ]}
activeOpacity={0.7}> activeOpacity={0.7}>
<Text <Text
style={styles.eventTitle} style={styles.eventTitle}
numberOfLines={height > 60 ? 2 : 1}> numberOfLines={event.height > 60 ? 2 : 1}>
{event.title} {event.title}
</Text> </Text>
{height > 40 && ( {event.height > 40 && (
<Text style={styles.eventSubtitle} numberOfLines={1}> <Text style={styles.eventSubtitle} numberOfLines={1}>
{event.subtitle} {event.subtitle}
</Text> </Text>
......
import React, {useState, useMemo, useRef} from 'react'; import React, {useState, useMemo, useRef, useEffect} from 'react';
import {Animated, PanResponder, Dimensions, DeviceEventEmitter} from 'react-native'; import {Animated, PanResponder, Dimensions, DeviceEventEmitter} from 'react-native';
import {useFocusEffect} from '@react-navigation/native';
import ClassScheduleView from './view'; import ClassScheduleView from './view';
// ==================== HẰNG SỐ ==================== // ==================== HẰNG SỐ ====================
...@@ -12,6 +13,19 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => { ...@@ -12,6 +13,19 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
const [currentDate, setCurrentDate] = useState(new Date()); const [currentDate, setCurrentDate] = useState(new Date());
const [selectedDate, setSelectedDate] = useState(null); const [selectedDate, setSelectedDate] = useState(null);
// ==================== EFFECTS ====================
// Reset về ngày hiện tại khi chuyển màn hình
useFocusEffect(
React.useCallback(() => {
const today = new Date();
setCurrentDate(today);
setSelectedDate(null);
DeviceEventEmitter.emit('onDateChange', today);
// Cập nhật header drawer với tháng hiện tại
DeviceEventEmitter.emit('updateHeaderMonth', today.getMonth());
}, [])
);
// B2: State bottom sheet // B2: State bottom sheet
const [showBottomSheet, setShowBottomSheet] = useState(false); const [showBottomSheet, setShowBottomSheet] = useState(false);
...@@ -291,6 +305,8 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => { ...@@ -291,6 +305,8 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
// Phát sự kiện để cập nhật header title // Phát sự kiện để cập nhật header title
DeviceEventEmitter.emit('onDateChange', newDate.toISOString()); DeviceEventEmitter.emit('onDateChange', newDate.toISOString());
// Cập nhật header drawer với tháng mới
DeviceEventEmitter.emit('updateHeaderMonth', newDate.getMonth());
if (showBottomSheet) { if (showBottomSheet) {
hideBottomSheetModal(); hideBottomSheetModal();
......
...@@ -3,7 +3,7 @@ import R from '../../assets/R'; ...@@ -3,7 +3,7 @@ import R from '../../assets/R';
const {width: screenWidth, height: screenHeight} = Dimensions.get('window'); const {width: screenWidth, height: screenHeight} = Dimensions.get('window');
const CELL_WIDTH = (screenWidth - 30) / 7; const CELL_WIDTH = (screenWidth - 30) / 7;
const CELL_HEIGHT = (screenHeight - 140) / 6; const CELL_HEIGHT = (screenHeight - 160) / 6;
const BOTTOM_SHEET_HEIGHT = screenHeight * 0.6; const BOTTOM_SHEET_HEIGHT = screenHeight * 0.6;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
...@@ -40,6 +40,7 @@ const styles = StyleSheet.create({ ...@@ -40,6 +40,7 @@ const styles = StyleSheet.create({
color: R.colors.white, color: R.colors.white,
fontSize: R.fontsize.fontsSizeTitle, fontSize: R.fontsize.fontsSizeTitle,
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
height: '100%',
}, },
// Tiêu đề các ngày trong tuần // Tiêu đề các ngày trong tuần
...@@ -227,7 +228,7 @@ const styles = StyleSheet.create({ ...@@ -227,7 +228,7 @@ const styles = StyleSheet.create({
marginBottom: 10, marginBottom: 10,
marginHorizontal: 15, marginHorizontal: 15,
borderLeftWidth: 4, borderLeftWidth: 4,
borderLeftColor: R.colors.blue500, borderLeftColor: R.colors.blue,
shadowColor: R.colors.black, shadowColor: R.colors.black,
shadowOffset: { shadowOffset: {
width: 0, width: 0,
......
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