valtech-components 4.0.230 → 4.0.231
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/esm2022/lib/components/molecules/chat-composer/chat-composer.component.mjs +107 -300
- package/esm2022/lib/components/molecules/message-bubble/message-bubble.component.mjs +4 -19
- package/esm2022/lib/components/organisms/chat-window/chat-window.component.mjs +8 -5
- package/esm2022/lib/components/organisms/thread-panel/thread-panel.component.mjs +4 -6
- package/esm2022/lib/services/chat/conversation.service.mjs +4 -15
- package/esm2022/lib/services/pdf/pdf.service.mjs +44 -4
- package/esm2022/lib/services/pdf/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +2 -2
- package/fesm2022/valtech-components.mjs +162 -342
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/chat-composer/chat-composer.component.d.ts +15 -44
- package/lib/components/molecules/message-bubble/message-bubble.component.d.ts +0 -1
- package/lib/components/organisms/chat-window/chat-window.component.d.ts +4 -4
- package/lib/components/organisms/thread-panel/thread-panel.component.d.ts +1 -4
- package/lib/services/chat/conversation.service.d.ts +3 -5
- package/lib/services/pdf/pdf.service.d.ts +25 -3
- package/lib/services/pdf/types.d.ts +25 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -1
|
@@ -1,49 +1,30 @@
|
|
|
1
|
-
import { OnDestroy } from '@angular/core';
|
|
2
1
|
import { MessageReplyTo } from '../../../services/chat/types';
|
|
3
2
|
import * as i0 from "@angular/core";
|
|
4
|
-
type PendingKind = 'image' | 'audio' | 'file';
|
|
5
|
-
interface PendingAttachment {
|
|
6
|
-
id: number;
|
|
7
|
-
file: File;
|
|
8
|
-
url?: string;
|
|
9
|
-
kind: PendingKind;
|
|
10
|
-
}
|
|
11
|
-
/** Evento de envío: texto (caption) + adjuntos staged. files vacío => solo texto. */
|
|
12
|
-
export interface ChatComposerSendEvent {
|
|
13
|
-
text: string;
|
|
14
|
-
files: File[];
|
|
15
|
-
}
|
|
16
3
|
/**
|
|
17
4
|
* val-chat-composer — barra de redacción de chat moderna (signal inputs).
|
|
18
5
|
*
|
|
19
|
-
* Pill con: adjuntar (+), textarea auto-grow, y mic/enviar
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* No incluye picker de emoji: el teclado del sistema ya lo trae.
|
|
6
|
+
* Pill con: adjuntar (+), textarea auto-grow, emoji (fila rápida) y mic/enviar
|
|
7
|
+
* (mic cuando está vacío, enviar cuando hay texto — patrón WhatsApp/Telegram).
|
|
8
|
+
* Muestra una barra de contexto "respondiendo a" cuando `replyingTo` está seteado.
|
|
9
|
+
* `typing` se emite con debounce (máx. 1 vez cada 2s) para no spamear writes.
|
|
24
10
|
*/
|
|
25
|
-
export declare class ChatComposerComponent
|
|
11
|
+
export declare class ChatComposerComponent {
|
|
26
12
|
private i18n;
|
|
27
13
|
readonly placeholder: import("@angular/core").InputSignal<string>;
|
|
28
14
|
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
29
15
|
readonly maxLength: import("@angular/core").InputSignal<number>;
|
|
30
16
|
readonly replyingTo: import("@angular/core").InputSignal<MessageReplyTo>;
|
|
31
17
|
readonly showAttach: import("@angular/core").InputSignal<boolean>;
|
|
18
|
+
readonly showEmoji: import("@angular/core").InputSignal<boolean>;
|
|
32
19
|
readonly showMic: import("@angular/core").InputSignal<boolean>;
|
|
33
|
-
readonly send: import("@angular/core").OutputEmitterRef<
|
|
20
|
+
readonly send: import("@angular/core").OutputEmitterRef<string>;
|
|
34
21
|
readonly typing: import("@angular/core").OutputEmitterRef<void>;
|
|
22
|
+
readonly attach: import("@angular/core").OutputEmitterRef<File>;
|
|
35
23
|
readonly voice: import("@angular/core").OutputEmitterRef<void>;
|
|
36
24
|
readonly cancelReply: import("@angular/core").OutputEmitterRef<void>;
|
|
37
25
|
protected readonly body: import("@angular/core").WritableSignal<string>;
|
|
38
|
-
protected readonly
|
|
39
|
-
|
|
40
|
-
protected readonly recording: import("@angular/core").WritableSignal<boolean>;
|
|
41
|
-
private readonly recSeconds;
|
|
42
|
-
private recorder?;
|
|
43
|
-
private recStream?;
|
|
44
|
-
private recChunks;
|
|
45
|
-
private recTimer?;
|
|
46
|
-
protected readonly recTimeLabel: import("@angular/core").Signal<string>;
|
|
26
|
+
protected readonly emojiOpen: import("@angular/core").WritableSignal<boolean>;
|
|
27
|
+
protected readonly quickEmojis: string[];
|
|
47
28
|
private lastTypingEmit;
|
|
48
29
|
constructor();
|
|
49
30
|
protected readonly canSend: import("@angular/core").Signal<boolean>;
|
|
@@ -51,25 +32,15 @@ export declare class ChatComposerComponent implements OnDestroy {
|
|
|
51
32
|
protected onInput(event: Event): void;
|
|
52
33
|
protected onKeydown(event: KeyboardEvent): void;
|
|
53
34
|
protected onSend(): void;
|
|
35
|
+
protected toggleEmoji(): void;
|
|
36
|
+
protected insertEmoji(emoji: string): void;
|
|
54
37
|
protected onFile(event: Event): void;
|
|
55
|
-
/** Pegar imagen desde el portapapeles (captura de pantalla, copiar imagen). */
|
|
56
|
-
protected onPaste(event: ClipboardEvent): void;
|
|
57
|
-
private addPending;
|
|
58
|
-
protected removePending(id: number): void;
|
|
59
38
|
/**
|
|
60
|
-
* Emite typing como máximo 1 vez cada 2s.
|
|
39
|
+
* Emite typing como máximo 1 vez cada 2s. No usa Date.now() directo en plantillas
|
|
40
|
+
* de workflow; aquí estamos en runtime de navegador, performance.now es seguro.
|
|
61
41
|
*/
|
|
62
42
|
private emitTypingDebounced;
|
|
63
|
-
/** Selecciona un mimeType de audio soportado por el navegador. */
|
|
64
|
-
private pickAudioMime;
|
|
65
|
-
protected startRecording(): Promise<void>;
|
|
66
|
-
/** Para la grabación y la stagea como adjunto pendiente (con preview de audio). */
|
|
67
|
-
protected finishRecording(): void;
|
|
68
|
-
protected cancelRecording(): void;
|
|
69
|
-
private cleanupRecording;
|
|
70
|
-
ngOnDestroy(): void;
|
|
71
43
|
t(key: string): string;
|
|
72
44
|
static ɵfac: i0.ɵɵFactoryDeclaration<ChatComposerComponent, never>;
|
|
73
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ChatComposerComponent, "val-chat-composer", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "replyingTo": { "alias": "replyingTo"; "required": false; "isSignal": true; }; "showAttach": { "alias": "showAttach"; "required": false; "isSignal": true; }; "showMic": { "alias": "showMic"; "required": false; "isSignal": true; }; }, { "send": "send"; "typing": "typing"; "voice": "voice"; "cancelReply": "cancelReply"; }, never, never, true, never>;
|
|
45
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ChatComposerComponent, "val-chat-composer", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "replyingTo": { "alias": "replyingTo"; "required": false; "isSignal": true; }; "showAttach": { "alias": "showAttach"; "required": false; "isSignal": true; }; "showEmoji": { "alias": "showEmoji"; "required": false; "isSignal": true; }; "showMic": { "alias": "showMic"; "required": false; "isSignal": true; }; }, { "send": "send"; "typing": "typing"; "attach": "attach"; "voice": "voice"; "cancelReply": "cancelReply"; }, never, never, true, never>;
|
|
74
46
|
}
|
|
75
|
-
export {};
|
|
@@ -31,7 +31,6 @@ export declare class MessageBubbleComponent {
|
|
|
31
31
|
protected readonly time: import("@angular/core").Signal<string>;
|
|
32
32
|
protected readonly initials: import("@angular/core").Signal<string>;
|
|
33
33
|
protected readonly imageAttachments: import("@angular/core").Signal<import("valtech-components").MessageAttachment[]>;
|
|
34
|
-
protected readonly audioAttachments: import("@angular/core").Signal<import("valtech-components").MessageAttachment[]>;
|
|
35
34
|
protected readonly fileAttachments: import("@angular/core").Signal<import("valtech-components").MessageAttachment[]>;
|
|
36
35
|
protected readonly statusIcon: import("@angular/core").Signal<"time-outline" | "alert-circle" | "checkmark-done" | "checkmark">;
|
|
37
36
|
protected toggleActions(): void;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { MessageReplyTo } from '../../../services/chat/types';
|
|
2
2
|
import { MessageBubbleAction } from '../../molecules/message-bubble/message-bubble.component';
|
|
3
3
|
import { MessageBubbleMetadata } from '../../molecules/message-bubble/types';
|
|
4
|
-
import { ChatComposerSendEvent } from '../../molecules/chat-composer/chat-composer.component';
|
|
5
4
|
import * as i0 from "@angular/core";
|
|
6
5
|
type ChatRow = {
|
|
7
6
|
kind: 'date';
|
|
@@ -35,7 +34,7 @@ export declare class ChatWindowComponent {
|
|
|
35
34
|
readonly isOpen: import("@angular/core").InputSignal<boolean>;
|
|
36
35
|
readonly typingUsers: import("@angular/core").InputSignal<string[]>;
|
|
37
36
|
readonly isLoading: import("@angular/core").InputSignal<boolean>;
|
|
38
|
-
readonly sendMessage: import("@angular/core").OutputEmitterRef<
|
|
37
|
+
readonly sendMessage: import("@angular/core").OutputEmitterRef<string>;
|
|
39
38
|
readonly loadMore: import("@angular/core").OutputEmitterRef<void>;
|
|
40
39
|
readonly reactionClick: import("@angular/core").OutputEmitterRef<{
|
|
41
40
|
msgId: string;
|
|
@@ -45,6 +44,7 @@ export declare class ChatWindowComponent {
|
|
|
45
44
|
readonly replyTo: import("@angular/core").OutputEmitterRef<string>;
|
|
46
45
|
readonly editMessage: import("@angular/core").OutputEmitterRef<string>;
|
|
47
46
|
readonly typing: import("@angular/core").OutputEmitterRef<void>;
|
|
47
|
+
readonly attach: import("@angular/core").OutputEmitterRef<File>;
|
|
48
48
|
readonly voice: import("@angular/core").OutputEmitterRef<void>;
|
|
49
49
|
private readonly msgsEl;
|
|
50
50
|
protected readonly replyingTo: import("@angular/core").WritableSignal<MessageReplyTo>;
|
|
@@ -55,10 +55,10 @@ export declare class ChatWindowComponent {
|
|
|
55
55
|
protected readonly rows: import("@angular/core").Signal<ChatRow[]>;
|
|
56
56
|
protected onScroll(): void;
|
|
57
57
|
protected scrollToBottom(smooth: boolean): void;
|
|
58
|
-
protected onSend(
|
|
58
|
+
protected onSend(body: string): void;
|
|
59
59
|
protected onAction(event: MessageBubbleAction): void;
|
|
60
60
|
t(key: string): string;
|
|
61
61
|
static ɵfac: i0.ɵɵFactoryDeclaration<ChatWindowComponent, never>;
|
|
62
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ChatWindowComponent, "val-chat-window", never, { "convId": { "alias": "convId"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; "currentUserId": { "alias": "currentUserId"; "required": false; "isSignal": true; }; "isOpen": { "alias": "isOpen"; "required": false; "isSignal": true; }; "typingUsers": { "alias": "typingUsers"; "required": false; "isSignal": true; }; "isLoading": { "alias": "isLoading"; "required": false; "isSignal": true; }; }, { "sendMessage": "sendMessage"; "loadMore": "loadMore"; "reactionClick": "reactionClick"; "deleteMessage": "deleteMessage"; "replyTo": "replyTo"; "editMessage": "editMessage"; "typing": "typing"; "voice": "voice"; }, never, never, true, never>;
|
|
62
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ChatWindowComponent, "val-chat-window", never, { "convId": { "alias": "convId"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; "currentUserId": { "alias": "currentUserId"; "required": false; "isSignal": true; }; "isOpen": { "alias": "isOpen"; "required": false; "isSignal": true; }; "typingUsers": { "alias": "typingUsers"; "required": false; "isSignal": true; }; "isLoading": { "alias": "isLoading"; "required": false; "isSignal": true; }; }, { "sendMessage": "sendMessage"; "loadMore": "loadMore"; "reactionClick": "reactionClick"; "deleteMessage": "deleteMessage"; "replyTo": "replyTo"; "editMessage": "editMessage"; "typing": "typing"; "attach": "attach"; "voice": "voice"; }, never, never, true, never>;
|
|
63
63
|
}
|
|
64
64
|
export {};
|
|
@@ -42,10 +42,7 @@ export declare class ThreadPanelComponent implements OnInit, OnDestroy {
|
|
|
42
42
|
protected isConvOpen: import("@angular/core").Signal<boolean>;
|
|
43
43
|
protected loadingText: import("@angular/core").Signal<string>;
|
|
44
44
|
protected bubbleMessages: import("@angular/core").Signal<MessageBubbleMetadata[]>;
|
|
45
|
-
protected onSend(
|
|
46
|
-
text: string;
|
|
47
|
-
files: File[];
|
|
48
|
-
}): void;
|
|
45
|
+
protected onSend(body: string): void;
|
|
49
46
|
protected onReactionClick(event: {
|
|
50
47
|
msgId: string;
|
|
51
48
|
token: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import { Conversation, ConversationType, CreateConversationRequest, ListConversationsResponse, Message,
|
|
2
|
+
import { Conversation, ConversationType, CreateConversationRequest, ListConversationsResponse, Message, UpdateConversationRequest } from './types';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
/**
|
|
5
5
|
* ConversationService
|
|
@@ -75,11 +75,9 @@ export declare class ConversationService {
|
|
|
75
75
|
*/
|
|
76
76
|
removeParticipant(convId: string, userId: string): Observable<void>;
|
|
77
77
|
/**
|
|
78
|
-
* Envia un mensaje a una conversacion
|
|
79
|
-
* El backend espera `attachments: { url, type, name, size }[]` (key `type` = MIME),
|
|
80
|
-
* mientras que el front usa `mimeType` — se mapea aqui.
|
|
78
|
+
* Envia un mensaje a una conversacion.
|
|
81
79
|
*/
|
|
82
|
-
sendMessage(convId: string, body: string
|
|
80
|
+
sendMessage(convId: string, body: string): Observable<Message>;
|
|
83
81
|
/**
|
|
84
82
|
* Elimina (marca como eliminado) un mensaje.
|
|
85
83
|
*/
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { ValtechAuthConfig } from '../auth/types';
|
|
3
|
-
import type { PdfGenerateRequest, PdfResult } from './types';
|
|
3
|
+
import type { PdfGenerateRequest, PdfResult, PdfJob, PdfJobEnqueued } from './types';
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
5
|
/**
|
|
6
|
-
* Servicio
|
|
6
|
+
* Servicio de PDF de plataforma (ADR-042). Reutilizable por cualquier app.
|
|
7
7
|
*
|
|
8
8
|
* El JWT del usuario se inyecta automáticamente por el authInterceptor
|
|
9
9
|
* (configurado vía provideValtechAuth). El app-id se toma de ValtechAuthConfig.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Tres modos:
|
|
12
|
+
* - generate() → HTTP sync: genera y devuelve la URL presignada.
|
|
13
|
+
* - createJob() → async: encola un job (delivery.mode='async') y devuelve
|
|
14
|
+
* { jobId, status:'queued' }. El PDF se genera fuera de banda.
|
|
15
|
+
* - watchJob() → observa el estado del job en tiempo real (Firestore),
|
|
16
|
+
* proyectado por el backend al completarse.
|
|
17
|
+
*
|
|
18
|
+
* Fuentes (en los 3 modos):
|
|
12
19
|
* - source.template → renderiza una plantilla desde DynamoDB
|
|
13
20
|
* - source.html → HTML arbitrario provisto por el caller
|
|
14
21
|
* - source.url → URL pública (Puppeteer la carga)
|
|
@@ -16,11 +23,26 @@ import * as i0 from "@angular/core";
|
|
|
16
23
|
export declare class PdfService {
|
|
17
24
|
private config;
|
|
18
25
|
private http;
|
|
26
|
+
private auth;
|
|
27
|
+
private collections;
|
|
19
28
|
constructor(config: ValtechAuthConfig | null);
|
|
20
29
|
private get baseUrl();
|
|
21
30
|
private get appIdHeader();
|
|
22
31
|
generate(req: PdfGenerateRequest): Observable<PdfResult>;
|
|
23
32
|
generateAndDownload(req: PdfGenerateRequest, filename?: string): Observable<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Encola un job PDF async. El backend publica `pdf.generate.requested`; el PDF
|
|
35
|
+
* Lambda lo genera fuera de banda y, al completar, proyecta el estado a
|
|
36
|
+
* Firestore. Usar watchJob(jobId) para observar el resultado en tiempo real.
|
|
37
|
+
*/
|
|
38
|
+
createJob(req: PdfGenerateRequest): Observable<PdfJobEnqueued>;
|
|
39
|
+
/**
|
|
40
|
+
* Observa el estado de un job PDF async en tiempo real (onSnapshot del doc
|
|
41
|
+
* `apps/{appId}/orgs/{orgId}/pdf-jobs/{jobId}`). Emite null si no hay org
|
|
42
|
+
* activa o hasta que el doc exista. Cuando el job completa/falla, el doc trae
|
|
43
|
+
* status + url. Cierra la suscripción al completar tu propia lógica.
|
|
44
|
+
*/
|
|
45
|
+
watchJob(jobId: string): Observable<PdfJob | null>;
|
|
24
46
|
private _download;
|
|
25
47
|
static ɵfac: i0.ɵɵFactoryDeclaration<PdfService, [{ optional: true; }]>;
|
|
26
48
|
static ɵprov: i0.ɵɵInjectableDeclaration<PdfService>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FirestoreDocument } from '../firebase/types';
|
|
1
2
|
export interface PdfTemplateSource {
|
|
2
3
|
template: {
|
|
3
4
|
id: string;
|
|
@@ -18,6 +19,8 @@ export interface PdfGenerateOptions {
|
|
|
18
19
|
export interface PdfDeliveryOptions {
|
|
19
20
|
expiresIn?: number;
|
|
20
21
|
filename?: string;
|
|
22
|
+
/** 'sync' (default) genera y devuelve la URL; 'async' encola un job (ADR-042). */
|
|
23
|
+
mode?: 'sync' | 'async';
|
|
21
24
|
}
|
|
22
25
|
export interface PdfGenerateRequest {
|
|
23
26
|
source: PdfSource;
|
|
@@ -30,3 +33,25 @@ export interface PdfResult {
|
|
|
30
33
|
url: string;
|
|
31
34
|
expiresAt: string;
|
|
32
35
|
}
|
|
36
|
+
export type PdfJobStatus = 'queued' | 'processing' | 'completed' | 'failed';
|
|
37
|
+
/** Respuesta al encolar un job async (ADR-042). */
|
|
38
|
+
export interface PdfJobEnqueued {
|
|
39
|
+
jobId: string;
|
|
40
|
+
status: 'queued';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Estado de un job PDF async proyectado a Firestore por el admin Lambda
|
|
44
|
+
* (apps/{appId}/orgs/{orgId}/pdf-jobs/{jobId}). Lo observa PdfService.watchJob().
|
|
45
|
+
* Extiende FirestoreDocument (id/createdAt/updatedAt los maneja Firestore).
|
|
46
|
+
*/
|
|
47
|
+
export interface PdfJob extends FirestoreDocument {
|
|
48
|
+
jobId: string;
|
|
49
|
+
appId: string;
|
|
50
|
+
orgId: string;
|
|
51
|
+
status: PdfJobStatus;
|
|
52
|
+
url?: string;
|
|
53
|
+
s3Key?: string;
|
|
54
|
+
expiresAt?: string;
|
|
55
|
+
elapsedMs?: number;
|
|
56
|
+
caller?: string;
|
|
57
|
+
}
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -478,7 +478,7 @@ export { MessageBubbleComponent, type MessageBubbleAction, } from './lib/compone
|
|
|
478
478
|
export * from './lib/components/molecules/message-bubble/types';
|
|
479
479
|
export { ChatInputComponent } from './lib/components/molecules/chat-input/chat-input.component';
|
|
480
480
|
export * from './lib/components/molecules/chat-input/types';
|
|
481
|
-
export { ChatComposerComponent
|
|
481
|
+
export { ChatComposerComponent } from './lib/components/molecules/chat-composer/chat-composer.component';
|
|
482
482
|
export { ConversationListItemComponent } from './lib/components/molecules/conversation-list-item/conversation-list-item.component';
|
|
483
483
|
export { TypingIndicatorComponent } from './lib/components/molecules/typing-indicator/typing-indicator.component';
|
|
484
484
|
export { ChatWindowComponent } from './lib/components/organisms/chat-window/chat-window.component';
|