valtech-components 4.0.988 → 4.0.990

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.
Files changed (29) hide show
  1. package/esm2022/lib/components/organisms/attachment-uploader/attachment-uploader.component.mjs +41 -2
  2. package/esm2022/lib/components/organisms/attachment-uploader/types.mjs +1 -1
  3. package/esm2022/lib/components/organisms/request-review-panel/request-review-panel.component.mjs +316 -481
  4. package/esm2022/lib/components/organisms/request-review-panel/request-review-panel.i18n.mjs +21 -0
  5. package/esm2022/lib/components/organisms/request-review-panel/types.mjs +2 -0
  6. package/esm2022/lib/components/organisms/survey-builder/survey-builder.component.mjs +24 -5
  7. package/esm2022/lib/components/organisms/survey-builder/types.mjs +1 -1
  8. package/esm2022/lib/services/payments/config.mjs +23 -0
  9. package/esm2022/lib/services/payments/index.mjs +4 -0
  10. package/esm2022/lib/services/payments/payments-gateway.service.mjs +69 -0
  11. package/esm2022/lib/services/payments/types.mjs +8 -0
  12. package/esm2022/lib/version.mjs +2 -2
  13. package/esm2022/public-api.mjs +4 -2
  14. package/fesm2022/valtech-components.mjs +793 -784
  15. package/fesm2022/valtech-components.mjs.map +1 -1
  16. package/lib/components/organisms/attachment-uploader/attachment-uploader.component.d.ts +14 -0
  17. package/lib/components/organisms/attachment-uploader/types.d.ts +30 -0
  18. package/lib/components/organisms/request-review-panel/request-review-panel.component.d.ts +72 -76
  19. package/lib/components/organisms/request-review-panel/request-review-panel.i18n.d.ts +2 -0
  20. package/lib/components/organisms/request-review-panel/types.d.ts +73 -0
  21. package/lib/components/organisms/survey-builder/survey-builder.component.d.ts +9 -2
  22. package/lib/components/organisms/survey-builder/types.d.ts +28 -1
  23. package/lib/services/payments/config.d.ts +14 -0
  24. package/lib/services/payments/index.d.ts +3 -0
  25. package/lib/services/payments/payments-gateway.service.d.ts +53 -0
  26. package/lib/services/payments/types.d.ts +33 -0
  27. package/lib/version.d.ts +1 -1
  28. package/package.json +1 -1
  29. package/public-api.d.ts +3 -1
