DotDev Click and Collect
This package provides a collection React Component which can be used to build a Click and Collect feature.
Internally it uses the @dotdev/reactive-google-map
for the embedded Google Map and miscellaneous Google API's for different geocoding and geolocation purposes.
Install
This package is private and requires access to the @dotdev
organization to install.
yarn add @dotdev/reactive-click-and-collect
Example
An example React Component is available in the EXAMPLE.md
file.
Usage
ClickAndCollect
Class
The ClickAndCollect
class is responsible for initializing the Google API's and state management of all of the components which can be used.
If needed you can safely create multiple instances of the ClickAndCollect
class.
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect({
endpoint: {
locations: "https://clickandcollect.foostore.com/api/locations",
stock: "https://clickandcollect.foostore.com/api/stock",
},
googleMapsApiKey: "...",
googleMapsApiVersion: "...",
formatData: (apiData) => ({ ... }),
});
The endpoint
property defines where the ClickAndCollect
component will go to look for locations and check stock.
The endpoint.locations
provided should accept a POST
request with the following JSON body structure:
{
"position": {
"lat": 999,
"lng": 999,
},
"limit": 100,
"search": "Melbourne, Australia",
"query": {
"variantId": 222,
"inStock": true,
...
}
}
The endpoint will be called whenever the ClickAndCollect
state changes with the latest query information (eg, dragging the map, selecting and Autocomplete address).
To update the Query and more specifically the search
property, you can call the updateQuery()
method on a ClickAndCollect
instance, similar to React's setState()
method.
The endpoint.stock
provided should accept a POST
request with the following JSON body structure:
{
"location": "xxx",
"items": [111, 222],
}
The endpoint can be called with the checkStock(...)
method on a ClickAndCollect
instance, if no location is provided it will try and use the currently selected location.
The endpoint should return the same structure as above, but the items
property should only contain items which are in stock.
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect(...);
clickAndCollect.updateQuery({
search: {
variant: 9999,
},
});
ClickAndCollect.Provider
Component
This component implements the React.Context
API and exposes a Context Provider which expects an instance of ClickAndCollect
as a prop, other components provided by this package must be wrapped by the ClickAndCollect.Provider
component in order to maintain a consistent and stable state.
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect(...);
const jsx = (
<ClickAndCollect.Provider
clickAndCollect={clickAndCollect}
>
<ClickAndCollect.Map ... />
<ClickAndCollect.List ... />
<ClickAndCollect.Search ... />
</ClickAndCollect.Provider>
)
ClickAndCollect.Map
Component
This component extends the GoogleMap
component from @dotdev/reactive-google-map
and will populate some of the props based on whats provided to the ClickAndCollect
class.
The props which are populated include:
googleMapsApiVersion
googleMapsApiKey
callback
mapOnClick
mapOnBoundsChange
markersOnClick
infowindowMaxWidth
infowindowOnClose
markers
You can override these props by providing your own, although it may be dangerous and cause unexpected behaviour.
Only one ClickAndCollect.Map
component can be used per ClickAndCollect instance.
Implementation
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect(...);
const jsx = (
<ClickAndCollect.Provider
clickAndCollect={clickAndCollect}
>
<ClickAndCollect.Map
style={{
width: "500px",
height: "500px",
}}
googleMapsOptions={{
center: {
lat: -37.8836542,
lng: 145.0140682,
},
zoom: 12,
maxZoom: 14,
zoomControl: true,
mapTypeControl: false,
scaleControl: false,
streetViewControl: false,
rotateControl: false,
fullscreenControl: false,
}}
/>
</ClickAndCollect.Provider>
)
ClickAndCollect.Search
Component
This component extends a simple HTMLInputElement
and updates the search
text value used by ClickAndCollect to query for results.
Optionally, if the autocomplete
prop is set to true, this component will extend the GoogleMapAutocomplete
component from @dotdev/reactive-google-map
and populate some of the props based on whats provided to the ClickAndCollect
class.
The props which are populated include:
googleMapsApiVersion
googleMapsApiKey
callback
onSelect
You can override these props by providing your own, although it may be dangerous and cause unexpected behaviour.
Only one ClickAndCollect.Search
component can be used per ClickAndCollect instance.
Implementation
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect(...);
const jsx = (
<ClickAndCollect.Provider
clickAndCollect={clickAndCollect}
>
<ClickAndCollect.Search
style={{
width: "400px",
}}
autocomplete={true}
/>
</ClickAndCollect.Provider>
)
ClickAndCollect.Geolocate
Component
This component implements the Geocoder
utility provided by @dotdev/reactive-google-map
.
When you click this component it will attempt to reverse geocode the users Postal Code with the Geolocation Web API, it expects a function to be provided as it's children
prop and exposes a loading
argument which can be used to determine if geolocation is in progress.
Implementation
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect(...);
const jsx = (
<ClickAndCollect.Provider
clickAndCollect={clickAndCollect}
>
<ClickAndCollect.Geolocate
style={{
width: "400px",
}}
>
{(loading) => (
<span>{loading ? "Locating..." : "Geolocate!"}</span>
)}
</ClickAndCollect.Geolocate>
</ClickAndCollect.Provider>
)
ClickAndCollect.List
Component
This component exposes a simple child-iterator to render out a list of the available locations.
Implementation
import { ClickAndCollect } from "@dotdev/reactive-click-and-collect";
const clickAndCollect = new ClickAndCollect(...);
const jsx = (
<ClickAndCollect.Provider
clickAndCollect={clickAndCollect}
>
<ul>
<ClickAndCollect.List>
{(marker, selected) => (
<li key={marker.id}>
<span>Marker {marker.id}</span><br />
<span onClick={() => clickAndCollect.selectMarker(marker)}>Select</span><br />
<a href={Geocoder.latLngToDirections(marker.position)} target="_blank">Directions</a>
</li>
)}
</ClickAndCollect.List>
</ul>
</ClickAndCollect.Provider>
)
Development
Git management follows the standard Git Flow ideology.
Package for usage:
yarn run package
Package during development, with rebuild on file change:
yarn run package --watch
Lint before commiting:
yarn run lint
Generate reference documentation:
yarn run docs