valtech-components 4.0.150 → 4.0.152

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.
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
56
56
  * Current version of valtech-components.
57
57
  * This is automatically updated during the publish process.
58
58
  */
59
- const VERSION = '4.0.150';
59
+ const VERSION = '4.0.152';
60
60
 
61
61
  // Control de estado de refresco (singleton a nivel de módulo)
62
62
  let isRefreshing = false;
@@ -1789,6 +1789,7 @@ class ToastService {
1789
1789
  duration: request.duration,
1790
1790
  position: request.position ?? 'top',
1791
1791
  color: request.color ?? 'dark',
1792
+ buttons: request.buttons,
1792
1793
  });
1793
1794
  await toast.present();
1794
1795
  }
@@ -1883,7 +1884,7 @@ class ValtechErrorService {
1883
1884
  */
1884
1885
  handle(err, opts = {}) {
1885
1886
  const interpreted = interpretError(err);
1886
- const { context, i18nMap, fallbackKey, i18nNamespace, toast } = opts;
1887
+ const { context, i18nMap, fallbackKey, i18nNamespace, toast, showOperationId } = opts;
1887
1888
  // 1. Observabilidad — log estructurado a consola.
1888
1889
  console.error('[ValtechError] handled', {
1889
1890
  context: context ?? 'n/a',
@@ -1917,11 +1918,23 @@ class ValtechErrorService {
1917
1918
  });
1918
1919
  // 4. Toast (estándar Valtech: color 'dark', position 'top').
1919
1920
  if (toast !== false) {
1921
+ const opId = showOperationId ? interpreted.operationId : undefined;
1920
1922
  this.toast.show({
1921
1923
  message,
1922
1924
  color: 'dark',
1923
1925
  position: 'top',
1924
- duration: 3000,
1926
+ // Más tiempo cuando hay botón de copia — el usuario necesita leerlo y tapear.
1927
+ duration: opId ? 6000 : 3000,
1928
+ buttons: opId
1929
+ ? [
1930
+ {
1931
+ text: 'Copiar ID',
1932
+ handler: () => {
1933
+ void navigator.clipboard.writeText(opId);
1934
+ },
1935
+ },
1936
+ ]
1937
+ : undefined,
1925
1938
  });
1926
1939
  }
1927
1940
  // 5. Devolver el error normalizado para lógica extra del caller.
@@ -60059,18 +60072,18 @@ class PageContentComponent {
60059
60072
  '--background': getBackground(),
60060
60073
  }"
60061
60074
  >
60062
- <!-- Pull-to-refresh: visible solo si la página activa registró un handler
60063
- vía PageRefreshService (connectPageRefresh). ion-refresher slot="fixed"
60064
- DEBE ser hijo directo de ion-content. Mismo patrón que val-page-wrapper,
60065
- para que las vistas públicas (seller, buy, live) también lo tengan. -->
60066
- @if (pageRefresh.hasHandler()) {
60067
- <ion-refresher slot="fixed" (ionRefresh)="onPageRefresh($event)">
60068
- <ion-refresher-content
60069
- pullingIcon="chevron-down-circle-outline"
60070
- refreshingSpinner="circular"
60071
- ></ion-refresher-content>
60072
- </ion-refresher>
60073
- }
60075
+ <!-- Pull-to-refresh para las vistas públicas (seller, buy, live) que usan
60076
+ val-page-content y llaman connectPageRefresh. El ion-refresher SIEMPRE
60077
+ está en el DOM (hijo directo de ion-content) para que Ionic lo enganche
60078
+ en la init del scroll; se HABILITA solo cuando hay handler registrado.
60079
+ Con @if el refresher aparecía tarde (contenido proyectado vía ng-content,
60080
+ no router-outlet) y Ionic no lo reconocía → el gesto no disparaba. -->
60081
+ <ion-refresher slot="fixed" [disabled]="!pageRefresh.hasHandler()" (ionRefresh)="onPageRefresh($event)">
60082
+ <ion-refresher-content
60083
+ pullingIcon="chevron-down-circle-outline"
60084
+ refreshingSpinner="circular"
60085
+ ></ion-refresher-content>
60086
+ </ion-refresher>
60074
60087
  @if (showUpdateBanner) {
60075
60088
  <val-update-banner />
60076
60089
  }
@@ -60096,18 +60109,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
60096
60109
  '--background': getBackground(),
60097
60110
  }"
60098
60111
  >
60099
- <!-- Pull-to-refresh: visible solo si la página activa registró un handler
60100
- vía PageRefreshService (connectPageRefresh). ion-refresher slot="fixed"
60101
- DEBE ser hijo directo de ion-content. Mismo patrón que val-page-wrapper,
60102
- para que las vistas públicas (seller, buy, live) también lo tengan. -->
60103
- @if (pageRefresh.hasHandler()) {
60104
- <ion-refresher slot="fixed" (ionRefresh)="onPageRefresh($event)">
60105
- <ion-refresher-content
60106
- pullingIcon="chevron-down-circle-outline"
60107
- refreshingSpinner="circular"
60108
- ></ion-refresher-content>
60109
- </ion-refresher>
60110
- }
60112
+ <!-- Pull-to-refresh para las vistas públicas (seller, buy, live) que usan
60113
+ val-page-content y llaman connectPageRefresh. El ion-refresher SIEMPRE
60114
+ está en el DOM (hijo directo de ion-content) para que Ionic lo enganche
60115
+ en la init del scroll; se HABILITA solo cuando hay handler registrado.
60116
+ Con @if el refresher aparecía tarde (contenido proyectado vía ng-content,
60117
+ no router-outlet) y Ionic no lo reconocía → el gesto no disparaba. -->
60118
+ <ion-refresher slot="fixed" [disabled]="!pageRefresh.hasHandler()" (ionRefresh)="onPageRefresh($event)">
60119
+ <ion-refresher-content
60120
+ pullingIcon="chevron-down-circle-outline"
60121
+ refreshingSpinner="circular"
60122
+ ></ion-refresher-content>
60123
+ </ion-refresher>
60111
60124
  @if (showUpdateBanner) {
60112
60125
  <val-update-banner />
60113
60126
  }
@@ -69934,20 +69947,24 @@ class TicketCardComponent {
69934
69947
  }
69935
69948
  </div>
69936
69949
 
69937
- @if (props().showDownload && qr()) {
69938
- <ion-button fill="clear" size="small" [disabled]="downloading()" (click)="downloadCard()">
69939
- <ion-icon name="download-outline" slot="start" />
69940
- {{ props().downloadLabel || t('download') }}
69941
- </ion-button>
69942
- }
69943
- @if (props().showShare && qr()) {
69944
- <ion-button fill="clear" size="small" [disabled]="sharing()" (click)="shareCard()">
69945
- <ion-icon name="share-outline" slot="start" />
69946
- {{ props().shareLabel || t('share') }}
69947
- </ion-button>
69950
+ @if ((props().showDownload || props().showShare) && qr()) {
69951
+ <div class="ticket-card__actions">
69952
+ @if (props().showDownload) {
69953
+ <ion-button fill="outline" expand="block" [disabled]="downloading()" (click)="downloadCard()">
69954
+ <ion-icon name="download-outline" slot="start" />
69955
+ {{ props().downloadLabel || t('download') }}
69956
+ </ion-button>
69957
+ }
69958
+ @if (props().showShare) {
69959
+ <ion-button fill="outline" expand="block" [disabled]="sharing()" (click)="shareCard()">
69960
+ <ion-icon name="share-outline" slot="start" />
69961
+ {{ props().shareLabel || t('share') }}
69962
+ </ion-button>
69963
+ }
69964
+ </div>
69948
69965
  }
69949
69966
  </div>
69950
- `, isInline: true, styles: ["@charset \"UTF-8\";:host{display:block}.ticket-card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px;border:1px solid var(--ion-color-light-shade, #e0e0e0);border-radius:16px;background:var(--ion-card-background, #ffffff);max-width:320px;margin:0 auto}.ticket-card__title{font-size:1rem;font-weight:700;color:var(--ion-color-dark);text-align:center}.ticket-card__qr{display:flex;align-items:center;justify-content:center;min-height:200px}.ticket-card__qr-loading{display:flex;align-items:center;justify-content:center;width:200px;height:200px}.ticket-card__qr-fallback{font-family:monospace;font-size:.75rem;color:var(--ion-color-medium);word-break:break-all;text-align:center;padding:16px}.ticket-card__meta{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}.ticket-card__folio{font-size:1rem;font-weight:700;color:var(--ion-color-dark)}.ticket-card__buyer{font-size:.875rem;color:var(--ion-color-medium)}.ticket-card__badge{margin-top:4px;font-size:.75rem;font-weight:600;padding:3px 12px;border-radius:999px;background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff);white-space:nowrap}.ticket-card__badge[data-status=sold]{background:var(--ion-color-success, #2dd36f);color:var(--ion-color-success-contrast, #fff)}.ticket-card__badge[data-status=checkedIn]{background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: QrCodeComponent, selector: "val-qr-code", inputs: ["props"], outputs: ["actionComplete", "imageLoad", "imageError"] }] }); }
69967
+ `, isInline: true, styles: ["@charset \"UTF-8\";:host{display:block}.ticket-card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px;border:1px solid var(--ion-color-light-shade, #e0e0e0);border-radius:16px;background:var(--ion-card-background, #ffffff);max-width:320px;margin:0 auto}.ticket-card__title{font-size:1rem;font-weight:700;color:var(--ion-color-dark);text-align:center}.ticket-card__qr{display:flex;align-items:center;justify-content:center;min-height:200px}.ticket-card__qr-loading{display:flex;align-items:center;justify-content:center;width:200px;height:200px}.ticket-card__qr-fallback{font-family:monospace;font-size:.75rem;color:var(--ion-color-medium);word-break:break-all;text-align:center;padding:16px}.ticket-card__meta{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}.ticket-card__folio{font-size:1rem;font-weight:700;color:var(--ion-color-dark)}.ticket-card__buyer{font-size:.875rem;color:var(--ion-color-medium)}.ticket-card__badge{margin-top:4px;font-size:.75rem;font-weight:600;padding:3px 12px;border-radius:999px;background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff);white-space:nowrap}.ticket-card__badge[data-status=sold]{background:var(--ion-color-success, #2dd36f);color:var(--ion-color-success-contrast, #fff)}.ticket-card__badge[data-status=checkedIn]{background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff)}.ticket-card__actions{width:100%;display:flex;flex-direction:column;gap:8px}.ticket-card__actions ion-button{--border-radius: 10px;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: QrCodeComponent, selector: "val-qr-code", inputs: ["props"], outputs: ["actionComplete", "imageLoad", "imageError"] }] }); }
69951
69968
  }
69952
69969
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TicketCardComponent, decorators: [{
69953
69970
  type: Component,
@@ -69981,20 +69998,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
69981
69998
  }
69982
69999
  </div>
69983
70000
 
69984
- @if (props().showDownload && qr()) {
69985
- <ion-button fill="clear" size="small" [disabled]="downloading()" (click)="downloadCard()">
69986
- <ion-icon name="download-outline" slot="start" />
69987
- {{ props().downloadLabel || t('download') }}
69988
- </ion-button>
69989
- }
69990
- @if (props().showShare && qr()) {
69991
- <ion-button fill="clear" size="small" [disabled]="sharing()" (click)="shareCard()">
69992
- <ion-icon name="share-outline" slot="start" />
69993
- {{ props().shareLabel || t('share') }}
69994
- </ion-button>
70001
+ @if ((props().showDownload || props().showShare) && qr()) {
70002
+ <div class="ticket-card__actions">
70003
+ @if (props().showDownload) {
70004
+ <ion-button fill="outline" expand="block" [disabled]="downloading()" (click)="downloadCard()">
70005
+ <ion-icon name="download-outline" slot="start" />
70006
+ {{ props().downloadLabel || t('download') }}
70007
+ </ion-button>
70008
+ }
70009
+ @if (props().showShare) {
70010
+ <ion-button fill="outline" expand="block" [disabled]="sharing()" (click)="shareCard()">
70011
+ <ion-icon name="share-outline" slot="start" />
70012
+ {{ props().shareLabel || t('share') }}
70013
+ </ion-button>
70014
+ }
70015
+ </div>
69995
70016
  }
69996
70017
  </div>
69997
- `, styles: ["@charset \"UTF-8\";:host{display:block}.ticket-card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px;border:1px solid var(--ion-color-light-shade, #e0e0e0);border-radius:16px;background:var(--ion-card-background, #ffffff);max-width:320px;margin:0 auto}.ticket-card__title{font-size:1rem;font-weight:700;color:var(--ion-color-dark);text-align:center}.ticket-card__qr{display:flex;align-items:center;justify-content:center;min-height:200px}.ticket-card__qr-loading{display:flex;align-items:center;justify-content:center;width:200px;height:200px}.ticket-card__qr-fallback{font-family:monospace;font-size:.75rem;color:var(--ion-color-medium);word-break:break-all;text-align:center;padding:16px}.ticket-card__meta{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}.ticket-card__folio{font-size:1rem;font-weight:700;color:var(--ion-color-dark)}.ticket-card__buyer{font-size:.875rem;color:var(--ion-color-medium)}.ticket-card__badge{margin-top:4px;font-size:.75rem;font-weight:600;padding:3px 12px;border-radius:999px;background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff);white-space:nowrap}.ticket-card__badge[data-status=sold]{background:var(--ion-color-success, #2dd36f);color:var(--ion-color-success-contrast, #fff)}.ticket-card__badge[data-status=checkedIn]{background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff)}\n"] }]
70018
+ `, styles: ["@charset \"UTF-8\";:host{display:block}.ticket-card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px;border:1px solid var(--ion-color-light-shade, #e0e0e0);border-radius:16px;background:var(--ion-card-background, #ffffff);max-width:320px;margin:0 auto}.ticket-card__title{font-size:1rem;font-weight:700;color:var(--ion-color-dark);text-align:center}.ticket-card__qr{display:flex;align-items:center;justify-content:center;min-height:200px}.ticket-card__qr-loading{display:flex;align-items:center;justify-content:center;width:200px;height:200px}.ticket-card__qr-fallback{font-family:monospace;font-size:.75rem;color:var(--ion-color-medium);word-break:break-all;text-align:center;padding:16px}.ticket-card__meta{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}.ticket-card__folio{font-size:1rem;font-weight:700;color:var(--ion-color-dark)}.ticket-card__buyer{font-size:.875rem;color:var(--ion-color-medium)}.ticket-card__badge{margin-top:4px;font-size:.75rem;font-weight:600;padding:3px 12px;border-radius:999px;background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff);white-space:nowrap}.ticket-card__badge[data-status=sold]{background:var(--ion-color-success, #2dd36f);color:var(--ion-color-success-contrast, #fff)}.ticket-card__badge[data-status=checkedIn]{background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff)}.ticket-card__actions{width:100%;display:flex;flex-direction:column;gap:8px}.ticket-card__actions ion-button{--border-radius: 10px;margin:0}\n"] }]
69998
70019
  }], ctorParameters: () => [] });
69999
70020
 
70000
70021
  /**