Browse Source

浏览历史和收藏的ui

main
Mac 1 month ago
parent
commit
cec61f7ce0
  1. 38
      App.tsx
  2. 13
      app/components/TiktokIcon.tsx
  3. 179
      app/screens/CategoryScreen.tsx
  4. 1
      app/screens/CountrySelect.tsx
  5. 2
      app/screens/HomeScreen.tsx
  6. 2
      app/screens/MyAccount/myAccount.tsx
  7. 36
      app/screens/ProfileScreen.tsx
  8. 0
      app/screens/banner/InquiryScreen.tsx
  9. 20
      app/screens/banner/ShippingDetailsSection.tsx
  10. 290
      app/screens/banner/TikTokScreen.tsx
  11. 199
      app/screens/function/BrowseHistoryScreen.tsx
  12. 207
      app/screens/function/Collection.tsx
  13. 2
      app/screens/pay/PaySuccess.tsx
  14. 92
      app/screens/setting/MyAddress.tsx
  15. BIN
      assets/img/Mask group (1).png
  16. BIN
      assets/img/Mask group.png
  17. 4
      package-lock.json
  18. 1
      package.json
  19. 1052
      yarn.lock

38
App.tsx

@ -15,9 +15,9 @@ import { SearchScreen } from "./app/screens/SearchScreen";
import { SearchResultScreen } from "./app/screens/SearchResultScreen"; import { SearchResultScreen } from "./app/screens/SearchResultScreen";
import { ProductDetailScreen } from "./app/screens/ProductDetailScreen"; import { ProductDetailScreen } from "./app/screens/ProductDetailScreen";
import { BalanceScreen } from "./app/screens/BalanceScreen"; import { BalanceScreen } from "./app/screens/BalanceScreen";
import { ShippingDetailsSection } from "./app/screens/ShippingDetailsSection"; import { ShippingDetailsSection } from "./app/screens/banner/ShippingDetailsSection";
import { GestureHandlerRootView } from "react-native-gesture-handler"; import { GestureHandlerRootView } from "react-native-gesture-handler";
import { InquiryScreen } from "./app/screens/InquiryScreen/InquiryScreen"; import { InquiryScreen } from "./app/screens/banner/InquiryScreen";
import { Recipient } from "./app/screens/Recipient/Recipient"; import { Recipient } from "./app/screens/Recipient/Recipient";
import { AddRess } from "./app/screens/Recipient/Address"; import { AddRess } from "./app/screens/Recipient/Address";
import { SettingList } from "./app/screens/setting/SettingList"; import { SettingList } from "./app/screens/setting/SettingList";
@ -31,7 +31,9 @@ import { ConfirmOrder } from "./app/screens/Recipient/ConfirmOrder";
import { Pay } from "./app/screens/pay/Pay"; import { Pay } from "./app/screens/pay/Pay";
import { Status } from "./app/screens/productStatus/Status"; import { Status } from "./app/screens/productStatus/Status";
import { OrderDetails } from "./app/screens/productStatus/OrderDatails"; import { OrderDetails } from "./app/screens/productStatus/OrderDatails";
import { TikTokScreen } from "./app/screens/banner/TikTokScreen";
import { BrowseHistoryScreen } from "./app/screens/function/BrowseHistoryScreen";
import { Collection } from "./app/screens/function/Collection";
export type RootStackParamList = { export type RootStackParamList = {
CountrySelect: undefined; CountrySelect: undefined;
MainApp: undefined; MainApp: undefined;
@ -57,6 +59,9 @@ export type RootStackParamList = {
Pay: undefined; Pay: undefined;
Status: undefined; Status: undefined;
OrderDetails: undefined; OrderDetails: undefined;
TikTokScreen: undefined;
BrowseHistoryScreen: undefined;
Collection: undefined;
}; };
const Stack = createNativeStackNavigator<RootStackParamList>(); const Stack = createNativeStackNavigator<RootStackParamList>();
@ -274,6 +279,33 @@ export default function App() {
gestureDirection: "horizontal", gestureDirection: "horizontal",
}} }}
/> />
<Stack.Screen
name="TikTokScreen"
component={TikTokScreen}
options={{
animation: "slide_from_right",
gestureEnabled: true,
gestureDirection: "horizontal",
}}
/>
<Stack.Screen
name="BrowseHistoryScreen"
component={BrowseHistoryScreen}
options={{
animation: "slide_from_right",
gestureEnabled: true,
gestureDirection: "horizontal",
}}
/>
<Stack.Screen
name="Collection"
component={Collection}
options={{
animation: "slide_from_right",
gestureEnabled: true,
gestureDirection: "horizontal",
}}
/>
</Stack.Navigator> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
</AuthProvider> </AuthProvider>

13
app/components/TiktokIcon.tsx

