|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
import {
|
|
|
|
View,
|
|
|
|
Text,
|
|
|
|
FlatList,
|
|
|
|
TouchableOpacity,
|
|
|
|
StyleSheet,
|
|
|
|
Image,
|
|
|
|
Dimensions,
|
|
|
|
ListRenderItem,
|
|
|
|
Platform,
|
|
|
|
StatusBar,
|
|
|
|
SafeAreaView,
|
|
|
|
ActivityIndicator
|
|
|
|
} from 'react-native';
|
|
|
|
import fontSize from '../utils/fontsizeUtils';
|
|
|
|
import widthUtils from '../utils/widthUtils';
|
|
|
|
import { categoriesApi, Category } from '../services/api/categories';
|
|
|
|
import { useNavigation } from '@react-navigation/native';
|
|
|
|
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
|
|
|
import { RootStackParamList } from '../navigation/types';
|
|
|
|
|
|
|
|
const { width: SCREEN_WIDTH } = Dimensions.get('window');
|
|
|
|
const MENU_WIDTH = widthUtils(120, 120).width;
|
|
|
|
const AVAILABLE_WIDTH = SCREEN_WIDTH - MENU_WIDTH - 20; // 20 for padding
|
|
|
|
const NUM_COLUMNS = 4;
|
|
|
|
const ITEM_MARGIN = '2.66%';
|
|
|
|
const ITEM_WIDTH = (AVAILABLE_WIDTH / NUM_COLUMNS) - (AVAILABLE_WIDTH * 0.0266);
|
|
|
|
|
|
|
|
|
|
|
|
export const CategoryScreen = () => {
|
|
|
|
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
|
|
|
|
const [mainCategories, setMainCategories] = useState<Category[]>([]);
|
|
|
|
const [subCategories, setSubCategories] = useState<Category[]>([]);
|
|
|
|
const [activeMainCategory, setActiveMainCategory] = useState<number | null>(null);
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const [subLoading, setSubLoading] = useState(false);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
fetchMainCategories();
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (activeMainCategory) {
|
|
|
|
fetchSubCategories(activeMainCategory);
|
|
|
|
}
|
|
|
|
}, [activeMainCategory]);
|
|
|
|
|
|
|
|
const fetchMainCategories = async () => {
|
|
|
|
try {
|
|
|
|
const response = await categoriesApi.getCategories();
|
|
|
|
setMainCategories(response);
|
|
|
|
if (response.length > 0) {
|
|
|
|
setActiveMainCategory(response[0].category_id);
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Error fetching main categories:', error);
|
|
|
|
} finally {
|
|
|
|
setLoading(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const fetchSubCategories = async (parentId: number) => {
|
|
|
|
setSubLoading(true);
|
|
|
|
try {
|
|
|
|
const response = await categoriesApi.getCategory(parentId);
|
|
|
|
if (Array.isArray(response)) {
|
|
|
|
setSubCategories(response);
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Error fetching sub categories:', error);
|
|
|
|
} finally {
|
|
|
|
setSubLoading(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderMainCategoryItem: ListRenderItem<Category> = ({ item }) => (
|
|
|
|
<TouchableOpacity
|
|
|
|
style={[
|
|
|
|
styles.menuItem,
|
|
|
|
item.category_id === activeMainCategory && styles.menuItemActive,
|
|
|
|
]}
|
|
|
|
onPress={() => setActiveMainCategory(item.category_id)}
|
|
|
|
>
|
|
|
|
<Text
|
|
|
|
style={[
|
|
|
|
styles.menuText,
|
|
|
|
item.category_id === activeMainCategory && styles.menuTextActive,
|
|
|
|
]}
|
|
|
|
numberOfLines={1}
|
|
|
|
ellipsizeMode="tail"
|
|
|
|
>
|
|
|
|
{item.name_cn}
|
|
|
|
</Text>
|
|
|
|
</TouchableOpacity>
|
|
|
|
);
|
|
|
|
|
|
|
|
const renderSubCategoryItem: ListRenderItem<Category> = ({ item }) => (
|
|
|
|
<TouchableOpacity
|
|
|
|
style={styles.subCategoryItem}
|
|
|
|
onPress={() => {
|
|
|
|
navigation.navigate('SearchResult', { category_id: item.category_id });
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Image
|
|
|
|
source={item.image ? { uri: item.image } : require('../../assets/img/1034058.png')}
|
|
|
|
style={styles.subCategoryImage}
|
|
|
|
resizeMode="cover"
|
|
|
|
/>
|
|
|
|
<View style={styles.subCategoryInfo}>
|
|
|
|
<Text
|
|
|
|
style={styles.subCategoryName}
|
|
|
|
numberOfLines={2}
|
|
|
|
ellipsizeMode="tail"
|
|
|
|
>
|
|
|
|
{item.name_cn}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
</TouchableOpacity>
|
|
|
|
);
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
return (
|
|
|
|
<View style={styles.loadingContainer}>
|
|
|
|
<ActivityIndicator size="large" color="#e60012" />
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<SafeAreaView style={styles.safeArea}>
|
|
|
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" />
|
|
|
|
<View style={styles.safeAreaContent}>
|
|
|
|
<View style={styles.container}>
|
|
|
|
<View style={styles.leftMenu}>
|
|
|
|
<FlatList
|
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
|
showsHorizontalScrollIndicator={false}
|
|
|
|
|
|
|
|
data={mainCategories}
|
|
|
|
renderItem={renderMainCategoryItem}
|
|
|
|
keyExtractor={(item) => item.category_id.toString()}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
<View style={styles.rightContent}>
|
|
|
|
{subLoading ? (
|
|
|
|
<View style={styles.loadingContainer}>
|
|
|
|
<ActivityIndicator size="large" color="#e60012" />
|
|
|
|
</View>
|
|
|
|
) : (
|
|
|
|
<FlatList
|
|
|
|
data={subCategories}
|
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
|
showsHorizontalScrollIndicator={false}
|
|
|
|
|
|
|
|
renderItem={renderSubCategoryItem}
|
|
|
|
keyExtractor={(item) => item.category_id.toString()}
|
|
|
|
numColumns={NUM_COLUMNS}
|
|
|
|
contentContainerStyle={styles.productGrid}
|
|
|
|
columnWrapperStyle={styles.columnWrapper}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</View>
|
|
|
|
</View>
|
|
|
|
</View>
|
|
|
|
</SafeAreaView>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
|
|
safeArea: {
|
|
|
|
flex: 1,
|
|
|
|
backgroundColor: '#fff',
|
|
|
|
},
|
|
|
|
safeAreaContent: {
|
|
|
|
flex: 1,
|
|
|
|
paddingTop: Platform.OS === 'android' ? 0 : 0,
|
|
|
|
},
|
|
|
|
container: {
|
|
|
|
flex: 1,
|
|
|
|
flexDirection: 'row',
|
|
|
|
},
|
|
|
|
leftMenu: {
|
|
|
|
width: MENU_WIDTH,
|
|
|
|
backgroundColor: '#fff',
|
|
|
|
borderRightWidth: 1,
|
|
|
|
borderColor: '#eee',
|
|
|
|
},
|
|
|
|
menuItem: {
|
|
|
|
paddingVertical: 16,
|
|
|
|
alignItems: 'center',
|
|
|
|
borderBottomWidth: 1,
|
|
|
|
borderColor: '#f0f0f0',
|
|
|
|
},
|
|
|
|
menuItemActive: {
|
|
|
|
backgroundColor: '#f5f5f5',
|
|
|
|
},
|
|
|
|
menuText: {
|
|
|
|
fontSize: fontSize(14),
|
|
|
|
color: '#333',
|
|
|
|
},
|
|
|
|
menuTextActive: {
|
|
|
|
color: '#e60012',
|
|
|
|
fontWeight: 'bold',
|
|
|
|
},
|
|
|
|
rightContent: {
|
|
|
|
flex: 1,
|
|
|
|
backgroundColor: '#ffffff',
|
|
|
|
paddingHorizontal: 10,
|
|
|
|
paddingTop: 12,
|
|
|
|
},
|
|
|
|
productGrid: {
|
|
|
|
paddingBottom: 20,
|
|
|
|
},
|
|
|
|
loadingContainer: {
|
|
|
|
flex: 1,
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
backgroundColor: '#fff',
|
|
|
|
},
|
|
|
|
columnWrapper: {
|
|
|
|
justifyContent: 'flex-start',
|
|
|
|
marginBottom: 15,
|
|
|
|
},
|
|
|
|
subCategoryItem: {
|
|
|
|
width: ITEM_WIDTH,
|
|
|
|
overflow: 'hidden',
|
|
|
|
marginRight: ITEM_MARGIN,
|
|
|
|
},
|
|
|
|
subCategoryImage: {
|
|
|
|
width: '100%',
|
|
|
|
height: ITEM_WIDTH,
|
|
|
|
},
|
|
|
|
subCategoryInfo: {
|
|
|
|
padding: 8,
|
|
|
|
height: 26,
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
},
|
|
|
|
subCategoryName: {
|
|
|
|
fontSize: fontSize(12),
|
|
|
|
color: '#333',
|
|
|
|
textAlign: 'center',
|
|
|
|
},
|
|
|
|
});
|