ordering-ui-react-native 0.22.72 → 0.22.73-release

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.
Files changed (136) hide show
  1. package/package.json +5 -7
  2. package/src/components/BusinessesListing/index.tsx +1 -1
  3. package/src/components/Checkout/index.tsx +40 -39
  4. package/src/components/VerifyPhone/styles.tsx +1 -2
  5. package/src/context/OfflineActions/index.tsx +236 -0
  6. package/src/providers/AlertProvider.tsx +3 -1
  7. package/themes/business/src/components/AcceptOrRejectOrder/index.tsx +5 -3
  8. package/themes/business/src/components/AcceptOrRejectOrder/styles.tsx +1 -0
  9. package/themes/business/src/components/BusinessController/index.tsx +8 -3
  10. package/themes/business/src/components/BusinessProductList/index.tsx +3 -2
  11. package/themes/business/src/components/Chat/index.tsx +15 -3
  12. package/themes/business/src/components/DriverMap/index.tsx +44 -33
  13. package/themes/business/src/components/FloatingButton/index.tsx +3 -2
  14. package/themes/business/src/components/LanguageSelector/index.tsx +1 -1
  15. package/themes/business/src/components/LoginForm/index.tsx +123 -98
  16. package/themes/business/src/components/LogoutButton/index.tsx +13 -4
  17. package/themes/business/src/components/MapView/RenderMarker.tsx +146 -0
  18. package/themes/business/src/components/MapView/index.tsx +68 -142
  19. package/themes/business/src/components/NewOrderNotification/index.tsx +38 -54
  20. package/themes/business/src/components/OrderDetails/Business.tsx +56 -20
  21. package/themes/business/src/components/OrderDetails/Delivery.tsx +123 -54
  22. package/themes/business/src/components/OrderDetails/OrderContentComponent.tsx +146 -36
  23. package/themes/business/src/components/OrderDetails/OrderHeaderComponent.tsx +51 -28
  24. package/themes/business/src/components/OrderDetails/styles.tsx +39 -3
  25. package/themes/business/src/components/OrderDetails/usePrinterCommands.tsx +17 -16
  26. package/themes/business/src/components/OrderDetailsLogistic/index.tsx +3 -2
  27. package/themes/business/src/components/OrderSummary/index.tsx +271 -176
  28. package/themes/business/src/components/OrdersListManager/index.tsx +13 -1
  29. package/themes/business/src/components/OrdersOption/index.tsx +219 -144
  30. package/themes/business/src/components/OrdersOption/styles.tsx +14 -0
  31. package/themes/business/src/components/PreviousMessages/index.tsx +26 -3
  32. package/themes/business/src/components/PreviousOrders/OrderItem.tsx +20 -8
  33. package/themes/business/src/components/PreviousOrders/index.tsx +74 -66
  34. package/themes/business/src/components/PreviousOrders/styles.tsx +2 -1
  35. package/themes/business/src/components/PrinterEdition/MessageAlert.tsx +33 -0
  36. package/themes/business/src/components/PrinterEdition/index.tsx +143 -75
  37. package/themes/business/src/components/PrinterEdition/printerList.tsx +23 -0
  38. package/themes/business/src/components/PrinterSettings/index.tsx +1 -1
  39. package/themes/business/src/components/ProductItemAccordion/index.tsx +15 -16
  40. package/themes/business/src/components/ReviewCustomer/index.tsx +2 -0
  41. package/themes/business/src/components/StoresList/index.tsx +2 -2
  42. package/themes/business/src/components/UserProfileForm/index.tsx +48 -10
  43. package/themes/business/src/components/UserProfileForm/styles.tsx +7 -0
  44. package/themes/business/src/components/WebsocketStatus/index.tsx +2 -2
  45. package/themes/business/src/config/currency.tsx +1010 -0
  46. package/themes/business/src/hooks/useLocation.tsx +16 -12
  47. package/themes/business/src/layouts/SafeAreaContainer.tsx +35 -19
  48. package/themes/business/src/types/index.tsx +28 -4
  49. package/themes/business/src/utils/index.tsx +28 -3
  50. package/themes/doordash/src/components/BusinessesListing/index.tsx +1 -1
  51. package/themes/doordash/src/components/LoginForm/index.tsx +1 -2
  52. package/themes/instacart/src/components/BusinessesListing/index.tsx +1 -1
  53. package/themes/kiosk/src/components/Checkout/index.tsx +9 -5
  54. package/themes/kiosk/src/components/CustomerName/index.tsx +1 -1
  55. package/themes/kiosk/src/components/NavBar/index.tsx +14 -14
  56. package/themes/kiosk/src/components/OptionCard/index.tsx +1 -1
  57. package/themes/kiosk/src/components/OrderTypeCardSelector/index.tsx +8 -10
  58. package/themes/kiosk/src/components/PaymentOptions/index.tsx +121 -57
  59. package/themes/kiosk/src/components/shared/OButton.tsx +5 -18
  60. package/themes/original/index.tsx +223 -219
  61. package/themes/original/src/components/AddressForm/index.tsx +922 -885
  62. package/themes/original/src/components/AppleLogin/index.tsx +3 -4
  63. package/themes/original/src/components/BusinessController/index.tsx +4 -2
  64. package/themes/original/src/components/BusinessItemAccordion/index.tsx +8 -3
  65. package/themes/original/src/components/BusinessListingSearch/BusinessSearchFooter.tsx +102 -90
  66. package/themes/original/src/components/BusinessListingSearch/BusinessSearchHeader.tsx +7 -3
  67. package/themes/original/src/components/BusinessListingSearch/index.tsx +8 -13
  68. package/themes/original/src/components/BusinessPreorder/index.tsx +30 -17
  69. package/themes/original/src/components/BusinessProductsList/SubcategoriesComponent/index.tsx +72 -69
  70. package/themes/original/src/components/BusinessProductsList/index.tsx +4 -5
  71. package/themes/original/src/components/BusinessProductsList/styles.tsx +0 -3
  72. package/themes/original/src/components/BusinessProductsListing/index.tsx +5 -4
  73. package/themes/original/src/components/BusinessesListing/Layout/Original/styles.tsx +1 -1
  74. package/themes/original/src/components/Cart/index.tsx +43 -12
  75. package/themes/original/src/components/Checkout/index.tsx +126 -98
  76. package/themes/original/src/components/FloatingButton/index.tsx +1 -1
  77. package/themes/original/src/components/GPSButton/index.tsx +2 -1
  78. package/themes/original/src/components/GoogleMap/index.tsx +3 -2
  79. package/themes/original/src/components/Help/functions.tsx +76 -0
  80. package/themes/original/src/components/Help/index.tsx +74 -29
  81. package/themes/original/src/components/Help/styles.tsx +4 -1
  82. package/themes/original/src/components/HelpOptions/index.tsx +53 -0
  83. package/themes/original/src/components/HighestRatedBusinesses/index.tsx +1 -1
  84. package/themes/original/src/components/Home/index.tsx +36 -11
  85. package/themes/original/src/components/LastOrder/index.tsx +1 -1
  86. package/themes/original/src/components/LoginForm/index.tsx +11 -5
  87. package/themes/original/src/components/MessageListing/index.tsx +1 -1
  88. package/themes/original/src/components/Messages/index.tsx +562 -555
  89. package/themes/original/src/components/MomentOption/TimeListItem.tsx +56 -0
  90. package/themes/original/src/components/MomentOption/index.tsx +141 -61
  91. package/themes/original/src/components/MomentOption/styles.tsx +1 -1
  92. package/themes/original/src/components/MomentSelector/index.tsx +5 -2
  93. package/themes/original/src/components/MultiCheckout/index.tsx +78 -33
  94. package/themes/original/src/components/MultiOrdersDetails/SingleOrderCard.tsx +2 -2
  95. package/themes/original/src/components/MultiOrdersDetails/index.tsx +2 -2
  96. package/themes/original/src/components/NavBar/index.tsx +6 -2
  97. package/themes/original/src/components/NotFoundSource/index.tsx +40 -39
  98. package/themes/original/src/components/NotFoundSource/styles.tsx +18 -9
  99. package/themes/original/src/components/OrderDetails/OrderEta.tsx +4 -3
  100. package/themes/original/src/components/OrderDetails/OrderHistory.tsx +11 -4
  101. package/themes/original/src/components/OrderDetails/index.tsx +44 -20
  102. package/themes/original/src/components/OrderDetails/styles.tsx +0 -1
  103. package/themes/original/src/components/OrderProgress/index.tsx +5 -4
  104. package/themes/original/src/components/OrderSummary/index.tsx +32 -11
  105. package/themes/original/src/components/OrderTypeSelector/index.tsx +120 -120
  106. package/themes/original/src/components/OrdersOption/index.tsx +325 -325
  107. package/themes/original/src/components/PaymentOptionWallet/index.tsx +1 -0
  108. package/themes/original/src/components/PaymentOptions/index.tsx +471 -459
  109. package/themes/original/src/components/PhoneInputNumber/index.tsx +92 -7
  110. package/themes/original/src/components/ProductItemAccordion/index.tsx +28 -37
  111. package/themes/original/src/components/ProductOptionSubOption/index.tsx +15 -14
  112. package/themes/original/src/components/ServiceForm/index.tsx +2 -2
  113. package/themes/original/src/components/SignupForm/index.tsx +40 -24
  114. package/themes/original/src/components/SingleOrderCard/index.tsx +8 -5
  115. package/themes/original/src/components/SingleProductCard/index.tsx +2 -1
  116. package/themes/original/src/components/SingleProductCard/styles.tsx +0 -3
  117. package/themes/original/src/components/StripeCardsList/index.tsx +9 -4
  118. package/themes/original/src/components/StripeElementsForm/index.tsx +2 -2
  119. package/themes/original/src/components/TaxInformation/index.tsx +3 -2
  120. package/themes/original/src/components/UpsellingProducts/UpsellingContent.tsx +7 -2
  121. package/themes/original/src/components/UserDetails/index.tsx +17 -16
  122. package/themes/original/src/components/UserFormDetails/index.tsx +109 -67
  123. package/themes/original/src/components/UserVerification/index.tsx +18 -5
  124. package/themes/original/src/components/VerifyPhone/index.tsx +1 -1
  125. package/themes/original/src/components/shared/OInput.tsx +97 -97
  126. package/themes/original/src/components/shared/OModal.tsx +7 -2
  127. package/themes/original/src/providers/AlertProvider.tsx +1 -1
  128. package/themes/original/src/types/index.tsx +700 -695
  129. package/themes/original/src/utils/index.tsx +50 -34
  130. package/themes/uber-eats/src/components/BusinessesListing/index.tsx +1 -1
  131. package/themes/original/src/components/HelpAccountAndPayment/index.tsx +0 -62
  132. package/themes/original/src/components/HelpAccountAndPayment/styles.tsx +0 -12
  133. package/themes/original/src/components/HelpGuide/index.tsx +0 -68
  134. package/themes/original/src/components/HelpGuide/styles.tsx +0 -12
  135. package/themes/original/src/components/HelpOrder/index.tsx +0 -71
  136. package/themes/original/src/components/HelpOrder/styles.tsx +0 -13
@@ -1,20 +1,20 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
2
  import {
3
- StyleSheet,
4
- View,
5
- TouchableOpacity,
6
- Keyboard,
7
- TouchableWithoutFeedback,
8
- Platform,
3
+ StyleSheet,
4
+ View,
5
+ TouchableOpacity,
6
+ Keyboard,
7
+ TouchableWithoutFeedback,
8
+ Platform,
9
9
  } from 'react-native';
10
10
  import {
11
- AddressForm as AddressFormController,
12
- useLanguage,
13
- useConfig,
14
- useSession,
15
- useOrder,
16
- useToast,
17
- ToastType
11
+ AddressForm as AddressFormController,
12
+ useLanguage,
13
+ useConfig,
14
+ useSession,
15
+ useOrder,
16
+ useToast,
17
+ ToastType
18
18
  } from 'ordering-components/native';
19
19
  import { DeviceOrientationMethods } from '../../../../../src/hooks/DeviceOrientation'
20
20
 
@@ -31,11 +31,11 @@ import { GoogleMap } from '../GoogleMap';
31
31
  import NavBar from '../NavBar';
32
32
 
33
33
  import {
34
- AddressFormContainer,
35
- AutocompleteInput,
36
- IconsContainer,
37
- GoogleMapContainer,
38
- FormInput,
34
+ AddressFormContainer,
35
+ AutocompleteInput,
36
+ IconsContainer,
37
+ GoogleMapContainer,
38
+ FormInput,
39
39
  } from './styles';
40
40
  import { GPSButton } from '../GPSButton';
41
41
  import { ScrollView } from 'react-native-gesture-handler';
@@ -43,877 +43,914 @@ import { ScrollView } from 'react-native-gesture-handler';
43
43
  const { useDeviceOrientation } = DeviceOrientationMethods
44
44
 
45
45
  const inputNames = [
46
- { name: 'address', code: 'Address' },
47
- { name: 'internal_number', code: 'Internal number' },
48
- { name: 'zipcode', code: 'Zipcode' },
49
- { name: 'address_notes', code: 'Address notes' },
46
+ { name: 'address', code: 'Address' },
47
+ { name: 'internal_number', code: 'Internal number' },
48
+ { name: 'zipcode', code: 'Zipcode' },
49
+ { name: 'address_notes', code: 'Address notes' },
50
50
  ];
51
51
 
