demo app hanoicomputer home category productdetail cart

This commit is contained in:
2021-03-16 17:00:55 +07:00
commit 6db1634f60
35 changed files with 36093 additions and 0 deletions

6
.expo-shared/assets.json Normal file
View File

@@ -0,0 +1,6 @@
{
"e997a5256149a4b76e6bfd6cbf519c5e5a0f1d278a3d8fa1253022b03c90473b": true,
"af683c96e0ffd2cf81287651c9433fa44debc1220ca7cb431fe482747f34a505": true,
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
}

13
.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
node_modules/**/*
.expo/*
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
# macOS
.DS_Store

117
App.tsx Normal file
View File

@@ -0,0 +1,117 @@
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity } from 'react-native';
import { Header, MainSeach } from './components/header/headerMain';
import useCachedResources from './hooks/useCachedResources';
import useColorScheme from './hooks/useColorScheme';
import Navigation from './navigation';
import { createDrawerNavigator, DrawerItemList, DrawerItem, DrawerContentScrollView } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator, StackScreenProps } from '@react-navigation/stack';
import { Text, View, } from './components/Themed';
import TabOneScreen from './screens/TabOneScreen';
import TabTwoScreen from './screens/TabTwoScreen';
import ProductDetail from './screens/ProductDetail';
import CartDetail from './screens/Cart';
export default function App() {
const isLoadingComplete = useCachedResources();
const colorScheme = useColorScheme();
if (!isLoadingComplete) {
return null;
} else {
return (
<NavigationContainer>
<MainContentRouter />
</NavigationContainer>
);
}
}
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
/* cài đặt thông số cho header */
const HeaderAllPageOpion = ({ navigation }: { navigation: any }) => {
return (
{
headerLeft: () => (
<Header props={navigation} />
),
headerTitle: () => (
<Text></Text>
),
headerStyle: {
backgroundColor: '#3385ff',
height: 130,
}
}
)
}
/* redirect về trang chủ */
const HomePage = ({ navigation }: { navigation: any }) => {
return (
<Stack.Navigator>
<Stack.Screen
name="homepage"
component={TabOneScreen}
options={HeaderAllPageOpion}
/>
</Stack.Navigator>
);
}
/* redirect về danh mục */
const ProductList = ({ navigation }: { navigation: any }) => {
return (
<Stack.Navigator>
<Stack.Screen
name="homepage"
component={TabTwoScreen}
options={HeaderAllPageOpion}
/>
</Stack.Navigator>
);
}
const ProductDetailRec = ({ navigation }: { navigation: any }) => {
return (
<Stack.Navigator>
<Stack.Screen
name="homepage"
component={ProductDetail}
options={HeaderAllPageOpion}
/>
</Stack.Navigator>
);
}
const CartPage = ({ navigation }: { navigation: any }) => {
return (
<Stack.Navigator>
<Stack.Screen
name="homepage"
component={CartDetail}
options={HeaderAllPageOpion}
/>
</Stack.Navigator>
);
}
const MainContentRouter = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomePage} />
<Drawer.Screen name="Laptop, Máy Tính Xách Tay" component={ProductList} />
<Drawer.Screen name="Trang san pham" component={ProductDetailRec} />
<Drawer.Screen name="cart" component={CartPage} />
</Drawer.Navigator>
);
}

34
app.json Normal file
View File

@@ -0,0 +1,34 @@
{
"expo": {
"name": "demo",
"slug": "demo",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/images/favicon.png"
}
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
assets/images/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

6
babel.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};

View File

@@ -0,0 +1,108 @@
import * as WebBrowser from 'expo-web-browser';
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import Colors from '../constants/Colors';
import { MonoText } from './StyledText';
import { Text, View } from './Themed';
export default function EditScreenInfo({ path }: { path: string }) {
return (
<View>
<View style={styles.getStartedContainer}>
<Text
style={styles.getStartedText}
lightColor="rgba(0,0,0,0.8)"
darkColor="rgba(255,255,255,0.8)">
Open up the code for this screen:
</Text>
<View
style={[styles.codeHighlightContainer, styles.homeScreenFilename]}
darkColor="rgba(255,255,255,0.05)"
lightColor="rgba(0,0,0,0.05)">
<MonoText>{path}</MonoText>
</View>
<Text
style={styles.getStartedText}
lightColor="rgba(0,0,0,0.8)"
darkColor="rgba(255,255,255,0.8)">
Change any of the text, save the file, and your app will automatically update.
</Text>
</View>
<View style={styles.helpContainer}>
<TouchableOpacity onPress={handleHelpPress} style={styles.helpLink}>
<Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
Tap here if your app doesn't automatically update after making changes
</Text>
</TouchableOpacity>
</View>
</View>
);
}
function handleHelpPress() {
WebBrowser.openBrowserAsync(
'https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet'
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
developmentModeText: {
marginBottom: 20,
fontSize: 14,
lineHeight: 19,
textAlign: 'center',
},
contentContainer: {
paddingTop: 30,
},
welcomeContainer: {
alignItems: 'center',
marginTop: 10,
marginBottom: 20,
},
welcomeImage: {
width: 100,
height: 80,
resizeMode: 'contain',
marginTop: 3,
marginLeft: -10,
},
getStartedContainer: {
alignItems: 'center',
marginHorizontal: 50,
},
homeScreenFilename: {
marginVertical: 7,
},
codeHighlightText: {
color: 'rgba(96,100,109, 0.8)',
},
codeHighlightContainer: {
borderRadius: 3,
paddingHorizontal: 4,
},
getStartedText: {
fontSize: 17,
lineHeight: 24,
textAlign: 'center',
},
helpContainer: {
marginTop: 15,
marginHorizontal: 20,
alignItems: 'center',
},
helpLink: {
paddingVertical: 15,
},
helpLinkText: {
textAlign: 'center',
},
});

View File

@@ -0,0 +1,7 @@
import * as React from 'react';
import { Text, TextProps } from './Themed';
export function MonoText(props: TextProps) {
return <Text {...props} style={[props.style, { fontFamily: 'space-mono' }]} />;
}

41
components/Themed.tsx Normal file
View File

