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