Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
AppUms_Lecturer
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tungnq
AppUms_Lecturer
Commits
df7585d6
Commit
df7585d6
authored
Sep 12, 2025
by
tungnq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TODO: Thêm workaround cho lỗi DeviceEventEmitter.removeListener và đồng bộ tháng ở header Drawer
parent
5cfc51c6
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
578 additions
and
208 deletions
+578
-208
App.js
App.js
+12
-1
drawerView.js
src/routers/drawer_schedule/drawerView.js
+11
-1
index.js
src/screens/class_schedule/filter3day/index.js
+158
-109
style.js
src/screens/class_schedule/filter3day/style.js
+63
-0
index.js
src/screens/class_schedule/filterWeek/index.js
+26
-31
style.js
src/screens/class_schedule/filterWeek/style.js
+47
-24
index.js
src/screens/class_schedule/filterday/index.js
+184
-3
style.js
src/screens/class_schedule/filterday/style.js
+44
-23
view.js
src/screens/class_schedule/filterday/view.js
+13
-13
index.js
src/screens/class_schedule/index.js
+17
-1
style.js
src/screens/class_schedule/style.js
+3
-2
No files found.
App.js
View file @
df7585d6
...
@@ -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
));
...
...
src/routers/drawer_schedule/drawerView.js
View file @
df7585d6
...
@@ -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
}
>
...
...
src/screens/class_schedule/filter3day/index.js
View file @
df7585d6
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
d
ates
=
[];
const
threeDayD
ates
=
[];
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
);
d
ates
.
push
(
dayDate
);
threeDayD
ates
.
push
(
dayDate
);
}
}
return
d
ates
;
return
threeDayD
ates
;
};
};
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
)
{
swipeToPrev
3Days
();
swipeToPrev
ThreeDay
();
}
else
if
(
gestureState
.
dx
<
-
50
)
{
}
else
if
(
gestureState
.
dx
<
-
50
)
{
swipeToNext
3Days
();
swipeToNext
ThreeDay
();
}
}
},
},
});
});
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
}
/
>
/
>
);
);
};
};
...
...
src/screens/class_schedule/filter3day/style.js
View file @
df7585d6
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
,
...
...
src/screens/class_schedule/filterWeek/index.js
View file @
df7585d6
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-0
8-26
'
,
date
:
'2025-0
1-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-0
7-22
'
,
date
:
'2025-0
1-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
...
...
src/screens/class_schedule/filterWeek/style.js
View file @
df7585d6
...
@@ -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
,
...
...
src/screens/class_schedule/filterday/index.js
View file @
df7585d6
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
}
/
>
/
>
);
);
};
};
...
...
src/screens/class_schedule/filterday/style.js
View file @
df7585d6
...
@@ -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
,
...
...
src/screens/class_schedule/filterday/view.js
View file @
df7585d6
...
@@ -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
>
...
...
src/screens/class_schedule/index.js
View file @
df7585d6
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
();
...
...
src/screens/class_schedule/style.js
View file @
df7585d6
...
@@ -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
-
1
4
0
)
/
6
;
const
CELL_HEIGHT
=
(
screenHeight
-
1
6
0
)
/
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
.
blue
500
,
borderLeftColor
:
R
.
colors
.
blue
,
shadowColor
:
R
.
colors
.
black
,
shadowColor
:
R
.
colors
.
black
,
shadowOffset
:
{
shadowOffset
:
{
width
:
0
,
width
:
0
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment