Browse Source

添加首页图搜

main
Your Name 3 weeks ago
parent
commit
36a355a817
  1. 3
      .npmrc
  2. 4
      app/screens/CartScreen.tsx
  3. 307
      app/screens/HomeScreen.tsx
  4. 51
      app/screens/MemberScreen/MemberIntroduction.tsx
  5. 944
      app/screens/ProductCard.tsx
  6. 23408
      package-lock.json
  7. 4
      package.json
  8. 4029
      yarn.lock

3
.npmrc

@ -0,0 +1,3 @@
legacy-peer-deps=true
strict-peer-dependencies=false
engine-strict=false

4
app/screens/CartScreen.tsx

@ -35,7 +35,7 @@ import useUserStore from "../store/user";
export const CartScreen = () => { export const CartScreen = () => {
const [cartList, setCartList] = useState<GetCartList[]>([]); const [cartList, setCartList] = useState<GetCartList[]>([]);
const { const {
user: { user_id }, user: { user_id,currency },
} = useUserStore(); } = useUserStore();
const [selectedItems, setSelectedItems] = useState<{ const [selectedItems, setSelectedItems] = useState<{
[key: string]: boolean; [key: string]: boolean;
@ -763,7 +763,7 @@ export const CartScreen = () => {
<View style={styles.productInfoContainer}> <View style={styles.productInfoContainer}>
<View style={styles.productInfoContainer}> <View style={styles.productInfoContainer}>
<Text style={styles.highlightedText1}>{totalAmount}</Text> <Text style={styles.highlightedText1}>{totalAmount}</Text>
<Text style={styles.priceLabel}>FCFA</Text> <Text style={styles.priceLabel}>{currency}</Text>
</View> </View>
<TouchableOpacity <TouchableOpacity
style={styles.submitButtonStyle} style={styles.submitButtonStyle}

307
app/screens/HomeScreen.tsx

@ -9,13 +9,17 @@ import {
Image, Image,
ScrollView, ScrollView,
Modal, Modal,
ImageBackground,
RefreshControl, RefreshControl,
Dimensions, Dimensions,
Animated, Animated,
Platform, Platform,
StatusBar, StatusBar,
SafeAreaView, SafeAreaView,
ViewStyle,
TextStyle,
ImageStyle,
Linking,
Alert,
} from "react-native"; } from "react-native";
import { import {
productApi, productApi,
@ -35,6 +39,8 @@ import CloseIcon from "../components/CloseIcon";
import CheckmarkIcon from "../components/CheckmarkIcon"; import CheckmarkIcon from "../components/CheckmarkIcon";
import { getSubjectTransLanguage } from "../utils/languageUtils"; import { getSubjectTransLanguage } from "../utils/languageUtils";
import useUserStore from "../store/user"; import useUserStore from "../store/user";
import * as ImagePicker from 'expo-image-picker';
import * as FileSystem from 'expo-file-system';
// 为图标定义类型 // 为图标定义类型
type IconProps = { type IconProps = {
name: string; name: string;
@ -200,12 +206,102 @@ const ProductSkeleton = React.memo(() => {
); );
}); });
// Define the styles type to fix TypeScript errors
type StylesType = {
safeArea: ViewStyle;
safeAreaContent: ViewStyle;
container: ViewStyle;
swpImg: ImageStyle;
searchOverlay: ViewStyle;
searchBar: ViewStyle;
searchPlaceholder: TextStyle;
cameraButton: ViewStyle;
bannerContainer: ViewStyle;
leftContainer: ViewStyle;
leftTopItem: ViewStyle;
leftBottomItem: ViewStyle;
rightContainer: ViewStyle;
bannerIcon: ImageStyle;
bigbannerIcon: ImageStyle;
category: ViewStyle;
categoryScrollContainer: ViewStyle;
categoryScroll: ViewStyle;
categoryItem: ViewStyle;
categoryItemActive: ViewStyle;
categoryText: TextStyle;
categoryTextActive: TextStyle;
swiperContainer: ViewStyle;
swiper: ViewStyle;
dot: ViewStyle;
activeDot: ViewStyle;
slide: ViewStyle;
slideImage: ImageStyle;
fadeGradient: ViewStyle;
categoryArrowContainer: ViewStyle;
modalOverlay: ViewStyle;
modalContent: ViewStyle;
modalHeader: ViewStyle;
modalTitleContainer: ViewStyle;
modalTitle: TextStyle;
closeButton: ViewStyle;
closeButtonText: TextStyle;
modalScrollView: ViewStyle;
categoryModalItem: ViewStyle;
categoryModalText: TextStyle;
selectedCategoryText: TextStyle;
subcategoryContainer: ViewStyle;
subcategoryScroll: ViewStyle;
subcategoryContent: ViewStyle;
subcategoryItem: ViewStyle;
subcategoryImagePlaceholder: ViewStyle;
subcategoryText: TextStyle;
productContainer: ViewStyle;
productCardList: ViewStyle;
productCardGroup: ViewStyle;
beautyProductCard1: ViewStyle;
beautyCardContainer1: ViewStyle;
vipButtonContainer: ViewStyle;
vipButton: ViewStyle;
vipButtonText: TextStyle;
vipLabelBold: TextStyle;
beautyProductCard: ViewStyle;
beautyProductTitle: TextStyle;
beautyProductInfoRow: ViewStyle;
flexRowCentered: ViewStyle;
priceContainer: ViewStyle;
highlightedText: TextStyle;
highlightedText1: TextStyle;
priceContainer1: ViewStyle;
priceLabel1: TextStyle;
beautySalesInfo: TextStyle;
indicatorContainer: ViewStyle;
indicator: ViewStyle;
activeIndicator: ViewStyle;
inactiveIndicator: ViewStyle;
skeletonContainer: ViewStyle;
skeletonImage: ViewStyle;
skeletonTitle: ViewStyle;
skeletonPrice: ViewStyle;
skeletonSales: ViewStyle;
shimmer: ViewStyle;
imagePlaceholder: ViewStyle;
productImage: ImageStyle;
imagePickerOverlay: ViewStyle;
imagePickerContent: ViewStyle;
imagePickerOption: ViewStyle;
imagePickerText: TextStyle;
imagePickerDivider: ViewStyle;
imagePickerCancelButton: ViewStyle;
imagePickerCancelText: TextStyle;
};
export const HomeScreen = () => { export const HomeScreen = () => {
const [activeIndex, setActiveIndex] = useState(0); const [activeIndex, setActiveIndex] = useState(0);
const screenWidth = Dimensions.get("window").width; const screenWidth = Dimensions.get("window").width;
const navigation = useNavigation<NativeStackNavigationProp<any>>(); const navigation = useNavigation<NativeStackNavigationProp<any>>();
const { t } = useTranslation(); const { t } = useTranslation();
const [showCategoryModal, setShowCategoryModal] = useState(false); const [showCategoryModal, setShowCategoryModal] = useState(false);
const [showImagePickerModal, setShowImagePickerModal] = useState(false);
const [selectedCategory, setSelectedCategory] = useState("Bijoux"); const [selectedCategory, setSelectedCategory] = useState("Bijoux");
const [selectedHorizontalCategory, setSelectedHorizontalCategory] = const [selectedHorizontalCategory, setSelectedHorizontalCategory] =
useState("Tous"); useState("Tous");
@ -237,6 +333,7 @@ export const HomeScreen = () => {
add: "CompanyScreen", add: "CompanyScreen",
}, },
]; ];
const [galleryUsed, setGalleryUsed] = useState(false); // 标记是否使用过相册
const getProductData = async () => { const getProductData = async () => {
setLoading(true); // 开始加载,显示骨架屏 setLoading(true); // 开始加载,显示骨架屏
try { try {
@ -369,7 +466,7 @@ export const HomeScreen = () => {
resizeMode="cover" resizeMode="cover"
/> />
) : ( ) : (
<View style={[styles.productImage, styles.imagePlaceholder]}> <View style={[styles.productImage as any, styles.imagePlaceholder]}>
<IconComponent name="image-outline" size={24} color="#999" /> <IconComponent name="image-outline" size={24} color="#999" />
</View> </View>
)} )}
@ -438,6 +535,109 @@ export const HomeScreen = () => {
); );
}, []); }, []);
// 清理expo-image-picker临时文件
const cleanupImagePickerCache = async () => {
try {
// 相册选择后清理临时缓存
const cacheDir = `${FileSystem.cacheDirectory}ImagePicker`;
await FileSystem.deleteAsync(cacheDir, { idempotent: true });
console.log('已清理ImagePicker缓存');
// 立即重置状态,无需用户干预
setGalleryUsed(false);
} catch (error) {
console.log('清理缓存错误', error);
}
};
// 处理从相册选择
const handleChooseFromGallery = useCallback(async () => {
console.log('handleChooseFromGallery');
setShowImagePickerModal(false);
// 等待模态窗关闭后再执行
setTimeout(async () => {
try {
// 请求相册权限
const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (permissionResult.status !== 'granted') {
console.log('相册权限被拒绝');
return;
}
// 打开相册
const result = await ImagePicker.launchImageLibraryAsync({
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();
}
} catch (error: any) {
console.error('相册错误:', error);
// 出错时也清理缓存
await cleanupImagePickerCache();
}
}, 500);
}, []);
// 处理相机拍照 - 简化版本,不再需要处理galleryUsed
const handleTakePhoto = useCallback(async () => {
console.log('handleTakePhoto');
setShowImagePickerModal(false);
// 等待模态窗关闭后再执行
setTimeout(async () => {
try {
const permissionResult = await ImagePicker.requestCameraPermissionsAsync();
if (permissionResult.status !== 'granted') {
console.log('相机权限被拒绝');
return;
}
const result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.canceled && result.assets && result.assets.length > 0) {
console.log('拍照成功:', result.assets[0].uri);
// 这里可以添加后续处理代码,如图片上传等
}
// 使用后清理缓存
await cleanupImagePickerCache();
} catch (error: any) {
console.error('相机错误:', error);
// 出错时也清理缓存
await cleanupImagePickerCache();
}
}, 500);
}, []);
// 重置应用状态函数
const resetAppState = useCallback(() => {
// 重置标记
setGalleryUsed(false);
// 清理缓存
cleanupImagePickerCache();
// 提示用户
Alert.alert('已重置', '现在您可以使用相机功能了');
}, []);
// 渲染列表头部内容 // 渲染列表头部内容
const renderHeader = () => ( const renderHeader = () => (
<> <>
@ -495,7 +695,10 @@ export const HomeScreen = () => {
> >
<IconComponent name="search-outline" size={20} color="#999" /> <IconComponent name="search-outline" size={20} color="#999" />
<Text style={styles.searchPlaceholder}></Text> <Text style={styles.searchPlaceholder}></Text>
<TouchableOpacity style={styles.cameraButton}> <TouchableOpacity
style={styles.cameraButton}
onPress={() => setShowImagePickerModal(true)}
>
<IconComponent name="camera-outline" size={24} color="#333" /> <IconComponent name="camera-outline" size={24} color="#333" />
</TouchableOpacity> </TouchableOpacity>
</TouchableOpacity> </TouchableOpacity>
@ -710,12 +913,65 @@ export const HomeScreen = () => {
</View> </View>
</View> </View>
</Modal> </Modal>
{/* Image Picker Modal */}
<Modal
visible={showImagePickerModal}
animationType="slide"
transparent={true}
onRequestClose={() => setShowImagePickerModal(false)}
>
<TouchableOpacity
style={styles.imagePickerOverlay}
activeOpacity={1}
onPress={() => setShowImagePickerModal(false)}
>
<View style={styles.imagePickerContent}>
{!galleryUsed ? (
// 正常状态,显示相机选项
<TouchableOpacity
style={styles.imagePickerOption}
onPress={handleTakePhoto}
>
<IconComponent name="camera-outline" size={24} color="#333" />
<Text style={styles.imagePickerText}></Text>
</TouchableOpacity>
) : (
// 已使用相册状态,显示重置选项
<TouchableOpacity
style={styles.imagePickerOption}
onPress={resetAppState}
>
<IconComponent name="refresh-outline" size={24} color="#333" />
<Text style={styles.imagePickerText}></Text>
</TouchableOpacity>
)}
<View style={styles.imagePickerDivider} />
<TouchableOpacity
style={styles.imagePickerOption}
onPress={handleChooseFromGallery}
>
<IconComponent name="images-outline" size={24} color="#333" />
<Text style={styles.imagePickerText}></Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.imagePickerCancelButton}
onPress={() => setShowImagePickerModal(false)}
>
<Text style={styles.imagePickerCancelText}></Text>
</TouchableOpacity>
</View>
</TouchableOpacity>
</Modal>
</View> </View>
</View> </View>
</SafeAreaView> </SafeAreaView>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create<StylesType>({
safeArea: { safeArea: {
flex: 1, flex: 1,
backgroundColor: '#fff', backgroundColor: '#fff',
@ -1013,8 +1269,8 @@ const styles = StyleSheet.create({
zIndex: 2, zIndex: 2,
}, },
vipButton: { vipButton: {
width: widthUtils(30, 66).width, width: widthUtils(30, 60).width,
height: widthUtils(30, 66).height, height: widthUtils(30, 60).height,
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
backgroundColor: "#3b3b3b", backgroundColor: "#3b3b3b",
@ -1157,4 +1413,43 @@ const styles = StyleSheet.create({
height: "100%", height: "100%",
borderRadius: 10, borderRadius: 10,
}, },
// Image Picker Modal Styles
imagePickerOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'flex-end',
},
imagePickerContent: {
backgroundColor: '#fff',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
paddingTop: 20,
},
imagePickerOption: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 16,
paddingHorizontal: 20,
},
imagePickerText: {
fontSize: fontSize(16),
marginLeft: 12,
color: '#333',
},
imagePickerDivider: {
height: 1,
backgroundColor: '#f0f0f0',
marginHorizontal: 20,
},
imagePickerCancelButton: {
alignItems: 'center',
paddingVertical: 16,
marginTop: 8,
borderTopWidth: 1,
borderTopColor: '#f0f0f0',
},
imagePickerCancelText: {
fontSize: fontSize(16),
color: '#999',
},
}); });

51
app/screens/MemberScreen/MemberIntroduction.tsx

@ -15,7 +15,8 @@ import CrownIcon from "../../components/CrownIcon";
import BookLabIcon from "../../components/BookLabIcon"; import BookLabIcon from "../../components/BookLabIcon";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import useUserStore from "../../store/user"; import useUserStore from "../../store/user";
import BackIcon from "../../components/BackIcon";
type RootStackParamList = { type RootStackParamList = {
Balance: undefined; Balance: undefined;
}; };
@ -26,7 +27,8 @@ export const MemberIntroduction = () => {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<ScrollView <ScrollView
bounces={false} overScrollMode="never" bounces={false}
overScrollMode="never"
style={styles.scrollView} style={styles.scrollView}
contentContainerStyle={{ flexGrow: 1 }} contentContainerStyle={{ flexGrow: 1 }}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
@ -36,12 +38,24 @@ export const MemberIntroduction = () => {
style={styles.timecardWidget} style={styles.timecardWidget}
source={require("../../../assets/img/制作背景图 (1) (2).png")} source={require("../../../assets/img/制作背景图 (1) (2).png")}
resizeMode="stretch" resizeMode="stretch"
></ImageBackground> >
<View style={styles.titleContainer}>
<View style={styles.backIconContainer}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<BackIcon size={20} color="#fff"/>
</TouchableOpacity>
</View>
<Text style={styles.titleHeading}></Text>
</View>
</ImageBackground>
<View style={styles.VipContainer}> <View style={styles.VipContainer}>
<View style={styles.VipContainerTop}> <View style={styles.VipContainerTop}>
<View style={styles.VipContainerBox}> <View style={styles.VipContainerBox}>
<View style={styles.Vip}> <View style={styles.Vip}>
<Text style={styles.VipText}>VIP {userStore.user?.vip_level || 0}</Text> <Text style={styles.VipText}>
VIP {userStore.user?.vip_level || 0}
</Text>
</View> </View>
<View style={styles.VipLine}> <View style={styles.VipLine}>
<View style={styles.lineText}> <View style={styles.lineText}>
@ -509,6 +523,35 @@ const styles = StyleSheet.create({
width: "100%", width: "100%",
height: "100%", height: "100%",
}, },
titleContainer: {
width: "100%",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
position: "absolute",
left: 0,
right: 0,
top: 10,
height: 48,
zIndex: 10,
paddingLeft: 19,
paddingRight: 19,
paddingTop: 10,
paddingBottom: 10,
},
backIconContainer: {
position: "absolute",
left: 19,
top: 10,
zIndex: 11,
},
titleHeading: {
fontWeight: "600",
fontSize: 20,
lineHeight: 16,
fontFamily: "PingFang SC",
color: "#fff",
},
VipContainer: { VipContainer: {
width: widthUtils(400, 400).width, width: widthUtils(400, 400).width,
height: widthUtils(200, 200).height, height: widthUtils(200, 200).height,

944
app/screens/ProductCard.tsx

@ -213,519 +213,521 @@ const ProductCard: React.FC<ProductCardProps> = ({
return ( return (
<View style={styles.wrapper}> <View style={styles.wrapper}>
<View style={styles.container}> <ScrollView style={{flex: 1}}>
<View style={styles.productInfo}> <View style={styles.container}>
<View style={styles.productBigImgBox}> <View style={styles.productInfo}>
<Image source={{ uri: imgTitle }} style={styles.productBigImg} /> <View style={styles.productBigImgBox}>
<View style={styles.cornerView}> <Image source={{ uri: imgTitle }} style={styles.productBigImg} />
<View style={styles.topRightIcon}> <View style={styles.cornerView}>
<XIconTop size={6} /> <View style={styles.topRightIcon}>
</View> <XIconTop size={6} />
<View style={styles.bottomLeftIcon}> </View>
<XIconBottom size={6} /> <View style={styles.bottomLeftIcon}>
</View> <XIconBottom size={6} />
</View>
</View>
<View style={styles.productInfoBox}>
<View style={styles.priceInfo}>
<View style={styles.priceInfoBox}>
<View style={styles.price}>
<Text style={styles.priceInfoText}>{price}</Text>
<Text style={styles.priceInfoTextCon}>FCFA</Text>
</View> </View>
{vip_level > 0 && (
<>
<View style={styles.priceInfoOffer}>
<Image
source={require("../../assets/img/折扣VIP1 (1).png")}
style={styles.priceInfoOfferImg}
/>
<View style={styles.discountTextContainer}>
<Text style={styles.discountText}>-5%</Text>
</View>
</View>
<View style={styles.priceInfoVip}>
<ImageBackground
source={require("../../assets/img/vip1.png")}
style={styles.priceInfoVipImg}
>
<Text style={styles.vipStatusNumeric}>
VIP {vip_level}
</Text>
</ImageBackground>
</View>
</>
)}
</View>
<View style={styles.priceInfoClose}>
<TouchableOpacity onPress={() => onClose()}>
<CloseIcon size={fontSize(20)} />
</TouchableOpacity>
</View> </View>
</View> </View>
<View style={styles.productInfoBox}>
<ScrollView <View style={styles.priceInfo}>
horizontal <View style={styles.priceInfoBox}>
showsHorizontalScrollIndicator={false} <View style={styles.price}>
showsVerticalScrollIndicator={false} <Text style={styles.priceInfoText}>{price}</Text>
style={styles.priceInfoList} <Text style={styles.priceInfoTextCon}>{currency}</Text>
> </View>
{product && {vip_level > 0 && (
product.sale_info && <>
product.sale_info.price_range_list && <View style={styles.priceInfoOffer}>
product.sale_info.price_range_list.length > 0 <Image
? product.sale_info.price_range_list.map((item, index) => { source={require("../../assets/img/折扣VIP1 (1).png")}
return ( style={styles.priceInfoOfferImg}
<View style={styles.priceList} key={index}> />
<View style={styles.priceListBox}> <View style={styles.discountTextContainer}>
<Text style={styles.priceListBoxText}> <Text style={styles.discountText}>-5%</Text>
{item.price}
</Text>
<Text style={styles.priceListBoxTextCon}>FCFA</Text>
</View> </View>
<View style={styles.priceListBoxPie}> </View>
<Text style={styles.priceListBoxListText}> <View style={styles.priceInfoVip}>
&gt;= {item.min_quantity} <Text></Text> <ImageBackground
source={require("../../assets/img/vip1.png")}
style={styles.priceInfoVipImg}
>
<Text style={styles.vipStatusNumeric}>
VIP {vip_level}
</Text> </Text>
</View> </ImageBackground>
</View> </View>
); </>
}) )}
: null} </View>
</ScrollView> <View style={styles.priceInfoClose}>
</View> <TouchableOpacity onPress={() => onClose()}>
</View> <CloseIcon size={fontSize(20)} />
{/* 图片和文字 */} </TouchableOpacity>
{hasImg && groupList.length > 1 && hasImg.has_image && (
<View style={styles.productBox}>
{hasImg && (
<>
<View style={styles.productTit}>
<Text style={styles.productTitText}>
{hasImg.attribute_name} :{" "}
</Text>
<Text style={styles.productTitText}>{size}</Text>
</View> </View>
</View>
<ScrollView
style={styles.productBoxImgList}
horizontal
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
>
{hasImg?.attributes?.map((item, index) => {
return (
<TouchableOpacity
style={[
styles.productBoxImgListBox,
item?.has_color && styles.productBoxImgListBoxActive,
]}
key={index}
onPress={() =>
handleColorSelect(
item?.value || '',
index,
item?.sku_image_url || ''
)
}
>
<Image
source={{ uri: item?.sku_image_url || '' }}
style={styles.productBoxImgListBoxImg}
/>
{(item?.size ?? 0) > 0 && (
<View style={styles.fixedCornerView}>
<Text style={styles.fixedCornerViewText}>
x{item.size}
</Text>
</View>
)}
</TouchableOpacity>
);
})}
</ScrollView>
</>
)}
<View style={styles.productTit}>
<Text style={styles.productTitText}>{sizeTitle}</Text>
</View>
<View style={{ flex: 1 }}>
<ScrollView <ScrollView
style={styles.sizePrice} horizontal
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
style={styles.priceInfoList}
> >
<View style={styles.sizePriceBox}> {product &&
{hasImg && product.sale_info &&
hasImg.attributes product.sale_info.price_range_list &&
?.find((item) => item?.has_color) product.sale_info.price_range_list.length > 0
?.list.map((list, index1) => ( ? product.sale_info.price_range_list.map((item, index) => {
<View style={styles.sizePriceBoxItems} key={index1}> return (
<View style={styles.sizePriceBoxItem}> <View style={styles.priceList} key={index}>
<View style={styles.sizePriceBoxItemTextBox}> <View style={styles.priceListBox}>
{(list?.size ?? 0) > 0 && ( <Text style={styles.priceListBoxText}>
<Text style={styles.selectedNumText}> {item.price}
x{list?.size}
</Text>
)}
<Text style={styles.priceText}>
{list?.offer_price || price || 0}
</Text>
<Text
style={styles.sizePriceBoxItemText}
numberOfLines={1}
ellipsizeMode="tail"
>
{list.attributes?.[0]?.value}
</Text>
</View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text> </Text>
<Text style={styles.priceListBoxTextCon}>{currency}</Text>
</View> </View>
<View style={styles.sizePriceBoxStepForward}> <View style={styles.priceListBoxPie}>
<TouchableOpacity <Text style={styles.priceListBoxListText}>
style={styles.sizePriceBoxStepForwardButton} &gt;= {item.min_quantity} <Text></Text>
onPress={() => </Text>
handleSizeSelect(
list?.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>-</Text>
</TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
value={list?.size?.toString() ?? "0"}
keyboardType="numeric"
onChangeText={(text) =>
handleSizeSelect(
list?.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleSizeSelect(
list?.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View> </View>
</View> </View>
))} );
</View> })
: null}
</ScrollView> </ScrollView>
</View> </View>
</View> </View>
)} {/* 图片和文字 */}
{/* 两个都是文字 */} {hasImg && groupList.length > 1 && hasImg.has_image && (
{hasImg && groupList.length > 1 && !hasImg.has_image && ( <View style={styles.productBox}>
<View style={styles.productBox}> {hasImg && (
<View style={styles.productTit}> <>
<Text style={styles.productTitText}>{hasImg?.attribute_name || ''}</Text> <View style={styles.productTit}>
</View> <Text style={styles.productTitText}>
{hasImg.attribute_name} :{" "}
</Text>
<Text style={styles.productTitText}>{size}</Text>
</View>
{hasImg.attributes?.map((item, index) => { <ScrollView
return ( style={styles.productBoxImgList}
<TouchableOpacity horizontal
style={[ showsHorizontalScrollIndicator={false}
styles.noImgBoxs, showsVerticalScrollIndicator={false}
item?.has_color && styles.productBoxImgListBoxActive, >
]} {hasImg?.attributes?.map((item, index) => {
key={index} return (
onPress={() => { <TouchableOpacity
handleColorSelect(item?.value || '', index, item?.sku_image_url || ''); style={[
}} styles.productBoxImgListBox,
item?.has_color && styles.productBoxImgListBoxActive,
]}
key={index}
onPress={() =>
handleColorSelect(
item?.value || '',
index,
item?.sku_image_url || ''
)
}
>
<Image
source={{ uri: item?.sku_image_url || '' }}
style={styles.productBoxImgListBoxImg}
/>
{(item?.size ?? 0) > 0 && (
<View style={styles.fixedCornerView}>
<Text style={styles.fixedCornerViewText}>
x{item.size}
</Text>
</View>
)}
</TouchableOpacity>
);
})}
</ScrollView>
</>
)}
<View style={styles.productTit}>
<Text style={styles.productTitText}>{sizeTitle}</Text>
</View>
<View style={{ flex: 1 }}>
<ScrollView
style={styles.sizePrice}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
> >
{(item?.size ?? 0) > 0 && ( <View style={styles.sizePriceBox}>
<Text style={styles.selectedNumText}>x{item?.size}</Text> {hasImg &&
)} hasImg.attributes
<Text style={styles.noImgBoxsText}>{item?.value || ''}</Text> ?.find((item) => item?.has_color)
</TouchableOpacity> ?.list.map((list, index1) => (
); <View style={styles.sizePriceBoxItems} key={index1}>
})} <View style={styles.sizePriceBoxItem}>
<View style={styles.sizePriceBoxItemTextBox}>
<View style={styles.productBox}> {(list?.size ?? 0) > 0 && (
<Text style={styles.productTitText}>{sizeTitle}</Text> <Text style={styles.selectedNumText}>
</View> x{list?.size}
<View style={{ flex: 1 }}> </Text>
<ScrollView )}
style={[styles.sizePrice]} <Text style={styles.priceText}>
showsHorizontalScrollIndicator={false} {list?.offer_price || price || 0}
showsVerticalScrollIndicator={false}
>
<View style={styles.sizePriceBox}>
{hasImg &&
hasImg.attributes
?.find((item) => item?.has_color)
?.list.map((list, index1) => (
<View style={styles.sizePriceBoxItems} key={index1}>
<View style={styles.sizePriceBoxItem}>
<View style={styles.sizePriceBoxItemTextBox}>
{(list?.size ?? 0) > 0 && (
<Text style={styles.selectedNumText}>
x{list?.size}
</Text> </Text>
)} <Text
<Text style={styles.priceText}> style={styles.sizePriceBoxItemText}
{list?.offer_price || price || 0} numberOfLines={1}
ellipsizeMode="tail"
>
{list.attributes?.[0]?.value}
</Text>
</View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text> </Text>
<Text </View>
style={styles.sizePriceBoxItemText} <View style={styles.sizePriceBoxStepForward}>
numberOfLines={1} <TouchableOpacity
ellipsizeMode="tail" style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleSizeSelect(
list?.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
> >
{list.attributes?.[0]?.value} <Text>-</Text>
</Text> </TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
value={list?.size?.toString() ?? "0"}
keyboardType="numeric"
onChangeText={(text) =>
handleSizeSelect(
list?.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleSizeSelect(
list?.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View> </View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text>
</View> </View>
<View style={styles.sizePriceBoxStepForward}> ))}
<TouchableOpacity </View>
style={styles.sizePriceBoxStepForwardButton} </ScrollView>
onPress={() => </View>
handleSizeSelect(
list?.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>-</Text>
</TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
value={list?.size?.toString() ?? "0"}
keyboardType="numeric"
onChangeText={(text) =>
handleSizeSelect(
list?.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleSizeSelect(
list?.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View>
</View>
))}
</View>
</ScrollView>
</View> </View>
</View> )}
)} {/* 两个都是文字 */}
{/* 只有一个文字 */} {hasImg && groupList.length > 1 && !hasImg.has_image && (
{noImgList && groupList.length === 1 && !flag && ( <View style={styles.productBox}>
<View style={styles.productBox}> <View style={styles.productTit}>
<View style={styles.productTit}> <Text style={styles.productTitText}>{hasImg?.attribute_name || ''}</Text>
<Text style={styles.productTitText}>{sizeTitle}</Text> </View>
{hasImg.attributes?.map((item, index) => {
return (
<TouchableOpacity
style={[
styles.noImgBoxs,
item?.has_color && styles.productBoxImgListBoxActive,
]}
key={index}
onPress={() => {
handleColorSelect(item?.value || '', index, item?.sku_image_url || '');
}}
>
{(item?.size ?? 0) > 0 && (
<Text style={styles.selectedNumText}>x{item?.size}</Text>
)}
<Text style={styles.noImgBoxsText}>{item?.value || ''}</Text>
</TouchableOpacity>
);
})}
<View style={styles.productBox}>
<Text style={styles.productTitText}>{sizeTitle}</Text>
</View>
<View style={{ flex: 1 }}>
<ScrollView
style={[styles.sizePrice]}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
>
<View style={styles.sizePriceBox}>
{hasImg &&
hasImg.attributes
?.find((item) => item?.has_color)
?.list.map((list, index1) => (
<View style={styles.sizePriceBoxItems} key={index1}>
<View style={styles.sizePriceBoxItem}>
<View style={styles.sizePriceBoxItemTextBox}>
{(list?.size ?? 0) > 0 && (
<Text style={styles.selectedNumText}>
x{list?.size}
</Text>
)}
<Text style={styles.priceText}>
{list?.offer_price || price || 0}
</Text>
<Text
style={styles.sizePriceBoxItemText}
numberOfLines={1}
ellipsizeMode="tail"
>
{list.attributes?.[0]?.value}
</Text>
</View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text>
</View>
<View style={styles.sizePriceBoxStepForward}>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleSizeSelect(
list?.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>-</Text>
</TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
value={list?.size?.toString() ?? "0"}
keyboardType="numeric"
onChangeText={(text) =>
handleSizeSelect(
list?.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleSizeSelect(
list?.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View>
</View>
))}
</View>
</ScrollView>
</View>
</View> </View>
<View style={{ flex: 1 }}> )}
<ScrollView {/* 只有一个文字 */}
style={[styles.sizePrice]} {noImgList && groupList.length === 1 && !flag && (
showsVerticalScrollIndicator={false} <View style={styles.productBox}>
> <View style={styles.productTit}>
{noImgList && <Text style={styles.productTitText}>{sizeTitle}</Text>
noImgList?.map((list, index1) => ( </View>
<View style={styles.sizePriceBoxItems} key={index1}> <View style={{ flex: 1 }}>
<View style={styles.sizePriceBoxItem}> <ScrollView
<View style={styles.sizePriceBoxItemTextBox}> style={[styles.sizePrice]}
{(list?.size ?? 0) > 0 && ( showsVerticalScrollIndicator={false}
<Text style={styles.selectedNumText}> >
x{list?.size} {noImgList &&
noImgList?.map((list, index1) => (
<View style={styles.sizePriceBoxItems} key={index1}>
<View style={styles.sizePriceBoxItem}>
<View style={styles.sizePriceBoxItemTextBox}>
{(list?.size ?? 0) > 0 && (
<Text style={styles.selectedNumText}>
x{list?.size}
</Text>
)}
<Text style={styles.priceText}>
{list?.offer_price || price || 0}
</Text> </Text>
)} <Text
<Text style={styles.priceText}> style={styles.sizePriceBoxItemText}
{list?.offer_price || price || 0} numberOfLines={1}
ellipsizeMode="tail"
>
{list.attributes?.[0]?.value}
</Text>
</View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text> </Text>
<Text </View>
style={styles.sizePriceBoxItemText} <View style={styles.sizePriceBoxStepForward}>
numberOfLines={1} <TouchableOpacity
ellipsizeMode="tail" style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list?.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
> >
{list.attributes?.[0]?.value} <Text>-</Text>
</Text> </TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
value={list?.size?.toString() ?? "0"}
keyboardType="numeric"
onChangeText={(text) =>
handleNoImgSizeSelect(
list?.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list?.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View> </View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text>
</View> </View>
<View style={styles.sizePriceBoxStepForward}> ))}
<TouchableOpacity </ScrollView>
style={styles.sizePriceBoxStepForwardButton} </View>
onPress={() =>
handleNoImgSizeSelect(
list?.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>-</Text>
</TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
value={list?.size?.toString() ?? "0"}
keyboardType="numeric"
onChangeText={(text) =>
handleNoImgSizeSelect(
list?.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list?.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View>
</View>
))}
</ScrollView>
</View> </View>
</View> )}
)}
{/* 只有图片 */} {/* 只有图片 */}
{noImgList && groupList.length === 1 && flag && ( {noImgList && groupList.length === 1 && flag && (
<View style={styles.productBox}> <View style={styles.productBox}>
<View style={styles.productTit}> <View style={styles.productTit}>
<Text style={styles.productTitText}>{sizeTitle}</Text> <Text style={styles.productTitText}>{sizeTitle}</Text>
</View> </View>
<View style={{ flex: 1 }}> <View style={{ flex: 1 }}>
<ScrollView <ScrollView
style={[styles.sizePrice]} style={[styles.sizePrice]}
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
> >
{noImgList.map((list, index1) => ( {noImgList.map((list, index1) => (
<View style={styles.allImageBox} key={index1}> <View style={styles.allImageBox} key={index1}>
<View style={styles.allImageBoxImg}> <View style={styles.allImageBoxImg}>
<Image <Image
source={{ uri: list.attributes?.[0]?.sku_image_url }} source={{ uri: list.attributes?.[0]?.sku_image_url }}
style={styles.allImageBoxImgImg} style={styles.allImageBoxImgImg}
/> />
</View> </View>
<View style={styles.allImageBoxList}> <View style={styles.allImageBoxList}>
<View style={styles.allImageBoxListBox}> <View style={styles.allImageBoxListBox}>
<View <View
style={{ flexDirection: "row", alignItems: "center" }} style={{ flexDirection: "row", alignItems: "center" }}
>
<Text
style={{
fontSize: fontSize(16),
fontWeight: "700",
fontFamily: "Segoe UI",
color: "red",
marginRight: 5,
}}
> >
{list?.offer_price || price || 0} <Text
style={{
fontSize: fontSize(16),
fontWeight: "700",
fontFamily: "Segoe UI",
color: "red",
marginRight: 5,
}}
>
{list?.offer_price || price || 0}
</Text>
<Text
style={styles.allImageBoxListBoxText}
numberOfLines={1}
ellipsizeMode="tail"
>
{list.attributes?.[0]?.value}
</Text>
</View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text> </Text>
<Text </View>
style={styles.allImageBoxListBoxText} <View style={styles.allImageBoxListStop}>
numberOfLines={1} <TouchableOpacity
ellipsizeMode="tail" style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
> >
{list.attributes?.[0]?.value} <Text>-</Text>
</Text> </TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
keyboardType="numeric"
value={list?.size?.toString() ?? "0"}
onChangeText={(text) =>
handleNoImgSizeSelect(
list.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View> </View>
<Text style={styles.amountText}>
{list?.amount_on_sale ?? 0}
</Text>
</View>
<View style={styles.allImageBoxListStop}>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list.attributes?.[0]?.value,
"-",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>-</Text>
</TouchableOpacity>
<TextInput
style={styles.sizePriceBoxStepForwardInput}
keyboardType="numeric"
value={list?.size?.toString() ?? "0"}
onChangeText={(text) =>
handleNoImgSizeSelect(
list.attributes?.[0]?.value,
text,
index1,
list?.amount_on_sale ?? 0
)
}
/>
<TouchableOpacity
style={styles.sizePriceBoxStepForwardButton}
onPress={() =>
handleNoImgSizeSelect(
list.attributes?.[0]?.value,
"+",
index1,
list?.amount_on_sale ?? 0
)
}
>
<Text>+</Text>
</TouchableOpacity>
</View> </View>
</View> </View>
</View> ))}
))} </ScrollView>
</ScrollView> </View>
</View> </View>
</View> )}
)} </View>
</View> </ScrollView>
<View style={styles.fixedBottomView}> <View style={styles.fixedBottomView}>
<View style={styles.fixedBottomViewBox}> <View style={styles.fixedBottomViewBox}>
@ -738,7 +740,7 @@ const ProductCard: React.FC<ProductCardProps> = ({
<View style={styles.fixedBottomViewBoxRight}> <View style={styles.fixedBottomViewBoxRight}>
<Text style={styles.fixedBottomViewBoxRightText}>:</Text> <Text style={styles.fixedBottomViewBoxRightText}>:</Text>
<Text style={styles.fixedBottomViewBoxPriceText}> <Text style={styles.fixedBottomViewBoxPriceText}>
{totalPrice.toFixed(2)} FCFA {totalPrice.toFixed(2)} {currency}
</Text> </Text>
</View> </View>
</View> </View>

23408
package-lock.json generated

File diff suppressed because it is too large Load Diff

4
package.json

@ -26,6 +26,7 @@
"expo-auth-session": "~6.0.3", "expo-auth-session": "~6.0.3",
"expo-build-properties": "~0.13.3", "expo-build-properties": "~0.13.3",
"expo-image": "~2.0.7", "expo-image": "~2.0.7",
"expo-image-picker": "^16.1.4",
"expo-linear-gradient": "~14.0.2", "expo-linear-gradient": "~14.0.2",
"expo-localization": "^16.0.1", "expo-localization": "^16.0.1",
"expo-random": "^14.0.1", "expo-random": "^14.0.1",
@ -72,5 +73,8 @@
"react-native-svg-transformer": "^1.5.0", "react-native-svg-transformer": "^1.5.0",
"typescript": "^5.3.3" "typescript": "^5.3.3"
}, },
"resolutions": {
"expo": "~52.0.41"
},
"private": true "private": true
} }

4029
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save