ordering-ui-react-native 0.12.59 → 0.12.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/components/AppleLogin/index.tsx +14 -8
- package/src/components/Messages/index.tsx +4 -4
- package/src/components/OrderCreating/index.tsx +1 -2
- package/src/components/OrderDetails/index.tsx +7 -1
- package/src/navigators/HomeNavigator.tsx +0 -1
- package/themes/business/src/components/Chat/index.tsx +31 -16
- package/themes/doordash/src/components/LastOrders/index.tsx +1 -1
- package/themes/original/index.tsx +4 -0
- package/themes/original/src/components/BusinessBasicInformation/index.tsx +1 -1
- package/themes/original/src/components/BusinessController/index.tsx +9 -2
- package/themes/original/src/components/BusinessMenuList/index.tsx +132 -0
- package/themes/original/src/components/BusinessMenuList/styles.tsx +15 -0
- package/themes/original/src/components/BusinessPreorder/index.tsx +474 -0
- package/themes/original/src/components/BusinessPreorder/styles.tsx +60 -0
- package/themes/original/src/components/BusinessesListing/index.tsx +2 -1
- package/themes/original/src/components/HighestRatedBusinesses/index.tsx +3 -1
- package/themes/original/src/types/index.tsx +22 -1
- package/themes/single-business/src/components/Cart/index.tsx +47 -26
- package/themes/single-business/src/components/Cart/styles.tsx +9 -0
- package/themes/single-business/src/components/TaxInformation/index.tsx +22 -17
- package/themes/single-business/src/components/TaxInformation/styles.tsx +3 -2
- package/themes/single-business/src/types/index.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ordering-ui-react-native",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.63",
|
|
4
4
|
"description": "Reusable components made in react native",
|
|
5
5
|
"main": "src/index.tsx",
|
|
6
6
|
"author": "ordering.inc",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"react-native-background-timer": "^2.4.1",
|
|
70
70
|
"react-native-bootsplash": "^3.2.3",
|
|
71
71
|
"react-native-calendar-picker": "^7.1.2",
|
|
72
|
+
"react-native-calendar-strip": "^2.2.5",
|
|
72
73
|
"react-native-country-picker-modal": "^2.0.0",
|
|
73
74
|
"react-native-credit-card-input": "^0.4.1",
|
|
74
75
|
"react-native-document-picker": "^5.2.0",
|
|
@@ -10,8 +10,7 @@ import { useTheme } from 'styled-components/native';
|
|
|
10
10
|
import { OText } from '../shared';
|
|
11
11
|
import { AppleLoginParams } from '../../types';
|
|
12
12
|
|
|
13
|
-
export const AppleLogin = (props
|
|
14
|
-
|
|
13
|
+
export const AppleLogin = (props: AppleLoginParams) => {
|
|
15
14
|
const {
|
|
16
15
|
notificationState,
|
|
17
16
|
handleErrors,
|
|
@@ -55,7 +54,7 @@ export const AppleLogin = (props : AppleLoginParams) => {
|
|
|
55
54
|
handleErrors && handleErrors(t('ERROR_LOGIN_APPLE', 'Error login with apple'))
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
} catch (error
|
|
57
|
+
} catch (error: any) {
|
|
59
58
|
handleErrors && handleErrors(error.message)
|
|
60
59
|
}
|
|
61
60
|
} else {
|
|
@@ -70,15 +69,22 @@ export const AppleLogin = (props : AppleLoginParams) => {
|
|
|
70
69
|
});
|
|
71
70
|
const { code } = await appleAuthAndroid.signIn();
|
|
72
71
|
handleLoginApple(code)
|
|
73
|
-
} catch (error
|
|
72
|
+
} catch (error: any) {
|
|
74
73
|
handleErrors && handleErrors(error?.message)
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
const handleLoginApple = async (code: string) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
let body: any
|
|
79
|
+
if (Platform.OS === 'ios') {
|
|
80
|
+
body = {
|
|
81
|
+
code,
|
|
82
|
+
platform: 'ios'
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
body = {
|
|
86
|
+
code
|
|
87
|
+
}
|
|
82
88
|
}
|
|
83
89
|
if (notificationState?.notification_token) {
|
|
84
90
|
body.notification_token = notificationState.notification_token
|
|
@@ -99,7 +105,7 @@ export const AppleLogin = (props : AppleLoginParams) => {
|
|
|
99
105
|
} else {
|
|
100
106
|
handleErrors && handleErrors(result || t('ERROR_LOGIN_AUTH_APPLE', 'Error login auth with apple'))
|
|
101
107
|
}
|
|
102
|
-
} catch (error
|
|
108
|
+
} catch (error: any) {
|
|
103
109
|
handleLoading && handleLoading(false)
|
|
104
110
|
handleErrors && handleErrors(error?.message)
|
|
105
111
|
}
|
|
@@ -67,10 +67,10 @@ const MessagesUI = (props: MessagesParams) => {
|
|
|
67
67
|
const theme = useTheme();
|
|
68
68
|
|
|
69
69
|
const quickMessageList = [
|
|
70
|
-
{ key: '
|
|
71
|
-
{ key: '
|
|
72
|
-
{ key: '
|
|
73
|
-
{ key: '
|
|
70
|
+
{ key: 'customer_message_1', text: t('CUSTOMER_MESSAGE_1', 'customer_message_1') },
|
|
71
|
+
{ key: 'customer_message_2', text: t('CUSTOMER_MESSAGE_2', 'customer_message_2') },
|
|
72
|
+
{ key: 'customer_message_3', text: t('CUSTOMER_MESSAGE_3', 'customer_message_3') },
|
|
73
|
+
{ key: 'customer_message_4', text: t('CUSTOMER_MESSAGE_4', 'customer_message_4') }
|
|
74
74
|
]
|
|
75
75
|
|
|
76
76
|
const [formattedMessages, setFormattedMessages] = useState<Array<any>>([])
|
|
@@ -86,7 +86,7 @@ export const OrderCreating = (props: any) => {
|
|
|
86
86
|
if (business?.address) {
|
|
87
87
|
AsyncStorage.setItem(
|
|
88
88
|
'business-address',
|
|
89
|
-
|
|
89
|
+
business?.address
|
|
90
90
|
);
|
|
91
91
|
setAddress(business?.address)
|
|
92
92
|
}
|
|
@@ -97,7 +97,6 @@ export const OrderCreating = (props: any) => {
|
|
|
97
97
|
if (isOrderDetail) {
|
|
98
98
|
try {
|
|
99
99
|
const value = await AsyncStorage.getItem('business-address');
|
|
100
|
-
value != null ? JSON.parse(value) : null;
|
|
101
100
|
setAddress(value)
|
|
102
101
|
} catch {
|
|
103
102
|
console.log('err')
|
|
@@ -105,7 +105,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
105
105
|
const [openModalForDriver, setOpenModalForDriver] = useState(false)
|
|
106
106
|
const [unreadAlert, setUnreadAlert] = useState({ business: false, driver: false })
|
|
107
107
|
const [isReviewed, setIsReviewed] = useState(false)
|
|
108
|
-
const [openOrderCreating, setOpenOrderCreating] = useState(
|
|
108
|
+
const [openOrderCreating, setOpenOrderCreating] = useState(false)
|
|
109
109
|
const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, data: null })
|
|
110
110
|
const { order, loading, businessData, error } = props.order
|
|
111
111
|
const isTaxIncluded = order?.tax_type === 1
|
|
@@ -245,6 +245,12 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
245
245
|
}
|
|
246
246
|
}, [loading])
|
|
247
247
|
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
AsyncStorage.getItem('business-address', (err, result) => {
|
|
250
|
+
if (result !== null) setOpenOrderCreating(true)
|
|
251
|
+
})
|
|
252
|
+
}, [])
|
|
253
|
+
|
|
248
254
|
return (
|
|
249
255
|
<OrderDetailsContainer keyboardShouldPersistTaps='handled'>
|
|
250
256
|
{order && order?.id && !error && !loading && (
|
|
@@ -21,7 +21,6 @@ import HelpOrder from '../pages/HelpOrder'
|
|
|
21
21
|
import HelpGuide from '../pages/HelpGuide'
|
|
22
22
|
import HelpAccountAndPayment from '../pages/HelpAccountAndPayment'
|
|
23
23
|
import Splash from '../pages/Splash';
|
|
24
|
-
|
|
25
24
|
const Stack = createStackNavigator();
|
|
26
25
|
|
|
27
26
|
const HomeNavigator = (e : any) => {
|
|
@@ -66,14 +66,22 @@ const ChatUI = (props: MessagesParams) => {
|
|
|
66
66
|
const [, t] = useLanguage();
|
|
67
67
|
const [, { showToast }] = useToast();
|
|
68
68
|
const theme = useTheme();
|
|
69
|
+
const [messageList, setMessageList] = useState<any>([])
|
|
69
70
|
|
|
70
|
-
const
|
|
71
|
+
const storeMessageList: any = [
|
|
71
72
|
{ key: 'store_message_1', text: t('STORE_MESSAGE_1', 'store_message_1') },
|
|
72
73
|
{ key: 'store_message_2', text: t('STORE_MESSAGE_2', 'store_message_2') },
|
|
73
74
|
{ key: 'store_message_3', text: t('STORE_MESSAGE_3', 'store_message_3') },
|
|
74
75
|
{ key: 'store_message_4', text: t('STORE_MESSAGE_4', 'store_message_4') }
|
|
75
76
|
]
|
|
76
77
|
|
|
78
|
+
const driverMessageList: any = [
|
|
79
|
+
{ key: 'driver_message_1', text: t('DRIVER_MESSAGE_1', 'driver_message_1') },
|
|
80
|
+
{ key: 'driver_message_2', text: t('DRIVER_MESSAGE_2', 'driver_message_2') },
|
|
81
|
+
{ key: 'driver_message_3', text: t('DRIVER_MESSAGE_3', 'driver_message_3') },
|
|
82
|
+
{ key: 'driver_message_4', text: t('DRIVER_MESSAGE_4', 'driver_message_4') }
|
|
83
|
+
]
|
|
84
|
+
|
|
77
85
|
const handleClickQuickMessage = (text: string) => {
|
|
78
86
|
setMessage && setMessage(`${message}${text}`)
|
|
79
87
|
}
|
|
@@ -464,6 +472,12 @@ const ChatUI = (props: MessagesParams) => {
|
|
|
464
472
|
);
|
|
465
473
|
};
|
|
466
474
|
|
|
475
|
+
useEffect(() => {
|
|
476
|
+
if (user.level === 2) setMessageList(storeMessageList)
|
|
477
|
+
else if (user.level === 4) setMessageList(driverMessageList)
|
|
478
|
+
else setMessageList([])
|
|
479
|
+
}, [user])
|
|
480
|
+
|
|
467
481
|
useEffect(() => {
|
|
468
482
|
let newMessages: Array<any> = [];
|
|
469
483
|
const console = (
|
|
@@ -754,21 +768,22 @@ const ChatUI = (props: MessagesParams) => {
|
|
|
754
768
|
horizontal
|
|
755
769
|
showsHorizontalScrollIndicator={false}
|
|
756
770
|
>
|
|
757
|
-
{
|
|
758
|
-
<
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
771
|
+
{messageList.map((quickMessage: any, i: number) => (
|
|
772
|
+
<React.Fragment key={i}>
|
|
773
|
+
<OButton
|
|
774
|
+
text={quickMessage.text}
|
|
775
|
+
bgColor='#E9ECEF'
|
|
776
|
+
borderColor='#E9ECEF'
|
|
777
|
+
imgRightSrc={null}
|
|
778
|
+
textStyle={{
|
|
779
|
+
fontSize: 11,
|
|
780
|
+
lineHeight: 16,
|
|
781
|
+
color: '#414954'
|
|
782
|
+
}}
|
|
783
|
+
style={{ ...styles.editButton }}
|
|
784
|
+
onClick={() => handleClickQuickMessage(quickMessage.text)}
|
|
785
|
+
/>
|
|
786
|
+
</React.Fragment>
|
|
772
787
|
))}
|
|
773
788
|
</QuickMessageContainer>
|
|
774
789
|
</View>
|
|
@@ -15,6 +15,8 @@ import { MomentOption } from './src/components/MomentOption';
|
|
|
15
15
|
import { OrdersOption } from './src/components/OrdersOption';
|
|
16
16
|
import { OrderDetails } from './src/components/OrderDetails';
|
|
17
17
|
import { OrderProgress } from './src/components/OrderProgress';
|
|
18
|
+
import { BusinessPreorder } from './src/components/BusinessPreorder';
|
|
19
|
+
import { BusinessMenuList } from './src/components/BusinessMenuList';
|
|
18
20
|
import { UserProfileForm } from './src/components/UserProfileForm';
|
|
19
21
|
import { ReviewOrder } from './src/components/ReviewOrder';
|
|
20
22
|
import { UserProfile } from './src/components/UserProfile';
|
|
@@ -69,8 +71,10 @@ export {
|
|
|
69
71
|
OrdersOption,
|
|
70
72
|
OrderDetails,
|
|
71
73
|
OrderProgress,
|
|
74
|
+
BusinessPreorder,
|
|
72
75
|
UserProfileForm,
|
|
73
76
|
ReviewOrder,
|
|
77
|
+
BusinessMenuList,
|
|
74
78
|
UserProfile,
|
|
75
79
|
Help,
|
|
76
80
|
HelpAccountAndPayment,
|
|
@@ -25,7 +25,7 @@ import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5';
|
|
|
25
25
|
import FastImage from 'react-native-fast-image'
|
|
26
26
|
|
|
27
27
|
export const BusinessControllerUI = (props: BusinessControllerParams) => {
|
|
28
|
-
const { business, handleClick } = props;
|
|
28
|
+
const { business, handleClick, navigation } = props;
|
|
29
29
|
const [{ parsePrice, parseDistance, parseNumber, optimizeImage }] =
|
|
30
30
|
useUtils();
|
|
31
31
|
const [orderState] = useOrder();
|
|
@@ -98,8 +98,15 @@ export const BusinessControllerUI = (props: BusinessControllerParams) => {
|
|
|
98
98
|
return _types.join(', ');
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
const handleBusinessClick = (selectedBusiness: any) => {
|
|
102
|
+
if (business?.open) handleClick && handleClick(selectedBusiness)
|
|
103
|
+
else {
|
|
104
|
+
navigation.navigate('BusinessPreorder', { business: selectedBusiness, handleBusinessClick: handleClick })
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
101
108
|
return (
|
|
102
|
-
<Card activeOpacity={1} onPress={() =>
|
|
109
|
+
<Card activeOpacity={1} onPress={() => handleBusinessClick(business)}>
|
|
103
110
|
<BusinessHero>
|
|
104
111
|
<FastImage
|
|
105
112
|
style={{ height: 120 }}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { useLanguage, BusinessMenuListing } from 'ordering-components/native'
|
|
3
|
+
import { OModal, OText } from '../shared'
|
|
4
|
+
import { BusinessMenuListParams } from '../../types'
|
|
5
|
+
import { View, StyleSheet, TouchableOpacity, Text } from 'react-native'
|
|
6
|
+
import { useTheme } from 'styled-components/native'
|
|
7
|
+
import IconAntDesign from 'react-native-vector-icons/AntDesign'
|
|
8
|
+
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
|
9
|
+
import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'
|
|
10
|
+
import { MenuListWrapper, DropOption } from './styles'
|
|
11
|
+
|
|
12
|
+
const BusinessMenuListUI = (props: BusinessMenuListParams) => {
|
|
13
|
+
const {
|
|
14
|
+
menu,
|
|
15
|
+
businessMenuList,
|
|
16
|
+
setMenu
|
|
17
|
+
} = props
|
|
18
|
+
|
|
19
|
+
const [, t] = useLanguage()
|
|
20
|
+
const theme = useTheme()
|
|
21
|
+
const [isShowMenuList, setIsShowMenuList] = useState(false)
|
|
22
|
+
|
|
23
|
+
const styles = StyleSheet.create({
|
|
24
|
+
selectOption: {
|
|
25
|
+
backgroundColor: theme.colors.backgroundGray100,
|
|
26
|
+
borderRadius: 7.6,
|
|
27
|
+
paddingVertical: 10,
|
|
28
|
+
paddingHorizontal: 14,
|
|
29
|
+
flexDirection: 'row',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
justifyContent: 'space-between',
|
|
32
|
+
height: 44
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const handleClickMenu = (option: any) => {
|
|
37
|
+
setMenu(option)
|
|
38
|
+
setIsShowMenuList(false)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
{businessMenuList.loading ? (
|
|
44
|
+
<Placeholder Animation={Fade}>
|
|
45
|
+
<View>
|
|
46
|
+
<PlaceholderLine height={44}/>
|
|
47
|
+
</View>
|
|
48
|
+
</Placeholder>
|
|
49
|
+
) : (
|
|
50
|
+
<TouchableOpacity onPress={() => setIsShowMenuList(true)}>
|
|
51
|
+
<View style={styles.selectOption}>
|
|
52
|
+
<OText
|
|
53
|
+
size={14}
|
|
54
|
+
color={theme.colors.disabled}
|
|
55
|
+
style={{
|
|
56
|
+
lineHeight: 24,
|
|
57
|
+
flex: 1
|
|
58
|
+
}}
|
|
59
|
+
numberOfLines={1}
|
|
60
|
+
ellipsizeMode="tail"
|
|
61
|
+
>
|
|
62
|
+
{menu?.name || t('MENU_NAME', 'Menu name')}
|
|
63
|
+
</OText>
|
|
64
|
+
<IconAntDesign
|
|
65
|
+
name='down'
|
|
66
|
+
color={theme.colors.textThird}
|
|
67
|
+
size={16}
|
|
68
|
+
/>
|
|
69
|
+
</View>
|
|
70
|
+
</TouchableOpacity>
|
|
71
|
+
)}
|
|
72
|
+
|
|
73
|
+
<OModal
|
|
74
|
+
open={isShowMenuList}
|
|
75
|
+
onClose={() => setIsShowMenuList(false)}
|
|
76
|
+
customClose
|
|
77
|
+
entireModal
|
|
78
|
+
>
|
|
79
|
+
<MenuListWrapper>
|
|
80
|
+
<TouchableOpacity onPress={() => setIsShowMenuList(false)} style={{ marginBottom: 12 }}>
|
|
81
|
+
<IconAntDesign
|
|
82
|
+
name='close'
|
|
83
|
+
color={theme.colors.textThird}
|
|
84
|
+
size={24}
|
|
85
|
+
/>
|
|
86
|
+
</TouchableOpacity>
|
|
87
|
+
{businessMenuList?.menus && businessMenuList?.menus.length > 0 && businessMenuList.menus.map((option: any, index: number) => (
|
|
88
|
+
<TouchableOpacity
|
|
89
|
+
key={index}
|
|
90
|
+
onPress={() => handleClickMenu(option)}
|
|
91
|
+
>
|
|
92
|
+
<DropOption
|
|
93
|
+
selected={option.id === menu.id}
|
|
94
|
+
>
|
|
95
|
+
<View style={{ marginRight: 10 }}>
|
|
96
|
+
{option.id === menu.id ? (
|
|
97
|
+
<MaterialCommunityIcons
|
|
98
|
+
name='radiobox-marked'
|
|
99
|
+
size={24}
|
|
100
|
+
color={theme.colors.primary}
|
|
101
|
+
/>
|
|
102
|
+
) : (
|
|
103
|
+
<MaterialCommunityIcons
|
|
104
|
+
name='radiobox-blank'
|
|
105
|
+
size={24}
|
|
106
|
+
color={theme.colors.arrowColor}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
</View>
|
|
110
|
+
<Text
|
|
111
|
+
numberOfLines={1}
|
|
112
|
+
ellipsizeMode="tail"
|
|
113
|
+
style={{flex: 1}}
|
|
114
|
+
>{option.name}</Text>
|
|
115
|
+
</DropOption>
|
|
116
|
+
</TouchableOpacity>
|
|
117
|
+
))}
|
|
118
|
+
</MenuListWrapper>
|
|
119
|
+
</OModal>
|
|
120
|
+
</>
|
|
121
|
+
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const BusinessMenuList = (props: any) => {
|
|
126
|
+
const businessMenuListProps = {
|
|
127
|
+
...props,
|
|
128
|
+
UIComponent: BusinessMenuListUI,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return <BusinessMenuListing {...businessMenuListProps} />;
|
|
132
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import styled from 'styled-components/native'
|
|
2
|
+
|
|
3
|
+
export const MenuListWrapper = styled.ScrollView`
|
|
4
|
+
padding: 20px 40px 30px 40px;
|
|
5
|
+
`
|
|
6
|
+
|
|
7
|
+
export const DropOption = styled.View`
|
|
8
|
+
padding: 10px;
|
|
9
|
+
margin-bottom: 5px;
|
|
10
|
+
font-size: 16px;
|
|
11
|
+
border-bottom-width: 1px;
|
|
12
|
+
border-bottom-color: ${(props: any) => props.theme.colors.lightGray};
|
|
13
|
+
flex-direction: row;
|
|
14
|
+
align-items: center;
|
|
15
|
+
`
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react'
|
|
2
|
+
import { TouchableOpacity, StyleSheet, View, Text } from 'react-native'
|
|
3
|
+
import { useLanguage, useUtils, useConfig, useOrder, MomentOption } from 'ordering-components/native'
|
|
4
|
+
import { OButton, OModal, OText } from '../shared'
|
|
5
|
+
import { useTheme } from 'styled-components/native'
|
|
6
|
+
import IconAntDesign from 'react-native-vector-icons/AntDesign'
|
|
7
|
+
import FastImage from 'react-native-fast-image'
|
|
8
|
+
import CalendarStrip from 'react-native-calendar-strip'
|
|
9
|
+
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
|
10
|
+
import { BusinessMenuList } from '../BusinessMenuList'
|
|
11
|
+
import Spinner from 'react-native-loading-spinner-overlay'
|
|
12
|
+
import { BusinessPreorderParams } from '../../types'
|
|
13
|
+
import moment from 'moment'
|
|
14
|
+
import {
|
|
15
|
+
PreOrderContainer,
|
|
16
|
+
BusinessInfoWrapper,
|
|
17
|
+
PreorderTypeWrapper,
|
|
18
|
+
MenuWrapper,
|
|
19
|
+
OrderTimeWrapper,
|
|
20
|
+
TimeListWrapper,
|
|
21
|
+
TimeContentWrapper,
|
|
22
|
+
TimeItem,
|
|
23
|
+
PreorderTypeListWrapper,
|
|
24
|
+
DropOption
|
|
25
|
+
} from './styles'
|
|
26
|
+
|
|
27
|
+
const BusinessPreorderUI = (props: BusinessPreorderParams) => {
|
|
28
|
+
const {
|
|
29
|
+
goToBack,
|
|
30
|
+
business,
|
|
31
|
+
datesList,
|
|
32
|
+
hoursList,
|
|
33
|
+
dateSelected,
|
|
34
|
+
timeSelected,
|
|
35
|
+
handleBusinessClick,
|
|
36
|
+
handleChangeDate,
|
|
37
|
+
handleChangeTime
|
|
38
|
+
} = props
|
|
39
|
+
|
|
40
|
+
const theme = useTheme()
|
|
41
|
+
const [, t] = useLanguage()
|
|
42
|
+
const [{ optimizeImage, parseTime }] = useUtils()
|
|
43
|
+
const [{ configs }] = useConfig()
|
|
44
|
+
const [orderState] = useOrder()
|
|
45
|
+
const [selectedPreorderType, setSelectedPreorderType] = useState({ key: 'business_hours', name: t('BUSINESS_HOURS', 'Business hours') })
|
|
46
|
+
const [isPreorderTypeList, setIsPreorderTypeList] = useState(false)
|
|
47
|
+
const [menu, setMenu] = useState({})
|
|
48
|
+
const [timeList, setTimeList] = useState<any>([])
|
|
49
|
+
const [selectDate, setSelectedDate] = useState<any>(null)
|
|
50
|
+
const [datesWhitelist, setDateWhitelist] = useState<any>([{start: null, end: null}])
|
|
51
|
+
|
|
52
|
+
const styles = StyleSheet.create({
|
|
53
|
+
businessLogo: {
|
|
54
|
+
backgroundColor: 'white',
|
|
55
|
+
width: 60,
|
|
56
|
+
height: 60,
|
|
57
|
+
borderRadius: 7.6,
|
|
58
|
+
justifyContent: 'center',
|
|
59
|
+
alignItems: 'center',
|
|
60
|
+
shadowColor: '#000000',
|
|
61
|
+
shadowOffset: { width: 0, height: 1 },
|
|
62
|
+
shadowOpacity: 0.1,
|
|
63
|
+
shadowRadius: 1,
|
|
64
|
+
elevation: 2
|
|
65
|
+
},
|
|
66
|
+
selectOption: {
|
|
67
|
+
backgroundColor: theme.colors.backgroundGray100,
|
|
68
|
+
borderRadius: 7.6,
|
|
69
|
+
paddingVertical: 10,
|
|
70
|
+
paddingHorizontal: 14,
|
|
71
|
+
flexDirection: 'row',
|
|
72
|
+
alignItems: 'center',
|
|
73
|
+
justifyContent: 'space-between',
|
|
74
|
+
height: 44
|
|
75
|
+
},
|
|
76
|
+
calendar: {
|
|
77
|
+
paddingBottom: 15,
|
|
78
|
+
borderBottomWidth: 1,
|
|
79
|
+
borderColor: theme.colors.backgroundGray200,
|
|
80
|
+
height: 90
|
|
81
|
+
},
|
|
82
|
+
calendarHeaderContainer: {
|
|
83
|
+
flex: 1,
|
|
84
|
+
justifyContent: 'flex-start',
|
|
85
|
+
textAlign: 'left',
|
|
86
|
+
marginBottom: 17,
|
|
87
|
+
borderBottomWidth: 1,
|
|
88
|
+
borderColor: theme.colors.backgroundGray200
|
|
89
|
+
},
|
|
90
|
+
calendarHeader: {
|
|
91
|
+
color: '#344050',
|
|
92
|
+
alignSelf: 'flex-start',
|
|
93
|
+
fontSize: 14,
|
|
94
|
+
fontWeight: '400'
|
|
95
|
+
},
|
|
96
|
+
dateNumber: {
|
|
97
|
+
color: '#B1BCCC',
|
|
98
|
+
fontSize: 16,
|
|
99
|
+
fontWeight: '500'
|
|
100
|
+
},
|
|
101
|
+
dateName: {
|
|
102
|
+
color: '#B1BCCC',
|
|
103
|
+
fontSize: 12,
|
|
104
|
+
textTransform: 'capitalize'
|
|
105
|
+
},
|
|
106
|
+
highlightDateName: {
|
|
107
|
+
color: '#344050',
|
|
108
|
+
fontSize: 12,
|
|
109
|
+
textTransform: 'capitalize'
|
|
110
|
+
},
|
|
111
|
+
highlightDateNumber: {
|
|
112
|
+
color: '#344050',
|
|
113
|
+
fontSize: 16,
|
|
114
|
+
textTransform: 'capitalize'
|
|
115
|
+
},
|
|
116
|
+
disabledDateName: {
|
|
117
|
+
color: '#B1BCCC',
|
|
118
|
+
fontSize: 10,
|
|
119
|
+
textTransform: 'capitalize',
|
|
120
|
+
opacity: 1
|
|
121
|
+
},
|
|
122
|
+
disabledDateNumber: {
|
|
123
|
+
color: '#B1BCCC',
|
|
124
|
+
fontSize: 14,
|
|
125
|
+
fontWeight: '500'
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
const preorderTypeList = [
|
|
130
|
+
{ key: 'business_menu', name: t('BUSINESS_MENU', 'Business menu') },
|
|
131
|
+
{ key: 'business_hours', name: t('BUSINESS_HOURS', 'Business hours') }
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
const handleClickPreorderType = (option: any) => {
|
|
135
|
+
setSelectedPreorderType(option)
|
|
136
|
+
setIsPreorderTypeList(false)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const getTimes = (curdate: any, menu: any) => {
|
|
140
|
+
const date = new Date()
|
|
141
|
+
var dateSeleted = new Date(curdate)
|
|
142
|
+
var times = []
|
|
143
|
+
for (var k = 0; k < menu.schedule[dateSeleted.getDay()].lapses.length; k++) {
|
|
144
|
+
var open = {
|
|
145
|
+
hour: menu.schedule[dateSeleted.getDay()].lapses[k].open.hour,
|
|
146
|
+
minute: menu.schedule[dateSeleted.getDay()].lapses[k].open.minute
|
|
147
|
+
}
|
|
148
|
+
var close = {
|
|
149
|
+
hour: menu.schedule[dateSeleted.getDay()].lapses[k].close.hour,
|
|
150
|
+
minute: menu.schedule[dateSeleted.getDay()].lapses[k].close.minute
|
|
151
|
+
}
|
|
152
|
+
for (var i = open.hour; i <= close.hour; i++) {
|
|
153
|
+
if (date.getDate() !== dateSeleted.getDate() || i >= date.getHours()) {
|
|
154
|
+
let hour = ''
|
|
155
|
+
let meridian = ''
|
|
156
|
+
if (configs?.format_time?.value === '12') {
|
|
157
|
+
if (i === 0) {
|
|
158
|
+
hour = '12'
|
|
159
|
+
meridian = ' ' + t('AM', 'AM')
|
|
160
|
+
} else if (i > 0 && i < 12) {
|
|
161
|
+
hour = (i < 10 ? '0' + i : i)
|
|
162
|
+
meridian = ' ' + t('AM', 'AM')
|
|
163
|
+
} else if (i === 12) {
|
|
164
|
+
hour = '12'
|
|
165
|
+
meridian = ' ' + t('PM', 'PM')
|
|
166
|
+
} else {
|
|
167
|
+
hour = ((i - 12 < 10) ? '0' + (i - 12) : `${(i - 12)}`)
|
|
168
|
+
meridian = ' ' + t('PM', 'PM')
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
hour = i < 10 ? '0' + i : i
|
|
172
|
+
}
|
|
173
|
+
for (let j = (i === open.hour ? open.minute : 0); j <= (i === close.hour ? close.minute : 59); j += 15) {
|
|
174
|
+
if (i !== date.getHours() || j >= date.getMinutes() || date.getDate() !== dateSeleted.getDate()) {
|
|
175
|
+
times.push({
|
|
176
|
+
text: hour + ':' + (j < 10 ? '0' + j : j) + meridian,
|
|
177
|
+
value: (i < 10 ? '0' + i : i) + ':' + (j < 10 ? '0' + j : j)
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return times
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const onSelectDate = (val: any) => {
|
|
188
|
+
setSelectedDate(val)
|
|
189
|
+
if (handleChangeDate) handleChangeDate(moment(val).format('YYYY-MM-DD'))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const LeftSelector = () => {
|
|
193
|
+
return (
|
|
194
|
+
<View style={{height: '100%', justifyContent: 'flex-end'}}>
|
|
195
|
+
<IconAntDesign
|
|
196
|
+
name='caretleft'
|
|
197
|
+
color={theme.colors.textNormal}
|
|
198
|
+
size={16}
|
|
199
|
+
/>
|
|
200
|
+
</View>
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const RightSelector = () => {
|
|
205
|
+
return (
|
|
206
|
+
<View style={{height: '100%', justifyContent: 'flex-end'}}>
|
|
207
|
+
<IconAntDesign
|
|
208
|
+
name='caretright'
|
|
209
|
+
color={theme.colors.textNormal}
|
|
210
|
+
size={16}
|
|
211
|
+
/>
|
|
212
|
+
</View>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (datesList?.length > 0) {
|
|
218
|
+
const _datesList = datesList.slice(0, Number(configs?.max_days_preorder?.value || 6))
|
|
219
|
+
const minDateParts = _datesList[0].split('-')
|
|
220
|
+
const maxDateParts = _datesList[_datesList.length - 1].split('-')
|
|
221
|
+
const _minDate = new Date(minDateParts[0], minDateParts[1] - 1, minDateParts[2])
|
|
222
|
+
const _maxDate = new Date(maxDateParts[0], maxDateParts[1] - 1, maxDateParts[2])
|
|
223
|
+
setDateWhitelist([{ start: _minDate, end: _maxDate }])
|
|
224
|
+
}
|
|
225
|
+
}, [datesList])
|
|
226
|
+
|
|
227
|
+
const handleClickBusiness = () => {
|
|
228
|
+
handleBusinessClick && handleBusinessClick(business)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
if (hoursList.length === 0) return
|
|
233
|
+
if (Object.keys(menu).length > 0) {
|
|
234
|
+
const _times: any = getTimes(selectDate, menu)
|
|
235
|
+
setTimeList(_times)
|
|
236
|
+
} else {
|
|
237
|
+
const _timeLists = hoursList.map((hour: any) => {
|
|
238
|
+
return {
|
|
239
|
+
value: hour.startTime,
|
|
240
|
+
text: configs?.format_time?.value === '12' ? (
|
|
241
|
+
hour.startTime.includes('12')
|
|
242
|
+
? `${hour.startTime}PM`
|
|
243
|
+
: parseTime(moment(hour.startTime, 'HH:mm'), { outputFormat: 'hh:mma' })
|
|
244
|
+
) : (
|
|
245
|
+
parseTime(moment(hour.startTime, 'HH:mm'), { outputFormat: 'HH:mm' })
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
setTimeList(_timeLists)
|
|
250
|
+
}
|
|
251
|
+
}, [selectDate, hoursList, menu])
|
|
252
|
+
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
if (selectedPreorderType.key === 'business_hours' && Object.keys(menu).length > 0) setMenu({})
|
|
255
|
+
}, [selectedPreorderType])
|
|
256
|
+
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
if (dateSelected) {
|
|
259
|
+
const dateParts = dateSelected.split('-')
|
|
260
|
+
const _dateSelected = new Date(dateParts[0], dateParts[1] - 1, dateParts[2])
|
|
261
|
+
setSelectedDate(_dateSelected)
|
|
262
|
+
}
|
|
263
|
+
}, [dateSelected])
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<>
|
|
267
|
+
<PreOrderContainer>
|
|
268
|
+
<TouchableOpacity onPress={() => goToBack && goToBack()} style={{ marginBottom: 12 }}>
|
|
269
|
+
<IconAntDesign
|
|
270
|
+
name='close'
|
|
271
|
+
color={theme.colors.textThird}
|
|
272
|
+
size={24}
|
|
273
|
+
/>
|
|
274
|
+
</TouchableOpacity>
|
|
275
|
+
<BusinessInfoWrapper>
|
|
276
|
+
<OText
|
|
277
|
+
size={20}
|
|
278
|
+
style={{
|
|
279
|
+
fontWeight: '600'
|
|
280
|
+
}}
|
|
281
|
+
>{t('PREORDER', 'Preorder')}</OText>
|
|
282
|
+
<View style={styles.businessLogo}>
|
|
283
|
+
<FastImage
|
|
284
|
+
style={{ width: 59, height: 59 }}
|
|
285
|
+
source={{
|
|
286
|
+
uri: optimizeImage(business?.logo, 'h_60,c_limit'),
|
|
287
|
+
priority: FastImage.priority.normal,
|
|
288
|
+
}}
|
|
289
|
+
resizeMode={FastImage.resizeMode.cover}
|
|
290
|
+
/>
|
|
291
|
+
</View>
|
|
292
|
+
</BusinessInfoWrapper>
|
|
293
|
+
<PreorderTypeWrapper>
|
|
294
|
+
<OText
|
|
295
|
+
size={16}
|
|
296
|
+
style={{
|
|
297
|
+
fontWeight: '600',
|
|
298
|
+
lineHeight: 24,
|
|
299
|
+
marginBottom: 12
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
{t('PREORDER_TYPE', 'Preorder type')}
|
|
303
|
+
</OText>
|
|
304
|
+
<TouchableOpacity onPress={() => setIsPreorderTypeList(true)}>
|
|
305
|
+
<View style={styles.selectOption}>
|
|
306
|
+
<OText
|
|
307
|
+
size={14}
|
|
308
|
+
color={theme.colors.disabled}
|
|
309
|
+
style={{
|
|
310
|
+
lineHeight: 24
|
|
311
|
+
}}
|
|
312
|
+
>
|
|
313
|
+
{selectedPreorderType.name}
|
|
314
|
+
</OText>
|
|
315
|
+
<IconAntDesign
|
|
316
|
+
name='down'
|
|
317
|
+
color={theme.colors.textThird}
|
|
318
|
+
size={16}
|
|
319
|
+
/>
|
|
320
|
+
</View>
|
|
321
|
+
</TouchableOpacity>
|
|
322
|
+
</PreorderTypeWrapper>
|
|
323
|
+
{selectedPreorderType?.key === 'business_menu' && (
|
|
324
|
+
<MenuWrapper>
|
|
325
|
+
<OText
|
|
326
|
+
size={16}
|
|
327
|
+
style={{
|
|
328
|
+
fontWeight: '600',
|
|
329
|
+
lineHeight: 24,
|
|
330
|
+
marginBottom: 12
|
|
331
|
+
}}
|
|
332
|
+
>
|
|
333
|
+
{t('MENU', 'Menu')}
|
|
334
|
+
</OText>
|
|
335
|
+
<BusinessMenuList
|
|
336
|
+
businessId={business.id}
|
|
337
|
+
setMenu={setMenu}
|
|
338
|
+
menu={menu}
|
|
339
|
+
/>
|
|
340
|
+
</MenuWrapper>
|
|
341
|
+
)}
|
|
342
|
+
<OrderTimeWrapper>
|
|
343
|
+
<OText
|
|
344
|
+
size={16}
|
|
345
|
+
style={{
|
|
346
|
+
fontWeight: '600',
|
|
347
|
+
lineHeight: 24
|
|
348
|
+
}}
|
|
349
|
+
>
|
|
350
|
+
{t('ORDER_TIME', 'Order time')}
|
|
351
|
+
</OText>
|
|
352
|
+
<View style={{ flex: 1 }}>
|
|
353
|
+
{selectDate && datesWhitelist[0].start !== null && (
|
|
354
|
+
<CalendarStrip
|
|
355
|
+
scrollable
|
|
356
|
+
style={styles.calendar}
|
|
357
|
+
calendarHeaderContainerStyle={styles.calendarHeaderContainer}
|
|
358
|
+
calendarHeaderStyle={styles.calendarHeader}
|
|
359
|
+
dateNumberStyle={styles.dateNumber}
|
|
360
|
+
dateNameStyle={styles.dateName}
|
|
361
|
+
iconContainer={{flex: 0.1}}
|
|
362
|
+
highlightDateNameStyle={styles.highlightDateName}
|
|
363
|
+
highlightDateNumberStyle={styles.highlightDateNumber}
|
|
364
|
+
calendarHeaderFormat='MMMM, YYYY'
|
|
365
|
+
iconStyle={{borderWidth: 1}}
|
|
366
|
+
selectedDate={selectDate}
|
|
367
|
+
datesWhitelist={datesWhitelist}
|
|
368
|
+
disabledDateNameStyle={styles.disabledDateName}
|
|
369
|
+
disabledDateNumberStyle={styles.disabledDateNumber}
|
|
370
|
+
disabledDateOpacity={0.6}
|
|
371
|
+
onDateSelected={(date) => onSelectDate(date)}
|
|
372
|
+
leftSelector={<LeftSelector />}
|
|
373
|
+
rightSelector={<RightSelector />}
|
|
374
|
+
/>
|
|
375
|
+
)}
|
|
376
|
+
</View>
|
|
377
|
+
<TimeListWrapper nestedScrollEnabled={true}>
|
|
378
|
+
<TimeContentWrapper>
|
|
379
|
+
{timeList.map((time: any, i: number) => (
|
|
380
|
+
<TouchableOpacity key={i} onPress={() => handleChangeTime(time.value)}>
|
|
381
|
+
<TimeItem active={timeSelected === time.value}>
|
|
382
|
+
<OText
|
|
383
|
+
size={14}
|
|
384
|
+
color={timeSelected === time.value ? theme.colors.primary: theme.colors.textNormal}
|
|
385
|
+
style={{
|
|
386
|
+
lineHeight: 24
|
|
387
|
+
}}
|
|
388
|
+
>{time.text}</OText>
|
|
389
|
+
</TimeItem>
|
|
390
|
+
</TouchableOpacity>
|
|
391
|
+
))}
|
|
392
|
+
{timeList.length % 3 === 2 && (
|
|
393
|
+
<TimeItem style={{backgroundColor: 'transparent'}}/>
|
|
394
|
+
)}
|
|
395
|
+
</TimeContentWrapper>
|
|
396
|
+
</TimeListWrapper>
|
|
397
|
+
</OrderTimeWrapper>
|
|
398
|
+
<OButton
|
|
399
|
+
text={t('GO_TO_MENU', 'Go to menu')}
|
|
400
|
+
textStyle={{color: 'white'}}
|
|
401
|
+
style={{borderRadius: 7.6, marginBottom: 50, marginTop: 30}}
|
|
402
|
+
onClick={() => handleClickBusiness()}
|
|
403
|
+
/>
|
|
404
|
+
</PreOrderContainer>
|
|
405
|
+
<Spinner visible={orderState.loading} />
|
|
406
|
+
<OModal
|
|
407
|
+
open={isPreorderTypeList}
|
|
408
|
+
onClose={() => setIsPreorderTypeList(false)}
|
|
409
|
+
customClose
|
|
410
|
+
entireModal
|
|
411
|
+
>
|
|
412
|
+
<PreorderTypeListWrapper>
|
|
413
|
+
<TouchableOpacity onPress={() => setIsPreorderTypeList(false)} style={{ marginBottom: 12 }}>
|
|
414
|
+
<IconAntDesign
|
|
415
|
+
name='close'
|
|
416
|
+
color={theme.colors.textThird}
|
|
417
|
+
size={24}
|
|
418
|
+
/>
|
|
419
|
+
</TouchableOpacity>
|
|
420
|
+
{preorderTypeList?.map((option: any, index: number) => (
|
|
421
|
+
<TouchableOpacity
|
|
422
|
+
key={index}
|
|
423
|
+
onPress={() => handleClickPreorderType(option)}
|
|
424
|
+
>
|
|
425
|
+
<DropOption
|
|
426
|
+
numberOfLines={1}
|
|
427
|
+
selected={option.key === selectedPreorderType.key}
|
|
428
|
+
>
|
|
429
|
+
<View style={{ marginRight: 10 }}>
|
|
430
|
+
{option.key === selectedPreorderType.key ? (
|
|
431
|
+
<MaterialCommunityIcons
|
|
432
|
+
name='radiobox-marked'
|
|
433
|
+
size={24}
|
|
434
|
+
color={theme.colors.primary}
|
|
435
|
+
/>
|
|
436
|
+
) : (
|
|
437
|
+
<MaterialCommunityIcons
|
|
438
|
+
name='radiobox-blank'
|
|
439
|
+
size={24}
|
|
440
|
+
color={theme.colors.arrowColor}
|
|
441
|
+
/>
|
|
442
|
+
)}
|
|
443
|
+
</View>
|
|
444
|
+
<Text>{option.name}</Text>
|
|
445
|
+
</DropOption>
|
|
446
|
+
</TouchableOpacity>
|
|
447
|
+
))}
|
|
448
|
+
</PreorderTypeListWrapper>
|
|
449
|
+
</OModal>
|
|
450
|
+
</>
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export const BusinessPreorder = (props: any) => {
|
|
455
|
+
const [{ configs }] = useConfig()
|
|
456
|
+
|
|
457
|
+
const limitDays = parseInt(configs?.max_days_preorder?.value, 10)
|
|
458
|
+
|
|
459
|
+
const currentDate = new Date()
|
|
460
|
+
const time = limitDays > 1
|
|
461
|
+
? currentDate.getTime() + ((limitDays - 1) * 24 * 60 * 60 * 1000)
|
|
462
|
+
: limitDays === 1 ? currentDate.getTime() : currentDate.getTime() + (6 * 24 * 60 * 60 * 1000)
|
|
463
|
+
|
|
464
|
+
currentDate.setTime(time)
|
|
465
|
+
currentDate.setHours(23)
|
|
466
|
+
currentDate.setMinutes(59)
|
|
467
|
+
|
|
468
|
+
const businessPreorderProps = {
|
|
469
|
+
...props,
|
|
470
|
+
UIComponent: BusinessPreorderUI,
|
|
471
|
+
maxDate: currentDate
|
|
472
|
+
}
|
|
473
|
+
return <MomentOption {...businessPreorderProps} />
|
|
474
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components/native'
|
|
2
|
+
|
|
3
|
+
export const PreOrderContainer = styled.ScrollView`
|
|
4
|
+
padding: 20px 40px 30px 40px;
|
|
5
|
+
`
|
|
6
|
+
|
|
7
|
+
export const BusinessInfoWrapper = styled.View`
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
justify-content: space-between;
|
|
10
|
+
align-items: center;
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
export const PreorderTypeWrapper = styled.View`
|
|
14
|
+
margin-top: 23px;
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
export const MenuWrapper = styled(PreorderTypeWrapper)``
|
|
18
|
+
|
|
19
|
+
export const OrderTimeWrapper = styled.View`
|
|
20
|
+
margin-top: 34px;
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
export const TimeListWrapper = styled.ScrollView`
|
|
24
|
+
margin-top: 30px;
|
|
25
|
+
max-height: 160px;
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
export const TimeContentWrapper = styled.View`
|
|
29
|
+
flex: 1;
|
|
30
|
+
flex-wrap: wrap;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
`
|
|
34
|
+
|
|
35
|
+
export const TimeItem = styled.View`
|
|
36
|
+
width: 86px;
|
|
37
|
+
height: 34px;
|
|
38
|
+
background: #E9ECEF;
|
|
39
|
+
border-radius: 7.6px;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
align-items: center;
|
|
42
|
+
margin: 10px 0px;
|
|
43
|
+
${({ active }: any) => active && css`
|
|
44
|
+
background: #F5F9FF;
|
|
45
|
+
`}
|
|
46
|
+
`
|
|
47
|
+
|
|
48
|
+
export const PreorderTypeListWrapper = styled.ScrollView`
|
|
49
|
+
padding: 20px 40px 30px 40px;
|
|
50
|
+
`
|
|
51
|
+
|
|
52
|
+
export const DropOption = styled.View`
|
|
53
|
+
padding: 10px;
|
|
54
|
+
margin-bottom: 5px;
|
|
55
|
+
font-size: 16px;
|
|
56
|
+
border-bottom-width: 1px;
|
|
57
|
+
border-bottom-color: ${(props: any) => props.theme.colors.lightGray};
|
|
58
|
+
flex-direction: row;
|
|
59
|
+
align-items: center;
|
|
60
|
+
`
|
|
@@ -263,7 +263,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
|
|
|
263
263
|
</FeaturedWrapper>
|
|
264
264
|
)}
|
|
265
265
|
<View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
|
|
266
|
-
<HighestRatedBusinesses onBusinessClick={handleBusinessClick} />
|
|
266
|
+
<HighestRatedBusinesses onBusinessClick={handleBusinessClick} navigation={navigation} />
|
|
267
267
|
<View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
|
|
268
268
|
<ListWrapper>
|
|
269
269
|
<BusinessTypeFilter
|
|
@@ -287,6 +287,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
|
|
|
287
287
|
business={business}
|
|
288
288
|
handleCustomClick={handleBusinessClick}
|
|
289
289
|
orderType={orderState?.options?.type}
|
|
290
|
+
navigation={navigation}
|
|
290
291
|
/>
|
|
291
292
|
)
|
|
292
293
|
)}
|
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
const HighestRatedBusinessesUI = (props: HighestRatedBusinessesParams) => {
|
|
18
18
|
const {
|
|
19
19
|
businessesList,
|
|
20
|
-
onBusinessClick
|
|
20
|
+
onBusinessClick,
|
|
21
|
+
navigation
|
|
21
22
|
} = props;
|
|
22
23
|
|
|
23
24
|
const [, t] = useLanguage()
|
|
@@ -104,6 +105,7 @@ const HighestRatedBusinessesUI = (props: HighestRatedBusinessesParams) => {
|
|
|
104
105
|
business={business}
|
|
105
106
|
handleCustomClick={onBusinessClick}
|
|
106
107
|
orderType={orderState?.options?.type}
|
|
108
|
+
navigation={navigation}
|
|
107
109
|
/>
|
|
108
110
|
</View>
|
|
109
111
|
)
|
|
@@ -132,6 +132,7 @@ export interface BusinessesListingParams {
|
|
|
132
132
|
export interface HighestRatedBusinessesParams {
|
|
133
133
|
businessesList: { businesses: Array<any>, loading: boolean, error: null | string };
|
|
134
134
|
onBusinessClick?: void;
|
|
135
|
+
navigation? :any;
|
|
135
136
|
}
|
|
136
137
|
export interface BusinessTypeFilterParams {
|
|
137
138
|
businessTypes?: Array<any>;
|
|
@@ -149,7 +150,8 @@ export interface BusinessControllerParams {
|
|
|
149
150
|
handleClick?: any;
|
|
150
151
|
isBusinessOpen?: boolean;
|
|
151
152
|
businessWillCloseSoonMinutes?: number
|
|
152
|
-
isBusinessClose?: number
|
|
153
|
+
isBusinessClose?: number,
|
|
154
|
+
navigation?: any
|
|
153
155
|
}
|
|
154
156
|
export interface BusinessProductsListingParams {
|
|
155
157
|
navigation?: any;
|
|
@@ -379,6 +381,25 @@ export interface MomentOptionParams {
|
|
|
379
381
|
handleChangeDate: (value: any) => {};
|
|
380
382
|
handleChangeTime: (value: any) => {};
|
|
381
383
|
}
|
|
384
|
+
export interface BusinessPreorderParams {
|
|
385
|
+
navigation?: any;
|
|
386
|
+
datesList: Array<any>;
|
|
387
|
+
hoursList: Array<any>;
|
|
388
|
+
dateSelected?: any;
|
|
389
|
+
timeSelected?: any;
|
|
390
|
+
isAsap?: boolean;
|
|
391
|
+
handleAsap?: () => {};
|
|
392
|
+
handleChangeDate: (value: any) => {};
|
|
393
|
+
handleChangeTime: (value: any) => {};
|
|
394
|
+
goToBack: any;
|
|
395
|
+
business: any;
|
|
396
|
+
handleBusinessClick: (value: any) => {};
|
|
397
|
+
}
|
|
398
|
+
export interface BusinessMenuListParams {
|
|
399
|
+
menu: any;
|
|
400
|
+
businessMenuList: any;
|
|
401
|
+
setMenu: (value: any) => {};
|
|
402
|
+
}
|
|
382
403
|
export interface OrderTypeSelectParams {
|
|
383
404
|
navigation?: any;
|
|
384
405
|
handleChangeOrderType: (value: any) => {};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
useValidationFields,
|
|
9
9
|
} from 'ordering-components/native';
|
|
10
10
|
import { useTheme } from 'styled-components/native';
|
|
11
|
-
import { ScrollView, View, useWindowDimensions, ActivityIndicator } from 'react-native';
|
|
11
|
+
import { ScrollView, View, useWindowDimensions, ActivityIndicator, StyleSheet } from 'react-native';
|
|
12
12
|
import {
|
|
13
13
|
CheckoutAction,
|
|
14
14
|
OSBill,
|
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
BIHeader,
|
|
21
21
|
BIInfo,
|
|
22
22
|
BIContentInfo,
|
|
23
|
-
BITotal
|
|
23
|
+
BITotal,
|
|
24
|
+
TopHeader
|
|
24
25
|
} from './styles';
|
|
25
26
|
|
|
26
27
|
import { ProductItemAccordion } from '../ProductItemAccordion';
|
|
@@ -187,6 +188,15 @@ const CartUI = (props: any) => {
|
|
|
187
188
|
)
|
|
188
189
|
}
|
|
189
190
|
|
|
191
|
+
const styles = StyleSheet.create({
|
|
192
|
+
headerItem: {
|
|
193
|
+
overflow: 'hidden',
|
|
194
|
+
backgroundColor: theme.colors.clear,
|
|
195
|
+
width: 35,
|
|
196
|
+
marginVertical: 18,
|
|
197
|
+
},
|
|
198
|
+
})
|
|
199
|
+
|
|
190
200
|
return (
|
|
191
201
|
cart?.products?.length > 0 ? (
|
|
192
202
|
<ScrollView
|
|
@@ -307,32 +317,22 @@ const CartUI = (props: any) => {
|
|
|
307
317
|
</OSTable>
|
|
308
318
|
)}
|
|
309
319
|
|
|
310
|
-
<OSTotal>
|
|
311
|
-
<OSTable style={{ marginTop: 15 }}>
|
|
312
|
-
<OText size={14} lineHeight={21} weight={'600'}>
|
|
313
|
-
{t('TOTAL', 'Total')}
|
|
314
|
-
</OText>
|
|
315
|
-
<OText size={14} lineHeight={21} weight={'600'}>
|
|
316
|
-
{cart?.total >= 1 && parsePrice(cart?.total)}
|
|
317
|
-
</OText>
|
|
318
|
-
</OSTable>
|
|
319
|
-
</OSTotal>
|
|
320
320
|
{cart?.status !== 2 && (
|
|
321
321
|
<OSTable>
|
|
322
|
-
<View style={{ width: '100%', marginTop:
|
|
323
|
-
<OText size={
|
|
322
|
+
<View style={{ width: '100%', marginTop: 0 }}>
|
|
323
|
+
<OText size={14} style={{ marginBottom: 10 }}>{t('COMMENTS', 'Comments')}</OText>
|
|
324
324
|
<View style={{ flex: 1, width: '100%' }}>
|
|
325
325
|
<OInput
|
|
326
326
|
value={cart?.comment}
|
|
327
327
|
placeholder={t('SPECIAL_COMMENTS', 'Special Comments')}
|
|
328
328
|
onChange={(value: string) => handleChangeComment(value)}
|
|
329
329
|
style={{
|
|
330
|
+
borderColor: theme.colors.border,
|
|
331
|
+
borderRadius: 10,
|
|
332
|
+
marginBottom: 20,
|
|
333
|
+
height: 104,
|
|
334
|
+
maxHeight: 104,
|
|
330
335
|
alignItems: 'flex-start',
|
|
331
|
-
width: '100%',
|
|
332
|
-
height: 100,
|
|
333
|
-
borderColor: theme.colors.textSecondary,
|
|
334
|
-
paddingRight: 50,
|
|
335
|
-
marginTop: 10
|
|
336
336
|
}}
|
|
337
337
|
multiline
|
|
338
338
|
/>
|
|
@@ -349,6 +349,17 @@ const CartUI = (props: any) => {
|
|
|
349
349
|
</View>
|
|
350
350
|
</OSTable>
|
|
351
351
|
)}
|
|
352
|
+
|
|
353
|
+
<OSTotal>
|
|
354
|
+
<OSTable style={{ marginTop: 15 }}>
|
|
355
|
+
<OText size={14} lineHeight={21} weight={'600'}>
|
|
356
|
+
{t('TOTAL', 'Total')}
|
|
357
|
+
</OText>
|
|
358
|
+
<OText size={14} lineHeight={21} weight={'600'}>
|
|
359
|
+
{cart?.total >= 1 && parsePrice(cart?.total)}
|
|
360
|
+
</OText>
|
|
361
|
+
</OSTable>
|
|
362
|
+
</OSTotal>
|
|
352
363
|
</OSBill>
|
|
353
364
|
)}
|
|
354
365
|
</View>
|
|
@@ -427,7 +438,24 @@ const CartUI = (props: any) => {
|
|
|
427
438
|
onSave={handlerProductAction}
|
|
428
439
|
onClose={() => setModalIsOpen(false)}
|
|
429
440
|
/>
|
|
441
|
+
</OModal>
|
|
430
442
|
|
|
443
|
+
<OModal
|
|
444
|
+
open={openTaxModal.open}
|
|
445
|
+
onClose={() => setOpenTaxModal({ open: false, data: null })}
|
|
446
|
+
entireModal
|
|
447
|
+
customClose
|
|
448
|
+
>
|
|
449
|
+
<>
|
|
450
|
+
<TopHeader>
|
|
451
|
+
<TouchableOpacity
|
|
452
|
+
style={styles.headerItem}
|
|
453
|
+
onPress={() => setOpenTaxModal({ open: false, data: null })}>
|
|
454
|
+
<OIcon src={theme.images.general.close} width={16} />
|
|
455
|
+
</TouchableOpacity>
|
|
456
|
+
</TopHeader>
|
|
457
|
+
<TaxInformation data={openTaxModal.data} products={cart?.products} />
|
|
458
|
+
</>
|
|
431
459
|
</OModal>
|
|
432
460
|
</ScrollView>
|
|
433
461
|
) : (
|
|
@@ -445,13 +473,6 @@ const CartUI = (props: any) => {
|
|
|
445
473
|
image={theme.images.general.notFound}
|
|
446
474
|
/>
|
|
447
475
|
</View>
|
|
448
|
-
<OModal
|
|
449
|
-
open={openTaxModal.open}
|
|
450
|
-
onClose={() => setOpenTaxModal({ open: false, data: null })}
|
|
451
|
-
entireModal
|
|
452
|
-
>
|
|
453
|
-
<TaxInformation data={openTaxModal.data} products={cart?.products} />
|
|
454
|
-
</OModal>
|
|
455
476
|
</Container>
|
|
456
477
|
)
|
|
457
478
|
)
|
|
@@ -100,3 +100,12 @@ export const BITotal = styled.View`
|
|
|
100
100
|
flex-direction: column;
|
|
101
101
|
align-items: flex-end;
|
|
102
102
|
`
|
|
103
|
+
|
|
104
|
+
export const TopHeader = styled.View`
|
|
105
|
+
width: 100%;
|
|
106
|
+
flex-direction: row;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: space-between;
|
|
109
|
+
z-index: 1;
|
|
110
|
+
padding-horizontal: 40px;
|
|
111
|
+
`
|
|
@@ -21,31 +21,36 @@ export const TaxInformation = (props: taxInformationParams) => {
|
|
|
21
21
|
const isTax = typeof data?.rate === 'number'
|
|
22
22
|
const TaxFeeString = isTax ? 'tax' : 'fee'
|
|
23
23
|
const includedOnPriceString = data?.type === 1 ? `(${t('INCLUDED_ON_PRICE', 'Included on price')})` : `(${t('NOT_INCLUDED_ON_PRICE', 'Not included on price')})`
|
|
24
|
+
const productsWithTaxes = products
|
|
25
|
+
.filter((product: any) => isTax
|
|
26
|
+
? (product.tax?.id ? product.tax?.id === data?.id: product.tax?.id === null && data?.id === null)
|
|
27
|
+
: (product.fee?.id ? product.fee?.id === data?.id : (product.fee?.id === null && data?.id === null))) ?? []
|
|
24
28
|
|
|
25
29
|
return (
|
|
26
30
|
<TaxInformationContainer>
|
|
27
|
-
<OText size={
|
|
28
|
-
{`${data?.name
|
|
29
|
-
t('INHERIT_FROM_BUSINESS', 'Inherit from business')} (${typeof data?.rate === 'number' ? `${data?.rate}%` : `${parsePrice(data?.fixed ?? 0)} + ${data?.percentage}%`})`}
|
|
31
|
+
<OText size={18} style={{ alignSelf: 'flex-start', textAlign: 'left' }} mBottom={10}>
|
|
32
|
+
{`${data?.name ?? t('INHERIT_FROM_BUSINESS', 'Inherit from business')} (${typeof data?.rate === 'number' ? `${data?.rate}%` : `${parsePrice(data?.fixed ?? 0)} + ${data?.percentage}%`})`}
|
|
30
33
|
</OText>
|
|
31
34
|
{data?.description && (
|
|
32
|
-
<OText mBottom={10} size={
|
|
35
|
+
<OText mBottom={10} size={16} style={{ alignSelf: 'flex-start', textAlign: 'left' }}>
|
|
33
36
|
{t('DESCRIPTION', 'Description')}: {data?.description} {data?.type && includedOnPriceString}
|
|
34
37
|
</OText>
|
|
35
38
|
)}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
{productsWithTaxes.length > 0 && (
|
|
40
|
+
<>
|
|
41
|
+
<OText>{`${t(`OTHER_PRODUCTS_WITH_THIS_${TaxFeeString.toUpperCase()}`, `Other products with this ${TaxFeeString}`)}:`}</OText>
|
|
42
|
+
<ProductContainer>
|
|
43
|
+
{productsWithTaxes.map(product => (
|
|
44
|
+
<SingleProductCard
|
|
45
|
+
key={product.id}
|
|
46
|
+
product={product}
|
|
47
|
+
isSoldOut={false}
|
|
48
|
+
businessId={product?.business_id}
|
|
49
|
+
/>
|
|
50
|
+
))}
|
|
51
|
+
</ProductContainer>
|
|
52
|
+
</>
|
|
53
|
+
)}
|
|
49
54
|
</TaxInformationContainer>
|
|
50
55
|
)
|
|
51
56
|
}
|