This commit is contained in:
Andi Firwansyah 2022-12-04 12:32:55 +07:00
parent bdca218c7f
commit f5ba03de84
15 changed files with 193 additions and 78 deletions

View File

@ -17,7 +17,7 @@
"services": "./src/services",
"store": "./src/store",
"global-styles": "./src/styles",
"utilites": "./src/utilites"
"utilities": "./src/utilities"
}
}
]

View File

@ -17,7 +17,7 @@ module.exports = {
services: './src/services',
store: './src/store',
'global-styles': './src/styles',
utilites: './src/utilites',
utilities: './src/utilities',
},
},
},

View File

@ -12,7 +12,7 @@
"services": ["src/services/*"],
"store": ["src/store/*"],
"global-styles": ["src/styles/*"],
"utilites": ["src/utilites/*"]
"utilities": ["src/utilities/*"]
}
}
}

View File

@ -19,6 +19,7 @@
"eslint-import-resolver-babel-module": "^5.3.1",
"eslint-plugin-import": "^2.26.0",
"i18next": "^22.0.6",
"lodash.debounce": "^4.0.8",
"moment": "^2.29.4",
"react": "18.1.0",
"react-i18next": "^12.0.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -1,4 +1,4 @@
import React, {useState} from 'react';
import React, {useEffect, useState, useMemo} from 'react';
import {
View,
StyleSheet,
@ -6,6 +6,8 @@ import {
Text,
TouchableOpacity,
TextInput,
FlatList,
Image,
} from 'react-native';
import {Colors, FONTS} from 'global-styles';
import {RFValue} from 'react-native-responsive-fontsize';
@ -14,19 +16,44 @@ import Modal from 'react-native-modal';
import {useTranslation} from 'react-i18next';
import MapView, {PROVIDER_GOOGLE, Marker} from 'react-native-maps';
const {width, height} = Dimensions.get('window');
import debounce from 'lodash.debounce';
import {searchPlace} from 'services';
let coordinateX = {
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
};
const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 0.001;
const _Maps = props => {
const {t} = useTranslation();
const [modal, setModal] = useState(false);
const [coordinate, setCoordinate] = useState({});
const {label, note, error, required} = props;
const [modal, setModal] = useState(false);
const [location, setLocation] = useState({
name: '',
address: '',
coordinate: {},
});
const [keyword, setKeyword] = useState('');
const [places, setPlaces] = useState([]);
useEffect(() => {
return () => {
debouncedResults.cancel();
};
});
const handleSearchPlace = async e => {
setKeyword(e);
const {_data, _error} = await searchPlace(e);
if (_error) {
console.log(_error);
return;
}
setPlaces(_data);
};
const debouncedResults = useMemo(() => {
return debounce(handleSearchPlace, 300);
}, []);
return (
<View style={styles.container}>
{label && (
@ -70,9 +97,11 @@ const _Maps = props => {
<Text style={styles.title}>
{t('select_outlet_location_text')}
</Text>
{coordinate?.latitude ? (
{location.coordinate?.latitude ? (
<TouchableOpacity
onPress={() => setCoordinate({})}
onPress={() =>
setLocation({name: '', address: '', coordinate: {}})
}
style={styles.buttonSearch}>
<Icon
name="search"
@ -82,7 +111,11 @@ const _Maps = props => {
</TouchableOpacity>
) : (
<View style={styles.inputSearchSection}>
<TextInput style={styles.input} placeholder="Cari" />
<TextInput
style={styles.input}
onChangeText={debouncedResults}
placeholder={t('search_placeholder')}
/>
<Icon
name="search"
type="Feather"
@ -92,63 +125,71 @@ const _Maps = props => {
)}
</View>
{!coordinate?.latitude && (
<View style={styles.locationContainer}>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
setCoordinate({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
})
}
style={styles.locationSection}>
<Icon
name="my-location"
type="MaterialIcons"
style={styles.myLoationIcon}
/>
<View style={styles.locationInfoSection(true)}>
<Text style={styles.locationInfoName}>
Warung Sop & Sate Sapi Pak Bayu
</Text>
<Text numberOfLines={2} style={styles.locationInfoAddress}>
Jl. Yudistiro No.2, RT.05/RW.11, Palgading, Sinduharjo,
Kec. Ngaglik, Kabupaten Sleman, Daerah Istimewa Yogyakarta
55581
</Text>
{!location.coordinate?.latitude && (
<FlatList
data={places}
keyExtractor={(item, index) => index.toString()}
renderItem={({item, index}) => (
<View style={styles.locationContainer}>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
setLocation({
name: item.text_id,
address: item.place_name_id,
coordinate: {
latitude: item.geometry.coordinates[1],
longitude: item.geometry.coordinates[0],
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LATITUDE_DELTA * ASPECT_RATIO,
},
})
}
style={styles.locationSection}>
<Icon
name="my-location"
type="MaterialIcons"
style={styles.myLoationIcon}
/>
<View style={styles.locationInfoSection(true)}>
<Text style={styles.locationInfoName}>
{item.text_id}
</Text>
<Text
numberOfLines={2}
style={styles.locationInfoAddress}>
{`${item.place_name_id}`}
</Text>
</View>
</TouchableOpacity>
</View>
</TouchableOpacity>
</View>
)}
/>
)}
{coordinate?.latitude && (
{location.coordinate?.latitude && (
<React.Fragment>
<View style={styles.mapSection}>
<MapView
provider={PROVIDER_GOOGLE} // remove if not using Google Maps
provider={PROVIDER_GOOGLE}
style={styles.map}
region={coordinate}>
<Marker
coordinate={coordinate}
title={'title'}
description={'description'}
/>
zoomEnabled={true}
initialRegion={location.coordinate}
onRegionChangeComplete={v =>
setLocation({...location, coordinate: v})
}>
<Marker coordinate={location.coordinate}>
<Image
source={require('assets/images/marker.png')}
style={styles.marker}
/>
</Marker>
</MapView>
</View>
<View style={styles.buttonSection}>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
setCoordinate({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
})
}
disabled
style={styles.locationSection}>
<Icon
name="my-location"
@ -157,14 +198,12 @@ const _Maps = props => {
/>
<View style={styles.locationInfoSection(false)}>
<Text style={styles.locationInfoName}>
Warung Sop & Sate Sapi Pak Bayu
{location.name}
</Text>
<Text
numberOfLines={2}
style={styles.locationInfoAddress}>
Jl. Yudistiro No.2, RT.05/RW.11, Palgading, Sinduharjo,
Kec. Ngaglik, Kabupaten Sleman, Daerah Istimewa
Yogyakarta 55581
{location.address}
</Text>
</View>
</TouchableOpacity>
@ -334,8 +373,9 @@ const styles = StyleSheet.create({
width: width,
},
map: {
flex: 1,
height: height - 0.5,
// flex: 1,
// height: 500,
height: height - width * 1,
},
buttonClose: {
backgroundColor: Colors.WHITE,
@ -379,6 +419,19 @@ const styles = StyleSheet.create({
fontSize: RFValue(12),
marginTop: width * 0.005,
},
marker: {
width: width * 0.15,
height: width * 0.15,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
});
export default _Maps;

View File

@ -1,10 +1,14 @@
import React from 'react';
import {View, Text, Image} from 'react-native';
import {View, Text, Image, TouchableOpacity} from 'react-native';
import styles from './styles';
const ProductRaw = props => {
const {onPress} = props;
return (
<View style={styles.container}>
<TouchableOpacity
onPress={onPress}
activeOpacity={0.5}
style={styles.container}>
<Image
source={require('assets/images/product-1.png')}
style={styles.image}
@ -16,7 +20,7 @@ const ProductRaw = props => {
</Text>
<Text style={styles.price}>Rp15.000</Text>
</View>
</View>
</TouchableOpacity>
);
};

View File

@ -48,9 +48,11 @@ export default {
menu_category_title: 'Menu Category',
category_list_text: 'Category list',
add_category_title: 'Add Category',
update_category_title: 'Change Category',
category_name_text: 'Category name',
change_text: 'Change',
add_new_menu_title: 'Add Menus',
update_new_menu_title: 'Update Menus',
menu_photo_text: 'Menu photo',
menu_photo_note: 'Upload attractive photos to make potential customers more interested.',
upload_image_text: 'Upload photos',
@ -59,4 +61,5 @@ export default {
price_text: 'Price (Rp)',
name_food_placeholder: 'Ex: Chicken Teriyaki Rice Set',
description_food_placeholder: 'Ex: Chicken Katsu + Steam Rice + Salad + Katsu Sauce + Spicy Mayonnaise',
search_placeholder: 'Search . . .',
};

View File

@ -48,9 +48,11 @@ export default {
menu_category_title: 'Kategori Menu',
category_list_text: 'Daftar kategori',
add_category_title: 'Tambah Kategori',
update_category_title: 'Ubah Kategori',
category_name_text: 'Nama kategori',
change_text: 'Ubah',
add_new_menu_title: 'Tambah Menu',
update_new_menu_title: 'Update Menu',
menu_photo_text: 'Foto menu',
menu_photo_note: 'Upload foto yang menarik agar calon pelangganmu makin tertarik.',
upload_image_text: 'Upload foto',
@ -59,4 +61,5 @@ export default {
price_text: 'Harga (Rp)',
name_food_placeholder: 'Cth: Chicken Teriyaki Rice Set',
description_food_placeholder: 'Cth: Chicken Katsu + Steam Rice + Salad + Katsu Sauce + Spicy Mayonnaise',
search_placeholder: 'Cari . . .',
};

View File

@ -5,12 +5,18 @@ import {Colors} from 'global-styles';
import {useTranslation} from 'react-i18next';
import styles from './styles';
const AddMenuCategory = ({navigation}) => {
const AddMenuCategory = ({route, navigation}) => {
const {t} = useTranslation();
const [category, setCategory] = useState('');
const {type} = route.params;
return (
<Container backgroundColor={Colors.WHITE}>
<Header navigation={navigation} smTitle={t('add_category_title')} />
<Header
navigation={navigation}
smTitle={t(
type === 'add' ? 'add_category_title' : 'update_category_title',
)}
/>
<View style={styles.container}>
<ScrollView>
<View style={styles.spacing} />

View File

@ -20,7 +20,9 @@ const MenuCategory = ({navigation}) => {
<View style={[styles.sceneTopSection, styles.horizontal]}>
<Text style={styles.sceneLabel}>{t('category_list_text')}</Text>
<TouchableOpacity
onPress={() => navigation.navigate('AddMenuCategory')}
onPress={() =>
navigation.navigate('AddMenuCategory', {type: 'add'})
}
style={styles.buttonAddCategory}>
<Text style={styles.buttonAddCategoryTitle}>Tambah</Text>
</TouchableOpacity>

View File

@ -5,12 +5,18 @@ import {Colors} from 'global-styles';
import {useTranslation} from 'react-i18next';
import styles from './styles';
const AddProduct = ({navigation}) => {
const AddProduct = ({route, navigation}) => {
const {t} = useTranslation();
const [price, setPrice] = useState('0');
const {type} = route.params;
return (
<Container backgroundColor={Colors.WHITE}>
<Header navigation={navigation} smTitle={t('add_new_menu_title')} />
<Header
navigation={navigation}
smTitle={t(
type === 'add' ? 'add_new_menu_title' : 'update_new_menu_title',
)}
/>
<View style={styles.container}>
<ScrollView>
<View style={styles.spacing} />

View File

@ -13,18 +13,24 @@ const ProductList = ({navigation}) => {
<Header
navigation={navigation}
smTitle={'Mie Ayam'}
onButtonPress={() => navigation.navigate('AddProduct')}
onButtonPress={() =>
navigation.navigate('AddMenuCategory', {type: 'update'})
}
/>
<View style={styles.container}>
<ScrollView>
<View style={styles.spacing} />
<ProductRaw />
<ProductRaw
onPress={() => navigation.navigate('AddProduct', {type: 'update'})}
/>
<View style={styles.separator} />
<ProductRaw />
<ProductRaw
onPress={() => navigation.navigate('AddProduct', {type: 'update'})}
/>
</ScrollView>
<Button
title="Tambah"
onPress={() => navigation.navigate('AddProduct')}
onPress={() => navigation.navigate('AddProduct', {type: 'add'})}
/>
</View>
</Container>

View File

@ -1 +1,2 @@
export * from './auth-services';
export * from './master-service';

View File

@ -0,0 +1,30 @@
import {HttpRequest, RestConstant, StatusCode} from 'constants';
const initialState = {
_data: undefined,
_error: undefined,
};
export const searchPlace = async keyword => {
const newState = {...initialState};
// eslint-disable-next-line prettier/prettier
const access_token = 'pk.eyJ1IjoiYW5kaXdhd2FuayIsImEiOiJja2ZuZmViejUxbHltMnFrdTFreHZ1MDIyIn0.n7s5b5vF6YqcKrMHxB8p1Q';
const config = `country=id&types=place,address,country,postcode,region,locality,district,neighborhood,poi&language=id&access_token=${access_token}`;
const url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${keyword}.json?${config}`;
try {
const response = await HttpRequest.get(url);
switch (response.request.status) {
case StatusCode.OK:
newState._data = response.data.features;
return newState;
case StatusCode.UNAUTHORIZED:
newState._error = response.response.data;
return newState;
case StatusCode.SERVER_ERROR:
newState._error = response.response.data;
return newState;
}
} catch (error) {
console.log(error);
}
};