@@ -0,0 +1,41 @@
import * as React from 'react';
import { Text as DefaultText, View as DefaultView } from 'react-native';
import Colors from '../constants/Colors';
import useColorScheme from '../hooks/useColorScheme';
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
const theme = useColorScheme();
const colorFromProps = props[theme];
if (colorFromProps) {
return colorFromProps;
} else {
return Colors[theme][colorName];
}
}
type ThemeProps = {
lightColor?: string;
darkColor?: string;
};
export type TextProps = ThemeProps & DefaultText['props'];
export type ViewProps = ThemeProps & DefaultView['props'];
export function Text(props: TextProps) {
const { style, lightColor, darkColor, ...otherProps } = props;
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
return <DefaultText style={[{ color }, style]} {...otherProps} />;
}
export function View(props: ViewProps) {
const { style, lightColor, darkColor, ...otherProps } = props;
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
}

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import renderer from 'react-test-renderer';
import { MonoText } from '../StyledText';
it(`renders correctly`, () => {
const tree = renderer.create(<MonoText>Snapshot test!</MonoText>).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@@ -0,0 +1,369 @@
import * as React from 'react';
import { useState } from 'react';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity } from 'react-native';
import { Text, View, } from '../Themed';
import { TextInput } from 'react-native-gesture-handler';
import { Ionicons, FontAwesome } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
const PolicyFooter = () => {
return (
<View style={styles.homePolicy}>
<LinearGradient colors={['#243a76', '#ed1b24']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.bgLinearGradient}>
<Text style={styles.homePolicyTitle}>
Chính sách bán hàng
</Text>
</LinearGradient>
<View style={styles.homePolicyList}>
<View style={styles.homePolicyItem}>
<FontAwesome style={styles.homePolicyIcon} name="truck" size={25} />
<View>
<Text style={styles.homePolicyTextSt}>CHÍNH SÁCH GIAO HÀNG</Text>
<Text style={styles.homePolicyTextNd}>Nhận hàng thanh toán tại nhà</Text>
</View>
</View>
<View style={styles.homePolicyItem}>
<FontAwesome style={styles.homePolicyIcon} name="refresh" size={25} />
<View>
<Text style={styles.homePolicyTextSt}>ĐI TRẢ DỄ DÀNG</Text>
<Text style={styles.homePolicyTextNd}>Dùng thử trong vòng 3 ngày</Text>
</View>
</View>
<View style={styles.homePolicyItem}>
<FontAwesome style={styles.homePolicyIcon} name="credit-card" size={25} />
<View>
<Text style={styles.homePolicyTextSt}>THANH TOÁN TIỆN LỢI</Text>
<Text style={styles.homePolicyTextNd}>Trả tiền mặt, CK, trả góp 0%</Text>
</View>
</View>
<View style={styles.homePolicyItem}>
<FontAwesome style={styles.homePolicyIcon} name="comments-o" size={25} />
<View>
<Text style={styles.homePolicyTextSt}>HỖ TRỢ NHIỆT TÌNH</Text>
<Text style={styles.homePolicyTextNd}> vấn, giải đáp mọi thắc mắc</Text>
</View>
</View>
</View>
</View>
);
}
const Social = () => {
return (
<View style={styles.homeSocial}>
<LinearGradient colors={['#243a76', '#ed1b24']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.bgLinearGradient}>
<Text style={styles.homePolicyTitle}>
Kết nối với chúng tôi
</Text>
</LinearGradient>
<View style={styles.homeSocialList}>
<View style={styles.homeSocialItem}>
<FontAwesome style={styles.homeSocialIconFace} name="facebook" size={25} />
</View>
<View style={styles.homeSocialItem}>
<FontAwesome style={styles.homeSocialIconYoutube} name="youtube-play" size={25} />
</View>
<View style={styles.homeSocialItem}>
<LinearGradient colors={['#f09433', '#e6683c', '#dc2743', '#cc2366', '#bc1888']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.homeSocialItemBg}>
<FontAwesome style={styles.homeSocialIconInsta} name="instagram" size={25} />
</LinearGradient>
</View>
</View>
</View>
);
}
const ShowroomList = () => {
const [showFooter, setFooter] = useState('');
const ShowroomData = [
{
id: 'id1',
title: 'HANOICOMPUTER - HAI BÀ TRƯNG',
address: '- 129+131 Lê Thanh Nghị - Đồng Tâm - Hai Bà Trưng - Hà Nội\n- Tel: (024) 36282024\n- Email: kinhdoanhle.lethanhnghi@hanoicomputer.com\n\n'
},
{
id: 'id2',
title: 'HANOICOMPUTER - ĐỐNG ĐA',
address: '- 43 Thái Hà - Trung Liệt - Đống Đa - Hà Nội\n- Tel: 1900 1903 (máy lẻ 201) - (024) 35380088\n- Email: kinhdoanhle.thaiha@hanoicomputer.com\n\n'
},
{
id: 'id3',
title: 'HANOICOMPUTER - CẦU GIẤY',
address: '- 79 Nguyễn Văn Huyên - Cầu Giấy - Hà Nội\n- Tel: 1900 1903 (máy lẻ 503) - (024) 38610088\n- Email: kinhdoanhle.caugiay@hanoicomputer.com\n\n'
},
{
id: 'id4',
title: 'HANOICOMPUTER - HÀ ĐÔNG',
address: '- 511+513 Quang Trung - Hà Đông - Hà Nội\n- Tel: 1900 1903 (máy lẻ 600) - (024) 38580088\n- Email: kinhdoanhle.hadong@hanoicomputer.com\n\n'
},
{
id: 'id5',
title: 'HANOICOMPUTER - HẢI PHÒNG',
address: '- A1-6 Lô 8A, Lê Hồng Phong, Quận Ngô Quyền, Hải Phòng\n- Tel: 1900 1903 (máy lẻ 301) - (022) 58830013\n- Email: kinhdoanhle.haiphong@hanoicomputer.com\n\n'
},
{
id: 'id6',
title: 'HANOICOMPUTER - TP. HỒ CHÍ MINH',
address: '- 520 Cách Mạng Tháng Tám - Phường 11 - Quận 3 - TP. Hồ Chí Minh\n- Tel: 1900 1903 (máy lẻ 710) - (028) 73078877\n- Email: kd.hcmq3@hanoicomputer.com\n\n'
},
{
id: 'id7',
title: 'HANOICOMPUTER - LONG BIÊN',
address: '- Số 398 Nguyễn Văn Cừ - Long Biên - Hà Nội\n- Tel: 19001903 (máy lẻ 808) - (024) 73088877\n- Email: kinhdoanh.longbien@hanoicomputer.com\n\n'
},
{
id: 'id8',
title: 'PHÒNG CAMERA & TB AN NINH',
address: '- 43 Thái Hà - Trung Liệt - Đống Đa - Hà Nội\n- Phụ trách: Anh Nguyễn Văn Hiển\n- Mobile: 096.411.0606\n- Email: hiennv@hanoicomputer.com\n\n'
},
{
id: 'id9',
title: 'PHÒNG BÁN HÀNG DỰ ÁN',
address: '- 129 + 131 Lê Thanh Nghị, Đồng Tâm, Hai Bà Trưng, Hà Nội\n- Tel: 0913.226.335\n- Email: diepnm@hanoicomputer.com\n\n'
},
{
id: 'id10',
title: 'PHÒNG BÁN HÀNG TRỰC TUYẾN',
address: '- 129 + 131 Lê Thanh Nghị, Đồng Tâm, Hai Bà Trưng, Hà Nội\n- Tel: 098.33033.90 / 096.266.0316\n- Email: thuydb@hanoicomputer.com\n\n'
},
];
return (
<View style={styles.homeShowrrom}>
<LinearGradient colors={['#243a76', '#ed1b24']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.bgLinearGradient}>
<Text style={styles.homePolicyTitle}>
Hệ thông showroom
</Text>
</LinearGradient>
<View style={styles.homeShowrromList}>
{
ShowroomData.map(item => <ShowroomOneItem key={item.id}
title={item.title} id={item.id} setFooter={setFooter} address={item.address} current_show_id={showFooter} />)
}
</View>
</View>
);
}
const ShowroomOneItem = (props: { id: string, current_show_id: string, title: string, address: string, setFooter: (id: string) => void }) => {
const { id, current_show_id, title, address, setFooter } = props;
return (
<View style={styles.homeShowrromItem}>
<TouchableOpacity onPress={() => setFooter(id)} style={styles.homeShowrromItemTitle}>
<Text style={styles.homeShowrromItemTitleText}>{title}</Text>
<Text style={styles.homeShowrromItemTitleIcon}>{current_show_id == id ? '-' : '+'}</Text>
</TouchableOpacity>
<View style={current_show_id == id ? styles.homeShowrromItemContentHienThi : styles.homeShowrromItemContent}>
<Text>
{address}
<TouchableOpacity onPress={() => Alert.alert('Go to map')} style={styles.homeShowrromItemContentMap}>
<Text style={styles.homeShowrromItemContentMapText}>- Xem bản đ</Text>
</TouchableOpacity>
</Text>
</View>
</View>
);
}
const FooterInfo = () => {
return (
<View style={styles.footer}>
<Text style={styles.footerBold}>© 2020 Công Ty Cổ Phần Máy Tính Nội</Text>
<Text style={styles.footerText}>
Đa chỉ: Số 129 + 131, phố Thanh Nghị, Phường Đng Tâm, Quận Hai Trưng, Nội{'\n'}{'\n'}
GPĐKKD số 0101161194 do Sở KHĐT Tp. Nội cấp ngày 31/8/2001{'\n'}{'\n'}
Email: hnc@hanoicomputer.com. Điện thoại: 1900 1903
</Text>
</View>
);
}
export { PolicyFooter, Social, ShowroomList, FooterInfo }
let winWidth = Dimensions.get('window').width; //full width
let winHeight = Dimensions.get('window').height; //full height
const styles = StyleSheet.create({
bgLinearGradient: {
marginBottom: 20,
borderRadius: 5,
overflow: 'hidden',
},
homePolicy: {
width: winWidth,
paddingLeft: 10,
paddingRight: 10,
},
homePolicyTitle: {
width: '100%',
fontSize: 15,
paddingLeft: 10,
paddingRight: 10,
borderRadius: 3,
lineHeight: 40,
textTransform: 'uppercase',
fontWeight: '700',
color: '#fff',
overflow: 'hidden',
},
homePolicyList: {
paddingTop: 10,
paddingBottom: 10,
},
homePolicyItem: {
marginBottom: 10,
display: 'flex',
flexDirection: 'row',
padding: 10,
borderWidth: 1,
borderColor: '#d9d9d9',
borderRadius: 5,
alignItems: 'center',
},
homePolicyIcon: {
width: 50,
height: 50,
textAlign: 'center',
lineHeight: 50,
borderRadius: 25,
backgroundColor: '#2b3179',
color: '#fff',
fontSize: 23,
overflow: 'hidden',
marginRight: 10.
},
homePolicyTextSt: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 5,
},
homePolicyTextNd: {
fontSize: 13,
},
homeSocial: {
marginBottom: 20,
paddingLeft: 10,
paddingRight: 10,
},
homeSocialList: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
homeSocialItem: {
marginRight: 10,
},
homeSocialIconFace: {
width: 50,
height: 50,
textAlign: 'center',
lineHeight: 50,
borderRadius: 25,
backgroundColor: '#2b3179',
color: '#fff',
fontSize: 23,
overflow: 'hidden',
},
homeSocialIconYoutube: {
width: 50,
height: 50,
textAlign: 'center',
lineHeight: 50,
borderRadius: 25,
backgroundColor: '#ff0000',
color: '#fff',
fontSize: 23,
overflow: 'hidden',
},
homeSocialIconInsta: {
width: 50,
height: 50,
textAlign: 'center',
lineHeight: 50,
borderRadius: 25,
color: '#fff',
fontSize: 23,
overflow: 'hidden',
},
homeSocialItemBg: {
width: 50,
height: 50,
textAlign: 'center',
lineHeight: 50,
borderRadius: 25,
color: '#fff',
fontSize: 23,
overflow: 'hidden',
},
homeShowrrom: {
paddingLeft: 10,
paddingRight: 10,
marginBottom: 20,
},
homeShowrromList: {
borderWidth: 1,
borderRadius: 5,
borderColor: '#d9d9d9',
overflow: 'hidden',
},
homeShowrromItem: {
},
homeShowrromItemTitle: {
position: 'relative',
backgroundColor: '#fff',
paddingLeft: 10,
paddingRight: 10,
borderColor: '#d9d9d9',
borderBottomWidth: 1,
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
},
homeShowrromItemTitleText: {
color: '#333',
lineHeight: 40,
fontSize: 16,
fontWeight: 'bold',
},
homeShowrromItemTitleIcon: {
color: '#333',
lineHeight: 40,
fontSize: 16,
},
homeShowrromItemContent: {
padding: 10,
fontSize: 12,
borderColor: '#d9d9d9',
borderBottomWidth: 1,
overflow: 'hidden',
display: 'none',
},
homeShowrromItemContentHienThi: {
padding: 10,
fontSize: 12,
borderColor: '#d9d9d9',
borderBottomWidth: 1,
},
homeShowrromItemContentMap: {},
homeShowrromItemContentMapText: {
color: '#0063C3'
},
footer: {
paddingLeft: 10,
paddingRight: 10,
},
footerBold: {
textAlign: 'center',
fontSize: 14,
fontWeight: 'bold',
},
footerText: {
textAlign: 'center',
fontSize: 14,
},
})

View File

@@ -0,0 +1,144 @@
import 'react-native-gesture-handler';
import * as React from 'react';
import { useState } from 'react';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity } from 'react-native';
import { Text, View, } from '../Themed';
import { TextInput } from 'react-native-gesture-handler';
import { Ionicons, FontAwesome } from '@expo/vector-icons';
import { createDrawerNavigator, DrawerItemList, DrawerItem, DrawerContentScrollView } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Animated, { Easing } from 'react-native-reanimated';
const Header = ({props} : {props : any}) => {
const toggleDrawer = () => {
//Props to open/close the drawer
props.toggleDrawer();
};
return (
<View style={styles.headerAll}>
<View style={styles.header}>
<TouchableOpacity onPress={toggleDrawer} style={styles.menu}>
<Ionicons style={styles.iconMenu} name="md-list" size={32} />
</TouchableOpacity>
<View style={styles.bgNone}>
<Image style={styles.img} source={{ uri: 'https://www.hanoicomputer.vn/media/lib/logo-trang.png' }} />
</View>
<View style={styles.headerCart}>
<Ionicons style={styles.iconMenu} name="cart-outline" size={32} />
<Text style={styles.countCart}>0</Text>
</View>
</View>
<MainSeach />
</View>
);
}
const MainSeach = () => {
return (
<View style={styles.boxSearch}>
<View style={styles.boxSearchBo}>
<TextInput style={styles.inputSearch} placeholder="Nhập tên, mã sản phẩm" autoCapitalize="none" />
<Ionicons style={styles.buttonSearch} onPress={() => { Alert.alert('aaaaaaaaaa') }} name="search-outline" size={26} />
</View>
</View>
);
}
export { Header, MainSeach };
let winWidth = Dimensions.get('window').width; //full width
let winHeight = Dimensions.get('window').height; //full height
const styles = StyleSheet.create({
headerAll: {
width: winWidth,
flex: 1,
},
bgNone: {
backgroundColor: 'rgba(0, 0, 0, 0)',
},
header: {
backgroundColor: '#243a76',
height: 53,
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: winWidth,
padding: 10,
},
menu: {
backgroundColor: '#243a76',
},
iconMenu: {
color: '#fff',
},
headerCart: {
backgroundColor: 'rgba(0,0,0,0)',
position: 'relative',
},
countCart: {
position: 'absolute',
top: -5,
right: -5,
zIndex: 1,
width: 20,
height: 20,
backgroundColor: '#ffe100',
borderRadius: 10,
textAlign: 'center',
lineHeight: 20,
fontSize: 13,
color: '#000',
overflow: 'hidden',
},
img: {
height: 40,
width: 100,
},
boxSearch: {
position: 'relative',
padding: 10,
backgroundColor: '#fff',
width: winWidth,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.18,
shadowRadius: 1.00,
elevation: 1,
},
boxSearchBo: {
position: 'relative',
flexDirection: 'row',
borderWidth: 1,
justifyContent: 'space-between',
borderStyle: 'solid',
alignItems: 'center',
borderRadius: 5,
display: 'flex',
height: 38,
padding: 0,
margin: 0,
},
inputSearch: {
width: winWidth - 65,
padding: 10,
paddingTop: 10,
paddingBottom: 10,
height: 36,
margin: 0,
fontSize: 14,
},
buttonSearch: {
width: 40,
textAlign: 'center',
height: 36,
lineHeight: 36,
},
})

View File

@@ -0,0 +1,245 @@
import * as React from 'react';
import { useState } from 'react';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity, Pressable } from 'react-native';
import { Text, View, } from '../Themed';
import { Ionicons, FontAwesome } from '@expo/vector-icons';
import ProductDetail from '../../screens/ProductDetail';
import { createDrawerNavigator, DrawerItemList, DrawerItem, DrawerContentScrollView } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator, StackScreenProps } from '@react-navigation/stack';
import { NativeRouter, Route, Link } from "react-router-native";
import { TextInput } from 'react-native-gesture-handler';
import { Checkbox } from 'react-native-paper';
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
function formatCurrency(price: string | number) {
let priceConvert = parseFloat(`${price}`).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1.").toString();
let len = priceConvert.length;
return priceConvert.substring(0, len - 3);
}
const ShowProductItem = (props: { id: number, productName: string, productSKU: string, productImage: { small: string, medium: string, large: string, original: string }, price: number, marketPrice: number, quantity: number, privateStyle: object }) => {
const { id, productName, productSKU, productImage, price, marketPrice, quantity, privateStyle } = props;
const discount = Math.ceil(100 - (price / marketPrice * 100));
return (
<View style={[styles.itemProduct, privateStyle]}>
<View style={styles.pBloxImgProduct}>
<Text style={styles.pSkuProduct}>{productSKU}</Text>
<Text style={styles.pDiscountProduct}>-{discount}%</Text>
<View style={styles.pBloxImgProductBao}>
<Image style={styles.pImgProduct} source={{ uri: productImage.large }} />
</View>
</View>
<Text style={styles.pNameProduct} numberOfLines={2}>
{productName}
</Text>
<Text style={styles.priceProduct}>{formatCurrency(price)} đ</Text>
<Text style={styles.oldPriceProduct}>{formatCurrency(marketPrice)} đ</Text>
<View style={styles.pBottonProduct}>
<Text style={styles.pStatusProduct}>
{quantity > 0 ? <Ionicons style={styles.pStatusProductIcon} name="checkmark-outline" size={13} /> : <Ionicons style={styles.pStatusProductIcon} name="close-outline" size={13} />}
{quantity > 0 ? 'Còn hàng' : 'Hết hàng'}
</Text>
<Text style={styles.pCartProduct}><Ionicons style={styles.pCartProductIcon} name="cart-outline" size={13} />Giỏ hàng</Text>
</View>
</View>
);
}
const ItemComboSet = (props: { id: number, productName: string, productSKU: string, productImage: { small: string, medium: string, large: string, original: string }, price: number, marketPrice: number, quantity: number }) => {
const { id, productName, productSKU, productImage, price, marketPrice, quantity } = props;
const discountCombo = Math.ceil(100 - (price / marketPrice * 100));
const [checked, setChecked] = React.useState(false);
return (
<View style={[styles.itemProductCombo]}>
<View style={styles.pBloxImgProduct}>
<View style={styles.pBloxImgProductBao}>
<Image style={styles.pImgProduct} source={{ uri: productImage.large }} />
</View>
</View>
<View style={styles.pNameProductAll}>
<Checkbox.IOS status={checked ? 'checked' : 'unchecked'} onPress={() => setChecked(!checked)} style={styles.inputComboCheck} />
<Text style={[styles.pNameProduct, styles.pNameProductCombo]} numberOfLines={2}>
{productName}
</Text>
</View>
<View style={styles.priceProductAll}>
<Text style={[styles.priceProduct, styles.priceProductCombo]}>{formatCurrency(price)} đ</Text>
<Text style={[styles.oldPriceProduct, styles.oldPriceProductCombo]}>{formatCurrency(marketPrice)} đ</Text>
<Text style={styles.pDiscountProductCombo}>-{discountCombo}%</Text>
</View>
<TouchableOpacity onPress={() => Alert.alert('popup product')} >
<Text>Chọn tai nghe khác</Text>
</TouchableOpacity>
</View>
);
}
const ItemComboSetProDetail = (props: { id: number, productName: string, productSKU: string, productImage: { small: string, medium: string, large: string, original: string }, price: number, marketPrice: number, quantity: number }) => {
const { id, productName, productSKU, productImage, price, marketPrice, quantity } = props;
const discountCombo = Math.ceil(100 - (price / marketPrice * 100));
return (
<View style={[styles.itemProductCombo]}>
<View style={styles.pBloxImgProduct}>
<View style={styles.pBloxImgProductBao}>
<Image style={styles.pImgProduct} source={{ uri: productImage.large }} />
</View>
</View>
<Text style={styles.pNameProduct} numberOfLines={2}>
{productName}
</Text>
<Text style={styles.priceProduct}>{formatCurrency(price)} đ</Text>
<Text style={styles.oldPriceProduct}>{formatCurrency(marketPrice)} đ</Text>
<Text style={styles.pDiscountProductCombo}>-{discountCombo}%</Text>
</View>
);
}
export { ShowProductItem, ItemComboSet, ItemComboSetProDetail };
let winWidth = Dimensions.get('window').width; //full width
let winHeight = Dimensions.get('window').height; //full height
const styles = StyleSheet.create({
itemProduct: {
padding: 10,
},
pBloxImgProduct: {
position: 'relative',
marginBottom: 10,
},
pSkuProduct: {
position: 'absolute',
fontSize: 12,
color: '#e00',
top: 0,
left: 0,
lineHeight: 36,
zIndex: 10,
},
pDiscountProduct: {
width: 36,
height: 36,
backgroundColor: '#e00',
position: 'absolute',
top: 0,
right: 0,
color: '#fff',
textAlign: 'center',
lineHeight: 36,
borderRadius: 18,
overflow: 'hidden',
fontSize: 12,
zIndex: 10,
},
pBloxImgProductBao: {
position: 'relative',
paddingTop: '100%',
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
pImgProduct: {
position: 'absolute',
top: 0,
left: '5%',
right: 0,
bottom: 0,
maxHeight: 500,
width: '90%',
},
pNameProduct: {
height: 40,
lineHeight: 20,
overflow: 'hidden',
fontSize: 14,
color: '#111',
marginBottom: 5,
},
priceProduct: {
fontSize: 16,
fontWeight: 'bold',
color: '#f10000',
marginBottom: 5,
},
oldPriceProduct: {
fontSize: 14,
color: '#b7b7b7',
marginBottom: 5,
height: 24,
lineHeight: 24,
overflow: 'hidden',
textDecorationLine: 'line-through',
},
pBottonProduct: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
marginTop: 5,
},
pStatusProduct: {
fontSize: 13,
color: '#00a706',
},
pCartProduct: {
fontSize: 13,
color: '#333',
},
pStatusProductIcon: {
fontSize: 15,
},
pCartProductIcon: {
fontSize: 15
},
itemProductCombo: {
width: '100%',
marginBottom: 10,
borderWidth: 1,
borderColor: '#e1e1e1',
padding: 10,
},
inputComboCheck: {
width: 20,
height: 20,
borderColor: '#222',
borderWidth: 1,
borderRadius: 3,
alignSelf: 'center',
backgroundColor: '#e0c',
},
pDiscountProductCombo: {
textDecorationLine: 'line-through'
},
priceProductAll: {
display: 'flex',
flexDirection: 'row',
alignItems: 'baseline'
},
pNameProductCombo: {
paddingLeft: 10,
width: winWidth - 70,
},
pNameProductAll: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center'
},
priceProductCombo: {
lineHeight: 22,
},
oldPriceProductCombo: {
lineHeight: 22,
marginHorizontal: 10
},
})

19
constants/Colors.ts Normal file
View File

@@ -0,0 +1,19 @@
const tintColorLight = '#2f95dc';
const tintColorDark = '#fff';
export default {
light: {
text: '#000',
background: '#fff',
tint: tintColorLight,
tabIconDefault: '#ccc',
tabIconSelected: tintColorLight,
},
dark: {
text: '#fff',
background: '#000',
tint: tintColorDark,
tabIconDefault: '#ccc',
tabIconSelected: tintColorDark,
},
};

12
constants/Layout.ts Normal file
View File

@@ -0,0 +1,12 @@
import { Dimensions } from 'react-native';
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
export default {
window: {
width,
height,
},
isSmallDevice: width < 375,
};

View File

@@ -0,0 +1,33 @@
import { Ionicons } from '@expo/vector-icons';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import * as React from 'react';
export default function useCachedResources() {
const [isLoadingComplete, setLoadingComplete] = React.useState(false);
// Load any resources or data that we need prior to rendering the app
React.useEffect(() => {
async function loadResourcesAndDataAsync() {
try {
SplashScreen.preventAutoHideAsync();
// Load fonts
await Font.loadAsync({
...Ionicons.font,
'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
});
} catch (e) {
// We might want to provide this error information to an error reporting service
console.warn(e);
} finally {
setLoadingComplete(true);
SplashScreen.hideAsync();
}
}
loadResourcesAndDataAsync();
}, []);
return isLoadingComplete;
}

8
hooks/useColorScheme.ts Normal file
View File

@@ -0,0 +1,8 @@
import { ColorSchemeName, useColorScheme as _useColorScheme } from 'react-native';
// The useColorScheme value is always either light or dark, but the built-in
// type suggests that it can be null. This will not happen in practice, so this
// makes it a bit easier to work with.
export default function useColorScheme(): NonNullable<ColorSchemeName> {
return _useColorScheme() as NonNullable<ColorSchemeName>;
}

View File

@@ -0,0 +1,5 @@
// useColorScheme from react-native does not support web currently. You can replace
// this with react-native-appearance if you would like theme support on web.
export default function useColorScheme() {
return 'light';
}

View File

@@ -0,0 +1,73 @@
import { Ionicons } from '@expo/vector-icons';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import * as React from 'react';
import Colors from '../constants/Colors';
import useColorScheme from '../hooks/useColorScheme';
import TabOneScreen from '../screens/TabOneScreen';
import TabTwoScreen from '../screens/TabTwoScreen';
import { BottomTabParamList, TabOneParamList, TabTwoParamList } from '../types';
const BottomTab = createBottomTabNavigator<BottomTabParamList>();
export default function BottomTabNavigator() {
const colorScheme = useColorScheme();
return (
<BottomTab.Navigator
initialRouteName="TabOne"
tabBarOptions={{ activeTintColor: Colors[colorScheme].tint }}>
<BottomTab.Screen
name="TabOne"
component={TabOneNavigator}
options={{
tabBarIcon: ({ color }) => <TabBarIcon name="ios-code" color={color} />,
}}
/>
<BottomTab.Screen
name="TabTwo"
component={TabTwoNavigator}
options={{
tabBarIcon: ({ color }) => <TabBarIcon name="ios-code" color={color} />,
}}
/>
</BottomTab.Navigator>
);
}
// You can explore the built-in icon families and icons on the web at:
// https://icons.expo.fyi/
function TabBarIcon(props: { name: React.ComponentProps<typeof Ionicons>['name']; color: string }) {
return <Ionicons size={30} style={{ marginBottom: -3 }} {...props} />;
}
// Each tab has its own navigation stack, you can read more about this pattern here:
// https://reactnavigation.org/docs/tab-based-navigation#a-stack-navigator-for-each-tab
const TabOneStack = createStackNavigator<TabOneParamList>();
function TabOneNavigator() {
return (
<TabOneStack.Navigator>
<TabOneStack.Screen
name="TabOneScreen"
component={TabOneScreen}
options={{ headerTitle: 'Tab One Title' }}
/>
</TabOneStack.Navigator>
);
}
const TabTwoStack = createStackNavigator<TabTwoParamList>();
function TabTwoNavigator() {
return (
<TabTwoStack.Navigator>
<TabTwoStack.Screen
name="TabTwoScreen"
component={TabTwoScreen}
options={{ headerTitle: 'Tab Two Title' }}
/>
</TabTwoStack.Navigator>
);
}

View File

@@ -0,0 +1,24 @@
import * as Linking from 'expo-linking';
export default {
prefixes: [Linking.makeUrl('/')],
config: {
screens: {
Root: {
screens: {
TabOne: {
screens: {
TabOneScreen: 'one',
},
},
TabTwo: {
screens: {
TabTwoScreen: 'two',
},
},
},
},
NotFound: '*',
},
},
};

34
navigation/index.tsx Normal file
View File

@@ -0,0 +1,34 @@
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import * as React from 'react';
import { ColorSchemeName } from 'react-native';
import NotFoundScreen from '../screens/NotFoundScreen';
import { RootStackParamList } from '../types';
import BottomTabNavigator from './BottomTabNavigator';
import LinkingConfiguration from './LinkingConfiguration';
// If you are not familiar with React Navigation, we recommend going through the
// "Fundamentals" guide: https://reactnavigation.org/docs/getting-started
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
return (
<NavigationContainer
linking={LinkingConfiguration}
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<RootNavigator />
</NavigationContainer>
);
}
// A root stack navigator is often used for displaying modals on top of all other content
// Read more here: https://reactnavigation.org/docs/modal
const Stack = createStackNavigator<RootStackParamList>();
function RootNavigator() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Root" component={BottomTabNavigator} />
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
</Stack.Navigator>
);
}

32042
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

65
package.json Normal file
View File

@@ -0,0 +1,65 @@
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"test": "jest --watchAll"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@expo/vector-icons": "^12.0.0",
"@react-native-community/checkbox": "^0.5.7",
"@react-native-community/masked-view": "0.1.10",
"@react-native-picker/picker": "^1.9.12",
"@react-navigation/bottom-tabs": "5.11.2",
"@react-navigation/drawer": "^5.12.4",
"@react-navigation/native": "~5.8.10",
"@react-navigation/routers": "^5.7.2",
"@react-navigation/stack": "^5.12.8",
"@types/react-router": "^5.1.11",
"expo": "~40.0.0",
"expo-asset": "~8.2.1",
"expo-av": "~8.7.0",
"expo-constants": "~9.3.3",
"expo-font": "~8.4.0",
"expo-linear-gradient": "~8.4.0",
"expo-linking": "~2.0.1",
"expo-splash-screen": "~0.8.1",
"expo-status-bar": "~1.0.3",
"expo-web-browser": "~8.6.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
"react-native-bem-check-box": "^1.0.0",
"react-native-gesture-handler": "~1.8.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-paper": "^4.7.2",
"react-native-reanimated": "~1.13.0",
"react-native-safe-area-context": "3.1.9",
"react-native-screens": "~2.15.2",
"react-native-swiper": "^1.6.0-rc.3",
"react-native-table-component": "^1.2.1",
"react-native-textarea": "^1.0.4",
"react-native-web": "~0.13.12",
"react-native-youtube-iframe": "^1.4.1",
"react-router": "^5.2.0",
"react-router-native": "^5.2.0",
"styled-components": "^5.2.1"
},
"devDependencies": {
"@babel/core": "~7.9.0",
"@types/react": "~16.9.35",
"@types/react-native": "~0.63.2",
"@types/react-native-table-component": "^1.2.0",
"@types/react-router-native": "^5.1.0",
"@types/styled-components": "^5.1.7",
"jest-expo": "^40.0.0",
"typescript": "~4.0.0"
},
"private": true
}

492
screens/Cart.tsx Normal file
View File

