Skip to content

Commit

Permalink
Create checkout demo blocks in Boilerplate
Browse files Browse the repository at this point in the history
  • Loading branch information
OscarMerino committed Dec 30, 2024
1 parent 19d1799 commit b15bae5
Show file tree
Hide file tree
Showing 15 changed files with 5,300 additions and 0 deletions.
119 changes: 119 additions & 0 deletions blocks/commerce-checkout-bopis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Adding Buy Online, Pickup In-Store (BOPIS) to Checkout

This guide will walk you through the steps to extend the Checkout to support the Buy Online, Pickup In-Store (BOPIS) functionality.

## Step-by-Step Process:

### 1. Update Content Fragment

For the new section, we need to add additional DOM elements, which can be done by modifying the contextual fragment.

```html
<div class="checkout__delivery-method">
<h2 class="checkout-delivery-method__title">Delivery Method</h2>
<div class="checkout-delivery-method__toggle-buttons">
<div class="checkout-delivery-method__delivery-button"></div>
<div class="checkout-delivery-method__in-store-pickup-button"></div>
</div>
</div>
<div class="checkout__in-store-pickup"></div>
```

We will also need to add new selectors, allowing us to use them later to render the required components and content.

```javascript
export const $deliveryButton = fragment.querySelector('.checkout-delivery-method__delivery-button');
export const $inStorePickupButton = fragment.querySelector('.checkout-delivery-method__in-store-pickup-button');
export const $inStorePickup = fragment.querySelector('.checkout__in-store-pickup');
```

### 2. UI Components for Delivery and In-Store Pickup

During the initialization, two buttons are rendered: one for Delivery and one for In-Store Pickup. These buttons allow users to toggle between the two options.

```javascript
UI.render(ToggleButton, {
label: 'Delivery',
onChange: () => onToggle('delivery'),
})($deliveryButton)

UI.render(ToggleButton, {
label: 'In-store Pickup',
onChange: () => onToggle('in-store-pickup'),
})($inStorePickupButton)
```

### 3. Toggle Between Delivery and In-Store Pickup

The `onToggle` function manages switching between delivery and in-store pickup. It updates the selected state of the buttons and toggles the visibility of the corresponding forms.

```javascript
async function onToggle(type) {
if (type === 'delivery') {
deliveryButton.setProps((prev) => ({ ...prev, selected: true }));
inStorePickupButton.setProps((prev) => ({ ...prev, selected: false }));
$shippingForm.removeAttribute('hidden');
$shippingMethods.removeAttribute('hidden');
$inStorePickup.setAttribute('hidden', '');
} else {
inStorePickupButton.setProps((prev) => ({ ...prev, selected: true }));
deliveryButton.setProps((prev) => ({ ...prev, selected: false }));
$shippingForm.setAttribute('hidden', '');
$shippingMethods.setAttribute('hidden', '');
$inStorePickup.removeAttribute('hidden');
}
}
```

### 4. Fetching Pickup Locations

The function `fetchPickupLocations` retrieves the list of available pickup locations using a GraphQL query. These locations will be displayed for the user to choose where they'd like to pick up their order.

```javascript
async function fetchPickupLocations() {
return checkoutApi
.fetchGraphQl(
`query pickupLocations {
pickupLocations {
items {
name
pickup_location_code
}
total_count
}
}`,
{ method: 'GET', cache: 'no-cache' }
)
.then((res) => res.data.pickupLocations.items);
}
```

### 5. Rendering the Pickup Location Options

Once the pickup locations are fetched, they are rendered as radio buttons. The user can select a location, which updates the shipping address with the corresponding pickup location code.

```javascript
const pickupLocations = await fetchPickupLocations();

pickupLocations.forEach((location) => {
const { name, pickup_location_code } = location;
const locationRadiobutton = document.createElement('div');

UI.render(RadioButton, {
label: name,
value: name,
onChange: () => {
checkoutApi.setShippingAddress({
address: {},
pickupLocationCode: pickup_location_code,
});
},
})(locationRadiobutton);

$inStorePickup.appendChild(locationRadiobutton);
});
```

### 6. Finalizing the BOPIS Flow

Once the user selects "In-store Pickup" and chooses a location, the form for pickup is shown, while the shipping form is hidden. This provides a clear and seamless way for users to choose how they want to receive their order.
198 changes: 198 additions & 0 deletions blocks/commerce-checkout-bopis/commerce-checkout-bopis.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/* stylelint-disable selector-class-pattern */

