Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 100 additions & 1 deletion js/app/components/AddressAutosuggest.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { withTranslation, useTranslation } from 'react-i18next'
import _ from 'lodash'
import axios from 'axios'
import classNames from 'classnames'
import { OpenLocationCode } from 'open-location-code'

import '../i18n'
import { getCountry, localeDetector } from '../i18n'
Expand Down Expand Up @@ -111,9 +112,32 @@ const adapters = {
geocode: geocodeGOOG,
configure: configureGOOG,
onSuggestionSelected: onSuggestionSelectedGOOG,
}
}

const openLocationCode = new OpenLocationCode()

// Lazy compute coordinates
// Needed to avoid func exec before DOM is ready
const coordinates = {
get value() {
delete this.value
const element = document.getElementById('cpccl_settings')
if (!element) return (this.value = [0, 0])

try {
const [lat, lng] = JSON.parse(element.dataset.latlng)
.split(',')
.map(s => parseFloat(s.trim()))
return (this.value = [lat, lng])
} catch {
return (this.value = [0, 0])
}
},
}



// WARNING
// Do *NOT* use arrow functions, to allow binding
const generic = {
Expand Down Expand Up @@ -299,6 +323,14 @@ const localize = (func, adapter, thisArg) => {
const getSuggestionValue = suggestion => suggestion.value

const renderSuggestion = suggestion => {
if (suggestion.type === 'plus_code') {
return (
<div>
<i className="fa fa-map-marker mr-2" aria-hidden="true"></i>
{suggestion.value}
</div>
)
}
const parts = [suggestion.value]

if (suggestion.type === 'address') {
Expand Down Expand Up @@ -411,6 +443,23 @@ class AddressAutosuggest extends Component {
return
}

// Check if the input is a plus code - takes priority over all adapters
const plusCodeMatch = value.match(/\b[23456789CFGHJMPQRVWX]{2,8}\+[23456789CFGHJMPQRVWX]{2,4}\b/i)
if (plusCodeMatch) {
this.setState({
suggestions: [{
title: 'Plus code',
suggestions: [{
type: 'plus_code',
value: plusCodeMatch[0].toUpperCase(),
index: 0,
}],
}],
multiSection: true,
})
return
}

if (value.trimStart().length < 5) {
this.onSuggestionsFetchRequestedThrottled({ value })
} else {
Expand All @@ -420,7 +469,6 @@ class AddressAutosuggest extends Component {

// Localized methods
this.getInitialState = localize('getInitialState', adapter, this)
this.onSuggestionSelected = localize('onSuggestionSelected', adapter, this)
this.transformSuggestion = localize('transformSuggestion', adapter, this)
this.placeholder = localize('placeholder', adapter, this)
this.poweredBy = localize('poweredBy', adapter, this)
Expand All @@ -437,6 +485,57 @@ class AddressAutosuggest extends Component {
this.handleKeyDown = this.handleKeyDown.bind(this)

this.state = this.getInitialState()


this.onSuggestionSelected = localize('onSuggestionSelected', adapter, this)
const originalOnSuggestionSelected = this.onSuggestionSelected.bind(this)
this.onSuggestionSelected = (event, { suggestion }) => {
if (suggestion.type === 'plus_code') {
if (!openLocationCode.isValid(suggestion.value)) {
// Handle invalid plus code
if (this.props.reportValidity) {
this.autosuggest.input.setCustomValidity(
this.props.t('INVALID_PLUS_CODE'),
)
if (HTMLInputElement.prototype.reportValidity) {
this.autosuggest.input.reportValidity()
}
}
return
}

// Decode the plus code to get coordinates
const [cc_lat, cc_long] = coordinates.value
const { latitudeCenter: latitude, longitudeCenter: longitude } =
openLocationCode.decode(
openLocationCode.recoverNearest(
suggestion.value, cc_lat, cc_long
)
)

// Create address object with decoded coordinates
const address = {
streetAddress: suggestion.value,
latitude,
longitude,
geo: { latitude, longitude },
geohash: ngeohash.encode(latitude, longitude, 11),
isPrecise: true,
needsGeocoding: false,
provider: 'PLUS_CODE',
}

this.props.onAddressSelected(
this.state.value,
address,
suggestion.type,
)
return
}

// Call the original adapter-specific or generic onSuggestionSelected
originalOnSuggestionSelected(event, { suggestion })
}
}

componentDidMount() {
Expand Down
4 changes: 2 additions & 2 deletions js/app/foodtech/dashboard/components/Timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ export default withTranslation()(({ order, t }) => {
<ul className="list-unstyled">
<li>{order.shippingAddress.streetAddress}</li>
</ul>
{order.shippingAddress.provider === 'MAP_PICKER' && (
{order.shippingAddress?.provider !== null && (
<span className="text-info small" style={{ display: 'block', marginTop: '3px' }}>
<i className="fa fa-map-marker" aria-hidden="true" style={{ marginRight: '5px' }}></i>
{t('CART_SHIPPING_ADDRESS_MAP_PICKED')}
{t(`CART_SHIPPING_ADDRESS_${order.shippingAddress.provider}`)}
</span>
)}
{order.shippingAddress.description && (
Expand Down
3 changes: 2 additions & 1 deletion js/app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,8 @@
"PRICING_RULE_PICKER_VEHICLE_CARGO_BIKE": "Cargo Bike",
"PRICING_RULE_PICKER_UNIT_KM": "km",
"PRICING_RULE_PICKER_UNIT_KG": "kg",
"CART_SHIPPING_ADDRESS_MAP_PICKED": "Address selected via the map",
"CART_SHIPPING_ADDRESS_MAP_PICKER": "Address selected via the map",
"CART_SHIPPING_ADDRESS_PLUS_CODE": "Address selected via the plus code",
"ADDRESS_AUTOSUGGEST_MAP_PICKER_LABEL": "Cannot find your address?",
"SELECT_YOUR_LOCATION": "Select your location",
"CONFIRM_LOCATION": "Confirm location",
Expand Down
3 changes: 2 additions & 1 deletion js/app/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,8 @@
"PRICING_RULE_PICKER_UNIT_KG": "kg",
"DELIVERY_FORM_KEEP_ORIGINAL_PRICE": "Mantener precio original",
"DELIVERY_FORM_APPLY_NEW_PRICE": "Aplicar nuevo precio",
"CART_SHIPPING_ADDRESS_MAP_PICKED": "Dirección seleccionada en el mapa",
"CART_SHIPPING_ADDRESS_MAP_PICKER": "Dirección seleccionada en el mapa",
"CART_SHIPPING_ADDRESS_PLUS_CODE": "Dirección seleccionada con el plus code",
"ADDRESS_AUTOSUGGEST_MAP_PICKER_LABEL": "¿No encuentra su dirección?",
"SELECT_YOUR_LOCATION": "Selecciona tu ubicación",
"CONFIRM_LOCATION": "Confirmar ubicación",
Expand Down
3 changes: 2 additions & 1 deletion js/app/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,8 @@
"PRICING_RULE_PICKER_UNIT_KG": "kg",
"DELIVERY_FORM_KEEP_ORIGINAL_PRICE": "Conserver le prix d'origine",
"DELIVERY_FORM_APPLY_NEW_PRICE": "Appliquer le nouveau prix",
"CART_SHIPPING_ADDRESS_MAP_PICKED": "Adresse sélectionnée sur la carte",
"CART_SHIPPING_ADDRESS_MAP_PICKER": "Adresse sélectionnée sur la carte",
"CART_SHIPPING_ADDRESS_PLUS_CODE": "Adresse sélectionnée via le plus code",
"ADDRESS_AUTOSUGGEST_MAP_PICKER_LABEL": "Vous ne trouvez pas votre adresse ?",
"SELECT_YOUR_LOCATION": "Sélectionnez votre position",
"CONFIRM_LOCATION": "Confirmer la position",
Expand Down
4 changes: 2 additions & 2 deletions js/app/restaurant/components/Order/FulfillmentMethod.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ export default function FulfillmentMethod({
<span data-testid="cart.shippingAddress">
{shippingAddress?.streetAddress}
</span>
{shippingAddress?.provider === 'MAP_PICKER' && (
{shippingAddress?.provider !== null && (
<span className="text-info small" style={{ display: 'block', marginTop: '3px' }}>
<i className="fa fa-map-marker" aria-hidden="true" style={{ marginRight: '5px' }}></i>
{t('CART_SHIPPING_ADDRESS_MAP_PICKED')}
{t(`CART_SHIPPING_ADDRESS_${shippingAddress?.provider}`)}
</span>
)}
</React.Fragment>
Expand Down
11 changes: 10 additions & 1 deletion js/app/restaurant/redux/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,15 @@ function geocodeAndSync() {
return
}

if (cart.shippingAddress?.provider !== null) {
dispatch(changeAddress({
...cart.shippingAddress,
isPrecise: true,
}))

return
}

dispatch(fetchRequest())

geocode(cart.shippingAddress.streetAddress).then(address => {
Expand Down Expand Up @@ -419,7 +428,7 @@ export function changeAddress(address) {
restaurant
} = getState()

if (address.isPrecise || address.provider === 'MAP_PICKER') {
if (address.isPrecise || address?.provider !== null) {

// Change field value immediately
dispatch(setStreetAddress(address.streetAddress))
Expand Down
6 changes: 2 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"form-data": "^2.3.3",
"google-libphonenumber": "^3.2.40",
"lodash": "^4.17.21",
"open-location-code": "^1.0.3",
"promise": "^8.3.0",
"react-leaflet": "^4.2.1",
"whatwg-fetch": "^2.0.4"
Expand Down Expand Up @@ -140,7 +141,6 @@
"ngeohash": "^0.6.3",
"numbro": "^2.3.6",
"object-hash": "^2.2.0",
"open-location-code": "^1.0.3",
"papaparse": "^5.5.3",
"payment-icons": "^1.2.1",
"postcss-loader": "^8.0.0",
Expand Down
4 changes: 3 additions & 1 deletion src/Entity/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ class Address extends BaseAddress
{

const PROVIDER_MAPPICKER = 'MAP_PICKER';
const PROVIDER_PLUS_CODE = 'PLUS_CODE';
const PROVIDERS = [
self::PROVIDER_MAPPICKER
self::PROVIDER_MAPPICKER,
self::PROVIDER_PLUS_CODE
];

/**
Expand Down
17 changes: 17 additions & 0 deletions src/Form/Checkout/CheckoutAddressType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace AppBundle\Form\Checkout;

use AppBundle\Entity\Address;
use AppBundle\Entity\Nonprofit;
use AppBundle\Entity\Sylius\Order;
use AppBundle\Form\AddressType;
Expand Down Expand Up @@ -63,9 +64,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
$builder->get('shippingAddress')->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {

$form = $event->getForm();
$data = $event->getData();

// Disable shippingAddress.streetAddress
$this->disableChildForm($form, 'streetAddress');

if ($data instanceof Address && $data->getProvider() === Address::PROVIDER_PLUS_CODE) {
$this->setAddressDescriptionRequired($form, 'description');
}
});

$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
Expand Down Expand Up @@ -230,6 +236,17 @@ private function disableChildForm(FormInterface $form, $name)
$form->add($name, get_class($config->getType()->getInnerType()), $options);
}

private function setAddressDescriptionRequired(FormInterface $form, $name)
{
$child = $form->get($name);

$config = $child->getConfig();
$options = $config->getOptions();
$options['required'] = true;

$form->add($name, get_class($config->getType()->getInnerType()), $options);
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
Expand Down
Loading