Skip to content

Commit

Permalink
feat: create store locator template (#27)
Browse files Browse the repository at this point in the history
* feat: create store locator template

* style: remove first line

* style: add missing ;

* fix: use square_business_hours

* fix: update breaking changes

* fix: update link type

* refactor: remove unused data prop

* refactor: remove href

* fix: remove escape
  • Loading branch information
sohnj877 authored Mar 28, 2024
1 parent b72d603 commit 412992a
Show file tree
Hide file tree
Showing 16 changed files with 751 additions and 15 deletions.
3 changes: 1 addition & 2 deletions site/global/sections/footer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
"children": [
{
"label": "Locations And Hours",
"type": "external",
"href": "/"
"type": "storeLocator"
},
{
"label": "Returns And Exchanges",
Expand Down
9 changes: 9 additions & 0 deletions site/pages/store-locator.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"props": {
"locations": {
"filters": []
}
},
"template": "templates/store/locations",
"route": "s/store-locator"
}
75 changes: 75 additions & 0 deletions theme/assets/css/templates/store/store-locator.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.store-locator-page__heading {
margin-bottom: var(--space-x2);
}

.store-locator-input__wrapper {
margin-bottom: var(--space-x3);
}

.store-locator-list__item {
padding-top: var(--space-x2);
padding-bottom: var(--space-x2);
border-bottom: 1px solid var(--theme-border-color);
transition: border-color 0.1s ease;
}

.store-locator-list .store-locator-list__item:focus-visible {
outline: none;
}

.store-locator-list__item.is-active::before,
.store-locator-list__item:focus-visible::before {
opacity: 1;
}

.store-locator-list__item-icon {
opacity: 0.4;
}

.store-locator-map {
position: sticky;
top: var(--header-height, 0);
align-self: start;
margin-bottom: 0;
}

.store-locator-list-async {
position: relative;
min-height: 30vh;
}

/* store locator dialog */

.store-locator-dialog {
display: flex;
flex-flow: column;
gap: var(--space-x3);
padding-bottom: var(--space-x3);
}

.store-locator-dialog p {
font-size: var(--theme-font-size-minus-1);
line-height: var(--theme-font-size-minus-1-line-height);
color: var(--theme-body-text-color-subtle);
}

.store-locator-dialog__heading {
font-weight: var(--theme-font-weight-normal);
}

.store-locator-dialog__detail {
margin-top: var(--space-x2);
}

.store-locator-dialog__buttons {
display: flex;
gap: var(--space-x2);
padding-top: var(--space-x2);
margin-top: var(--space-x2);
border-top: 1px solid var(--theme-border-color);
}

.store-locator-dialog__hours-row {
row-gap: var(--space-half);
margin-top: var(--space);
}
3 changes: 3 additions & 0 deletions theme/assets/css/ui/google-map.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.ui-google-map {
border-radius: var(--theme-border-radius);
}
8 changes: 7 additions & 1 deletion theme/assets/css/ui/row.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

.ui-row__icon,
.ui-row__label,
.ui-row__sublabel {
.ui-row__sublabel,
.ui-row__side {
position: relative;
}

Expand Down Expand Up @@ -43,3 +44,8 @@
.ui-row:hover::before {
opacity: 1;
}

.ui-row__side {
display: flex;
gap: var(--space-x2);
}
49 changes: 49 additions & 0 deletions theme/assets/js/components/store-locator-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
window.onStoreLocatorListReady = () => {
const createStoreLocatorItemData = (locationId) => ({
isActive: false,
init() {
this.$watch('$store.storeLocator.locationId', (id) => {
this.isActive = locationId === id;
});
},
/**
* Opens location details on item click
* @param {String} id
*/
onStoreLocatorItemClick(id) {
if (Alpine.store('global').isMobile) {
this.openLocationDetails(id);
}
Alpine.store('storeLocator').onStoreLocatorItemClick(id);
},
/**
* Opens location details on item focus
* @param {String} id
*/
onStoreLocatorItemFocus(id) {
Alpine.store('storeLocator').updateLocationId(id);
},
/**
* Opens location details on item enter
* @param {String} id
*/
onStoreLocatorKeyEnter(id) {
if (Alpine.store('global').isMobile) {
this.openLocationDetails(id);
} else {
this.onStoreLocatorItemClick(id);
}
},
/**
* Opens location details
* @param {String} id
*/
openLocationDetails(id) {
Alpine.store('storeLocator').openLocationDetails(id);
},
});

Alpine.data('storeLocatorItem', createStoreLocatorItemData);
};

document.addEventListener('alpine:init', window.onStoreLocatorListReady);
41 changes: 39 additions & 2 deletions theme/assets/js/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ document.addEventListener('alpine:init', () => {
fulfillment: Alpine.$persist(''),
customerLocale: Alpine.$persist({}),
suggestedPlaceItem: Alpine.$persist({}),
suggestedPlaceItemsCached: Alpine.$persist({}),
isMobile: true,
isTablet: false,
isPageScrollDisabled: false,
Expand Down Expand Up @@ -484,6 +485,7 @@ document.addEventListener('alpine:init', () => {
*/
formatLocationsWithDistance(locations, sort) {
let customerCoordinates = {};
let formattedLocations = locations;

if (this.suggestedPlaceItem?.place_id === sort?.place_id && Utils.hasValidCoordinates(this.suggestedPlaceItem)) {
customerCoordinates = { latitude: this.suggestedPlaceItem.latitude, longitude: this.suggestedPlaceItem.longitude };
Expand All @@ -492,9 +494,9 @@ document.addEventListener('alpine:init', () => {
}

if (Utils.hasValidCoordinates(customerCoordinates)) {
return locations.map((location) => Utils.formatLocationWithDistance(location, customerCoordinates));
formattedLocations = locations.map((location) => Utils.formatLocationWithDistance(location, customerCoordinates));
}
return locations;
return formattedLocations.sort((a, b) => a.distance - b.distance);
},
/**
* Gets the location id by the user's current location and fulfillment
Expand All @@ -505,6 +507,41 @@ document.addEventListener('alpine:init', () => {
await store.getCustomerCoordinates();
await store.getClosestLocation(fulfillment);
},
/**
* Gets the place coordinates
* @param {Object} suggestedItem
*/
async getPlaceDetails(suggestedItem) {
const store = Alpine.store('global');
const placeId = suggestedItem.place_id;

if (store.suggestedPlaceItemsCached[placeId]) {
store.updateProperty('suggestedPlaceItem', store.suggestedPlaceItemsCached[placeId]);
} else {
store.updateProperty('suggestedPlaceItem', suggestedItem);
}

const suggestedPlaceItem = store.suggestedPlaceItem;
if (Utils.hasValidCoordinates(suggestedPlaceItem) && suggestedPlaceItem.place_id === placeId) {
return;
}

await SquareWebSDK.places.getPlace({ placeId })
.then(async ({ data }) => {
if (Utils.hasValidCoordinates(data)) {
const suggestedPlaceItemDetail = {
...suggestedPlaceItem,
latitude: data.latitude,
longitude: data.longitude,
};
store.updateProperty('suggestedPlaceItemsCached', {
...store.suggestedPlaceItemsCached,
[placeId]: suggestedPlaceItemDetail,
});
store.updateProperty('suggestedPlaceItem', suggestedPlaceItemDetail);
}
});
},
});

Alpine.data('global', (dataId) => ({
Expand Down
42 changes: 40 additions & 2 deletions theme/assets/js/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ window.Utils = {
|| Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
);
},
/**
* Defines "browser" as having the `window` global
* Checks if the browser supports them
* @return {boolean}
*/
isBrowser() {
return (typeof window !== 'undefined');
},
/**
* Checks if the current device is a touch device
*/
Expand All @@ -52,12 +60,27 @@ window.Utils = {
|| (navigator.maxTouchPoints > 0)
|| (navigator.msMaxTouchPoints > 0);
},
/**
* Checks if the user agent is an android device
* @return {boolean}
*/
isAndroidDevice() {
return this.isBrowser() && Boolean(window.navigator.userAgent.match(/android/i));
},
/**
* Checks if the user agent is an ios device
* Does *not* check whether it is in a webview or actual browser
* @return {boolean}
*/
isIOSDevice() {
return this.isBrowser() && Boolean(window.navigator.userAgent.match(/iPad|iPhone|iPod/i));
},
/**
* Is it apple safari browser
* @return {boolean}
*/
isSafari() {
return (typeof window !== 'undefined') && window.navigator.userAgent.includes('Safari')
return this.isBrowser() && window.navigator.userAgent.includes('Safari')
&& !window.navigator.userAgent.includes('Chrome');
},
/**
Expand Down Expand Up @@ -186,6 +209,7 @@ window.Utils = {
}
return {
...location,
distance,
formatted_distance: formattedDistance,
};
},
Expand Down Expand Up @@ -387,7 +411,7 @@ window.Utils = {
for (let y = 0; y <= topPos; y += yPosPerScroll) {
window.scrollTo({ top: y, behavior: 'smooth' });
// eslint-disable-next-line no-await-in-loop
await Utils.delay(scrollDelay);
await this.delay(scrollDelay);
if (y + yPosPerScroll > topPos && typeof callback === 'function') {
callback();
}
Expand Down Expand Up @@ -446,4 +470,18 @@ window.Utils = {
el.innerHTML = text;
});
},
/**
* Get directions url
* Opens native map app for android and ios devices
* @param {String} destination
* @return {String}
*/
getDirectionsUrl(destination) {
if (this.isAndroidDevice()) {
return `geo:0,0?q=${destination}`;
} if (this.isIOSDevice()) {
return `maps://google.com/maps?daddr=${destination}`;
}
return `https://www.google.com/maps/dir/?api=1&destination=${destination}`;
},
};
Loading

0 comments on commit 412992a

Please sign in to comment.