ctt-babylon 0.22.113 → 0.22.115

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.
@@ -7598,7 +7598,7 @@ class BabylonBlogDetailsComponent {
7598
7598
  this.removeJsonLd();
7599
7599
  }
7600
7600
  updateJsonLd() {
7601
- if (!this.title)
7601
+ if (!this.title || typeof window === 'undefined')
7602
7602
  return;
7603
7603
  let lang;
7604
7604
  this.route.url.subscribe((segments) => {
@@ -23912,46 +23912,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
23912
23912
  * - filter -> tipo principal (ej: hoteles, apartamentos, villas, etc.)
23913
23913
  * - destination -> destino (por nombre)
23914
23914
  * - brand -> marca / grupo
23915
+ * - experience -> experiencia asociada
23916
+ * - services -> servicios disponibles
23915
23917
  *
23916
- * CÓMO FUNCIONA
23917
- * -------------
23918
- * 1. Las opciones de filtros se construyen dinámicamente a partir de `items`.
23919
- * 2. Cada opción tiene:
23920
- * - label: texto real mostrado al usuario
23921
- * - slug : versión normalizada usada en la URL
23922
- * 3. Al navegar con query params:
23923
- * - Se leen los slugs de la URL
23924
- * - Se resuelven a labels reales cuando los items están disponibles
23925
- * 4. El filtrado interno SIEMPRE compara por slug (no por texto crudo).
23926
- *
23927
- * NORMALIZACIÓN
23928
- * -------------
23929
- * - Se usa `Utils.toSlug()` para normalizar textos (tildes, espacios, símbolos).
23930
- * - Para el filtro principal (`filter`) se aplica además una singularización genérica
23931
- * (hoteles -> hotel, apartamentos -> apartamento), SIN traducciones ni diccionarios.
23932
- *
23933
- * EXTENDER CON NUEVOS FILTROS
23934
- * --------------------------
23935
- * Para añadir un nuevo filtro (ej: category, experience, rating):
23936
- *
23937
- * 1. Añadir un nuevo queryParam (ej: `category`)
23938
- * 2. Crear:
23939
- * - selectedCategory
23940
- * - categoryOptions
23941
- * - categorySlugToLabel / categoryLabelToSlug
23942
- * 3. Construir opciones en `buildFilterOptions()`
23943
- * 4. Resolver desde URL en `resolvePendingFromMaps()`
23944
- * 5. Aplicar condición en `filteredItems`
23945
- * 6. Sincronizar en `syncQueryParams()`
23946
- *
23947
- * IMPORTANTE
23948
- * ----------
23949
- * - NUNCA comparar por texto directo.
23950
- * - NUNCA meter valores crudos en la URL.
23951
- * - Todo filtro nuevo debe pasar por slug.
23952
- *
23953
- * Con esto el componente es reutilizable entre proyectos,
23954
- * idiomas y configuraciones distintas sin cambios estructurales.
23918
+ * ACTUALIZACIÓN: BÚSQUEDA FACETADA (Faceted Search)
23919
+ * -------------------------------------------------
23920
+ * Ahora el componente actualiza dinámicamente las opciones de los desplegables.
23921
+ * Al seleccionar un filtro, los demás ocultan las opciones que no tendrían resultados
23922
+ * cruzados con la selección actual. Para evitar bloqueos, siempre se mantiene visible
23923
+ * la opción que esté actualmente seleccionada.
23955
23924
  */
23956
23925
  class LisC4TxtDesCtaComponent {
23957
23926
  constructor() {
@@ -23963,15 +23932,22 @@ class LisC4TxtDesCtaComponent {
23963
23932
  this.hideServicesFilter = false;
23964
23933
  this.tagName = 'LisC4TxtDesCta';
23965
23934
  // UI labels seleccionados (lo que se muestra en los selects)
23966
- // En URL se guardan slugs.
23967
- this.selectedHotelType = ''; // => queryParam "filter"
23968
- this.selectedDestination = ''; // => queryParam "destination"
23969
- this.selectedBrand = ''; // => queryParam "brand"
23935
+ this.selectedHotelType = '';
23936
+ this.selectedDestination = '';
23937
+ this.selectedBrand = '';
23970
23938
  this.selectedExperience = '';
23939
+ // Opciones Dinámicas (Las que se muestran en el HTML y se actualizan al filtrar)
23971
23940
  this.hotelTypeOptions = [];
23972
23941
  this.destinationOptions = [];
23973
23942
  this.brandOptions = [];
23974
23943
  this.experienceOptions = [];
23944
+ this.availableServices = [];
23945
+ // Opciones Base (Listas maestras generadas al cargar, nunca se reducen)
23946
+ this.baseHotelTypeOptions = [];
23947
+ this.baseDestinationOptions = [];
23948
+ this.baseBrandOptions = [];
23949
+ this.baseExperienceOptions = [];
23950
+ this.baseAvailableServices = [];
23975
23951
  this.pendingFilterSlug = null;
23976
23952
  this.pendingDestinationSlug = null;
23977
23953
  this.pendingBrandSlug = null;
@@ -23990,7 +23966,6 @@ class LisC4TxtDesCtaComponent {
23990
23966
  this.router = inject(Router);
23991
23967
  this.cdr = inject(ChangeDetectorRef);
23992
23968
  this.isSyncingFromUrl = false;
23993
- this.availableServices = [];
23994
23969
  this.selectedServices = new Set();
23995
23970
  this.isServicesMenuOpen = false;
23996
23971
  }
@@ -24007,8 +23982,6 @@ class LisC4TxtDesCtaComponent {
24007
23982
  this.pendingBrandSlug = params.get('brand');
24008
23983
  this.pendingExperienceSlug = params.get('experience');
24009
23984
  this.resolvePendingFromMaps();
24010
- // Si aún no hay maps (items no llegó), intenta fallback (mantener algo decente)
24011
- // Nota: no navegamos aquí.
24012
23985
  if (!this.selectedHotelType && filterSlug)
24013
23986
  this.selectedHotelType = filterSlug;
24014
23987
  if (!this.selectedDestination && destinationSlug)
@@ -24017,6 +23990,7 @@ class LisC4TxtDesCtaComponent {
24017
23990
  this.selectedBrand = brandSlug;
24018
23991
  if (!this.selectedExperience && experienceSlug)
24019
23992
  this.selectedExperience = experienceSlug;
23993
+ this.updateDynamicOptions(); // Actualiza los listados dinámicos con la hidratación
24020
23994
  this.cdr.markForCheck();
24021
23995
  queueMicrotask(() => (this.isSyncingFromUrl = false));
24022
23996
  });
@@ -24024,7 +23998,6 @@ class LisC4TxtDesCtaComponent {
24024
23998
  ngOnChanges(changes) {
24025
23999
  if (changes['items']) {
24026
24000
  this.buildFilterOptions();
24027
- // rehidrata desde URL ya con maps listos (sin navegar)
24028
24001
  const qp = this.route.snapshot.queryParamMap;
24029
24002
  const filterSlug = qp.get('filter') ?? '';
24030
24003
  const destinationSlug = qp.get('destination') ?? '';
@@ -24039,6 +24012,7 @@ class LisC4TxtDesCtaComponent {
24039
24012
  this.selectedExperience =
24040
24013
  this.experienceSlugToLabel.get(experienceSlug) ?? '';
24041
24014
  this.forceOptionMatch();
24015
+ this.updateDynamicOptions(); // Vuelve a filtrar las opciones según la nueva hidratación
24042
24016
  this.cdr.markForCheck();
24043
24017
  this.cdr.detectChanges();
24044
24018
  queueMicrotask(() => (this.isSyncingFromUrl = false));
@@ -24050,16 +24024,17 @@ class LisC4TxtDesCtaComponent {
24050
24024
  buildFilterOptions() {
24051
24025
  const items = this.items ?? [];
24052
24026
  const experiences = this.experiences ?? [];
24053
- this.hotelTypeOptions = Array.from(new Set(items
24027
+ // Llenamos las listas MAESTRAS
24028
+ this.baseHotelTypeOptions = Array.from(new Set(items
24054
24029
  .map((i) => i?.hoteltype)
24055
24030
  .filter(Boolean)
24056
24031
  .map((v) => v.trim()))).sort((a, b) => a.localeCompare(b));
24057
- this.destinationOptions = Array.from(new Set(items
24032
+ this.baseDestinationOptions = Array.from(new Set(items
24058
24033
  .flatMap((i) => (i?.destinations ?? []).map((d) => d?.name))
24059
24034
  .filter(Boolean)
24060
24035
  .map((v) => v.trim()))).sort((a, b) => a.localeCompare(b));
24061
- this.brandOptions = Array.from(new Set(items.map((i) => this.getItemBrand(i)).filter(Boolean))).sort((a, b) => a.localeCompare(b));
24062
- this.experienceOptions = Array.from(new Set(experiences.map((e) => e.nameIdentifier)?.filter(Boolean))).sort((a, b) => a.localeCompare(b));
24036
+ this.baseBrandOptions = Array.from(new Set(items.map((i) => this.getItemBrand(i)).filter(Boolean))).sort((a, b) => a.localeCompare(b));
24037
+ this.baseExperienceOptions = Array.from(new Set(experiences.map((e) => e.nameIdentifier)?.filter(Boolean))).sort((a, b) => a.localeCompare(b));
24063
24038
  // Reset maps
24064
24039
  this.filterSlugToLabel.clear();
24065
24040
  this.destinationSlugToLabel.clear();
@@ -24069,39 +24044,34 @@ class LisC4TxtDesCtaComponent {
24069
24044
  this.destinationLabelToSlug.clear();
24070
24045
  this.brandLabelToSlug.clear();
24071
24046
  this.experienceLabelToSlug.clear();
24072
- // used sets para sufijos -2 -3...
24073
24047
  const usedFilter = new Set();
24074
24048
  const usedDest = new Set();
24075
24049
  const usedBrand = new Set();
24076
24050
  const usedExperience = new Set();
24077
- // FILTER (query param "filter") => slug CANÓNICO (singular genérico)
24078
- for (const label of this.hotelTypeOptions) {
24051
+ for (const label of this.baseHotelTypeOptions) {
24079
24052
  const base = this.canonicalSlug(label);
24080
24053
  const slug = Utils.uniqueSlug(base, usedFilter);
24081
24054
  this.filterSlugToLabel.set(slug, label);
24082
24055
  this.filterLabelToSlug.set(label, slug);
24083
24056
  }
24084
- // DESTINATIONS
24085
- for (const label of this.destinationOptions) {
24057
+ for (const label of this.baseDestinationOptions) {
24086
24058
  const base = Utils.toSlug(label) || 'destination';
24087
24059
  const slug = Utils.uniqueSlug(base, usedDest);
24088
24060
  this.destinationSlugToLabel.set(slug, label);
24089
24061
  this.destinationLabelToSlug.set(label, slug);
24090
24062
  }
24091
- // BRANDS
24092
- for (const label of this.brandOptions) {
24063
+ for (const label of this.baseBrandOptions) {
24093
24064
  const base = Utils.toSlug(label) || 'brand';
24094
24065
  const slug = Utils.uniqueSlug(base, usedBrand);
24095
24066
  this.brandSlugToLabel.set(slug, label);
24096
24067
  this.brandLabelToSlug.set(label, slug);
24097
24068
  }
24098
- for (const label of this.experienceOptions) {
24069
+ for (const label of this.baseExperienceOptions) {
24099
24070
  const base = Utils.toSlug(label) || 'experience';
24100
24071
  const slug = Utils.uniqueSlug(base, usedExperience);
24101
24072
  this.experienceSlugToLabel.set(slug, label);
24102
24073
  this.experienceLabelToSlug.set(label, slug);
24103
24074
  }
24104
- const allServices = new Set();
24105
24075
  const allServicesNames = new Set();
24106
24076
  const filteredServicesNames = new Set();
24107
24077
  let requestedClasses = [];
@@ -24112,14 +24082,12 @@ class LisC4TxtDesCtaComponent {
24112
24082
  .filter(Boolean);
24113
24083
  }
24114
24084
  items.forEach((it) => {
24115
- // Soportamos camelCase o snake_case según como llegue de la API
24116
24085
  const services = it?.servicesService || it?.services_service;
24117
24086
  if (Array.isArray(services)) {
24118
24087
  services.forEach((s) => {
24119
24088
  if (s?.name) {
24120
24089
  const name = s.name.trim();
24121
24090
  allServicesNames.add(name);
24122
- // Si hay clases solicitadas, validamos contra el atributo 'class'
24123
24091
  if (requestedClasses.length > 0 && s.class) {
24124
24092
  if (requestedClasses.includes(s.class.trim().toLowerCase())) {
24125
24093
  filteredServicesNames.add(name);
@@ -24129,13 +24097,18 @@ class LisC4TxtDesCtaComponent {
24129
24097
  });
24130
24098
  }
24131
24099
  });
24132
- // 3. Decidimos qué lista mostrar
24133
24100
  let finalServices = Array.from(filteredServicesNames);
24134
- // Si no se pasaron clases por Input, o si lo que se pasó NO hizo match con nada, mostramos TODOS
24135
24101
  if (requestedClasses.length === 0 || finalServices.length === 0) {
24136
24102
  finalServices = Array.from(allServicesNames);
24137
24103
  }
24138
- this.availableServices = finalServices.sort((a, b) => a.localeCompare(b));
24104
+ this.baseAvailableServices = finalServices.sort((a, b) => a.localeCompare(b));
24105
+ // Inicializamos las opciones de UI con las maestras y luego filtramos
24106
+ this.hotelTypeOptions = [...this.baseHotelTypeOptions];
24107
+ this.destinationOptions = [...this.baseDestinationOptions];
24108
+ this.brandOptions = [...this.baseBrandOptions];
24109
+ this.experienceOptions = [...this.baseExperienceOptions];
24110
+ this.availableServices = [...this.baseAvailableServices];
24111
+ this.updateDynamicOptions();
24139
24112
  }
24140
24113
  getItemBrand(it) {
24141
24114
  if (this.additional1LikeMarca)
@@ -24143,13 +24116,17 @@ class LisC4TxtDesCtaComponent {
24143
24116
  return (it?.marca ?? it?.brand ?? it?.group ?? '').trim();
24144
24117
  }
24145
24118
  // ----------------------
24146
- // FILTRADO
24119
+ // LÓGICA DE FILTRADO BASE (FACETED SEARCH)
24147
24120
  // ----------------------
24148
- get filteredItems() {
24121
+ /**
24122
+ * Obtiene los items coincidentes excluyendo uno de los filtros.
24123
+ * Es clave para calcular qué opciones deben quedar disponibles en un desplegable
24124
+ * sin que su propia selección previa las borre por completo.
24125
+ */
24126
+ getItemsMatching(excludeFilter) {
24149
24127
  const items = this.items ?? [];
24150
- if (!this.showFilters) {
24128
+ if (!this.showFilters)
24151
24129
  return items;
24152
- }
24153
24130
  let validHotelIdsForExperience = [];
24154
24131
  if (this.selectedExperience && this.experiences) {
24155
24132
  const targetExp = this.experiences.find((e) => e.nameIdentifier === this.selectedExperience);
@@ -24161,25 +24138,29 @@ class LisC4TxtDesCtaComponent {
24161
24138
  const itemHotelType = it?.hoteltype ?? '';
24162
24139
  const itemBrand = this.getItemBrand(it);
24163
24140
  const itemId = it?.id;
24164
- const hotelTypeOk = !this.selectedHotelType ||
24141
+ const hotelTypeOk = excludeFilter === 'hotelType' ||
24142
+ !this.selectedHotelType ||
24165
24143
  this.canonicalSlug(itemHotelType) ===
24166
24144
  this.canonicalSlug(this.selectedHotelType);
24167
- const destinationOk = !this.selectedDestination ||
24145
+ const destinationOk = excludeFilter === 'destination' ||
24146
+ !this.selectedDestination ||
24168
24147
  (it?.destinations ?? []).some((d) => Utils.toSlug(d?.name ?? '') ===
24169
24148
  Utils.toSlug(this.selectedDestination));
24170
- const brandOk = !this.selectedBrand ||
24149
+ const brandOk = excludeFilter === 'brand' ||
24150
+ !this.selectedBrand ||
24171
24151
  Utils.toSlug(itemBrand) === Utils.toSlug(this.selectedBrand);
24172
- const experienceOk = !this.selectedExperience ||
24152
+ const experienceOk = excludeFilter === 'experience' ||
24153
+ !this.selectedExperience ||
24173
24154
  validHotelIdsForExperience.includes(itemId);
24174
- // NUEVA VALIDACIÓN: Verifica que el item tenga TODOS los servicios seleccionados (AND)
24175
- const servicesOk = this.selectedServices.size === 0 ||
24155
+ const servicesOk = excludeFilter === 'services' ||
24156
+ this.selectedServices.size === 0 ||
24176
24157
  Array.from(this.selectedServices).every((selectedSrv) => {
24177
- const itemServices = it?.servicesService;
24158
+ const itemServices = it?.servicesService ||
24159
+ it?.services_service;
24178
24160
  if (!Array.isArray(itemServices))
24179
24161
  return false;
24180
24162
  return itemServices.some((s) => s?.name?.trim() === selectedSrv);
24181
24163
  });
24182
- // Retorna validando también servicesOk
24183
24164
  return (hotelTypeOk &&
24184
24165
  destinationOk &&
24185
24166
  brandOk &&
@@ -24187,35 +24168,93 @@ class LisC4TxtDesCtaComponent {
24187
24168
  servicesOk);
24188
24169
  });
24189
24170
  }
24171
+ get filteredItems() {
24172
+ return this.getItemsMatching('none');
24173
+ }
24174
+ /**
24175
+ * Actualiza los arrays de opciones para ocultar aquellas que devolverían 0 resultados.
24176
+ */
24177
+ updateDynamicOptions() {
24178
+ if (!this.items || this.items.length === 0)
24179
+ return;
24180
+ // -- Destinos --
24181
+ const itemsForDest = this.getItemsMatching('destination');
24182
+ const validDests = new Set(itemsForDest
24183
+ .flatMap((i) => (i?.destinations ?? []).map((d) => d?.name))
24184
+ .filter(Boolean)
24185
+ .map((v) => v.trim()));
24186
+ this.destinationOptions = this.baseDestinationOptions.filter((opt) => validDests.has(opt) || this.selectedDestination === opt);
24187
+ // -- Marcas --
24188
+ const itemsForBrand = this.getItemsMatching('brand');
24189
+ const validBrands = new Set(itemsForBrand.map((i) => this.getItemBrand(i)).filter(Boolean));
24190
+ this.brandOptions = this.baseBrandOptions.filter((opt) => validBrands.has(opt) || this.selectedBrand === opt);
24191
+ // -- Tipos de Hotel --
24192
+ const itemsForHotelType = this.getItemsMatching('hotelType');
24193
+ const validHotelTypes = new Set(itemsForHotelType
24194
+ .map((i) => i?.hoteltype)
24195
+ .filter(Boolean)
24196
+ .map((v) => v.trim()));
24197
+ this.hotelTypeOptions = this.baseHotelTypeOptions.filter((opt) => validHotelTypes.has(opt) || this.selectedHotelType === opt);
24198
+ // -- Experiencias --
24199
+ const itemsForExp = this.getItemsMatching('experience');
24200
+ const validExpIds = new Set(itemsForExp.map((i) => i?.id));
24201
+ this.experienceOptions = this.baseExperienceOptions.filter((opt) => {
24202
+ if (this.selectedExperience === opt)
24203
+ return true;
24204
+ const targetExp = this.experiences?.find((e) => e.nameIdentifier === opt);
24205
+ if (!targetExp?.hotels)
24206
+ return false;
24207
+ return targetExp.hotels.some((h) => validExpIds.has(h.id));
24208
+ });
24209
+ // -- Servicios --
24210
+ const itemsForServices = this.getItemsMatching('services');
24211
+ const validServices = new Set();
24212
+ itemsForServices.forEach((it) => {
24213
+ const services = it?.servicesService || it?.services_service;
24214
+ if (Array.isArray(services)) {
24215
+ services.forEach((s) => {
24216
+ if (s?.name) {
24217
+ validServices.add(s.name.trim());
24218
+ }
24219
+ });
24220
+ }
24221
+ });
24222
+ this.availableServices = this.baseAvailableServices.filter((opt) => validServices.has(opt) || this.selectedServices.has(opt));
24223
+ }
24190
24224
  get hasActiveFilters() {
24191
24225
  return !!(this.selectedHotelType ||
24192
24226
  this.selectedDestination ||
24193
24227
  this.selectedBrand ||
24194
- this.selectedExperience);
24228
+ this.selectedExperience ||
24229
+ this.selectedServices.size > 0);
24195
24230
  }
24196
24231
  // ----------------------
24197
24232
  // HANDLERS UI
24198
24233
  // ----------------------
24199
24234
  onHotelTypeChange(value) {
24200
24235
  this.selectedHotelType = value ?? '';
24236
+ this.updateDynamicOptions();
24201
24237
  if (this.isSyncingFromUrl)
24202
24238
  return;
24203
24239
  this.syncQueryParams();
24204
24240
  }
24205
24241
  onDestinationChange(value) {
24206
24242
  this.selectedDestination = value ?? '';
24243
+ this.updateDynamicOptions();
24207
24244
  if (this.isSyncingFromUrl)
24208
24245
  return;
24209
24246
  this.syncQueryParams();
24210
24247
  }
24211
24248
  onBrandChange(value) {
24212
24249
  this.selectedBrand = value ?? '';
24250
+ this.updateDynamicOptions();
24213
24251
  if (this.isSyncingFromUrl)
24214
24252
  return;
24215
24253
  this.syncQueryParams();
24216
24254
  }
24217
24255
  onExperienceChange(value) {
24218
24256
  this.selectedExperience = value ?? '';
24257
+ this.updateDynamicOptions();
24219
24258
  if (this.isSyncingFromUrl)
24220
24259
  return;
24221
24260
  this.syncQueryParams();
@@ -24226,6 +24265,7 @@ class LisC4TxtDesCtaComponent {
24226
24265
  this.selectedBrand = '';
24227
24266
  this.selectedExperience = '';
24228
24267
  this.selectedServices.clear();
24268
+ this.updateDynamicOptions();
24229
24269
  this.syncQueryParams(true);
24230
24270
  }
24231
24271
  toggleService(service) {
@@ -24237,6 +24277,8 @@ class LisC4TxtDesCtaComponent {
24237
24277
  newSelected.add(service);
24238
24278
  }
24239
24279
  this.selectedServices = newSelected;
24280
+ this.updateDynamicOptions();
24281
+ // Nota: Servicios no se sincan con URL históricamente, pero re-evaluamos dinámicamente.
24240
24282
  }
24241
24283
  toggleServicesMenu() {
24242
24284
  this.isServicesMenuOpen = !this.isServicesMenuOpen;
@@ -24246,7 +24288,7 @@ class LisC4TxtDesCtaComponent {
24246
24288
  // ----------------------
24247
24289
  syncQueryParams(clearAll = false) {
24248
24290
  const qp = clearAll
24249
- ? { filter: null, destination: null, brand: null }
24291
+ ? { filter: null, destination: null, brand: null, experience: null }
24250
24292
  : {
24251
24293
  filter: this.selectedHotelType
24252
24294
  ? (this.filterLabelToSlug.get(this.selectedHotelType) ??
@@ -24270,29 +24312,20 @@ class LisC4TxtDesCtaComponent {
24270
24312
  });
24271
24313
  this.cdr.markForCheck();
24272
24314
  }
24273
- // ----------------------
24274
- // CANONICAL SLUG (sin traductor)
24275
- // - Garantiza singular/plural genérico
24276
- // ----------------------
24277
24315
  canonicalSlug(value) {
24278
24316
  let s = Utils.toSlug(value);
24279
24317
  if (!s)
24280
24318
  return '';
24281
- // Regla -es (hoteles -> hotel, luces -> luz, peces -> pez)
24282
24319
  if (s.length > 3 && s.endsWith('es')) {
24283
24320
  const base = s.slice(0, -2);
24284
24321
  if (base.endsWith('c'))
24285
24322
  return base.slice(0, -1) + 'z';
24286
24323
  return base;
24287
24324
  }
24288
- // Regla -s (apartamentos -> apartamento)
24289
24325
  if (s.length > 3 && s.endsWith('s'))
24290
24326
  return s.slice(0, -1);
24291
24327
  return s;
24292
24328
  }
24293
- // ----------------------
24294
- // UI utils
24295
- // ----------------------
24296
24329
  getKeysArray(count) {
24297
24330
  return count ? Array.from({ length: count }) : [];
24298
24331
  }
@@ -24318,7 +24351,6 @@ class LisC4TxtDesCtaComponent {
24318
24351
  this.pendingFilterSlug = null;
24319
24352
  }
24320
24353
  }
24321
- // DESTINATION
24322
24354
  if (this.pendingDestinationSlug != null) {
24323
24355
  const slug = Utils.toSlug(this.pendingDestinationSlug);
24324
24356
  const label = this.destinationSlugToLabel.get(slug);
@@ -24327,7 +24359,6 @@ class LisC4TxtDesCtaComponent {
24327
24359
  this.pendingDestinationSlug = null;
24328
24360
  }
24329
24361
  }
24330
- // BRAND
24331
24362
  if (this.pendingBrandSlug != null) {
24332
24363
  const slug = Utils.toSlug(this.pendingBrandSlug);
24333
24364
  const label = this.brandSlugToLabel.get(slug);
@@ -24336,7 +24367,6 @@ class LisC4TxtDesCtaComponent {
24336
24367
  this.pendingBrandSlug = null;
24337
24368
  }
24338
24369
  }
24339
- //EXPERIENCES
24340
24370
  if (this.pendingExperienceSlug != null) {
24341
24371
  const slug = Utils.toSlug(this.pendingExperienceSlug);
24342
24372
  const label = this.experienceSlugToLabel.get(slug);
@@ -24349,46 +24379,40 @@ class LisC4TxtDesCtaComponent {
24349
24379
  forceOptionMatch() {
24350
24380
  if (this.selectedHotelType) {
24351
24381
  const wanted = this.canonicalSlug(this.selectedHotelType);
24352
- const match = this.hotelTypeOptions.find((o) => this.canonicalSlug(o) === wanted);
24382
+ const match = this.baseHotelTypeOptions.find((o) => this.canonicalSlug(o) === wanted);
24353
24383
  this.selectedHotelType = match ?? '';
24354
24384
  }
24355
24385
  if (this.selectedBrand) {
24356
24386
  const wanted = Utils.toSlug(this.selectedBrand);
24357
- const match = this.brandOptions.find((o) => Utils.toSlug(o) === wanted);
24387
+ const match = this.baseBrandOptions.find((o) => Utils.toSlug(o) === wanted);
24358
24388
  this.selectedBrand = match ?? '';
24359
24389
  }
24360
24390
  if (this.selectedDestination) {
24361
24391
  const wanted = Utils.toSlug(this.selectedDestination);
24362
- const match = this.destinationOptions.find((o) => Utils.toSlug(o) === wanted);
24392
+ const match = this.baseDestinationOptions.find((o) => Utils.toSlug(o) === wanted);
24363
24393
  this.selectedDestination = match ?? '';
24364
24394
  }
24365
24395
  if (this.selectedExperience) {
24366
24396
  const wanted = Utils.toSlug(this.selectedExperience);
24367
- const match = this.experienceOptions.find((o) => Utils.toSlug(o) === wanted);
24397
+ const match = this.baseExperienceOptions.find((o) => Utils.toSlug(o) === wanted);
24368
24398
  this.selectedExperience = match ?? '';
24369
24399
  }
24370
24400
  }
24371
24401
  getButtonUrl(btn, item, index) {
24372
24402
  const urlBase = btn.url || '';
24373
- // Si no es el primer botón, devolvemos la URL base sin alterar
24374
24403
  if (index !== 0) {
24375
24404
  return urlBase;
24376
24405
  }
24377
- // Buscamos el identificador (priorizamos nameIdentifier, luego name para destinos)
24378
24406
  const identifier = item?.nameIdentifier ?? item?.name_identifier ?? item?.name;
24379
24407
  if (!identifier) {
24380
24408
  return urlBase;
24381
24409
  }
24382
24410
  const separator = urlBase.includes('?') ? '&' : '?';
24383
- // 1. Lógica para EXPERIENCIAS
24384
- // Entra si el type es 'experience' o si tiene un nameIdentifier pero no tiene type (fallback)
24385
24411
  if (item?.type === 'experience' ||
24386
24412
  (!item?.type && (item?.nameIdentifier || item?.name_identifier))) {
24387
24413
  return `${urlBase}${separator}experience=${identifier}`;
24388
24414
  }
24389
- // 2. Lógica para DESTINOS
24390
24415
  if (item?.type === 'destination') {
24391
- // Usamos tu Utils para normalizar espacios y mayúsculas (ej: "Andorra la Vella" -> "andorra-la-vella")
24392
24416
  const destinationSlug = Utils.toSlug(identifier);
24393
24417
  return `${urlBase}${separator}destination=${destinationSlug}`;
24394
24418
  }