.checkout__content {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-big) 0;
}

.checkout__shipping-form:empty,
.checkout__shipping-methods:has(> div:empty),
.checkout__bill-to-shipping-address:has(> div:empty) {
display: none;
}

.checkout__main {
display: grid;
row-gap: var(--spacing-xbig);
margin-top: var(--spacing-medium);
}

.checkout__aside {
display: grid;
gap: var(--spacing-xbig);
}

.checkout__block.checkout__heading .dropin-header-container {
gap: var(--spacing-xsmall);
}

.checkout__place-order {
grid-column: unset;
justify-items: unset;
margin-top: calc(var(--spacing-big) * -1);
}

.checkout__heading .dropin-divider {
margin: 0;
}

/* To add into the cart dropin **/
.cart-order-summary__taxes.dropin-accordion .dropin-divider {
margin: var(--spacing-medium) auto;
}

/* CartSummaryList */

.cart-summary-list {
padding: var(--spacing-medium);
background-color: var(--color-neutral-200);
}

.cart-summary-list__heading {
display: flex;
justify-content: space-between;
}

.cart-summary-list__heading-text {
font: var(--type-headline-2-strong-font);
letter-spacing: var(--type-headline-2-strong-letter-spacing);
color: var(--color-neutral-800);
}

.cart-cart-summary-list__heading {
row-gap: var(--spacing-small);
padding-top: 0;
}

.cart-cart-summary-list__heading-text {
font: var(--type-headline-2-strong-font);
letter-spacing: var(--type-headline-2-strong-letter-spacing);
color: var(--color-neutral-800);
}

.cart-summary-list__edit {
font: var(--type-body-2-strong-font);
letter-spacing: var(--type-body-2-strong-letter-spacing);
}

/* BOPIS specific styles */

.checkout__in-store-pickup {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
}

.checkout__in-store-pickup[hidden] {
display:none;
}

.checkout-delivery-method__title {
color: var(--color-neutral-800);
font: var(--type-headline-2-strong-font);
letter-spacing: var(--type-headline-2-strong-letter-spacing);
margin: 0 0 var(--spacing-medium) 0;
}

.checkout-delivery-method__toggle-buttons {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-big);
}

@media only screen and (width >= 320px) and (width <= 768px) {
.checkout__main,
.checkout__aside {
display: contents;
}

.checkout__block {
order: 3;
}

.checkout__heading {
order: 1;
}

.checkout__cart-summary {
order: 2;
}

.checkout__place-order {
order: 4;
}

.order-confirmation {
grid-template-columns: repeat(var(--grid-1-columns), 1fr);
padding-top: 0;
}

.order-confirmation__main,
.order-confirmation__aside {
grid-row-gap: var(--spacing-medium);
}

.order-confirmation > div {
grid-column: 1 / span 4;
}

.order-confirmation__block .dropin-card {
border: 0;
}
}

@media only screen and (width >= 768px) {
.checkout__content {
display: grid;
align-items: start;
grid-template-columns: repeat(var(--grid-4-columns), 1fr);
gap: var(--spacing-big) var(--grid-4-gutters);
}

.checkout__content--error,
.checkout__content--empty {
display: grid;
grid-template-columns: 1fr;
}

.checkout__main {
grid-column: 1 / span 7;
row-gap: var(--spacing-xbig);
}

.checkout__aside {
grid-column: 9 / span 4;
gap: var(--spacing-xbig);
}

.checkout__error-banner,
.checkout__merged-cart-banner {
display: grid;
grid-column: 1 / span 12;
}

.checkout__place-order {
margin-top: 0;
}
}

/* Extra small devices (phones, 600px and down) */

/* @media only screen and (max-width: 600px) { } */

/* Small devices (portrait tablets and large phones, 600px and up) */

/* @media only screen and (min-width: 600px) { } */

/* Medium devices (landscape tablets, 768px and up) */

/* @media only screen and (min-width: 768px) { } */

/* Large devices (laptops/desktops, 992px and up) */

/* @media only screen and (min-width: 992px) { } */

/* Extra large devices (large laptops and desktops, 1200px and up) */

/* @media only screen and (min-width: 1200px) { } */
Loading

0 comments on commit b15bae5

Please sign in to comment.