1
0
mirror of https://github.com/twirl/The-API-Book.git synced 2025-06-30 22:43:38 +02:00

Further dive into decomposing

This commit is contained in:
Sergey Konstantinov
2023-07-30 23:04:39 +03:00
parent c1358cb70b
commit c35d5ae61d
18 changed files with 621 additions and 207 deletions

View File

@ -0,0 +1,12 @@
class CustomSearchBox extends ourCoffeeSdk.SearchBox {
createOrder(offer) {
alert(`Isn't actually implemented (yet)`);
return super.createOrder(offer);
}
}
const searchBox = new CustomSearchBox(
document.getElementById("search-box"),
ourCoffeeSdk.dummyCoffeeApi
);
searchBox.search("Lungo");

View File

@ -1,4 +1,56 @@
const buildCustomOrderButton = function (
offer,
container
) {
return ourCoffeeSdk.OfferPanelComponent.buildCreateOrderButton(
offer,
container,
{
createOrderButtonUrl:
offer && offer.createOrderButtonIcon,
createOrderButtonText:
(offer &&
`Buy now for just ${offer.price.formattedValue}`) ||
"Place an Order"
}
);
};
class CustomComposer extends ourCoffeeSdk.SearchBoxComposer {
generateOfferPreviews(offerList) {
const result = super.generateOfferPreviews(
offerList
);
return result === null
? result
: result.map((preview, index) => ({
...preview,
imageUrl: offerList[index].place.icon
}));
}
generateCurrentOfferFullView(offer, options) {
return offer === null
? offer
: {
...super.generateCurrentOfferFullView(
offer,
options
),
createOrderButtonIcon: offer.place.icon
};
}
}
class CustomSearchBox extends ourCoffeeSdk.SearchBox {
buildComposer(context, container, options) {
return new CustomComposer(
context,
container,
options
);
}
createOrder(offer) {
alert(`Isn't actually implemented (yet)`);
return super.createOrder(offer);
@ -7,6 +59,16 @@ class CustomSearchBox extends ourCoffeeSdk.SearchBox {
const searchBox = new CustomSearchBox(
document.getElementById("search-box"),
ourCoffeeSdk.dummyCoffeeApi
ourCoffeeSdk.dummyCoffeeApi,
{
offerPanel: {
buttonBuilders: [
buildCustomOrderButton,
ourCoffeeSdk.OfferPanelComponent
.buildCloseButton
],
closeButtonText: "❌Not Now"
}
}
);
searchBox.search("Lungo");

View File

@ -1,22 +1,78 @@
const buildCustomOrderButton = function (
offer,
container
) {
return ourCoffeeSdk.OfferPanelComponent.buildCreateOrderButton(
offer,
container,
{
createOrderButtonUrl:
offer && offer.createOrderButtonIcon,
createOrderButtonText:
(offer &&
`Buy now for just ${offer.price.formattedValue}`) ||
"Place an Order"
class CustomOfferList {
constructor(context, container, offerList) {
this.context = context;
this.container = container;
this.events =
new ourCoffeeSdk.util.EventEmitter();
this.offerList = null;
this.map = null;
this.onMarkerSelect = (markerId) => {
this.events.emit("offerSelect", {
offerId: markerId
});
};
this.setOfferList = ({
offerList: newOfferList
}) => {
if (this.map) {
this.map.destroy();
this.map = null;
}
this.offerList = newOfferList;
if (newOfferList) {
this.map = new ourCoffeeSdk.DummyMapApi(
this.container,
[
[16.355, 48.206],
[16.375, 48.214]
]
);
for (const offer of newOfferList) {
this.map.addMarker(
offer.offerId,
offer.location,
this.onMarkerSelect
);
}
}
};
this.setOfferList({ offerList });
this.contextListener = context.events.on(
"offerPreviewListChange",
this.setOfferList
);
}
destroy() {
if (this.map) {
this.map.destroy();
}
);
};
this.contextListener.off();
}
}
class CustomComposer extends ourCoffeeSdk.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
@ -25,21 +81,10 @@ class CustomComposer extends ourCoffeeSdk.SearchBoxComposer {
? result
: result.map((preview, index) => ({
...preview,
imageUrl: offerList[index].place.icon
location:
offerList[index].place.location
}));
}
generateCurrentOfferFullView(offer, options) {
return offer === null
? offer
: {
...super.generateCurrentOfferFullView(
offer,
options
),
createOrderButtonIcon: offer.place.icon
};
}
}
class CustomSearchBox extends ourCoffeeSdk.SearchBox {
@ -59,16 +104,6 @@ class CustomSearchBox extends ourCoffeeSdk.SearchBox {
const searchBox = new CustomSearchBox(
document.getElementById("search-box"),
ourCoffeeSdk.dummyCoffeeApi,
{
offerPanel: {
buttonBuilders: [
buildCustomOrderButton,
ourCoffeeSdk.OfferPanelComponent
.buildCloseButton
],
closeButtonText: "❌Not Now"
}
}
ourCoffeeSdk.dummyCoffeeApi
);
searchBox.search("Lungo");

View File

@ -1,55 +1,75 @@
class CustomOfferList {
constructor(context, container, offerList) {
this.context = context;
this.container = container;
this.events =
new ourCoffeeSdk.util.EventEmitter();
this.offerList = null;
this.map = null;
this.onMarkerSelect = (markerId) => {
this.events.emit("offerSelect", {
offerId: markerId
});
};
this.setOfferList = ({
offerList: newOfferList
}) => {
if (this.map) {
this.map.destroy();
this.map = null;
}
this.offerList = newOfferList;
if (newOfferList) {
this.map = new ourCoffeeSdk.DummyMapApi(
this.container,
[
[16.355, 48.206],
[16.375, 48.214]
]
);
for (const offer of newOfferList) {
this.map.addMarker(
offer.offerId,
offer.location,
this.onMarkerSelect
class CustomOfferList extends ourCoffeeSdk.OfferListComponent {
constructor(
context,
container,
offerList,
options
) {
super(context, container, offerList, options);
this.onOfferButtonClickListener = (e) => {
const action = e.target.dataset.action;
const offerId = e.target.dataset.offerId;
if (action === "offerSelect") {
this.events.emit(action, { offerId });
} else if (action === "createOffer") {
const offer =
this.context.findOfferById(offerId);
if (offer) {
this.context.events.emit(
"createOrder",
{
offer
}
);
}
}
};
this.setOfferList({ offerList });
this.contextListener = context.events.on(
"offerPreviewListChange",
this.setOfferList
);
}
destroy() {
if (this.map) {
this.map.destroy();
generateOfferHtml(offer) {
return ourCoffeeSdk.util.html`<li
class="custom-offer"
>
<aside><button
data-offer-id="${ourCoffeeSdk.util.attrValue(
offer.offerId
)}"
data-action="createOffer">Buy now for ${
offer.price.formattedValue
}</button><button
data-offer-id="${ourCoffeeSdk.util.attrValue(
offer.offerId
)}"
data-action="offerSelect">View details
</button></aside>
<div><strong>${offer.title}</strong></div>
<div>${offer.subtitle}</div>
<div>${offer.bottomLine}</div>
</li>`.toString();
}
setupDomListeners() {
const buttons =
this.container.querySelectorAll("button");
for (const button of buttons) {
button.addEventListener(
"click",
this.onOfferButtonClickListener
);
}
}
teardownDomListeners() {
const buttons = document.querySelectorAll(
this.container,
"button"
);
for (const button of buttons) {
button.removeEventListener(
"click",
this.onOfferButtonClickListener
);
}
this.contextListener.off();
}
}
@ -72,19 +92,6 @@ class CustomComposer extends ourCoffeeSdk.SearchBoxComposer {
)
);
}
generateOfferPreviews(offerList) {
const result = super.generateOfferPreviews(
offerList
);
return result === null
? result
: result.map((preview, index) => ({
...preview,
location:
offerList[index].place.location
}));
}
}
class CustomSearchBox extends ourCoffeeSdk.SearchBox {

View File

@ -1,102 +1,82 @@
class CustomOfferList extends ourCoffeeSdk.OfferListComponent {
constructor(
context,
container,
offerList,
options
) {
super(context, container, offerList, options);
this.onOfferButtonClickListener = (e) => {
const action = e.target.dataset.action;
const offerId = e.target.dataset.offerId;
if (action === "offerSelect") {
this.events.emit(action, { offerId });
} else if (action === "createOffer") {
const offer =
this.context.findOfferById(offerId);
if (offer) {
this.context.events.emit(
"createOrder",
{
offer
}
);
}
}
};
}
const {
SearchBox,
SearchBoxComposer,
OfferPanelComponent,
OfferPanelButton,
util,
dummyCoffeeApi
} = ourCoffeeSdk;
generateOfferHtml(offer) {
return ourCoffeeSdk.util.html`<li
class="custom-offer"
>
<div><strong>${offer.title}</strong></div>
<div>${offer.subtitle}</div>
<div>${offer.bottomLine} <button
data-offer-id="${ourCoffeeSdk.util.attrValue(
offer.offerId
)}"
data-action="createOffer"
>Buy now for ${
offer.price.formattedValue
}</button><button
data-offer-id="${ourCoffeeSdk.util.attrValue(
offer.offerId
)}"
data-action="offerSelect"
>View details</button>
</div>
<hr/>
</li>`.toString();
}
const buildCallButton = function (
offer,
container,
options
) {
return new OfferPanelButton("call", container, {
text: util.html`<a href="tel:${util.attrValue(
offer.phone
)}" style="color: inherit; text-decoration: none;">${
options.callButtonText
}</a>`
});
};
setupDomListeners() {
const buttons =
this.container.querySelectorAll("button");
for (const button of buttons) {
button.addEventListener(
"click",
this.onOfferButtonClickListener
);
}
}
const buildCreateOrderButton =
OfferPanelComponent.buildCreateOrderButton;
const buildCloseButton =
OfferPanelComponent.buildCloseButton;
teardownDomListeners() {
const buttons = document.querySelectorAll(
this.container,
"button"
);
for (const button of buttons) {
button.removeEventListener(
"click",
this.onOfferButtonClickListener
);
}
class CustomOfferPanel extends OfferPanelComponent {
show() {
this.options.buttonBuilders = this
.currentOffer.phone
? [
buildCreateOrderButton,
buildCallButton,
buildCloseButton
]
: [
buildCreateOrderButton,
buildCloseButton
];
return super.show();
}
}
class CustomComposer extends ourCoffeeSdk.SearchBoxComposer {
buildOfferListComponent(
class CustomComposer extends SearchBoxComposer {
buildOfferPanelComponent(
context,
container,
offerList,
currentOffer,
contextOptions
) {
return new CustomOfferList(
return new CustomOfferPanel(
context,
container,
this.generateOfferPreviews(
offerList,
this.generateCurrentOfferFullView(
currentOffer,
contextOptions
),
this.generateOfferListComponentOptions(
this.generateOfferPanelComponentOptions(
contextOptions
)
);
}
generateCurrentOfferFullView(offer, options) {
const offerFullView =
super.generateCurrentOfferFullView(
offer,
options
);
if (offer && offer.place.phone) {
offerFullView.phone = offer.place.phone;
}
return offerFullView;
}
}
class CustomSearchBox extends ourCoffeeSdk.SearchBox {
class CustomSearchBox extends SearchBox {
buildComposer(context, container, options) {
return new CustomComposer(
context,
@ -113,6 +93,13 @@ class CustomSearchBox extends ourCoffeeSdk.SearchBox {
const searchBox = new CustomSearchBox(
document.getElementById("search-box"),
ourCoffeeSdk.dummyCoffeeApi
dummyCoffeeApi,
{
offerPanel: {
createOrderButtonText: "🛒Place an Order",
callButtonText: "☎️ Make a Call",
closeButtonText: "❌Not Now"
}
}
);
searchBox.search("Lungo");