@altazion/commerce-sdk-htmx 26.618.8367 → 26.619.8377

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.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 radiusKm = payload.radiusKm === void 0 ? 50 : requireNumber(payload.radiusKm, "radiusKm");
660
- return client.stores.findByLocation(latitude, longitude, radiusKm);
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
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
  };