Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
AppUms_Student
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_Student
Commits
b96e6766
Commit
b96e6766
authored
Sep 26, 2025
by
tungnq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TODO: Đã fix thành công filter 3 ngày
parent
9b3fee3a
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
467 additions
and
6 deletions
+467
-6
index.js
src/screens/class_schedule/filter_3_date/index.js
+246
-6
style.js
src/screens/class_schedule/filter_3_date/style.js
+221
-0
view.js
src/screens/class_schedule/filter_3_date/view.js
+0
-0
No files found.
src/screens/class_schedule/filter_3_date/index.js
View file @
b96e6766
import
React
from
'react'
;
import
React
,
{
useState
,
useRef
,
useEffect
}
from
'react'
;
import
{
Text
,
View
,
StyleSheet
}
from
'react-native'
;
import
{
Dimensions
,
PanResponder
}
from
'react-native'
;
import
Filter3DateView
from
'./view'
;
import
{
useNavigation
,
useFocusEffect
}
from
'@react-navigation/native'
;
import
{
DeviceEventEmitter
}
from
'react-native'
;
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
navigationHook
=
useNavigation
();
// ==================== QUẢN LÝ STATE ====================
const
[
currentDate
,
setCurrentDate
]
=
useState
(
new
Date
());
const
[
selectedDate
,
setSelectedDate
]
=
useState
(
new
Date
());
const
[
showMonthPicker
,
setShowMonthPicker
]
=
useState
(
false
);
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
(()
=>
{
DeviceEventEmitter
.
emit
(
'onDateChange'
,
selectedDate
);
},
[
selectedDate
]);
// ==================== HÀM TIỆN ÍCH ====================
// T1: Định dạng ngày thành chuỗi
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
}
`
;
};
// T2: Kiểm tra ngày hôm nay
const
isToday
=
someDate
=>
{
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
days
=
[
'CN'
,
'T2'
,
'T3'
,
'T4'
,
'T5'
,
'T6'
,
'T7'
];
return
days
[
date
.
getDay
()];
};
// T4: Lấy tên tháng
const
getMonthName
=
monthIndex
=>
{
const
months
=
[
'Tháng 1'
,
'Tháng 2'
,
'Tháng 3'
,
'Tháng 4'
,
'Tháng 5'
,
'Tháng 6'
,
'Tháng 7'
,
'Tháng 8'
,
'Tháng 9'
,
'Tháng 10'
,
'Tháng 11'
,
'Tháng 12'
,
];
return
months
[
monthIndex
];
};
// T5: Lấy 3 ngày liên tiếp
const
get3DaysDates
=
date
=>
{
const
threeDayDates
=
[];
for
(
let
i
=
-
1
;
i
<=
1
;
i
++
)
{
const
dayDate
=
new
Date
(
date
);
dayDate
.
setDate
(
date
.
getDate
()
+
i
);
threeDayDates
.
push
(
dayDate
);
}
return
threeDayDates
;
};
// T6: Tính toán vị trí sự kiện
const
calculateEventPosition
=
(
startTime
,
endTime
)
=>
{
const
[
startHour
,
startMinute
]
=
startTime
.
split
(
':'
).
map
(
Number
);
const
[
endHour
,
endMinute
]
=
endTime
.
split
(
':'
).
map
(
Number
);
const
startTotalMinutes
=
startHour
*
60
+
startMinute
;
const
endTotalMinutes
=
endHour
*
60
+
endMinute
;
const
durationMinutes
=
endTotalMinutes
-
startTotalMinutes
;
const
topPosition
=
(
startTotalMinutes
/
60
)
*
HOUR_HEIGHT
;
const
height
=
(
durationMinutes
/
60
)
*
HOUR_HEIGHT
;
return
{
topPosition
,
height
};
};
// ==================== QUẢN LÝ DỮ LIỆU ====================
// D1: Tạo dữ liệu sự kiện mẫu
const
createMockEvents
=
()
=>
{
const
today
=
new
Date
();
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
[
// 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'
,
},
];
};
// D2: Xử lý dữ liệu sự kiện
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
({
onMoveShouldSetPanResponder
:
(
evt
,
gestureState
)
=>
{
return
Math
.
abs
(
gestureState
.
dx
)
>
30
&&
Math
.
abs
(
gestureState
.
dy
)
<
100
;
},
onPanResponderMove
:
(
evt
,
gestureState
)
=>
{},
onPanResponderRelease
:
(
evt
,
gestureState
)
=>
{
if
(
gestureState
.
dx
>
50
)
{
swipeToPrevThreeDay
();
}
else
if
(
gestureState
.
dx
<
-
50
)
{
swipeToNextThreeDay
();
}
},
});
// ==================== XỬ LÝ SỰ KIỆN ====================
// X1: Xử lý chọn tháng
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
);
};
// X2: Xử lý chuyển 3 ngày
const
swipeToNextThreeDay
=
()
=>
{
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
swipeToPrevThreeDay
=
()
=>
{
const
prevThreeDay
=
new
Date
(
currentDate
);
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
());
};
// X3: Xử lý toggle month picker
const
toggleMonthPicker
=
()
=>
{
setShowMonthPicker
(
!
showMonthPicker
);
};
const
Filter3Date
=
(
props
)
=>
{
return
(
return
(
<
Filter3DateView
/>
<
Filter3DayView
navigation
=
{
navigation
}
currentDate
=
{
currentDate
}
selectedDate
=
{
selectedDate
}
showMonthPicker
=
{
showMonthPicker
}
scrollViewRef
=
{
scrollViewRef
}
panResponder
=
{
panResponder
}
isToday
=
{
isToday
}
getDayName
=
{
getDayName
}
getMonthName
=
{
getMonthName
}
get3DaysDates
=
{
get3DaysDates
}
getEventsForDate
=
{
getEventsForDate
}
calculateEventPosition
=
{
calculateEventPosition
}
handleMonthSelect
=
{
handleMonthSelect
}
toggleMonthPicker
=
{
toggleMonthPicker
}
HOUR_HEIGHT
=
{
HOUR_HEIGHT
}
DAY_COLUMN_WIDTH
=
{
DAY_COLUMN_WIDTH
}
/
>
);
);
};
};
export
default
Filter3Da
te
;
export
default
Filter3Da
y
;
src/screens/class_schedule/filter_3_date/style.js
0 → 100644
View file @
b96e6766
import
{
StyleSheet
,
Dimensions
}
from
'react-native'
;
import
R
from
'../../../assets/R'
;
// ==================== HẰNG SỐ ====================
const
{
width
:
screenWidth
,
height
:
screenHeight
}
=
Dimensions
.
get
(
'window'
);
const
HOUR_HEIGHT
=
80
;
const
DAY_COLUMN_WIDTH
=
(
screenWidth
-
70
)
/
3
;
const
styles
=
StyleSheet
.
create
({
// ==================== CONTAINER CHÍNH ====================
// Container tổng thể của màn hình Filter 3 ngày
container
:
{
flex
:
1
,
backgroundColor
:
R
.
colors
.
white
,
},
// ==================== MONTH PICKER SECTION ====================
// Container chứa bộ chọn tháng
monthPickerContainer
:
{
backgroundColor
:
R
.
colors
.
white
,
borderBottomWidth
:
1
,
borderBottomColor
:
R
.
colors
.
gray220
,
paddingVertical
:
10
,
},
// Nội dung cuộn ngang của bộ chọn tháng
monthPickerContent
:
{
paddingHorizontal
:
15
,
},
// Item tháng trong bộ chọn
monthItem
:
{
paddingHorizontal
:
20
,
paddingVertical
:
10
,
marginRight
:
10
,
borderRadius
:
20
,
backgroundColor
:
R
.
colors
.
gray220
,
},
// Item tháng được chọn
monthItemSelected
:
{
backgroundColor
:
R
.
colors
.
black
,
},
// Text của item tháng
monthItemText
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterRegular
,
color
:
R
.
colors
.
black
,
},
// Text của item tháng được chọn
monthItemTextSelected
:
{
color
:
R
.
colors
.
white
,
fontFamily
:
R
.
fonts
.
InterMedium
,
},
// ==================== 3 DAYS HEADER SECTION ====================
// Container chứa header 3 ngày
daysHeaderContainer
:
{
flexDirection
:
'row'
,
backgroundColor
:
R
.
colors
.
gray220
,
borderBottomWidth
:
1
,
borderBottomColor
:
R
.
colors
.
gray220
,
},
// Header cột thời gian (trống)
timeColumnHeader
:
{
width
:
70
,
},
// Cell header của mỗi ngày
dayHeaderCell
:
{
width
:
DAY_COLUMN_WIDTH
,
alignItems
:
'center'
,
justifyContent
:
'center'
,
borderRightWidth
:
1
,
borderRightColor
:
R
.
colors
.
gray220
,
},
// Text tên ngày (Thứ 2, Thứ 3...)
dayHeaderText
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterMedium
,
color
:
R
.
colors
.
black
,
fontWeight
:
'600'
,
},
// Text tên ngày hôm nay
todayHeaderText
:
{
color
:
R
.
colors
.
black
,
fontFamily
:
R
.
fonts
.
InterMedium
,
fontWeight
:
'600'
,
},
// Container chứa số ngày
dayNumberContainer
:
{
minWidth
:
28
,
minHeight
:
28
,
borderRadius
:
30
,
alignItems
:
'center'
,
justifyContent
:
'center'
,
marginVertical
:
5
,
},
// Container số ngày hôm nay (có background xanh)
todayNumberContainer
:
{
backgroundColor
:
R
.
colors
.
main
,
},
// Text số ngày
dayHeaderNumber
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterRegular
,
color
:
R
.
colors
.
black
,
fontWeight
:
'400'
,
},
// Text số ngày hôm nay (màu trắng)
todayHeaderNumber
:
{
color
:
R
.
colors
.
white
,
fontFamily
:
R
.
fonts
.
InterMedium
,
fontWeight
:
'600'
,
},
// ==================== TIME SLOTS SECTION ====================
// Container chứa các khung thời gian
timeSlotsContainer
:
{
flex
:
1
,
backgroundColor
:
R
.
colors
.
white
,
},
// Nội dung cuộn dọc
scrollContent
:
{},
// Container timeline tổng thể
timelineContainer
:
{
flexDirection
:
'row'
,
position
:
'relative'
,
},
// Cột nhãn thời gian bên trái
timeLabelsColumn
:
{
width
:
70
,
borderRightWidth
:
1
,
borderRightColor
:
R
.
colors
.
gray220
,
},
// Container chứa grid 3 ngày
daysGridContainer
:
{
flex
:
1
,
flexDirection
:
'row'
,
},
// Cột của mỗi ngày
dayColumn
:
{
width
:
DAY_COLUMN_WIDTH
,
position
:
'relative'
,
borderRightWidth
:
1
,
borderRightColor
:
R
.
colors
.
gray220
,
},
// Khung thời gian (1 giờ)
timeSlot
:
{
height
:
HOUR_HEIGHT
,
alignItems
:
'center'
,
justifyContent
:
'center'
,
borderBottomWidth
:
1
,
borderBottomColor
:
R
.
colors
.
gray220
,
},
// Cell grid của mỗi giờ trong ngày
gridCell
:
{
height
:
HOUR_HEIGHT
,
borderBottomWidth
:
1
,
borderBottomColor
:
R
.
colors
.
gray220
,
width
:
'100%'
,
},
// Text hiển thị giờ (07:00, 08:00...)
timeText
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterRegular
,
color
:
R
.
colors
.
black
,
fontWeight
:
'400'
,
},
// ==================== EVENT CARD SECTION ====================
// Card hiển thị sự kiện
eventCard
:
{
borderRadius
:
8
,
paddingHorizontal
:
6
,
paddingVertical
:
4
,
},
// Tiêu đề sự kiện
eventTitle
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterMedium
,
color
:
R
.
colors
.
white
,
marginBottom
:
2
,
},
// Phụ đề sự kiện
eventSubtitle
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterRegular
,
color
:
R
.
colors
.
white
,
fontWeight
:
'400'
,
},
// Thời gian sự kiện
eventTime
:
{
fontSize
:
R
.
fontsize
.
fontsSize12
,
fontFamily
:
R
.
fonts
.
InterRegular
,
color
:
R
.
colors
.
white
,
fontWeight
:
'400'
,
},
});
export
default
styles
;
src/screens/class_schedule/filter_3_date/view.js
View file @
b96e6766
This diff is collapsed.
Click to expand it.
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