Commit 74d3ef42 by nguyenquangtung004

TODO: Đã fix thành công SafeAreaView không bị khoảng trắng

parent cd549183
...@@ -6,7 +6,6 @@ const styles = StyleSheet.create({ ...@@ -6,7 +6,6 @@ const styles = StyleSheet.create({
containerBoxHeader: { containerBoxHeader: {
flexDirection: "row", flexDirection: "row",
marginHorizontal: 15, marginHorizontal: 15,
marginTop: 15,
maxHeight: 40, maxHeight: 40,
}, },
boxLogo:{ boxLogo:{
......
...@@ -10,6 +10,8 @@ import { ...@@ -10,6 +10,8 @@ import {
Keyboard, Keyboard,
SafeAreaView, SafeAreaView,
Image, Image,
StatusBar, // FEATURE: Thêm StatusBar để control status bar
Platform, // FEATURE: Check platform để xử lý khác biệt iOS/Android
} from "react-native"; } from "react-native";
import HeaderCus from "../home/header"; import HeaderCus from "../home/header";
import R from "../../assets/R"; import R from "../../assets/R";
...@@ -17,6 +19,7 @@ import ItemGrid from "./item"; ...@@ -17,6 +19,7 @@ import ItemGrid from "./item";
import styles from "./style"; import styles from "./style";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import * as SCREENNAME from "../../routers/ScreenNames"; import * as SCREENNAME from "../../routers/ScreenNames";
const HomeView = (props) => { const HomeView = (props) => {
const { const {
menuActivity, menuActivity,
...@@ -29,142 +32,188 @@ const HomeView = (props) => { ...@@ -29,142 +32,188 @@ const HomeView = (props) => {
onSearchChange, onSearchChange,
} = props; } = props;
const navigate = useNavigation(); const navigate = useNavigation();
// FUNCTIONALITY: Render menu item với tối ưu performance
const renderMenuItem = ({ item }) => { const renderMenuItem = ({ item }) => {
return <ItemGrid item={item} onPress={() => onMenuItemPress(item)} />; return <ItemGrid item={item} onPress={() => onMenuItemPress(item)} />;
}; };
const cardItemInfo =()=>{
return <View style={styles.profileCard}> // UI/UX: Card thông tin user với layout tối ưu
<View style={styles.profile_left}> const cardItemInfo = () => {
{/* Avatar */} return (
<View style={styles.avatar}> <View style={styles.profileCard}>
{userProfile?.avatar ? ( <View style={styles.profile_left}>
<Image {/* FEATURE: Avatar với fallback placeholder */}
source={{ uri: userProfile.avatar }} <View style={styles.avatar}>
style={styles.avatar_image} {userProfile?.avatar ? (
resizeMode="cover" <Image
/> source={{ uri: userProfile.avatar }}
) : ( style={styles.avatar_image}
<View style={styles.avatar_placeholder}> resizeMode="cover"
<Text style={styles.avatar_text}> />
{userProfile?.name?.charAt(0)} ) : (
<View style={styles.avatar_placeholder}>
<Text style={styles.avatar_text}>
{userProfile?.name?.charAt(0) || "U"}
</Text>
</View>
)}
</View>
{/* FEATURE: Thông tin user với null safety */}
<View style={styles.information}>
<Text
style={styles.text_card_info}
numberOfLines={1}
ellipsizeMode="tail"
>
{userProfile?.name ?? "Không có dữ liệu"}
</Text>
<Text
style={styles.text_card_info}
numberOfLines={1}
ellipsizeMode="tail"
>
{userProfile?.phone ?? "Không có dữ liệu"}
</Text> </Text>
</View> </View>
)} </View>
</View> {/* FEATURE: Button navigate tới profile */}
{/* Information */} <TouchableOpacity
<View style={styles.information}> style={styles.profile_btn}
<Text onPress={() => navigate.navigate(SCREENNAME.PROFILE)}
style={styles.text_card_info} activeOpacity={0.7}
numberOfLines={1}
ellipsizeMode="tail"
>
{userProfile?.name?? "Không có dữ liệu"}
</Text>
<Text
style={styles.text_card_info}
numberOfLines={1}
ellipsizeMode="tail"
> >
{userProfile?.phone??"Không có dữ liệu"} <Text style={styles.btn_text}>H sơ cá nhân</Text>
</Text> <View style={styles.iconNext}>
<Image
source={R.images.icNext}
style={{ width: 5, height: 10 }} // OPTIMIZE: Dùng style thay maxWidth/maxHeight
/>
</View>
</TouchableOpacity>
</View> </View>
</View> );
};
<TouchableOpacity style={styles.profile_btn} onPress={() => navigate.navigate(SCREENNAME.PROFILE)}> // FUNCTIONALITY: Render menu activity với FlatList tối ưu
<Text style={styles.btn_text}>H sơ cá nhân</Text> const renderMenuActivity = () => {
<View style={styles.iconNext}> return (
<Image <View style={styles.menu_container}>
source={R.images.icNext} <Text style={styles.menu_title}>Ging dy</Text>
maxWidth={5} <FlatList
maxHeight={10} data={menuActivity}
renderItem={renderMenuItem}
numColumns={3}
keyExtractor={(item) => item.id.toString()}
scrollEnabled={false}
columnWrapperStyle={styles.row}
ListEmptyComponent={renderItemEmpty}
removeClippedSubviews={true} // PERFORMANCE: Tối ưu memory
maxToRenderPerBatch={9} // PERFORMANCE: Render tối đa 9 items/batch
/> />
</View> </View>
</TouchableOpacity> );
</View> };
}
const renderMenuActivity =()=>{ // FUNCTIONALITY: Render menu statistics
return <View style={styles.menu_container}> const renderMenuStatistics = () => {
<Text style={styles.menu_title}>Ging dy</Text> return (
<FlatList <View style={styles.menu_container}>
data={menuActivity} <Text style={styles.menu_title}>Thng kê</Text>
renderItem={renderMenuItem} <FlatList
numColumns={3} data={menuStatistics}
keyExtractor={(item) => item.id.toString()} renderItem={renderMenuItem}
scrollEnabled={false} numColumns={3}
columnWrapperStyle={styles.row} keyExtractor={(item) => item.id.toString()}
ListEmptyComponent={renderItemEmpty} scrollEnabled={false}
/> columnWrapperStyle={styles.row}
</View> ListEmptyComponent={renderItemEmpty}
} removeClippedSubviews={true}
const renderMenuStatistics =()=>{ maxToRenderPerBatch={9}
return <View style={styles.menu_container}> />
<Text style={styles.menu_title}>Thng kê</Text> </View>
<FlatList );
data={menuStatistics} };
renderItem={renderMenuItem}
numColumns={3}
keyExtractor={(item) => item.id.toString()}
scrollEnabled={false}
columnWrapperStyle={styles.row}
ListEmptyComponent={renderItemEmpty}
/>
</View>
}
const renderMenuNotification =()=>{
return <View style={styles.menu_container}>
<Text style={styles.menu_title}>Văn bn và thông báo</Text>
<FlatList
data={menuNotification}
renderItem={renderMenuItem}
numColumns={3}
keyExtractor={(item) => item.id.toString()}
scrollEnabled={false}
columnWrapperStyle={styles.row}
ListEmptyComponent={renderItemEmpty}
/>
</View>
}
const renderItemEmpty =()=>{ // FUNCTIONALITY: Render menu notification
return <View style={styles.cardItemEmpty}> const renderMenuNotification = () => {
<Image return (
source={R.images.icNoData} <View style={styles.menu_container}>
maxWidth={50} <Text style={styles.menu_title}>Văn bn và thông báo</Text>
maxHeight={50} <FlatList
/> data={menuNotification}
<Text style={[styles.menu_text,{color:R.colors.red}]}>Không có d liu</Text> renderItem={renderMenuItem}
</View> numColumns={3}
} keyExtractor={(item) => item.id.toString()}
scrollEnabled={false}
columnWrapperStyle={styles.row}
ListEmptyComponent={renderItemEmpty}
removeClippedSubviews={true}
maxToRenderPerBatch={9}
/>
</View>
);
};
// UI/UX: Empty state component
const renderItemEmpty = () => {
return (
<View style={styles.cardItemEmpty}>
<Image
source={R.images.icNoData}
style={{ width: 50, height: 50 }} // OPTIMIZE: Dùng style object
/>
<Text style={[styles.menu_text, { color: R.colors.red }]}>
Không có d liu
</Text>
</View>
);
};
return ( return (
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}> <>
<SafeAreaView style={styles.safeArea}> {/* FIXME: StatusBar để control màu status bar và remove white space */}
<View style={styles.container_body}> <StatusBar
<ImageBackground barStyle="light-content" // Text trắng trên status bar
source={R.images.igBackground} backgroundColor="transparent" // Background trong suốt
style={styles.background_header} translucent={true} // Cho phép content hiển thị dưới status bar
> />
<HeaderCus
value={searchText} <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
onChangeText={onSearchChange} {/* FIXME: Dùng View thay SafeAreaView để loại bỏ white space */}
/> <View style={[styles.safeArea, { paddingTop: Platform.OS === 'ios' ? 0 : StatusBar.currentHeight }]}>
{cardItemInfo()} <View style={styles.container_body}>
</ImageBackground> <ImageBackground
<ScrollView source={R.images.igBackground}
showsVerticalScrollIndicator={false} style={[styles.background_header, {
style={styles.scroll}> // FIXME: Extend background lên trên để cover status bar
{renderMenuActivity()} paddingTop: Platform.OS === 'ios' ? 50 : (StatusBar.currentHeight || 0) + 10,
{renderMenuStatistics()} }]}
{renderMenuNotification()} >
</ScrollView> <HeaderCus
value={searchText}
onChangeText={onSearchChange}
/>
{cardItemInfo()}
</ImageBackground>
<ScrollView
showsVerticalScrollIndicator={false}
style={styles.scroll}
bounces={false} // OPTIMIZE: Tắt bounce effect
overScrollMode="never" // OPTIMIZE: Android không over scroll
>
{renderMenuActivity()}
{renderMenuStatistics()}
{renderMenuNotification()}
</ScrollView>
</View>
</View> </View>
</SafeAreaView> </TouchableWithoutFeedback>
</TouchableWithoutFeedback> </>
); );
}; };
export default HomeView; export default HomeView;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment