mirror of
https://github.com/twirl/The-API-Book.git
synced 2025-05-13 21:26:26 +02:00
172 lines
4.2 KiB
JavaScript
172 lines
4.2 KiB
JavaScript
/**
|
|
* @fileoverview
|
|
* In this example, we replace the standard offer list
|
|
* with an alternative implementation that shows offers
|
|
* as markers on a map
|
|
*/
|
|
const {
|
|
SearchBox,
|
|
SearchBoxComposer,
|
|
DummyMapApi,
|
|
dummyCoffeeApi,
|
|
util
|
|
} = ourCoffeeSdk;
|
|
|
|
/**
|
|
* A custom offer list component that
|
|
* renders data on the map instead of a static
|
|
* list. This class implements the `IOfferListComponent`
|
|
* interface from scratch.
|
|
*/
|
|
class CustomOfferList {
|
|
constructor(context, container, offerList) {
|
|
this.context = context;
|
|
this.container = container;
|
|
this.events = new util.EventEmitter();
|
|
this.offerList = null;
|
|
this.map = null;
|
|
|
|
/**
|
|
* We listen to the map events (marker selection)
|
|
* and translate it as an offer selection event.
|
|
* This is the requirement from the `IOfferListComponent`
|
|
* interface
|
|
*/
|
|
this.onMarkerClick = (markerId) => {
|
|
this.events.emit("offerSelect", {
|
|
offerId: markerId
|
|
});
|
|
};
|
|
/**
|
|
* We are free to implement the business logic in
|
|
* any that suits our needs
|
|
*/
|
|
this.setOfferList = ({ offerList: newOfferList }) => {
|
|
if (this.map) {
|
|
this.map.destroy();
|
|
this.map = null;
|
|
}
|
|
this.offerList = newOfferList;
|
|
if (newOfferList) {
|
|
// We're displaying data on a map (a dummy one),
|
|
// using the additional data we pass through the
|
|
// customized composer (see below)
|
|
this.map = new DummyMapApi(this.container, [
|
|
[16.355, 48.2],
|
|
[16.375, 48.214]
|
|
]);
|
|
for (const offer of newOfferList) {
|
|
this.map.addMarker(
|
|
offer.offerId,
|
|
offer.location,
|
|
this.onMarkerClick
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.setOfferList({ offerList });
|
|
this.contextListeners = [
|
|
context.events.on(
|
|
"offerPreviewListChange",
|
|
this.setOfferList
|
|
),
|
|
// We listen to the
|
|
// 'offerFullViewToggle' event on
|
|
// the parent composer context
|
|
// to select or deselect the corresponding
|
|
// marker.
|
|
//
|
|
// Note the important pattern:
|
|
// when the marker is clicked, we DO NOT
|
|
// mark it as selected, but only emit an
|
|
// event. This is because the offer list
|
|
// does not own the logic of selecting
|
|
// offers.
|
|
// It is the composer's responsibility
|
|
// to decide, whether this event should
|
|
// result in opening a panel or not
|
|
context.events.on(
|
|
"offerFullViewToggle",
|
|
({ offer }) => {
|
|
this.map.selectSingleMarker(
|
|
offer && offer.offerId
|
|
);
|
|
}
|
|
)
|
|
];
|
|
}
|
|
|
|
/**
|
|
* As required in the `IOfferListComponent` interface
|
|
*/
|
|
destroy() {
|
|
if (this.map) {
|
|
this.map.destroy();
|
|
}
|
|
for (const listener of this.contextListeners) {
|
|
listener.off();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* We need to subclass a standard `SearchBoxComposer`
|
|
* to achieve to important goals:
|
|
* * Use the custom offer list we created instead
|
|
* of the standard component
|
|
* * Enrich the preview data with the geographical
|
|
* coordinates of the coffee shop
|
|
*/
|
|
class CustomComposer extends SearchBoxComposer {
|
|
buildOfferListComponent(
|
|
context,
|
|
container,
|
|
offerList,
|
|
contextOptions
|
|
) {
|
|
return new CustomOfferList(
|
|
context,
|
|
container,
|
|
this.generateOfferPreviews(offerList, contextOptions),
|
|
this.generateOfferListComponentOptions(contextOptions)
|
|
);
|
|
}
|
|
|
|
generateOfferPreviews(offerList) {
|
|
const result = super.generateOfferPreviews(offerList);
|
|
return result === null
|
|
? result
|
|
: result.map((preview, index) => ({
|
|
...preview,
|
|
location: offerList[index].place.location
|
|
}));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* We're subclassing `SearchBox` to use our
|
|
* enhanced composer
|
|
*/
|
|
class CustomSearchBox extends SearchBox {
|
|
buildComposer(context, container, options) {
|
|
return new CustomComposer(context, container, options);
|
|
}
|
|
|
|
createOrder(offer) {
|
|
alert(`Isn't actually implemented (yet)`);
|
|
return super.createOrder(offer);
|
|
}
|
|
}
|
|
|
|
const searchBox = new CustomSearchBox(
|
|
document.getElementById("search-box"),
|
|
dummyCoffeeApi,
|
|
{
|
|
offerPanel: {
|
|
transparent: true
|
|
}
|
|
}
|
|
);
|
|
searchBox.search("Lungo");
|