@@ -0,0 +1,492 @@
import 'react-native-gesture-handler';
import * as React from 'react';
import { useState } from 'react';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity, Modal, Pressable, Share } from 'react-native';
import Constants from 'expo-constants';
import { Ionicons, FontAwesome } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import { PolicyFooter, Social, ShowroomList, FooterInfo } from '../components/footer/footerMain';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View, } from '../components/Themed';
import useColorScheme from '../hooks/useColorScheme';
import { TextInput } from 'react-native-gesture-handler';
import { RadioButton, Checkbox } from 'react-native-paper';
import { Picker } from '@react-native-picker/picker';
export default function CartDetail() {
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<View style={styles.boxCartPage}>
<View style={styles.boxCartPageHeader}>
<View style={styles.boxCartPageBackHome}>
<Pressable>
<Ionicons style={styles.boxCartPageBackHomeIcon} name="arrow-back-outline" />
</Pressable>
<Text style={styles.boxCartPageBackHomeText}>Giỏ hàng</Text>
</View>
<Pressable style={styles.boxCartPageDeleteAll}>
<Text style={styles.boxCartPageDeleteAllText}>Xóa toàn bộ</Text>
</Pressable>
</View>
<View style={styles.boxCartPageListProduct}>
<CartItem />
</View>
<Voucher />
<PayOption />
<CustommerInfoCart />
<PolicyFooter />
<Social />
<ShowroomList />
<FooterInfo />
</View>
</ScrollView>
</SafeAreaView>
)
}
const CartItem = () => {
return (
<View style={styles.cartItem}>
<View style={styles.cartItemImg}>
<Image style={styles.cartItemImgContent} source={{ uri: 'https://hanoicomputercdn.com/media/product/250_56516_vosro3405__4_.png' }} />
</View>
<View style={styles.cartItemCtNd}>
<Text style={styles.cartItemProName} numberOfLines={2}>
Laptop Dell Vostro 3405 (V4R53500U003W) (R5 3500U 8GB asa asas )
</Text>
<TouchableOpacity style={styles.cartItemDelete}>
<FontAwesome style={styles.cartItemDeleteIcon} name="trash-o" />
</TouchableOpacity>
</View>
<View style={styles.cartItemCtRd}>
<Text style={styles.cartItemPrice}>20.000.000 đ</Text>
<View style={styles.cartItemQuantity}>
<Pressable style={styles.cartItemQuantityChange}><Text style={styles.cartItemQuantityChangeText}>-</Text></Pressable>
<TextInput style={styles.cartItemQuantityInput} value="1" />
<Pressable style={styles.cartItemQuantityChange}><Text style={styles.cartItemQuantityChangeText}>+</Text></Pressable>
</View>
</View>
</View>
);
}
const Voucher = () => {
return (
<View style={styles.voucher}>
<Text style={styles.voucherTitle}> giảm giả / Quà tặng</Text>
<View style={styles.voucherContent}>
<TextInput style={styles.voucherInput} placeholder="Nhập mã giảm giá" />
<Pressable style={styles.voucherSubmit}>
<LinearGradient colors={['#243a76', '#ed1b24']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.linearGradientBg}>
<Text style={styles.voucherSubmitText}>Áp dụng</Text>
</LinearGradient>
</Pressable>
</View>
</View>
)
}
const PayOption = () => {
const [checked, setChecked] = React.useState('pay1');
const listPayment = [
{
id: 1,
name: 'Thanh toán tiền mặt khi nhận hàng (tiền mặt / quẹt thẻ ATM, Visa, Master)',
description: '',
},
{
id: 2,
name: 'Thanh toán qua chuyển khoản qua tài khoản ngân hàng (khuyên dùng)',
description: '',
},
{
id: 3,
name: 'Thanh toán qua Ngân Lượng (ATM nội địa, Visa, Master)',
description: '',
},
{
id: 4,
name: 'Trả góp qua Alepay (Ngân Lượng)',
description: '',
},
]
return (
<View style={styles.BoxPayment}>
<Text style={styles.BoxPaymentTitle}>Lựa chọn hình thức thanh toán</Text>
<View style={styles.BoxPaymentList}>
{
listPayment.map(item => {
let idpay = 'pay' + item.id;
return (
<View style={styles.paymentItem} key={item.id}>
<View style={styles.paymentItemRadio}>
<RadioButton color={'#243a76'} value={idpay} status={checked === idpay ? 'checked' : 'unchecked'} onPress={() => setChecked(idpay)} />
</View>
<Text style={styles.paymentItemText}>{item.name}</Text>
</View>
)
})
}
</View>
</View>
)
}
const CustommerInfoCart = () => {
const [selectedLanguage, setSelectedLanguage] = useState();
const [checked, setChecked] = React.useState(false);
return (
<View style={styles.BoxCustommerInfoCart}>
<Text style={styles.BoxPaymentTitle}>Thông tin khách hàng</Text>
<View style={styles.BoxCustommerInfoCartList}>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Họ tên*</Text>
<TextInput style={styles.cartCusItemInput} />
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Email*</Text>
<TextInput style={styles.cartCusItemInput} />
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Số điện thoại*</Text>
<TextInput style={styles.cartCusItemInput} />
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Chọn tỉnh thành phố*</Text>
<Picker
style={styles.picker}
itemStyle={styles.onePickerItem}
selectedValue={selectedLanguage}
onValueChange={(itemValue, itemIndex) =>
setSelectedLanguage(itemValue)
}
>
<Picker.Item label="Hà Nội" value="1" />
<Picker.Item label="Đà Nẵng" value="2" />
<Picker.Item label="Hải Phòng" value="3" />
<Picker.Item label="TP Hồ Chí Minh" value="4" />
</Picker>
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Đa chỉ*</Text>
<TextInput multiline={true} numberOfLines={3} style={styles.cartCusItemArea} />
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Ghi chú</Text>
<TextInput multiline={true} numberOfLines={4} style={styles.cartCusItemArea} />
</View>
</View>
<View style={styles.companyCart}>
<View style={styles.companyCartCheck}>
<View style={styles.companyCartCheckBox}>
<Checkbox.IOS status={checked ? 'checked' : 'unchecked'} onPress={() => setChecked(!checked)} />
</View>
<Text style={styles.companyCartCheckText}>Xuất hóa đơn công ty</Text>
</View>
<View style={styles.companyCartList}>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Công ty/ tổ chức*:</Text>
<TextInput multiline={true} numberOfLines={4} style={styles.cartCusItemArea} />
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}>Đa chỉ*:</Text>
<TextInput multiline={true} numberOfLines={4} style={styles.cartCusItemArea} />
</View>
<View style={styles.cartCusItem}>
<Text style={styles.cartCusItemText}> số thuế*:</Text>
<TextInput multiline={true} numberOfLines={4} style={styles.cartCusItemArea} />
</View>
</View>
</View>
</View>
)
}
const winWidth = Dimensions.get('window').width; //full width
const winHeight = Dimensions.get('window').height; //full height
const halfWinWidth = winWidth / 2;
const ratio = winWidth / 500; //541 is actual image width
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
},
boxCartPage: {
marginBottom: 20,
width: winWidth
},
boxCartPageHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
height: 40,
alignItems: 'center',
paddingHorizontal: 10,
borderBottomColor: '#d42333',
borderBottomWidth: 1,
},
boxCartPageBackHome: {
flexDirection: 'row',
alignItems: 'center'
},
boxCartPageBackHomeIcon: {
fontSize: 14,
marginRight: 8,
width: 30
},
boxCartPageBackHomeText: {
fontWeight: 'bold'
},
boxCartPageDeleteAll: {},
boxCartPageDeleteAllText: {
fontWeight: 'bold',
color: '#f00'
},
boxCartPageListProduct: {
width: winWidth - 20,
marginLeft: 10,
marginTop: 20,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
marginBottom: 15,
},
cartItem: {
padding: 10,
},
cartItemImg: {
position: 'relative',
paddingTop: '100%',
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
width: '100%',
},
cartItemImgContent: {
position: 'absolute',
top: 0,
left: '5%',
right: 0,
bottom: 0,
maxHeight: 500,
width: '90%',
},
cartItemCtNd: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 5,
width: '100%',
alignItems: 'center'
},
cartItemProName: {
fontSize: 14,
height: 40,
lineHeight: 20,
width: winWidth - 80,
},
cartItemDelete: {
width: 60,
flexDirection: 'row',
justifyContent: 'center',
height: 40,
alignItems: 'center',
display: 'flex',
},
cartItemDeleteIcon: {
fontSize: 24,
color: '#f00'
},
cartItemCtRd: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
alignItems: 'center'
},
cartItemPrice: {
fontSize: 16,
fontWeight: 'bold',
color: '#e00'
},
cartItemQuantity: {
width: 100,
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderColor: '#e1e1e1',
borderWidth: 1,
},
cartItemQuantityChange: {
width: 30,
height: 30,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
cartItemQuantityChangeText: {},
cartItemQuantityInput: {
width: 40,
height: 30,
textAlign: 'center',
borderLeftWidth: 1,
borderRightWidth: 1,
borderLeftColor: '#e1e1e1',
borderRightColor: '#e1e1e1',
},
voucher: {
paddingHorizontal: 10,
marginBottom: 20,
},
voucherTitle: {
fontWeight: 'bold',
fontSize: 14,
marginBottom: 5,
},
voucherContent: {
flexDirection: 'row',
justifyContent: 'space-between',
},
voucherInput: {
borderWidth: 1,
borderColor: '#ccc',
height: 34,
paddingHorizontal: 10,
borderRadius: 5,
width: winWidth - 110,
},
voucherSubmit: {
width: 85,
marginLeft: 5,
},
linearGradientBg: {
width: '100%',
height: 34,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 5,
},
voucherSubmitText: {
color: '#fff',
fontWeight: 'bold'
},
BoxPayment: {
paddingHorizontal: 10,
},
BoxPaymentTitle: {
padding: 10,
backgroundColor: '#243a76',
borderRadius: 3,
fontSize: 16,
fontWeight: 'bold',
color: '#fff',
textTransform: 'uppercase',
overflow: 'hidden',
marginBottom: 10,
},
BoxPaymentList: {
flexDirection: 'column',
},
paymentItem: {
flexDirection: 'row',
marginBottom: 10,
alignItems: 'center'
},
paymentItemRadio: {
width: 36,
height: 36,
borderRadius: 18,
borderWidth: 1,
borderColor: '#222',
marginRight: 10,
position: 'relative',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
overflow: 'hidden',
},
paymentItemText: {
width: winWidth - 56,
},
BoxCustommerInfoCart: {
paddingHorizontal: 10,
marginBottom: 20,
},
BoxCustommerInfoCartList: {
flexDirection: 'column',
},
cartCusItem: {
flexDirection: 'column',
marginBottom: 10,
},
cartCusItemText: {
fontSize: 14,
marginBottom: 5,
},
cartCusItemInput: {
height: 34,
width: '100%',
paddingHorizontal: 10,
borderColor: '#e1e1e1',
borderWidth: 1,
borderRadius: 5,
},
cartCusItemArea: {
height: 65,
width: '100%',
padding: 10,
borderColor: '#e1e1e1',
borderWidth: 1,
borderRadius: 5,
},
picker: {
height: 42,
width: '100%',
},
onePickerItem: {
height: 46,
color: '#222',
fontSize: 14,
textAlign: 'center',
width: '100%',
},
companyCart: {
marginTop: 5,
},
companyCartCheck: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 10,
},
companyCartCheckBox: {
width: 36,
height: 36,
borderWidth: 1,
borderColor: '#e1e1e1',
marginRight: 10,
borderRadius: 18,
},
companyCartCheckText: {},
companyCartList: {},
})

View File

@@ -0,0 +1,40 @@
import { StackScreenProps } from '@react-navigation/stack';
import * as React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { RootStackParamList } from '../types';
export default function NotFoundScreen({
navigation,
}: StackScreenProps<RootStackParamList, 'NotFound'>) {
return (
<View style={styles.container}>
<Text style={styles.title}>This screen doesn't exist.</Text>
<TouchableOpacity onPress={() => navigation.replace('Root')} style={styles.link}>
<Text style={styles.linkText}>Go to home screen!</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
link: {
marginTop: 15,
paddingVertical: 15,
},
linkText: {
fontSize: 14,
color: '#2e78b7',
},
});

1283
screens/ProductDetail.tsx Normal file

File diff suppressed because it is too large Load Diff

273
screens/TabOneScreen.tsx Normal file
View File

