valtech-components 4.0.240 → 4.0.242
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 +75 -13
- package/esm2022/lib/components/molecules/message-bubble/message-bubble.component.mjs +28 -3
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +102 -15
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +1 -1
- package/lib/components/atoms/text/text.component.d.ts +1 -1
- package/lib/components/atoms/user-avatar/user-avatar.component.d.ts +1 -1
- package/lib/components/molecules/chat-composer/chat-composer.component.d.ts +5 -0
- package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
- package/lib/components/molecules/load-more/load-more.component.d.ts +1 -1
- package/lib/components/molecules/message-bubble/message-bubble.component.d.ts +5 -0
- package/lib/components/organisms/article/article.component.d.ts +6 -6
- package/lib/components/organisms/chat-window/chat-window.component.d.ts +1 -1
- package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
- package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +1 -1
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -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.
|
|
59
|
+
const VERSION = '4.0.242';
|
|
60
60
|
|
|
61
61
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
62
62
|
let isRefreshing = false;
|
|
@@ -72621,6 +72621,19 @@ class MessageBubbleComponent {
|
|
|
72621
72621
|
this.actionsOpen.set(false);
|
|
72622
72622
|
this.action.emit({ type, msgId: this.msg().msgId, token });
|
|
72623
72623
|
}
|
|
72624
|
+
/** Diagnóstico: el navegador no pudo reproducir el audio recibido. */
|
|
72625
|
+
onAudioError(att, event) {
|
|
72626
|
+
const el = event.target;
|
|
72627
|
+
const codes = { 1: 'ABORTED', 2: 'NETWORK', 3: 'DECODE', 4: 'SRC_NOT_SUPPORTED' };
|
|
72628
|
+
const canPlay = att.mimeType ? document.createElement('audio').canPlayType(att.mimeType) : '';
|
|
72629
|
+
console.error('[MessageBubble] audio play error', {
|
|
72630
|
+
mimeType: att.mimeType,
|
|
72631
|
+
url: att.url.slice(0, 80),
|
|
72632
|
+
code: el.error?.code,
|
|
72633
|
+
reason: el.error ? codes[el.error.code] : 'unknown',
|
|
72634
|
+
canPlayThisType: canPlay,
|
|
72635
|
+
});
|
|
72636
|
+
}
|
|
72624
72637
|
t(key) {
|
|
72625
72638
|
return this.i18n.t(key, 'MessageBubble');
|
|
72626
72639
|
}
|
|
@@ -72669,7 +72682,13 @@ class MessageBubbleComponent {
|
|
|
72669
72682
|
@if (audioAttachments().length > 0) {
|
|
72670
72683
|
<div class="audios">
|
|
72671
72684
|
@for (att of audioAttachments(); track att.url) {
|
|
72672
|
-
<audio
|
|
72685
|
+
<audio
|
|
72686
|
+
class="att-audio"
|
|
72687
|
+
controls
|
|
72688
|
+
preload="metadata"
|
|
72689
|
+
[src]="att.url"
|
|
72690
|
+
(error)="onAudioError(att, $event)"
|
|
72691
|
+
></audio>
|
|
72673
72692
|
}
|
|
72674
72693
|
</div>
|
|
72675
72694
|
}
|
|
@@ -72784,7 +72803,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72784
72803
|
@if (audioAttachments().length > 0) {
|
|
72785
72804
|
<div class="audios">
|
|
72786
72805
|
@for (att of audioAttachments(); track att.url) {
|
|
72787
|
-
<audio
|
|
72806
|
+
<audio
|
|
72807
|
+
class="att-audio"
|
|
72808
|
+
controls
|
|
72809
|
+
preload="metadata"
|
|
72810
|
+
[src]="att.url"
|
|
72811
|
+
(error)="onAudioError(att, $event)"
|
|
72812
|
+
></audio>
|
|
72788
72813
|
}
|
|
72789
72814
|
</div>
|
|
72790
72815
|
}
|
|
@@ -73184,6 +73209,10 @@ class ChatComposerComponent {
|
|
|
73184
73209
|
this.recStream = stream;
|
|
73185
73210
|
const mimeType = this.pickAudioMime();
|
|
73186
73211
|
this.recorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);
|
|
73212
|
+
console.log('[ChatComposer] recording start', {
|
|
73213
|
+
picked: mimeType || '(default)',
|
|
73214
|
+
recorderMimeType: this.recorder.mimeType,
|
|
73215
|
+
});
|
|
73187
73216
|
this.recChunks = [];
|
|
73188
73217
|
this.recorder.ondataavailable = e => {
|
|
73189
73218
|
if (e.data.size > 0)
|
|
@@ -73210,6 +73239,13 @@ class ChatComposerComponent {
|
|
|
73210
73239
|
const blob = new Blob(this.recChunks, { type });
|
|
73211
73240
|
const ext = type.includes('mp4') ? 'm4a' : 'webm';
|
|
73212
73241
|
const file = new File([blob], `audio-${this.recSeconds()}s.${ext}`, { type });
|
|
73242
|
+
console.log('[ChatComposer] audio recorded', {
|
|
73243
|
+
type,
|
|
73244
|
+
size: blob.size,
|
|
73245
|
+
chunks: this.recChunks.length,
|
|
73246
|
+
canPlayWebm: this.canPlay('audio/webm'),
|
|
73247
|
+
canPlayMp4: this.canPlay('audio/mp4'),
|
|
73248
|
+
});
|
|
73213
73249
|
if (blob.size > 0)
|
|
73214
73250
|
this.addPending(file);
|
|
73215
73251
|
this.cleanupRecording();
|
|
@@ -73240,6 +73276,43 @@ class ChatComposerComponent {
|
|
|
73240
73276
|
this.recording.set(false);
|
|
73241
73277
|
this.recSeconds.set(0);
|
|
73242
73278
|
}
|
|
73279
|
+
/** Diagnóstico: el navegador no pudo reproducir el adjunto de audio. */
|
|
73280
|
+
onAudioError(where, file, event) {
|
|
73281
|
+
const el = event.target;
|
|
73282
|
+
const err = el.error;
|
|
73283
|
+
const codes = {
|
|
73284
|
+
1: 'ABORTED',
|
|
73285
|
+
2: 'NETWORK',
|
|
73286
|
+
3: 'DECODE',
|
|
73287
|
+
4: 'SRC_NOT_SUPPORTED',
|
|
73288
|
+
};
|
|
73289
|
+
console.error('[ChatComposer] audio play error', {
|
|
73290
|
+
where,
|
|
73291
|
+
fileType: file.type,
|
|
73292
|
+
fileName: file.name,
|
|
73293
|
+
code: err?.code,
|
|
73294
|
+
reason: err ? codes[err.code] : 'unknown',
|
|
73295
|
+
message: err?.message,
|
|
73296
|
+
canPlayThisType: this.canPlay(file.type),
|
|
73297
|
+
});
|
|
73298
|
+
}
|
|
73299
|
+
onAudioLoaded(where, file, event) {
|
|
73300
|
+
const el = event.target;
|
|
73301
|
+
console.log('[ChatComposer] audio loadedmetadata', {
|
|
73302
|
+
where,
|
|
73303
|
+
fileType: file.type,
|
|
73304
|
+
duration: el.duration,
|
|
73305
|
+
});
|
|
73306
|
+
}
|
|
73307
|
+
/** ¿El navegador declara que puede reproducir este tipo? '' / 'maybe' / 'probably'. */
|
|
73308
|
+
canPlay(type) {
|
|
73309
|
+
try {
|
|
73310
|
+
return document.createElement('audio').canPlayType(type);
|
|
73311
|
+
}
|
|
73312
|
+
catch {
|
|
73313
|
+
return 'error';
|
|
73314
|
+
}
|
|
73315
|
+
}
|
|
73243
73316
|
ngOnDestroy() {
|
|
73244
73317
|
this.cleanupRecording();
|
|
73245
73318
|
for (const att of this.pending()) {
|
|
@@ -73270,7 +73343,13 @@ class ChatComposerComponent {
|
|
|
73270
73343
|
@for (att of pending(); track att.id) {
|
|
73271
73344
|
@if (att.kind === 'audio') {
|
|
73272
73345
|
<div class="audio-chip">
|
|
73273
|
-
<audio
|
|
73346
|
+
<audio
|
|
73347
|
+
controls
|
|
73348
|
+
preload="metadata"
|
|
73349
|
+
[src]="att.url"
|
|
73350
|
+
(error)="onAudioError('preview', att.file, $event)"
|
|
73351
|
+
(loadedmetadata)="onAudioLoaded('preview', att.file, $event)"
|
|
73352
|
+
></audio>
|
|
73274
73353
|
<button class="thumb-remove inline" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
|
|
73275
73354
|
<ion-icon name="close-outline" aria-hidden="true" />
|
|
73276
73355
|
</button>
|
|
@@ -73321,21 +73400,22 @@ class ChatComposerComponent {
|
|
|
73321
73400
|
></div>
|
|
73322
73401
|
|
|
73323
73402
|
<div class="actions">
|
|
73403
|
+
<span class="actions-spacer"></span>
|
|
73324
73404
|
@if (showAttach()) {
|
|
73325
73405
|
<label class="icon-btn" [attr.aria-label]="t('attach')">
|
|
73326
73406
|
<ion-icon name="add-outline" aria-hidden="true" />
|
|
73327
73407
|
<input type="file" hidden (change)="onFile($event)" accept="image/*,application/pdf" />
|
|
73328
73408
|
</label>
|
|
73329
73409
|
}
|
|
73330
|
-
|
|
73410
|
+
@if (showMic()) {
|
|
73411
|
+
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="startRecording()">
|
|
73412
|
+
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73413
|
+
</button>
|
|
73414
|
+
}
|
|
73331
73415
|
@if (canSend()) {
|
|
73332
73416
|
<button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
|
|
73333
73417
|
<ion-icon name="arrow-up-outline" aria-hidden="true" />
|
|
73334
73418
|
</button>
|
|
73335
|
-
} @else if (showMic()) {
|
|
73336
|
-
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="startRecording()">
|
|
73337
|
-
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73338
|
-
</button>
|
|
73339
73419
|
}
|
|
73340
73420
|
</div>
|
|
73341
73421
|
</div>
|
|
@@ -73364,7 +73444,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
73364
73444
|
@for (att of pending(); track att.id) {
|
|
73365
73445
|
@if (att.kind === 'audio') {
|
|
73366
73446
|
<div class="audio-chip">
|
|
73367
|
-
<audio
|
|
73447
|
+
<audio
|
|
73448
|
+
controls
|
|
73449
|
+
preload="metadata"
|
|
73450
|
+
[src]="att.url"
|
|
73451
|
+
(error)="onAudioError('preview', att.file, $event)"
|
|
73452
|
+
(loadedmetadata)="onAudioLoaded('preview', att.file, $event)"
|
|
73453
|
+
></audio>
|
|
73368
73454
|
<button class="thumb-remove inline" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
|
|
73369
73455
|
<ion-icon name="close-outline" aria-hidden="true" />
|
|
73370
73456
|
</button>
|
|
@@ -73415,21 +73501,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
73415
73501
|
></div>
|
|
73416
73502
|
|
|
73417
73503
|
<div class="actions">
|
|
73504
|
+
<span class="actions-spacer"></span>
|
|
73418
73505
|
@if (showAttach()) {
|
|
73419
73506
|
<label class="icon-btn" [attr.aria-label]="t('attach')">
|
|
73420
73507
|
<ion-icon name="add-outline" aria-hidden="true" />
|
|
73421
73508
|
<input type="file" hidden (change)="onFile($event)" accept="image/*,application/pdf" />
|
|
73422
73509
|
</label>
|
|
73423
73510
|
}
|
|
73424
|
-
|
|
73511
|
+
@if (showMic()) {
|
|
73512
|
+
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="startRecording()">
|
|
73513
|
+
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73514
|
+
</button>
|
|
73515
|
+
}
|
|
73425
73516
|
@if (canSend()) {
|
|
73426
73517
|
<button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
|
|
73427
73518
|
<ion-icon name="arrow-up-outline" aria-hidden="true" />
|
|
73428
73519
|
</button>
|
|
73429
|
-
} @else if (showMic()) {
|
|
73430
|
-
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="startRecording()">
|
|
73431
|
-
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73432
|
-
</button>
|
|
73433
73520
|
}
|
|
73434
73521
|
</div>
|
|
73435
73522
|
</div>
|