You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
6.2 KiB
239 lines
6.2 KiB
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 '../types/navigation'; |
|
|
|
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', { keyword: item.name_en.trim() }); |
|
}} |
|
> |
|
<Image |
|
source={item.image_url ? { uri: item.image_url } : 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 |
|
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} |
|
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', |
|
}, |
|
});
|
|
|