diff --git a/app/screens/ProductDetailScreen.tsx b/app/screens/ProductDetailScreen.tsx index 5443d71..dacfc39 100644 --- a/app/screens/ProductDetailScreen.tsx +++ b/app/screens/ProductDetailScreen.tsx @@ -16,7 +16,7 @@ import { Platform, StatusBar, SafeAreaView, - Modal + Modal, } from "react-native"; import fontSize from "../utils/fontsizeUtils"; import widthUtils from "../utils/widthUtils"; @@ -29,13 +29,12 @@ import HeartRedIcon from "../components/HeartIconRed"; import ShareIcon from "../components/ShareIcon"; import { Image as ExpoImage, ImageBackground } from "expo-image"; import useUserStore from "../store/user"; -import { getSubjectTransLanguage } from "../utils/languageUtils"; +import { getSubjectTransLanguage,getSkuTransLanguage } from "../utils/languageUtils"; import { useTranslation } from "react-i18next"; import { getBurialPointData } from "../store/burialPoint"; import useBurialPointStore from "../store/burialPoint"; import * as ImagePicker from "expo-image-picker"; import * as FileSystem from "expo-file-system"; - import { productApi, ProductDetailParams, @@ -91,18 +90,18 @@ export const ProductDetailScreen = () => { // 遍历数据 res.skus.forEach((item) => { item.attributes.forEach((attribute) => { - const { attribute_name, value } = attribute; + const { attribute_name_trans, value } = attribute; // 如果结果对象中没有对应的属性名,则创建一个空数组 - if (!result[attribute_name]) { - result[attribute_name] = []; + if (!result[attribute_name_trans]) { + result[attribute_name_trans] = []; } // 如果当前属性的值(value)已经存在于该组内,跳过 if ( - !result[attribute_name].some( + !result[attribute_name_trans].some( (existingAttribute: any) => existingAttribute.value === value ) ) { - result[attribute_name].push(attribute); + result[attribute_name_trans].push(attribute); } }); }); @@ -128,7 +127,10 @@ export const ProductDetailScreen = () => { // Add has_image to the list item list.push({ attribute_name: attributeName, - has_image: withImage.length > 0, // If there are any items with images, set has_image to true + attribute_name_trans: attributeName, + attribute_name_trans_ar: attributeName, + attribute_name_trans_en: attributeName, + has_image: withImage.length > 0, attributes: [...withImage, ...withoutImage], }); } @@ -325,9 +327,9 @@ export const ProductDetailScreen = () => { imageUrls.length > 5 ? imageUrls.slice(0, 5) : imageUrls; setImageUrls(limitedImageUrls); setGroupList(list); - - const previousScreen = navigation.getState().routes[navigation.getState().index - 1]; + const previousScreen = + navigation.getState().routes[navigation.getState().index - 1]; const data = { offer_id: res.offer_id, category_id: res.category_id, @@ -337,12 +339,9 @@ export const ProductDetailScreen = () => { product_name: res.subject, product_img: res.product_image_urls[0], timestamp: new Date().toISOString(), - } - logViewProduct(data,previousScreen?.name as string); - + }; + logViewProduct(data, previousScreen?.name as string); console.log(getBurialPointData()); - - } catch (error) { console.error("Error fetching product details:", error); } finally { @@ -389,7 +388,6 @@ export const ProductDetailScreen = () => { navigation.navigate("Search"); }, [navigation]); - const handleCameraPress = useCallback(() => { setShowImagePickerModal(true); }, []); @@ -404,36 +402,35 @@ export const ProductDetailScreen = () => { }, [navigation] ); - // Add this function to render skeleton UI const renderSkeletonItems = () => { // Create an array of 5 skeleton items - return Array(5).fill(0).map((_, index) => ( - - - - - + return Array(5) + .fill(0) + .map((_, index) => ( + + + + + + - - )); + )); }; - // 清理expo-image-picker临时文件 const cleanupImagePickerCache = async () => { try { // Skip cache cleanup on web platform - if (Platform.OS === 'web') { - console.log('Cache cleanup skipped on web platform'); + if (Platform.OS === "web") { + console.log("Cache cleanup skipped on web platform"); setGalleryUsed(false); return; } - + // 相册选择后清理临时缓存 const cacheDir = `${FileSystem.cacheDirectory}ImagePicker`; await FileSystem.deleteAsync(cacheDir, { idempotent: true }); console.log("已清理ImagePicker缓存"); - // 立即重置状态,无需用户干预 setGalleryUsed(false); } catch (error) { @@ -442,12 +439,10 @@ export const ProductDetailScreen = () => { setGalleryUsed(false); } }; - // 处理从相册选择 const handleChooseFromGallery = useCallback(async () => { console.log("handleChooseFromGallery"); setShowImagePickerModal(false); - // 等待模态窗关闭后再执行 setTimeout(async () => { try { @@ -458,7 +453,6 @@ export const ProductDetailScreen = () => { console.log("相册权限被拒绝"); return; } - // 打开相册 const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, @@ -466,10 +460,8 @@ export const ProductDetailScreen = () => { aspect: [4, 3], quality: 1, }); - if (!result.canceled && result.assets && result.assets.length > 0) { console.log("相册选择成功:", result.assets[0].uri); - await cleanupImagePickerCache(); navigation.navigate("ImageSearchResultScreen", { image: result.assets[0].uri, @@ -483,12 +475,10 @@ export const ProductDetailScreen = () => { } }, 500); }, [navigation, userStore.user]); - // 处理相机拍照 const handleTakePhoto = useCallback(async () => { console.log("handleTakePhoto"); setShowImagePickerModal(false); - // 等待模态窗关闭后再执行 setTimeout(async () => { try { @@ -498,17 +488,14 @@ export const ProductDetailScreen = () => { console.log("相机权限被拒绝"); return; } - const result = await ImagePicker.launchCameraAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, aspect: [4, 3], quality: 1, }); - if (!result.canceled && result.assets && result.assets.length > 0) { console.log("拍照成功:", result.assets[0].uri); - // 使用后清理缓存 await cleanupImagePickerCache(); navigation.navigate("ImageSearchResultScreen", { @@ -523,19 +510,15 @@ export const ProductDetailScreen = () => { } }, 500); }, [navigation, userStore.user]); - // 重置应用状态函数 const resetAppState = useCallback(() => { // 重置标记 setGalleryUsed(false); - // 清理缓存 cleanupImagePickerCache(); - // 提示用户 Alert.alert("已重置", "现在您可以使用相机功能了"); }, []); - return ( @@ -555,18 +538,17 @@ export const ProductDetailScreen = () => { > - - - + {t("search")} - { @@ -660,7 +642,8 @@ export const ProductDetailScreen = () => { }} > - {activeIndex + 1}/{product?.product_image_urls?.length} + {activeIndex + 1}/ + {product?.product_image_urls?.length} @@ -693,9 +676,10 @@ export const ProductDetailScreen = () => { {userStore.user?.vip_level > 0 && ( <> - -5% + + -5% + - { {groupList.map((item, index) => item.has_image ? ( - + - {item.attribute_name} :{" "} + {item.attribute_name_trans} :{" "} { - item.attributes.find((item) => item.has_color) - ?.value + // getSkuTransLanguage() + item.attributes.find( + (item) => item.has_color + )?.value } {getDisplayAttributes( item.attributes, - item.attribute_name + item.attribute_name_trans ).map((attribute) => ( - handleColorSelect(attribute.value, index) + handleColorSelect( + attribute.value, + index + ) } style={[ styles.colorImageContainer, @@ -740,17 +729,19 @@ export const ProductDetailScreen = () => { ]} > ))} - {!expandedGroups[item.attribute_name] && + {!expandedGroups[item.attribute_name_trans] && item.attributes.length > 6 && ( - toggleExpand(item.attribute_name) + toggleExpand(item.attribute_name_trans) } > @@ -758,11 +749,11 @@ export const ProductDetailScreen = () => { )} - {expandedGroups[item.attribute_name] && ( + {expandedGroups[item.attribute_name_trans] && ( - toggleExpand(item.attribute_name) + toggleExpand(item.attribute_name_trans) } > @@ -793,14 +784,14 @@ export const ProductDetailScreen = () => { )} ) : ( - + - {item.attribute_name} + {item.attribute_name_trans} {getDisplayAttributes( item.attributes, - item.attribute_name + item.attribute_name_trans ).map((attribute) => ( { ))} - {!expandedGroups[item.attribute_name] && + {!expandedGroups[item.attribute_name_trans] && item.attributes.length > 6 && ( - toggleExpand(item.attribute_name) + toggleExpand(item.attribute_name_trans) } > @@ -837,11 +828,11 @@ export const ProductDetailScreen = () => { )} - {expandedGroups[item.attribute_name] && ( + {expandedGroups[item.attribute_name_trans] && ( - toggleExpand(item.attribute_name) + toggleExpand(item.attribute_name_trans) } > @@ -888,31 +879,32 @@ export const ProductDetailScreen = () => { showsHorizontalScrollIndicator={false} contentContainerStyle={styles.productGridContainer} > - {isSimilarsFlag ? - similars?.map((item) => ( - handleProductPress(item)} - > - - - - - - {item.max_price} - - - FCFA - - - - )) - : renderSkeletonItems() - } + {isSimilarsFlag + ? similars?.map((item) => ( + handleProductPress(item)} + > + + + + + + {item.max_price} + + + FCFA + + + + )) + : renderSkeletonItems()} @@ -962,7 +954,7 @@ export const ProductDetailScreen = () => { )} - + {/* Image Picker Modal */} { 重置相机功能 )} - - 从相册选择 - setShowImagePickerModal(false)} @@ -1019,15 +1008,15 @@ export const ProductDetailScreen = () => { const styles = StyleSheet.create({ safeArea: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, safeAreaContent: { flex: 1, - paddingTop: Platform.OS === 'android' ? 0 : 0, + paddingTop: Platform.OS === "android" ? 0 : 0, }, container: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, scrollView: { flex: 1, @@ -1306,7 +1295,7 @@ const styles = StyleSheet.create({ fontSize: fontSize(18), color: "#f1c355", textAlign: "center", - marginLeft:2 + marginLeft: 2, }, emphasizedTextVip: { fontStyle: "italic", @@ -1733,14 +1722,14 @@ const styles = StyleSheet.create({ color: "#666", }, skeletonBox: { - backgroundColor: '#e0e0e0', + backgroundColor: "#e0e0e0", height: widthUtils(90, 90).height, width: widthUtils(90, 90).width, borderRadius: 5, }, skeletonText: { height: 16, - backgroundColor: '#e0e0e0', + backgroundColor: "#e0e0e0", borderRadius: 3, }, imagePickerOverlay: { diff --git a/app/screens/setting/SettingList.tsx b/app/screens/setting/SettingList.tsx index 6e92820..c16eb80 100644 --- a/app/screens/setting/SettingList.tsx +++ b/app/screens/setting/SettingList.tsx @@ -1,4 +1,12 @@ -import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, StatusBar, Platform } from "react-native"; +import { + View, + Text, + StyleSheet, + TouchableOpacity, + SafeAreaView, + StatusBar, + Platform, +} from "react-native"; import BackIcon from "../../components/BackIcon"; import fontSize from "../../utils/fontsizeUtils"; import LeftArrowIcon from "../../components/DownArrowIcon"; @@ -8,24 +16,26 @@ import { useState, useEffect } from "react"; import { settingApi, MySetting } from "../../services/api/setting"; import { RootStackParamList } from "../../navigation/types"; import { eventBus } from "../../utils/eventBus"; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from "@react-native-async-storage/async-storage"; import { useTranslation } from "react-i18next"; +import useUserStore from "../../store/user"; export const SettingList = () => { const { t } = useTranslation(); const [mySetting, setMySetting] = useState(); + const { user } = useUserStore(); const getMySetting = async () => { - const res = await settingApi.getMySetting() - console.log("MySetting:"); - console.log(res); + const res = await settingApi.getMySetting(); setMySetting(res); - } + }; useEffect(() => { - getMySetting(); - const refreshSetting = () => { + if (user?.user_id) { getMySetting(); } + const refreshSetting = () => { + getMySetting(); + }; eventBus.on("refreshSetting", refreshSetting); return () => { eventBus.off("refreshSetting", refreshSetting); @@ -39,15 +49,13 @@ export const SettingList = () => { - navigation.goBack()} - > + navigation.goBack()}> {t("settings.title")} - + {t("settings.profile")} @@ -70,19 +78,19 @@ export const SettingList = () => { - { - if (mySetting?.language && mySetting?.currency) { - navigation.navigate("MyAddress"); - } - }} - style={styles.item} - > - {t("settings.my_address")} - - - - + { + if (mySetting?.language && mySetting?.currency) { + navigation.navigate("MyAddress"); + } + }} + style={styles.item} + > + {t("settings.my_address")} + + + + {t("settings.feedback")} @@ -102,10 +110,13 @@ export const SettingList = () => { - { - AsyncStorage.clear(); - navigation.navigate("CountrySelect"); - }}> + { + AsyncStorage.clear(); + navigation.navigate("CountrySelect"); + }} + > {t("settings.clear_cache")} @@ -115,9 +126,9 @@ export const SettingList = () => { { - // if (mySetting?.language && mySetting?.currency) { - navigation.navigate("CountrySetting", { mySetting }); - // } + // if (mySetting?.language && mySetting?.currency) { + navigation.navigate("CountrySetting", { mySetting }); + // } }} style={styles.item} > @@ -136,7 +147,7 @@ export const SettingList = () => { const styles = StyleSheet.create({ safeArea: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, safeAreaContent: { flex: 1, diff --git a/app/services/api/productApi.ts b/app/services/api/productApi.ts index ae08871..1102af1 100644 --- a/app/services/api/productApi.ts +++ b/app/services/api/productApi.ts @@ -178,6 +178,9 @@ export type Products = Product[] export interface ProductGroupList { attribute_name:string, has_image:boolean, + attribute_name_trans:string, + attribute_name_trans_ar:string, + attribute_name_trans_en:string, attributes:SkuAttribute[], value?:string } diff --git a/app/utils/languageUtils.ts b/app/utils/languageUtils.ts index 486696a..5dab337 100644 --- a/app/utils/languageUtils.ts +++ b/app/utils/languageUtils.ts @@ -30,28 +30,28 @@ export const getSubjectTransLanguage = >(data: T): -// export const getSkuTransLanguage = >(data: T): string => { -// // 获取当前i18n语言 -// const currentLang = getCurrentLanguage(); +export const getSkuTransLanguage = >(data: T): string => { + // 获取当前i18n语言 + const currentLang = getCurrentLanguage(); -// // 特殊处理中文 -// if (currentLang === 'zh' && 'value' in data) { -// return data.value as string; -// } - -// // 获取所有subject_trans开头的字段 -// const translationFields = Object.keys(data).filter(key => -// key.startsWith('value_trans') -// ); - -// // 查找匹配的字段 -// const matchedField = translationFields.find(field => { -// // 从字段名中提取语言代码 -// const langCode = field.replace('value_trans_', ''); -// // 如果没有后缀,则为法语 -// return langCode === '' ? currentLang === 'fr' : langCode === currentLang; -// }); - -// // 返回匹配的翻译值,如果没有匹配则返回法语 -// return (data[matchedField || 'value_trans'] as string) || ''; -// }; + // 特殊处理中文 + if (currentLang === 'zh' && 'value' in data) { + return data.value as string; + } + + // 获取所有subject_trans开头的字段 + const translationFields = Object.keys(data).filter(key => + key.startsWith('value_trans') + ); + + // 查找匹配的字段 + const matchedField = translationFields.find(field => { + // 从字段名中提取语言代码 + const langCode = field.replace('value_trans_', ''); + // 如果没有后缀,则为法语 + return langCode === '' ? currentLang === 'fr' : langCode === currentLang; + }); + + // 返回匹配的翻译值,如果没有匹配则返回法语 + return (data[matchedField || 'value_trans'] as string) || ''; +};