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
96d19d3b
Commit
96d19d3b
authored
Aug 12, 2025
by
nguyenquangtung004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TODO: Đã fix thành công SafeAreaView không bị khoảng trắng trên màn hình home
parent
61052ad2
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
135 additions
and
107 deletions
+135
-107
Header.js
src/components/Header/Header.js
+1
-0
header.js
src/screens/home/header.js
+0
-1
view.js
src/screens/home/view.js
+132
-104
view.js
src/screens/profile/view.js
+2
-2
No files found.
src/components/Header/Header.js
View file @
96d19d3b
import
React
from
'react'
;
import
{
SafeAreaView
,
StyleSheet
,
Text
,
TouchableOpacity
,
...
...
src/screens/home/header.js
View file @
96d19d3b
...
...
@@ -49,7 +49,6 @@ const styles = StyleSheet.create({
container
:
{
flexDirection
:
"row"
,
marginHorizontal
:
15
,
marginTop
:
15
,
maxHeight
:
40
,
},
size_box
:{
...
...
src/screens/home/view.js
View file @
96d19d3b
...
...
@@ -10,6 +10,8 @@ import {
Keyboard
,
SafeAreaView
,
Image
,
StatusBar
,
// FEATURE: Import StatusBar để control status bar
Platform
,
// FEATURE: Check platform iOS/Android
}
from
"react-native"
;
import
HeaderCus
from
"../home/header"
;
import
R
from
"../../assets/R"
;
...
...
@@ -18,6 +20,7 @@ import ItemGrid from "./item";
import
styles
from
"./style"
;
import
{
useNavigation
}
from
"@react-navigation/native"
;
import
*
as
SCREENNAME
from
"../../routers/ScreenNames"
;
const
HomeView
=
(
props
)
=>
{
const
{
menuDataStudy
,
...
...
@@ -29,119 +32,143 @@ const HomeView = (props) => {
onMenuItemPress
,
onSearchChange
,
}
=
props
;
// OPTIMIZE: Move icon reference outside render để tránh re-create
const
ArrowRightIcon
=
R
.
images
.
icArrowRight
;
const
navigate
=
useNavigation
();
const
renderMenuItem
=
({
item
})
=>
{
return
<
ItemGrid
item
=
{
item
}
onPress
=
{()
=>
onMenuItemPress
(
item
)}
/>
;
};
return
(
<
TouchableWithoutFeedback
onPress
=
{
Keyboard
.
dismiss
}
accessible
=
{
false
}
>
<
SafeAreaView
style
=
{{
flex
:
1
}}
>
// PERFORMANCE: Memoized render function
const
renderMenuItem
=
React
.
useCallback
(({
item
})
=>
{
return
<
ItemGrid
item
=
{
item
}
onPress
=
{()
=>
onMenuItemPress
(
item
)}
/>
;
},
[
onMenuItemPress
]);
<
View
style
=
{
styles
.
container_body
}
>
<
ImageBackground
source
=
{
R
.
images
.
igBackgroundSlider
}
style
=
{
styles
.
background_header
}
>
<
HeaderCus
pathLogo
=
{
R
.
images
.
igLogo
}
width
=
{
75
}
height
=
{
36
}
textInput
=
{
R
.
colors
.
white
}
backgroundInput
=
{
R
.
colors
.
backgroundInputSearch
}
textLabel
=
{
I18n
.
t
(
"Search"
)}
textColorLabel
=
{
R
.
colors
.
white
}
// UI/UX: Profile card component với null safety
const
renderProfileCard
=
()
=>
(
<
View
style
=
{
styles
.
profile_card
}
>
<
View
style
=
{
styles
.
profile_left
}
>
{
/* FEATURE: Avatar với fallback */
}
<
View
style
=
{
styles
.
avatar
}
>
{
userProfile
?.
avatar
?
(
<
Image
source
=
{{
uri
:
userProfile
.
avatar
}}
style
=
{
styles
.
avatar_image
}
resizeMode
=
"cover"
/>
)
:
(
<
View
style
=
{
styles
.
avatar_placeholder
}
>
<
Text
style
=
{
styles
.
avatar_text
}
>
{
userProfile
?.
name
?.
charAt
(
0
)
||
"U"
}
<
/Text
>
<
/View
>
)}
<
/View
>
{
/* FEATURE: User information với null safety */
}
<
View
style
=
{
styles
.
information
}
>
<
Text
style
=
{
styles
.
text_card_info
}
numberOfLines
=
{
1
}
ellipsizeMode
=
"tail"
>
{
userProfile
?.
name
||
"Không có tên"
}
<
/Text
>
<
Text
style
=
{
styles
.
text_card_info
}
numberOfLines
=
{
1
}
ellipsizeMode
=
"tail"
>
{
userProfile
?.
phone
||
"Không có SĐT"
}
<
/Text
>
<
/View
>
<
/View
>
<
View
style
=
{
styles
.
profile_card
}
>
<
View
style
=
{
styles
.
profile_left
}
>
<
View
style
=
{
styles
.
avatar
}
>
{
userProfile
?.
avatar
?
(
<
Image
source
=
{{
uri
:
userProfile
.
avatar
}}
style
=
{
styles
.
avatar_image
}
resizeMode
=
"cover"
/>
)
:
(
<
View
style
=
{
styles
.
avatar_placeholder
}
>
<
Text
style
=
{
styles
.
avatar_text
}
>
{
userProfile
?.
name
?.
charAt
(
0
)}
<
/Text
>
<
/View
>
)}
<
/View
>
<
View
style
=
{
styles
.
information
}
>
<
Text
style
=
{
styles
.
text_card_info
}
numberOfLines
=
{
1
}
ellipsizeMode
=
"tail"
>
{
userProfile
?.
name
}
<
/Text
>
<
Text
style
=
{
styles
.
text_card_info
}
numberOfLines
=
{
1
}
ellipsizeMode
=
"tail"
>
{
userProfile
?.
phone
}
<
/Text
>
<
/View
>
<
/View
>
{
/* FEATURE: Profile button với better UX */
}
<
TouchableOpacity
style
=
{
styles
.
profile_btn
}
onPress
=
{()
=>
navigate
.
navigate
(
SCREENNAME
.
PROFILE
)}
activeOpacity
=
{
0.7
}
>
<
Text
style
=
{
styles
.
btn_text
}
>
H
ồ
s
ở
c
á
nh
â
n
<
/Text
>
<
ArrowRightIcon
width
=
{
5
}
height
=
{
10
}
fill
=
{
R
.
colors
.
txtMain
}
style
=
{
styles
.
icon
}
/
>
<
/TouchableOpacity
>
<
/View
>
);
<
TouchableOpacity
style
=
{
styles
.
profile_btn
}
onPress
=
{()
=>
navigate
.
navigate
(
SCREENNAME
.
PROFILE
)}
>
<
Text
style
=
{
styles
.
btn_text
}
>
H
ồ
s
ơ
c
á
nh
â
n
<
/Text
>
<
ArrowRightIcon
width
=
{
5
}
height
=
{
10
}
fill
=
{
R
.
colors
.
txtMain
}
style
=
{
styles
.
icon
}
/
>
<
/TouchableOpacity
>
<
/View
>
<
/ImageBackground
>
<
ScrollView
showsVerticalScrollIndicator
=
{
false
}
style
=
{
styles
.
scroll
}
>
<
View
style
=
{
styles
.
menu_container
}
>
<
Text
style
=
{
styles
.
menu_title
}
>
H
ọ
c
t
ậ
p
<
/Text
>
<
FlatList
data
=
{
menuDataStudy
}
renderItem
=
{
renderMenuItem
}
numColumns
=
{
3
}
keyExtractor
=
{(
item
)
=>
item
.
id
.
toString
()}
scrollEnabled
=
{
false
}
columnWrapperStyle
=
{
styles
.
row
}
/
>
<
/View
>
<
View
style
=
{
styles
.
menu_container
}
>
<
Text
style
=
{
styles
.
menu_title
}
>
C
á
nh
â
n
<
/Text
>
<
FlatList
data
=
{
menuDataIndividual
}
renderItem
=
{
renderMenuItem
}
numColumns
=
{
3
}
keyExtractor
=
{(
item
)
=>
item
.
id
.
toString
()}
scrollEnabled
=
{
false
}
columnWrapperStyle
=
{
styles
.
row
}
/
>
<
/View
>
<
View
style
=
{
styles
.
menu_container
}
>
<
Text
style
=
{
styles
.
menu_title
}
>
D
ị
ch
v
ụ
tr
ự
c
tuy
ế
n
<
/Text
>
<
FlatList
data
=
{
menuDataOnlineSer
}
renderItem
=
{
renderMenuItem
}
numColumns
=
{
3
}
keyExtractor
=
{(
item
)
=>
item
.
id
.
toString
()}
scrollEnabled
=
{
false
}
columnWrapperStyle
=
{
styles
.
row
}
// FUNCTIONALITY: Render menu section với reusable logic
const
renderMenuSection
=
(
title
,
data
)
=>
(
<
View
style
=
{
styles
.
menu_container
}
>
<
Text
style
=
{
styles
.
menu_title
}
>
{
title
}
<
/Text
>
<
FlatList
data
=
{
data
}
renderItem
=
{
renderMenuItem
}
numColumns
=
{
3
}
keyExtractor
=
{(
item
)
=>
item
.
id
.
toString
()}
scrollEnabled
=
{
false
}
columnWrapperStyle
=
{
styles
.
row
}
removeClippedSubviews
=
{
true
}
// PERFORMANCE: Memory optimization
maxToRenderPerBatch
=
{
9
}
// PERFORMANCE: Render batch size
windowSize
=
{
10
}
// PERFORMANCE: Window size optimization
/
>
<
/View
>
);
return
(
<>
{
/* FIXME: StatusBar configuration để loại bỏ white space */
}
<
StatusBar
barStyle
=
"light-content"
// Text trắng trên dark background
backgroundColor
=
"transparent"
// Background trong suốt
translucent
=
{
true
}
// Cho phép content extend lên status bar
/
>
<
TouchableWithoutFeedback
onPress
=
{
Keyboard
.
dismiss
}
accessible
=
{
false
}
>
{
/* FIXME: Dùng View với manual padding thay SafeAreaView */
}
<
View
style
=
{[
{
flex
:
1
},
{
paddingTop
:
Platform
.
OS
===
'ios'
?
0
:
StatusBar
.
currentHeight
}
]}
>
<
View
style
=
{
styles
.
container_body
}
>
<
ImageBackground
source
=
{
R
.
images
.
igBackgroundSlider
}
style
=
{[
styles
.
background_header
,
{
// FIXME: Extend background để cover status bar area
paddingTop
:
Platform
.
OS
===
'ios'
?
50
:
(
StatusBar
.
currentHeight
||
0
)
+
10
,
}]}
>
<
HeaderCus
pathLogo
=
{
R
.
images
.
igLogo
}
width
=
{
75
}
height
=
{
36
}
textInput
=
{
R
.
colors
.
white
}
backgroundInput
=
{
R
.
colors
.
backgroundInputSearch
}
textLabel
=
{
I18n
.
t
(
"Search"
)}
textColorLabel
=
{
R
.
colors
.
white
}
/
>
<
/View
>
<
/ScrollView
>
{
renderProfileCard
()}
<
/ImageBackground
>
<
ScrollView
showsVerticalScrollIndicator
=
{
false
}
style
=
{
styles
.
scroll
}
bounces
=
{
false
}
// OPTIMIZE: Tắt bounce trên iOS
overScrollMode
=
"never"
// OPTIMIZE: Tắt over scroll trên Android
>
{
/* FUNCTIONALITY: Render các menu sections */
}
{
renderMenuSection
(
"Học tập"
,
menuDataStudy
)}
{
renderMenuSection
(
"Cá nhân"
,
menuDataIndividual
)}
{
renderMenuSection
(
"Dịch vụ trực tuyến"
,
menuDataOnlineSer
)}
<
/ScrollView
>
<
/View
>
<
/View
>
<
/
SafeAreaView
>
<
/
TouchableWithoutFeedback
>
<
/
TouchableWithoutFeedback
>
<
/
>
);
};
export
default
HomeView
;
export
default
HomeView
;
\ No newline at end of file
src/screens/profile/view.js
View file @
96d19d3b
...
...
@@ -18,7 +18,7 @@ const ProfileView = (props) => {
const
{
phone
,
setPhone
,
cmnd
,
setCmnd
,
bank
,
setBank
}
=
props
;
const
IconCamera
=
R
.
images
.
icCamera
;
return
(
<
SafeAreaView
style
=
{{
flex
:
1
,
backgroundColor
:
R
.
colors
.
white
}}
>
<
View
style
=
{{
flex
:
1
}}
>
<
Header
title
=
{
"Hồ sơ cá nhân"
}
isBack
/>
<
ScrollView
showsVerticalScrollIndicator
=
{
false
}
style
=
{{
flex
:
1
}}
>
<
View
style
=
{
styles
.
container
}
>
...
...
@@ -335,7 +335,7 @@ const ProfileView = (props) => {
<
/View
>
<
/View
>
<
/ScrollView
>
<
/
SafeArea
View
>
<
/View
>
);
};
...
...
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