@altazion/commerce-sdk-htmx 26.618.8362 → 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.cjs
CHANGED
|
@@ -658,8 +658,8 @@ const storesModuleDefinition = {
|
|
|
658
658
|
case "findByLocation": {
|
|
659
659
|
const latitude = requireNumber(payload.latitude, "latitude");
|
|
660
660
|
const longitude = requireNumber(payload.longitude, "longitude");
|
|
661
|
-
const
|
|
662
|
-
return client.stores.findByLocation(latitude, longitude,
|
|
661
|
+
const countryCode = payload.countryCode === void 0 ? "FRA" : requireString(payload.countryCode, "countryCode");
|
|
662
|
+
return client.stores.findByLocation(latitude, longitude, countryCode);
|
|
663
663
|
}
|
|
664
664
|
case "findByPostalCode": {
|
|
665
665
|
const postalCode = requireString(payload.postalCode, "postalCode");
|
|
@@ -956,6 +956,179 @@ function resolveTemplate(templateId, handlebars, templateCache) {
|
|
|
956
956
|
templateCache.set(templateId, compiled);
|
|
957
957
|
return compiled;
|
|
958
958
|
}
|
|
959
|
+
const DIALOG_SELECTOR = "[data-hz-store-picker]";
|
|
960
|
+
const TEMPLATE_ID = "hz-store-picker-store-tmpl";
|
|
961
|
+
const RESULTS_SELECTOR = "[data-store-picker-results]";
|
|
962
|
+
const HINT_SELECTOR = "[data-store-picker-hint]";
|
|
963
|
+
const FORM_SELECTOR = "[data-store-picker-form]";
|
|
964
|
+
const INPUT_SELECTOR = "[data-store-picker-input]";
|
|
965
|
+
function initStorePicker(client, handlebars) {
|
|
966
|
+
if (typeof document === "undefined") return () => {
|
|
967
|
+
};
|
|
968
|
+
let renderStore = null;
|
|
969
|
+
const templateEl = document.getElementById(TEMPLATE_ID);
|
|
970
|
+
if (templateEl && handlebars) {
|
|
971
|
+
try {
|
|
972
|
+
const tplSource = templateEl.innerHTML;
|
|
973
|
+
const compiled = handlebars.compile(tplSource);
|
|
974
|
+
renderStore = (store) => compiled(store);
|
|
975
|
+
} catch {
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
if (!renderStore) {
|
|
979
|
+
renderStore = fallbackRender;
|
|
980
|
+
}
|
|
981
|
+
function getDialog() {
|
|
982
|
+
return document.querySelector(DIALOG_SELECTOR);
|
|
983
|
+
}
|
|
984
|
+
function openDialog() {
|
|
985
|
+
var _a;
|
|
986
|
+
(_a = getDialog()) == null ? void 0 : _a.showModal();
|
|
987
|
+
}
|
|
988
|
+
function closeDialog() {
|
|
989
|
+
var _a;
|
|
990
|
+
(_a = getDialog()) == null ? void 0 : _a.close();
|
|
991
|
+
}
|
|
992
|
+
function getConfig() {
|
|
993
|
+
const dialog = getDialog();
|
|
994
|
+
return {
|
|
995
|
+
countryCode: (dialog == null ? void 0 : dialog.dataset.storePickerCountry) ?? "FRA",
|
|
996
|
+
feature: (dialog == null ? void 0 : dialog.dataset.storePickerFeature) ?? "InStoreOrder"
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
function renderResults(stores) {
|
|
1000
|
+
const dialog = getDialog();
|
|
1001
|
+
if (!dialog) return;
|
|
1002
|
+
const list = dialog.querySelector(RESULTS_SELECTOR);
|
|
1003
|
+
const hint = dialog.querySelector(HINT_SELECTOR);
|
|
1004
|
+
if (!list) return;
|
|
1005
|
+
if (stores.length === 0) {
|
|
1006
|
+
list.innerHTML = "";
|
|
1007
|
+
list.hidden = true;
|
|
1008
|
+
if (hint) {
|
|
1009
|
+
hint.textContent = "Aucun magasin trouvé dans ce secteur.";
|
|
1010
|
+
hint.hidden = false;
|
|
1011
|
+
}
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
list.innerHTML = stores.map((s) => renderStore(s)).join("");
|
|
1015
|
+
list.hidden = false;
|
|
1016
|
+
if (hint) hint.hidden = true;
|
|
1017
|
+
}
|
|
1018
|
+
function showSearching() {
|
|
1019
|
+
const dialog = getDialog();
|
|
1020
|
+
if (!dialog) return;
|
|
1021
|
+
const hint = dialog.querySelector(HINT_SELECTOR);
|
|
1022
|
+
const list = dialog.querySelector(RESULTS_SELECTOR);
|
|
1023
|
+
if (hint) {
|
|
1024
|
+
hint.textContent = "Recherche en cours…";
|
|
1025
|
+
hint.hidden = false;
|
|
1026
|
+
}
|
|
1027
|
+
if (list) list.hidden = true;
|
|
1028
|
+
}
|
|
1029
|
+
function showError(message) {
|
|
1030
|
+
const dialog = getDialog();
|
|
1031
|
+
if (!dialog) return;
|
|
1032
|
+
const hint = dialog.querySelector(HINT_SELECTOR);
|
|
1033
|
+
if (hint) {
|
|
1034
|
+
hint.textContent = message;
|
|
1035
|
+
hint.hidden = false;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
async function handlePostalCodeSearch(postalCode) {
|
|
1039
|
+
showSearching();
|
|
1040
|
+
const { countryCode, feature } = getConfig();
|
|
1041
|
+
try {
|
|
1042
|
+
const stores = await client.stores.findByPostalCode(postalCode, countryCode, 10, feature);
|
|
1043
|
+
renderResults(stores);
|
|
1044
|
+
} catch {
|
|
1045
|
+
showError("La recherche a échoué. Vérifiez votre code postal et réessayez.");
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
async function handleGeolocate() {
|
|
1049
|
+
if (!navigator.geolocation) {
|
|
1050
|
+
showError("La géolocalisation n'est pas disponible sur cet appareil.");
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
showSearching();
|
|
1054
|
+
const { countryCode, feature } = getConfig();
|
|
1055
|
+
navigator.geolocation.getCurrentPosition(
|
|
1056
|
+
async (position) => {
|
|
1057
|
+
try {
|
|
1058
|
+
const stores = await client.stores.findByLocation(
|
|
1059
|
+
position.coords.latitude,
|
|
1060
|
+
position.coords.longitude,
|
|
1061
|
+
countryCode,
|
|
1062
|
+
10,
|
|
1063
|
+
feature
|
|
1064
|
+
);
|
|
1065
|
+
renderResults(stores);
|
|
1066
|
+
} catch {
|
|
1067
|
+
showError("La recherche a échoué. Veuillez réessayer.");
|
|
1068
|
+
}
|
|
1069
|
+
},
|
|
1070
|
+
() => {
|
|
1071
|
+
showError("Impossible d'obtenir votre position. Vérifiez les autorisations de géolocalisation.");
|
|
1072
|
+
}
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
async function handleSelectStore(storeGuid) {
|
|
1076
|
+
try {
|
|
1077
|
+
await client.session.associateStore(storeGuid);
|
|
1078
|
+
closeDialog();
|
|
1079
|
+
document.dispatchEvent(new CustomEvent("altazion:stores:store-associated", {
|
|
1080
|
+
bubbles: true,
|
|
1081
|
+
detail: { storeGuid }
|
|
1082
|
+
}));
|
|
1083
|
+
window.location.reload();
|
|
1084
|
+
} catch {
|
|
1085
|
+
showError("Impossible de sélectionner ce magasin. Veuillez réessayer.");
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
function handleClick(event) {
|
|
1089
|
+
const target = event.target.closest("[data-action]");
|
|
1090
|
+
if (!target) return;
|
|
1091
|
+
const action = target.dataset.action;
|
|
1092
|
+
switch (action) {
|
|
1093
|
+
case "open-store-picker":
|
|
1094
|
+
openDialog();
|
|
1095
|
+
break;
|
|
1096
|
+
case "close-store-picker":
|
|
1097
|
+
closeDialog();
|
|
1098
|
+
break;
|
|
1099
|
+
case "store-picker-geolocate":
|
|
1100
|
+
void handleGeolocate();
|
|
1101
|
+
break;
|
|
1102
|
+
case "select-store": {
|
|
1103
|
+
const guid = target.dataset.storeGuid;
|
|
1104
|
+
if (guid) void handleSelectStore(guid);
|
|
1105
|
+
break;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
function handleFormSubmit(event) {
|
|
1110
|
+
const form = event.target.closest(FORM_SELECTOR);
|
|
1111
|
+
if (!form) return;
|
|
1112
|
+
event.preventDefault();
|
|
1113
|
+
const input = form.querySelector(INPUT_SELECTOR);
|
|
1114
|
+
const postalCode = input == null ? void 0 : input.value.trim();
|
|
1115
|
+
if (postalCode) void handlePostalCodeSearch(postalCode);
|
|
1116
|
+
}
|
|
1117
|
+
document.addEventListener("click", handleClick);
|
|
1118
|
+
document.addEventListener("submit", handleFormSubmit);
|
|
1119
|
+
return () => {
|
|
1120
|
+
document.removeEventListener("click", handleClick);
|
|
1121
|
+
document.removeEventListener("submit", handleFormSubmit);
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
function fallbackRender(store) {
|
|
1125
|
+
const name = store.label ?? store.code ?? "Magasin";
|
|
1126
|
+
const address = [store.streetAddress, store.postalCode, store.city].filter(Boolean).join(", ");
|
|
1127
|
+
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>`;
|
|
1128
|
+
}
|
|
1129
|
+
function escHtml(str) {
|
|
1130
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1131
|
+
}
|
|
959
1132
|
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';
|
|
960
1133
|
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';
|
|
961
1134
|
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';
|
|
@@ -1041,6 +1214,7 @@ function initAltazionHtmx(config) {
|
|
|
1041
1214
|
registerCartHelpers(handlebars, getCart, defaults);
|
|
1042
1215
|
}
|
|
1043
1216
|
declarativeRenderer.render();
|
|
1217
|
+
const disposeStorePicker = initStorePicker(client, handlebarsRuntime);
|
|
1044
1218
|
const offlineEl = typeof document !== "undefined" ? document.querySelector(offlineSelector) ?? document.body : null;
|
|
1045
1219
|
let lastConnectivityStatus = null;
|
|
1046
1220
|
const updateOfflineClass = () => {
|
|
@@ -1088,6 +1262,7 @@ function initAltazionHtmx(config) {
|
|
|
1088
1262
|
document.removeEventListener("altazion:marketing:items-loaded", syncMarketingItemsFromEvent);
|
|
1089
1263
|
}
|
|
1090
1264
|
declarativeRenderer.dispose();
|
|
1265
|
+
disposeStorePicker();
|
|
1091
1266
|
unsubscribeConnectivity == null ? void 0 : unsubscribeConnectivity();
|
|
1092
1267
|
}
|
|
1093
1268
|
};
|