52
52
  const AddressFormUI = (props: AddressFormParams) => {
53
- const {
54
- navigation,
55
- updateChanges,
56
- address,
57
- formState,
58
- isEditing,
59
- handleChangeInput,
60
- addressState,
61
- addressesList,
62
- saveAddress,
63
- isGuestUser,
64
- isRequiredField,
65
- showField,
66
- isFromProductsList,
67
- hasAddressDefault,
68
- afterSignup,
69
- businessSlug,
70
- isFromCheckout,
71
- onNavigationRedirect
72
- } = props;
73
-
74
- const theme = useTheme();
75
- const [orientationState] = useDeviceOrientation();
76
-
77
- const [autoCompleteInputFocused, setAutoCompleteInputFocused] = useState(false)
78
-
79
- const tagsName = [
80
- { icon: theme.images.general.tag_home, value: 'home' },
81
- { icon: theme.images.general.tag_building, value: 'office' },
82
- { icon: theme.images.general.tag_heart, value: 'favorite' },
83
- { icon: theme.images.general.tag_plus, value: 'other' },
84
- ];
85
-
86
- const HEIGHT_SCREEN = orientationState?.dimensions?.height
87
-
88
- const styles = StyleSheet.create({
89
- iconContainer: {
90
- display: 'flex',
91
- justifyContent: 'center',
92
- alignItems: 'center',
93
- paddingHorizontal: 18,
94
- paddingVertical: 5,
95
- backgroundColor: theme.colors.clear
96
- },
97
- inputsStyle: {
98
- borderRadius: 10,
99
- marginBottom: 20,
100
- height: 50,
101
- maxHeight: 50,
102
- minHeight: 50,
103
- flex: 1,
104
- },
105
- textAreaStyles: {
106
- borderRadius: 10,
107
- marginBottom: 20,
108
- height: 104,
109
- maxHeight: 104,
110
- minHeight: 104,
111
- textAlignVertical: 'top',
112
- alignItems: 'flex-start',
113
- },
114
- pinIcon: {
115
- position: 'absolute',
116
- end: 0,
117
- top: 12,
118
- zIndex: 1002,
119
- right: autoCompleteInputFocused && (
120
- !!address?.address ||
121
- !!formState.changes?.address ||
122
- !!addressState.address.address
123
- ) ? 30 : 15,
124
- width: 16
125
- },
126
- wrapperNavbar: Platform.OS === 'ios'
127
- ? { paddingVertical: 0, paddingLeft: 20, paddingRight: 20 }
128
- : { paddingVertical: 10, paddingLeft: 20, paddingRight: 20 }
129
- });
130
-
131
- const [, t] = useLanguage();
132
- const [{ auth }] = useSession();
133
- const [, { showToast }] = useToast();
134
- const [configState] = useConfig();
135
- const [orderState] = useOrder();
136
- const { handleSubmit, errors, control, setValue } = useForm();
137
- const [autoCompleteAddress, setAutoCompleteAddress] = useState(false)
138
-
139
- const [toggleMap, setToggleMap] = useState(false);
140
- const [alertState, setAlertState] = useState<{
141
- open: boolean;
142
- content: Array<string>;
143
- key?: string | null;
144
- }>({ open: false, content: [], key: null });
145
- const [addressTag, setAddressTag] = useState(addressState?.address?.tag);
146
- const [firstLocationNoEdit, setFirstLocationNoEdit] = useState({
147
- value: { lat: null, lng: null },
148
- address: null,
149
- });
150
- const [isFirstTime, setIsFirstTime] = useState(true);
151
- const [locationChange, setLocationChange] = useState(
152
- isEditing
153
- ? addressState?.address?.location
154
- : formState.changes?.location ?? null,
155
- );
156
- const [saveMapLocation, setSaveMapLocation] = useState(false);
157
- const [isKeyboardShow, setIsKeyboardShow] = useState(false);
158
- const [isSignUpEffect, setIsSignUpEffect] = useState(false);
159
- const [hasEditing, setAddressEditing] = useState(false);
160
-
161
- const googleInput: any = useRef(null);
162
- const internalNumberRef: any = useRef(null);
163
- const zipCodeRef: any = useRef(null);
164
- const addressNotesRef: any = useRef(null);
165
-
166
- const googleMapsApiKey = configState?.configs?.google_maps_api_key?.value;
167
- const isLocationRequired =
168
- configState.configs?.google_autocomplete_selection_required?.value ===
169
- '1' ||
170
- configState.configs?.google_autocomplete_selection_required?.value ===
171
- 'true';
172
- const maxLimitLocation =
173
- configState?.configs?.meters_to_change_address?.value;
174
- const countryCode = configState?.configs?.country_autocomplete?.value
175
- const isHideMap = theme?.address?.components?.map?.hidden
176
- const isHideIcons = theme?.address?.components?.icons?.hidden
177
- const continueAsGuest = () => navigation.navigate(!!businessSlug ? 'Business' : 'BusinessList', { isGuestUser: true });
178
- const unaddressedTypes = configState?.configs?.unaddressed_order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
179
- const isAllowUnaddressOrderType = unaddressedTypes.includes(orderState?.options?.type)
180
- const goToBack = () => navigation?.canGoBack() && navigation.goBack();
181
-
182
- const getAddressFormatted = (address: any) => {
183
- const data: any = { address: null, error: null };
184
- Geocoder.from(address)
185
- .then((json) => {
186
- if (json.results && json.results?.length > 0) {
187
- let postalCode = null;
188
- for (const component of json.results?.[0].address_components) {
189
- const addressType = component.types?.[0];
190
- if (addressType === 'postal_code') {
191
- postalCode = component.short_name;
192
- break;
193
- }
194
- }
195
- data.address = {
196
- address,
197
- location: json.results[0].geometry.location,
198
- map_data: {
199
- library: 'google',
200
- place_id: json.results?.[0].place_id,
201
- },
202
- };
203
- if (postalCode) {
204
- data.address.zipcode = postalCode;
205
- }
206
-
207
- const arrayList = isEditing
208
- ? addressesList?.addresses?.filter(
209
- (address: any) => address.id !== addressState?.address?.id,
210
- ) || []
211
- : addressesList || [];
212
- const addressToCompare = isEditing
213
- ? { ...addressState.address, ...data.address, ...formState.changes }
214
- : { ...data.address, ...formState?.changes };
215
-
216
- const isAddressAlreadyExist =
217
- arrayList
218
- .map((address: any) => checkAddress(address, addressToCompare))
219
- .some((value: any) => value) ?? false;
220
-
221
- if (!isAddressAlreadyExist) {
222
- saveAddress(data.address);
223
- if (isGuestUser) {
224
- continueAsGuest();
225
- return;
226
- }
227
- if (!isGuestUser && !auth) {
228
- !isFromProductsList
229
- ? navigation.navigate('Business')
230
- : navigation?.canGoBack() && navigation.goBack();
231
- }
232
- return;
233
- }
234
-
235
- setAlertState({
236
- open: true,
237
- content: [t('ADDRESS_ALREADY_EXIST', 'The address already exists')],
238
- });
239
- } else {
240
- setAlertState({
241
- open: true,
242
- content: [t('ERROR_NOT_FOUND_ADDRESS', 'Error, address not found')],
243
- });
244
- }
245
- })
246
- .catch((error) => {
247
- setAlertState({
248
- open: true,
249
- content: [error?.message || error?.toString()],
250
- });
251
- });
252
- };
253
-
254
- const onSubmit = () => {
255
- if (
256
- !auth &&
257
- formState?.changes?.address === '' &&
258
- addressState?.address?.address
259
- ) {
260
- setAlertState({
261
- open: true,
262
- content: [
263
- t(
264
- 'VALIDATION_ERROR_ADDRESS_REQUIRED',
265
- 'The field Address is required',
266
- ),
267
- ],
268
- });
269
- return;
270
- }
271
- if (formState?.changes?.address && !formState?.changes?.location) {
272
- if (isLocationRequired) {
273
- setAlertState({
274
- open: true,
275
- content: [
276
- t(
277
- 'ADDRESS_REQUIRE_LOCATION',
278
- 'The address needs a location, please select one of the suggested',
279
- ),
280
- ],
281
- });
282
- return;
283
- }
284
- getAddressFormatted(formState?.changes?.address);
285
- return;
286
- }
287
-
288
- const arrayList = isEditing
289
- ? addressesList?.addresses?.filter(
290
- (address: any) => address.id !== addressState?.address?.id,
291
- ) || []
292
- : addressesList || [];
293
- const addressToCompare = isEditing
294
- ? { ...addressState.address, ...formState.changes }
295
- : formState?.changes;
296
-
297
- const isAddressAlreadyExist =
298
- arrayList
299
- .map((address: any) => checkAddress(address, addressToCompare))
300
- .some((value: any) => value) ?? false;
301
-
302
- if (!isAddressAlreadyExist) {
303
- saveAddress();
304
- if (isGuestUser) {
305
- continueAsGuest();
306
- }
307
- if (!isGuestUser && !auth && !afterSignup) {
308
- !isFromProductsList
309
- ? navigation.navigate('Business')
310
- : navigation?.canGoBack() && navigation.goBack();
311
- }
312
- return;
313
- }
314
-
315
- setAlertState({
316
- open: true,
317
- content: [t('ADDRESS_ALREADY_EXIST', 'The address already exists')],
318
- });
319
- };
320
-
321
- /**
322
- * Returns true when the user made no changes
323
- * @param {object} address
324
- */
325
- const checkAddress = (address: any, addressToCompare: any) => {
326
- const props = [
327
- 'address',
328
- 'address_notes',
329
- 'zipcode',
330
- 'location',
331
- 'internal_number',
332
- ];
333
- const values: any = [];
334
- props.forEach((prop) => {
335
- if (addressToCompare[prop]) {
336
- if (prop === 'location') {
337
- values.push(
338
- address[prop]?.lat === addressToCompare[prop]?.lat &&
339
- address[prop]?.lng === addressToCompare[prop]?.lng,
340
- );
341
- } else {
342
- values.push(address[prop] === addressToCompare[prop]);
343
- }
344
- } else {
345
- values.push(!address[prop]);
346
- }
347
- });
348
- return values.every((value: any) => value);
349
- };
350
-
351
- const handleChangeAddress = (data: any, details: any) => {
352
- const addressSelected = {
353
- address: data?.description || data?.address,
354
- location: details?.geometry?.location,
355
- utc_offset: details?.utc_offset || null,
356
- map_data: { library: 'google', place_id: data.place_id },
357
- zip_code: data?.zip_code || null,
358
- };
359
- updateChanges(addressSelected);
360
- };
361
-
362
- const handleAddressTag = (tag: string) => {
363
- setAddressTag(tag);
364
- handleChangeInput({
365
- target: {
366
- name: 'tag',
367
- value: tag,
368
- },
369
- });
370
- };
371
-
372
- const handleToggleMap = () => {
373
- setToggleMap(!toggleMap);
374
- };
375
-
376
- const showFieldWithTheme = (name) => {
377
- return !theme?.address?.components?.[name]?.hidden
378
- }
379
-
380
- useEffect(() => {
381
- if (
382
- orderState.loading &&
383
- !addressesList &&
384
- orderState?.options?.address &&
385
- auth &&
386
- !afterSignup
387
- ) {
388
- isFromCheckout
389
- ? navigation.goBack()
390
- : !isFromProductsList
391
- ? navigation.navigate('BottomTab')
392
- : navigation.navigate('Business');
393
- }
394
- }, [orderState?.options?.address]);
395
-
396
- useEffect(() => {
397
- if (alertState.open && alertState?.key !== 'ERROR_MAX_LIMIT_LOCATION') {
398
- alertState.content && showToast(ToastType.Error, alertState.content);
399
- }
400
- }, [alertState.content]);
401
-
402
- useEffect(() => {
403
- if (!auth) {
404
- inputNames.forEach((field) =>
405
- setValue(
406
- field.name,
407
- formState?.changes[field.name] ||
408
- (orderState?.options?.address &&
409
- orderState?.options?.address[field.name]) ||
410
- '',
411
- ),
412
- );
413
- return;
414
- }
415
-
416
- if (!formState.loading && formState.result?.error) {
417
- setAlertState({
418
- open: true,
419
- content: formState.result?.result || [t('ERROR', 'Error')],
420
- });
421
- }
422
-
423
- setValue(
424
- 'address',
425
- formState?.changes?.address ?? addressState.address?.address ?? '',
426
- );
427
- if (!isEditing) {
428
- formState?.changes?.address &&
429
- setLocationChange(formState?.changes?.location);
430
- if (
431
- formState?.changes?.address &&
432
- formState?.changes?.address !== firstLocationNoEdit?.address &&
433
- formState?.changes?.location &&
434
- formState?.changes?.location?.lat !== firstLocationNoEdit.value?.lat &&
435
- formState?.changes?.location?.lng !== firstLocationNoEdit.value?.lng
436
- ) {
437
- setFirstLocationNoEdit({
438
- value: formState?.changes?.location,
439
- address: formState?.changes?.address,
440
- });
441
- }
442
- }
443
-
444
- if (isEditing) {
445
- if (formState?.changes?.location) {
446
- const prevLocation = {
447
- lat: locationChange?.lat?.toFixed(5),
448
- lng: locationChange?.lng?.toFixed(5),
449
- };
450
- const newLocation = {
451
- lat: formState?.changes?.location?.lat?.toFixed(5),
452
- lng: formState?.changes?.location?.lng?.toFixed(5),
453
- };
454
- if (
455
- prevLocation?.lat !== newLocation?.lat &&
456
- prevLocation?.lng !== newLocation?.lng
457
- ) {
458
- setLocationChange(formState?.changes?.location);
459
- }
460
- }
461
- }
462
- }, [formState]);
463
-
464
- useEffect(() => {
465
- if (formState?.result?.result && !formState?.loading) {
466
- if (formState.result?.error) {
467
- showToast(ToastType.Error, formState.result.result);
468
- } else {
469
- showToast(
470
- ToastType.Success,
471
- t('UPDATE_SUCCESSFULLY', 'Update successfully'),
472
- );
473
- }
474
- }
475
- }, [formState.result]);
476
-
477
- useEffect(() => {
478
- if (Object.keys(errors).length > 0) {
479
- // Convert all errors in one string to show in toast provider
480
- const list = Object.values(errors);
481
- let stringError = '';
482
- list.map((item: any, i: number) => {
483
- stringError +=
484
- i + 1 === list.length ? `- ${item.message}` : `- ${item.message}\n`;
485
- });
486
- showToast(ToastType.Error, stringError);
487
- }
488
- }, [errors]);
489
-
490
- useEffect(() => {
491
- if (googleInput?.current) {
492
- googleInput?.current?.setAddressText(
493
- address?.address ||
494
- formState.changes?.address ||
495
- addressState.address.address ||
496
- '',
497
- );
498
- }
499
- }, []);
500
-
501
- useEffect(() => {
502
- Geocoder.init(googleMapsApiKey);
503
- }, [googleMapsApiKey]);
504
-
505
- useEffect(() => {
506
- const keyboardDidShowListener = Keyboard.addListener(
507
- 'keyboardDidShow',
508
- () => {
509
- setIsKeyboardShow(true);
510
- },
511
- );
512
- const keyboardDidHideListener = Keyboard.addListener(
513
- 'keyboardDidHide',
514
- () => {
515
- setIsKeyboardShow(false);
516
- },
517
- );
518
- return () => {
519
- keyboardDidShowListener.remove();
520
- keyboardDidHideListener.remove();
521
- };
522
- }, []);
523
-
524
- useEffect(() => {
525
- if (!orderState.loading && auth && !hasAddressDefault && isSignUpEffect) {
526
- navigation.navigate('BottomTab');
527
- }
528
- setIsSignUpEffect(true);
529
- }, [orderState.loading]);
530
-
531
- useEffect(() => {
532
- if (isAllowUnaddressOrderType) {
533
- onNavigationRedirect && onNavigationRedirect(!!businessSlug ? 'Business' : 'BusinessList')
534
- }
535
- }, [isAllowUnaddressOrderType])
536
-
537
- return (
538
- <ScrollView
539
- keyboardShouldPersistTaps='always'
540
- listViewDisplayed={false}
541
- >
542
- <View style={styles.wrapperNavbar}>
543
- <NavBar
544
- title={t('WHERE_DO_WE_DELIVERY', 'Where do we delivery?')}
545
- titleAlign={'center'}
546
- onActionLeft={goToBack}
547
- showCall={false}
548
- btnStyle={{ paddingLeft: 0, paddingRight: 5 }}
549
- style={{ marginTop: Platform.OS === 'ios' ? 0 : 10 }}
550
- titleWrapStyle={{ paddingHorizontal: 0, width: '100%' }}
551
- titleStyle={{ marginRight: 0, marginLeft: 0, paddingRight: 5 }}
552
- />
553
- </View>
554
- <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
555
- <AddressFormContainer style={{ overflow: 'scroll' }}>
556
- <View>
557
- <FormInput>
558
- <AutocompleteInput>
559
- <Controller
560
- control={control}
561
- name="address"
562
- defaultValue={
563
- address?.address ||
564
- formState.changes?.address ||
565
- addressState.address.address ||
566
- ''
567
- }
568
- rules={{
569
- required:
570
- isRequiredField && isRequiredField('address')
571
- ? t(
572
- `VALIDATION_ERROR_ADDRESS_REQUIRED`,
573
- `The field Address is required`,
574
- )
575
- : null,
576
- }}
577
- render={() => (
578
- <GooglePlacesAutocomplete
579
- placeholder={t('ADD_ADDRESS', 'Add a address')}
580
- onPress={(data, details: any) => {
581
- handleChangeAddress(data, details);
582
- setAutoCompleteAddress(true);
583
- }}
584
- query={{
585
- key: googleMapsApiKey,
586
- components: countryCode && countryCode !== '*' ? `country:${countryCode}` : ''
587
- }}
588
- fetchDetails
589
- ref={googleInput}
590
- textInputProps={{
591
- onChangeText: (text) => {
592
- if (!isFirstTime) {
593
- handleChangeInput({
594
- target: { name: 'address', value: text },
595
- });
596
- setValue('address', text);
597
- setAutoCompleteAddress(true)
598
- }
599
- setIsFirstTime(false);
600
- setAddressEditing(text.length == 0);
601
- },
602
- onSubmitEditing: () =>
603
- internalNumberRef?.current?.focus?.(),
604
- autoCorrect: false,
605
- blurOnSubmit: false,
606
- returnKeyType: 'next',
607
- onFocus: () => setAutoCompleteInputFocused(true),
608
- onBlur: () => setAutoCompleteInputFocused(false)
609
- }}
610
- onFail={(error) =>
611
- setAlertState({
612
- open: true,
613
- content: getTraduction(error),
614
- })
615
- }
616
- styles={{
617
- listView: {
618
- position: 'relative',
619
- borderBottomStartRadius: 15,
620
- borderBottomEndRadius: 15,
621
- elevation: 2,
622
- borderWidth: 1,
623
- borderColor: '#ddd',
624
- bottom: 20,
625
- },
626
- container: {
627
- zIndex: 100,
628
- },
629
- textInput: {
630
- borderWidth: 1,
631
- borderRadius: 7.6,
632
- borderColor: autoCompleteInputFocused ? theme.colors.primary : theme.colors.border,
633
- flexGrow: 1,
634
- fontSize: 15,
635
- paddingLeft: 16,
636
- paddingRight: 32,
637
- minHeight: 50,
638
- fontFamily: 'Poppins-Regular',
639
- marginBottom: 24
640
- },
641
- }}
642
- />
643
- )}
644
- />
645
-
646
- {(
647
- ((!isEditing && !isGuestUser) ||
648
- (isEditing && !isGuestUser)) ||
649
- (isGuestUser)) &&
650
- (
651
- <View style={styles.pinIcon}>
652
- <GPSButton
653
- apiKey={googleMapsApiKey}
654
- handleGPS={(data: any, detail: any) => {
655
- handleChangeAddress(data, detail);
656
- setValue('address', data.address);
657
- if (googleInput?.current) {
658
- googleInput?.current?.setAddressText(data.address);
659
- }
660
- }}
661
- IconButton={<OIcon src={theme.images.general.pin} width={16} />}
662
- isIntGeoCoder
663
- />
664
- </View>
665
- )}
666
- </AutocompleteInput>
667
-
668
- {!isHideMap && (locationChange || formState.changes?.location) && (
669
- <View
670
- style={{
671
- height: 189,
672
- borderRadius: 7.6,
673
- overflow: 'hidden',
674
- marginBottom: 24,
675
- }}>
676
- <GoogleMapContainer>
677
- <GoogleMap
678
- location={locationChange || formState.changes?.location}
679
- handleChangeAddressMap={handleChangeAddress}
680
- maxLimitLocation={maxLimitLocation}
681
- saveLocation={saveMapLocation}
682
- setSaveLocation={setSaveMapLocation}
683
- handleToggleMap={handleToggleMap}
684
- isIntGeoCoder
685
- setAutoCompleteAddress={setAutoCompleteAddress}
686
- autoCompleteAddress={autoCompleteAddress}
687
- />
688
- </GoogleMapContainer>
689
- </View>
690
- )}
691
-
692
- <View style={{ flexDirection: 'row', flexBasis: '50%' }}>
693
- {((isRequiredField && isRequiredField('internal_number')) || showFieldWithTheme('internal_number')) && (
694
- <Controller
695
- control={control}
696
- name="internal_number"
697
- rules={{
698
- required:
699
- isRequiredField && isRequiredField('internal_number')
700
- ? t(
701
- `VALIDATION_ERROR_INTERNAL_NUMBER_REQUIRED`,
702
- `The field internal number is required`,
703
- )
704
- : null,
705
- }}
706
- defaultValue={
707
- address?.internal_number ||
708
- formState.changes?.internal_number ||
709
- addressState?.address?.internal_number ||
710
- ''
711
- }
712
- render={() => (
713
- <OInput
714
- name="internal_number"
715
- placeholder={t('INTERNAL_NUMBER', 'Internal number')}
716
- onChange={(text: string) => {
717
- handleChangeInput(text);
718
- setValue('internal_number', text);
719
- }}
720
- value={
721
- address?.internal_number ||
722
- formState.changes?.internal_number ||
723
- addressState?.address?.internal_number ||
724
- ''
725
- }
726
- isFocusHighlight
727
- style={{
728
- ...styles.inputsStyle,
729
- marginRight: showField?.('internal_number') && showField?.('zipcode') ? 24 : 0
730
- }}
731
- forwardRef={internalNumberRef}
732
- returnKeyType="next"
733
- onSubmitEditing={() => zipCodeRef?.current?.focus?.()}
734
- blurOnSubmit={false}
735
- />
736
- )}
737
- />
738
- )}
739
-
740
- {((isRequiredField && isRequiredField('zipcode')) || showFieldWithTheme('zipcode')) && (
741
- <Controller
742
- control={control}
743
- name="zipcode"
744
- rules={{
745
- required:
746
- isRequiredField && isRequiredField('zipcode')
747
- ? t(
748
- `VALIDATION_ERROR_ZIP_CODE_REQUIRED`,
749
- `The field Zip Code is required`,
750
- )
751
- : null,
752
- }}
753
- defaultValue={
754
- address?.zipcode ||
755
- formState.changes?.zipcode ||
756
- addressState.address.zipcode ||
757
- ''
758
- }
759
- render={() => (
760
- <OInput
761
- name="zipcode"
762
- placeholder={t('ZIP_CODE', 'Zip code')}
763
- onChange={(text: string) => {
764
- handleChangeInput(text);
765
- setValue('zipcode', text);
766
- }}
767
- value={
768
- address?.zipcode ||
769
- formState.changes?.zipcode ||
770
- addressState.address.zipcode ||
771
- ''
772
- }
773
- isFocusHighlight
774
- style={styles.inputsStyle}
775
- forwardRef={zipCodeRef}
776
- returnKeyType="next"
777
- onSubmitEditing={() => addressNotesRef?.current?.focus?.()}
778
- blurOnSubmit={false}
779
- />
780
- )}
781
- />
782
- )}
783
- </View>
784
-
785
- {((isRequiredField && isRequiredField('address_notes')) || showFieldWithTheme('address_notes')) && (
786
- <Controller
787
- control={control}
788
- name="address_notes"
789
- rules={{
790
- required:
791
- isRequiredField && isRequiredField('address_notes')
792
- ? t(
793
- `VALIDATION_ERROR_ADDRESS_NOTES_REQUIRED`,
794
- `The field address notes is required`,
795
- )
796
- : null,
797
- }}
798
- defaultValue={
799
- address?.address_notes ||
800
- formState.changes?.address_notes ||
801
- addressState.address.address_notes ||
802
- ''
803
- }
804
- render={() => (
805
- <OInput
806
- name="address_notes"
807
- placeholder={t('ADDRESS_NOTES', 'Address notes')}
808
- onChange={(text: any) => {
809
- handleChangeInput(text);
810
- setValue('address_notes', text);
811
- }}
812
- value={
813
- address?.address_notes ||
814
- formState.changes?.address_notes ||
815
- addressState.address.address_notes ||
816
- ''
817
- }
818
- multiline
819
- isFocusHighlight
820
- style={styles.textAreaStyles}
821
- returnKeyType="done"
822
- forwardRef={addressNotesRef}
823
- blurOnSubmit
824
- />
825
- )}
826
- />
827
- )}
828
- </FormInput>
829
- {!isHideIcons && (
830
- <IconsContainer>
831
- {tagsName.map((tag) => (
832
- <TouchableOpacity
833
- key={tag.value}
834
- onPress={() => handleAddressTag(tag.value)}>
835
- <View
836
- style={{
837
- ...styles.iconContainer,
838
- }}>
839
- <OIcon
840
- src={tag.icon}
841
- width={24}
842
- color={
843
- addressTag === tag.value ?
844
- theme.colors.primary : theme.colors.disabled
845
- }
846
- />
847
- </View>
848
- </TouchableOpacity>
849
- ))}
850
- </IconsContainer>
851
- )}
852
- </View>
853
-
854
- <View>
855
- {Object.keys(formState?.changes).length > 0 ? (
856
- <OButton
857
- text={
858
- !formState.loading
859
- ? isEditing ||
860
- (!auth && orderState.options?.address?.address)
861
- ? t('UPDATE', 'Update')
862
- : t('CONTINUE', 'Continue')
863
- : t('LOADING', 'Loading')
864
- }
865
- onClick={handleSubmit(onSubmit)}
866
- isDisabled={formState.loading}
867
- style={{ borderRadius: 7.6, shadowOpacity: 0 }}
868
- showNextIcon
869
- />
870
- ) : (
871
- <OButton
872
- text={t('CANCEL', 'Cancel')}
873
- bgColor={theme.colors.secundary}
874
- borderColor={theme.colors.secundary}
875
- textStyle={{ color: theme.colors.textNormal }}
876
- style={{ borderRadius: 7.6, borderWidth: 1, shadowOpacity: 0 }}
877
- onClick={() => navigation?.canGoBack() && navigation.goBack()}
878
- />
879
- )}
880
- </View>
881
- <OModal
882
- open={toggleMap}
883
- onClose={() => handleToggleMap()}
884
- entireModal
885
- customClose>
886
- {(locationChange || formState.changes?.location) && (
887
- <GoogleMapContainer>
888
- <GoogleMap
889
- location={locationChange || formState.changes?.location}
890
- handleChangeAddressMap={handleChangeAddress}
891
- maxLimitLocation={maxLimitLocation}
892
- saveLocation={saveMapLocation}
893
- setSaveLocation={setSaveMapLocation}
894
- handleToggleMap={handleToggleMap}
895
- isIntGeoCoder
896
- />
897
- </GoogleMapContainer>
898
- )}
899
- <OButton
900
- text={t('SAVE', 'Save')}
901
- imgRightSrc={null}
902
- style={{ marginHorizontal: 30, marginBottom: 10 }}
903
- onClick={() => setSaveMapLocation(true)}
904
- />
905
- </OModal>
906
- <Spinner visible={saveMapLocation} />
907
- </AddressFormContainer>
908
- </TouchableWithoutFeedback>
909
- </ScrollView>
910
- );
53
+ const {
54
+ navigation,
55
+ updateChanges,
56
+ address,
57
+ formState,
58
+ isEditing,
59
+ handleChangeInput,
60
+ addressState,
61
+ addressesList,
62
+ saveAddress,
63
+ isGuestUser,
64
+ isRequiredField,
65
+ showField,
66
+ isFromProductsList,
67
+ hasAddressDefault,
68
+ afterSignup,
69
+ businessSlug,
70
+ isFromCheckout,
71
+ onNavigationRedirect
72
+ } = props;
73
+
74
+ const theme = useTheme();
75
+ const [orientationState] = useDeviceOrientation();
76
+
77
+ const [autoCompleteInputFocused, setAutoCompleteInputFocused] = useState(false)
78
+
79
+ const isEmptyField = (key: any, str: any) => isRequiredField && isRequiredField(key) && (!str || str.trim().length === 0)
80
+
81
+ const tagsName = [
82
+ { icon: theme.images.general.tag_home, value: 'home' },
83
+ { icon: theme.images.general.tag_building, value: 'office' },
84
+ { icon: theme.images.general.tag_heart, value: 'favorite' },
85
+ { icon: theme.images.general.tag_plus, value: 'other' },
86
+ ];
87
+
88
+ const HEIGHT_SCREEN = orientationState?.dimensions?.height
89
+
90
+ const styles = StyleSheet.create({
91
+ iconContainer: {
92
+ display: 'flex',
93
+ justifyContent: 'center',
94
+ alignItems: 'center',
95
+ paddingHorizontal: 18,
96
+ paddingVertical: 5,
97
+ backgroundColor: theme.colors.clear
98
+ },
99
+ inputsStyle: {
100
+ borderRadius: 10,
101
+ marginBottom: 20,
102
+ height: 50,
103
+ maxHeight: 50,
104
+ minHeight: 50,
105
+ flex: 1,
106
+ },
107
+ textAreaStyles: {
108
+ borderRadius: 10,
109
+ marginBottom: 20,
110
+ height: 104,
111
+ maxHeight: 104,
112
+ minHeight: 104,
113
+ textAlignVertical: 'top',
114
+ alignItems: 'flex-start',
115
+ },
116
+ pinIcon: {
117
+ position: 'absolute',
118
+ end: 0,
119
+ top: 12,
120
+ zIndex: 1002,
121
+ right: autoCompleteInputFocused && (
122
+ !!address?.address ||
123
+ !!formState.changes?.address ||
124
+ !!addressState.address.address
125
+ ) ? 30 : 15,
126
+ width: 16
127
+ },
128
+ wrapperNavbar: Platform.OS === 'ios'
129
+ ? { paddingVertical: 0, paddingLeft: 20, paddingRight: 20 }
130
+ : { paddingVertical: 10, paddingLeft: 20, paddingRight: 20 }
131
+ });
132
+
133
+ const [, t] = useLanguage();
134
+ const [{ auth }] = useSession();
135
+ const [, { showToast }] = useToast();
136
+ const [configState] = useConfig();
137
+ const [orderState] = useOrder();
138
+ const { handleSubmit, errors, control, setValue } = useForm();
139
+ const [autoCompleteAddress, setAutoCompleteAddress] = useState(false)
140
+
141
+ const [toggleMap, setToggleMap] = useState(false);
142
+ const [alertState, setAlertState] = useState<{
143
+ open: boolean;
144
+ content: Array<string>;
145
+ key?: string | null;
146
+ }>({ open: false, content: [], key: null });
147
+ const [addressTag, setAddressTag] = useState(addressState?.address?.tag);
148
+ const [firstLocationNoEdit, setFirstLocationNoEdit] = useState({
149
+ value: { lat: null, lng: null },
150
+ address: null,
151
+ });
152
+ const [isFirstTime, setIsFirstTime] = useState(true);
153
+ const [locationChange, setLocationChange] = useState(
154
+ isEditing
155
+ ? addressState?.address?.location
156
+ : formState.changes?.location ?? null,
157
+ );
158
+ const [saveMapLocation, setSaveMapLocation] = useState(false);
159
+ const [isKeyboardShow, setIsKeyboardShow] = useState(false);
160
+ const [isSignUpEffect, setIsSignUpEffect] = useState(false);
161
+ const [hasEditing, setAddressEditing] = useState(false);
162
+
163
+ const googleInput: any = useRef(null);
164
+ const internalNumberRef: any = useRef(null);
165
+ const zipCodeRef: any = useRef(null);
166
+ const addressNotesRef: any = useRef(null);
167
+
168
+ const googleMapsApiKey = configState?.configs?.google_maps_api_key?.value;
169
+ const isLocationRequired =
170
+ configState.configs?.google_autocomplete_selection_required?.value ===
171
+ '1' ||
172
+ configState.configs?.google_autocomplete_selection_required?.value ===
173
+ 'true';
174
+ const maxLimitLocation =
175
+ configState?.configs?.meters_to_change_address?.value;
176
+ const countryCode = configState?.configs?.country_autocomplete?.value
177
+ const isHideMap = theme?.address?.components?.map?.hidden
178
+ const isHideIcons = theme?.address?.components?.icons?.hidden
179
+ const continueAsGuest = () => navigation.navigate(!!businessSlug ? 'Business' : 'BusinessList', { isGuestUser: true });
180
+ const unaddressedTypes = configState?.configs?.unaddressed_order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
181
+ const isAllowUnaddressOrderType = unaddressedTypes.includes(orderState?.options?.type)
182
+ const goToBack = () => navigation?.canGoBack() && navigation.goBack();
183
+
184
+ const getAddressFormatted = (address: any) => {
185
+ const data: any = { address: null, error: null };
186
+ Geocoder.from(address)
187
+ .then((json) => {
188
+ if (json.results && json.results?.length > 0) {
189
+ let postalCode = null;
190
+ for (const component of json.results?.[0].address_components) {
191
+ const addressType = component.types?.[0];
192
+ if (addressType === 'postal_code') {
193
+ postalCode = component.short_name;
194
+ break;
195
+ }
196
+ }
197
+ data.address = {
198
+ address,
199
+ location: json.results[0].geometry.location,
200
+ map_data: {
201
+ library: 'google',
202
+ place_id: json.results?.[0].place_id,
203
+ },
204
+ };
205
+ if (postalCode) {
206
+ data.address.zipcode = postalCode;
207
+ }
208
+
209
+ const arrayList = isEditing
210
+ ? addressesList?.addresses?.filter(
211
+ (address: any) => address.id !== addressState?.address?.id,
212
+ ) || []
213
+ : addressesList || [];
214
+ const addressToCompare = isEditing
215
+ ? { ...addressState.address, ...data.address, ...formState.changes }
216
+ : { ...data.address, ...formState?.changes };
217
+
218
+ const isAddressAlreadyExist =
219
+ arrayList
220
+ .map((address: any) => checkAddress(address, addressToCompare))
221
+ .some((value: any) => value) ?? false;
222
+
223
+ if (!isAddressAlreadyExist) {
224
+ saveAddress(data.address);
225
+ if (isGuestUser) {
226
+ continueAsGuest();
227
+ return;
228
+ }
229
+ if (!isGuestUser && !auth) {
230
+ !isFromProductsList
231
+ ? navigation.navigate('Business')
232
+ : navigation?.canGoBack() && navigation.goBack();
233
+ }
234
+ return;
235
+ }
236
+
237
+ setAlertState({
238
+ open: true,
239
+ content: [t('ADDRESS_ALREADY_EXIST', 'The address already exists')],
240
+ });
241
+ } else {
242
+ setAlertState({
243
+ open: true,
244
+ content: [t('ERROR_NOT_FOUND_ADDRESS', 'Error, address not found')],
245
+ });
246
+ }
247
+ })
248
+ .catch((error) => {
249
+ setAlertState({
250
+ open: true,
251
+ content: [error?.message || error?.toString()],
252
+ });
253
+ });
254
+ };
255
+
256
+ const onSubmit = () => {
257
+ if (
258
+ !auth &&
259
+ formState?.changes?.address === '' &&
260
+ addressState?.address?.address
261
+ ) {
262
+ setAlertState({
263
+ open: true,
264
+ content: [
265
+ t(
266
+ 'VALIDATION_ERROR_ADDRESS_REQUIRED',
267
+ 'The field Address is required',
268
+ ),
269
+ ],
270
+ });
271
+ return;
272
+ }
273
+ if (formState?.changes?.address && !formState?.changes?.location) {
274
+ if (isLocationRequired) {
275
+ setAlertState({
276
+ open: true,
277
+ content: [
278
+ t(
279
+ 'ADDRESS_REQUIRE_LOCATION',
280
+ 'The address needs a location, please select one of the suggested',
281
+ ),
282
+ ],
283
+ });
284
+ return;
285
+ }
286
+ getAddressFormatted(formState?.changes?.address);
287
+ return;
288
+ }
289
+
290
+ const arrayList = isEditing
291
+ ? addressesList?.addresses?.filter(
292
+ (address: any) => address.id !== addressState?.address?.id,
293
+ ) || []
294
+ : addressesList || [];
295
+ const addressToCompare = isEditing
296
+ ? { ...addressState.address, ...formState.changes }
297
+ : formState?.changes;
298
+
299
+ const isAddressAlreadyExist =
300
+ arrayList
301
+ .map((address: any) => checkAddress(address, addressToCompare))
302
+ .some((value: any) => value) ?? false;
303
+
304
+ if (!isAddressAlreadyExist) {
305
+ saveAddress();
306
+ if (isGuestUser) {
307
+ continueAsGuest();
308
+ }
309
+ if (!isGuestUser && !auth && !afterSignup) {
310
+ !isFromProductsList
311
+ ? navigation.navigate('Business')
312
+ : navigation?.canGoBack() && navigation.goBack();
313
+ }
314
+ return;
315
+ }
316
+
317
+ setAlertState({
318
+ open: true,
319
+ content: [t('ADDRESS_ALREADY_EXIST', 'The address already exists')],
320
+ });
321
+ };
322
+
323
+ /**
324
+ * Returns true when the user made no changes
325
+ * @param {object} address
326
+ */
327
+ const checkAddress = (address: any, addressToCompare: any) => {
328
+ const props = [
329
+ 'address',
330
+ 'address_notes',
331
+ 'zipcode',
332
+ 'location',
333
+ 'internal_number',
334
+ ];
335
+ const values: any = [];
336
+ props.forEach((prop) => {
337
+ if (addressToCompare[prop]) {
338
+ if (prop === 'location') {
339
+ values.push(
340
+ address[prop]?.lat === addressToCompare[prop]?.lat &&
341
+ address[prop]?.lng === addressToCompare[prop]?.lng,
342
+ );
343
+ } else {
344
+ values.push(address[prop] === addressToCompare[prop]);
345
+ }
346
+ } else {
347
+ values.push(!address[prop]);
348
+ }
349
+ });
350
+ return values.every((value: any) => value);
351
+ };
352
+
353
+ const handleChangeAddress = (data: any, details: any) => {
354
+ const addressObj: any = {}
355
+ if (details?.address_components) {
356
+ details.address_components.map((component: any) => {
357
+ const addressType = component.types[0]
358
+ if (addressType === 'postal_code') {
359
+ addressObj.zipcode = component.short_name
360
+ }
361
+ if (addressType === 'street_number') {
362
+ addressObj.street_number = component.long_name
363
+ }
364
+ if (addressType === 'neighborhood') {
365
+ addressObj.neighborhood = component.long_name
366
+ }
367
+ if (addressType === 'route') {
368
+ addressObj.route = component.short_name
369
+ }
370
+ if (addressType === 'locality') {
371
+ addressObj.locality = component.long_name
372
+ }
373
+ if (component.types?.includes('sublocality')) {
374
+ addressObj.sublocality = component.long_name
375
+ }
376
+ if (addressType === 'country') {
377
+ addressObj.country = component.long_name
378
+ addressObj.country_code = component.short_name
379
+ }
380
+ if (addressType === 'administrative_area_level_1') {
381
+ addressObj.state = component.long_name
382
+ }
383
+ if (addressType === 'administrative_area_level_2') {
384
+ addressObj.city = component.long_name
385
+ }
386
+ })
387
+ }
388
+ const addressSelected = {
389
+ address: data?.description || data?.address,
390
+ location: details?.geometry?.location,
391
+ utc_offset: details?.utc_offset || null,
392
+ map_data: { library: 'google', place_id: data.place_id },
393
+ zipcode: data?.zipcode || null,
394
+ ...addressObj
395
+ };
396
+ updateChanges(addressSelected);
397
+ };
398
+
399
+ const handleAddressTag = (tag: string) => {
400
+ setAddressTag(tag);
401
+ handleChangeInput({
402
+ target: {
403
+ name: 'tag',
404
+ value: tag,
405
+ },
406
+ });
407
+ };
408
+
409
+ const handleToggleMap = () => {
410
+ setToggleMap(!toggleMap);
411
+ };
412
+
413
+ const showFieldWithTheme = (name) => {
414
+ return !theme?.address?.components?.[name]?.hidden
415
+ }
416
+
417
+ useEffect(() => {
418
+ if (
419
+ orderState.loading &&
420
+ !addressesList &&
421
+ orderState?.options?.address &&
422
+ auth &&
423
+ !afterSignup
424
+ ) {
425
+ isFromCheckout
426
+ ? navigation.goBack()
427
+ : !isFromProductsList
428
+ ? navigation.navigate('BottomTab')
429
+ : navigation.navigate('Business');
430
+ }
431
+ }, [orderState?.options?.address]);
432
+
433
+ useEffect(() => {
434
+ if (alertState.open && alertState?.key !== 'ERROR_MAX_LIMIT_LOCATION') {
435
+ alertState.content && showToast(ToastType.Error, alertState.content);
436
+ }
437
+ }, [alertState.content]);
438
+
439
+ useEffect(() => {
440
+ if (!auth) {
441
+ inputNames.forEach((field) =>
442
+ setValue(
443
+ field.name,
444
+ formState?.changes[field.name] ||
445
+ (orderState?.options?.address &&
446
+ orderState?.options?.address[field.name]) ||
447
+ '',
448
+ ),
449
+ );
450
+ return;
451
+ }
452
+
453
+ if (!formState.loading && formState.result?.error) {
454
+ setAlertState({
455
+ open: true,
456
+ content: formState.result?.result || [t('ERROR', 'Error')],
457
+ });
458
+ }
459
+
460
+ setValue(
461
+ 'address',
462
+ formState?.changes?.address ?? addressState.address?.address ?? '',
463
+ );
464
+ if (!isEditing) {
465
+ formState?.changes?.address &&
466
+ setLocationChange(formState?.changes?.location);
467
+ if (
468
+ formState?.changes?.address &&
469
+ formState?.changes?.address !== firstLocationNoEdit?.address &&
470
+ formState?.changes?.location &&
471
+ formState?.changes?.location?.lat !== firstLocationNoEdit.value?.lat &&
472
+ formState?.changes?.location?.lng !== firstLocationNoEdit.value?.lng
473
+ ) {
474
+ setFirstLocationNoEdit({
475
+ value: formState?.changes?.location,
476
+ address: formState?.changes?.address,
477
+ });
478
+ }
479
+ }
480
+
481
+ if (isEditing) {
482
+ if (formState?.changes?.location) {
483
+ const prevLocation = {
484
+ lat: locationChange?.lat?.toFixed(5),
485
+ lng: locationChange?.lng?.toFixed(5),
486
+ };
487
+ const newLocation = {
488
+ lat: formState?.changes?.location?.lat?.toFixed(5),
489
+ lng: formState?.changes?.location?.lng?.toFixed(5),
490
+ };
491
+ if (
492
+ prevLocation?.lat !== newLocation?.lat &&
493
+ prevLocation?.lng !== newLocation?.lng
494
+ ) {
495
+ setLocationChange(formState?.changes?.location);
496
+ }
497
+ }
498
+ }
499
+ }, [formState]);
500
+
501
+ useEffect(() => {
502
+ if (formState?.result && !formState?.loading) {
503
+ if (formState?.error) {
504
+ showToast(ToastType.Error, formState.error[0]);
505
+ } else {
506
+ showToast(
507
+ ToastType.Success,
508
+ t('UPDATE_SUCCESSFULLY', 'Update successfully'),
509
+ );
510
+ }
511
+ }
512
+ }, [formState.result]);
513
+
514
+ useEffect(() => {
515
+ if (Object.keys(errors).length > 0) {
516
+ // Convert all errors in one string to show in toast provider
517
+ const list = Object.values(errors);
518
+ let stringError = '';
519
+ list.map((item: any, i: number) => {
520
+ stringError +=
521
+ i + 1 === list.length ? `- ${item.message}` : `- ${item.message}\n`;
522
+ });
523
+ showToast(ToastType.Error, stringError);
524
+ }
525
+ }, [errors]);
526
+
527
+ useEffect(() => {
528
+ if (googleInput?.current) {
529
+ googleInput?.current?.setAddressText(
530
+ address?.address ||
531
+ formState.changes?.address ||
532
+ addressState.address.address ||
533
+ '',
534
+ );
535
+ }
536
+ }, []);
537
+
538
+ useEffect(() => {
539
+ Geocoder.init(googleMapsApiKey);
540
+ }, [googleMapsApiKey]);
541
+
542
+ useEffect(() => {
543
+ const keyboardDidShowListener = Keyboard.addListener(
544
+ 'keyboardDidShow',
545
+ () => {
546
+ setIsKeyboardShow(true);
547
+ },
548
+ );
549
+ const keyboardDidHideListener = Keyboard.addListener(
550
+ 'keyboardDidHide',
551
+ () => {
552
+ setIsKeyboardShow(false);
553
+ },
554
+ );
555
+ return () => {
556
+ keyboardDidShowListener.remove();
557
+ keyboardDidHideListener.remove();
558
+ };
559
+ }, []);
560
+
561
+ useEffect(() => {
562
+ if (!orderState.loading && auth && !hasAddressDefault && isSignUpEffect) {
563
+ navigation.navigate('BottomTab');
564
+ }
565
+ setIsSignUpEffect(true);
566
+ }, [orderState.loading]);
567
+
568
+ useEffect(() => {
569
+ if (isAllowUnaddressOrderType) {
570
+ onNavigationRedirect && onNavigationRedirect(!!businessSlug ? 'Business' : 'BusinessList')
571
+ }
572
+ }, [isAllowUnaddressOrderType])
573
+
574
+ return (
575
+ <ScrollView
576
+ keyboardShouldPersistTaps='always'
577
+ listViewDisplayed={false}
578
+ >
579
+ <View style={styles.wrapperNavbar}>
580
+ <NavBar
581
+ title={t('WHERE_DO_WE_DELIVERY', 'Where do we delivery?')}
582
+ titleAlign={'center'}
583
+ onActionLeft={goToBack}
584
+ showCall={false}
585
+ btnStyle={{ paddingLeft: 0, paddingRight: 5 }}
586
+ style={{ marginTop: Platform.OS === 'ios' ? 0 : 10 }}
587
+ titleWrapStyle={{ paddingHorizontal: 0, width: '100%' }}
588
+ titleStyle={{ marginRight: 0, marginLeft: 0, paddingRight: 5 }}
589
+ />
590
+ </View>
591
+ <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
592
+ <AddressFormContainer style={{ overflow: 'scroll' }}>
593
+ <View>
594
+ <FormInput>
595
+ <AutocompleteInput>
596
+ <Controller
597
+ control={control}
598
+ name="address"
599
+ defaultValue={
600
+ address?.address ||
601
+ formState.changes?.address ||
602
+ addressState.address.address ||
603
+ ''
604
+ }
605
+ rules={{
606
+ required:
607
+ isRequiredField && isRequiredField('address')
608
+ ? t(
609
+ `VALIDATION_ERROR_ADDRESS_REQUIRED`,
610
+ `The field Address is required`,
611
+ )
612
+ : null,
613
+ }}
614
+ render={() => (
615
+ <GooglePlacesAutocomplete
616
+ placeholder={t('ADD_ADDRESS', 'Add a address')}
617
+ onPress={(data, details: any) => {
618
+ handleChangeAddress(data, details);
619
+ setAutoCompleteAddress(true);
620
+ }}
621
+ query={{
622
+ key: googleMapsApiKey,
623
+ components: countryCode && countryCode !== '*' ? `country:${countryCode}` : ''
624
+ }}
625
+ fetchDetails
626
+ ref={googleInput}
627
+ textInputProps={{
628
+ onChangeText: (text) => {
629
+ if (!isFirstTime) {
630
+ handleChangeInput({
631
+ target: { name: 'address', value: text },
632
+ });
633
+ setValue('address', text);
634
+ setAutoCompleteAddress(true)
635
+ }
636
+ setIsFirstTime(false);
637
+ setAddressEditing(text.length == 0);
638
+ },
639
+ onSubmitEditing: () =>
640
+ internalNumberRef?.current?.focus?.(),
641
+ autoCorrect: false,
642
+ blurOnSubmit: false,
643
+ returnKeyType: 'next',
644
+ onFocus: () => setAutoCompleteInputFocused(true),
645
+ onBlur: () => setAutoCompleteInputFocused(false)
646
+ }}
647
+ onFail={(error) =>
648
+ setAlertState({
649
+ open: true,
650
+ content: getTraduction(error, t),
651
+ })
652
+ }
653
+ styles={{
654
+ listView: {
655
+ position: 'relative',
656
+ borderBottomStartRadius: 15,
657
+ borderBottomEndRadius: 15,
658
+ elevation: 2,
659
+ borderWidth: 1,
660
+ borderColor: '#ddd',
661
+ bottom: 20,
662
+ },
663
+ container: {
664
+ zIndex: 100,
665
+ },
666
+ textInput: {
667
+ borderWidth: 1,
668
+ borderRadius: 7.6,
669
+ borderColor: autoCompleteInputFocused ? theme.colors.primary : theme.colors.border,
670
+ flexGrow: 1,
671
+ fontSize: 15,
672
+ paddingLeft: 16,
673
+ paddingRight: 32,
674
+ minHeight: 50,
675
+ fontFamily: 'Poppins-Regular',
676
+ marginBottom: 24
677
+ },
678
+ }}
679
+ />
680
+ )}
681
+ />
682
+
683
+ {(
684
+ ((!isEditing && !isGuestUser) ||
685
+ (isEditing && !isGuestUser)) ||
686
+ (isGuestUser)) &&
687
+ (
688
+ <View style={styles.pinIcon}>
689
+ <GPSButton
690
+ apiKey={googleMapsApiKey}
691
+ handleGPS={(data: any, detail: any) => {
692
+ handleChangeAddress(data, detail);
693
+ setValue('address', data.address);
694
+ if (googleInput?.current) {
695
+ googleInput?.current?.setAddressText(data.address);
696
+ }
697
+ }}
698
+ IconButton={<OIcon src={theme.images.general.pin} width={16} />}
699
+ isIntGeoCoder
700
+ />
701
+ </View>
702
+ )}
703
+ </AutocompleteInput>
704
+
705
+ {!isHideMap && (locationChange || formState.changes?.location) && (
706
+ <View
707
+ style={{
708
+ height: 189,
709
+ borderRadius: 7.6,
710
+ overflow: 'hidden',
711
+ marginBottom: 24,
712
+ }}>
713
+ <GoogleMapContainer>
714
+ <GoogleMap
715
+ location={locationChange || formState.changes?.location}
716
+ handleChangeAddressMap={handleChangeAddress}
717
+ maxLimitLocation={maxLimitLocation}
718
+ saveLocation={saveMapLocation}
719
+ setSaveLocation={setSaveMapLocation}
720
+ handleToggleMap={handleToggleMap}
721
+ isIntGeoCoder
722
+ setAutoCompleteAddress={setAutoCompleteAddress}
723
+ autoCompleteAddress={autoCompleteAddress}
724
+ />
725
+ </GoogleMapContainer>
726
+ </View>
727
+ )}
728
+
729
+ <View style={{ flexDirection: 'row', flexBasis: '50%' }}>
730
+ {showField?.('internal_number') && ((isRequiredField && isRequiredField('internal_number')) || showFieldWithTheme('internal_number')) && (
731
+ <Controller
732
+ control={control}
733
+ name="internal_number"
734
+ rules={{
735
+ required:
736
+ isRequiredField && isRequiredField('internal_number')
737
+ ? t(
738
+ `VALIDATION_ERROR_INTERNAL_NUMBER_REQUIRED`,
739
+ `The field internal number is required`,
740
+ )
741
+ : null,
742
+ }}
743
+ defaultValue={
744
+ address?.internal_number ||
745
+ formState.changes?.internal_number ||
746
+ addressState?.address?.internal_number ||
747
+ ''
748
+ }
749
+ render={() => (
750
+ <OInput
751
+ name="internal_number"
752
+ placeholder={t('INTERNAL_NUMBER', 'Internal number')}
753
+ onChange={(data: any) => {
754
+ handleChangeInput(data);
755
+ setValue('internal_number', isEmptyField('internal_number', data?.target?.value) ? null : data);
756
+ }}
757
+ value={
758
+ address?.internal_number ||
759
+ formState.changes?.internal_number ||
760
+ addressState?.address?.internal_number ||
761
+ ''
762
+ }
763
+ isFocusHighlight
764
+ style={{
765
+ ...styles.inputsStyle,
766
+ marginRight: showField?.('internal_number') && showField?.('zipcode') ? 24 : 0
767
+ }}
768
+ forwardRef={internalNumberRef}
769
+ returnKeyType="next"
770
+ onSubmitEditing={() => zipCodeRef?.current?.focus?.()}
771
+ blurOnSubmit={false}
772
+ />
773
+ )}
774
+ />
775
+ )}
776
+
777
+ {showField?.('zipcode') && ((isRequiredField && isRequiredField('zipcode')) || showFieldWithTheme('zipcode')) && (
778
+ <Controller
779
+ control={control}
780
+ name="zipcode"
781
+ rules={{
782
+ required:
783
+ isRequiredField && isRequiredField('zipcode')
784
+ ? t(
785
+ `VALIDATION_ERROR_ZIP_CODE_REQUIRED`,
786
+ `The field Zip Code is required`,
787
+ )
788
+ : null,
789
+ }}
790
+ defaultValue={
791
+ address?.zipcode ||
792
+ formState.changes?.zipcode ||
793
+ addressState.address.zipcode ||
794
+ ''
795
+ }
796
+ render={() => (
797
+ <OInput
798
+ name="zipcode"
799
+ placeholder={t('ZIP_CODE', 'Zip code')}
800
+ onChange={(data: any) => {
801
+ handleChangeInput(data);
802
+ setValue('zipcode', isEmptyField('zipcode', data?.target?.value) ? null : data);
803
+ }}
804
+ value={
805
+ address?.zipcode ||
806
+ formState.changes?.zipcode ||
807
+ addressState.address.zipcode ||
808
+ ''
809
+ }
810
+ isFocusHighlight
811
+ style={styles.inputsStyle}
812
+ forwardRef={zipCodeRef}
813
+ returnKeyType="next"
814
+ onSubmitEditing={() => addressNotesRef?.current?.focus?.()}
815
+ blurOnSubmit={false}
816
+ />
817
+ )}
818
+ />
819
+ )}
820
+ </View>
821
+
822
+ {showField?.('address_notes') && ((isRequiredField && isRequiredField('address_notes')) || showFieldWithTheme('address_notes')) && (
823
+ <Controller
824
+ control={control}
825
+ name="address_notes"
826
+ rules={{
827
+ required:
828
+ isRequiredField && isRequiredField('address_notes')
829
+ ? t(
830
+ `VALIDATION_ERROR_ADDRESS_NOTES_REQUIRED`,
831
+ `The field address notes is required`,
832
+ )
833
+ : null,
834
+ }}
835
+ defaultValue={
836
+ address?.address_notes ||
837
+ formState.changes?.address_notes ||
838
+ addressState.address.address_notes ||
839
+ ''
840
+ }
841
+ render={() => (
842
+ <OInput
843
+ name="address_notes"
844
+ placeholder={t('ADDRESS_NOTES', 'Address notes')}
845
+ onChange={(text: any) => {
846
+ handleChangeInput(text);
847
+ setValue('address_notes', text);
848
+ }}
849
+ value={
850
+ address?.address_notes ||
851
+ formState.changes?.address_notes ||
852
+ addressState.address.address_notes ||
853
+ ''
854
+ }
855
+ multiline
856
+ isFocusHighlight
857
+ style={styles.textAreaStyles}
858
+ returnKeyType="done"
859
+ forwardRef={addressNotesRef}
860
+ blurOnSubmit
861
+ />
862
+ )}
863
+ />
864
+ )}
865
+ </FormInput>
866
+ {!isHideIcons && (
867
+ <IconsContainer>
868
+ {tagsName.map((tag) => (
869
+ <TouchableOpacity
870
+ key={tag.value}
871
+ onPress={() => handleAddressTag(tag.value)}>
872
+ <View
873
+ style={{
874
+ ...styles.iconContainer,
875
+ }}>
876
+ <OIcon
877
+ src={tag.icon}
878
+ width={24}
879
+ color={
880
+ addressTag === tag.value ?
881
+ theme.colors.primary : theme.colors.disabled
882
+ }
883
+ />
884
+ </View>
885
+ </TouchableOpacity>
886
+ ))}
887
+ </IconsContainer>
888
+ )}
889
+ </View>
890
+
891
+ <View>
892
+ {Object.keys(formState?.changes).length > 0 ? (
893
+ <OButton
894
+ text={
895
+ !formState.loading
896
+ ? isEditing ||
897
+ (!auth && orderState.options?.address?.address)
898
+ ? t('UPDATE', 'Update')
899
+ : t('CONTINUE', 'Continue')
900
+ : t('LOADING', 'Loading')
901
+ }
902
+ onClick={handleSubmit(onSubmit)}
903
+ isDisabled={formState.loading}
904
+ style={{ borderRadius: 7.6, shadowOpacity: 0 }}
905
+ showNextIcon
906
+ />
907
+ ) : (
908
+ <OButton
909
+ text={t('CANCEL', 'Cancel')}
910
+ bgColor={theme.colors.secundary}
911
+ borderColor={theme.colors.secundary}
912
+ textStyle={{ color: theme.colors.textNormal }}
913
+ style={{ borderRadius: 7.6, borderWidth: 1, shadowOpacity: 0 }}
914
+ onClick={() => navigation?.canGoBack() && navigation.goBack()}
915
+ />
916
+ )}
917
+ </View>
918
+ <OModal
919
+ open={toggleMap}
920
+ onClose={() => handleToggleMap()}
921
+ entireModal
922
+ customClose>
923
+ {(locationChange || formState.changes?.location) && (
924
+ <GoogleMapContainer>
925
+ <GoogleMap
926
+ location={locationChange || formState.changes?.location}
927
+ handleChangeAddressMap={handleChangeAddress}
928
+ maxLimitLocation={maxLimitLocation}
929
+ saveLocation={saveMapLocation}
930
+ setSaveLocation={setSaveMapLocation}
931
+ handleToggleMap={handleToggleMap}
932
+ isIntGeoCoder
933
+ />
934
+ </GoogleMapContainer>
935
+ )}
936
+ <OButton
937
+ text={t('SAVE', 'Save')}
938
+ imgRightSrc={null}
939
+ style={{ marginHorizontal: 30, marginBottom: 10 }}
940
+ onClick={() => setSaveMapLocation(true)}
941
+ />
942
+ </OModal>
943
+ <Spinner visible={saveMapLocation} />
944
+ </AddressFormContainer>
945
+ </TouchableWithoutFeedback>
946
+ </ScrollView>
947
+ );
911
948
  };
912
949
 
913
950
  export const AddressForm = (props: AddressFormParams) => {
914
- const addressFormProps = {
915
- ...props,
916
- UIComponent: AddressFormUI,
917
- };
918
- return <AddressFormController {...addressFormProps} />;
951
+ const addressFormProps = {
952
+ ...props,
953
+ UIComponent: AddressFormUI,
954
+ };
955
+ return <AddressFormController {...addressFormProps} />;
919
956
  };