@@ -0,0 +1,273 @@
import 'react-native-gesture-handler';
import * as React from 'react';
import { useState } from 'react';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
import { Ionicons, FontAwesome } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import Swiper from 'react-native-swiper';
import styled from 'styled-components';
import { PolicyFooter, Social, ShowroomList, FooterInfo } from '../components/footer/footerMain';
import { ShowProductItem } from '../components/product/productItem';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View, } from '../components/Themed';
import useColorScheme from '../hooks/useColorScheme';
var winWidth = Dimensions.get('window').width; //full width
var winHeight = Dimensions.get('window').height; //full height
const ratio = winWidth / 930; //541 is actual image width
export default function TabOneScreen() {
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<SliderHome />
<CateHome />
<ShowProductList />
<ShowProductList />
<PolicyFooter />
<Social />
<ShowroomList />
<FooterInfo />
</ScrollView>
</SafeAreaView>
);
}
const SliderHome = () => {
const imageSlider = [
'https://hanoicomputercdn.com/media/banner/04_Feb6a20714a3495fa80e985095a9a548f98.png',
'https://hanoicomputercdn.com/media/banner/19_Febbc8b55d8c3a6be385d8523c79eb4c8da.jpg',
'https://hanoicomputercdn.com/media/banner/25_Feb8a3b5d706fea215ed9004c6ad5ea9065.png'
]
return (
<View style={styles.slider}>
<Swiper style={styles.sliderSwipper} autoplay={true} showsButtons={false} index={3000} showsPagination={false}>
{
imageSlider.map((item, index) => {
return (<Image style={styles.imgSlider} key={index} source={{ uri: item }} />);
})
}
</Swiper>
</View>
);
}
const CateHome = () => {
return (
<View style={styles.catHomepage}>
<View style={styles.catHomepageItem}>
<Ionicons style={styles.catHomepageIcon} name="list-outline" size={28} />
<Text style={styles.catHomepageText}>Danh mục sản phẩm</Text>
</View>
<View style={styles.catHomepageItem}>
<Ionicons style={styles.catHomepageIcon} name="pricetags-outline" size={28} />
<Text style={styles.catHomepageText}>Chương trình khuyến mại</Text>
</View>
<View style={styles.catHomepageItem}>
<Ionicons style={styles.catHomepageIcon} name="search-outline" size={28} />
<Text style={styles.catHomepageText}>Sản phẩm vừa xem</Text>
</View>
<View style={styles.catHomepageItem}>
<Ionicons style={styles.catHomepageIcon} name="build-outline" size={28} />
<Text style={styles.catHomepageText}>Xây dựng cấu hình</Text>
</View>
</View>
);
}
const ShowProductList = () => {
const itemProductHomeStyle = {
width: 180,
borderRadius: 5,
margin: 5,
borderWidth: 1,
borderColor: '#e8e8e8',
}
const productData = [
{
id: 1,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 30000000,
marketPrice: 50000000,
quantity: 1,
},
{
id: 2,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 25000000,
marketPrice: 50000000,
quantity: 0,
},
{
id: 3,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 35000000,
marketPrice: 50000000,
quantity: 1,
},
{
id: 4,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 40000000,
marketPrice: 50000000,
quantity: 1,
},
{
id: 5,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 30000000,
marketPrice: 50000000,
quantity: 1,
},
]
return (
<View style={styles.bloxProductHome}>
<Text style={styles.titleProductHome}>Lap top, máy tính xách tay</Text>
<View style={styles.listProductHomeBao}>
<ScrollView horizontal={true} style={styles.listProductHome}>
{
productData.map(item => <ShowProductItem key={item.id} id={item.id} productName={item.productName}
productSKU={item.productSKU} productImage={item.productImage} price={item.price} marketPrice={item.marketPrice} quantity={item.quantity} privateStyle={itemProductHomeStyle}
/>)
}
</ScrollView>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
slider: {
width: winWidth,
marginBottom: 20,
height: ratio * 430,
},
sliderSwipper: {
},
imgSlider: {
width: winWidth,
height: 430 * ratio,
},
catHomepage: {
width: winWidth,
marginBottom: 20,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
catHomepageItem: {
width: winWidth / 4,
padding: 10,
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
alignItems: 'center',
},
catHomepageIcon: {
width: 48,
height: 48,
backgroundColor: '#2b3179',
textAlign: 'center',
lineHeight: 48,
borderRadius: 24,
overflow: 'hidden',
color: '#fff',
marginBottom: 5,
},
catHomepageText: {
fontSize: 12,
textAlign: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: '#ff00cc',
},
bloxProductHome: {
width: winWidth,
marginBottom: 20,
padding: 10,
},
titleProductHome: {
backgroundColor: '#243a76',
fontSize: 15,
paddingLeft: 10,
paddingRight: 10,
borderRadius: 3,
lineHeight: 40,
marginBottom: 5,
textTransform: 'uppercase',
fontWeight: '700',
color: '#fff',
overflow: 'hidden',
},
listProductHomeBao: {
overflow: 'hidden',
},
listProductHome: {
marginRight: -5,
marginLeft: -5,
},
});

549
screens/TabTwoScreen.tsx Normal file
View File

@@ -0,0 +1,549 @@
import 'react-native-gesture-handler';
import * as React from 'react';
import { useState } from 'react';
import { Alert, Button, Image, StyleSheet, Dimensions, SafeAreaView, ScrollView, TouchableOpacity, Modal, Pressable } from 'react-native';
import Constants from 'expo-constants';
import { Ionicons, FontAwesome } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import Swiper from 'react-native-swiper';
import styled from 'styled-components';
import { PolicyFooter, Social, ShowroomList, FooterInfo } from '../components/footer/footerMain';
import { ShowProductItem } from '../components/product/productItem';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View, } from '../components/Themed';
import useColorScheme from '../hooks/useColorScheme';
import TabOneScreen from './TabOneScreen';
export default function TabTwoScreen() {
const [showFilter, setFilter] = useState(false);
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<View style={styles.brecrumb}>
<Text style={styles.brecrumbText}>Trang chủ</Text>
<FontAwesome style={styles.brecrumbIcon} name="angle-right" />
<Text style={styles.brecrumbTextLast}>Laptop, Máy Tính Xách Tay</Text>
</View>
<View style={styles.listCategoryChild}>
<TouchableOpacity style={styles.listCategoryChildItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.listCategoryChildName}>Laptop Asus</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.listCategoryChildItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.listCategoryChildName}>Laptop Dell</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.listCategoryChildItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.listCategoryChildName}>Laptop HP</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.listCategoryChildItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.listCategoryChildName}>Laptop Lenovo</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.listCategoryChildItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.listCategoryChildName}>Laptop Acer</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.listCategoryChildItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.listCategoryChildName}>Laptop MSI</Text>
</TouchableOpacity>
</View>
<View style={styles.listFilter}>
<FilterBrand />
<FilterPrice />
</View>
<ShowProductListCategory />
<Paging />
<ProductCategorySummary />
<PolicyFooter />
<Social />
<ShowroomList />
<FooterInfo />
</ScrollView>
</SafeAreaView>
);
}
const winWidth = Dimensions.get('window').width; //full width
const winHeight = Dimensions.get('window').height; //full height
const halfWinWidth = winWidth / 2;
const ratio = winWidth / 930; //541 is actual image width
type ItemTyep = {id:string, title: string}
const FilterBrand = () => {
const [modalVisible, setModalVisible] = useState(false);
const dataBrandFilter = [
{
url: '/',
name: 'Acer',
},
{
url: '/',
name: 'Asus',
},
{
url: '/',
name: 'HP',
},
{
url: '/',
name: 'Dell',
},
{
url: '/',
name: 'Apple',
},
]
return (
<View style={styles.filterBox}>
<TouchableOpacity style={styles.filterBoxTitle} onPress={() => setModalVisible(true)}>
<Text style={styles.filterBoxTitleName}>Thứ tự sản phẩm</Text>
<FontAwesome style={styles.filterBoxTitleIcon} name="caret-down" />
</TouchableOpacity>
<Modal visible={modalVisible} animationType="slide" transparent={true} onRequestClose={() => { setModalVisible(!modalVisible); }}>
<Pressable onPress={() => setModalVisible(!modalVisible)} style={styles.filterItemContent}>
<View style={styles.filterItemList}>
<View style={styles.filterItemListTitle}>
<Text style={styles.filterItemListTitleName}>Hãng sản xuất</Text>
<Pressable onPress={() => setModalVisible(!modalVisible)}>
<FontAwesome style={styles.filterItemListClose} name="times" />
</Pressable>
</View>
<ScrollView>
{
dataBrandFilter.map((item , index) =>
<FilterItem key={index} name={item.name} />
)
}
</ScrollView>
</View>
</Pressable>
</Modal>
</View>
)
}
const FilterPrice = () => {
const [modalVisible, setModalVisible] = useState(false);
const dataPriceFilter = [
{
url: '/',
name: '1000000',
},
{
url: '/',
name: '2000000',
},
{
url: '/',
name: '3000000',
},
{
url: '/',
name: '4000000',
},
{
url: '/',
name: '5000000',
},
]
return (
<View style={styles.filterBox}>
<TouchableOpacity style={styles.filterBoxTitle} onPress={() => setModalVisible(true)}>
<Text style={styles.filterBoxTitleName}>Khoảng giá</Text>
<FontAwesome style={styles.filterBoxTitleIcon} name="caret-down" />
</TouchableOpacity>
<Modal visible={modalVisible} animationType="slide" transparent={true} onRequestClose={() => { setModalVisible(!modalVisible); }}>
<Pressable onPress={() => setModalVisible(!modalVisible)} style={styles.filterItemContent}>
<View style={styles.filterItemList}>
<View style={styles.filterItemListTitle}>
<Text style={styles.filterItemListTitleName}>Khoảng giá</Text>
<Pressable onPress={() => setModalVisible(!modalVisible)}>
<FontAwesome style={styles.filterItemListClose} name="times" />
</Pressable>
</View>
<ScrollView>
{
dataPriceFilter.map((item , index) =>
<FilterItem key={index} name={item.name} />
)
}
</ScrollView>
</View>
</Pressable>
</Modal>
</View>
)
}
const FilterItem = (props: { name: string }) => {
const { name } = props;
return (
<Pressable style={styles.filterItem} onPress={() => Alert.alert('danh muc sp')}>
<Text style={styles.filterItemName}>{name}</Text>
</Pressable>
);
}
const ShowProductListCategory = () => {
const itemProductStyle = {
width: halfWinWidth,
borderBottomWidth: 1,
borderBottomColor: '#e8e8e8',
borderRightWidth: 1,
borderRightColor: '#e8e8e8',
}
const productData = [
{
id: 1,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 30000000,
marketPrice: 50000000,
quantity: 1,
},
{
id: 2,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 25000000,
marketPrice: 50000000,
quantity: 0,
},
{
id: 3,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 35000000,
marketPrice: 50000000,
quantity: 1,
},
{
id: 4,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 40000000,
marketPrice: 50000000,
quantity: 1,
},
{
id: 5,
productName: 'Laptop LG Gram 14ZD90N-V.AX55A5 (i5 1035G7/8GB RAM/512GBSSD/14.0 inch FHD/FP/Xám Bạc) (model 2020)',
productSKU: 'TESTSKU',
productImage: {
small: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
medium: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
large: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
original: 'https://hanoicomputercdn.com/media/product/120_52019_14zd90n_v_ax55a5.png',
},
price: 30000000,
marketPrice: 50000000,
quantity: 1,
},
]
return (
<View style={styles.boxProductCategory}>
<View style={styles.listProductCategory}>
{
productData.map(item => <ShowProductItem key={item.id} id={item.id} productName={item.productName}
productSKU={item.productSKU} productImage={item.productImage} price={item.price} marketPrice={item.marketPrice} quantity={item.quantity} privateStyle={itemProductStyle}
/>)
}
</View>
</View>
)
}
const Paging = () => {
const pagingData = [
{
url: '/',
name: 1,
isCurrent: 1,
},
{
url: '/',
name: 2,
isCurrent: 0,
},
{
url: '/',
name: 3,
isCurrent: 0,
},
{
url: '/',
name: 4,
isCurrent: 0,
},
{
url: '/',
name: 5,
isCurrent: 0,
}
]
return (
<View style={styles.boxPaging}>
<View style={styles.boxPagingList}>
{
pagingData.map((item, index) =>
<Pressable key={index} style={item.isCurrent == 1 ? styles.boxPagingItemCurrent : styles.boxPagingItem} onPress={() => Alert.alert('page')}>
<Text style={item.isCurrent == 1 ? styles.boxPagingItemCurrentText : styles.boxPagingItemText}>{item.name}</Text>
</Pressable>
)
}
</View>
</View>
)
}
const ProductCategorySummary = () => {
return(
<View style={styles.boxProductCategorySummary}>
<Text>NHỮNG ĐIỀU CẦN LƯU Ý KHI CHỌN MUA LAPTOP</Text>
<Text>Đ thể sở hữu đưc một sản phẩm chất lượng ưng ý nhất thì bạn cần xem xét các yếu tố như sau khi mua laptop:</Text>
<Text>Tốt nhất bạn nên lựa chọn những laptop thương hiệu nổi tiếng. Điều này phần nào đã chứng minh đưc chất lượng của laptop. Những thương hiệu đưc nhiều người ưa chuộng trong thời gian dài thì chắc chắn sản phẩm các ưu điểm nổi bật, mang đến nhiều giá trị tối ưu cho người dùng khi sử dụng sản phẩm. Khi đã chọn các thương hiệu nổi tiếng thì hàng chính hãng cũng điều bạn nên đc biệt quan tâm bởi hàng giả, hàng nhái hiện nay trên thị trường rất nhiều</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
brecrumb: {
display: 'flex',
width: winWidth,
paddingLeft: 10,
paddingRight: 10,
flexDirection: 'row',
height: 18,
alignItems: 'center',
marginTop: 10,
marginBottom: 10,
},
brecrumbText: {
fontSize: 13,
color: '#222',
},
brecrumbTextLast: {
fontSize: 13,
color: '#b7b7b7',
},
brecrumbIcon: {
fontSize: 13,
color: '#222',
marginLeft: 6,
marginRight: 6
},
listCategoryChild: {
width: winWidth,
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
paddingLeft: 10,
paddingRight: 10,
},
listCategoryChildItem: {
width: halfWinWidth - 15,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
height: 36,
backgroundColor: '#243a76',
marginBottom: 10,
borderRadius: 5,
},
listCategoryChildName: {
color: '#fff',
fontSize: 14,
},
listFilter: {
width: winWidth,
paddingLeft: 10,
paddingRight: 10,
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
},
filterBox: {
width: halfWinWidth - 15,
position: 'relative',
marginBottom: 10,
zIndex: -1,
},
filterBox1: {
zIndex: 1,
},
filterBoxTitle: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
height: 36,
backgroundColor: '#dcdcdc',
borderRadius: 5,
paddingLeft: 10,
paddingRight: 10,
zIndex: 1,
position: 'relative',
},
filterItemListTitleName: {
fontSize: 16,
fontWeight: 'bold',
textTransform: 'uppercase',
color: '#222',
},
filterItemListClose: {
fontSize: 16,
},
filterBoxTitleName: {
},
filterBoxTitleIcon: {},
filterItemContent: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.5)',
position: 'relative',
zIndex: 1,
},
filterItemList: {
width: winWidth - 30,
maxWidth: 300,
height: 450,
backgroundColor: '#fff',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 0,
},
shadowOpacity: 2.22,
shadowRadius: 2.22,
elevation: 3,
borderRadius: 5,
overflow: 'hidden',
position: 'relative',
zIndex: 2,
},
filterItemListTitle: {
height: 40,
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: '#e1e1e1',
paddingLeft: 10,
paddingRight: 10,
marginBottom: 10,
},
filterItem: {
width: '100%',
height: 30,
paddingLeft: 10,
paddingRight: 10,
alignItems: 'center',
flexDirection: 'row',
},
filterItemName: {},
boxProductCategory: {
width: winWidth,
},
listProductCategory: {
flexWrap: 'wrap',
display: 'flex',
flexDirection: 'row',
marginTop: 10,
borderTopColor: '#e8e8e8',
borderTopWidth: 1,
},
boxPaging: {
width: winWidth,
marginTop: 20,
marginBottom: 20,
},
boxPagingList: {
display: 'flex',
justifyContent: 'center',
flexDirection: 'row',
},
boxPagingItemCurrent: {
paddingHorizontal: 8,
paddingVertical: 5,
lineHeight: 16,
marginHorizontal: 2,
borderWidth: 1,
borderColor: '#bbb',
borderRadius: 3,
backgroundColor: '#243a76'
},
boxPagingItem: {
paddingHorizontal: 8,
paddingVertical: 5,
lineHeight: 16,
marginHorizontal: 2,
borderWidth: 1,
borderColor: '#bbb',
borderRadius: 3,
},
boxPagingItemCurrentText: {
color: '#fff',
fontSize: 14,
},
boxPagingItemText: {
color: '#333',
fontSize: 14,
},
boxProductCategorySummary: {
paddingLeft: 10,
paddingRight: 10,
marginBottom: 20,
},
});

12
screens/test.tsx Normal file
View File

@@ -0,0 +1,12 @@
import React from 'react';
import { Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }} >
<Text> Home Screen </Text>
</View>
);
}

12
tsconfig.json Normal file
View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"jsx": "react-native",
"lib": ["dom", "esnext"],
"moduleResolution": "node",
"noEmit": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"strict": true
}
}

17
types.tsx Normal file
View File

@@ -0,0 +1,17 @@
export type RootStackParamList = {
Root: undefined;
NotFound: undefined;
};
export type BottomTabParamList = {
TabOne: undefined;
TabTwo: undefined;
};
export type TabOneParamList = {
TabOneScreen: undefined;
};
export type TabTwoParamList = {
TabTwoScreen: undefined;
};