Browser API
Search…
Examples
These examples show how Browser API can be leveraged to create custom widget implementations to display combos, bundles, and bundle builders.

Combos

1
const renderCombo = (containerSelector) => {
2
// Grab the API client, a location and a combo
3
const { client } = window.pickystory
4
const location = client.getLocations('combos').shift()
5
const combo = location.deals.shift()
6
7
// Find the designated slot in the page and add a title and product cards
8
const container = document.querySelector(containerSelector)
9
const header = document.createElement('h2')
10
header.textContent = 'COMBO'
11
container.append(header)
12
for (let product of combo.products) {
13
renderProductCard(product, container)
14
}
15
16
// Render the ATC button and specify its action
17
renderAddToCart(container, async (selections) => {
18
const variants = combo.getVariantsForSelections(selections)
19
await combo.addVariantsToCart(variants, 1)
20
})
21
}
Copied!

Bundles

1
const renderBundle = (containerSelector) => {
2
// Grab the API client, a location and a bundle
3
const { client } = window.pickystory
4
const location = client.getLocations('bundles').shift()
5
const bundle = location.deals.shift()
6
7
// Find the designated slot in the page and add a title and product cards
8
const container = document.querySelector(containerSelector)
9
const header = document.createElement('h2')
10
header.textContent = 'BUNDLE'
11
container.append(header)
12
for (let product of bundle.products) {
13
renderProductCard(product, container)
14
}
15
16
// Render the ATC button and specify its action
17
renderAddToCart(container, async (selections) => {
18
const variants = bundle.getVariantsForSelections(selections)
19
await bundle.addVariantsToCart(variants, 1)
20
})
21
}
Copied!

Bundle builders

1
const renderBuilder = (containerSelector) => {
2
// Grab the API client, a location and a builder
3
const { client } = window.pickystory
4
const location = client.getLocations('builders').shift()
5
const builder = location.deals.shift()
6
7
// Find the designated slot in the page and add a title and product cards
8
const container = document.querySelector(containerSelector)
9
const header = document.createElement('h2')
10
header.textContent = 'BUILDER'
11
container.append(header)
12
for (let product of builder.products) {
13
renderProductCard(product, container)
14
}
15
16
// Render the ATC button and specify its action
17
renderAddToCart(container, async (selections) => {
18
const variants = builder.getVariantsForSelections(selections)
19
await builder.addVariantsToCart(variants, 1)
20
})
21
}
Copied!

Kits

Coming soon!

Looks

Coming soon!

Common

For the purpose of this demo, we assume widget slots have been added to the store HTML as below:
1
<div id="api-combo-container"></div>
2
<div id="api-bundle-container"></div>
3
<div id="api-builder-container"></div>
4
<div id="api-kit-container"></div>
5
<div id="api-look-container"></div>
Copied!
1
/**
2
* Render a card containing product title, image and options
3
*/
4
const renderProductCard = (product, container) => {
5
// Show the title and the product image using simple <div>, <h3> and <img> tags
6
const productDiv = document.createElement('div')
7
container.append(productDiv)
8
const title = document.createElement('h3')
9
productDiv.append(title)
10
title.textContent = product.title
11
const image = document.createElement('img')
12
productDiv.append(image)
13
image.height = 100
14
image.width = 100
15
image.src = product.images[0].src
16
17
// Show product options and their values as dropdowns using <select>
18
for (let option of product.options) {
19
const select = document.createElement('select')
20
productDiv.append(select)
21
select.name = option.name
22
select.setAttribute('product-position', product.position)
23
select.setAttribute('option-position', option.position)
24
select.classList.add('picky-option')
25
for (let value of option.values) {
26
const option = document.createElement('option')
27
select.append(option)
28
option.value = value
29
option.textContent = value
30
}
31
}
32
}
33
34
/**
35
* Render a sample Add To Cart button
36
*/
37
const renderAddToCart = (container, onAddSelections, callToAction = 'ADD') => {
38
// Create a simple button and style it a bit
39
const button = document.createElement('button')
40
container.append(button)
41
button.type = 'button'
42
button.textContent = callToAction
43
Object.entries({
44
width: '100%', 'text-align': 'center', background: 'black', color: 'white', height: '40px'
45
}).forEach(([key, value]) => button.style.setProperty(key, value))
46
47
// Collect product option values from the relevant <select> elements
48
button.onclick = async () => {
49
const selections = [...container.querySelectorAll('.picky-option')]
50
.reduce((result, node) => {
51
const productPosition = parseInt(node.getAttribute('product-position'), 10)
52
const optionPosition = parseInt(node.getAttribute('option-position'), 10)
53
let product = result.find(({ position }) => position === productPosition)
54
if (!product) {
55
product = { position: productPosition }
56
result.push(product)
57
}
58
const optionAlias = 'option' + optionPosition
59
product[optionAlias] = node.value
60
return result
61
}, [])
62
63
// Use a naive opacity effect while cart addition is in progress
64
button.disabled = true
65
button.style.setProperty('opacity', '0.4')
66
67
// An async click handler must be provided
68
if (typeof onAddSelections === 'function') {
69
await onAddSelections(selections)
70
}
71
72
button.disabled = false
73
button.style.setProperty('opacity', '1')
74
}
75
}
76
77
(() => {
78
// A simple way of activating the widget once the API becomes available
79
let apiWaitCount = 0
80
const interval = window.setInterval(() => {
81
++apiWaitCount
82
if (window?.pickystory?.client) {
83
clearInterval(interval)
84
renderCombo('#api-combo-container')
85
renderBundle('#api-bundle-container')
86
renderBuilder('#api-builder-container')
87
} else if (apiWaitCount > 50) clearInterval(interval)
88
}, 50)
89
})()
Copied!