@@ -9,6 +9,7 @@ export declare class AttachmentUploaderComponent implements OnInit {
9
9
  attachmentsChange: import("@angular/core").OutputEmitterRef<AttachmentItem[]>;
10
10
  protected i18n: I18nService;
11
11
  private feedbackService;
12
+ private imageService;
12
13
  attachments: import("@angular/core").WritableSignal<AttachmentItem[]>;
13
14
  showCameraOverlay: import("@angular/core").WritableSignal<boolean>;
14
15
  private cameraStream;
@@ -26,6 +27,19 @@ export declare class AttachmentUploaderComponent implements OnInit {
26
27
  onFilesSelected(event: Event): Promise<void>;
27
28
  private processFiles;
28
29
  private compressImage;
30
+ /**
31
+ * Genera y sube la miniatura de una imagen ya comprimida.
32
+ *
33
+ * Recibe el archivo COMPRIMIDO a propósito: `compressorjs` ya normalizó la
34
+ * orientación EXIF, y `ImageService` trabaja sobre canvas sin leer EXIF — si
35
+ * se le pasara el original, las fotos verticales de teléfono saldrían
36
+ * rotadas. Ver la nota en `generateThumbnail` (types.ts).
37
+ *
38
+ * Nunca es fatal: si falla, el adjunto queda subido sin miniatura y las
39
+ * listas caen al archivo grande. Perder la miniatura no justifica perder la
40
+ * foto que el usuario acaba de subir.
41
+ */
42
+ private uploadThumbnail;
29
43
  private uploadFile;
30
44
  remove(id: string): void;
31
45
  thumbFailed(id: string): void;
@@ -3,6 +3,13 @@ export interface AttachmentItem {
3
3
  file?: File;
4
4
  status: 'uploading' | 'ready' | 'error';
5
5
  url?: string;
6
+ /**
7
+ * URL de la miniatura, presente solo si se pidió `generateThumbnail` y el
8
+ * archivo es una imagen. Es la que deben usar las LISTAS: `url` apunta al
9
+ * archivo de hasta 1920px, y pedirlo para pintar un recuadro de 84px es la
10
+ * diferencia entre 240KB y 15KB por fila. Ver `generateThumbnail`.
11
+ */
12
+ thumbnailUrl?: string;
6
13
  error?: string;
7
14
  isExternal?: boolean;
8
15
  }
@@ -16,6 +23,29 @@ export interface AttachmentUploaderMetadata {
16
23
  disabled?: boolean;
17
24
  /** Compress images before upload (default: true). PDFs are never compressed. */
18
25
  compressImages?: boolean;
26
+ /**
27
+ * Genera y sube además una miniatura cuadrada por cada imagen, y la expone en
28
+ * `AttachmentItem.thumbnailUrl` (default: false).
29
+ *
30
+ * Por qué es opt-in y no el default: sube DOS archivos por imagen en vez de
31
+ * uno, y no todo consumer quiere pagar ese costo (ni tener el archivo extra
32
+ * en su bucket). Actívalo cuando las fotos se muestren en una lista o grilla,
33
+ * que es donde el ahorro es real.
34
+ *
35
+ * La miniatura se genera a partir del archivo YA comprimido, no del original:
36
+ * `compressorjs` normaliza la orientación EXIF al comprimir, así que a esa
37
+ * altura la imagen ya está derecha. Generarla del original la sacaría rotada
38
+ * en las fotos verticales de teléfono (ImageService usa canvas y no lee EXIF).
39
+ */
40
+ generateThumbnail?: boolean;
41
+ /** Lado de la miniatura en píxeles (default: 320). Cuadrada, recorte centrado. */
42
+ thumbnailSize?: number;
43
+ /**
44
+ * Función de subida de la miniatura. Si se omite, se usa `uploadFn` con un
45
+ * File renombrado a `<nombre>-thumb.jpg` — así el consumer que deriva la ruta
46
+ * del nombre del archivo no necesita hacer nada.
47
+ */
48
+ thumbnailUploadFn?: (file: File) => Promise<string>;
19
49
  /** Upload function. If omitted, falls back to FeedbackService.uploadAttachment. */
20
50
  uploadFn?: (file: File) => Promise<string>;
21
51
  /** URLs de items ya subidos — se pre-seedean como items 'ready' al montar. */
@@ -1,83 +1,79 @@
1
- import { OnInit } from '@angular/core';
2
- import { AppRequest, RequestComment } from '../../../services/requests/types';
3
- import { EmptyStateMetadata } from '../../molecules/empty-state/types';
1
+ import { EventEmitter, TemplateRef } from '@angular/core';
2
+ import { ComponentState } from '../../types';
3
+ import { RequestReviewDecision, RequestReviewItem, RequestReviewPanelMetadata } from './types';
4
4
  import * as i0 from "@angular/core";
5
- interface StatusStyle {
6
- bg: string;
7
- color: string;
8
- }
9
- /**
10
- * Config del "entity hero" (bloque opcional arriba del status: ej. animal en
11
- * Chesed, receta en Mealplan). Agnóstico al dominio — cada app declara de qué
12
- * campos de `metadata` sacar nombre/imagen y a dónde navegar.
13
- */
14
- export interface RequestReviewEntityHeroConfig {
15
- labelKey: string;
16
- nameField: string;
17
- imageField?: string;
18
- placeholderIcon?: string;
19
- canNavigate: (metadata: Record<string, any>) => boolean;
20
- navigate: (metadata: Record<string, any>) => void;
21
- }
22
- export interface RequestReviewPanelConfig {
23
- /** Namespace i18n donde viven las keys (status_*, approve, reject, submitter, fields, commentsTitle, noComments, submittedAt, statusUpdated, statusError, errorTitle, offlineTitle, offlineHint, retry, viewAnimal). */
24
- i18nNamespace: string;
25
- entityHero?: RequestReviewEntityHeroConfig;
26
- /** Si el usuario actual puede aprobar/rechazar (ej. persona.isPublisher()). */
27
- canReview: () => boolean;
28
- /** CTA post-aprobación para quien NO revisa (ej. "ver receta"/"ver animal"). */
29
- viewEntityCtaLabelKey?: string;
30
- }
31
5
  /**
32
- * Panel de revisión de una Request genérica (ADR-061/062): status + acciones
33
- * approve/reject + fields del formulario + comentarios. Config-driven, sin
34
- * conocimiento del dominio (adoption, recipe_verification, etc.) — cada
35
- * consumer inyecta su `RequestReviewPanelConfig`.
6
+ * val-request-review-panel cola de revisión del factory (ADR-062).
7
+ *
8
+ * Es **presentacional**: no carga datos, no conoce el backend ni el dominio. El
9
+ * consumer le pasa la cola ya normalizada y escucha `(decision)`.
10
+ *
11
+ * ## Por qué el cuerpo va proyectado y no configurado
12
+ *
13
+ * El ADR original proponía describir el cuerpo con arrays de nombres de campo
14
+ * (`fields.display: ['taxId', 'tagsRequested']`). Al implementarlo con los dos
15
+ * consumidores reales delante quedó claro que eso reinventa un motor de
16
+ * templating peor que Angular: Chesed necesita una lista de documentos con
17
+ * iconos y `target="_blank"`, Okhelia un enlace a la receta y un input de
18
+ * comentario. Ninguna lista de strings expresa eso sin agregarle un flag al
19
+ * componente por cada caso nuevo.
20
+ *
21
+ * Entonces el panel es dueño de lo que **de verdad** se repite — la cáscara, el
22
+ * chrome de la card, y la mecánica de decisión — y el cuerpo de cada ítem lo
23
+ * escribe cada vertical en un `ng-template` con su propio HTML.
24
+ *
25
+ * ```html
26
+ * <val-request-review-panel [props]="panelProps()" [itemBody]="body"
27
+ * (decision)="onDecision($event)" />
28
+ *
29
+ * <ng-template #body let-item>
30
+ * <a [routerLink]="['/app/recetas', recipeIdOf(item)]">Ver receta</a>
31
+ * </ng-template>
32
+ * ```
33
+ *
34
+ * ## Rechazo con motivo
35
+ *
36
+ * El flujo de dos pasos (Rechazar → escribir motivo → Confirmar) es del panel,
37
+ * no del consumer, y está activo por defecto. Rechazar de un click deja al
38
+ * solicitante sin saber qué corregir; era el único de los dos paneles que lo
39
+ * tenía bien resuelto y ahora lo heredan los dos.
36
40
  */
37
- export declare class RequestReviewPanelComponent implements OnInit {
38
- private requests;
41
+ export declare class RequestReviewPanelComponent {
39
42
  private i18n;
40
- private errors;
41
- private toast;
42
- private destroyRef;
43
- readonly requestId: import("@angular/core").InputSignal<string>;
44
- readonly config: import("@angular/core").InputSignal<RequestReviewPanelConfig>;
45
- readonly loaded: import("@angular/core").OutputEmitterRef<AppRequest>;
46
- private readonly _req;
47
- private readonly _loading;
48
- private readonly _loadError;
49
- private readonly _comments;
50
- private readonly _loadingComments;
51
- private readonly _transitioning;
52
- readonly req: import("@angular/core").Signal<AppRequest>;
53
- readonly loading: import("@angular/core").Signal<boolean>;
54
- readonly loadError: import("@angular/core").Signal<unknown>;
55
- readonly comments: import("@angular/core").Signal<RequestComment[]>;
56
- readonly loadingComments: import("@angular/core").Signal<boolean>;
57
- readonly transitioning: import("@angular/core").Signal<boolean>;
58
- readonly heroImgFailed: import("@angular/core").WritableSignal<boolean>;
59
- readonly heroConfig: import("@angular/core").Signal<RequestReviewEntityHeroConfig>;
60
- readonly statusStyle: import("@angular/core").Signal<StatusStyle>;
61
- readonly heroName: import("@angular/core").Signal<string>;
62
- readonly heroImage: import("@angular/core").Signal<string>;
63
- readonly canNavigateHero: import("@angular/core").Signal<boolean>;
64
- readonly submitterInitial: import("@angular/core").Signal<string>;
65
- readonly fieldEntries: import("@angular/core").Signal<{
66
- key: string;
67
- value: string;
68
- }[]>;
69
- readonly errorState: import("@angular/core").Signal<EmptyStateMetadata>;
43
+ readonly props: import("@angular/core").InputSignal<RequestReviewPanelMetadata>;
44
+ /**
45
+ * Cuerpo de cada card. El contexto trae el ítem como `$implicit` y también
46
+ * como `item`, para que el consumer pueda usar `let-item` o `let-x="item"`.
47
+ */
48
+ itemBody?: TemplateRef<{
49
+ $implicit: RequestReviewItem;
50
+ item: RequestReviewItem;
51
+ }>;
52
+ decision: EventEmitter<RequestReviewDecision>;
53
+ /** ID del ítem cuyo formulario de rechazo está abierto. */
54
+ private readonly _rejectingId;
55
+ readonly rejectingId: import("@angular/core").Signal<string>;
56
+ private readonly _reason;
57
+ readonly reason: import("@angular/core").Signal<string>;
58
+ readonly cfg: import("@angular/core").Signal<RequestReviewPanelMetadata>;
59
+ readonly skeletonRows: import("@angular/core").Signal<number[]>;
60
+ /** Hay una decisión en vuelo: toda la cola se congela. */
61
+ readonly isBusy: import("@angular/core").Signal<boolean>;
70
62
  constructor();
71
- ngOnInit(): void;
72
- load(): Promise<void>;
73
- private subscribeComments;
74
- transition(status: 'approved' | 'rejected'): Promise<void>;
75
- onHeroClick(): void;
76
- formatDate(iso: string): string;
77
- authorInitial(c: RequestComment): string;
78
- relativeTime(iso: string): string;
79
- t(key: string): string;
63
+ protected t(key: string): string;
64
+ /** El ítem en vuelo muestra WORKING; los demás quedan deshabilitados. */
65
+ private stateFor;
66
+ protected approveState(item: RequestReviewItem): ComponentState;
67
+ /**
68
+ * Confirmar el rechazo exige motivo cuando `requireRejectReason` está activo
69
+ * (el default). Es el freno que evita la notificación de rechazo vacía.
70
+ */
71
+ protected confirmRejectState(item: RequestReviewItem): ComponentState;
72
+ protected onReasonInput(event: Event): void;
73
+ protected startReject(item: RequestReviewItem): void;
74
+ protected cancelReject(): void;
75
+ protected confirmReject(item: RequestReviewItem): void;
76
+ protected approve(item: RequestReviewItem): void;
80
77
  static ɵfac: i0.ɵɵFactoryDeclaration<RequestReviewPanelComponent, never>;
81
- static ɵcmp: i0.ɵɵComponentDeclaration<RequestReviewPanelComponent, "val-request-review-panel", never, { "requestId": { "alias": "requestId"; "required": true; "isSignal": true; }; "config": { "alias": "config"; "required": true; "isSignal": true; }; }, { "loaded": "loaded"; }, never, never, true, never>;
78
+ static ɵcmp: i0.ɵɵComponentDeclaration<RequestReviewPanelComponent, "val-request-review-panel", never, { "props": { "alias": "props"; "required": true; "isSignal": true; }; "itemBody": { "alias": "itemBody"; "required": false; }; }, { "decision": "decision"; }, never, never, true, never>;
82
79
  }
83
- export {};
@@ -0,0 +1,2 @@
1
+ import { LanguagesContent } from '../../../services/i18n';
2
+ export declare const REQUEST_REVIEW_PANEL_I18N: LanguagesContent;
@@ -0,0 +1,73 @@
1
+ import { EmptyStateMetadata } from '../../molecules/empty-state/types';
2
+ /**
3
+ * Un ítem de la cola de revisión, ya normalizado por el consumer.
4
+ *
5
+ * Deliberadamente pobre: id, título y unas líneas de metadata. Todo lo que sea
6
+ * del dominio (el RUT del criadero, los tags de la receta, los documentos
7
+ * adjuntos) va en el cuerpo proyectado, no acá — la lib no aprende qué es una
8
+ * receta ni un criadero.
9
+ */
10
+ export interface RequestReviewItem {
11
+ /** Identidad del ítem. Es lo que viaja en la decisión. */
12
+ id: string;
13
+ /** Encabezado de la card. */
14
+ title: string;
15
+ /**
16
+ * Líneas bajo el título (fecha de envío, identificador, estado). Texto ya
17
+ * resuelto y formateado por el consumer: la lib no traduce ni formatea fechas.
18
+ */
19
+ meta?: string[];
20
+ }
21
+ /** Lo que emite el panel cuando el revisor decide. */
22
+ export interface RequestReviewDecision {
23
+ itemId: string;
24
+ approved: boolean;
25
+ /**
26
+ * Motivo del rechazo. Presente solo al rechazar con `requireRejectReason`
27
+ * activo (el default), donde el panel garantiza que no viene vacío.
28
+ */
29
+ reason?: string;
30
+ }
31
+ export interface RequestReviewPanelMetadata {
32
+ /** La cola. Vacía + `loading: false` muestra el estado vacío. */
33
+ items: RequestReviewItem[];
34
+ /** Muestra el skeleton en vez de la lista. */
35
+ loading?: boolean;
36
+ /** Filas del skeleton (default: 3). */
37
+ skeletonRows?: number;
38
+ /**
39
+ * Estado de error de la carga. Tiene prioridad sobre todo lo demás — un panel
40
+ * que no pudo cargar no debe mostrar "no hay nada pendiente", que es una
41
+ * afirmación distinta y falsa.
42
+ */
43
+ errorState?: EmptyStateMetadata | null;
44
+ /** Estado cuando la cola está vacía de verdad. */
45
+ emptyState?: EmptyStateMetadata;
46
+ /**
47
+ * Línea de conteo sobre la lista, ya compuesta por el consumer
48
+ * ("3 pendientes"). Sin ella no se muestra nada.
49
+ */
50
+ countLabel?: string;
51
+ /**
52
+ * ID del ítem con una decisión en vuelo. Ese ítem muestra su acción en
53
+ * `WORKING` y el resto queda deshabilitado: dos decisiones simultáneas sobre
54
+ * la misma cola es justo lo que no se quiere.
55
+ */
56
+ busyItemId?: string;
57
+ /**
58
+ * Exigir un motivo escrito para rechazar (default: **true**).
59
+ *
60
+ * Es el default a propósito. Rechazar sin explicación deja al solicitante sin
61
+ * saber qué corregir, y la notificación de decisión sale vacía. Ponerlo en
62
+ * `false` es una decisión explícita del consumer, no un olvido.
63
+ */
64
+ requireRejectReason?: boolean;
65
+ /** Etiquetas. Todas opcionales — la lib trae defaults es/en. */
66
+ approveLabel?: string;
67
+ rejectLabel?: string;
68
+ cancelLabel?: string;
69
+ confirmRejectLabel?: string;
70
+ rejectReasonLabel?: string;
71
+ rejectReasonPlaceholder?: string;
72
+ rejectReasonHint?: string;
73
+ }
@@ -3,7 +3,7 @@ import { FormControl } from '@angular/forms';
3
3
  import { ButtonMetadata } from '../../types';
4
4
  import type { Color } from '@ionic/core';
5
5
  import { EditableFieldDef, FieldSchemaEditorMetadata } from '../field-schema-editor/types';
6
- import { SurveyBuilderMetadata, SurveyBuilderSaveEvent } from './types';
6
+ import { SurveyBuilderMetadata, SurveyBuilderSaveEvent, SurveyDraftEvent } from './types';
7
7
  import * as i0 from "@angular/core";
8
8
  /**
9
9
  * val-survey-builder
@@ -25,6 +25,13 @@ import * as i0 from "@angular/core";
25
25
  export declare class SurveyBuilderComponent implements OnInit {
26
26
  props: SurveyBuilderMetadata;
27
27
  readonly saved: EventEmitter<SurveyBuilderSaveEvent>;
28
+ /**
29
+ * Emite lo escrito, ya validado, SIN guardarlo. Solo con `props.persist:
30
+ * false` — ver el comentario de ese campo: cuando la app tiene endpoint
31
+ * propio, guardar desde acá se salta la validación de la entidad dueña y el
32
+ * permiso de la vertical.
33
+ */
34
+ readonly draft: EventEmitter<SurveyDraftEvent>;
28
35
  private readonly i18n;
29
36
  private readonly requests;
30
37
  private readonly formBuilder;
@@ -61,5 +68,5 @@ export declare class SurveyBuilderComponent implements OnInit {
61
68
  save(): Promise<void>;
62
69
  private rowFromField;
63
70
  static ɵfac: i0.ɵɵFactoryDeclaration<SurveyBuilderComponent, never>;
64
- static ɵcmp: i0.ɵɵComponentDeclaration<SurveyBuilderComponent, "val-survey-builder", never, { "props": { "alias": "props"; "required": false; }; }, { "saved": "saved"; }, never, never, true, never>;
71
+ static ɵcmp: i0.ɵɵComponentDeclaration<SurveyBuilderComponent, "val-survey-builder", never, { "props": { "alias": "props"; "required": false; }; }, { "saved": "saved"; "draft": "draft"; }, never, never, true, never>;
65
72
  }
@@ -1,4 +1,4 @@
1
- import { EntityRef, RequestTypeConfig, RequestVisibility } from '../../../services/requests/types';
1
+ import { EntityRef, FieldSchemaDef, RequestTypeConfig, RequestVisibility } from '../../../services/requests/types';
2
2
  /**
3
3
  * Tipos de pregunta que ofrece una encuesta.
4
4
  *
@@ -46,7 +46,34 @@ export interface SurveyBuilderMetadata {
46
46
  allowAnonymous?: boolean;
47
47
  /** Acota el catálogo de `SURVEY_QUESTION_TYPES` si una app quiere ofrecer menos. */
48
48
  questionTypes?: string[];
49
+ /**
50
+ * Si el builder guarda por su cuenta contra `/v2/request-types`.
51
+ *
52
+ * Default `true` por compatibilidad, pero **una app con endpoint propio debe
53
+ * pasar `false`** y guardar ella: el endpoint de la vertical es el que valida
54
+ * la entidad dueña, evita que dos encuestas de distinto evento colisionen en
55
+ * el mismo `typeId`, y autoriza con SU permiso. Con `false`, `save()` valida
56
+ * y emite `draft` sin tocar la red.
57
+ */
58
+ persist?: boolean;
49
59
  }
50
60
  export interface SurveyBuilderSaveEvent {
51
61
  typeConfig: RequestTypeConfig;
52
62
  }
63
+ /**
64
+ * Lo que se escribió, sin persistir.
65
+ *
66
+ * Existe porque **el builder no siempre debe guardar por su cuenta**. Cuando la
67
+ * app tiene su propio endpoint de dominio (el de bingo valida el evento, acota
68
+ * el `typeId` para que dos eventos no colisionen y autoriza con el permiso de
69
+ * la vertical en vez de `apps:manage`), guardar desde acá se salta todo eso.
70
+ *
71
+ * Los tres campos son exactamente los de `CreateEventSurveyRequest` en
72
+ * `services/bingo/survey.go` — no es casualidad: es el contrato que la app
73
+ * necesita reenviar.
74
+ */
75
+ export interface SurveyDraftEvent {
76
+ label: string;
77
+ subtitle: string;
78
+ questions: FieldSchemaDef[];
79
+ }
@@ -0,0 +1,14 @@
1
+ import { EnvironmentProviders, InjectionToken } from '@angular/core';
2
+ import { ValtechPaymentsConfig } from './types';
3
+ /** Token de inyección de la configuración de pagos. */
4
+ export declare const VALTECH_PAYMENTS_CONFIG: InjectionToken<ValtechPaymentsConfig>;
5
+ export declare const DEFAULT_PAYMENTS_CONFIG: Partial<ValtechPaymentsConfig>;
6
+ /**
7
+ * Provee el cliente de pasarelas de pago.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * providePaymentsGateway({ apiUrl: environment.apiUrl }),
12
+ * ```
13
+ */
14
+ export declare function providePaymentsGateway(config: ValtechPaymentsConfig): EnvironmentProviders;
@@ -0,0 +1,3 @@
1
+ export * from './types';
2
+ export * from './config';
3
+ export * from './payments-gateway.service';
@@ -0,0 +1,53 @@
1
+ import { Observable } from 'rxjs';
2
+ import { ConnectionStatusResponse, OAuthAuthorizeURLResponse } from './types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Cliente del onboarding de pasarelas de pago (ADR-028).
6
+ *
7
+ * Conecta la cuenta de UNA ORGANIZACIÓN con una pasarela, para que el dinero
8
+ * le llegue directo. Ese es el punto: si el dinero pasara por una cuenta de
9
+ * Valtech, Valtech sería un PSP regulado por la CMF (ver ADR-028). Por eso
10
+ * todas las operaciones son por `orgId`, y no existe acá un modo "cuenta de la
11
+ * plataforma".
12
+ *
13
+ * Vive en la lib y no en una app porque el flujo es idéntico en todas: Bingo
14
+ * lo usa para que cada colegio cobre sus cartones, y Chesed para que cada
15
+ * refugio reciba aportes. Lo que cambia entre apps es qué se cobra, no cómo se
16
+ * conecta la cuenta.
17
+ *
18
+ * Autenticación: no agrega el Bearer a mano — lo pone el interceptor de
19
+ * `provideValtechAuth`. Errores: no se capturan acá; los maneja la pantalla.
20
+ */
21
+ export declare class PaymentsGatewayService {
22
+ private http;
23
+ private config;
24
+ private get base();
25
+ /**
26
+ * Estado de conexión de la organización con una pasarela.
27
+ *
28
+ * Es lo que decide si la app puede ofrecer el cobro: `connected` habilita,
29
+ * `expired` y `revoked` NO. Mostrar un botón de pago con un token revocado
30
+ * lleva al usuario a un cobro que falla después de que ya decidió pagar.
31
+ */
32
+ getConnectionStatus(orgId: string, gateway: string): Observable<ConnectionStatusResponse>;
33
+ /**
34
+ * URL de autorización OAuth, con su `state` CSRF.
35
+ *
36
+ * El caller guarda el `state` antes de redirigir y lo compara al volver: sin
37
+ * eso, cualquiera podría completar la conexión de otra organización.
38
+ */
39
+ getOAuthAuthorizeURL(orgId: string, gateway: string): Observable<OAuthAuthorizeURLResponse>;
40
+ /** Desconecta la credencial de la organización para esa pasarela. */
41
+ disconnect(orgId: string, gateway: string): Observable<{
42
+ operationId: string;
43
+ }>;
44
+ /**
45
+ * Guarda una credencial de acceso directo (pasarelas sin OAuth, ej. Khipu).
46
+ * El token es el secreto del cobrador.
47
+ */
48
+ setCredential(orgId: string, gateway: string, accessToken: string): Observable<{
49
+ operationId: string;
50
+ }>;
51
+ static ɵfac: i0.ɵɵFactoryDeclaration<PaymentsGatewayService, never>;
52
+ static ɵprov: i0.ɵɵInjectableDeclaration<PaymentsGatewayService>;
53
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Contratos del onboarding de pasarelas de pago (ADR-028).
3
+ *
4
+ * Espejo reducido del backend: solo lo que una app necesita para conectar la
5
+ * cuenta de una organización y saber si puede cobrar.
6
+ */
7
+ /** Estado del ciclo de vida de una credencial OAuth. */
8
+ export type OAuthStatus = 'never' | 'connected' | 'expired' | 'revoked';
9
+ /**
10
+ * Respuesta de `connection-status`. No expone el token: solo un enmascarado
11
+ * informativo, porque la UI nunca necesita el secreto.
12
+ */
13
+ export interface ConnectionStatusResponse {
14
+ operationId: string;
15
+ connected: boolean;
16
+ oauthStatus: OAuthStatus;
17
+ connectedAt?: string;
18
+ maskedToken?: string;
19
+ }
20
+ /** Respuesta de `oauth/authorize-url`. */
21
+ export interface OAuthAuthorizeURLResponse {
22
+ operationId: string;
23
+ authorizeUrl: string;
24
+ /** CSRF. El caller lo guarda antes de redirigir y lo compara al volver. */
25
+ state: string;
26
+ }
27
+ /** Configuración del cliente de pagos. */
28
+ export interface ValtechPaymentsConfig {
29
+ /** Base del backend, sin barra final (ej. `https://api-dev.myvaltech.com`). */
30
+ apiUrl: string;
31
+ /** Prefijo de la API de pagos. Default `/v1/payments`. */
32
+ paymentsPrefix?: string;
33
+ }
package/lib/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export declare const VERSION = "4.0.988";
5
+ export declare const VERSION = "4.0.990";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valtech-components",
3
- "version": "4.0.988",
3
+ "version": "4.0.990",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "valtech-firebase-config": "./src/lib/services/firebase/scripts/generate-sw-config.js"
package/public-api.d.ts CHANGED
@@ -242,6 +242,8 @@ export * from './lib/components/organisms/survey-response/survey-response.compon
242
242
  export * from './lib/components/organisms/survey-response/types';
243
243
  export * from './lib/components/organisms/field-schema-editor/field-schema-editor.component';
244
244
  export * from './lib/components/organisms/field-schema-editor/types';
245
+ export * from './lib/components/organisms/request-review-panel/request-review-panel.component';
246
+ export * from './lib/components/organisms/request-review-panel/types';
245
247
  export * from './lib/components/organisms/survey-builder/survey-builder.component';
246
248
  export * from './lib/components/organisms/survey-builder/types';
247
249
  export * from './lib/components/molecules/empty-state/empty-state.component';
@@ -269,7 +271,6 @@ export * from './lib/components/organisms/share-profile-modal/share-profile-moda
269
271
  export * from './lib/components/organisms/share-profile-modal/types';
270
272
  export * from './lib/components/organisms/fun-modal/fun-modal.component';
271
273
  export * from './lib/components/organisms/request-modal/request-modal.component';
272
- export * from './lib/components/organisms/request-review-panel/request-review-panel.component';
273
274
  export * from './lib/components/organisms/fun-modal/types';
274
275
  export * from './lib/components/organisms/cookie-banner/cookie-banner.component';
275
276
  export * from './lib/components/organisms/cookie-banner/types';
@@ -499,6 +500,7 @@ export * from './lib/components/organisms/verify-view/verify-view.component';
499
500
  export * from './lib/components/organisms/verify-view/types';
500
501
  export * from './lib/services/content-platform';
501
502
  export * from './lib/services/feedback';
503
+ export * from './lib/services/payments';
502
504
  export * from './lib/services/whatsapp';
503
505
  export * from './lib/components/organisms/whatsapp-fab/whatsapp-fab.component';
504
506
  export * from './lib/services/phone-format/phone-format.service';