@ -0,0 +1,13 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const TiktokIcon = ({color,size}:{color:string,size:number}) => (
<Svg width={size} height={size} viewBox="0 0 22 22" fill="none">
<Path
d="M17.4167 9.53425C16.0839 9.53425 14.7492 9.11533 13.6676 8.27842V13.9737C13.6676 16.8208 11.4997 19.25 8.66625 19.25C5.83283 19.25 3.66675 16.9052 3.66675 13.9737C3.66675 11.0422 5.83375 8.69642 8.66716 8.69642C8.9165 8.69642 9.25016 8.69642 9.50041 8.78075V11.7957C9.25016 11.7122 8.99991 11.6279 8.66625 11.6279C7.41683 11.6279 6.50016 12.7169 6.50016 13.8893C6.50016 15.2295 7.49933 16.1508 8.66716 16.1508C9.83316 16.1508 10.8332 15.0618 10.8332 13.8893V2.75H13.5832C13.5832 4.928 15.2497 6.68617 17.2499 6.68617L17.4167 9.53425Z"
fill={color}
/>
</Svg>
);
export default TiktokIcon;

179
app/screens/CategoryScreen.tsx

@ -1,71 +1,162 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, Modal, TouchableOpacity, Dimensions } from 'react-native'; import {
View,
Text,
FlatList,
TouchableOpacity,
StyleSheet,
Image,
Dimensions,
ListRenderItem,
} from 'react-native';
import fontSize from '../utils/fontsizeUtils';
import widthUtils from '../utils/widthUtils';
export const CategoryScreen = () => { type Category = {
const [isModalVisible, setIsModalVisible] = useState(false); id: string;
name: string;
};
const toggleModal = () => { type Product = {
setIsModalVisible(!isModalVisible); name: string;
img: string;
}; };
return ( const categories: Category[] = [
<View style={styles.container}> { id: 'fruit', name: '水果' },
<Button title="Category Screen" onPress={toggleModal} /> { id: 'snacks', name: '零食' },
{ id: 'clothes', name: '服饰' },
{ id: 'home', name: '家居' },
];
<Modal const productsData: Record<string, Product[]> = {
visible={isModalVisible} fruit: [
transparent={true} { name: '苹果', img: 'https://via.placeholder.com/100?text=苹果' },
animationType="slide" { name: '香蕉', img: 'https://via.placeholder.com/100?text=香蕉' },
onRequestClose={toggleModal} { name: '西瓜', img: 'https://via.placeholder.com/100?text=西瓜' },
> ],
snacks: [
{ name: '薯片', img: 'https://via.placeholder.com/100?text=薯片' },
{ name: '饼干', img: 'https://via.placeholder.com/100?text=饼干' },
{ name: '巧克力', img: 'https://via.placeholder.com/100?text=巧克力' },
],
clothes: [
{ name: 'T恤', img: 'https://via.placeholder.com/100?text=T恤' },
{ name: '牛仔裤', img: 'https://via.placeholder.com/100?text=牛仔裤' },
{ name: '外套', img: 'https://via.placeholder.com/100?text=外套' },
],
home: [
{ name: '毛巾fdfd一定要人盯人一天的玉兔捣药', img: 'https://via.placeholder.com/100?text=毛巾' },
{ name: '椅子', img: 'https://via.placeholder.com/100?text=椅子' },
{ name: '灯具', img: 'https://via.placeholder.com/100?text=灯具' },
],
};
export function CategoryScreen() {
const [activeCategory, setActiveCategory] = useState<string>('fruit');
const renderCategoryItem: ListRenderItem<Category> = ({ item }) => (
<TouchableOpacity <TouchableOpacity
style={styles.modalOverlay} style={[
activeOpacity={1} styles.menuItem,
onPress={toggleModal} item.id === activeCategory && styles.menuItemActive,
]}
onPress={() => setActiveCategory(item.id)}
> >
<View style={styles.modalContent}> <Text
<View style={styles.modalHeader}> style={[
<View style={styles.modalHandle} /> styles.menuText,
item.id === activeCategory && styles.menuTextActive,
]}
numberOfLines={1}
ellipsizeMode="tail"
>
{item.name}
</Text>
</TouchableOpacity>
);
const renderProductItem: ListRenderItem<Product> = ({ item }) => (
<View style={styles.productCard}>
<Image source={{ uri: item.img }} style={styles.productImage} />
<Text style={styles.productName} numberOfLines={1} ellipsizeMode="tail">{item.name}</Text>
</View>
);
return (
<View style={styles.container}>
<View style={styles.leftMenu}>
<FlatList
data={categories}
renderItem={renderCategoryItem}
keyExtractor={(item) => item.id}
/>
</View> </View>
{/* 这里可以添加模态框的内容 */} <View style={styles.rightContent}>
<FlatList
data={productsData[activeCategory]}
renderItem={renderProductItem}
keyExtractor={(_, index) => `${activeCategory}-${index}`}
numColumns={3}
contentContainerStyle={styles.productGrid}
/>
</View> </View>
</TouchableOpacity>
</Modal>
</View> </View>
); );
}; }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
justifyContent: 'center', flexDirection: 'row',
alignItems: 'center', },
leftMenu: {
width: widthUtils(100,100).width,
backgroundColor: '#fff', backgroundColor: '#fff',
borderRightWidth: 1,
borderColor: '#eee',
}, },
text: { menuItem: {
fontSize: 20, paddingVertical: 16,
alignItems: 'center',
borderBottomWidth: 1,
borderColor: '#f0f0f0',
},
menuItemActive: {
backgroundColor: '#f5f5f5',
},
menuText: {
fontSize: fontSize(14),
color: '#333', color: '#333',
}, },
modalOverlay: { menuTextActive: {
color: '#e60012',
fontWeight: 'bold',
},
rightContent: {
flex: 1, flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)', backgroundColor: '#f8f8f8',
justifyContent: 'flex-end', paddingHorizontal: 10,
paddingTop: 12,
}, },
modalContent: { productGrid: {
height: '70%', paddingBottom: 20,
backgroundColor: 'white',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
padding: 20,
}, },
modalHeader: { productCard: {
flexBasis: '33.33%',
padding: 6,
alignItems: 'center', alignItems: 'center',
paddingBottom: 10,
}, },
modalHandle: { productImage: {
width: 40, width: '100%',
height: 4, aspectRatio: 1,
backgroundColor: '#ccc', borderRadius: 6,
borderRadius: 2, backgroundColor: '#eee',
},
productName: {
fontSize: fontSize(13),
color: '#333',
marginTop: 6,
textAlign: 'center',
}, },
}); });

