@altazion/commerce-sdk-htmx 26.618.8367 → 26.619.8376
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +177 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.iife.js +177 -2
- package/dist/index.iife.js.map +1 -1
- package/dist/index.js +177 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -656,8 +656,8 @@ const storesModuleDefinition = {
|
|
|
656
656
|
case "findByLocation": {
|
|
657
657
|
const latitude = requireNumber(payload.latitude, "latitude");
|
|
658
658
|
const longitude = requireNumber(payload.longitude, "longitude");
|
|
659
|
-
const
|
|
660
|
-
return client.stores.findByLocation(latitude, longitude,
|
|
659
|
+
const countryCode = payload.countryCode === void 0 ? "FRA" : requireString(payload.countryCode, "countryCode");
|
|
660
|
+
return client.stores.findByLocation(latitude, longitude, countryCode);
|
|
661
661
|
}
|
|
662
662
|
case "findByPostalCode": {
|
|
663
663
|
const postalCode = requireString(payload.postalCode, "postalCode");
|
|
@@ -954,6 +954,179 @@ function resolveTemplate(templateId, handlebars, templateCache) {
|
|
|
954
954
|
templateCache.set(templateId, compiled);
|
|
955
955
|
return compiled;
|
|
956
956
|
}
|
|
957
|
+
const DIALOG_SELECTOR = "[data-hz-store-picker]";
|
|
958
|
+
const TEMPLATE_ID = "hz-store-picker-store-tmpl";
|
|
959
|
+
const RESULTS_SELECTOR = "[data-store-picker-results]";
|
|
960
|
+
const HINT_SELECTOR = "[data-store-picker-hint]";
|
|
961
|
+
const FORM_SELECTOR = "[data-store-picker-form]";
|
|
962
|
+
const INPUT_SELECTOR = "[data-store-picker-input]";
|
|
963
|
+
function initStorePicker(client, handlebars) {
|
|
964
|
+
if (typeof document === "undefined") return () => {
|
|
965
|
+
};
|
|
966
|
+
let renderStore = null;
|
|
967
|
+
const templateEl = document.getElementById(TEMPLATE_ID);
|
|
968
|
+
if (templateEl && handlebars) {
|
|
969
|
+
try {
|
|
970
|
+
const tplSource = templateEl.innerHTML;
|
|
971
|
+
const compiled = handlebars.compile(tplSource);
|
|
972
|
+
renderStore = (store) => compiled(store);
|
|
973
|
+
} catch {
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (!renderStore) {
|
|
977
|
+
renderStore = fallbackRender;
|
|
978
|
+
}
|
|
979
|
+
function getDialog() {
|
|
980
|
+
return document.querySelector(DIALOG_SELECTOR);
|
|
981
|
+
}
|
|
982
|
+
function openDialog() {
|
|
983
|
+
var _a;
|
|
984
|
+
(_a = getDialog()) == null ? void 0 : _a.showModal();
|
|
985
|
+
}
|
|
986
|
+
function closeDialog() {
|
|
987
|
+
var _a;
|
|
988
|
+
(_a = getDialog()) == null ? void 0 : _a.close();
|
|
989
|
+
}
|
|
990
|
+
function getConfig() {
|
|
991
|
+
const dialog = getDialog();
|
|
992
|
+
return {
|
|
993
|
+
countryCode: (dialog == null ? void 0 : dialog.dataset.storePickerCountry) ?? "FRA",
|
|
994
|
+
feature: (dialog == null ? void 0 : dialog.dataset.storePickerFeature) ?? "InStoreOrder"
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
function renderResults(stores) {
|
|
998
|
+
const dialog = getDialog();
|
|
999
|
+
if (!dialog) return;
|
|
1000
|
+
const list = dialog.querySelector(RESULTS_SELECTOR);
|
|
1001
|
+
const hint = dialog.querySelector(HINT_SELECTOR);
|
|
1002
|
+
if (!list) return;
|
|
1003
|
+
if (stores.length === 0) {
|
|
1004
|
+
list.innerHTML = "";
|
|
1005
|
+
list.hidden = true;
|
|
1006
|
+
if (hint) {
|
|
1007
|
+
hint.textContent = "Aucun magasin trouvé dans ce secteur.";
|
|
1008
|
+
hint.hidden = false;
|
|
1009
|
+
}
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
list.innerHTML = stores.map((s) => renderStore(s)).join("");
|
|
1013
|
+
list.hidden = false;
|
|
1014
|
+
if (hint) hint.hidden = true;
|
|
1015
|
+
}
|
|
1016
|
+
function showSearching() {
|
|
1017
|
+
const dialog = getDialog();
|
|
1018
|
+
if (!dialog) return;
|
|
1019
|
+
const hint = dialog.querySelector(HINT_SELECTOR);
|
|
1020
|
+
const list = dialog.querySelector(RESULTS_SELECTOR);
|
|
1021
|
+
if (hint) {
|
|
1022
|
+
hint.textContent = "Recherche en cours…";
|
|
1023
|
+
hint.hidden = false;
|
|
1024
|
+
}
|
|
1025
|
+
if (list) list.hidden = true;
|
|
1026
|
+
}
|
|
1027
|
+
function showError(message) {
|
|
1028
|
+
const dialog = getDialog();
|
|
1029
|
+
if (!dialog) return;
|
|
1030
|
+
const hint = dialog.querySelector(HINT_SELECTOR);
|
|
1031
|
+
if (hint) {
|
|
1032
|
+
hint.textContent = message;
|
|
1033
|
+
hint.hidden = false;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
async function handlePostalCodeSearch(postalCode) {
|
|
1037
|
+
showSearching();
|
|
1038
|
+
const { countryCode, feature } = getConfig();
|
|
1039
|
+
try {
|
|
1040
|
+
const stores = await client.stores.findByPostalCode(postalCode, countryCode, 10, feature);
|
|
1041
|
+
renderResults(stores);
|
|
1042
|
+
} catch {
|
|
1043
|
+
showError("La recherche a échoué. Vérifiez votre code postal et réessayez.");
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
async function handleGeolocate() {
|
|
1047
|
+
if (!navigator.geolocation) {
|
|
1048
|
+
showError("La géolocalisation n'est pas disponible sur cet appareil.");
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
showSearching();
|
|
1052
|
+
const { countryCode, feature } = getConfig();
|
|
1053
|
+
navigator.geolocation.getCurrentPosition(
|
|
1054
|
+
async (position) => {
|
|
1055
|
+
try {
|
|
1056
|
+
const stores = await client.stores.findByLocation(
|
|
1057
|
+
position.coords.latitude,
|
|
1058
|
+
position.coords.longitude,
|
|
1059
|
+
countryCode,
|
|
1060
|
+
10,
|
|
1061
|
+
feature
|
|
1062
|
+
);
|
|
1063
|
+
renderResults(stores);
|
|
1064
|
+
} catch {
|
|
1065
|
+
showError("La recherche a échoué. Veuillez réessayer.");
|
|
1066
|
+
}
|
|
1067
|
+
},
|
|
1068
|
+
() => {
|
|
1069
|
+
showError("Impossible d'obtenir votre position. Vérifiez les autorisations de géolocalisation.");
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
async function handleSelectStore(storeGuid) {
|
|
1074
|
+
try {
|
|
1075
|
+
await client.session.associateStore(storeGuid);
|
|
1076
|
+
closeDialog();
|
|
1077
|
+
document.dispatchEvent(new CustomEvent("altazion:stores:store-associated", {
|
|
1078
|
+
bubbles: true,
|
|
1079
|
+
detail: { storeGuid }
|
|
1080
|
+
}));
|
|
1081
|
+
window.location.reload();
|
|
1082
|
+
} catch {
|
|
1083
|
+
showError("Impossible de sélectionner ce magasin. Veuillez réessayer.");
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
function handleClick(event) {
|
|
1087
|
+
const target = event.target.closest("[data-action]");
|
|
1088
|
+
if (!target) return;
|
|
1089
|
+
const action = target.dataset.action;
|
|
1090
|
+
switch (action) {
|
|
1091
|
+
case "open-store-picker":
|
|
1092
|
+
openDialog();
|
|
1093
|
+
break;
|
|
1094
|
+
case "close-store-picker":
|
|
1095
|
+
closeDialog();
|
|
1096
|
+
break;
|
|
1097
|
+
case "store-picker-geolocate":
|
|
1098
|
+
void handleGeolocate();
|
|
1099
|
+
break;
|
|
1100
|
+
case "select-store": {
|
|
1101
|
+
const guid = target.dataset.storeGuid;
|
|
1102
|
+
if (guid) void handleSelectStore(guid);
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function handleFormSubmit(event) {
|
|
1108
|
+
const form = event.target.closest(FORM_SELECTOR);
|
|
1109
|
+
if (!form) return;
|
|
1110
|
+
event.preventDefault();
|
|
1111
|
+
const input = form.querySelector(INPUT_SELECTOR);
|
|
1112
|
+
const postalCode = input == null ? void 0 : input.value.trim();
|
|
1113
|
+
if (postalCode) void handlePostalCodeSearch(postalCode);
|
|
1114
|
+
}
|
|
1115
|
+
document.addEventListener("click", handleClick);
|
|
1116
|
+
document.addEventListener("submit", handleFormSubmit);
|
|
1117
|
+
return () => {
|
|
1118
|
+
document.removeEventListener("click", handleClick);
|
|
1119
|
+
document.removeEventListener("submit", handleFormSubmit);
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
function fallbackRender(store) {
|
|
1123
|
+
const name = store.label ?? store.code ?? "Magasin";
|
|
1124
|
+
const address = [store.streetAddress, store.postalCode, store.city].filter(Boolean).join(", ");
|
|
1125
|
+
return `<li class="hz-store-picker__item"><div class="hz-store-picker__item-info"><strong class="hz-store-picker__item-name">${escHtml(name)}</strong>` + (address ? `<address class="hz-store-picker__item-address">${escHtml(address)}</address>` : "") + `</div><button class="hz-store-picker__item-select" type="button" data-action="select-store" data-store-guid="${escHtml(store.guid)}">Choisir ce magasin</button></li>`;
|
|
1126
|
+
}
|
|
1127
|
+
function escHtml(str) {
|
|
1128
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1129
|
+
}
|
|
957
1130
|
const productCardTemplate = '<article class="altz-product-card{{#unless (isAvailable availability)}} altz-product-card--unavailable{{/unless}}">\n {{#if imageUrl}}\n <a href="{{productUrl reference}}" class="altz-product-card__image-link" aria-label="{{name}}">\n <img\n src="{{thumbnailUrl imageUrl 400}}"\n alt="{{name}}"\n class="altz-product-card__image"\n loading="lazy"\n width="400"\n />\n </a>\n {{/if}}\n\n <div class="altz-product-card__body">\n <a href="{{productUrl reference}}" class="altz-product-card__title">\n {{name}}\n </a>\n\n <div class="altz-product-card__pricing">\n {{#if discount}}\n <span class="altz-product-card__price altz-product-card__price--discounted">\n {{formatPrice price}}\n </span>\n <span class="altz-product-card__price altz-product-card__price--original">\n {{formatPrice originalPrice}}\n </span>\n <span class="altz-product-card__discount-badge">\n {{discountPercent originalPrice price}}\n </span>\n {{else}}\n <span class="altz-product-card__price">\n {{formatPrice price}}\n </span>\n {{/if}}\n </div>\n\n {{#unless (isAvailable availability)}}\n <p class="altz-product-card__unavailable">{{unavailableLabel}}</p>\n {{/unless}}\n\n {{#if (isAvailable availability)}}\n <button\n class="altz-product-card__add-to-cart"\n hx-ext="altazion"\n hx-altazion-cart-action="addItem"\n hx-altazion-cart-reference="{{reference}}"\n hx-altazion-cart-quantity="1"\n hx-altazion-refresh="#altz-cart-mini"\n hx-indicator=".altz-spinner"\n >\n {{addToCartLabel}}\n </button>\n {{/if}}\n </div>\n</article>\n';
|
|
958
1131
|
const cartMiniTemplate = '<div id="altz-cart-mini" class="altz-cart-mini">\n <div class="altz-cart-mini__header">\n <span class="altz-cart-mini__label">{{cartLabel}}</span>\n <span class="altz-cart-mini__count">{{cartCount}}</span>\n </div>\n\n {{#cartHasItems}}\n <ul class="altz-cart-mini__lines">\n {{#each lines}}\n <li class="altz-cart-mini__line">\n <span class="altz-cart-mini__line-name">{{this.productName}}</span>\n <span class="altz-cart-mini__line-qty">× {{this.quantity}}</span>\n <span class="altz-cart-mini__line-price">{{formatPrice this.unitPriceWithTax}}</span>\n </li>\n {{/each}}\n </ul>\n\n <div class="altz-cart-mini__total">\n <span>{{totalLabel}}</span>\n <strong>{{cartTotal}}</strong>\n </div>\n\n <a href="{{cartUrl}}" class="altz-cart-mini__cta">\n {{viewCartLabel}}\n </a>\n {{/cartHasItems}}\n\n {{^cartHasItems}}\n <p class="altz-cart-mini__empty">{{emptyLabel}}</p>\n {{/cartHasItems}}\n</div>\n';
|
|
959
1132
|
const productListTemplate = '<section class="altz-product-list">\n {{#if title}}\n <h2 class="altz-product-list__title">{{title}}</h2>\n {{/if}}\n\n {{#if products.length}}\n <ul class="altz-product-list__grid" role="list">\n {{#each products}}\n <li class="altz-product-list__item">\n <article class="altz-product-card{{#unless (isAvailable this.availability)}} altz-product-card--unavailable{{/unless}}">\n {{#if this.imageUrl}}\n <a href="{{productUrl this.reference}}" class="altz-product-card__image-link" aria-label="{{this.name}}">\n <img\n src="{{thumbnailUrl this.imageUrl 300}}"\n alt="{{this.name}}"\n class="altz-product-card__image"\n loading="lazy"\n width="300"\n />\n </a>\n {{/if}}\n\n <div class="altz-product-card__body">\n <a href="{{productUrl this.reference}}" class="altz-product-card__title">\n {{this.name}}\n </a>\n\n <div class="altz-product-card__pricing">\n {{#if this.discount}}\n <span class="altz-product-card__price altz-product-card__price--discounted">\n {{formatPrice this.price}}\n </span>\n <span class="altz-product-card__price altz-product-card__price--original">\n {{formatPrice this.originalPrice}}\n </span>\n <span class="altz-product-card__discount-badge">\n {{discountPercent this.originalPrice this.price}}\n </span>\n {{else}}\n <span class="altz-product-card__price">\n {{formatPrice this.price}}\n </span>\n {{/if}}\n </div>\n\n {{#if (isAvailable this.availability)}}\n <button\n class="altz-product-card__add-to-cart"\n hx-ext="altazion"\n hx-altazion-cart-action="addItem"\n hx-altazion-cart-reference="{{this.reference}}"\n hx-altazion-cart-quantity="1"\n hx-altazion-refresh="#altz-cart-mini"\n hx-indicator=".altz-spinner"\n >\n {{../addToCartLabel}}\n </button>\n {{/if}}\n </div>\n </article>\n </li>\n {{/each}}\n </ul>\n {{else}}\n <p class="altz-product-list__empty">{{emptyLabel}}</p>\n {{/if}}\n</section>\n';
|
|
@@ -1039,6 +1212,7 @@ function initAltazionHtmx(config) {
|
|
|
1039
1212
|
registerCartHelpers(handlebars, getCart, defaults);
|
|
1040
1213
|
}
|
|
1041
1214
|
declarativeRenderer.render();
|
|
1215
|
+
const disposeStorePicker = initStorePicker(client, handlebarsRuntime);
|
|
1042
1216
|
const offlineEl = typeof document !== "undefined" ? document.querySelector(offlineSelector) ?? document.body : null;
|
|
1043
1217
|
let lastConnectivityStatus = null;
|
|
1044
1218
|
const updateOfflineClass = () => {
|
|
@@ -1086,6 +1260,7 @@ function initAltazionHtmx(config) {
|
|
|
1086
1260
|
document.removeEventListener("altazion:marketing:items-loaded", syncMarketingItemsFromEvent);
|
|
1087
1261
|
}
|
|
1088
1262
|
declarativeRenderer.dispose();
|
|
1263
|
+
disposeStorePicker();
|
|
1089
1264
|
unsubscribeConnectivity == null ? void 0 : unsubscribeConnectivity();
|
|
1090
1265
|
}
|
|
1091
1266
|
};
|