2023-08-14 17:41:39 +03:00
|
|
|
/**
|
|
|
|
* @fileoverview
|
|
|
|
* In this example, we change the composition logic:
|
|
|
|
* there is no “offer full view” (panel) component, only
|
|
|
|
* a offer list with additional actions
|
|
|
|
*/
|
2023-08-04 10:49:50 +03:00
|
|
|
const {
|
|
|
|
SearchBox,
|
|
|
|
SearchBoxComposer,
|
|
|
|
OfferListComponent,
|
|
|
|
dummyCoffeeApi,
|
|
|
|
util
|
|
|
|
} = ourCoffeeSdk;
|
|
|
|
|
2023-08-14 17:41:39 +03:00
|
|
|
/**
|
|
|
|
* A customized version of the standard `OfferListComponent`.
|
|
|
|
* As we're okay with its logic, we reuse it with two modifications:
|
|
|
|
* * List items could be expanded (and then collapsed back)
|
|
|
|
* * List items contain the 'Place an order' button
|
|
|
|
*/
|
2023-08-04 10:49:50 +03:00
|
|
|
class CustomOfferList extends OfferListComponent {
|
|
|
|
constructor(context, container, offerList, options) {
|
2023-08-01 01:25:30 +03:00
|
|
|
super(context, container, offerList, options);
|
2023-08-14 17:41:39 +03:00
|
|
|
/**
|
|
|
|
* This is a custom DOM event listener to make
|
|
|
|
* other than selecting an offer actions on the item
|
|
|
|
* click event. This is the shortcut we took (see
|
|
|
|
* the explanations in the `OfferPanelComponent.ts`
|
|
|
|
* file).
|
|
|
|
*/
|
2023-08-04 10:49:50 +03:00
|
|
|
this.onClickListener = (e) => {
|
|
|
|
const { target, value: action } = util.findDataField(
|
|
|
|
e.target,
|
|
|
|
"action"
|
|
|
|
);
|
|
|
|
if (target === null || action === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const { target: container, value: offerId } =
|
|
|
|
util.findDataField(target, "offerId");
|
|
|
|
if (container === null || offerId === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (action) {
|
|
|
|
case "expand":
|
|
|
|
this.expand(container);
|
|
|
|
break;
|
|
|
|
case "collapse":
|
|
|
|
this.collapse(container);
|
|
|
|
break;
|
|
|
|
case "createOrder":
|
2023-08-14 17:41:39 +03:00
|
|
|
this.events.emit("createOrder", { offerId });
|
2023-08-04 10:49:50 +03:00
|
|
|
break;
|
2023-07-30 23:04:39 +03:00
|
|
|
}
|
|
|
|
};
|
2023-08-01 01:25:30 +03:00
|
|
|
}
|
2023-07-30 23:04:39 +03:00
|
|
|
|
2023-08-04 10:49:50 +03:00
|
|
|
expand(item) {
|
|
|
|
item.classList.add("expanded");
|
2023-08-01 01:25:30 +03:00
|
|
|
}
|
|
|
|
|
2023-08-04 10:49:50 +03:00
|
|
|
collapse(item) {
|
|
|
|
item.classList.remove("expanded");
|
2023-07-30 23:04:39 +03:00
|
|
|
}
|
|
|
|
|
2023-08-14 17:41:39 +03:00
|
|
|
/**
|
|
|
|
* This is a redefined function that returns
|
|
|
|
* the offer “preview” markup in the list
|
|
|
|
*/
|
2023-08-04 10:49:50 +03:00
|
|
|
generateOfferHtml(offer) {
|
|
|
|
return util.html`<li
|
|
|
|
class="custom-offer"
|
|
|
|
data-offer-id="${util.attrValue(offer.offerId)}"
|
|
|
|
>
|
|
|
|
<button data-action="expand" class="preview"><aside class="expand-action">></aside><strong>${
|
|
|
|
offer.title
|
|
|
|
}</strong> · ${offer.price.formattedValue}</button>
|
|
|
|
<div class="fullview">
|
|
|
|
<button data-action="collapse" class="collapse-action">∧</button>
|
|
|
|
<div><strong>${offer.title}</strong> · ${
|
|
|
|
offer.price.formattedValue
|
|
|
|
}</div>
|
|
|
|
<div>${offer.subtitle}</div>
|
|
|
|
<div>${offer.bottomLine}</div>
|
|
|
|
<button data-action="createOrder" class="action-button">Place an Order</button>
|
|
|
|
</div>
|
|
|
|
</li>`.toString();
|
2023-07-30 23:04:39 +03:00
|
|
|
}
|
|
|
|
}
|
2023-07-30 15:25:21 +03:00
|
|
|
|
2023-08-14 17:41:39 +03:00
|
|
|
/**
|
|
|
|
* This is a custom implementation of the
|
|
|
|
* `ISearchBoxComposer` interface from scratch.
|
|
|
|
* As there is no offer panel in this particular
|
|
|
|
* UI, we don't need all the associated logic,
|
|
|
|
* so we replace the standard implementation
|
|
|
|
* with this new one. However, we re-use the
|
|
|
|
* implementation of the offer list subcomponent
|
|
|
|
*/
|
|
|
|
class CustomComposer {
|
|
|
|
constructor(searchBox, container) {
|
|
|
|
this.events = new util.EventEmitter();
|
|
|
|
this.offerList = null;
|
|
|
|
this.container = container;
|
|
|
|
// This is our enhanced offer list
|
|
|
|
this.offerList = new CustomOfferList(
|
|
|
|
this,
|
2023-07-30 23:04:39 +03:00
|
|
|
container,
|
2023-08-14 17:41:39 +03:00
|
|
|
this.offerList
|
2023-07-30 23:04:39 +03:00
|
|
|
);
|
2023-08-14 17:41:39 +03:00
|
|
|
this.eventDisposers = [
|
|
|
|
searchBox.events.on(
|
|
|
|
"offerListChange",
|
|
|
|
({ offerList }) => this.onOfferListChange(offerList)
|
|
|
|
),
|
|
|
|
// What we need is to listen to an additional event
|
|
|
|
// the custom offer list emits, and convert it into
|
|
|
|
// the order creation request
|
|
|
|
this.offerList.events.on(
|
|
|
|
"createOrder",
|
|
|
|
({ offerId }) => {
|
|
|
|
const offer = this.findOfferById(offerId);
|
|
|
|
if (offer) {
|
|
|
|
this.events.emit("createOrder", {
|
|
|
|
offer
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* This is the `ISearchBoxComposer` interface
|
|
|
|
* method we must implement
|
|
|
|
*/
|
|
|
|
findOfferById(refOfferId) {
|
|
|
|
return this.offerList
|
|
|
|
? this.offerList.find(
|
|
|
|
({ offerId }) => offerId == refOfferId
|
|
|
|
)
|
|
|
|
: null;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* This is the `ISearchBoxComposer` interface
|
|
|
|
* method we must implement
|
|
|
|
*/
|
|
|
|
destroy() {
|
|
|
|
for (const disposer of this.eventDisposers) {
|
|
|
|
disposer.off();
|
|
|
|
}
|
|
|
|
this.offerList.destroy();
|
|
|
|
}
|
|
|
|
onOfferListChange(offerList) {
|
|
|
|
this.offerList = offerList;
|
|
|
|
this.events.emit("offerPreviewListChange", {
|
|
|
|
// This is our custom offer preview generator
|
|
|
|
// function. As we don't plan to customize
|
|
|
|
// it further, we don't bother with exposing
|
|
|
|
// overridable methods, etc.
|
|
|
|
offerList:
|
|
|
|
offerList !== null
|
|
|
|
? offerList.map((offer) => ({
|
|
|
|
offerId: offer.offerId,
|
|
|
|
title: offer.place.title,
|
|
|
|
subtitle: offer.description,
|
|
|
|
bottomLine:
|
|
|
|
SearchBoxComposer.generateOfferBottomLine(
|
|
|
|
offer
|
|
|
|
),
|
|
|
|
price: offer.price
|
|
|
|
}))
|
|
|
|
: null
|
|
|
|
});
|
2023-07-30 23:04:39 +03:00
|
|
|
}
|
2023-07-30 15:25:21 +03:00
|
|
|
}
|
|
|
|
|
2023-08-14 17:41:39 +03:00
|
|
|
/**
|
|
|
|
* We're subclassing `SearchBox` to use our
|
|
|
|
* custom composer
|
|
|
|
*/
|
2023-08-04 10:49:50 +03:00
|
|
|
class CustomSearchBox extends SearchBox {
|
2023-07-30 15:25:21 +03:00
|
|
|
buildComposer(context, container, options) {
|
2023-08-04 10:49:50 +03:00
|
|
|
return new CustomComposer(context, container, options);
|
2023-07-30 15:25:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
createOrder(offer) {
|
|
|
|
alert(`Isn't actually implemented (yet)`);
|
|
|
|
return super.createOrder(offer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const searchBox = new CustomSearchBox(
|
|
|
|
document.getElementById("search-box"),
|
2023-08-04 10:49:50 +03:00
|
|
|
dummyCoffeeApi
|
2023-07-30 15:25:21 +03:00
|
|
|
);
|
|
|
|
searchBox.search("Lungo");
|