1
app/screens/CountrySelect.tsx

@ -1,3 +1,4 @@
// 国家选择
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
View, View,

2
app/screens/HomeScreen.tsx

@ -317,7 +317,7 @@ export const HomeScreen = () => {
style={styles.bannerIcon} style={styles.bannerIcon}
/> />
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.leftBottomItem}> <TouchableOpacity style={styles.leftBottomItem} onPress={() => navigation.navigate("TikTokScreen")}>
<Image <Image
source={require("../../assets/img/a_tiktok.png")} source={require("../../assets/img/a_tiktok.png")}
style={styles.bannerIcon} style={styles.bannerIcon}

2
app/screens/MyAccount/myAccount.tsx

@ -171,7 +171,7 @@ export function MyAccount() {
<View style={styles.FeaturesHeader}> <View style={styles.FeaturesHeader}>
<View> <View>
<MyFavoriteIcon size={20}/> <MyFavoriteIcon size={20} color="#707070"/>
</View> </View>
<View style={styles.FeaturesHeaderItem}> <View style={styles.FeaturesHeaderItem}>
<Text style={styles.FeaturesHeaderItemText}>My Favorite</Text> <Text style={styles.FeaturesHeaderItemText}>My Favorite</Text>

36
app/screens/ProfileScreen.tsx

@ -26,7 +26,11 @@ type RootStackParamList = {
Home: undefined; Home: undefined;
MyAccount: undefined; MyAccount: undefined;
Login: undefined; Login: undefined;
Status: { status: number }; Status: { status: number | null };
BrowseHistoryScreen: undefined;
MyAddress: undefined;
Collection: undefined;
Balance: undefined;
}; };
export const ProfileScreen = () => { export const ProfileScreen = () => {
@ -103,7 +107,7 @@ export const ProfileScreen = () => {
ID: {userInfo?.user_id} ID: {userInfo?.user_id}
</Text> </Text>
</View> </View>
<TouchableOpacity style={styles.transactionSummaryBox} onPress={() => navigation.navigate("MyAccount")}> <TouchableOpacity style={styles.transactionSummaryBox} onPress={() => navigation.navigate("Balance")}>
<View style={styles.svgContainer}> <View style={styles.svgContainer}>
<BookmarkIcon size={fontSize(24)} /> <BookmarkIcon size={fontSize(24)} />
</View> </View>
@ -155,10 +159,10 @@ export const ProfileScreen = () => {
<Text style={styles.groupItemTitleText}> <Text style={styles.groupItemTitleText}>
Mes commandes en cours Mes commandes en cours
</Text> </Text>
<View style={styles.groupItemTitleTextTout}> <TouchableOpacity style={styles.groupItemTitleTextTout} onPress={() => navigation.navigate("Status",{status:null})}>
<Text style={styles.groupItemTitleTextTout1}>tout</Text> <Text style={styles.groupItemTitleTextTout1}>tout</Text>
<LeftArrowIcon size={fontSize(14)} color="#8f8684" /> <LeftArrowIcon size={fontSize(14)} color="#8f8684" />
</View> </TouchableOpacity>
</View> </View>
<View style={styles.groupItem}> <View style={styles.groupItem}>
@ -186,30 +190,24 @@ export const ProfileScreen = () => {
<View style={styles.groupItem}> <View style={styles.groupItem}>
<View style={styles.groupItemContent}> <View style={styles.groupItemContent}>
<View style={styles.groupItemContentIcon}> <TouchableOpacity style={styles.groupItemContentIcon} onPress={() => navigation.navigate("BrowseHistoryScreen")}>
<DocumentApprovedIcon size={fontSize(38)} color="#707070" /> <DocumentApprovedIcon size={fontSize(38)} color="#707070" />
</View> </TouchableOpacity>
<Text style={styles.groupItemContentText}></Text> <Text style={styles.groupItemContentText}></Text>
</View> </View>
<View style={styles.groupItemContent}> <View style={styles.groupItemContent}>
<View style={styles.groupItemContentIcon}> <TouchableOpacity style={styles.groupItemContentIcon} onPress={() => navigation.navigate("Collection")}>
<PdfDocumentIcon size={fontSize(38)} color="#707070" /> <PdfDocumentIcon size={fontSize(38)} color="#707070" />
</TouchableOpacity>
<Text style={styles.groupItemContentText}></Text>
</View> </View>
<Text style={styles.groupItemContentText}></Text> <TouchableOpacity style={styles.groupItemContent} onPress={() => navigation.navigate("MyAddress")}>
</View>
<View style={styles.groupItemContent}>
<View style={styles.groupItemContentIcon}>
<DocumentClockIcon size={fontSize(38)} color="#707070" />
</View>
<Text style={styles.groupItemContentText}></Text>
</View>
<View style={styles.groupItemContent}>
<View style={styles.groupItemContentIcon}> <View style={styles.groupItemContentIcon}>
<DocumentClockIcon size={fontSize(38)} color="#707070" /> <DocumentClockIcon size={fontSize(38)} color="#707070" />
</View> </View>
<Text style={styles.groupItemContentText}></Text> <Text style={styles.groupItemContentText}></Text>
</View> </TouchableOpacity>
</View> </View>
</View> </View>
</View> </View>

0
app/screens/InquiryScreen/InquiryScreen.tsx → app/screens/banner/InquiryScreen.tsx

20
app/screens/ShippingDetailsSection.tsx → app/screens/banner/ShippingDetailsSection.tsx

@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { View, Text, Image, TouchableOpacity, StyleSheet, ImageBackground, ActivityIndicator } from 'react-native'; import { View, Text, Image, TouchableOpacity, StyleSheet, ImageBackground, ActivityIndicator } from 'react-native';
import BackIcon from '../components/BackIcon'; import BackIcon from '../../components/BackIcon';
import fontSize from '../utils/fontsizeUtils'; import fontSize from '../../utils/fontsizeUtils';
import widthUtils from '../utils/widthUtils'; import widthUtils from '../../utils/widthUtils';
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';
@ -25,8 +25,8 @@ export const ShippingDetailsSection = () => {
const preloadImages = async () => { const preloadImages = async () => {
try { try {
await Promise.all([ await Promise.all([
Image.prefetch(Image.resolveAssetSource(require('../../assets/img/image_f67fe9bc.png')).uri), Image.prefetch(Image.resolveAssetSource(require('../../../assets/img/image_f67fe9bc.png')).uri),
Image.prefetch(Image.resolveAssetSource(require('../../assets/img/feijiback.png')).uri) Image.prefetch(Image.resolveAssetSource(require('../../../assets/img/feijiback.png')).uri)
]); ]);
setIsLoading(false); setIsLoading(false);
} catch (error) { } catch (error) {
@ -45,8 +45,8 @@ export const ShippingDetailsSection = () => {
// Get background image based on shipping method // Get background image based on shipping method
const getBackgroundImage = () => { const getBackgroundImage = () => {
return shippingMethod === 'maritime' return shippingMethod === 'maritime'
? require('../../assets/img/image_f67fe9bc.png') ? require('../../../assets/img/image_f67fe9bc.png')
: require('../../assets/img/feijiback.png'); : require('../../../assets/img/feijiback.png');
}; };
return ( return (
@ -92,7 +92,7 @@ export const ShippingDetailsSection = () => {
> >
<View style={styles.svgContainer1}> <View style={styles.svgContainer1}>
<Image <Image
source={require('../../assets/img/海运 (1) 1.png')} source={require('../../../assets/img/海运 (1) 1.png')}
style={{width: widthUtils(24, 24).width, height: widthUtils(24, 24).height, style={{width: widthUtils(24, 24).width, height: widthUtils(24, 24).height,
tintColor: shippingMethod === 'maritime' ? '#fff' : '#747474'}} tintColor: shippingMethod === 'maritime' ? '#fff' : '#747474'}}
/> />
@ -113,7 +113,7 @@ export const ShippingDetailsSection = () => {
> >
<View style={styles.svgContainer2}> <View style={styles.svgContainer2}>
<Image <Image
source={require('../../assets/img/空运 1.png')} source={require('../../../assets/img/空运 1.png')}
style={{width: widthUtils(24, 24).width, height: widthUtils(24, 24).height, tintColor: shippingMethod === 'airway' ? '#fff' : '#747474'}} style={{width: widthUtils(24, 24).width, height: widthUtils(24, 24).height, tintColor: shippingMethod === 'airway' ? '#fff' : '#747474'}}
/> />
</View> </View>
@ -171,7 +171,7 @@ const styles = StyleSheet.create({
}, },
contentContainer: { contentContainer: {
flex: 1, flex: 1,
padding: 20, padding: 15,
}, },
timeShippingSection: { timeShippingSection: {
flexDirection: 'column', flexDirection: 'column',

290
app/screens/banner/TikTokScreen.tsx

@ -0,0 +1,290 @@
import {
View,
Text,
StyleSheet,
ImageBackground,
Dimensions,
ScrollView,
} from "react-native";
import BackIcon from "../../components/BackIcon";
import fontSize from "../../utils/fontsizeUtils";
import TiktokIcon from "../../components/TiktokIcon";
import widthUtils from "../../utils/widthUtils";
import Carousel from "react-native-reanimated-carousel";
import { useState } from "react";
export const TikTokScreen = () => {
const { width: screenWidth } = Dimensions.get("window");
const [currentIndex, setCurrentIndex] = useState(0);
const carouselItems = [
{
id: 1,
image: require("../../../assets/img/Mask group.png"),
liveText: "视频",
subTitle: "LIVE",
},
{
id: 2,
image: require("../../../assets/img/Mask group (1).png"),
liveText: "LIVE",
subTitle: "SHORTS",
},
];
const renderItem = ({ item }: { item: (typeof carouselItems)[0] }) => {
return (
<View style={styles.maskGroup}>
<ImageBackground
source={item.image}
style={styles.maskGroupImage}
resizeMode="contain"
>
<View style={styles.content}>
<View style={styles.titleContainer}>
<View style={styles.titleLogo}>
<TiktokIcon color="#fff" size={22} />
<Text style={styles.tikTokText}>TikTok</Text>
<Text style={styles.LiveText}>{item.liveText}</Text>
</View>
<View style={styles.titleText}>
<Text style={styles.titleTextTitle}>Section</Text>
<Text style={styles.titleTextSubTitle}>{item.subTitle}</Text>
</View>
</View>
</View>
</ImageBackground>
</View>
);
};
const onSnapToItem = (index: number) => {
setCurrentIndex(index);
};
return (
<View style={styles.container}>
<View style={styles.header}>
<BackIcon color="#fff" />
<Text style={styles.title}> tiktok</Text>
</View>
<View style={styles.maskGroup}>
<Carousel
data={carouselItems}
renderItem={renderItem}
width={screenWidth}
loop={true}
autoPlayInterval={3000}
onSnapToItem={onSnapToItem}
/>
<View
style={[styles.Instruction, { top: widthUtils(210, 210).height }]}
>
<View
style={[
styles.instructionLine1,
currentIndex === 0 && styles.instructionLine3,
]}
/>
<View
style={[
styles.instructionLine2,
currentIndex === 1 && styles.instructionLine3,
]}
/>
</View>
</View>
<ScrollView
style={styles.productContainer}
showsVerticalScrollIndicator={false}
>
<View style={styles.productList}>
<View style={styles.productItem}>
<View style={styles.productItemImage}></View>
<View style={styles.productItemInfo}>
<View style={styles.priceInfo}></View>
<View style={styles.priceTitle}>
<Text
style={styles.priceTitleText}
numberOfLines={2}
ellipsizeMode="tail"
>1231231131231231221323123123123123123123123121231231212311232</Text>
</View>
<View style={styles.ventes}></View>
</View>
</View>
</View>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
width: "100%",
padding: 19,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
position: "absolute",
top: 0,
left: 0,
zIndex: 1,
},
title: {
color: "#fff",
fontSize: fontSize(22),
fontWeight: "700",
textAlign: "center",
flex: 1,
},
maskGroup: {
width: "100%",
height: widthUtils(321, 321).height,
backgroundColor: "#000",
position: "relative",
top: 0,
left: 0,
},
maskGroupImage: {
width: "100%",
height: "100%",
resizeMode: "contain",
},
content: {
width: "100%",
flex: 1,
justifyContent: "center",
},
titleContainer: {
width: "100%",
alignItems: "center",
},
titleLogo: {
width: "100%",
paddingLeft: 22,
paddingRight: 22,
flexDirection: "row",
alignItems: "center",
},
tikTokText: {
color: "#fff",
fontSize: fontSize(26),
fontWeight: "600",
},
LiveText: {
marginLeft: 5,
backgroundColor: "#ff188a",
paddingLeft: 5,
paddingRight: 5,
fontSize: fontSize(16),
fontWeight: "600",
color: "#fff",
},
titleText: {
width: "100%",
paddingTop: widthUtils(19, 19).height,
paddingBottom: widthUtils(19, 19).height,
paddingLeft: widthUtils(22, 22).height,
paddingRight: widthUtils(22, 22).height,
},
Instruction: {
width: "100%",
paddingTop: widthUtils(19, 19).height,
paddingBottom: widthUtils(19, 19).height,
paddingLeft: widthUtils(22, 22).height,
paddingRight: widthUtils(22, 22).height,
flexDirection: "row",
gap: 6,
position: "absolute",
bottom: widthUtils(50, 50).height,
left: 0,
zIndex: 2,
},
instructionLine1: {
width: 10,
height: 6,
backgroundColor: "#52595f",
borderRadius: 10,
},
instructionLine2: {
width: 10,
height: 6,
backgroundColor: "#52595f",
borderRadius: 10,
},
instructionLine3: {
width: 20,
height: 6,
backgroundColor: "#ffff",
borderRadius: 10,
},
titleTextTitle: {
color: "#fff",
fontSize: fontSize(26),
fontWeight: "900",
fontFamily: "Montserrat-Bold",
},
titleTextSubTitle: {
color: "#fff",
fontSize: fontSize(30),
fontWeight: "900",
fontFamily: "Montserrat-Bold",
},
productContainer: {
flex: 1,
width: "100%",
position: "absolute",
top: widthUtils(321, 321).height,
left: 0,
right: 0,
bottom: 0,
zIndex: 1,
backgroundColor: "#000",
marginTop: -10,
paddingLeft: 19,
paddingRight: 19,
},
productList: {
width: "100%",
flexDirection: "row",
flexWrap: "wrap",
gap: 10,
},
productItem: {
width: "48%",
height: widthUtils(298, 298).height,
borderRadius: 10,
},
productItemImage:{
width: "100%",
height:widthUtils(190, 190).height,
borderRadius: 10,
},
productItemInfo:{
width: "100%",
flex: 1,
},
priceInfo:{
width: "100%",
padding: 10,
},
priceTitle: {
width: "100%",
padding: 10,
},
priceTitleText: {
color: "#fff",
fontSize: fontSize(14),
lineHeight: fontSize(20),
},
ventes:{
width: "100%",
padding: 10,
}
});

199
app/screens/function/BrowseHistoryScreen.tsx

@ -0,0 +1,199 @@
import React, { useState } from "react";
import {
View,
Text,
FlatList,
Image,
TouchableOpacity,
Platform,
StyleSheet,
} from "react-native";
import BackIcon from "../../components/BackIcon";
import fontSize from "../../utils/fontsizeUtils";
import { useNavigation } from "@react-navigation/native";
import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker';
import widthUtils from "../../utils/widthUtils";
const browseData = [
{
id: "1",
name: "商品名称示例",
time: "14:32",
price: 199.0,
image: "https://via.placeholder.com/60",
},
{
id: "2",
name: "另一商品示例",
time: "09:15",
price: 89.9,
image: "https://via.placeholder.com/60",
},
];
export function BrowseHistoryScreen() {
const navigation = useNavigation();
const [date, setDate] = useState(new Date());
const [show, setShow] = useState(false);
const onChange = (event: DateTimePickerEvent, selectedDate?: Date) => {
setShow(Platform.OS === "ios"); // iOS 会保持显示
if (selectedDate) {
setDate(selectedDate);
}
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
onPress={() => navigation.goBack()}
style={styles.backButton}
>
<BackIcon size={fontSize(22)} />
</TouchableOpacity>
<Text style={styles.title}></Text>
<View style={styles.placeholder} />
</View>
<TouchableOpacity
style={styles.dateInput}
onPress={() => setShow(true)}
>
<Text style={styles.dateText}></Text>
</TouchableOpacity>
{show && (
<DateTimePicker
value={date}
mode="date"
is24Hour={true}
display="default"
onChange={onChange}
/>
)}
<FlatList
data={browseData}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.list}
renderItem={({ item }) => (
<View style={styles.item}>
<Image source={{ uri: item.image }} style={styles.image} />
<View style={styles.info}>
<View style={styles.row}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.price}>¥{item.price.toFixed(2)}</Text>
</View>
<Text style={styles.time}>{item.time}</Text>
</View>
</View>
)}
ListEmptyComponent={
<Text style={styles.empty}></Text>
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: "#f8f8f8",
flex: 1,
},
header: {
paddingInline: 19,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
backgroundColor: "white",
width: "100%",
paddingVertical: 15,
borderBottomWidth: 1,
borderBottomColor: "#e9ecef",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
backButton: {
width: widthUtils(24,24).width,
},
title: {
fontSize: fontSize(20),
fontWeight: "600",
flex: 1,
textAlign: "center",
},
placeholder: {
width: widthUtils(24,24).width,
},
dateInput: {
padding: 20,
backgroundColor: "#fff",
marginBottom: 16,
},
dateText: {
fontSize: 16,
color: "#333",
},
list: {
gap: 12,
paddingHorizontal: 20,
},
item: {
flexDirection: "row",
backgroundColor: "#fff",
padding: 12,
borderRadius: 8,
gap: 12,
},
image: {
width: widthUtils(60,60).width,
height: widthUtils(60,60).height,
borderRadius: 6,
backgroundColor: "#eee",
},
info: {
flex: 1,
justifyContent: "center",
},
row: {
flexDirection: "row",
justifyContent: "space-between",
},
name: {
fontSize: 16,
fontWeight: "500",
flex: 1,
},
price: {
fontSize: 14,
fontWeight: "bold",
color: "#e60012",
marginLeft: 8,
},
time: {
fontSize: 12,
color: "#888",
marginTop: 4,
},
empty: {
textAlign: "center",
color: "#aaa",
fontSize: 15,
marginTop: 40,
},
});

207
app/screens/function/Collection.tsx

@ -0,0 +1,207 @@
import React from "react";
import {
View,
Text,
Image,
StyleSheet,
ScrollView,
TouchableOpacity,
} from "react-native";
import widthUtils from "../../utils/widthUtils";
import fontSize from "../../utils/fontsizeUtils";
import BackIcon from "../../components/BackIcon";
import { useNavigation } from "@react-navigation/native";
const FavoriteItem = ({
image,
title,
price,
}: {
image: string;
title: string;
price: number;
}) => {
return (
<View style={styles.item}>
<Image source={{ uri: image }} style={styles.image} />
<View style={styles.info}>
<Text style={styles.title} numberOfLines={2}>
{title}
</Text>
<Text style={styles.price}>{price}</Text>
<View style={styles.actions}>
<TouchableOpacity style={[styles.btn, styles.cart]}>
<Text style={styles.cartText}></Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.btn, styles.delete]}>
<Text style={styles.deleteText}></Text>
</TouchableOpacity>
</View>
</View>
</View>
);
};
export const Collection = () => {
const navigation = useNavigation();
const data = [
{
id: "1",
image: "https://img.alicdn.com/imgextra/i1/1234567890/O1CN01Item1.jpg",
title: "韩版宽松休闲卫衣女春秋款薄款学生ins潮",
price: 89.0,
},
{
id: "2",
image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg",
title: "小米无线蓝牙耳机半入耳式 轻巧便携",
price: 129.0,
},
{
id: "3",
image: "https://img.alicdn.com/imgextra/i3/3234567890/O1CN01Item3.jpg",
title: "华为MateBook X Pro 2020款 13.9英寸全面屏笔记本电脑",
price: 10999.0,
},
{
id: "4",
image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg",
title: "小米无线蓝牙耳机半入耳式 轻巧便携",
price: 129.0,
},
{
id: "5",
image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg",
title: "小米无线蓝牙耳机半入耳式 轻巧便携",
price: 129.0,
},
{
id: "6",
image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg",
title: "小米无线蓝牙耳机半入耳式 轻巧便携",
price: 129.0,
},
{
id: "7",
image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg",
title: "小米无线蓝牙耳机半入耳式 轻巧便携",
price: 129.0,
},
{
id: "82",
image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg",
title: "小米无线蓝牙耳机半入耳式 轻巧便携",
price: 129.0,
},
// 可以继续添加更多商品
];
return (
<View style={styles.containerBox}>
<View style={styles.header}>
<TouchableOpacity
onPress={() => navigation.goBack()}
style={styles.backButton}
>
<BackIcon size={fontSize(22)} />
</TouchableOpacity>
<Text style={styles.titles}></Text>
<View style={styles.placeholder} />
</View>
<ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
{data.map((item) => (
<FavoriteItem key={item.id} {...item} />
))}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
containerBox: {
flex: 1,
backgroundColor: "#f5f5f5",
},
header: {
paddingInline: 19,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
backgroundColor: "white",
width: "100%",
paddingVertical: 15,
},
titles: {
fontSize: fontSize(20),
fontWeight: "600",
flex: 1,
textAlign: "center",
},
backButton: {
width: widthUtils(24, 24).width,
},
placeholder: {
width: widthUtils(24, 24).width,
},
container: {
backgroundColor: "#f5f5f5",
paddingLeft: 20,
paddingRight: 20,
paddingBottom: 20,
marginTop: 20,
flex: 1,
},
item: {
flexDirection: "row",
padding: 12,
backgroundColor: "#fff",
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
image: {
width: widthUtils(100, 100).width,
height: widthUtils(100, 100).height,
borderRadius: 4,
marginRight: 12,
},
info: {
flex: 1,
justifyContent: "space-between",
},
title: {
fontSize: fontSize(15),
color: "#333",
lineHeight: 20,
marginBottom: 6,
},
price: {
color: "#f40",
fontSize: fontSize(16),
marginBottom: 10,
},
actions: {
flexDirection: "row",
gap: 8,
},
btn: {
paddingVertical: 4,
paddingHorizontal: 10,
borderRadius: 3,
borderWidth: 1,
},
cart: {
borderColor: "#ff5000",
},
delete: {
borderColor: "#ccc",
},
cartText: {
fontSize: fontSize(12),
color: "#ff5000",
},
deleteText: {
fontSize: fontSize(12),
color: "#999",
},
});

2
app/screens/pay/PaySuccess.tsx

@ -10,7 +10,7 @@ import {
export const PaymentSuccessScreen = () => { export const PaymentSuccessScreen = () => {
return ( return (
<ScrollView style={styles.container}> <ScrollView style={styles.container} showsVerticalScrollIndicator={false} >
<View style={styles.header}> <View style={styles.header}>
<View style={styles.headerSuccess}> <View style={styles.headerSuccess}>
<View style={styles.headerSuccessImg}></View> <View style={styles.headerSuccessImg}></View>

92
app/screens/setting/MyAddress.tsx

@ -4,31 +4,37 @@ import {
StyleSheet, StyleSheet,
ScrollView, ScrollView,
TouchableOpacity, TouchableOpacity,
ActivityIndicator,
} from "react-native"; } from "react-native";
import React, { Fragment } from "react";
import BackIcon from "../../components/BackIcon"; import BackIcon from "../../components/BackIcon";
import FileEditIcon from "../../components/FileEditIcon"; import FileEditIcon from "../../components/FileEditIcon";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { addressApi, AddressItem, } from "../../services/api/addressApi"; import { addressApi, AddressItem } from "../../services/api/addressApi";
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback } from "react";
import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useFocusEffect } from '@react-navigation/native'; import { useFocusEffect } from "@react-navigation/native";
import fontSize from "../../utils/fontsizeUtils"; import fontSize from "../../utils/fontsizeUtils";
import widthUtils from "../../utils/widthUtils"; import widthUtils from "../../utils/widthUtils";
export function MyAddress() { export function MyAddress() {
const navigation = useNavigation<NativeStackNavigationProp<any>>(); const navigation = useNavigation<NativeStackNavigationProp<any>>();
const [addressList, setAddressList] = useState<AddressItem[]>(); const [addressList, setAddressList] = useState<AddressItem[]>();
const [address, setAddress] = useState<number>(); const [address, setAddress] = useState<number>();
const [loading, setLoading] = useState(true);
const getAddress = async () => { const getAddress = async () => {
const response = await addressApi.getAddress(); const response = await addressApi.getAddress();
setAddressList(response.items); setAddressList(response.items);
setLoading(false);
}; };
useEffect(() => { useEffect(() => {
getAddress(); getAddress();
}, []); }, []);
const deleteAddress = async (address_id: number) => { const deleteAddress = async (address_id: number) => {
setAddressList(addressList?.filter((item) => item.address_id !== address_id)); setAddressList(
addressApi.deleteAddress(address_id) addressList?.filter((item) => item.address_id !== address_id)
} );
addressApi.deleteAddress(address_id);
};
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
getAddress(); getAddress();
@ -37,17 +43,31 @@ export function MyAddress() {
const setAddressId = (address_id: number) => { const setAddressId = (address_id: number) => {
setAddress(address_id); setAddress(address_id);
} };
return ( return (
<View style={styles.container}> <View style={styles.container}>
<View style={styles.header}> <View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()}> <TouchableOpacity
<BackIcon /> onPress={() => navigation.goBack()}
style={styles.backButton}
>
<BackIcon size={fontSize(22)} />
</TouchableOpacity> </TouchableOpacity>
<Text style={styles.titles}></Text>
<View style={styles.placeholder} />
</View>
{loading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#f77f3a" />
</View> </View>
<ScrollView style={{flex:1}} showsVerticalScrollIndicator={false}> ) : (
{ <Fragment>
addressList?.map((item) => ( <ScrollView
style={{ flex: 1, padding: 19 }}
showsVerticalScrollIndicator={false}
>
{addressList?.map((item) => (
<TouchableOpacity <TouchableOpacity
key={item.address_id} key={item.address_id}
onPress={() => { onPress={() => {
@ -55,10 +75,11 @@ export function MyAddress() {
}} }}
> >
<View <View
style={[ style={[
styles.userCardContainer, styles.userCardContainer,
item.address_id === address ? styles.addressItemSelected : styles.addressItemNoSelected item.address_id === address
? styles.addressItemSelected
: styles.addressItemNoSelected,
]} ]}
> >
<View style={styles.userInfoCard}> <View style={styles.userInfoCard}>
@ -68,8 +89,7 @@ export function MyAddress() {
numberOfLines={1} numberOfLines={1}
ellipsizeMode="tail" ellipsizeMode="tail"
> >
{item.receiver_first_name} .{" "} {item.receiver_first_name} . {item.receiver_last_name}
{item.receiver_last_name}
</Text> </Text>
<Text <Text
style={styles.userCardInfo1} style={styles.userCardInfo1}
@ -106,10 +126,9 @@ export function MyAddress() {
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
)) ))}
}
</ScrollView> </ScrollView>
<View style={{ paddingLeft: 19, paddingRight: 19 }}>
<TouchableOpacity <TouchableOpacity
style={styles.addButton} style={styles.addButton}
onPress={() => navigation.navigate("AddRess")} onPress={() => navigation.navigate("AddRess")}
@ -117,17 +136,45 @@ export function MyAddress() {
<Text style={styles.addButtonText}></Text> <Text style={styles.addButtonText}></Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</Fragment>
)}
</View>
); );
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
padding: 16,
backgroundColor: "#f8f8f8", backgroundColor: "#f8f8f8",
}, },
header: { header: {
paddingVertical: 16, paddingInline: 19,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
backgroundColor: "white",
width: "100%",
paddingVertical: 15,
},
backButton: {
width: widthUtils(24, 24).width,
},
titles: {
fontSize: fontSize(20),
fontWeight: "600",
flex: 1,
textAlign: "center",
},
placeholder: {
width: widthUtils(24, 24).width,
},
title: {
fontSize: fontSize(20),
fontWeight: "600",
textAlign: "center",
position: "absolute",
width: "100%",
left: 0,
}, },
userCardContainer1: { userCardContainer1: {
marginTop: 20, marginTop: 20,
@ -225,4 +272,9 @@ const styles = StyleSheet.create({
fontSize: fontSize(16), fontSize: fontSize(16),
fontWeight: "500", fontWeight: "500",
}, },
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
}); });

BIN
assets/img/Mask group (1).png

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
assets/img/Mask group.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

4
package-lock.json generated

@ -10093,9 +10093,7 @@
} }
}, },
"node_modules/npm/node_modules/chalk": { "node_modules/npm/node_modules/chalk": {
"version": "5.4.1", "version": "5.3.0",
"resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.4.1.tgz",
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {

1
package.json

@ -13,6 +13,7 @@
"@expo/metro-runtime": "~4.0.1", "@expo/metro-runtime": "~4.0.1",
"@react-native-async-storage/async-storage": "^2.1.2", "@react-native-async-storage/async-storage": "^2.1.2",
"@react-native-community/checkbox": "^0.5.17", "@react-native-community/checkbox": "^0.5.17",
"@react-native-community/datetimepicker": "8.2.0",
"@react-native-picker/picker": "^2.11.0", "@react-native-picker/picker": "^2.11.0",
"@react-navigation/bottom-tabs": "^7.3.3", "@react-navigation/bottom-tabs": "^7.3.3",
"@react-navigation/native": "^7.0.19", "@react-navigation/native": "^7.0.19",

1052
yarn.lock

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