@forgeroute/ui 0.4.78 → 0.4.79
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/fesm2022/forgeroute-ui-charts.mjs +30 -22
- package/fesm2022/forgeroute-ui-charts.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-maps.mjs +26 -18
- package/fesm2022/forgeroute-ui-maps.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-messaging.mjs +625 -544
- package/fesm2022/forgeroute-ui-messaging.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-offline.mjs +3036 -0
- package/fesm2022/forgeroute-ui-offline.mjs.map +1 -0
- package/fesm2022/forgeroute-ui-pdf.mjs +104 -71
- package/fesm2022/forgeroute-ui-pdf.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-stripe.mjs +291 -156
- package/fesm2022/forgeroute-ui-stripe.mjs.map +1 -1
- package/fesm2022/forgeroute-ui.mjs +13952 -5665
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +5 -1
- package/types/forgeroute-ui-charts.d.ts +10 -4
- package/types/forgeroute-ui-maps.d.ts +5 -2
- package/types/forgeroute-ui-messaging.d.ts +57 -36
- package/types/forgeroute-ui-offline.d.ts +887 -0
- package/types/forgeroute-ui-pdf.d.ts +24 -12
- package/types/forgeroute-ui-stripe.d.ts +72 -54
- package/types/forgeroute-ui.d.ts +3257 -334
|
@@ -4,7 +4,7 @@ import * as i1 from "@angular/forms";
|
|
|
4
4
|
import { FormsModule } from "@angular/forms";
|
|
5
5
|
import { HttpClient, HttpErrorResponse } from "@angular/common/http";
|
|
6
6
|
import { takeUntilDestroyed, toObservable } from "@angular/core/rxjs-interop";
|
|
7
|
-
import { AlertComponent, BadgeComponent, ButtonComponent, CheckboxComponent, ChipComponent, ComboboxComponent, ContactPickerComponent, DatetimeInputComponent, ErrorComponent, FORGEROUTE_CONFIG, FormRowComponent, FormSectionComponent, HintComponent, PillTabsComponent, RadioGroupComponent, RichTextEditorComponent, SelectComponent, SidePanelComponent, TextInputComponent, TextareaInputComponent, ToastService, ToggleBadgeComponent, UiFieldValidity, createFieldReveal, getErrorMessage, requiredIssue } from "@forgeroute/ui";
|
|
7
|
+
import { AlertComponent, BadgeComponent, ButtonComponent, CheckboxComponent, ChipComponent, ComboboxComponent, ContactPickerComponent, DatetimeInputComponent, ErrorComponent, FORGEROUTE_CONFIG, FormRowComponent, FormSectionComponent, HintComponent, PillTabsComponent, RadioGroupComponent, RichTextEditorComponent, SelectComponent, SidePanelComponent, TextInputComponent, TextareaInputComponent, ToastService, ToggleBadgeComponent, UI_DEFAULT_LABELS, UiFieldValidity, UiLabelsService, createFieldReveal, formatAttachmentSize, getErrorMessage, requiredIssue, safeLocale, uiLocale, uiText } from "@forgeroute/ui";
|
|
8
8
|
import { Subject, catchError, debounceTime, defer, distinctUntilChanged, map, of, switchMap, take, throwError } from "rxjs";
|
|
9
9
|
let nextVideoPickerId = 0;
|
|
10
10
|
var VideoPickerComponent = class VideoPickerComponent {
|
|
@@ -12,6 +12,7 @@ var VideoPickerComponent = class VideoPickerComponent {
|
|
|
12
12
|
return `${this.uid}-opt-${i}`;
|
|
13
13
|
}
|
|
14
14
|
constructor() {
|
|
15
|
+
this.labels = inject(UiLabelsService);
|
|
15
16
|
this.videoSelected = output();
|
|
16
17
|
this.label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
17
18
|
this.required = input(false, ...ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []);
|
|
@@ -36,7 +37,7 @@ var VideoPickerComponent = class VideoPickerComponent {
|
|
|
36
37
|
this.activeIndex = signal(-1, ...ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []);
|
|
37
38
|
this.reveal = createFieldReveal(this.showErrors);
|
|
38
39
|
this.invalid = computed(() => this.required() && !this.selected(), ...ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []);
|
|
39
|
-
this.errorMessage = computed(() => this.invalid() ? requiredIssue(this.label() || "
|
|
40
|
+
this.errorMessage = computed(() => this.invalid() ? requiredIssue(this.label() || this.labels.t("common.video")).message : "", ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
40
41
|
this.visibleError = computed(() => this.reveal.revealed() ? this.errorMessage() : "", ...ngDevMode ? [{ debugName: "visibleError" }] : /* istanbul ignore next */ []);
|
|
41
42
|
this.activeDescendant = computed(() => {
|
|
42
43
|
const i = this.activeIndex();
|
|
@@ -44,9 +45,9 @@ var VideoPickerComponent = class VideoPickerComponent {
|
|
|
44
45
|
}, ...ngDevMode ? [{ debugName: "activeDescendant" }] : /* istanbul ignore next */ []);
|
|
45
46
|
this.liveText = computed(() => {
|
|
46
47
|
if (!this.showResults()) return "";
|
|
47
|
-
if (this.loading() || this.pending()) return "
|
|
48
|
+
if (this.loading() || this.pending()) return this.labels.t("search.searching");
|
|
48
49
|
const n = this.results().length;
|
|
49
|
-
return n === 0 ? "
|
|
50
|
+
return this.labels.t(n === 0 ? "messagingSendMessagePanel.resultsCount_zero" : n === 1 ? "messagingSendMessagePanel.resultsCount_one" : "messagingSendMessagePanel.resultsCount_other", { count: n });
|
|
50
51
|
}, ...ngDevMode ? [{ debugName: "liveText" }] : /* istanbul ignore next */ []);
|
|
51
52
|
this.search$ = new Subject();
|
|
52
53
|
this.blurTimer = null;
|
|
@@ -231,12 +232,12 @@ var VideoPickerComponent = class VideoPickerComponent {
|
|
|
231
232
|
}
|
|
232
233
|
@if (selected()) {
|
|
233
234
|
<div class="selected-input" role="group" tabindex="-1"
|
|
234
|
-
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : '
|
|
235
|
+
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : labels.t('messagingSendMessagePanel.selectedVideo')">
|
|
235
236
|
<div class="selected-video">
|
|
236
237
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
|
|
237
238
|
<span>{{ selected()!.title }}</span>
|
|
238
239
|
</div>
|
|
239
|
-
<button type="button" class="clear-btn" (click)="clear()" aria-label="
|
|
240
|
+
<button type="button" class="clear-btn" (click)="clear()" [attr.aria-label]="labels.t('messagingVideoPicker.removeVideo')">×</button>
|
|
240
241
|
</div>
|
|
241
242
|
} @else {
|
|
242
243
|
<input
|
|
@@ -245,9 +246,9 @@ var VideoPickerComponent = class VideoPickerComponent {
|
|
|
245
246
|
role="combobox"
|
|
246
247
|
aria-autocomplete="list"
|
|
247
248
|
aria-haspopup="listbox"
|
|
248
|
-
placeholder="
|
|
249
|
+
[placeholder]="labels.t('messagingVideoPicker.searchVideos')"
|
|
249
250
|
[id]="inputId"
|
|
250
|
-
[attr.aria-label]="label() ? null : '
|
|
251
|
+
[attr.aria-label]="label() ? null : labels.t('messagingSendMessagePanel.searchVideosAria')"
|
|
251
252
|
[attr.aria-required]="required() || null"
|
|
252
253
|
[attr.aria-invalid]="visibleError() ? 'true' : null"
|
|
253
254
|
[attr.aria-describedby]="visibleError() && !showResults() ? errorId : null"
|
|
@@ -263,12 +264,12 @@ var VideoPickerComponent = class VideoPickerComponent {
|
|
|
263
264
|
/>
|
|
264
265
|
@if (showResults()) {
|
|
265
266
|
<div class="picker-dropdown" role="listbox" [id]="listboxId"
|
|
266
|
-
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : '
|
|
267
|
+
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : labels.t('common.videos')"
|
|
267
268
|
(mousedown)="$event.preventDefault()">
|
|
268
269
|
@if (loading() || (pending() && results().length === 0)) {
|
|
269
|
-
<div class="picker-loading">
|
|
270
|
+
<div class="picker-loading">{{ labels.t('messagingVideoPicker.searching') }}</div>
|
|
270
271
|
} @else if (results().length === 0 && query.length >= 2) {
|
|
271
|
-
<div class="picker-empty">
|
|
272
|
+
<div class="picker-empty">{{ labels.t('messagingVideoPicker.noVideosFound') }}</div>
|
|
272
273
|
} @else {
|
|
273
274
|
@for (v of results(); track v.id; let i = $index) {
|
|
274
275
|
<button type="button" class="picker-option" role="option" tabindex="-1"
|
|
@@ -356,12 +357,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
356
357
|
}
|
|
357
358
|
@if (selected()) {
|
|
358
359
|
<div class="selected-input" role="group" tabindex="-1"
|
|
359
|
-
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : '
|
|
360
|
+
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : labels.t('messagingSendMessagePanel.selectedVideo')">
|
|
360
361
|
<div class="selected-video">
|
|
361
362
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
|
|
362
363
|
<span>{{ selected()!.title }}</span>
|
|
363
364
|
</div>
|
|
364
|
-
<button type="button" class="clear-btn" (click)="clear()" aria-label="
|
|
365
|
+
<button type="button" class="clear-btn" (click)="clear()" [attr.aria-label]="labels.t('messagingVideoPicker.removeVideo')">×</button>
|
|
365
366
|
</div>
|
|
366
367
|
} @else {
|
|
367
368
|
<input
|
|
@@ -370,9 +371,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
370
371
|
role="combobox"
|
|
371
372
|
aria-autocomplete="list"
|
|
372
373
|
aria-haspopup="listbox"
|
|
373
|
-
placeholder="
|
|
374
|
+
[placeholder]="labels.t('messagingVideoPicker.searchVideos')"
|
|
374
375
|
[id]="inputId"
|
|
375
|
-
[attr.aria-label]="label() ? null : '
|
|
376
|
+
[attr.aria-label]="label() ? null : labels.t('messagingSendMessagePanel.searchVideosAria')"
|
|
376
377
|
[attr.aria-required]="required() || null"
|
|
377
378
|
[attr.aria-invalid]="visibleError() ? 'true' : null"
|
|
378
379
|
[attr.aria-describedby]="visibleError() && !showResults() ? errorId : null"
|
|
@@ -388,12 +389,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
388
389
|
/>
|
|
389
390
|
@if (showResults()) {
|
|
390
391
|
<div class="picker-dropdown" role="listbox" [id]="listboxId"
|
|
391
|
-
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : '
|
|
392
|
+
[attr.aria-labelledby]="label() ? labelId : null" [attr.aria-label]="label() ? null : labels.t('common.videos')"
|
|
392
393
|
(mousedown)="$event.preventDefault()">
|
|
393
394
|
@if (loading() || (pending() && results().length === 0)) {
|
|
394
|
-
<div class="picker-loading">
|
|
395
|
+
<div class="picker-loading">{{ labels.t('messagingVideoPicker.searching') }}</div>
|
|
395
396
|
} @else if (results().length === 0 && query.length >= 2) {
|
|
396
|
-
<div class="picker-empty">
|
|
397
|
+
<div class="picker-empty">{{ labels.t('messagingVideoPicker.noVideosFound') }}</div>
|
|
397
398
|
} @else {
|
|
398
399
|
@for (v of results(); track v.id; let i = $index) {
|
|
399
400
|
<button type="button" class="picker-option" role="option" tabindex="-1"
|
|
@@ -464,6 +465,7 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
464
465
|
return `${this.uid}-opt-${i}`;
|
|
465
466
|
}
|
|
466
467
|
constructor() {
|
|
468
|
+
this.labels = inject(UiLabelsService);
|
|
467
469
|
this.http = inject(HttpClient);
|
|
468
470
|
this.apiBase = inject(FORGEROUTE_CONFIG, { optional: true })?.baseUrl ?? "/api";
|
|
469
471
|
this.destroyRef = inject(DestroyRef);
|
|
@@ -472,7 +474,11 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
472
474
|
this.search$ = new Subject();
|
|
473
475
|
this.channel = input("", ...ngDevMode ? [{ debugName: "channel" }] : /* istanbul ignore next */ []);
|
|
474
476
|
this.selectedId = input(null, ...ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []);
|
|
475
|
-
this.
|
|
477
|
+
this.labelInput = input(null, {
|
|
478
|
+
...ngDevMode ? { debugName: "labelInput" } : /* istanbul ignore next */ {},
|
|
479
|
+
alias: "label"
|
|
480
|
+
});
|
|
481
|
+
this.label = computed(() => this.labelInput() ?? this.labels.t("messagingTemplatePicker.label"), ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
476
482
|
this.required = input(false, ...ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []);
|
|
477
483
|
this.showErrors = input(false, ...ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []);
|
|
478
484
|
this.templateSelected = output();
|
|
@@ -490,9 +496,9 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
490
496
|
this.visibleError = computed(() => this.reveal.revealed() ? this.errorMessage() : "", ...ngDevMode ? [{ debugName: "visibleError" }] : /* istanbul ignore next */ []);
|
|
491
497
|
this.liveText = computed(() => {
|
|
492
498
|
if (!this.showResults()) return "";
|
|
493
|
-
if (this.loading()) return "
|
|
499
|
+
if (this.loading()) return this.labels.t("search.searching");
|
|
494
500
|
const n = this.results().length;
|
|
495
|
-
return n === 0 ? "
|
|
501
|
+
return this.labels.t(n === 0 ? "messagingSendMessagePanel.resultsCount_zero" : n === 1 ? "messagingSendMessagePanel.resultsCount_one" : "messagingSendMessagePanel.resultsCount_other", { count: n });
|
|
496
502
|
}, ...ngDevMode ? [{ debugName: "liveText" }] : /* istanbul ignore next */ []);
|
|
497
503
|
this.uid = `ui-tpl-${TemplatePickerComponent.nextId++}`;
|
|
498
504
|
this.inputId = `${this.uid}-input`;
|
|
@@ -501,20 +507,6 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
501
507
|
this.blurTimer = null;
|
|
502
508
|
this.lastOptionMouse = 0;
|
|
503
509
|
this.lastPreviewMouse = 0;
|
|
504
|
-
this.sampleVars = {
|
|
505
|
-
first_name: "Sarah",
|
|
506
|
-
last_name: "Johnson",
|
|
507
|
-
full_name: "Sarah Johnson",
|
|
508
|
-
email: "sarah@example.com",
|
|
509
|
-
phone: "(555) 867-5309",
|
|
510
|
-
property_address: "1842 Maple Grove Lane",
|
|
511
|
-
address: "1842 Maple Grove Lane",
|
|
512
|
-
price: "$485,000",
|
|
513
|
-
list_price: "$485,000",
|
|
514
|
-
agent_name: "Alex Rivera",
|
|
515
|
-
company_name: "Real Estate",
|
|
516
|
-
closing_date: "Sept 15, 2026"
|
|
517
|
-
};
|
|
518
510
|
effect(() => {
|
|
519
511
|
this.invalidChange.emit(this.invalid());
|
|
520
512
|
});
|
|
@@ -637,6 +629,22 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
637
629
|
body: tpl.body
|
|
638
630
|
});
|
|
639
631
|
}
|
|
632
|
+
get sampleVars() {
|
|
633
|
+
return {
|
|
634
|
+
first_name: "Sarah",
|
|
635
|
+
last_name: "Johnson",
|
|
636
|
+
full_name: "Sarah Johnson",
|
|
637
|
+
email: "sarah@example.com",
|
|
638
|
+
phone: "(555) 867-5309",
|
|
639
|
+
property_address: this.labels.t("messagingTemplatePicker.sampleAddress"),
|
|
640
|
+
address: this.labels.t("messagingTemplatePicker.sampleAddress"),
|
|
641
|
+
price: "$485,000",
|
|
642
|
+
list_price: "$485,000",
|
|
643
|
+
agent_name: "Alex Rivera",
|
|
644
|
+
company_name: this.labels.t("messagingTemplatePicker.sampleCompany"),
|
|
645
|
+
closing_date: this.labels.t("messagingTemplatePicker.sampleClosingDate")
|
|
646
|
+
};
|
|
647
|
+
}
|
|
640
648
|
previewText(raw) {
|
|
641
649
|
const resolved = raw.replace(/\{\{(\w+)\}\}/g, (_, k) => this.sampleVars[k] ?? "…");
|
|
642
650
|
return resolved.length > 80 ? resolved.slice(0, 80) + "…" : resolved;
|
|
@@ -652,15 +660,15 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
652
660
|
return true;
|
|
653
661
|
}
|
|
654
662
|
activeDateLabel(tpl) {
|
|
655
|
-
if (tpl.useAllYear !== false) return "
|
|
656
|
-
const fmt = (d) => new Date(d).toLocaleDateString(
|
|
663
|
+
if (tpl.useAllYear !== false) return this.labels.t("messagingSendMessagePanel.activeAllYear");
|
|
664
|
+
const fmt = (d) => new Date(d).toLocaleDateString(safeLocale(this.labels.locale()), {
|
|
657
665
|
month: "short",
|
|
658
666
|
day: "numeric"
|
|
659
667
|
});
|
|
660
668
|
if (tpl.activeFrom && tpl.activeTo) return `${fmt(tpl.activeFrom)} – ${fmt(tpl.activeTo)}`;
|
|
661
|
-
if (tpl.activeFrom) return
|
|
662
|
-
if (tpl.activeTo) return
|
|
663
|
-
return "
|
|
669
|
+
if (tpl.activeFrom) return this.labels.t("messagingSendMessagePanel.activeFrom", { date: fmt(tpl.activeFrom) });
|
|
670
|
+
if (tpl.activeTo) return this.labels.t("messagingSendMessagePanel.activeUntil", { date: fmt(tpl.activeTo) });
|
|
671
|
+
return this.labels.t("messagingSendMessagePanel.activeAllYear");
|
|
664
672
|
}
|
|
665
673
|
static {
|
|
666
674
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
@@ -694,8 +702,8 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
694
702
|
isRequired: false,
|
|
695
703
|
transformFunction: null
|
|
696
704
|
},
|
|
697
|
-
|
|
698
|
-
classPropertyName: "
|
|
705
|
+
labelInput: {
|
|
706
|
+
classPropertyName: "labelInput",
|
|
699
707
|
publicName: "label",
|
|
700
708
|
isSignal: true,
|
|
701
709
|
isRequired: false,
|
|
@@ -737,11 +745,11 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
737
745
|
type="text"
|
|
738
746
|
role="combobox"
|
|
739
747
|
[id]="inputId"
|
|
740
|
-
placeholder="
|
|
748
|
+
[placeholder]="labels.t('messagingTemplatePicker.searchTemplates')"
|
|
741
749
|
autocomplete="off"
|
|
742
750
|
aria-autocomplete="list"
|
|
743
751
|
aria-haspopup="listbox"
|
|
744
|
-
[attr.aria-label]="label() ? null : '
|
|
752
|
+
[attr.aria-label]="label() ? null : labels.t('messagingSendMessagePanel.searchTemplatesAria')"
|
|
745
753
|
[attr.aria-invalid]="visibleError() ? 'true' : null"
|
|
746
754
|
[attr.aria-describedby]="visibleError() && !showResults() ? errorId : null"
|
|
747
755
|
[attr.aria-required]="required() || null"
|
|
@@ -755,11 +763,11 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
755
763
|
(keydown)="onKeydown($event)" />
|
|
756
764
|
|
|
757
765
|
@if (showResults()) {
|
|
758
|
-
<div class="picker-dropdown" [id]="listId" role="listbox" [attr.aria-label]="label() || '
|
|
766
|
+
<div class="picker-dropdown" [id]="listId" role="listbox" [attr.aria-label]="label() || labels.t('messagingSendMessagePanel.searchTemplatesAria')" (mousedown)="$event.preventDefault()">
|
|
759
767
|
@if (loading()) {
|
|
760
|
-
<div class="picker-loading">
|
|
768
|
+
<div class="picker-loading">{{ labels.t('messagingTemplatePicker.searching') }}</div>
|
|
761
769
|
} @else if (results().length === 0) {
|
|
762
|
-
<div class="picker-empty">
|
|
770
|
+
<div class="picker-empty">{{ labels.t('messagingTemplatePicker.noTemplatesFound') }}</div>
|
|
763
771
|
} @else {
|
|
764
772
|
@for (tpl of results(); track tpl.id; let i = $index) {
|
|
765
773
|
<div
|
|
@@ -776,17 +784,17 @@ var TemplatePickerComponent = class TemplatePickerComponent {
|
|
|
776
784
|
<span class="option-title">
|
|
777
785
|
<span class="option-name">{{ tpl.name }}</span>
|
|
778
786
|
@if (tpl.isSystem !== undefined) {
|
|
779
|
-
<span class="option-badge" [class.system]="tpl.isSystem">{{ tpl.isSystem ? '
|
|
787
|
+
<span class="option-badge" [class.system]="tpl.isSystem">{{ tpl.isSystem ? labels.t('messagingTemplatePicker.system') : labels.t('messagingTemplatePicker.custom') }}</span>
|
|
780
788
|
}
|
|
781
789
|
</span>
|
|
782
790
|
<span class="option-detail">
|
|
783
|
-
@if (!isCurrentlyActive(tpl)) { <span class="option-inactive">
|
|
791
|
+
@if (!isCurrentlyActive(tpl)) { <span class="option-inactive">{{ labels.t('messagingTemplatePicker.inactive') }} · </span> }{{ previewText(tpl.subject || tpl.body) }}
|
|
784
792
|
</span>
|
|
785
793
|
</span>
|
|
786
794
|
<button
|
|
787
795
|
type="button"
|
|
788
796
|
class="option-preview-btn"
|
|
789
|
-
[attr.aria-label]="'
|
|
797
|
+
[attr.aria-label]="labels.t('messagingSendMessagePanel.previewNamed', { name: tpl.name })"
|
|
790
798
|
(mousedown)="$event.stopPropagation(); $event.preventDefault(); onPreviewMouseDown(tpl)"
|
|
791
799
|
(click)="$event.stopPropagation(); onPreviewClick(tpl)">
|
|
792
800
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
@@ -875,11 +883,11 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
875
883
|
type="text"
|
|
876
884
|
role="combobox"
|
|
877
885
|
[id]="inputId"
|
|
878
|
-
placeholder="
|
|
886
|
+
[placeholder]="labels.t('messagingTemplatePicker.searchTemplates')"
|
|
879
887
|
autocomplete="off"
|
|
880
888
|
aria-autocomplete="list"
|
|
881
889
|
aria-haspopup="listbox"
|
|
882
|
-
[attr.aria-label]="label() ? null : '
|
|
890
|
+
[attr.aria-label]="label() ? null : labels.t('messagingSendMessagePanel.searchTemplatesAria')"
|
|
883
891
|
[attr.aria-invalid]="visibleError() ? 'true' : null"
|
|
884
892
|
[attr.aria-describedby]="visibleError() && !showResults() ? errorId : null"
|
|
885
893
|
[attr.aria-required]="required() || null"
|
|
@@ -893,11 +901,11 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
893
901
|
(keydown)="onKeydown($event)" />
|
|
894
902
|
|
|
895
903
|
@if (showResults()) {
|
|
896
|
-
<div class="picker-dropdown" [id]="listId" role="listbox" [attr.aria-label]="label() || '
|
|
904
|
+
<div class="picker-dropdown" [id]="listId" role="listbox" [attr.aria-label]="label() || labels.t('messagingSendMessagePanel.searchTemplatesAria')" (mousedown)="$event.preventDefault()">
|
|
897
905
|
@if (loading()) {
|
|
898
|
-
<div class="picker-loading">
|
|
906
|
+
<div class="picker-loading">{{ labels.t('messagingTemplatePicker.searching') }}</div>
|
|
899
907
|
} @else if (results().length === 0) {
|
|
900
|
-
<div class="picker-empty">
|
|
908
|
+
<div class="picker-empty">{{ labels.t('messagingTemplatePicker.noTemplatesFound') }}</div>
|
|
901
909
|
} @else {
|
|
902
910
|
@for (tpl of results(); track tpl.id; let i = $index) {
|
|
903
911
|
<div
|
|
@@ -914,17 +922,17 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
914
922
|
<span class="option-title">
|
|
915
923
|
<span class="option-name">{{ tpl.name }}</span>
|
|
916
924
|
@if (tpl.isSystem !== undefined) {
|
|
917
|
-
<span class="option-badge" [class.system]="tpl.isSystem">{{ tpl.isSystem ? '
|
|
925
|
+
<span class="option-badge" [class.system]="tpl.isSystem">{{ tpl.isSystem ? labels.t('messagingTemplatePicker.system') : labels.t('messagingTemplatePicker.custom') }}</span>
|
|
918
926
|
}
|
|
919
927
|
</span>
|
|
920
928
|
<span class="option-detail">
|
|
921
|
-
@if (!isCurrentlyActive(tpl)) { <span class="option-inactive">
|
|
929
|
+
@if (!isCurrentlyActive(tpl)) { <span class="option-inactive">{{ labels.t('messagingTemplatePicker.inactive') }} · </span> }{{ previewText(tpl.subject || tpl.body) }}
|
|
922
930
|
</span>
|
|
923
931
|
</span>
|
|
924
932
|
<button
|
|
925
933
|
type="button"
|
|
926
934
|
class="option-preview-btn"
|
|
927
|
-
[attr.aria-label]="'
|
|
935
|
+
[attr.aria-label]="labels.t('messagingSendMessagePanel.previewNamed', { name: tpl.name })"
|
|
928
936
|
(mousedown)="$event.stopPropagation(); $event.preventDefault(); onPreviewMouseDown(tpl)"
|
|
929
937
|
(click)="$event.stopPropagation(); onPreviewClick(tpl)">
|
|
930
938
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
@@ -966,7 +974,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
966
974
|
required: false
|
|
967
975
|
}]
|
|
968
976
|
}],
|
|
969
|
-
|
|
977
|
+
labelInput: [{
|
|
970
978
|
type: i0.Input,
|
|
971
979
|
args: [{
|
|
972
980
|
isSignal: true,
|
|
@@ -1015,7 +1023,7 @@ const SIGNER_ROLES = [
|
|
|
1015
1023
|
"signer3",
|
|
1016
1024
|
"signer4"
|
|
1017
1025
|
];
|
|
1018
|
-
const SIGNER_ROLE_LABEL_DEFAULT = (role) =>
|
|
1026
|
+
const SIGNER_ROLE_LABEL_DEFAULT = (role) => uiText("messagingDocumentSendOptions.signerRole", { n: roleNumber(role) });
|
|
1019
1027
|
function roleNumber(role) {
|
|
1020
1028
|
return Number(role.slice(6));
|
|
1021
1029
|
}
|
|
@@ -1097,15 +1105,15 @@ function describeDocumentSigners(docs, states, cfg) {
|
|
|
1097
1105
|
info.roles = roles;
|
|
1098
1106
|
info.multiSigner = roles.length > 1;
|
|
1099
1107
|
const d = per[0].doc;
|
|
1100
|
-
if (roles.length > 1) info.fieldsLine =
|
|
1101
|
-
else if (informational && d.hasMapping !== void 0) info.fieldsLine = "
|
|
1108
|
+
if (roles.length > 1) info.fieldsLine = uiText("messagingDocumentSendOptions.fieldsForSigners", { count: roles.length });
|
|
1109
|
+
else if (informational && d.hasMapping !== void 0) info.fieldsLine = uiText("messagingDocumentSendOptions.noFieldsPlaced");
|
|
1102
1110
|
} else info.multiDocumentNote = signable.some((p) => effectiveRoles(p.state.roles).length > 1);
|
|
1103
1111
|
return info;
|
|
1104
1112
|
}
|
|
1105
1113
|
function countersignLine(info, cfg, viaDocuSign) {
|
|
1106
1114
|
if (!info || !cfg || info.informational || !info.countersign) return "";
|
|
1107
|
-
if (viaDocuSign) return "
|
|
1108
|
-
return
|
|
1115
|
+
if (viaDocuSign) return uiText("messagingDocumentSendOptions.youCountersign");
|
|
1116
|
+
return uiText("messagingDocumentSendOptions.countersignedBy", { name: cfg.countersignerName?.trim() || uiText("messagingDocumentSendOptions.you") });
|
|
1109
1117
|
}
|
|
1110
1118
|
function buildSigners(roles, recipient, picks) {
|
|
1111
1119
|
if (roles.length < 2) return null;
|
|
@@ -1129,12 +1137,15 @@ function signerProblems(roles, recipient, picks, cfg) {
|
|
|
1129
1137
|
for (const role of roles) {
|
|
1130
1138
|
const p = role === "signer1" ? recipient : picks[role];
|
|
1131
1139
|
if (!p) {
|
|
1132
|
-
out[role] =
|
|
1140
|
+
out[role] = uiText("validation.required", { label: signerRoleLabel(role, cfg) });
|
|
1133
1141
|
continue;
|
|
1134
1142
|
}
|
|
1135
|
-
if (cfg?.requireSignerEmail !== false && !(p.email ?? "").trim()) out[role] =
|
|
1143
|
+
if (cfg?.requireSignerEmail !== false && !(p.email ?? "").trim()) out[role] = uiText("messagingDocumentSendOptions.signerNoEmail", { name: p.name });
|
|
1136
1144
|
const earlier = seen.get(p.id);
|
|
1137
|
-
if (earlier && !cfg?.allowSameContactInRoles && !out[role]) out[role] =
|
|
1145
|
+
if (earlier && !cfg?.allowSameContactInRoles && !out[role]) out[role] = uiText("messagingDocumentSendOptions.signerAlreadyRole", {
|
|
1146
|
+
name: p.name,
|
|
1147
|
+
role: signerRoleLabel(earlier, cfg)
|
|
1148
|
+
});
|
|
1138
1149
|
if (!earlier) seen.set(p.id, role);
|
|
1139
1150
|
}
|
|
1140
1151
|
return out;
|
|
@@ -1157,7 +1168,7 @@ function forwardContext(ctx, types) {
|
|
|
1157
1168
|
} : { dropped };
|
|
1158
1169
|
}
|
|
1159
1170
|
function mergeFieldText(f) {
|
|
1160
|
-
const reason = f.detail?.trim() || (f.reason === "NO_CONTEXT"
|
|
1171
|
+
const reason = f.detail?.trim() || (f.reason === "NO_CONTEXT" || f.reason === "NO_DATA" || f.reason === "UNKNOWN_PATH" ? uiText(`messagingDocumentSendOptions.mergeReason.${f.reason}`) : "");
|
|
1161
1172
|
return reason ? `${f.label} (${reason})` : f.label;
|
|
1162
1173
|
}
|
|
1163
1174
|
function mergeWarningLines(res, docTitles) {
|
|
@@ -1166,11 +1177,11 @@ function mergeWarningLines(res, docTitles) {
|
|
|
1166
1177
|
return docs.map((d) => {
|
|
1167
1178
|
const list = d.empty.map(mergeFieldText).join(", ");
|
|
1168
1179
|
const title = d.title || docTitles[d.documentId] || "";
|
|
1169
|
-
return `${prefixed && title ? `${title}: ` : ""}
|
|
1180
|
+
return `${prefixed && title ? `${title}: ` : ""}${uiText("messagingDocumentSendOptions.mergeEmpty", { list })}`;
|
|
1170
1181
|
});
|
|
1171
1182
|
}
|
|
1172
1183
|
function countersignPlaceLabel(title) {
|
|
1173
|
-
return
|
|
1184
|
+
return uiText("messagingDocumentSendOptions.placeCountersignOn", { title });
|
|
1174
1185
|
}
|
|
1175
1186
|
const DEFAULT_SIGNING_OPTIONS = {
|
|
1176
1187
|
expiryDays: 7,
|
|
@@ -1225,12 +1236,20 @@ const INFORMATIONAL_PURPOSE_LABELS = {
|
|
|
1225
1236
|
BOTH: "View link and attachment"
|
|
1226
1237
|
};
|
|
1227
1238
|
var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
1239
|
+
get searchFailedMessage() {
|
|
1240
|
+
return this.labels.t("messagingDocumentSendOptions.searchFailedMessage");
|
|
1241
|
+
}
|
|
1228
1242
|
constructor() {
|
|
1243
|
+
this.labels = inject(UiLabelsService);
|
|
1229
1244
|
this.http = inject(HttpClient);
|
|
1230
1245
|
this.destroyRef = inject(DestroyRef);
|
|
1231
1246
|
this.apiBase = inject(FORGEROUTE_CONFIG, { optional: true })?.baseUrl ?? "/api";
|
|
1232
1247
|
this.channel = input("email", ...ngDevMode ? [{ debugName: "channel" }] : /* istanbul ignore next */ []);
|
|
1233
|
-
this.
|
|
1248
|
+
this.labelInput = input(null, {
|
|
1249
|
+
...ngDevMode ? { debugName: "labelInput" } : /* istanbul ignore next */ {},
|
|
1250
|
+
alias: "label"
|
|
1251
|
+
});
|
|
1252
|
+
this.label = computed(() => this.labelInput() ?? this.labels.t("messagingDocumentSendOptions.label"), ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
1234
1253
|
this.required = input(false, ...ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []);
|
|
1235
1254
|
this.showErrors = input(false, ...ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []);
|
|
1236
1255
|
this.valueChange = output();
|
|
@@ -1252,11 +1271,14 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1252
1271
|
this.purposeOptions = computed(() => {
|
|
1253
1272
|
const allowed = this.purposes();
|
|
1254
1273
|
const base = DOCUMENT_PURPOSE_OPTIONS.filter((o) => allowed.includes(o.value));
|
|
1255
|
-
const opts = base.length ? base : DOCUMENT_PURPOSE_OPTIONS
|
|
1256
|
-
return this.signerInfo()?.informational ? opts.map((o) => ({
|
|
1274
|
+
const opts = (base.length ? base : DOCUMENT_PURPOSE_OPTIONS).map((o) => ({
|
|
1257
1275
|
...o,
|
|
1258
|
-
label:
|
|
1259
|
-
}))
|
|
1276
|
+
label: this.labels.t(`messagingDocumentSendOptions.purpose.${o.value}`)
|
|
1277
|
+
}));
|
|
1278
|
+
return this.signerInfo()?.informational ? opts.map((o) => INFORMATIONAL_PURPOSE_LABELS[o.value] ? {
|
|
1279
|
+
...o,
|
|
1280
|
+
label: this.labels.t(`messagingDocumentSendOptions.purposeInfo.${o.value}`)
|
|
1281
|
+
} : o) : opts;
|
|
1260
1282
|
}, ...ngDevMode ? [{ debugName: "purposeOptions" }] : /* istanbul ignore next */ []);
|
|
1261
1283
|
this.search$ = new Subject();
|
|
1262
1284
|
this.options = signal([], ...ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []);
|
|
@@ -1272,10 +1294,15 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1272
1294
|
this.expiryDays = signal(String(DEFAULT_SIGNING_OPTIONS.expiryDays), ...ngDevMode ? [{ debugName: "expiryDays" }] : /* istanbul ignore next */ []);
|
|
1273
1295
|
this.reminderIntervalDays = signal(String(DEFAULT_SIGNING_OPTIONS.reminderIntervalDays), ...ngDevMode ? [{ debugName: "reminderIntervalDays" }] : /* istanbul ignore next */ []);
|
|
1274
1296
|
this.maxReminders = signal(String(DEFAULT_SIGNING_OPTIONS.maxReminders), ...ngDevMode ? [{ debugName: "maxReminders" }] : /* istanbul ignore next */ []);
|
|
1275
|
-
this.providerOptions =
|
|
1297
|
+
this.providerOptions = computed(() => [{
|
|
1298
|
+
value: "NATIVE",
|
|
1299
|
+
label: this.labels.t("messagingDocumentSendOptions.provider.native")
|
|
1300
|
+
}, {
|
|
1301
|
+
value: "DOCUSIGN",
|
|
1302
|
+
label: this.labels.t("messagingDocumentSendOptions.provider.docusign")
|
|
1303
|
+
}], ...ngDevMode ? [{ debugName: "providerOptions" }] : /* istanbul ignore next */ []);
|
|
1276
1304
|
this.combo = viewChild(ComboboxComponent, ...ngDevMode ? [{ debugName: "combo" }] : /* istanbul ignore next */ []);
|
|
1277
1305
|
this.searchFailed = signal(false, ...ngDevMode ? [{ debugName: "searchFailed" }] : /* istanbul ignore next */ []);
|
|
1278
|
-
this.searchFailedMessage = "Couldn't search your documents. Check your connection and try again.";
|
|
1279
1306
|
this.available = computed(() => this.channel() !== "text" || this.purposes().includes("ESIGN"), ...ngDevMode ? [{ debugName: "available" }] : /* istanbul ignore next */ []);
|
|
1280
1307
|
this.providerChoiceShown = computed(() => {
|
|
1281
1308
|
if (!(this.docuSignConnected() && this.channel() === "email" && this.selected().length === 1 && this.purposes().includes("ESIGN"))) return false;
|
|
@@ -1290,23 +1317,32 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1290
1317
|
this.envelopeProblem = computed(() => {
|
|
1291
1318
|
if (!this.envelope() || this.envelopeStatus() !== "ready") return "";
|
|
1292
1319
|
const docs = this.selected();
|
|
1293
|
-
if (docs.length === 0) return
|
|
1320
|
+
if (docs.length === 0) return this.labels.t("messagingDocumentSendOptions.envelopeNoDocs");
|
|
1294
1321
|
const inactive = docs.find((d) => d.status !== void 0 && d.status !== "ACTIVE");
|
|
1295
|
-
return inactive ?
|
|
1322
|
+
return inactive ? this.labels.t("messagingDocumentSendOptions.envelopeInactive", {
|
|
1323
|
+
title: inactive.title,
|
|
1324
|
+
status: inactive.status.toLowerCase()
|
|
1325
|
+
}) : "";
|
|
1296
1326
|
}, ...ngDevMode ? [{ debugName: "envelopeProblem" }] : /* istanbul ignore next */ []);
|
|
1297
1327
|
this.envelopeReadMessage = computed(() => {
|
|
1298
1328
|
const status = this.envelopeStatus();
|
|
1299
|
-
return status === "loading" ? "
|
|
1329
|
+
return status === "loading" ? this.labels.t("messagingDocumentSendOptions.envelopeReading") : status === "error" ? this.labels.t("messagingDocumentSendOptions.envelopeReadFailed") : "";
|
|
1300
1330
|
}, ...ngDevMode ? [{ debugName: "envelopeReadMessage" }] : /* istanbul ignore next */ []);
|
|
1301
1331
|
this.signerReadMessage = computed(() => {
|
|
1302
1332
|
const status = this.signerInfo()?.status;
|
|
1303
|
-
return status === "loading" ? "
|
|
1333
|
+
return status === "loading" ? this.labels.t("messagingDocumentSendOptions.signersReading") : status === "error" ? this.labels.t("messagingDocumentSendOptions.signersReadFailed") : "";
|
|
1304
1334
|
}, ...ngDevMode ? [{ debugName: "signerReadMessage" }] : /* istanbul ignore next */ []);
|
|
1305
1335
|
this.signingSummary = computed(() => {
|
|
1306
|
-
const day = (raw) =>
|
|
1336
|
+
const day = (raw) => this.labels.t(raw.trim() === "1" ? "messagingDocumentSendOptions.day_one" : "messagingDocumentSendOptions.day_other", { n: raw });
|
|
1307
1337
|
const max = this.maxReminders().trim();
|
|
1308
|
-
const reminders = max === "0" ? "
|
|
1309
|
-
|
|
1338
|
+
const reminders = max === "0" ? this.labels.t("messagingDocumentSendOptions.noReminders") : this.labels.t("messagingDocumentSendOptions.remindersEvery", {
|
|
1339
|
+
interval: day(this.reminderIntervalDays().trim()),
|
|
1340
|
+
max
|
|
1341
|
+
});
|
|
1342
|
+
return this.labels.t("messagingDocumentSendOptions.signingSummary", {
|
|
1343
|
+
expiry: day(this.expiryDays().trim()),
|
|
1344
|
+
reminders
|
|
1345
|
+
});
|
|
1310
1346
|
}, ...ngDevMode ? [{ debugName: "signingSummary" }] : /* istanbul ignore next */ []);
|
|
1311
1347
|
this.signingExpanded = computed(() => this.signingOpen() || this.signingError() !== "", ...ngDevMode ? [{ debugName: "signingExpanded" }] : /* istanbul ignore next */ []);
|
|
1312
1348
|
this.purpose = computed(() => {
|
|
@@ -1343,24 +1379,29 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1343
1379
|
["maxReminders", this.maxReminders()]
|
|
1344
1380
|
];
|
|
1345
1381
|
for (const [key, raw] of fields) {
|
|
1346
|
-
const { min, max
|
|
1382
|
+
const { min, max } = SIGNING_LIMITS[key];
|
|
1383
|
+
const label = this.labels.t(`messagingDocumentSendOptions.${key}`);
|
|
1347
1384
|
const n = wholeNumber(raw);
|
|
1348
|
-
if ((raw ?? "").trim() === "") return
|
|
1349
|
-
if (n === null || n < min || n > max) return
|
|
1385
|
+
if ((raw ?? "").trim() === "") return this.labels.t("validation.required", { label });
|
|
1386
|
+
if (n === null || n < min || n > max) return this.labels.t("messagingDocumentSendOptions.mustBeWhole", {
|
|
1387
|
+
label,
|
|
1388
|
+
min,
|
|
1389
|
+
max
|
|
1390
|
+
});
|
|
1350
1391
|
}
|
|
1351
1392
|
return "";
|
|
1352
1393
|
}, ...ngDevMode ? [{ debugName: "signingError" }] : /* istanbul ignore next */ []);
|
|
1353
1394
|
this.documentError = computed(() => {
|
|
1354
1395
|
const docs = this.selected();
|
|
1355
|
-
if (this.required() && docs.length === 0) return "
|
|
1396
|
+
if (this.required() && docs.length === 0) return this.labels.t("messagingDocumentSendOptions.selectAtLeastOne");
|
|
1356
1397
|
if (this.purpose() === "ATTACH") {
|
|
1357
1398
|
const noFile = docs.find((d) => !d.hasFile);
|
|
1358
|
-
if (noFile) return
|
|
1399
|
+
if (noFile) return this.labels.t("messagingDocumentSendOptions.noFileToAttach", { title: noFile.title });
|
|
1359
1400
|
}
|
|
1360
1401
|
const env = this.envelopeProblem();
|
|
1361
1402
|
if (env) return env;
|
|
1362
1403
|
const info = this.signerInfo();
|
|
1363
|
-
if (info?.multiSigner && this.channel() === "text") return
|
|
1404
|
+
if (info?.multiSigner && this.channel() === "text") return this.labels.t("messagingDocumentSendOptions.multiSignerSendByEmail", { count: info.roles.length });
|
|
1364
1405
|
return "";
|
|
1365
1406
|
}, ...ngDevMode ? [{ debugName: "documentError" }] : /* istanbul ignore next */ []);
|
|
1366
1407
|
this.errorMessage = computed(() => this.documentError() || this.envelopeReadMessage() || this.signerReadMessage() || this.signingError(), ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
@@ -1393,7 +1434,7 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1393
1434
|
return {
|
|
1394
1435
|
value: doc.id,
|
|
1395
1436
|
label: doc.title,
|
|
1396
|
-
description: doc.fileName ?? "
|
|
1437
|
+
description: doc.fileName ?? this.labels.t("messagingDocumentSendOptions.noFileUploaded"),
|
|
1397
1438
|
data: doc
|
|
1398
1439
|
};
|
|
1399
1440
|
}));
|
|
@@ -1511,7 +1552,7 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1511
1552
|
static toOption(d) {
|
|
1512
1553
|
return {
|
|
1513
1554
|
id: String(d.id),
|
|
1514
|
-
title: String(d.title ?? d.fileName ?? "
|
|
1555
|
+
title: String(d.title ?? d.fileName ?? uiText("messagingDocumentSendOptions.untitled")),
|
|
1515
1556
|
fileName: d.fileName ?? null,
|
|
1516
1557
|
hasFile: Number(d.fileSize ?? 0) > 0 || !!d.fileName,
|
|
1517
1558
|
...d.requiresCountersign === true ? { requiresCountersign: true } : {},
|
|
@@ -1652,8 +1693,8 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1652
1693
|
isRequired: false,
|
|
1653
1694
|
transformFunction: null
|
|
1654
1695
|
},
|
|
1655
|
-
|
|
1656
|
-
classPropertyName: "
|
|
1696
|
+
labelInput: {
|
|
1697
|
+
classPropertyName: "labelInput",
|
|
1657
1698
|
publicName: "label",
|
|
1658
1699
|
isSignal: true,
|
|
1659
1700
|
isRequired: false,
|
|
@@ -1757,35 +1798,34 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1757
1798
|
<div class="dso" role="group" [attr.aria-label]="label()">
|
|
1758
1799
|
@if (available()) {
|
|
1759
1800
|
@if (locked()) {
|
|
1760
|
-
<p class="dso-locked-label" data-testid="locked-documents-label">
|
|
1801
|
+
<p class="dso-locked-label" data-testid="locked-documents-label">{{ labels.t('messagingDocumentSendOptions.includedDocuments') }}</p>
|
|
1761
1802
|
@if (envelopeStatus() === 'loading') {
|
|
1762
1803
|
<div role="status"><ui-hint data-testid="envelope-loading">{{ envelopeReadMessage() }}</ui-hint></div>
|
|
1763
1804
|
} @else if (envelopeStatus() === 'error') {
|
|
1764
1805
|
<div class="dso-retry">
|
|
1765
1806
|
<ui-error errorId="dso-envelope-error" [message]="envelopeReadMessage()" />
|
|
1766
|
-
<ui-button variant="secondary" size="sm" (click)="retryEnvelope()">
|
|
1807
|
+
<ui-button variant="secondary" size="sm" (click)="retryEnvelope()">{{ labels.t('common.retry') }}</ui-button>
|
|
1767
1808
|
</div>
|
|
1768
1809
|
}
|
|
1769
1810
|
} @else {
|
|
1770
1811
|
<ui-combobox
|
|
1771
1812
|
[label]="label()"
|
|
1772
1813
|
[required]="required()"
|
|
1773
|
-
placeholder="
|
|
1814
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchYourDocumentsByName')"
|
|
1774
1815
|
[options]="options()"
|
|
1775
1816
|
[loading]="loading()"
|
|
1776
1817
|
[minChars]="2"
|
|
1777
|
-
[noResultsText]="searchFailed() ? '
|
|
1778
|
-
[hint]="channel() === 'text' ? '
|
|
1818
|
+
[noResultsText]="searchFailed() ? labels.t('messagingDocumentSendOptions.searchFailed') : labels.t('messagingDocumentSendOptions.noMatchingDocuments')"
|
|
1819
|
+
[hint]="channel() === 'text' ? labels.t('messagingDocumentSendOptions.textedAsLink') : ''"
|
|
1779
1820
|
[error]="searchFailed() ? searchFailedMessage : ''"
|
|
1780
1821
|
[showErrors]="searchFailed()"
|
|
1781
1822
|
(searchChange)="search$.next($event)"
|
|
1782
1823
|
(valueChange)="onPick($event)" />
|
|
1783
|
-
<ui-error errorId="dso-search-error" [message]="searchFailed() ? 'Couldn\\'t search your documents. Check your connection and try again.' : ''" />
|
|
1784
1824
|
}
|
|
1785
1825
|
|
|
1786
1826
|
@if (selected().length > 0) {
|
|
1787
1827
|
<!-- One row per document: the chip (or the plain title when the list is fixed) and, beside it, its small Preview button. -->
|
|
1788
|
-
<div class="dso-docs" role="group" aria-label="
|
|
1828
|
+
<div class="dso-docs" role="group" [attr.aria-label]="labels.t('messagingDocumentSendOptions.chosenDocuments')">
|
|
1789
1829
|
@for (d of selected(); track d.id) {
|
|
1790
1830
|
<div class="dso-doc">
|
|
1791
1831
|
@if (locked()) {
|
|
@@ -1797,8 +1837,8 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1797
1837
|
@if (documentPreview()) {
|
|
1798
1838
|
<ui-button
|
|
1799
1839
|
variant="secondary" size="sm"
|
|
1800
|
-
[ariaLabel]="selected().length === 1 ? undefined : '
|
|
1801
|
-
(click)="preview(d)">{{ selected().length === 1 ? '
|
|
1840
|
+
[ariaLabel]="selected().length === 1 ? undefined : labels.t('messagingSendMessagePanel.previewNamed', { name: d.title })"
|
|
1841
|
+
(click)="preview(d)">{{ selected().length === 1 ? labels.t('messagingDocumentSendOptions.previewDocument') : labels.t('common.preview') }}</ui-button>
|
|
1802
1842
|
}
|
|
1803
1843
|
</div>
|
|
1804
1844
|
}
|
|
@@ -1813,30 +1853,30 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1813
1853
|
} @else if (signerInfo()?.status === 'error') {
|
|
1814
1854
|
<div class="dso-retry">
|
|
1815
1855
|
<ui-error errorId="dso-roles-error" [message]="signerReadMessage()" />
|
|
1816
|
-
<ui-button variant="secondary" size="sm" (click)="retryRoles()">
|
|
1856
|
+
<ui-button variant="secondary" size="sm" (click)="retryRoles()">{{ labels.t('common.retry') }}</ui-button>
|
|
1817
1857
|
</div>
|
|
1818
1858
|
}
|
|
1819
1859
|
|
|
1820
1860
|
@if (providerChoiceShown()) {
|
|
1821
1861
|
<ui-radio-group
|
|
1822
|
-
label="
|
|
1862
|
+
[label]="labels.t('messagingDocumentSendOptions.signatureProvider')"
|
|
1823
1863
|
orientation="horizontal"
|
|
1824
|
-
[options]="providerOptions"
|
|
1864
|
+
[options]="providerOptions()"
|
|
1825
1865
|
[ngModel]="provider()"
|
|
1826
1866
|
(ngModelChange)="setProvider($event)" />
|
|
1827
1867
|
}
|
|
1828
1868
|
|
|
1829
1869
|
@if (provider() === 'DOCUSIGN') {
|
|
1830
|
-
<ui-hint>
|
|
1870
|
+
<ui-hint>{{ labels.t('messagingDocumentSendOptions.docusignEmailsTheDocumentTo') }}</ui-hint>
|
|
1831
1871
|
@if (showCountersign()) {
|
|
1832
1872
|
<ui-checkbox
|
|
1833
|
-
label="
|
|
1873
|
+
[label]="labels.t('messagingDocumentSendOptions.requireMyCountersignatureAfterClient')"
|
|
1834
1874
|
[ngModel]="countersignChoice()"
|
|
1835
1875
|
(ngModelChange)="countersignChoice.set(!!$event)" />
|
|
1836
1876
|
}
|
|
1837
1877
|
} @else if (channel() === 'email' && selected().length > 0 && purposeOptions().length > 1) {
|
|
1838
1878
|
<ui-select
|
|
1839
|
-
label="
|
|
1879
|
+
[label]="labels.t('messagingDocumentSendOptions.whatShouldTheRecipientDo')"
|
|
1840
1880
|
[options]="purposeOptions()"
|
|
1841
1881
|
[ngModel]="purpose()"
|
|
1842
1882
|
(ngModelChange)="setPurpose($event)" />
|
|
@@ -1852,21 +1892,21 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1852
1892
|
<ui-button
|
|
1853
1893
|
variant="ghost" size="xs"
|
|
1854
1894
|
[ariaExpanded]="signingExpanded()"
|
|
1855
|
-
[ariaLabel]="signingExpanded() ? '
|
|
1856
|
-
(click)="toggleSigning()">{{ signingExpanded() ? '
|
|
1895
|
+
[ariaLabel]="signingExpanded() ? labels.t('messagingDocumentSendOptions.hideSigningOptions') : labels.t('messagingDocumentSendOptions.changeSigningOptions')"
|
|
1896
|
+
(click)="toggleSigning()">{{ signingExpanded() ? labels.t('common.hide') : labels.t('common.change') }}</ui-button>
|
|
1857
1897
|
</div>
|
|
1858
1898
|
@if (signingExpanded()) {
|
|
1859
1899
|
<ui-form-section>
|
|
1860
1900
|
<!-- One column: three labelled number fields do not fit side by side in a 480px panel or on a phone. -->
|
|
1861
1901
|
<ui-form-row [cols]="1">
|
|
1862
1902
|
<ui-text-input
|
|
1863
|
-
label="
|
|
1903
|
+
[label]="labels.t('messagingDocumentSendOptions.expiryDays')" type="number" [required]="true" [min]="1" [max]="90" [maxDecimals]="0"
|
|
1864
1904
|
[showErrors]="showErrors()" [ngModel]="expiryDays()" (ngModelChange)="expiryDays.set(asText($event))" />
|
|
1865
1905
|
<ui-text-input
|
|
1866
|
-
label="
|
|
1906
|
+
[label]="labels.t('messagingDocumentSendOptions.reminderIntervalDays')" type="number" [required]="true" [min]="1" [max]="30" [maxDecimals]="0"
|
|
1867
1907
|
[showErrors]="showErrors()" [ngModel]="reminderIntervalDays()" (ngModelChange)="reminderIntervalDays.set(asText($event))" />
|
|
1868
1908
|
<ui-text-input
|
|
1869
|
-
label="
|
|
1909
|
+
[label]="labels.t('messagingDocumentSendOptions.maxReminders')" type="number" [required]="true" [min]="0" [max]="10" [maxDecimals]="0"
|
|
1870
1910
|
[showErrors]="showErrors()" [ngModel]="maxReminders()" (ngModelChange)="maxReminders.set(asText($event))" />
|
|
1871
1911
|
</ui-form-row>
|
|
1872
1912
|
</ui-form-section>
|
|
@@ -1874,7 +1914,7 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1874
1914
|
</div>
|
|
1875
1915
|
}
|
|
1876
1916
|
} @else {
|
|
1877
|
-
<p class="dso-unavailable" role="note">
|
|
1917
|
+
<p class="dso-unavailable" role="note">{{ labels.t('messagingDocumentSendOptions.documentsCanOnlyBeTexted') }}</p>
|
|
1878
1918
|
}
|
|
1879
1919
|
</div>
|
|
1880
1920
|
`,
|
|
@@ -2157,35 +2197,34 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2157
2197
|
<div class="dso" role="group" [attr.aria-label]="label()">
|
|
2158
2198
|
@if (available()) {
|
|
2159
2199
|
@if (locked()) {
|
|
2160
|
-
<p class="dso-locked-label" data-testid="locked-documents-label">
|
|
2200
|
+
<p class="dso-locked-label" data-testid="locked-documents-label">{{ labels.t('messagingDocumentSendOptions.includedDocuments') }}</p>
|
|
2161
2201
|
@if (envelopeStatus() === 'loading') {
|
|
2162
2202
|
<div role="status"><ui-hint data-testid="envelope-loading">{{ envelopeReadMessage() }}</ui-hint></div>
|
|
2163
2203
|
} @else if (envelopeStatus() === 'error') {
|
|
2164
2204
|
<div class="dso-retry">
|
|
2165
2205
|
<ui-error errorId="dso-envelope-error" [message]="envelopeReadMessage()" />
|
|
2166
|
-
<ui-button variant="secondary" size="sm" (click)="retryEnvelope()">
|
|
2206
|
+
<ui-button variant="secondary" size="sm" (click)="retryEnvelope()">{{ labels.t('common.retry') }}</ui-button>
|
|
2167
2207
|
</div>
|
|
2168
2208
|
}
|
|
2169
2209
|
} @else {
|
|
2170
2210
|
<ui-combobox
|
|
2171
2211
|
[label]="label()"
|
|
2172
2212
|
[required]="required()"
|
|
2173
|
-
placeholder="
|
|
2213
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchYourDocumentsByName')"
|
|
2174
2214
|
[options]="options()"
|
|
2175
2215
|
[loading]="loading()"
|
|
2176
2216
|
[minChars]="2"
|
|
2177
|
-
[noResultsText]="searchFailed() ? '
|
|
2178
|
-
[hint]="channel() === 'text' ? '
|
|
2217
|
+
[noResultsText]="searchFailed() ? labels.t('messagingDocumentSendOptions.searchFailed') : labels.t('messagingDocumentSendOptions.noMatchingDocuments')"
|
|
2218
|
+
[hint]="channel() === 'text' ? labels.t('messagingDocumentSendOptions.textedAsLink') : ''"
|
|
2179
2219
|
[error]="searchFailed() ? searchFailedMessage : ''"
|
|
2180
2220
|
[showErrors]="searchFailed()"
|
|
2181
2221
|
(searchChange)="search$.next($event)"
|
|
2182
2222
|
(valueChange)="onPick($event)" />
|
|
2183
|
-
<ui-error errorId="dso-search-error" [message]="searchFailed() ? 'Couldn\\'t search your documents. Check your connection and try again.' : ''" />
|
|
2184
2223
|
}
|
|
2185
2224
|
|
|
2186
2225
|
@if (selected().length > 0) {
|
|
2187
2226
|
<!-- One row per document: the chip (or the plain title when the list is fixed) and, beside it, its small Preview button. -->
|
|
2188
|
-
<div class="dso-docs" role="group" aria-label="
|
|
2227
|
+
<div class="dso-docs" role="group" [attr.aria-label]="labels.t('messagingDocumentSendOptions.chosenDocuments')">
|
|
2189
2228
|
@for (d of selected(); track d.id) {
|
|
2190
2229
|
<div class="dso-doc">
|
|
2191
2230
|
@if (locked()) {
|
|
@@ -2197,8 +2236,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2197
2236
|
@if (documentPreview()) {
|
|
2198
2237
|
<ui-button
|
|
2199
2238
|
variant="secondary" size="sm"
|
|
2200
|
-
[ariaLabel]="selected().length === 1 ? undefined : '
|
|
2201
|
-
(click)="preview(d)">{{ selected().length === 1 ? '
|
|
2239
|
+
[ariaLabel]="selected().length === 1 ? undefined : labels.t('messagingSendMessagePanel.previewNamed', { name: d.title })"
|
|
2240
|
+
(click)="preview(d)">{{ selected().length === 1 ? labels.t('messagingDocumentSendOptions.previewDocument') : labels.t('common.preview') }}</ui-button>
|
|
2202
2241
|
}
|
|
2203
2242
|
</div>
|
|
2204
2243
|
}
|
|
@@ -2213,30 +2252,30 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2213
2252
|
} @else if (signerInfo()?.status === 'error') {
|
|
2214
2253
|
<div class="dso-retry">
|
|
2215
2254
|
<ui-error errorId="dso-roles-error" [message]="signerReadMessage()" />
|
|
2216
|
-
<ui-button variant="secondary" size="sm" (click)="retryRoles()">
|
|
2255
|
+
<ui-button variant="secondary" size="sm" (click)="retryRoles()">{{ labels.t('common.retry') }}</ui-button>
|
|
2217
2256
|
</div>
|
|
2218
2257
|
}
|
|
2219
2258
|
|
|
2220
2259
|
@if (providerChoiceShown()) {
|
|
2221
2260
|
<ui-radio-group
|
|
2222
|
-
label="
|
|
2261
|
+
[label]="labels.t('messagingDocumentSendOptions.signatureProvider')"
|
|
2223
2262
|
orientation="horizontal"
|
|
2224
|
-
[options]="providerOptions"
|
|
2263
|
+
[options]="providerOptions()"
|
|
2225
2264
|
[ngModel]="provider()"
|
|
2226
2265
|
(ngModelChange)="setProvider($event)" />
|
|
2227
2266
|
}
|
|
2228
2267
|
|
|
2229
2268
|
@if (provider() === 'DOCUSIGN') {
|
|
2230
|
-
<ui-hint>
|
|
2269
|
+
<ui-hint>{{ labels.t('messagingDocumentSendOptions.docusignEmailsTheDocumentTo') }}</ui-hint>
|
|
2231
2270
|
@if (showCountersign()) {
|
|
2232
2271
|
<ui-checkbox
|
|
2233
|
-
label="
|
|
2272
|
+
[label]="labels.t('messagingDocumentSendOptions.requireMyCountersignatureAfterClient')"
|
|
2234
2273
|
[ngModel]="countersignChoice()"
|
|
2235
2274
|
(ngModelChange)="countersignChoice.set(!!$event)" />
|
|
2236
2275
|
}
|
|
2237
2276
|
} @else if (channel() === 'email' && selected().length > 0 && purposeOptions().length > 1) {
|
|
2238
2277
|
<ui-select
|
|
2239
|
-
label="
|
|
2278
|
+
[label]="labels.t('messagingDocumentSendOptions.whatShouldTheRecipientDo')"
|
|
2240
2279
|
[options]="purposeOptions()"
|
|
2241
2280
|
[ngModel]="purpose()"
|
|
2242
2281
|
(ngModelChange)="setPurpose($event)" />
|
|
@@ -2252,21 +2291,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2252
2291
|
<ui-button
|
|
2253
2292
|
variant="ghost" size="xs"
|
|
2254
2293
|
[ariaExpanded]="signingExpanded()"
|
|
2255
|
-
[ariaLabel]="signingExpanded() ? '
|
|
2256
|
-
(click)="toggleSigning()">{{ signingExpanded() ? '
|
|
2294
|
+
[ariaLabel]="signingExpanded() ? labels.t('messagingDocumentSendOptions.hideSigningOptions') : labels.t('messagingDocumentSendOptions.changeSigningOptions')"
|
|
2295
|
+
(click)="toggleSigning()">{{ signingExpanded() ? labels.t('common.hide') : labels.t('common.change') }}</ui-button>
|
|
2257
2296
|
</div>
|
|
2258
2297
|
@if (signingExpanded()) {
|
|
2259
2298
|
<ui-form-section>
|
|
2260
2299
|
<!-- One column: three labelled number fields do not fit side by side in a 480px panel or on a phone. -->
|
|
2261
2300
|
<ui-form-row [cols]="1">
|
|
2262
2301
|
<ui-text-input
|
|
2263
|
-
label="
|
|
2302
|
+
[label]="labels.t('messagingDocumentSendOptions.expiryDays')" type="number" [required]="true" [min]="1" [max]="90" [maxDecimals]="0"
|
|
2264
2303
|
[showErrors]="showErrors()" [ngModel]="expiryDays()" (ngModelChange)="expiryDays.set(asText($event))" />
|
|
2265
2304
|
<ui-text-input
|
|
2266
|
-
label="
|
|
2305
|
+
[label]="labels.t('messagingDocumentSendOptions.reminderIntervalDays')" type="number" [required]="true" [min]="1" [max]="30" [maxDecimals]="0"
|
|
2267
2306
|
[showErrors]="showErrors()" [ngModel]="reminderIntervalDays()" (ngModelChange)="reminderIntervalDays.set(asText($event))" />
|
|
2268
2307
|
<ui-text-input
|
|
2269
|
-
label="
|
|
2308
|
+
[label]="labels.t('messagingDocumentSendOptions.maxReminders')" type="number" [required]="true" [min]="0" [max]="10" [maxDecimals]="0"
|
|
2270
2309
|
[showErrors]="showErrors()" [ngModel]="maxReminders()" (ngModelChange)="maxReminders.set(asText($event))" />
|
|
2271
2310
|
</ui-form-row>
|
|
2272
2311
|
</ui-form-section>
|
|
@@ -2274,7 +2313,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2274
2313
|
</div>
|
|
2275
2314
|
}
|
|
2276
2315
|
} @else {
|
|
2277
|
-
<p class="dso-unavailable" role="note">
|
|
2316
|
+
<p class="dso-unavailable" role="note">{{ labels.t('messagingDocumentSendOptions.documentsCanOnlyBeTexted') }}</p>
|
|
2278
2317
|
}
|
|
2279
2318
|
</div>
|
|
2280
2319
|
`,
|
|
@@ -2291,7 +2330,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2291
2330
|
required: false
|
|
2292
2331
|
}]
|
|
2293
2332
|
}],
|
|
2294
|
-
|
|
2333
|
+
labelInput: [{
|
|
2295
2334
|
type: i0.Input,
|
|
2296
2335
|
args: [{
|
|
2297
2336
|
isSignal: true,
|
|
@@ -2403,6 +2442,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2403
2442
|
});
|
|
2404
2443
|
var DocumentSignersComponent = class DocumentSignersComponent {
|
|
2405
2444
|
constructor() {
|
|
2445
|
+
this.labels = inject(UiLabelsService);
|
|
2406
2446
|
this.info = input(null, ...ngDevMode ? [{ debugName: "info" }] : /* istanbul ignore next */ []);
|
|
2407
2447
|
this.config = input(null, ...ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []);
|
|
2408
2448
|
this.recipient = input({
|
|
@@ -2443,7 +2483,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2443
2483
|
return countersignPlaceLabel(title);
|
|
2444
2484
|
}
|
|
2445
2485
|
placeText(title) {
|
|
2446
|
-
return this.placeDocs().length > 1 ? countersignPlaceLabel(title) : "
|
|
2486
|
+
return this.placeDocs().length > 1 ? countersignPlaceLabel(title) : this.labels.t("messagingDocumentSendOptions.placeCountersign");
|
|
2447
2487
|
}
|
|
2448
2488
|
label(role) {
|
|
2449
2489
|
return signerRoleLabel(role, this.config());
|
|
@@ -2524,7 +2564,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2524
2564
|
ngImport: i0,
|
|
2525
2565
|
template: `
|
|
2526
2566
|
@if (rowsShown()) {
|
|
2527
|
-
<ui-form-section label="
|
|
2567
|
+
<ui-form-section [label]="labels.t('messagingDocumentSendOptions.signers')" data-testid="signers-section">
|
|
2528
2568
|
@for (role of info()!.roles; track role) {
|
|
2529
2569
|
@if (role === 'signer1') {
|
|
2530
2570
|
<div class="ds-row" [attr.data-testid]="'signer-row-' + role">
|
|
@@ -2539,7 +2579,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2539
2579
|
[required]="true"
|
|
2540
2580
|
[showErrors]="showErrors()"
|
|
2541
2581
|
[errorId]="'ds-error-' + role"
|
|
2542
|
-
placeholder="
|
|
2582
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchForAContact')"
|
|
2543
2583
|
(contactSelected)="pick(role, $event)" />
|
|
2544
2584
|
<!-- The picker's own "<Role> is required." (shown after blur or with showErrors), else the contact problem (no email / twice). -->
|
|
2545
2585
|
<div class="ds-error" [attr.id]="'ds-error-' + role">
|
|
@@ -2548,7 +2588,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2548
2588
|
</div>
|
|
2549
2589
|
}
|
|
2550
2590
|
}
|
|
2551
|
-
<ui-hint data-testid="signers-order-hint">
|
|
2591
|
+
<ui-hint data-testid="signers-order-hint">{{ labels.t('messagingDocumentSendOptions.signersAreEmailedOneAfter') }}</ui-hint>
|
|
2552
2592
|
</ui-form-section>
|
|
2553
2593
|
}
|
|
2554
2594
|
@if (line()) {
|
|
@@ -2673,7 +2713,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2673
2713
|
}],
|
|
2674
2714
|
template: `
|
|
2675
2715
|
@if (rowsShown()) {
|
|
2676
|
-
<ui-form-section label="
|
|
2716
|
+
<ui-form-section [label]="labels.t('messagingDocumentSendOptions.signers')" data-testid="signers-section">
|
|
2677
2717
|
@for (role of info()!.roles; track role) {
|
|
2678
2718
|
@if (role === 'signer1') {
|
|
2679
2719
|
<div class="ds-row" [attr.data-testid]="'signer-row-' + role">
|
|
@@ -2688,7 +2728,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2688
2728
|
[required]="true"
|
|
2689
2729
|
[showErrors]="showErrors()"
|
|
2690
2730
|
[errorId]="'ds-error-' + role"
|
|
2691
|
-
placeholder="
|
|
2731
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchForAContact')"
|
|
2692
2732
|
(contactSelected)="pick(role, $event)" />
|
|
2693
2733
|
<!-- The picker's own "<Role> is required." (shown after blur or with showErrors), else the contact problem (no email / twice). -->
|
|
2694
2734
|
<div class="ds-error" [attr.id]="'ds-error-' + role">
|
|
@@ -2697,7 +2737,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2697
2737
|
</div>
|
|
2698
2738
|
}
|
|
2699
2739
|
}
|
|
2700
|
-
<ui-hint data-testid="signers-order-hint">
|
|
2740
|
+
<ui-hint data-testid="signers-order-hint">{{ labels.t('messagingDocumentSendOptions.signersAreEmailedOneAfter') }}</ui-hint>
|
|
2701
2741
|
</ui-form-section>
|
|
2702
2742
|
}
|
|
2703
2743
|
@if (line()) {
|
|
@@ -2942,6 +2982,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2942
2982
|
}]
|
|
2943
2983
|
}
|
|
2944
2984
|
});
|
|
2985
|
+
const SPANISH_VIDEO_LINK_WORDS = {
|
|
2986
|
+
watchVideo: "Ver video",
|
|
2987
|
+
watchNamed: "Ver \"{{ title }}\": {{ link }}"
|
|
2988
|
+
};
|
|
2945
2989
|
function buildVideoLink(baseLink, options = {}) {
|
|
2946
2990
|
const params = [];
|
|
2947
2991
|
if (options.autoplay) params.push("autoplay=1");
|
|
@@ -2962,63 +3006,110 @@ function videoLinkWithDefaults(baseLink, defaults = {}, contactId = "") {
|
|
|
2962
3006
|
hideReactions: !!defaults.hideReactions
|
|
2963
3007
|
});
|
|
2964
3008
|
}
|
|
3009
|
+
function watchVideoWordList() {
|
|
3010
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
3011
|
+
uiText("messagingVideoLink.watchVideo"),
|
|
3012
|
+
"Watch video",
|
|
3013
|
+
SPANISH_VIDEO_LINK_WORDS.watchVideo
|
|
3014
|
+
]));
|
|
3015
|
+
}
|
|
3016
|
+
function watchVideoWords() {
|
|
3017
|
+
return "(?:" + watchVideoWordList().map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|") + ")";
|
|
3018
|
+
}
|
|
2965
3019
|
function stripVideoLink(text) {
|
|
2966
|
-
return text.replace(
|
|
3020
|
+
return text.replace(new RegExp(`\\n\\n🎬 ${watchVideoWords()}: [^\\n]*`, "g"), "").replace(new RegExp(`\\n🎬 ${watchVideoWords()}: [^\\n]*`, "g"), "").replace(new RegExp(`🎬 ${watchVideoWords()}: [^\\n]*`, "g"), "").trimEnd();
|
|
2967
3021
|
}
|
|
2968
3022
|
function appendVideoLink(text, link) {
|
|
2969
3023
|
const base = stripVideoLink(text);
|
|
2970
|
-
|
|
3024
|
+
const line = `🎬 ${uiText("messagingVideoLink.watchVideo")}: ${link}`;
|
|
3025
|
+
return base ? `${base}\n\n${line}` : line;
|
|
2971
3026
|
}
|
|
2972
3027
|
function videoMessageLine(title, link) {
|
|
2973
|
-
return
|
|
3028
|
+
return uiText("messagingVideoLink.watchNamed", {
|
|
3029
|
+
title,
|
|
3030
|
+
link
|
|
3031
|
+
});
|
|
3032
|
+
}
|
|
3033
|
+
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3034
|
+
const fillTemplate = (tpl, title, link) => tpl.replace(/\{\{\s*title\s*\}\}/g, () => title).replace(/\{\{\s*link\s*\}\}/g, () => link);
|
|
3035
|
+
function namedTemplates() {
|
|
3036
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
3037
|
+
uiText("messagingVideoLink.watchNamed"),
|
|
3038
|
+
UI_DEFAULT_LABELS["messagingVideoLink.watchNamed"],
|
|
3039
|
+
SPANISH_VIDEO_LINK_WORDS.watchNamed
|
|
3040
|
+
]));
|
|
3041
|
+
}
|
|
3042
|
+
function videoLineForms(line) {
|
|
3043
|
+
const forms = [line];
|
|
3044
|
+
for (const tpl of namedTemplates()) {
|
|
3045
|
+
const parts = tpl.split(/(\{\{\s*(?:title|link)\s*\}\})/);
|
|
3046
|
+
const order = [];
|
|
3047
|
+
const hit = new RegExp("^" + parts.map((part) => {
|
|
3048
|
+
const m = /^\{\{\s*(title|link)\s*\}\}$/.exec(part);
|
|
3049
|
+
if (!m) return escapeRe(part);
|
|
3050
|
+
order.push(m[1]);
|
|
3051
|
+
return m[1] === "title" ? "(.*?)" : "(.+)";
|
|
3052
|
+
}).join("") + "$").exec(line);
|
|
3053
|
+
if (!hit) continue;
|
|
3054
|
+
const found = {};
|
|
3055
|
+
order.forEach((name, i) => {
|
|
3056
|
+
found[name] = hit[i + 1];
|
|
3057
|
+
});
|
|
3058
|
+
for (const t of namedTemplates()) forms.push(fillTemplate(t, found["title"] ?? "", found["link"] ?? ""));
|
|
3059
|
+
forms.push(...watchVideoWordList().map((w) => `🎬 ${w}: ${found["link"] ?? ""}`));
|
|
3060
|
+
break;
|
|
3061
|
+
}
|
|
3062
|
+
const emoji = new RegExp(`^🎬 ${watchVideoWords()}: (.+)$`).exec(line);
|
|
3063
|
+
if (emoji) forms.push(...watchVideoWordList().map((w) => `🎬 ${w}: ${emoji[1]}`));
|
|
3064
|
+
return Array.from(new Set(forms));
|
|
2974
3065
|
}
|
|
2975
3066
|
function applyVideoLine(body, prev, next) {
|
|
2976
3067
|
if (!prev) {
|
|
2977
3068
|
if (!next) return body;
|
|
2978
3069
|
return body.trim() ? `${body}\n\n${next}` : next;
|
|
2979
3070
|
}
|
|
2980
|
-
const
|
|
2981
|
-
if (
|
|
2982
|
-
|
|
3071
|
+
const found = videoLineForms(prev).find((form) => body.includes(form));
|
|
3072
|
+
if (found === void 0) return body;
|
|
3073
|
+
const at = body.indexOf(found);
|
|
3074
|
+
if (next) return body.slice(0, at) + next + body.slice(at + found.length);
|
|
2983
3075
|
const before = body.slice(0, at);
|
|
2984
|
-
const after = body.slice(at +
|
|
3076
|
+
const after = body.slice(at + found.length);
|
|
2985
3077
|
const trimmedBefore = before.replace(/\n{1,2}$/, "");
|
|
2986
3078
|
return (trimmedBefore + after).trim() === "" ? "" : trimmedBefore + after;
|
|
2987
3079
|
}
|
|
2988
|
-
const VIDEO_PLAYBACK_OPTIONS = [{
|
|
2989
|
-
value: "click",
|
|
2990
|
-
label: "Click to Play"
|
|
2991
|
-
}, {
|
|
2992
|
-
value: "autoplay",
|
|
2993
|
-
label: "Autoplay"
|
|
2994
|
-
}];
|
|
2995
|
-
const VIDEO_CTA_OPTIONS = [
|
|
2996
|
-
{
|
|
2997
|
-
value: "",
|
|
2998
|
-
label: "None (use video default)"
|
|
2999
|
-
},
|
|
3000
|
-
{
|
|
3001
|
-
value: "schedule",
|
|
3002
|
-
label: "Schedule a Call"
|
|
3003
|
-
},
|
|
3004
|
-
{
|
|
3005
|
-
value: "contact",
|
|
3006
|
-
label: "Contact Me"
|
|
3007
|
-
},
|
|
3008
|
-
{
|
|
3009
|
-
value: "custom",
|
|
3010
|
-
label: "Custom"
|
|
3011
|
-
}
|
|
3012
|
-
];
|
|
3013
3080
|
var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
3014
3081
|
constructor() {
|
|
3082
|
+
this.labels = inject(UiLabelsService);
|
|
3015
3083
|
this.video = input(null, ...ngDevMode ? [{ debugName: "video" }] : /* istanbul ignore next */ []);
|
|
3016
3084
|
this.defaults = input({}, ...ngDevMode ? [{ debugName: "defaults" }] : /* istanbul ignore next */ []);
|
|
3017
3085
|
this.contactId = input("", ...ngDevMode ? [{ debugName: "contactId" }] : /* istanbul ignore next */ []);
|
|
3018
3086
|
this.linkChange = output();
|
|
3019
3087
|
this.removed = output();
|
|
3020
|
-
this.playbackOptions =
|
|
3021
|
-
|
|
3088
|
+
this.playbackOptions = computed(() => [{
|
|
3089
|
+
value: "click",
|
|
3090
|
+
label: this.labels.t("messagingSendMessagePanel.playback.click")
|
|
3091
|
+
}, {
|
|
3092
|
+
value: "autoplay",
|
|
3093
|
+
label: this.labels.t("messagingSendMessagePanel.playback.autoplay")
|
|
3094
|
+
}], ...ngDevMode ? [{ debugName: "playbackOptions" }] : /* istanbul ignore next */ []);
|
|
3095
|
+
this.ctaOptions = computed(() => [
|
|
3096
|
+
{
|
|
3097
|
+
value: "",
|
|
3098
|
+
label: this.labels.t("messagingSendMessagePanel.cta.none")
|
|
3099
|
+
},
|
|
3100
|
+
{
|
|
3101
|
+
value: "schedule",
|
|
3102
|
+
label: this.labels.t("messagingSendMessagePanel.cta.schedule")
|
|
3103
|
+
},
|
|
3104
|
+
{
|
|
3105
|
+
value: "contact",
|
|
3106
|
+
label: this.labels.t("messagingSendMessagePanel.cta.contact")
|
|
3107
|
+
},
|
|
3108
|
+
{
|
|
3109
|
+
value: "custom",
|
|
3110
|
+
label: this.labels.t("messagingSendMessagePanel.cta.custom")
|
|
3111
|
+
}
|
|
3112
|
+
], ...ngDevMode ? [{ debugName: "ctaOptions" }] : /* istanbul ignore next */ []);
|
|
3022
3113
|
this.autoplay = signal("click", ...ngDevMode ? [{ debugName: "autoplay" }] : /* istanbul ignore next */ []);
|
|
3023
3114
|
this.ctaType = signal("", ...ngDevMode ? [{ debugName: "ctaType" }] : /* istanbul ignore next */ []);
|
|
3024
3115
|
this.ctaUrl = signal("", ...ngDevMode ? [{ debugName: "ctaUrl" }] : /* istanbul ignore next */ []);
|
|
@@ -3127,40 +3218,40 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3127
3218
|
<ui-form-section class="vls">
|
|
3128
3219
|
<div class="vls-bar">
|
|
3129
3220
|
@if (v.shareLink) {
|
|
3130
|
-
<ui-hint><a class="vls-preview" [href]="v.shareLink" target="_blank" rel="noopener" aria-label="
|
|
3221
|
+
<ui-hint><a class="vls-preview" [href]="v.shareLink" target="_blank" rel="noopener" [attr.aria-label]="labels.t('messagingVideoLinkSettings.watchPreviewOpensInA')">{{ labels.t('messagingVideoLinkSettings.watchPreview') }}</a></ui-hint>
|
|
3131
3222
|
}
|
|
3132
|
-
<ui-button variant="ghost" size="xs" [ariaExpanded]="settingsOpen()" (click)="toggleSettings()">
|
|
3133
|
-
<ui-button variant="secondary" size="sm" (click)="removed.emit()">
|
|
3223
|
+
<ui-button variant="ghost" size="xs" [ariaExpanded]="settingsOpen()" (click)="toggleSettings()">{{ labels.t('messagingVideoLinkSettings.videoSettings') }}</ui-button>
|
|
3224
|
+
<ui-button variant="secondary" size="sm" (click)="removed.emit()">{{ labels.t('messagingVideoLinkSettings.removeVideo') }}</ui-button>
|
|
3134
3225
|
</div>
|
|
3135
3226
|
<!-- Collapsed by default: the defaults from Communication settings are already applied. -->
|
|
3136
3227
|
@if (settingsOpen()) {
|
|
3137
3228
|
<ui-radio-group
|
|
3138
|
-
label="
|
|
3229
|
+
[label]="labels.t('messagingVideoLinkSettings.playback')"
|
|
3139
3230
|
orientation="horizontal"
|
|
3140
|
-
[options]="playbackOptions"
|
|
3231
|
+
[options]="playbackOptions()"
|
|
3141
3232
|
[ngModel]="autoplay()"
|
|
3142
3233
|
(ngModelChange)="setAutoplay($event)" />
|
|
3143
3234
|
<ui-select
|
|
3144
|
-
label="
|
|
3145
|
-
[options]="ctaOptions"
|
|
3235
|
+
[label]="labels.t('messagingVideoLinkSettings.callToAction')"
|
|
3236
|
+
[options]="ctaOptions()"
|
|
3146
3237
|
[ngModel]="ctaType()"
|
|
3147
3238
|
(ngModelChange)="setCtaType($event)" />
|
|
3148
3239
|
@if (ctaType()) {
|
|
3149
3240
|
<ui-text-input
|
|
3150
|
-
label="
|
|
3241
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionUrl')"
|
|
3151
3242
|
type="url"
|
|
3152
3243
|
placeholder="https://..."
|
|
3153
3244
|
[maxlength]="500"
|
|
3154
3245
|
[ngModel]="ctaUrl()"
|
|
3155
3246
|
(ngModelChange)="setCtaUrl($event)" />
|
|
3156
3247
|
<ui-text-input
|
|
3157
|
-
label="
|
|
3158
|
-
placeholder="
|
|
3248
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionLabel')"
|
|
3249
|
+
[placeholder]="labels.t('messagingVideoLinkSettings.buttonLabelEGBook')"
|
|
3159
3250
|
[maxlength]="100"
|
|
3160
3251
|
[ngModel]="ctaLabel()"
|
|
3161
3252
|
(ngModelChange)="setCtaLabel($event)" />
|
|
3162
3253
|
}
|
|
3163
|
-
<ui-checkbox label="
|
|
3254
|
+
<ui-checkbox [label]="labels.t('messagingVideoLinkSettings.hideReactions')" [ngModel]="hideReactions()" (ngModelChange)="setHideReactions($event)" />
|
|
3164
3255
|
}
|
|
3165
3256
|
</ui-form-section>
|
|
3166
3257
|
}
|
|
@@ -3381,40 +3472,40 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
3381
3472
|
<ui-form-section class="vls">
|
|
3382
3473
|
<div class="vls-bar">
|
|
3383
3474
|
@if (v.shareLink) {
|
|
3384
|
-
<ui-hint><a class="vls-preview" [href]="v.shareLink" target="_blank" rel="noopener" aria-label="
|
|
3475
|
+
<ui-hint><a class="vls-preview" [href]="v.shareLink" target="_blank" rel="noopener" [attr.aria-label]="labels.t('messagingVideoLinkSettings.watchPreviewOpensInA')">{{ labels.t('messagingVideoLinkSettings.watchPreview') }}</a></ui-hint>
|
|
3385
3476
|
}
|
|
3386
|
-
<ui-button variant="ghost" size="xs" [ariaExpanded]="settingsOpen()" (click)="toggleSettings()">
|
|
3387
|
-
<ui-button variant="secondary" size="sm" (click)="removed.emit()">
|
|
3477
|
+
<ui-button variant="ghost" size="xs" [ariaExpanded]="settingsOpen()" (click)="toggleSettings()">{{ labels.t('messagingVideoLinkSettings.videoSettings') }}</ui-button>
|
|
3478
|
+
<ui-button variant="secondary" size="sm" (click)="removed.emit()">{{ labels.t('messagingVideoLinkSettings.removeVideo') }}</ui-button>
|
|
3388
3479
|
</div>
|
|
3389
3480
|
<!-- Collapsed by default: the defaults from Communication settings are already applied. -->
|
|
3390
3481
|
@if (settingsOpen()) {
|
|
3391
3482
|
<ui-radio-group
|
|
3392
|
-
label="
|
|
3483
|
+
[label]="labels.t('messagingVideoLinkSettings.playback')"
|
|
3393
3484
|
orientation="horizontal"
|
|
3394
|
-
[options]="playbackOptions"
|
|
3485
|
+
[options]="playbackOptions()"
|
|
3395
3486
|
[ngModel]="autoplay()"
|
|
3396
3487
|
(ngModelChange)="setAutoplay($event)" />
|
|
3397
3488
|
<ui-select
|
|
3398
|
-
label="
|
|
3399
|
-
[options]="ctaOptions"
|
|
3489
|
+
[label]="labels.t('messagingVideoLinkSettings.callToAction')"
|
|
3490
|
+
[options]="ctaOptions()"
|
|
3400
3491
|
[ngModel]="ctaType()"
|
|
3401
3492
|
(ngModelChange)="setCtaType($event)" />
|
|
3402
3493
|
@if (ctaType()) {
|
|
3403
3494
|
<ui-text-input
|
|
3404
|
-
label="
|
|
3495
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionUrl')"
|
|
3405
3496
|
type="url"
|
|
3406
3497
|
placeholder="https://..."
|
|
3407
3498
|
[maxlength]="500"
|
|
3408
3499
|
[ngModel]="ctaUrl()"
|
|
3409
3500
|
(ngModelChange)="setCtaUrl($event)" />
|
|
3410
3501
|
<ui-text-input
|
|
3411
|
-
label="
|
|
3412
|
-
placeholder="
|
|
3502
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionLabel')"
|
|
3503
|
+
[placeholder]="labels.t('messagingVideoLinkSettings.buttonLabelEGBook')"
|
|
3413
3504
|
[maxlength]="100"
|
|
3414
3505
|
[ngModel]="ctaLabel()"
|
|
3415
3506
|
(ngModelChange)="setCtaLabel($event)" />
|
|
3416
3507
|
}
|
|
3417
|
-
<ui-checkbox label="
|
|
3508
|
+
<ui-checkbox [label]="labels.t('messagingVideoLinkSettings.hideReactions')" [ngModel]="hideReactions()" (ngModelChange)="setHideReactions($event)" />
|
|
3418
3509
|
}
|
|
3419
3510
|
</ui-form-section>
|
|
3420
3511
|
}
|
|
@@ -3478,10 +3569,16 @@ function buildDocumentsPayload(v, delivery, purpose = v.purpose, extras = {}) {
|
|
|
3478
3569
|
const DEFAULT_DOCUMENT_SUBJECT = "Document Signature Required";
|
|
3479
3570
|
function suggestDocumentSubject(titles, purpose, informational = false) {
|
|
3480
3571
|
if (titles.length === 0) return "";
|
|
3481
|
-
if (informational && purpose !== "ATTACH") return titles.length === 1 ?
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3572
|
+
if (informational && purpose !== "ATTACH") return titles.length === 1 ? uiText("messagingSendMessagePanel.subjectShared_one", { title: titles[0] }) : uiText("messagingSendMessagePanel.subjectShared_other", {
|
|
3573
|
+
count: titles.length,
|
|
3574
|
+
title: titles[0]
|
|
3575
|
+
});
|
|
3576
|
+
const base = purpose === "ATTACH" ? "messagingSendMessagePanel.subjectAttached" : "messagingSendMessagePanel.subjectSign";
|
|
3577
|
+
if (titles.length === 1) return uiText(`${base}_one`, { title: titles[0] });
|
|
3578
|
+
return uiText(`${base}_other`, {
|
|
3579
|
+
count: titles.length,
|
|
3580
|
+
title: titles[0]
|
|
3581
|
+
});
|
|
3485
3582
|
}
|
|
3486
3583
|
const MAX_CC = 10;
|
|
3487
3584
|
function parseCcList(raw) {
|
|
@@ -3498,9 +3595,9 @@ function parseCcList(raw) {
|
|
|
3498
3595
|
const CC_EMAIL_RE = /^[^\s@,;<>"]+@[^\s@,;<>"]+\.[^\s@,;<>"]+$/;
|
|
3499
3596
|
function ccError(list) {
|
|
3500
3597
|
const bad = list.find((a) => a.length > 254 || !CC_EMAIL_RE.test(a));
|
|
3501
|
-
if (bad) return
|
|
3502
|
-
if (list.length > 10) return
|
|
3503
|
-
if (list.join(",").length > 1e3) return "
|
|
3598
|
+
if (bad) return uiText("messagingSendMessagePanel.ccInvalid", { address: bad });
|
|
3599
|
+
if (list.length > 10) return uiText("messagingSendMessagePanel.ccTooMany", { max: 10 });
|
|
3600
|
+
if (list.join(",").length > 1e3) return uiText("messagingSendMessagePanel.ccTooLong");
|
|
3504
3601
|
return "";
|
|
3505
3602
|
}
|
|
3506
3603
|
function signingBodyFields(d) {
|
|
@@ -3555,13 +3652,14 @@ function nonBlankValues(...sources) {
|
|
|
3555
3652
|
return out;
|
|
3556
3653
|
}
|
|
3557
3654
|
function dateVars(now = /* @__PURE__ */ new Date()) {
|
|
3558
|
-
const
|
|
3655
|
+
const locale = uiLocale();
|
|
3656
|
+
const long = now.toLocaleDateString(locale, {
|
|
3559
3657
|
month: "long",
|
|
3560
3658
|
day: "numeric",
|
|
3561
3659
|
year: "numeric"
|
|
3562
3660
|
});
|
|
3563
3661
|
return {
|
|
3564
|
-
month: now.toLocaleString(
|
|
3662
|
+
month: now.toLocaleString(locale, { month: "long" }),
|
|
3565
3663
|
year: now.getFullYear().toString(),
|
|
3566
3664
|
date: long,
|
|
3567
3665
|
today: long
|
|
@@ -3593,6 +3691,9 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3593
3691
|
get deferredKeys() {
|
|
3594
3692
|
return this.bulk() ? PERSONAL_TAG_KEYS : [];
|
|
3595
3693
|
}
|
|
3694
|
+
get EMAIL_DISABLED_MESSAGE() {
|
|
3695
|
+
return this.labels.t("messagingSendMessagePanel.emailDisabled");
|
|
3696
|
+
}
|
|
3596
3697
|
ngOnInit() {
|
|
3597
3698
|
this.includeReceipt = this.receiptDefault();
|
|
3598
3699
|
this.http.get(`${this.apiBase}/service-areas?size=100`).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ next: (resp) => {
|
|
@@ -3601,6 +3702,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3601
3702
|
} });
|
|
3602
3703
|
}
|
|
3603
3704
|
constructor() {
|
|
3705
|
+
this.labels = inject(UiLabelsService);
|
|
3604
3706
|
this.destroyRef = inject(DestroyRef);
|
|
3605
3707
|
this.http = inject(HttpClient);
|
|
3606
3708
|
this.apiBase = inject(FORGEROUTE_CONFIG, { optional: true })?.baseUrl ?? "/api";
|
|
@@ -3617,7 +3719,11 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3617
3719
|
this.context = input({}, ...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
3618
3720
|
this.sendFn = input(null, ...ngDevMode ? [{ debugName: "sendFn" }] : /* istanbul ignore next */ []);
|
|
3619
3721
|
this.showReceiptOption = input(false, ...ngDevMode ? [{ debugName: "showReceiptOption" }] : /* istanbul ignore next */ []);
|
|
3620
|
-
this.
|
|
3722
|
+
this.receiptLabelInput = input(null, {
|
|
3723
|
+
...ngDevMode ? { debugName: "receiptLabelInput" } : /* istanbul ignore next */ {},
|
|
3724
|
+
alias: "receiptLabel"
|
|
3725
|
+
});
|
|
3726
|
+
this.receiptLabel = computed(() => this.receiptLabelInput() ?? this.labels.t("messagingSendMessagePanel.receiptLabel"), ...ngDevMode ? [{ debugName: "receiptLabel" }] : /* istanbul ignore next */ []);
|
|
3621
3727
|
this.receiptDefault = input(false, ...ngDevMode ? [{ debugName: "receiptDefault" }] : /* istanbul ignore next */ []);
|
|
3622
3728
|
this.documents = input(false, ...ngDevMode ? [{ debugName: "documents" }] : /* istanbul ignore next */ []);
|
|
3623
3729
|
this.documentPurposes = input([
|
|
@@ -3662,7 +3768,6 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3662
3768
|
this.validChange = output();
|
|
3663
3769
|
this.rejected = output();
|
|
3664
3770
|
this.mapFieldsClick = output();
|
|
3665
|
-
this.EMAIL_DISABLED_MESSAGE = "Email sending is disabled, so this can't be sent. Enable it in Communication Settings.";
|
|
3666
3771
|
this.mode = "compose";
|
|
3667
3772
|
this.subject = "";
|
|
3668
3773
|
this.body = "";
|
|
@@ -3685,13 +3790,13 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3685
3790
|
this.signersInvalid = false;
|
|
3686
3791
|
this.mergeWarnings = [];
|
|
3687
3792
|
this.savingEmail = signal(false, ...ngDevMode ? [{ debugName: "savingEmail" }] : /* istanbul ignore next */ []);
|
|
3688
|
-
this.modeTabs = [{
|
|
3793
|
+
this.modeTabs = computed(() => [{
|
|
3689
3794
|
key: "compose",
|
|
3690
|
-
label: "
|
|
3795
|
+
label: this.labels.t("messagingSendMessagePanel.tabCompose")
|
|
3691
3796
|
}, {
|
|
3692
3797
|
key: "template",
|
|
3693
|
-
label: "
|
|
3694
|
-
}];
|
|
3798
|
+
label: this.labels.t("messagingSendMessagePanel.tabTemplate")
|
|
3799
|
+
}], ...ngDevMode ? [{ debugName: "modeTabs" }] : /* istanbul ignore next */ []);
|
|
3695
3800
|
this.marketVars = {};
|
|
3696
3801
|
this._appliedDefaults = {
|
|
3697
3802
|
subject: "",
|
|
@@ -3805,7 +3910,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3805
3910
|
});
|
|
3806
3911
|
if (this.hasDocuments && this.signerInfo?.multiDocumentNote) out.push({
|
|
3807
3912
|
key: "multi",
|
|
3808
|
-
text: "
|
|
3913
|
+
text: this.labels.t("messagingSendMessagePanel.multiSignerOneAtATime"),
|
|
3809
3914
|
testId: "documents-multi-signer-note"
|
|
3810
3915
|
});
|
|
3811
3916
|
if (this.hasDocuments) this.mergeWarnings.forEach((text, i) => out.push({
|
|
@@ -3829,8 +3934,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3829
3934
|
}
|
|
3830
3935
|
this.syncSuggestedSubject();
|
|
3831
3936
|
if (this.hasDocuments) {
|
|
3832
|
-
const removed = [this.attachments.length > 0 ? "
|
|
3833
|
-
if (removed.length > 0) this.docsRemovedNote =
|
|
3937
|
+
const removed = [this.attachments.length > 0 ? this.labels.t("messagingSendMessagePanel.removedAttachments") : "", this.showSchedule ? this.labels.t("messagingSendMessagePanel.removedSchedule") : ""].filter(Boolean);
|
|
3938
|
+
if (removed.length > 0) this.docsRemovedNote = this.labels.t("messagingSendMessagePanel.removedBecauseRequest", { items: removed.join(` ${this.labels.t("messagingSendMessagePanel.listAnd")} `) });
|
|
3834
3939
|
this.attachments = [];
|
|
3835
3940
|
this.showSchedule = false;
|
|
3836
3941
|
this.scheduledAt = "";
|
|
@@ -3842,10 +3947,16 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3842
3947
|
this.notifyValid();
|
|
3843
3948
|
}
|
|
3844
3949
|
get bodyLengthError() {
|
|
3845
|
-
return this.resolvedBody.length > this.MAX_BODY ?
|
|
3950
|
+
return this.resolvedBody.length > this.MAX_BODY ? this.labels.t("messagingSendMessagePanel.bodyTooLong", {
|
|
3951
|
+
actual: this.labels.formatNumber(this.resolvedBody.length),
|
|
3952
|
+
max: this.labels.formatNumber(this.MAX_BODY)
|
|
3953
|
+
}) : "";
|
|
3846
3954
|
}
|
|
3847
3955
|
get subjectLengthError() {
|
|
3848
|
-
return this.resolvedSubject.length > this.MAX_SUBJECT ?
|
|
3956
|
+
return this.resolvedSubject.length > this.MAX_SUBJECT ? this.labels.t("messagingSendMessagePanel.subjectTooLong", {
|
|
3957
|
+
actual: this.labels.formatNumber(this.resolvedSubject.length),
|
|
3958
|
+
max: this.MAX_SUBJECT
|
|
3959
|
+
}) : "";
|
|
3849
3960
|
}
|
|
3850
3961
|
get sendLengthError() {
|
|
3851
3962
|
return this.subjectLengthError || (this.mode === "compose" ? "" : this.bodyLengthError);
|
|
@@ -3907,7 +4018,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3907
4018
|
}
|
|
3908
4019
|
get composeTagError() {
|
|
3909
4020
|
if (this.mode !== "compose") return "";
|
|
3910
|
-
return hasLeftoverTags(this.resolvedSubject, this.deferredKeys) || hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "
|
|
4021
|
+
return hasLeftoverTags(this.resolvedSubject, this.deferredKeys) || hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? this.labels.t("messagingSendMessagePanel.leftoverTags") : "";
|
|
3911
4022
|
}
|
|
3912
4023
|
get unresolvedVars() {
|
|
3913
4024
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -4007,7 +4118,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4007
4118
|
const reader = new FileReader();
|
|
4008
4119
|
reader.onload = () => {
|
|
4009
4120
|
const base64 = reader.result.split(",")[1];
|
|
4010
|
-
const sizeLabel =
|
|
4121
|
+
const sizeLabel = formatAttachmentSize(file.size);
|
|
4011
4122
|
this.attachments = [...this.attachments, {
|
|
4012
4123
|
filename: file.name,
|
|
4013
4124
|
content: base64,
|
|
@@ -4026,7 +4137,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4026
4137
|
insertVideo(v) {
|
|
4027
4138
|
if (!v.shareLink) return;
|
|
4028
4139
|
const sep = this.body.trim() ? "\n\n" : "";
|
|
4029
|
-
this.body = this.body + sep +
|
|
4140
|
+
this.body = this.body + sep + videoMessageLine(v.title, v.shareLink);
|
|
4030
4141
|
this.notifyValid();
|
|
4031
4142
|
}
|
|
4032
4143
|
docuSignBody(docs, payload) {
|
|
@@ -4071,7 +4182,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4071
4182
|
submit() {
|
|
4072
4183
|
if (!this.canSend || this.loading || !this.bulk() && !this.contactEmail()) return;
|
|
4073
4184
|
if (this.bulk() && !this.sendFn()) {
|
|
4074
|
-
this.toast.error(
|
|
4185
|
+
this.toast.error(this.labels.t("messagingSendMessagePanel.bulkNoSend"));
|
|
4075
4186
|
return;
|
|
4076
4187
|
}
|
|
4077
4188
|
if (this.mode === "template") this.applyPendingVars();
|
|
@@ -4148,7 +4259,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4148
4259
|
});
|
|
4149
4260
|
const onError = (err) => {
|
|
4150
4261
|
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
4151
|
-
this.toast.error(custom || docs ? getErrorMessage(err, "
|
|
4262
|
+
this.toast.error(custom || docs ? getErrorMessage(err, this.labels.t("messagingSendMessagePanel.ctxEmail"), "send") : serverMessage(err) || this.labels.t("messagingSendMessagePanel.failedSendEmail"));
|
|
4152
4263
|
this.loading = false;
|
|
4153
4264
|
this.cdr.markForCheck();
|
|
4154
4265
|
if (this.bulk()) this.bulkSending.emit(null);
|
|
@@ -4164,7 +4275,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4164
4275
|
provider: docs.provider,
|
|
4165
4276
|
informational: docs.signerInfo?.informational === true
|
|
4166
4277
|
}) : void 0;
|
|
4167
|
-
this.toast.show(sentText ?? (docs?.provider === "DOCUSIGN" ?
|
|
4278
|
+
this.toast.show(sentText ?? (docs?.provider === "DOCUSIGN" ? this.labels.t("messagingSendMessagePanel.sentViaDocusign", { title: docs.documents[0].title }) : docs && this.documentEnvelope() ? this.labels.t("messagingSendMessagePanel.envelopeSent", { name: this.documentEnvelope().name }) : this.showSchedule ? this.labels.t("messagingSendMessagePanel.emailScheduled") : this.labels.t("messagingSendMessagePanel.emailSent")));
|
|
4168
4279
|
this.loading = false;
|
|
4169
4280
|
this.attachments = [];
|
|
4170
4281
|
this.includeReceipt = this.receiptDefault();
|
|
@@ -4269,8 +4380,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4269
4380
|
isRequired: false,
|
|
4270
4381
|
transformFunction: null
|
|
4271
4382
|
},
|
|
4272
|
-
|
|
4273
|
-
classPropertyName: "
|
|
4383
|
+
receiptLabelInput: {
|
|
4384
|
+
classPropertyName: "receiptLabelInput",
|
|
4274
4385
|
publicName: "receiptLabel",
|
|
4275
4386
|
isSignal: true,
|
|
4276
4387
|
isRequired: false,
|
|
@@ -4445,25 +4556,21 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4445
4556
|
<!-- Missing email guard -->
|
|
4446
4557
|
@if (!bulk() && !contactEmail()) {
|
|
4447
4558
|
<div class="sm-missing-banner">
|
|
4448
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
4449
|
-
No email address on file for this contact.
|
|
4450
|
-
</div>
|
|
4559
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.noEmailAddressOnFile') }}</div>
|
|
4451
4560
|
<ui-text-input
|
|
4452
|
-
label="
|
|
4561
|
+
[label]="labels.t('messagingSendMessagePanel.addEmailAddress')"
|
|
4453
4562
|
type="email"
|
|
4454
4563
|
[required]="true"
|
|
4455
4564
|
placeholder="email@example.com"
|
|
4456
4565
|
[(ngModel)]="pendingEmail"
|
|
4457
4566
|
(ngModelChange)="notifyValid()"
|
|
4458
|
-
[error]="pendingEmail && !pendingEmailValid ? '
|
|
4459
|
-
<ui-button variant="primary" [disabled]="!pendingEmailValid || savingEmail()" [loading]="savingEmail()" (click)="saveEmail()">
|
|
4460
|
-
Save & Continue
|
|
4461
|
-
</ui-button>
|
|
4567
|
+
[error]="pendingEmail && !pendingEmailValid ? labels.t('validation.email') : ''" />
|
|
4568
|
+
<ui-button variant="primary" [disabled]="!pendingEmailValid || savingEmail()" [loading]="savingEmail()" (click)="saveEmail()">{{ labels.t('messagingSendMessagePanel.saveContinue') }}</ui-button>
|
|
4462
4569
|
} @else {
|
|
4463
4570
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
4464
4571
|
@if (!bulk()) {
|
|
4465
4572
|
<div class="sm-group">
|
|
4466
|
-
<span class="sm-group-label">
|
|
4573
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
4467
4574
|
<div class="sm-to-card">
|
|
4468
4575
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
4469
4576
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
@@ -4491,7 +4598,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4491
4598
|
<ui-text-input
|
|
4492
4599
|
label="CC"
|
|
4493
4600
|
placeholder="name@example.com, other@example.com"
|
|
4494
|
-
hint="
|
|
4601
|
+
[hint]="labels.t('messagingSendMessagePanel.separateAddressesWithCommasEveryone')"
|
|
4495
4602
|
[(ngModel)]="ccText"
|
|
4496
4603
|
[error]="ccError"
|
|
4497
4604
|
(ngModelChange)="notifyValid()" />
|
|
@@ -4500,24 +4607,24 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4500
4607
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
4501
4608
|
@if (showTemplates()) {
|
|
4502
4609
|
<div class="sm-mode-row">
|
|
4503
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
4610
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
4504
4611
|
</div>
|
|
4505
4612
|
}
|
|
4506
4613
|
|
|
4507
4614
|
@if (mode === 'compose') {
|
|
4508
4615
|
@if (showSubject()) {
|
|
4509
4616
|
<ui-text-input
|
|
4510
|
-
label="
|
|
4617
|
+
[label]="labels.t('common.subject')"
|
|
4511
4618
|
[required]="!viaDocuSign"
|
|
4512
|
-
placeholder="
|
|
4619
|
+
[placeholder]="labels.t('messagingSendMessagePanel.emailSubject')"
|
|
4513
4620
|
[maxlength]="MAX_SUBJECT"
|
|
4514
4621
|
[(ngModel)]="subject"
|
|
4515
4622
|
(ngModelChange)="notifyValid()" />
|
|
4516
4623
|
}
|
|
4517
4624
|
<ui-textarea-input
|
|
4518
|
-
label="
|
|
4625
|
+
[label]="labels.t('common.message')"
|
|
4519
4626
|
[required]="!viaDocuSign"
|
|
4520
|
-
placeholder="
|
|
4627
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
4521
4628
|
[rows]="8"
|
|
4522
4629
|
[(ngModel)]="body"
|
|
4523
4630
|
[error]="composeTagError || bodyLengthError"
|
|
@@ -4525,7 +4632,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4525
4632
|
|
|
4526
4633
|
@if (!hasDocuments && showAttachments()) {
|
|
4527
4634
|
<div class="sm-field">
|
|
4528
|
-
<label class="sm-field-label">
|
|
4635
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</label>
|
|
4529
4636
|
@if (attachments.length > 0) {
|
|
4530
4637
|
<div class="attach-chips">
|
|
4531
4638
|
@for (a of attachments; track a.filename; let i = $index) {
|
|
@@ -4533,25 +4640,23 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4533
4640
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
|
4534
4641
|
<span class="attach-name">{{ a.filename }}</span>
|
|
4535
4642
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
4536
|
-
<button class="attach-remove" type="button" (click)="removeAttachment(i)" aria-label="
|
|
4643
|
+
<button class="attach-remove" type="button" (click)="removeAttachment(i)" [attr.aria-label]="labels.t('messagingSendMessagePanel.removeAttachment')">×</button>
|
|
4537
4644
|
</div>
|
|
4538
4645
|
}
|
|
4539
4646
|
</div>
|
|
4540
4647
|
}
|
|
4541
4648
|
<input #emailFileInput type="file" multiple hidden (change)="onFilesSelected($event)" />
|
|
4542
4649
|
<button type="button" class="attach-add-btn" (click)="emailFileInput.click()">
|
|
4543
|
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
|
4544
|
-
Attach Files
|
|
4545
|
-
</button>
|
|
4650
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>{{ labels.t('messagingSendMessagePanel.attachFiles') }}</button>
|
|
4546
4651
|
</div>
|
|
4547
4652
|
|
|
4548
4653
|
}
|
|
4549
4654
|
|
|
4550
4655
|
@if (!hasDocuments && showScheduling()) {
|
|
4551
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
4656
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
4552
4657
|
@if (showSchedule) {
|
|
4553
4658
|
<ui-datetime-input
|
|
4554
|
-
label="
|
|
4659
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
4555
4660
|
[min]="minScheduleTime"
|
|
4556
4661
|
[(ngModel)]="scheduledAt"
|
|
4557
4662
|
(ngModelChange)="notifyValid()" />
|
|
@@ -4561,14 +4666,12 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4561
4666
|
@if (missingVars.length > 0) {
|
|
4562
4667
|
<div class="mv-section">
|
|
4563
4668
|
<p class="mv-hint">
|
|
4564
|
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
4565
|
-
This template has fields that need values before sending.
|
|
4566
|
-
</p>
|
|
4669
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.thisTemplateHasFieldsThat') }}</p>
|
|
4567
4670
|
@for (key of missingVars; track key) {
|
|
4568
4671
|
<div class="mv-row">
|
|
4569
4672
|
<div class="mv-input-wrap">
|
|
4570
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
4571
|
-
<ui-button variant="primary" size="sm" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" ariaLabel="
|
|
4673
|
+
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="labels.t('messagingSendMessagePanel.enterValue', { name: formatVarLabel(key).toLowerCase() })" [(ngModel)]="pendingInputs[key]" (ngModelChange)="notifyValid()" (keydown.enter)="applyVar(key)" />
|
|
4674
|
+
<ui-button variant="primary" size="sm" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" [ariaLabel]="labels.t('messagingSendMessagePanel.applyValue')">
|
|
4572
4675
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
4573
4676
|
</ui-button>
|
|
4574
4677
|
</div>
|
|
@@ -4579,22 +4682,18 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4579
4682
|
|
|
4580
4683
|
<div class="tpl-preview-header">
|
|
4581
4684
|
<ui-button variant="ghost" size="sm" (click)="clearTemplate()">
|
|
4582
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
|
4583
|
-
Back to templates
|
|
4584
|
-
</ui-button>
|
|
4685
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>{{ labels.t('messagingSendMessagePanel.backToTemplates') }}</ui-button>
|
|
4585
4686
|
<div class="tpl-view-toggle">
|
|
4586
|
-
<ui-button variant="tab" size="sm" [active]="previewFormat === 'preview'" [ariaPressed]="previewFormat === 'preview'" (click)="setPreviewFormat('preview')">
|
|
4587
|
-
<ui-button variant="tab" size="sm" [active]="previewFormat === 'raw'" [ariaPressed]="previewFormat === 'raw'" (click)="setPreviewFormat('raw')">
|
|
4687
|
+
<ui-button variant="tab" size="sm" [active]="previewFormat === 'preview'" [ariaPressed]="previewFormat === 'preview'" (click)="setPreviewFormat('preview')">{{ labels.t('common.preview') }}</ui-button>
|
|
4688
|
+
<ui-button variant="tab" size="sm" [active]="previewFormat === 'raw'" [ariaPressed]="previewFormat === 'raw'" (click)="setPreviewFormat('raw')">{{ labels.t('messagingSendMessagePanel.raw') }}</ui-button>
|
|
4588
4689
|
</div>
|
|
4589
4690
|
</div>
|
|
4590
4691
|
|
|
4591
4692
|
<div class="tpl-subject-card">
|
|
4592
4693
|
<div class="tpl-subject-card-top">
|
|
4593
|
-
<span class="tpl-subject-label">
|
|
4694
|
+
<span class="tpl-subject-label">{{ labels.t('messagingSendMessagePanel.subject') }}</span>
|
|
4594
4695
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
4595
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
4596
|
-
View Send Preview
|
|
4597
|
-
</ui-button>
|
|
4696
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>{{ labels.t('messagingSendMessagePanel.viewSendPreview') }}</ui-button>
|
|
4598
4697
|
</div>
|
|
4599
4698
|
<span class="tpl-subject-text">{{ resolvedSubject }}</span>
|
|
4600
4699
|
</div>
|
|
@@ -4602,9 +4701,9 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4602
4701
|
<div class="tpl-body-preview" [innerHTML]="previewBodyHtml"></div>
|
|
4603
4702
|
} @else {
|
|
4604
4703
|
<!-- Raw: the template source exactly as written, {{tags}} included — subject first, then the body. -->
|
|
4605
|
-
<div class="tpl-raw-label">
|
|
4704
|
+
<div class="tpl-raw-label">{{ labels.t('common.subject') }}</div>
|
|
4606
4705
|
<pre class="tpl-subject-raw">{{ subject }}</pre>
|
|
4607
|
-
<div class="tpl-raw-label">
|
|
4706
|
+
<div class="tpl-raw-label">{{ labels.t('messagingSendMessagePanel.body') }}</div>
|
|
4608
4707
|
<pre class="tpl-body-raw">{{ body }}</pre>
|
|
4609
4708
|
}
|
|
4610
4709
|
} @else {
|
|
@@ -4641,10 +4740,10 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4641
4740
|
<!-- One live region, at most ONE warning banner: every current non-blocking warning is a line in it. Blocking problems are inline on their field. -->
|
|
4642
4741
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
4643
4742
|
@if (hasDocuments) {
|
|
4644
|
-
<p class="sm-docs-note">
|
|
4743
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.yourMessageGoesOutWith') }}</p>
|
|
4645
4744
|
}
|
|
4646
4745
|
@if (warningLines.length > 0) {
|
|
4647
|
-
<ui-alert variant="warning" title="
|
|
4746
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
4648
4747
|
<ul class="sm-warn-list">
|
|
4649
4748
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
4650
4749
|
</ul>
|
|
@@ -4667,7 +4766,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4667
4766
|
|
|
4668
4767
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
4669
4768
|
@if (mode === 'compose' && showVideo()) {
|
|
4670
|
-
<ui-form-section label="
|
|
4769
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
4671
4770
|
@for (k of [videoPickerKey]; track k) {
|
|
4672
4771
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
4673
4772
|
}
|
|
@@ -4689,20 +4788,18 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4689
4788
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
4690
4789
|
<div class="sp-modal-header">
|
|
4691
4790
|
<div class="sp-modal-title">
|
|
4692
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
|
4693
|
-
|
|
4694
|
-
</div>
|
|
4695
|
-
<ui-button variant="ghost" size="sm" (click)="closeSendPreview()" ariaLabel="Close preview">
|
|
4791
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>{{ labels.t('messagingSendMessagePanel.emailPreview') }}</div>
|
|
4792
|
+
<ui-button variant="ghost" size="sm" (click)="closeSendPreview()" [ariaLabel]="labels.t('messagingSendMessagePanel.closePreview')">
|
|
4696
4793
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
4697
4794
|
</ui-button>
|
|
4698
4795
|
</div>
|
|
4699
4796
|
<div class="sp-email-meta">
|
|
4700
4797
|
<div class="sp-meta-row">
|
|
4701
|
-
<span class="sp-meta-label">
|
|
4702
|
-
<span class="sp-meta-value">@if (bulk()) { {{
|
|
4798
|
+
<span class="sp-meta-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
4799
|
+
<span class="sp-meta-value">@if (bulk()) { {{ labels.t(bulkRecipients()!.length === 1 ? 'messagingSendMessagePanel.recipientCount_one' : 'messagingSendMessagePanel.recipientCount_other', { count: bulkRecipients()!.length }) }} } @else { {{ contactName() }} <{{ contactEmail() }}> }</span>
|
|
4703
4800
|
</div>
|
|
4704
4801
|
<div class="sp-meta-row">
|
|
4705
|
-
<span class="sp-meta-label">
|
|
4802
|
+
<span class="sp-meta-label">{{ labels.t('common.subject') }}</span>
|
|
4706
4803
|
<span class="sp-meta-value sp-meta-subject">{{ sendPreviewSubject }}</span>
|
|
4707
4804
|
</div>
|
|
4708
4805
|
</div>
|
|
@@ -5068,25 +5165,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5068
5165
|
<!-- Missing email guard -->
|
|
5069
5166
|
@if (!bulk() && !contactEmail()) {
|
|
5070
5167
|
<div class="sm-missing-banner">
|
|
5071
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
5072
|
-
No email address on file for this contact.
|
|
5073
|
-
</div>
|
|
5168
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.noEmailAddressOnFile') }}</div>
|
|
5074
5169
|
<ui-text-input
|
|
5075
|
-
label="
|
|
5170
|
+
[label]="labels.t('messagingSendMessagePanel.addEmailAddress')"
|
|
5076
5171
|
type="email"
|
|
5077
5172
|
[required]="true"
|
|
5078
5173
|
placeholder="email@example.com"
|
|
5079
5174
|
[(ngModel)]="pendingEmail"
|
|
5080
5175
|
(ngModelChange)="notifyValid()"
|
|
5081
|
-
[error]="pendingEmail && !pendingEmailValid ? '
|
|
5082
|
-
<ui-button variant="primary" [disabled]="!pendingEmailValid || savingEmail()" [loading]="savingEmail()" (click)="saveEmail()">
|
|
5083
|
-
Save & Continue
|
|
5084
|
-
</ui-button>
|
|
5176
|
+
[error]="pendingEmail && !pendingEmailValid ? labels.t('validation.email') : ''" />
|
|
5177
|
+
<ui-button variant="primary" [disabled]="!pendingEmailValid || savingEmail()" [loading]="savingEmail()" (click)="saveEmail()">{{ labels.t('messagingSendMessagePanel.saveContinue') }}</ui-button>
|
|
5085
5178
|
} @else {
|
|
5086
5179
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
5087
5180
|
@if (!bulk()) {
|
|
5088
5181
|
<div class="sm-group">
|
|
5089
|
-
<span class="sm-group-label">
|
|
5182
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
5090
5183
|
<div class="sm-to-card">
|
|
5091
5184
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
5092
5185
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
@@ -5114,7 +5207,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5114
5207
|
<ui-text-input
|
|
5115
5208
|
label="CC"
|
|
5116
5209
|
placeholder="name@example.com, other@example.com"
|
|
5117
|
-
hint="
|
|
5210
|
+
[hint]="labels.t('messagingSendMessagePanel.separateAddressesWithCommasEveryone')"
|
|
5118
5211
|
[(ngModel)]="ccText"
|
|
5119
5212
|
[error]="ccError"
|
|
5120
5213
|
(ngModelChange)="notifyValid()" />
|
|
@@ -5123,24 +5216,24 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5123
5216
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
5124
5217
|
@if (showTemplates()) {
|
|
5125
5218
|
<div class="sm-mode-row">
|
|
5126
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
5219
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
5127
5220
|
</div>
|
|
5128
5221
|
}
|
|
5129
5222
|
|
|
5130
5223
|
@if (mode === 'compose') {
|
|
5131
5224
|
@if (showSubject()) {
|
|
5132
5225
|
<ui-text-input
|
|
5133
|
-
label="
|
|
5226
|
+
[label]="labels.t('common.subject')"
|
|
5134
5227
|
[required]="!viaDocuSign"
|
|
5135
|
-
placeholder="
|
|
5228
|
+
[placeholder]="labels.t('messagingSendMessagePanel.emailSubject')"
|
|
5136
5229
|
[maxlength]="MAX_SUBJECT"
|
|
5137
5230
|
[(ngModel)]="subject"
|
|
5138
5231
|
(ngModelChange)="notifyValid()" />
|
|
5139
5232
|
}
|
|
5140
5233
|
<ui-textarea-input
|
|
5141
|
-
label="
|
|
5234
|
+
[label]="labels.t('common.message')"
|
|
5142
5235
|
[required]="!viaDocuSign"
|
|
5143
|
-
placeholder="
|
|
5236
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5144
5237
|
[rows]="8"
|
|
5145
5238
|
[(ngModel)]="body"
|
|
5146
5239
|
[error]="composeTagError || bodyLengthError"
|
|
@@ -5148,7 +5241,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5148
5241
|
|
|
5149
5242
|
@if (!hasDocuments && showAttachments()) {
|
|
5150
5243
|
<div class="sm-field">
|
|
5151
|
-
<label class="sm-field-label">
|
|
5244
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</label>
|
|
5152
5245
|
@if (attachments.length > 0) {
|
|
5153
5246
|
<div class="attach-chips">
|
|
5154
5247
|
@for (a of attachments; track a.filename; let i = $index) {
|
|
@@ -5156,25 +5249,23 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5156
5249
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
|
5157
5250
|
<span class="attach-name">{{ a.filename }}</span>
|
|
5158
5251
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
5159
|
-
<button class="attach-remove" type="button" (click)="removeAttachment(i)" aria-label="
|
|
5252
|
+
<button class="attach-remove" type="button" (click)="removeAttachment(i)" [attr.aria-label]="labels.t('messagingSendMessagePanel.removeAttachment')">×</button>
|
|
5160
5253
|
</div>
|
|
5161
5254
|
}
|
|
5162
5255
|
</div>
|
|
5163
5256
|
}
|
|
5164
5257
|
<input #emailFileInput type="file" multiple hidden (change)="onFilesSelected($event)" />
|
|
5165
5258
|
<button type="button" class="attach-add-btn" (click)="emailFileInput.click()">
|
|
5166
|
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
|
5167
|
-
Attach Files
|
|
5168
|
-
</button>
|
|
5259
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>{{ labels.t('messagingSendMessagePanel.attachFiles') }}</button>
|
|
5169
5260
|
</div>
|
|
5170
5261
|
|
|
5171
5262
|
}
|
|
5172
5263
|
|
|
5173
5264
|
@if (!hasDocuments && showScheduling()) {
|
|
5174
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
5265
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
5175
5266
|
@if (showSchedule) {
|
|
5176
5267
|
<ui-datetime-input
|
|
5177
|
-
label="
|
|
5268
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
5178
5269
|
[min]="minScheduleTime"
|
|
5179
5270
|
[(ngModel)]="scheduledAt"
|
|
5180
5271
|
(ngModelChange)="notifyValid()" />
|
|
@@ -5184,14 +5275,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5184
5275
|
@if (missingVars.length > 0) {
|
|
5185
5276
|
<div class="mv-section">
|
|
5186
5277
|
<p class="mv-hint">
|
|
5187
|
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
5188
|
-
This template has fields that need values before sending.
|
|
5189
|
-
</p>
|
|
5278
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.thisTemplateHasFieldsThat') }}</p>
|
|
5190
5279
|
@for (key of missingVars; track key) {
|
|
5191
5280
|
<div class="mv-row">
|
|
5192
5281
|
<div class="mv-input-wrap">
|
|
5193
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
5194
|
-
<ui-button variant="primary" size="sm" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" ariaLabel="
|
|
5282
|
+
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="labels.t('messagingSendMessagePanel.enterValue', { name: formatVarLabel(key).toLowerCase() })" [(ngModel)]="pendingInputs[key]" (ngModelChange)="notifyValid()" (keydown.enter)="applyVar(key)" />
|
|
5283
|
+
<ui-button variant="primary" size="sm" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" [ariaLabel]="labels.t('messagingSendMessagePanel.applyValue')">
|
|
5195
5284
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
5196
5285
|
</ui-button>
|
|
5197
5286
|
</div>
|
|
@@ -5202,22 +5291,18 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5202
5291
|
|
|
5203
5292
|
<div class="tpl-preview-header">
|
|
5204
5293
|
<ui-button variant="ghost" size="sm" (click)="clearTemplate()">
|
|
5205
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
|
5206
|
-
Back to templates
|
|
5207
|
-
</ui-button>
|
|
5294
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>{{ labels.t('messagingSendMessagePanel.backToTemplates') }}</ui-button>
|
|
5208
5295
|
<div class="tpl-view-toggle">
|
|
5209
|
-
<ui-button variant="tab" size="sm" [active]="previewFormat === 'preview'" [ariaPressed]="previewFormat === 'preview'" (click)="setPreviewFormat('preview')">
|
|
5210
|
-
<ui-button variant="tab" size="sm" [active]="previewFormat === 'raw'" [ariaPressed]="previewFormat === 'raw'" (click)="setPreviewFormat('raw')">
|
|
5296
|
+
<ui-button variant="tab" size="sm" [active]="previewFormat === 'preview'" [ariaPressed]="previewFormat === 'preview'" (click)="setPreviewFormat('preview')">{{ labels.t('common.preview') }}</ui-button>
|
|
5297
|
+
<ui-button variant="tab" size="sm" [active]="previewFormat === 'raw'" [ariaPressed]="previewFormat === 'raw'" (click)="setPreviewFormat('raw')">{{ labels.t('messagingSendMessagePanel.raw') }}</ui-button>
|
|
5211
5298
|
</div>
|
|
5212
5299
|
</div>
|
|
5213
5300
|
|
|
5214
5301
|
<div class="tpl-subject-card">
|
|
5215
5302
|
<div class="tpl-subject-card-top">
|
|
5216
|
-
<span class="tpl-subject-label">
|
|
5303
|
+
<span class="tpl-subject-label">{{ labels.t('messagingSendMessagePanel.subject') }}</span>
|
|
5217
5304
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
5218
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
5219
|
-
View Send Preview
|
|
5220
|
-
</ui-button>
|
|
5305
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>{{ labels.t('messagingSendMessagePanel.viewSendPreview') }}</ui-button>
|
|
5221
5306
|
</div>
|
|
5222
5307
|
<span class="tpl-subject-text">{{ resolvedSubject }}</span>
|
|
5223
5308
|
</div>
|
|
@@ -5225,9 +5310,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5225
5310
|
<div class="tpl-body-preview" [innerHTML]="previewBodyHtml"></div>
|
|
5226
5311
|
} @else {
|
|
5227
5312
|
<!-- Raw: the template source exactly as written, {{tags}} included — subject first, then the body. -->
|
|
5228
|
-
<div class="tpl-raw-label">
|
|
5313
|
+
<div class="tpl-raw-label">{{ labels.t('common.subject') }}</div>
|
|
5229
5314
|
<pre class="tpl-subject-raw">{{ subject }}</pre>
|
|
5230
|
-
<div class="tpl-raw-label">
|
|
5315
|
+
<div class="tpl-raw-label">{{ labels.t('messagingSendMessagePanel.body') }}</div>
|
|
5231
5316
|
<pre class="tpl-body-raw">{{ body }}</pre>
|
|
5232
5317
|
}
|
|
5233
5318
|
} @else {
|
|
@@ -5264,10 +5349,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5264
5349
|
<!-- One live region, at most ONE warning banner: every current non-blocking warning is a line in it. Blocking problems are inline on their field. -->
|
|
5265
5350
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
5266
5351
|
@if (hasDocuments) {
|
|
5267
|
-
<p class="sm-docs-note">
|
|
5352
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.yourMessageGoesOutWith') }}</p>
|
|
5268
5353
|
}
|
|
5269
5354
|
@if (warningLines.length > 0) {
|
|
5270
|
-
<ui-alert variant="warning" title="
|
|
5355
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
5271
5356
|
<ul class="sm-warn-list">
|
|
5272
5357
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
5273
5358
|
</ul>
|
|
@@ -5290,7 +5375,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5290
5375
|
|
|
5291
5376
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
5292
5377
|
@if (mode === 'compose' && showVideo()) {
|
|
5293
|
-
<ui-form-section label="
|
|
5378
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
5294
5379
|
@for (k of [videoPickerKey]; track k) {
|
|
5295
5380
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
5296
5381
|
}
|
|
@@ -5312,20 +5397,18 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5312
5397
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
5313
5398
|
<div class="sp-modal-header">
|
|
5314
5399
|
<div class="sp-modal-title">
|
|
5315
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
|
5316
|
-
|
|
5317
|
-
</div>
|
|
5318
|
-
<ui-button variant="ghost" size="sm" (click)="closeSendPreview()" ariaLabel="Close preview">
|
|
5400
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>{{ labels.t('messagingSendMessagePanel.emailPreview') }}</div>
|
|
5401
|
+
<ui-button variant="ghost" size="sm" (click)="closeSendPreview()" [ariaLabel]="labels.t('messagingSendMessagePanel.closePreview')">
|
|
5319
5402
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
5320
5403
|
</ui-button>
|
|
5321
5404
|
</div>
|
|
5322
5405
|
<div class="sp-email-meta">
|
|
5323
5406
|
<div class="sp-meta-row">
|
|
5324
|
-
<span class="sp-meta-label">
|
|
5325
|
-
<span class="sp-meta-value">@if (bulk()) { {{
|
|
5407
|
+
<span class="sp-meta-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
5408
|
+
<span class="sp-meta-value">@if (bulk()) { {{ labels.t(bulkRecipients()!.length === 1 ? 'messagingSendMessagePanel.recipientCount_one' : 'messagingSendMessagePanel.recipientCount_other', { count: bulkRecipients()!.length }) }} } @else { {{ contactName() }} <{{ contactEmail() }}> }</span>
|
|
5326
5409
|
</div>
|
|
5327
5410
|
<div class="sp-meta-row">
|
|
5328
|
-
<span class="sp-meta-label">
|
|
5411
|
+
<span class="sp-meta-label">{{ labels.t('common.subject') }}</span>
|
|
5329
5412
|
<span class="sp-meta-value sp-meta-subject">{{ sendPreviewSubject }}</span>
|
|
5330
5413
|
</div>
|
|
5331
5414
|
</div>
|
|
@@ -5419,7 +5502,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5419
5502
|
required: false
|
|
5420
5503
|
}]
|
|
5421
5504
|
}],
|
|
5422
|
-
|
|
5505
|
+
receiptLabelInput: [{
|
|
5423
5506
|
type: i0.Input,
|
|
5424
5507
|
args: [{
|
|
5425
5508
|
isSignal: true,
|
|
@@ -5636,6 +5719,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5636
5719
|
const MAX_SUBJECT = 255;
|
|
5637
5720
|
var SendInAppComponent = class SendInAppComponent {
|
|
5638
5721
|
constructor() {
|
|
5722
|
+
this.labels = inject(UiLabelsService);
|
|
5639
5723
|
this.destroyRef = inject(DestroyRef);
|
|
5640
5724
|
this.toast = inject(ToastService);
|
|
5641
5725
|
this.cdr = inject(ChangeDetectorRef);
|
|
@@ -5684,7 +5768,7 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5684
5768
|
const reader = new FileReader();
|
|
5685
5769
|
reader.onload = () => {
|
|
5686
5770
|
const base64 = String(reader.result).split(",")[1] ?? "";
|
|
5687
|
-
const sizeLabel =
|
|
5771
|
+
const sizeLabel = formatAttachmentSize(file.size);
|
|
5688
5772
|
this.attachments = [...this.attachments, {
|
|
5689
5773
|
filename: file.name,
|
|
5690
5774
|
content: base64,
|
|
@@ -5722,13 +5806,13 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5722
5806
|
if (this.showSubject()) payload.subject = this.subject.trim();
|
|
5723
5807
|
send(payload).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
5724
5808
|
next: () => {
|
|
5725
|
-
this.toast.show("
|
|
5809
|
+
this.toast.show(this.labels.t("messagingSendMessagePanel.messageSent"));
|
|
5726
5810
|
this.sending.set(false);
|
|
5727
5811
|
this.attachments = [];
|
|
5728
5812
|
this.sent.emit();
|
|
5729
5813
|
},
|
|
5730
5814
|
error: (err) => {
|
|
5731
|
-
this.toast.error(serverMessage(err) || "
|
|
5815
|
+
this.toast.error(serverMessage(err) || this.labels.t("messagingSendMessagePanel.failedSendMessage"));
|
|
5732
5816
|
this.sending.set(false);
|
|
5733
5817
|
this.notifyValid();
|
|
5734
5818
|
}
|
|
@@ -5830,7 +5914,7 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5830
5914
|
ngImport: i0,
|
|
5831
5915
|
template: `
|
|
5832
5916
|
<div class="sm-group">
|
|
5833
|
-
<span class="sm-group-label">
|
|
5917
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
5834
5918
|
<div class="sm-to-card">
|
|
5835
5919
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
5836
5920
|
@if (contactEmail()) { <span class="sm-to-email">{{ contactEmail() }}</span> }
|
|
@@ -5838,56 +5922,56 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5838
5922
|
</div>
|
|
5839
5923
|
@if (showSubject()) {
|
|
5840
5924
|
<ui-text-input
|
|
5841
|
-
label="
|
|
5925
|
+
[label]="labels.t('common.subject')"
|
|
5842
5926
|
[required]="true"
|
|
5843
|
-
placeholder="
|
|
5927
|
+
[placeholder]="labels.t('messagingSendMessagePanel.subject2')"
|
|
5844
5928
|
[maxlength]="MAX_SUBJECT"
|
|
5845
5929
|
[(ngModel)]="subject"
|
|
5846
5930
|
(ngModelChange)="notifyValid()" />
|
|
5847
5931
|
}
|
|
5848
5932
|
@if (richText()) {
|
|
5849
5933
|
<ui-rich-text-editor
|
|
5850
|
-
label="
|
|
5934
|
+
[label]="labels.t('common.message')"
|
|
5851
5935
|
[required]="true"
|
|
5852
|
-
placeholder="
|
|
5936
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5853
5937
|
[minHeight]="180"
|
|
5854
|
-
[error]="richTooLong() ? '
|
|
5938
|
+
[error]="richTooLong() ? labels.t('validation.tooLong', { max: limit() }) : ''"
|
|
5855
5939
|
[(ngModel)]="body"
|
|
5856
5940
|
(ngModelChange)="notifyValid()" />
|
|
5857
5941
|
} @else if (limit(); as max) {
|
|
5858
5942
|
<ui-textarea-input
|
|
5859
|
-
label="
|
|
5943
|
+
[label]="labels.t('common.message')"
|
|
5860
5944
|
[required]="true"
|
|
5861
|
-
placeholder="
|
|
5945
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5862
5946
|
[rows]="8"
|
|
5863
5947
|
[maxlength]="max"
|
|
5864
5948
|
[(ngModel)]="body"
|
|
5865
5949
|
(ngModelChange)="notifyValid()" />
|
|
5866
5950
|
} @else {
|
|
5867
5951
|
<ui-textarea-input
|
|
5868
|
-
label="
|
|
5952
|
+
[label]="labels.t('common.message')"
|
|
5869
5953
|
[required]="true"
|
|
5870
|
-
placeholder="
|
|
5954
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5871
5955
|
[rows]="8"
|
|
5872
5956
|
[(ngModel)]="body"
|
|
5873
5957
|
(ngModelChange)="notifyValid()" />
|
|
5874
5958
|
}
|
|
5875
5959
|
@if (allowAttachments()) {
|
|
5876
5960
|
<div class="sm-group" data-testid="in-app-attachments">
|
|
5877
|
-
<span class="sm-group-label">
|
|
5961
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</span>
|
|
5878
5962
|
@if (attachments.length > 0) {
|
|
5879
5963
|
<div class="attach-chips">
|
|
5880
5964
|
@for (a of attachments; track $index; let i = $index) {
|
|
5881
5965
|
<div class="attach-chip">
|
|
5882
5966
|
<span class="attach-name">{{ a.filename }}</span>
|
|
5883
5967
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
5884
|
-
<button class="attach-remove" type="button" (click)="removeAttachment(i)" [attr.aria-label]="'
|
|
5968
|
+
<button class="attach-remove" type="button" (click)="removeAttachment(i)" [attr.aria-label]="labels.t('common.removeNamed', { name: a.filename })">×</button>
|
|
5885
5969
|
</div>
|
|
5886
5970
|
}
|
|
5887
5971
|
</div>
|
|
5888
5972
|
}
|
|
5889
5973
|
<input #fileInput type="file" multiple hidden data-testid="in-app-file-input" (change)="onFilesSelected($event)" />
|
|
5890
|
-
<button type="button" class="attach-add-btn" (click)="fileInput.click()">
|
|
5974
|
+
<button type="button" class="attach-add-btn" (click)="fileInput.click()">{{ labels.t('messagingSendMessagePanel.attachFiles') }}</button>
|
|
5891
5975
|
</div>
|
|
5892
5976
|
}
|
|
5893
5977
|
`,
|
|
@@ -6038,7 +6122,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6038
6122
|
],
|
|
6039
6123
|
template: `
|
|
6040
6124
|
<div class="sm-group">
|
|
6041
|
-
<span class="sm-group-label">
|
|
6125
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
6042
6126
|
<div class="sm-to-card">
|
|
6043
6127
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
6044
6128
|
@if (contactEmail()) { <span class="sm-to-email">{{ contactEmail() }}</span> }
|
|
@@ -6046,56 +6130,56 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6046
6130
|
</div>
|
|
6047
6131
|
@if (showSubject()) {
|
|
6048
6132
|
<ui-text-input
|
|
6049
|
-
label="
|
|
6133
|
+
[label]="labels.t('common.subject')"
|
|
6050
6134
|
[required]="true"
|
|
6051
|
-
placeholder="
|
|
6135
|
+
[placeholder]="labels.t('messagingSendMessagePanel.subject2')"
|
|
6052
6136
|
[maxlength]="MAX_SUBJECT"
|
|
6053
6137
|
[(ngModel)]="subject"
|
|
6054
6138
|
(ngModelChange)="notifyValid()" />
|
|
6055
6139
|
}
|
|
6056
6140
|
@if (richText()) {
|
|
6057
6141
|
<ui-rich-text-editor
|
|
6058
|
-
label="
|
|
6142
|
+
[label]="labels.t('common.message')"
|
|
6059
6143
|
[required]="true"
|
|
6060
|
-
placeholder="
|
|
6144
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6061
6145
|
[minHeight]="180"
|
|
6062
|
-
[error]="richTooLong() ? '
|
|
6146
|
+
[error]="richTooLong() ? labels.t('validation.tooLong', { max: limit() }) : ''"
|
|
6063
6147
|
[(ngModel)]="body"
|
|
6064
6148
|
(ngModelChange)="notifyValid()" />
|
|
6065
6149
|
} @else if (limit(); as max) {
|
|
6066
6150
|
<ui-textarea-input
|
|
6067
|
-
label="
|
|
6151
|
+
[label]="labels.t('common.message')"
|
|
6068
6152
|
[required]="true"
|
|
6069
|
-
placeholder="
|
|
6153
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6070
6154
|
[rows]="8"
|
|
6071
6155
|
[maxlength]="max"
|
|
6072
6156
|
[(ngModel)]="body"
|
|
6073
6157
|
(ngModelChange)="notifyValid()" />
|
|
6074
6158
|
} @else {
|
|
6075
6159
|
<ui-textarea-input
|
|
6076
|
-
label="
|
|
6160
|
+
[label]="labels.t('common.message')"
|
|
6077
6161
|
[required]="true"
|
|
6078
|
-
placeholder="
|
|
6162
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6079
6163
|
[rows]="8"
|
|
6080
6164
|
[(ngModel)]="body"
|
|
6081
6165
|
(ngModelChange)="notifyValid()" />
|
|
6082
6166
|
}
|
|
6083
6167
|
@if (allowAttachments()) {
|
|
6084
6168
|
<div class="sm-group" data-testid="in-app-attachments">
|
|
6085
|
-
<span class="sm-group-label">
|
|
6169
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</span>
|
|
6086
6170
|
@if (attachments.length > 0) {
|
|
6087
6171
|
<div class="attach-chips">
|
|
6088
6172
|
@for (a of attachments; track $index; let i = $index) {
|
|
6089
6173
|
<div class="attach-chip">
|
|
6090
6174
|
<span class="attach-name">{{ a.filename }}</span>
|
|
6091
6175
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
6092
|
-
<button class="attach-remove" type="button" (click)="removeAttachment(i)" [attr.aria-label]="'
|
|
6176
|
+
<button class="attach-remove" type="button" (click)="removeAttachment(i)" [attr.aria-label]="labels.t('common.removeNamed', { name: a.filename })">×</button>
|
|
6093
6177
|
</div>
|
|
6094
6178
|
}
|
|
6095
6179
|
</div>
|
|
6096
6180
|
}
|
|
6097
6181
|
<input #fileInput type="file" multiple hidden data-testid="in-app-file-input" (change)="onFilesSelected($event)" />
|
|
6098
|
-
<button type="button" class="attach-add-btn" (click)="fileInput.click()">
|
|
6182
|
+
<button type="button" class="attach-add-btn" (click)="fileInput.click()">{{ labels.t('messagingSendMessagePanel.attachFiles') }}</button>
|
|
6099
6183
|
</div>
|
|
6100
6184
|
}
|
|
6101
6185
|
`,
|
|
@@ -6217,6 +6301,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6217
6301
|
} });
|
|
6218
6302
|
}
|
|
6219
6303
|
constructor() {
|
|
6304
|
+
this.labels = inject(UiLabelsService);
|
|
6220
6305
|
this.formatPhone = formatPhone;
|
|
6221
6306
|
this.destroyRef = inject(DestroyRef);
|
|
6222
6307
|
this.http = inject(HttpClient);
|
|
@@ -6290,13 +6375,13 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6290
6375
|
this.mediaAttachment = signal(null, ...ngDevMode ? [{ debugName: "mediaAttachment" }] : /* istanbul ignore next */ []);
|
|
6291
6376
|
this.mediaUploading = signal(false, ...ngDevMode ? [{ debugName: "mediaUploading" }] : /* istanbul ignore next */ []);
|
|
6292
6377
|
this.savingPhone = signal(false, ...ngDevMode ? [{ debugName: "savingPhone" }] : /* istanbul ignore next */ []);
|
|
6293
|
-
this.modeTabs = [{
|
|
6378
|
+
this.modeTabs = computed(() => [{
|
|
6294
6379
|
key: "compose",
|
|
6295
|
-
label: "
|
|
6380
|
+
label: this.labels.t("messagingSendMessagePanel.tabCompose")
|
|
6296
6381
|
}, {
|
|
6297
6382
|
key: "template",
|
|
6298
|
-
label: "
|
|
6299
|
-
}];
|
|
6383
|
+
label: this.labels.t("messagingSendMessagePanel.tabTemplate")
|
|
6384
|
+
}], ...ngDevMode ? [{ debugName: "modeTabs" }] : /* istanbul ignore next */ []);
|
|
6300
6385
|
this.marketVars = {};
|
|
6301
6386
|
this._appliedDefaultBody = "";
|
|
6302
6387
|
this.forwardedContext = computed(() => forwardContext(this.sendContext(), this.documentContextTypes()).context, ...ngDevMode ? [{ debugName: "forwardedContext" }] : /* istanbul ignore next */ []);
|
|
@@ -6359,8 +6444,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6359
6444
|
onDocumentsChange(v) {
|
|
6360
6445
|
this.documentsValue = v;
|
|
6361
6446
|
if (this.hasDocuments) {
|
|
6362
|
-
const removed = [this.mediaAttachment() ? "
|
|
6363
|
-
if (removed.length > 0) this.docsRemovedNote =
|
|
6447
|
+
const removed = [this.mediaAttachment() ? this.labels.t("messagingSendMessagePanel.removedImage") : "", this.showSchedule ? this.labels.t("messagingSendMessagePanel.removedSchedule") : ""].filter(Boolean);
|
|
6448
|
+
if (removed.length > 0) this.docsRemovedNote = this.labels.t("messagingSendMessagePanel.removedBecauseRequest", { items: removed.join(` ${this.labels.t("messagingSendMessagePanel.listAnd")} `) });
|
|
6364
6449
|
this.showSchedule = false;
|
|
6365
6450
|
this.scheduledAt = "";
|
|
6366
6451
|
this.mediaAttachment.set(null);
|
|
@@ -6412,10 +6497,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6412
6497
|
return mergeTagKeys(this.body).filter((k) => !known[k] && !this.deferredKeys.includes(k));
|
|
6413
6498
|
}
|
|
6414
6499
|
get videoLengthError() {
|
|
6415
|
-
return this._videoLine && this.body.length > this.MAX_LENGTH ?
|
|
6500
|
+
return this._videoLine && this.body.length > this.MAX_LENGTH ? this.labels.t("messagingSendMessagePanel.textTooLongWithVideo", { max: this.MAX_LENGTH }) : "";
|
|
6416
6501
|
}
|
|
6417
6502
|
get composeTagError() {
|
|
6418
|
-
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "
|
|
6503
|
+
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? this.labels.t("messagingSendMessagePanel.leftoverTags") : "";
|
|
6419
6504
|
}
|
|
6420
6505
|
get unresolvedVars() {
|
|
6421
6506
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -6497,7 +6582,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6497
6582
|
onFileSelected(event) {
|
|
6498
6583
|
const file = event.target.files?.[0];
|
|
6499
6584
|
if (!file) return;
|
|
6500
|
-
const sizeLabel =
|
|
6585
|
+
const sizeLabel = formatAttachmentSize(file.size);
|
|
6501
6586
|
this.mediaUploading.set(true);
|
|
6502
6587
|
this.cdr.detectChanges();
|
|
6503
6588
|
const form = new FormData();
|
|
@@ -6514,7 +6599,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6514
6599
|
this.cdr.detectChanges();
|
|
6515
6600
|
},
|
|
6516
6601
|
error: () => {
|
|
6517
|
-
this.toast.error("
|
|
6602
|
+
this.toast.error(this.labels.t("messagingSendMessagePanel.failedUpload"));
|
|
6518
6603
|
this.mediaUploading.set(false);
|
|
6519
6604
|
this.cdr.detectChanges();
|
|
6520
6605
|
}
|
|
@@ -6527,7 +6612,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6527
6612
|
insertVideo(v) {
|
|
6528
6613
|
if (!v.shareLink) return;
|
|
6529
6614
|
const sep = this.body.trim() ? "\n\n" : "";
|
|
6530
|
-
this.body = (this.body + sep +
|
|
6615
|
+
this.body = (this.body + sep + videoMessageLine(v.title, v.shareLink)).slice(0, this.MAX_LENGTH);
|
|
6531
6616
|
this.notifyValid();
|
|
6532
6617
|
}
|
|
6533
6618
|
onVideoSelected(v) {
|
|
@@ -6562,7 +6647,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6562
6647
|
submit() {
|
|
6563
6648
|
if (!this.canSend || this.loading || !this.bulk() && !this.contactPhone()) return;
|
|
6564
6649
|
if (this.bulk() && !this.sendFn()) {
|
|
6565
|
-
this.toast.error(
|
|
6650
|
+
this.toast.error(this.labels.t("messagingSendMessagePanel.bulkNoSend"));
|
|
6566
6651
|
return;
|
|
6567
6652
|
}
|
|
6568
6653
|
if (this.mode === "template") this.applyPendingVars();
|
|
@@ -6634,7 +6719,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6634
6719
|
});
|
|
6635
6720
|
const onError = (err) => {
|
|
6636
6721
|
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
6637
|
-
this.toast.error(custom || docs ? getErrorMessage(err, "
|
|
6722
|
+
this.toast.error(custom || docs ? getErrorMessage(err, this.labels.t("messagingSendMessagePanel.ctxText"), "send") : serverMessage(err) || this.labels.t("messagingSendMessagePanel.failedSendText"));
|
|
6638
6723
|
this.loading = false;
|
|
6639
6724
|
this.cdr.detectChanges();
|
|
6640
6725
|
if (this.bulk()) this.bulkSending.emit(null);
|
|
@@ -6649,7 +6734,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6649
6734
|
channel: "text",
|
|
6650
6735
|
informational: docs.signerInfo?.informational === true
|
|
6651
6736
|
}) : void 0;
|
|
6652
|
-
this.toast.show(sentText ?? (docs && this.documentEnvelope() ?
|
|
6737
|
+
this.toast.show(sentText ?? (docs && this.documentEnvelope() ? this.labels.t("messagingSendMessagePanel.envelopeSent", { name: this.documentEnvelope().name }) : this.showSchedule ? this.labels.t("messagingSendMessagePanel.messageScheduled") : this.labels.t("messagingSendMessagePanel.textSent")));
|
|
6653
6738
|
this.loading = false;
|
|
6654
6739
|
this.mediaAttachment.set(null);
|
|
6655
6740
|
if (this.bulk()) this.bulkResult.emit({
|
|
@@ -6872,25 +6957,21 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6872
6957
|
<!-- Missing phone guard -->
|
|
6873
6958
|
@if (!bulk() && !contactPhone()) {
|
|
6874
6959
|
<div class="sm-missing-banner">
|
|
6875
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
6876
|
-
No phone number on file for this contact.
|
|
6877
|
-
</div>
|
|
6960
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.noPhoneNumberOnFile') }}</div>
|
|
6878
6961
|
<ui-text-input
|
|
6879
|
-
label="
|
|
6962
|
+
[label]="labels.t('messagingSendMessagePanel.addPhoneNumber')"
|
|
6880
6963
|
type="tel"
|
|
6881
6964
|
[required]="true"
|
|
6882
6965
|
placeholder="(555) 000-0000"
|
|
6883
6966
|
[(ngModel)]="pendingPhone"
|
|
6884
6967
|
(ngModelChange)="notifyValid()"
|
|
6885
|
-
[error]="pendingPhone && !pendingPhoneValid ? '
|
|
6886
|
-
<ui-button variant="primary" [disabled]="!pendingPhoneValid || savingPhone()" [loading]="savingPhone()" (click)="savePhone()">
|
|
6887
|
-
Save & Continue
|
|
6888
|
-
</ui-button>
|
|
6968
|
+
[error]="pendingPhone && !pendingPhoneValid ? labels.t('validation.phone') : ''" />
|
|
6969
|
+
<ui-button variant="primary" [disabled]="!pendingPhoneValid || savingPhone()" [loading]="savingPhone()" (click)="savePhone()">{{ labels.t('messagingSendMessagePanel.saveContinue') }}</ui-button>
|
|
6889
6970
|
} @else {
|
|
6890
6971
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
6891
6972
|
@if (!bulk()) {
|
|
6892
6973
|
<div class="sm-group">
|
|
6893
|
-
<span class="sm-group-label">
|
|
6974
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
6894
6975
|
<div class="sm-to-card">
|
|
6895
6976
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
6896
6977
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
@@ -6901,23 +6982,23 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6901
6982
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
6902
6983
|
@if (showTemplates()) {
|
|
6903
6984
|
<div class="sm-mode-row">
|
|
6904
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
6985
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
6905
6986
|
</div>
|
|
6906
6987
|
}
|
|
6907
6988
|
|
|
6908
6989
|
@if (mode === 'compose') {
|
|
6909
6990
|
<div class="sm-field">
|
|
6910
6991
|
<ui-textarea-input
|
|
6911
|
-
label="
|
|
6992
|
+
[label]="labels.t('common.message')"
|
|
6912
6993
|
[required]="true"
|
|
6913
|
-
placeholder="
|
|
6994
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6914
6995
|
[rows]="8"
|
|
6915
6996
|
[maxlength]="MAX_LENGTH"
|
|
6916
6997
|
[(ngModel)]="body"
|
|
6917
6998
|
[error]="composeTagError || videoLengthError"
|
|
6918
6999
|
(ngModelChange)="notifyValid()" />
|
|
6919
7000
|
<div class="sm-char-row">
|
|
6920
|
-
<span class="sm-hint">
|
|
7001
|
+
<span class="sm-hint">{{ labels.t('messagingSendMessagePanel.sentAsSmsKeepMessages') }}</span>
|
|
6921
7002
|
<span class="sm-char-count" [class.sm-char-warn]="body.length > MAX_LENGTH * 0.9">
|
|
6922
7003
|
{{ body.length }} / {{ MAX_LENGTH }}
|
|
6923
7004
|
</span>
|
|
@@ -6926,14 +7007,14 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6926
7007
|
|
|
6927
7008
|
@if (!hasDocuments && showAttachments()) {
|
|
6928
7009
|
<div class="sm-field">
|
|
6929
|
-
<label class="sm-field-label">
|
|
7010
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.addImageMediaMms') }}</label>
|
|
6930
7011
|
@if (mediaAttachment()) {
|
|
6931
7012
|
<div class="attach-chips">
|
|
6932
7013
|
<div class="attach-chip">
|
|
6933
7014
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
|
6934
7015
|
<span class="attach-name">{{ mediaAttachment()!.mediaFileName }}</span>
|
|
6935
7016
|
<span class="attach-size">{{ mediaAttachment()!.sizeLabel }}</span>
|
|
6936
|
-
<button class="attach-remove" type="button" (click)="removeMedia()" aria-label="
|
|
7017
|
+
<button class="attach-remove" type="button" (click)="removeMedia()" [attr.aria-label]="labels.t('messagingSendMessagePanel.removeAttachment')">×</button>
|
|
6937
7018
|
</div>
|
|
6938
7019
|
</div>
|
|
6939
7020
|
}
|
|
@@ -6941,10 +7022,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6941
7022
|
<input #smsFileInput type="file" accept="image/*,video/*,application/pdf" hidden (change)="onFileSelected($event)" />
|
|
6942
7023
|
<button type="button" class="attach-add-btn" [disabled]="mediaUploading()" (click)="smsFileInput.click()">
|
|
6943
7024
|
@if (mediaUploading()) {
|
|
6944
|
-
<span class="attach-spinner"></span>
|
|
7025
|
+
<span class="attach-spinner"></span> {{ labels.t('messagingSendText.uploading') }}
|
|
6945
7026
|
} @else {
|
|
6946
7027
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
|
6947
|
-
|
|
7028
|
+
{{ labels.t('messagingSendMessagePanel.attachImage') }}
|
|
6948
7029
|
}
|
|
6949
7030
|
</button>
|
|
6950
7031
|
}
|
|
@@ -6953,10 +7034,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6953
7034
|
}
|
|
6954
7035
|
|
|
6955
7036
|
@if (!hasDocuments && showScheduling()) {
|
|
6956
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
7037
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
6957
7038
|
@if (showSchedule) {
|
|
6958
7039
|
<ui-datetime-input
|
|
6959
|
-
label="
|
|
7040
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
6960
7041
|
[min]="minScheduleTime"
|
|
6961
7042
|
[(ngModel)]="scheduledAt"
|
|
6962
7043
|
(ngModelChange)="notifyValid()" />
|
|
@@ -6966,14 +7047,12 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6966
7047
|
@if (missingVars.length > 0) {
|
|
6967
7048
|
<div class="mv-section">
|
|
6968
7049
|
<p class="mv-hint">
|
|
6969
|
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
6970
|
-
This template has fields that need values before sending.
|
|
6971
|
-
</p>
|
|
7050
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.thisTemplateHasFieldsThat') }}</p>
|
|
6972
7051
|
@for (key of missingVars; track key) {
|
|
6973
7052
|
<div class="mv-row">
|
|
6974
7053
|
<div class="mv-input-wrap">
|
|
6975
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
6976
|
-
<button class="mv-apply-btn" type="button" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" aria-label="
|
|
7054
|
+
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="labels.t('messagingSendMessagePanel.enterValue', { name: formatVarLabel(key).toLowerCase() })" [(ngModel)]="pendingInputs[key]" (ngModelChange)="notifyValid()" (keydown.enter)="applyVar(key)" />
|
|
7055
|
+
<button class="mv-apply-btn" type="button" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" [attr.aria-label]="labels.t('messagingSendMessagePanel.applyValue')">
|
|
6977
7056
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
6978
7057
|
</button>
|
|
6979
7058
|
</div>
|
|
@@ -6984,20 +7063,16 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6984
7063
|
|
|
6985
7064
|
<div class="tpl-preview-header">
|
|
6986
7065
|
<button class="tpl-back-btn" type="button" (click)="clearTemplate()">
|
|
6987
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
|
6988
|
-
Back to templates
|
|
6989
|
-
</button>
|
|
7066
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>{{ labels.t('messagingSendMessagePanel.backToTemplates') }}</button>
|
|
6990
7067
|
<div class="tpl-view-toggle">
|
|
6991
|
-
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'preview'" [attr.aria-pressed]="previewFormat === 'preview'" type="button" (click)="setPreviewFormat('preview')">
|
|
6992
|
-
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'raw'" [attr.aria-pressed]="previewFormat === 'raw'" type="button" (click)="setPreviewFormat('raw')">
|
|
7068
|
+
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'preview'" [attr.aria-pressed]="previewFormat === 'preview'" type="button" (click)="setPreviewFormat('preview')">{{ labels.t('common.preview') }}</button>
|
|
7069
|
+
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'raw'" [attr.aria-pressed]="previewFormat === 'raw'" type="button" (click)="setPreviewFormat('raw')">{{ labels.t('messagingSendMessagePanel.raw') }}</button>
|
|
6993
7070
|
</div>
|
|
6994
7071
|
</div>
|
|
6995
7072
|
|
|
6996
7073
|
<div class="tpl-send-preview-row">
|
|
6997
7074
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
6998
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
6999
|
-
View Send Preview
|
|
7000
|
-
</ui-button>
|
|
7075
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>{{ labels.t('messagingSendMessagePanel.viewSendPreview') }}</ui-button>
|
|
7001
7076
|
</div>
|
|
7002
7077
|
|
|
7003
7078
|
@if (previewFormat === 'preview') {
|
|
@@ -7037,10 +7112,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7037
7112
|
<!-- One live region, at most ONE warning banner (every current non-blocking warning is a line in it). -->
|
|
7038
7113
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
7039
7114
|
@if (hasDocuments) {
|
|
7040
|
-
<p class="sm-docs-note">
|
|
7115
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.theDocumentsAreTextedAs') }}</p>
|
|
7041
7116
|
}
|
|
7042
7117
|
@if (warningLines.length > 0) {
|
|
7043
|
-
<ui-alert variant="warning" title="
|
|
7118
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
7044
7119
|
<ul class="sm-warn-list">
|
|
7045
7120
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
7046
7121
|
</ul>
|
|
@@ -7051,7 +7126,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7051
7126
|
|
|
7052
7127
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
7053
7128
|
@if (mode === 'compose' && showVideo()) {
|
|
7054
|
-
<ui-form-section label="
|
|
7129
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
7055
7130
|
@for (k of [videoPickerKey]; track k) {
|
|
7056
7131
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
7057
7132
|
}
|
|
@@ -7073,17 +7148,15 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7073
7148
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7074
7149
|
<div class="sp-modal-header">
|
|
7075
7150
|
<div class="sp-modal-title">
|
|
7076
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
7077
|
-
|
|
7078
|
-
</div>
|
|
7079
|
-
<button class="sp-close-btn" type="button" (click)="closeSendPreview()" aria-label="Close preview">
|
|
7151
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('messagingSendMessagePanel.textPreview') }}</div>
|
|
7152
|
+
<button class="sp-close-btn" type="button" (click)="closeSendPreview()" [attr.aria-label]="labels.t('messagingSendMessagePanel.closePreview')">
|
|
7080
7153
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
7081
7154
|
</button>
|
|
7082
7155
|
</div>
|
|
7083
7156
|
<div class="sp-text-meta">
|
|
7084
7157
|
<div class="sp-meta-row">
|
|
7085
|
-
<span class="sp-meta-label">
|
|
7086
|
-
<span class="sp-meta-value">@if (bulk()) { {{
|
|
7158
|
+
<span class="sp-meta-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
7159
|
+
<span class="sp-meta-value">@if (bulk()) { {{ labels.t(bulkRecipients()!.length === 1 ? 'messagingSendMessagePanel.recipientCount_one' : 'messagingSendMessagePanel.recipientCount_other', { count: bulkRecipients()!.length }) }} } @else { {{ contactName() }} {{ formatPhone(contactPhone()) }} }</span>
|
|
7087
7160
|
</div>
|
|
7088
7161
|
</div>
|
|
7089
7162
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7097,10 +7170,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7097
7170
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7098
7171
|
<div class="sp-modal-header">
|
|
7099
7172
|
<div class="sp-modal-title">
|
|
7100
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
7101
|
-
|
|
7102
|
-
</div>
|
|
7103
|
-
<button class="sp-close-btn" type="button" (click)="showQuickPreview = false; previewingTemplate = null" aria-label="Close preview">
|
|
7173
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('messagingSendMessagePanel.textPreview') }}</div>
|
|
7174
|
+
<button class="sp-close-btn" type="button" (click)="showQuickPreview = false; previewingTemplate = null" [attr.aria-label]="labels.t('messagingSendMessagePanel.closePreview')">
|
|
7104
7175
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
7105
7176
|
</button>
|
|
7106
7177
|
</div>
|
|
@@ -7441,25 +7512,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7441
7512
|
<!-- Missing phone guard -->
|
|
7442
7513
|
@if (!bulk() && !contactPhone()) {
|
|
7443
7514
|
<div class="sm-missing-banner">
|
|
7444
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
7445
|
-
No phone number on file for this contact.
|
|
7446
|
-
</div>
|
|
7515
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.noPhoneNumberOnFile') }}</div>
|
|
7447
7516
|
<ui-text-input
|
|
7448
|
-
label="
|
|
7517
|
+
[label]="labels.t('messagingSendMessagePanel.addPhoneNumber')"
|
|
7449
7518
|
type="tel"
|
|
7450
7519
|
[required]="true"
|
|
7451
7520
|
placeholder="(555) 000-0000"
|
|
7452
7521
|
[(ngModel)]="pendingPhone"
|
|
7453
7522
|
(ngModelChange)="notifyValid()"
|
|
7454
|
-
[error]="pendingPhone && !pendingPhoneValid ? '
|
|
7455
|
-
<ui-button variant="primary" [disabled]="!pendingPhoneValid || savingPhone()" [loading]="savingPhone()" (click)="savePhone()">
|
|
7456
|
-
Save & Continue
|
|
7457
|
-
</ui-button>
|
|
7523
|
+
[error]="pendingPhone && !pendingPhoneValid ? labels.t('validation.phone') : ''" />
|
|
7524
|
+
<ui-button variant="primary" [disabled]="!pendingPhoneValid || savingPhone()" [loading]="savingPhone()" (click)="savePhone()">{{ labels.t('messagingSendMessagePanel.saveContinue') }}</ui-button>
|
|
7458
7525
|
} @else {
|
|
7459
7526
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
7460
7527
|
@if (!bulk()) {
|
|
7461
7528
|
<div class="sm-group">
|
|
7462
|
-
<span class="sm-group-label">
|
|
7529
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
7463
7530
|
<div class="sm-to-card">
|
|
7464
7531
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
7465
7532
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
@@ -7470,23 +7537,23 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7470
7537
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
7471
7538
|
@if (showTemplates()) {
|
|
7472
7539
|
<div class="sm-mode-row">
|
|
7473
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
7540
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
7474
7541
|
</div>
|
|
7475
7542
|
}
|
|
7476
7543
|
|
|
7477
7544
|
@if (mode === 'compose') {
|
|
7478
7545
|
<div class="sm-field">
|
|
7479
7546
|
<ui-textarea-input
|
|
7480
|
-
label="
|
|
7547
|
+
[label]="labels.t('common.message')"
|
|
7481
7548
|
[required]="true"
|
|
7482
|
-
placeholder="
|
|
7549
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
7483
7550
|
[rows]="8"
|
|
7484
7551
|
[maxlength]="MAX_LENGTH"
|
|
7485
7552
|
[(ngModel)]="body"
|
|
7486
7553
|
[error]="composeTagError || videoLengthError"
|
|
7487
7554
|
(ngModelChange)="notifyValid()" />
|
|
7488
7555
|
<div class="sm-char-row">
|
|
7489
|
-
<span class="sm-hint">
|
|
7556
|
+
<span class="sm-hint">{{ labels.t('messagingSendMessagePanel.sentAsSmsKeepMessages') }}</span>
|
|
7490
7557
|
<span class="sm-char-count" [class.sm-char-warn]="body.length > MAX_LENGTH * 0.9">
|
|
7491
7558
|
{{ body.length }} / {{ MAX_LENGTH }}
|
|
7492
7559
|
</span>
|
|
@@ -7495,14 +7562,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7495
7562
|
|
|
7496
7563
|
@if (!hasDocuments && showAttachments()) {
|
|
7497
7564
|
<div class="sm-field">
|
|
7498
|
-
<label class="sm-field-label">
|
|
7565
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.addImageMediaMms') }}</label>
|
|
7499
7566
|
@if (mediaAttachment()) {
|
|
7500
7567
|
<div class="attach-chips">
|
|
7501
7568
|
<div class="attach-chip">
|
|
7502
7569
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
|
7503
7570
|
<span class="attach-name">{{ mediaAttachment()!.mediaFileName }}</span>
|
|
7504
7571
|
<span class="attach-size">{{ mediaAttachment()!.sizeLabel }}</span>
|
|
7505
|
-
<button class="attach-remove" type="button" (click)="removeMedia()" aria-label="
|
|
7572
|
+
<button class="attach-remove" type="button" (click)="removeMedia()" [attr.aria-label]="labels.t('messagingSendMessagePanel.removeAttachment')">×</button>
|
|
7506
7573
|
</div>
|
|
7507
7574
|
</div>
|
|
7508
7575
|
}
|
|
@@ -7510,10 +7577,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7510
7577
|
<input #smsFileInput type="file" accept="image/*,video/*,application/pdf" hidden (change)="onFileSelected($event)" />
|
|
7511
7578
|
<button type="button" class="attach-add-btn" [disabled]="mediaUploading()" (click)="smsFileInput.click()">
|
|
7512
7579
|
@if (mediaUploading()) {
|
|
7513
|
-
<span class="attach-spinner"></span>
|
|
7580
|
+
<span class="attach-spinner"></span> {{ labels.t('messagingSendText.uploading') }}
|
|
7514
7581
|
} @else {
|
|
7515
7582
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
|
7516
|
-
|
|
7583
|
+
{{ labels.t('messagingSendMessagePanel.attachImage') }}
|
|
7517
7584
|
}
|
|
7518
7585
|
</button>
|
|
7519
7586
|
}
|
|
@@ -7522,10 +7589,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7522
7589
|
}
|
|
7523
7590
|
|
|
7524
7591
|
@if (!hasDocuments && showScheduling()) {
|
|
7525
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
7592
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
7526
7593
|
@if (showSchedule) {
|
|
7527
7594
|
<ui-datetime-input
|
|
7528
|
-
label="
|
|
7595
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
7529
7596
|
[min]="minScheduleTime"
|
|
7530
7597
|
[(ngModel)]="scheduledAt"
|
|
7531
7598
|
(ngModelChange)="notifyValid()" />
|
|
@@ -7535,14 +7602,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7535
7602
|
@if (missingVars.length > 0) {
|
|
7536
7603
|
<div class="mv-section">
|
|
7537
7604
|
<p class="mv-hint">
|
|
7538
|
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
7539
|
-
This template has fields that need values before sending.
|
|
7540
|
-
</p>
|
|
7605
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>{{ labels.t('messagingSendMessagePanel.thisTemplateHasFieldsThat') }}</p>
|
|
7541
7606
|
@for (key of missingVars; track key) {
|
|
7542
7607
|
<div class="mv-row">
|
|
7543
7608
|
<div class="mv-input-wrap">
|
|
7544
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
7545
|
-
<button class="mv-apply-btn" type="button" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" aria-label="
|
|
7609
|
+
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="labels.t('messagingSendMessagePanel.enterValue', { name: formatVarLabel(key).toLowerCase() })" [(ngModel)]="pendingInputs[key]" (ngModelChange)="notifyValid()" (keydown.enter)="applyVar(key)" />
|
|
7610
|
+
<button class="mv-apply-btn" type="button" [disabled]="!(pendingInputs[key] || '').trim()" (click)="applyVar(key)" [attr.aria-label]="labels.t('messagingSendMessagePanel.applyValue')">
|
|
7546
7611
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
7547
7612
|
</button>
|
|
7548
7613
|
</div>
|
|
@@ -7553,20 +7618,16 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7553
7618
|
|
|
7554
7619
|
<div class="tpl-preview-header">
|
|
7555
7620
|
<button class="tpl-back-btn" type="button" (click)="clearTemplate()">
|
|
7556
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
|
7557
|
-
Back to templates
|
|
7558
|
-
</button>
|
|
7621
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>{{ labels.t('messagingSendMessagePanel.backToTemplates') }}</button>
|
|
7559
7622
|
<div class="tpl-view-toggle">
|
|
7560
|
-
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'preview'" [attr.aria-pressed]="previewFormat === 'preview'" type="button" (click)="setPreviewFormat('preview')">
|
|
7561
|
-
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'raw'" [attr.aria-pressed]="previewFormat === 'raw'" type="button" (click)="setPreviewFormat('raw')">
|
|
7623
|
+
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'preview'" [attr.aria-pressed]="previewFormat === 'preview'" type="button" (click)="setPreviewFormat('preview')">{{ labels.t('common.preview') }}</button>
|
|
7624
|
+
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'raw'" [attr.aria-pressed]="previewFormat === 'raw'" type="button" (click)="setPreviewFormat('raw')">{{ labels.t('messagingSendMessagePanel.raw') }}</button>
|
|
7562
7625
|
</div>
|
|
7563
7626
|
</div>
|
|
7564
7627
|
|
|
7565
7628
|
<div class="tpl-send-preview-row">
|
|
7566
7629
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
7567
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
7568
|
-
View Send Preview
|
|
7569
|
-
</ui-button>
|
|
7630
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>{{ labels.t('messagingSendMessagePanel.viewSendPreview') }}</ui-button>
|
|
7570
7631
|
</div>
|
|
7571
7632
|
|
|
7572
7633
|
@if (previewFormat === 'preview') {
|
|
@@ -7606,10 +7667,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7606
7667
|
<!-- One live region, at most ONE warning banner (every current non-blocking warning is a line in it). -->
|
|
7607
7668
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
7608
7669
|
@if (hasDocuments) {
|
|
7609
|
-
<p class="sm-docs-note">
|
|
7670
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.theDocumentsAreTextedAs') }}</p>
|
|
7610
7671
|
}
|
|
7611
7672
|
@if (warningLines.length > 0) {
|
|
7612
|
-
<ui-alert variant="warning" title="
|
|
7673
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
7613
7674
|
<ul class="sm-warn-list">
|
|
7614
7675
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
7615
7676
|
</ul>
|
|
@@ -7620,7 +7681,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7620
7681
|
|
|
7621
7682
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
7622
7683
|
@if (mode === 'compose' && showVideo()) {
|
|
7623
|
-
<ui-form-section label="
|
|
7684
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
7624
7685
|
@for (k of [videoPickerKey]; track k) {
|
|
7625
7686
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
7626
7687
|
}
|
|
@@ -7642,17 +7703,15 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7642
7703
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7643
7704
|
<div class="sp-modal-header">
|
|
7644
7705
|
<div class="sp-modal-title">
|
|
7645
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
7646
|
-
|
|
7647
|
-
</div>
|
|
7648
|
-
<button class="sp-close-btn" type="button" (click)="closeSendPreview()" aria-label="Close preview">
|
|
7706
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('messagingSendMessagePanel.textPreview') }}</div>
|
|
7707
|
+
<button class="sp-close-btn" type="button" (click)="closeSendPreview()" [attr.aria-label]="labels.t('messagingSendMessagePanel.closePreview')">
|
|
7649
7708
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
7650
7709
|
</button>
|
|
7651
7710
|
</div>
|
|
7652
7711
|
<div class="sp-text-meta">
|
|
7653
7712
|
<div class="sp-meta-row">
|
|
7654
|
-
<span class="sp-meta-label">
|
|
7655
|
-
<span class="sp-meta-value">@if (bulk()) { {{
|
|
7713
|
+
<span class="sp-meta-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
7714
|
+
<span class="sp-meta-value">@if (bulk()) { {{ labels.t(bulkRecipients()!.length === 1 ? 'messagingSendMessagePanel.recipientCount_one' : 'messagingSendMessagePanel.recipientCount_other', { count: bulkRecipients()!.length }) }} } @else { {{ contactName() }} {{ formatPhone(contactPhone()) }} }</span>
|
|
7656
7715
|
</div>
|
|
7657
7716
|
</div>
|
|
7658
7717
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7666,10 +7725,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7666
7725
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7667
7726
|
<div class="sp-modal-header">
|
|
7668
7727
|
<div class="sp-modal-title">
|
|
7669
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
7670
|
-
|
|
7671
|
-
</div>
|
|
7672
|
-
<button class="sp-close-btn" type="button" (click)="showQuickPreview = false; previewingTemplate = null" aria-label="Close preview">
|
|
7728
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('messagingSendMessagePanel.textPreview') }}</div>
|
|
7729
|
+
<button class="sp-close-btn" type="button" (click)="showQuickPreview = false; previewingTemplate = null" [attr.aria-label]="labels.t('messagingSendMessagePanel.closePreview')">
|
|
7673
7730
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
7674
7731
|
</button>
|
|
7675
7732
|
</div>
|
|
@@ -7912,13 +7969,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7912
7969
|
const BULK_MERGE_TAG_HINT = "Personal details such as {{first_name}} are filled in for each recipient when sent.";
|
|
7913
7970
|
const SKIPPED_NAMES_SHOWN = 5;
|
|
7914
7971
|
var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
7915
|
-
|
|
7916
|
-
return this.
|
|
7972
|
+
get BULK_MERGE_TAG_HINT() {
|
|
7973
|
+
return this.labels.t("messagingSendMessagePanel.bulkMergeTagHint");
|
|
7974
|
+
}
|
|
7975
|
+
skippedReason(count) {
|
|
7976
|
+
const one = count === 1;
|
|
7977
|
+
if (this.channel() === "email") return this.labels.t(one ? "messagingSendMessagePanel.reasonNoEmail_one" : "messagingSendMessagePanel.reasonNoEmail_other");
|
|
7978
|
+
return this.labels.t(one ? "messagingSendMessagePanel.reasonNoPhone_one" : "messagingSendMessagePanel.reasonNoPhone_other");
|
|
7917
7979
|
}
|
|
7918
7980
|
skippedNames() {
|
|
7919
|
-
const names = this.skippedRecipients().map((r) => r.name || "
|
|
7981
|
+
const names = this.skippedRecipients().map((r) => r.name || this.labels.t("messagingSendMessagePanel.unnamed"));
|
|
7920
7982
|
const shown = names.slice(0, SKIPPED_NAMES_SHOWN).join(", ");
|
|
7921
|
-
return names.length > SKIPPED_NAMES_SHOWN ?
|
|
7983
|
+
return names.length > SKIPPED_NAMES_SHOWN ? this.labels.t("messagingSendMessagePanel.skippedNameMore", {
|
|
7984
|
+
shown,
|
|
7985
|
+
count: names.length - SKIPPED_NAMES_SHOWN
|
|
7986
|
+
}) : shown;
|
|
7922
7987
|
}
|
|
7923
7988
|
bulkRecipientsFor(ch) {
|
|
7924
7989
|
if (!this.bulkMode()) return null;
|
|
@@ -7966,15 +8031,20 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7966
8031
|
this.jobOptions.set([]);
|
|
7967
8032
|
}
|
|
7968
8033
|
constructor() {
|
|
8034
|
+
this.labels = inject(UiLabelsService);
|
|
7969
8035
|
this.open = input(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
|
|
7970
8036
|
this.contact = input(null, ...ngDevMode ? [{ debugName: "contact" }] : /* istanbul ignore next */ []);
|
|
7971
8037
|
this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
7972
8038
|
this.recipients = input(null, ...ngDevMode ? [{ debugName: "recipients" }] : /* istanbul ignore next */ []);
|
|
7973
8039
|
this.initialChannel = input(null, ...ngDevMode ? [{ debugName: "initialChannel" }] : /* istanbul ignore next */ []);
|
|
7974
|
-
this.recipientNoun = input("
|
|
8040
|
+
this.recipientNoun = input("", ...ngDevMode ? [{ debugName: "recipientNoun" }] : /* istanbul ignore next */ []);
|
|
7975
8041
|
this.recipientNounSingular = input("", ...ngDevMode ? [{ debugName: "recipientNounSingular" }] : /* istanbul ignore next */ []);
|
|
7976
8042
|
this.textEnabled = input(false, ...ngDevMode ? [{ debugName: "textEnabled" }] : /* istanbul ignore next */ []);
|
|
7977
|
-
this.
|
|
8043
|
+
this.titleInput = input(null, {
|
|
8044
|
+
...ngDevMode ? { debugName: "titleInput" } : /* istanbul ignore next */ {},
|
|
8045
|
+
alias: "title"
|
|
8046
|
+
});
|
|
8047
|
+
this.title = computed(() => this.titleInput() ?? this.labels.t("messagingSendMessagePanel.title"), ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
|
|
7978
8048
|
this.defaultSubject = input("", ...ngDevMode ? [{ debugName: "defaultSubject" }] : /* istanbul ignore next */ []);
|
|
7979
8049
|
this.defaultBody = input("", ...ngDevMode ? [{ debugName: "defaultBody" }] : /* istanbul ignore next */ []);
|
|
7980
8050
|
this.defaultMessage = input("", ...ngDevMode ? [{ debugName: "defaultMessage" }] : /* istanbul ignore next */ []);
|
|
@@ -7982,7 +8052,11 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7982
8052
|
this.sendEmail = input(null, ...ngDevMode ? [{ debugName: "sendEmail" }] : /* istanbul ignore next */ []);
|
|
7983
8053
|
this.sendText = input(null, ...ngDevMode ? [{ debugName: "sendText" }] : /* istanbul ignore next */ []);
|
|
7984
8054
|
this.showReceiptOption = input(false, ...ngDevMode ? [{ debugName: "showReceiptOption" }] : /* istanbul ignore next */ []);
|
|
7985
|
-
this.
|
|
8055
|
+
this.receiptLabelInput = input(null, {
|
|
8056
|
+
...ngDevMode ? { debugName: "receiptLabelInput" } : /* istanbul ignore next */ {},
|
|
8057
|
+
alias: "receiptLabel"
|
|
8058
|
+
});
|
|
8059
|
+
this.receiptLabel = computed(() => this.receiptLabelInput() ?? this.labels.t("messagingSendMessagePanel.receiptLabel"), ...ngDevMode ? [{ debugName: "receiptLabel" }] : /* istanbul ignore next */ []);
|
|
7986
8060
|
this.receiptDefault = input(false, ...ngDevMode ? [{ debugName: "receiptDefault" }] : /* istanbul ignore next */ []);
|
|
7987
8061
|
this.documents = input(false, ...ngDevMode ? [{ debugName: "documents" }] : /* istanbul ignore next */ []);
|
|
7988
8062
|
this.documentsEnabled = input(true, ...ngDevMode ? [{ debugName: "documentsEnabled" }] : /* istanbul ignore next */ []);
|
|
@@ -7996,8 +8070,6 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7996
8070
|
this.showTemplates = input(true, ...ngDevMode ? [{ debugName: "showTemplates" }] : /* istanbul ignore next */ []);
|
|
7997
8071
|
this.showVideo = input(true, ...ngDevMode ? [{ debugName: "showVideo" }] : /* istanbul ignore next */ []);
|
|
7998
8072
|
this.inApp = computed(() => this.recipientMode() === "in-app" && !this.bulkMode(), ...ngDevMode ? [{ debugName: "inApp" }] : /* istanbul ignore next */ []);
|
|
7999
|
-
this.BULK_NO_SEND_MESSAGE = BULK_NO_SEND_MESSAGE;
|
|
8000
|
-
this.BULK_MERGE_TAG_HINT = BULK_MERGE_TAG_HINT;
|
|
8001
8073
|
this.attachmentsAndScheduling = input(true, ...ngDevMode ? [{ debugName: "attachmentsAndScheduling" }] : /* istanbul ignore next */ []);
|
|
8002
8074
|
this.allowAttachments = input(null, ...ngDevMode ? [{ debugName: "allowAttachments" }] : /* istanbul ignore next */ []);
|
|
8003
8075
|
this.allowScheduling = input(null, ...ngDevMode ? [{ debugName: "allowScheduling" }] : /* istanbul ignore next */ []);
|
|
@@ -8041,31 +8113,56 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8041
8113
|
this.submitSnapshot = null;
|
|
8042
8114
|
this.recipientWord = computed(() => {
|
|
8043
8115
|
const n = this.bulkList().length;
|
|
8044
|
-
const plural = this.recipientNoun() || "
|
|
8116
|
+
const plural = this.recipientNoun() || this.labels.t("messagingSendMessagePanel.recipientsWord");
|
|
8045
8117
|
if (n !== 1) return plural;
|
|
8046
8118
|
return this.recipientNounSingular() || (plural.endsWith("s") ? plural.slice(0, -1) : plural);
|
|
8047
8119
|
}, ...ngDevMode ? [{ debugName: "recipientWord" }] : /* istanbul ignore next */ []);
|
|
8048
8120
|
this.skippedText = computed(() => {
|
|
8049
8121
|
const n = this.skippedRecipients().length;
|
|
8050
8122
|
if (n === 0) return "";
|
|
8051
|
-
const what = this.channel() === "email" ? "
|
|
8052
|
-
return
|
|
8123
|
+
const what = this.channel() === "email" ? this.labels.t("messagingSendMessagePanel.whatEmail") : this.labels.t("messagingSendMessagePanel.whatText");
|
|
8124
|
+
return this.labels.t(n === 1 ? "messagingSendMessagePanel.skippedText_one" : "messagingSendMessagePanel.skippedText_other", {
|
|
8125
|
+
count: n,
|
|
8126
|
+
reason: this.skippedReason(n),
|
|
8127
|
+
names: this.skippedNames(),
|
|
8128
|
+
what
|
|
8129
|
+
});
|
|
8053
8130
|
}, ...ngDevMode ? [{ debugName: "skippedText" }] : /* istanbul ignore next */ []);
|
|
8054
8131
|
this.noneEligibleText = computed(() => {
|
|
8055
|
-
|
|
8132
|
+
const n = this.bulkList().length;
|
|
8133
|
+
const what = this.channel() === "email" ? this.labels.t("messagingSendMessagePanel.whatEmail") : this.labels.t("messagingSendMessagePanel.whatTextMessage");
|
|
8134
|
+
return this.labels.t(n === 1 ? "messagingSendMessagePanel.noneEligible_one" : "messagingSendMessagePanel.noneEligible_other", {
|
|
8135
|
+
count: n,
|
|
8136
|
+
what,
|
|
8137
|
+
reason: this.skippedReason(n)
|
|
8138
|
+
});
|
|
8056
8139
|
}, ...ngDevMode ? [{ debugName: "noneEligibleText" }] : /* istanbul ignore next */ []);
|
|
8057
8140
|
this.bulkAnnouncement = computed(() => {
|
|
8058
8141
|
if (!this.bulkMode()) return "";
|
|
8059
8142
|
const n = this.bulkList().length;
|
|
8060
8143
|
const ok = this.activeRecipients().length;
|
|
8061
|
-
const ch = this.channel() === "email" ? "
|
|
8062
|
-
if (ok === 0) return
|
|
8144
|
+
const ch = this.channel() === "email" ? this.labels.t("messagingSendMessagePanel.whatEmail") : this.labels.t("messagingSendMessagePanel.whatText");
|
|
8145
|
+
if (ok === 0) return this.labels.t(n === 1 ? "messagingSendMessagePanel.announceNone_one" : "messagingSendMessagePanel.announceNone_other", {
|
|
8146
|
+
count: n,
|
|
8147
|
+
word: this.recipientWord(),
|
|
8148
|
+
channel: ch
|
|
8149
|
+
});
|
|
8063
8150
|
const skipped = this.skippedRecipients().length;
|
|
8064
|
-
|
|
8151
|
+
const someKey = n === 1 ? "messagingSendMessagePanel.announceSome_one" : ok === 1 ? "messagingSendMessagePanel.announceSome_okOne" : "messagingSendMessagePanel.announceSome_other";
|
|
8152
|
+
return this.labels.t(someKey, {
|
|
8153
|
+
count: n,
|
|
8154
|
+
word: this.recipientWord(),
|
|
8155
|
+
ok,
|
|
8156
|
+
channel: ch
|
|
8157
|
+
}) + (skipped ? " " + this.labels.t(skipped === 1 ? "messagingSendMessagePanel.announceSkipped_one" : "messagingSendMessagePanel.announceSkipped_other", { count: skipped }) : "");
|
|
8065
8158
|
}, ...ngDevMode ? [{ debugName: "bulkAnnouncement" }] : /* istanbul ignore next */ []);
|
|
8066
8159
|
this.lastBulkResult = void 0;
|
|
8067
8160
|
this.showJobPicker = input(false, ...ngDevMode ? [{ debugName: "showJobPicker" }] : /* istanbul ignore next */ []);
|
|
8068
|
-
this.
|
|
8161
|
+
this.jobLabelInput = input(null, {
|
|
8162
|
+
...ngDevMode ? { debugName: "jobLabelInput" } : /* istanbul ignore next */ {},
|
|
8163
|
+
alias: "jobLabel"
|
|
8164
|
+
});
|
|
8165
|
+
this.jobLabel = computed(() => this.jobLabelInput() ?? this.labels.t("messagingSendMessagePanel.jobLabel"), ...ngDevMode ? [{ debugName: "jobLabel" }] : /* istanbul ignore next */ []);
|
|
8069
8166
|
this.jobHint = input("", ...ngDevMode ? [{ debugName: "jobHint" }] : /* istanbul ignore next */ []);
|
|
8070
8167
|
this.jobSearch = input(null, ...ngDevMode ? [{ debugName: "jobSearch" }] : /* istanbul ignore next */ []);
|
|
8071
8168
|
this.jobSelected = output();
|
|
@@ -8097,10 +8194,10 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8097
8194
|
if (!c || this.inApp()) return [];
|
|
8098
8195
|
const notices = [];
|
|
8099
8196
|
const hasEmail = !!c.email, hasPhone = !!c.phone;
|
|
8100
|
-
if (!this.textEnabled()) notices.push(
|
|
8101
|
-
else if (!c.smsOptedIn) notices.push(
|
|
8102
|
-
else if (!hasPhone) notices.push(
|
|
8103
|
-
if (!hasEmail && !hasPhone) notices.push(
|
|
8197
|
+
if (!this.textEnabled()) notices.push(this.labels.t("messagingSendMessagePanel.noticeTextDisabled"));
|
|
8198
|
+
else if (!c.smsOptedIn) notices.push(this.labels.t("messagingSendMessagePanel.noticeNoOptIn", { name: c.name }) + (!hasEmail && hasPhone ? " " + this.labels.t("messagingSendMessagePanel.noticeAddEmailBelow") : ""));
|
|
8199
|
+
else if (!hasPhone) notices.push(this.labels.t("messagingSendMessagePanel.noticeNoPhone", { name: c.name }));
|
|
8200
|
+
if (!hasEmail && !hasPhone) notices.push(this.labels.t("messagingSendMessagePanel.noticeNoContact", { name: c.name }));
|
|
8104
8201
|
return notices;
|
|
8105
8202
|
}, ...ngDevMode ? [{ debugName: "contactNotices" }] : /* istanbul ignore next */ []);
|
|
8106
8203
|
this.channel = signal("email", ...ngDevMode ? [{ debugName: "channel" }] : /* istanbul ignore next */ []);
|
|
@@ -8300,8 +8397,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8300
8397
|
isRequired: false,
|
|
8301
8398
|
transformFunction: null
|
|
8302
8399
|
},
|
|
8303
|
-
|
|
8304
|
-
classPropertyName: "
|
|
8400
|
+
titleInput: {
|
|
8401
|
+
classPropertyName: "titleInput",
|
|
8305
8402
|
publicName: "title",
|
|
8306
8403
|
isSignal: true,
|
|
8307
8404
|
isRequired: false,
|
|
@@ -8356,8 +8453,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8356
8453
|
isRequired: false,
|
|
8357
8454
|
transformFunction: null
|
|
8358
8455
|
},
|
|
8359
|
-
|
|
8360
|
-
classPropertyName: "
|
|
8456
|
+
receiptLabelInput: {
|
|
8457
|
+
classPropertyName: "receiptLabelInput",
|
|
8361
8458
|
publicName: "receiptLabel",
|
|
8362
8459
|
isSignal: true,
|
|
8363
8460
|
isRequired: false,
|
|
@@ -8580,8 +8677,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8580
8677
|
isRequired: false,
|
|
8581
8678
|
transformFunction: null
|
|
8582
8679
|
},
|
|
8583
|
-
|
|
8584
|
-
classPropertyName: "
|
|
8680
|
+
jobLabelInput: {
|
|
8681
|
+
classPropertyName: "jobLabelInput",
|
|
8585
8682
|
publicName: "jobLabel",
|
|
8586
8683
|
isSignal: true,
|
|
8587
8684
|
isRequired: false,
|
|
@@ -8641,8 +8738,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8641
8738
|
[open]="open()"
|
|
8642
8739
|
[title]="title()"
|
|
8643
8740
|
[wide]="wide()"
|
|
8644
|
-
cancelLabel="
|
|
8645
|
-
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? '
|
|
8741
|
+
[cancelLabel]="labels.t('common.cancel')"
|
|
8742
|
+
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? labels.t('messagingSendMessagePanel.sendMessage') : channel() === 'email' ? labels.t('messagingSendMessagePanel.sendEmail') : labels.t('messagingSendMessagePanel.sendText'))) : ''"
|
|
8646
8743
|
primaryVariant="warning"
|
|
8647
8744
|
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
8648
8745
|
(closed)="onClose()"
|
|
@@ -8659,25 +8756,25 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8659
8756
|
@if (!loading() && !hasTarget() && !inApp()) {
|
|
8660
8757
|
<div class="msg-step">
|
|
8661
8758
|
<span class="msg-step-badge">1</span>
|
|
8662
|
-
<span class="msg-step-text">
|
|
8759
|
+
<span class="msg-step-text">{{ labels.t('messagingSendMessagePanel.whoWouldYouLikeTo') }}</span>
|
|
8663
8760
|
</div>
|
|
8664
8761
|
<ui-contact-picker
|
|
8665
|
-
placeholder="
|
|
8762
|
+
[placeholder]="labels.t('messagingSendMessagePanel.searchByContactName')"
|
|
8666
8763
|
(contactSelected)="onContactSelected($event)" />
|
|
8667
8764
|
}
|
|
8668
8765
|
|
|
8669
8766
|
@if (!loading() && hasTarget()) {
|
|
8670
8767
|
@if (bulkMode()) {
|
|
8671
|
-
<div class="msg-bulk" role="group" aria-label="
|
|
8672
|
-
<p class="msg-bulk-to" data-testid="bulk-to">
|
|
8768
|
+
<div class="msg-bulk" role="group" [attr.aria-label]="labels.t('messagingSendMessagePanel.recipients')" data-testid="bulk-summary">
|
|
8769
|
+
<p class="msg-bulk-to" data-testid="bulk-to">{{ labels.t('messagingSendMessagePanel.toLabel') }} {{ bulkList().length }} {{ recipientWord() }}</p>
|
|
8673
8770
|
<div class="msg-bulk-counts">
|
|
8674
|
-
<ui-badge [label]="emailRecipients().length
|
|
8771
|
+
<ui-badge [label]="labels.t(emailRecipients().length === 1 ? 'messagingSendMessagePanel.canReceiveEmail_one' : 'messagingSendMessagePanel.canReceiveEmail_other', { count: emailRecipients().length })" [variant]="emailRecipients().length ? 'blue' : 'gray'" />
|
|
8675
8772
|
@if (textEnabled()) {
|
|
8676
|
-
<ui-badge [label]="textRecipients().length
|
|
8773
|
+
<ui-badge [label]="labels.t(textRecipients().length === 1 ? 'messagingSendMessagePanel.canReceiveText_one' : 'messagingSendMessagePanel.canReceiveText_other', { count: textRecipients().length })" [variant]="textRecipients().length ? 'blue' : 'gray'" />
|
|
8677
8774
|
}
|
|
8678
8775
|
</div>
|
|
8679
8776
|
@if (!textEnabled()) {
|
|
8680
|
-
<ui-hint>
|
|
8777
|
+
<ui-hint>{{ labels.t('messagingSendMessagePanel.textMessagingIsNotEnabled') }}</ui-hint>
|
|
8681
8778
|
}
|
|
8682
8779
|
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
8683
8780
|
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
@@ -8687,7 +8784,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8687
8784
|
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
8688
8785
|
}
|
|
8689
8786
|
@if (bulkMissingSend()) {
|
|
8690
|
-
<ui-alert variant="danger" data-testid="bulk-no-send">{{
|
|
8787
|
+
<ui-alert variant="danger" data-testid="bulk-no-send">{{ labels.t('messagingSendMessagePanel.bulkNoSend') }}</ui-alert>
|
|
8691
8788
|
}
|
|
8692
8789
|
@if (!bulkNoneEligible()) {
|
|
8693
8790
|
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
@@ -8697,23 +8794,19 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8697
8794
|
|
|
8698
8795
|
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
8699
8796
|
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
8700
|
-
<label class="form-label msg-via-label">
|
|
8797
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
8701
8798
|
@if (sending()) {
|
|
8702
8799
|
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
8703
8800
|
<div class="msg-via-tabs">
|
|
8704
|
-
<ui-badge [label]="channel() === 'email' ? '
|
|
8705
|
-
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">
|
|
8801
|
+
<ui-badge [label]="channel() === 'email' ? labels.t('common.email') : labels.t('common.text')" variant="blue" />
|
|
8802
|
+
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">{{ labels.t('messagingSendMessagePanel.channelLockedWhileSending') }}</span>
|
|
8706
8803
|
</div>
|
|
8707
8804
|
} @else {
|
|
8708
8805
|
<div class="msg-via-tabs">
|
|
8709
8806
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
8710
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
|
8711
|
-
Email
|
|
8712
|
-
</ui-toggle-badge>
|
|
8807
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>{{ labels.t('common.email') }}</ui-toggle-badge>
|
|
8713
8808
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
8714
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
8715
|
-
Text
|
|
8716
|
-
</ui-toggle-badge>
|
|
8809
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('common.text') }}</ui-toggle-badge>
|
|
8717
8810
|
</div>
|
|
8718
8811
|
}
|
|
8719
8812
|
</div>
|
|
@@ -8721,16 +8814,12 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8721
8814
|
|
|
8722
8815
|
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
8723
8816
|
<div class="msg-channel-row">
|
|
8724
|
-
<label class="form-label msg-via-label">
|
|
8817
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
8725
8818
|
<div class="msg-via-tabs">
|
|
8726
8819
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
8727
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
|
8728
|
-
Email
|
|
8729
|
-
</ui-toggle-badge>
|
|
8820
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>{{ labels.t('common.email') }}</ui-toggle-badge>
|
|
8730
8821
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
8731
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
8732
|
-
Text
|
|
8733
|
-
</ui-toggle-badge>
|
|
8822
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('common.text') }}</ui-toggle-badge>
|
|
8734
8823
|
</div>
|
|
8735
8824
|
</div>
|
|
8736
8825
|
}
|
|
@@ -8747,8 +8836,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8747
8836
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8748
8837
|
<div class="msg-job">
|
|
8749
8838
|
<ui-combobox
|
|
8750
|
-
[label]="jobLabel()" placeholder="
|
|
8751
|
-
[options]="jobOptions()" [loading]="jobLoading()" noResultsText="
|
|
8839
|
+
[label]="jobLabel()" [placeholder]="labels.t('messagingSendMessagePanel.searchByJobName')" [hint]="jobHint()"
|
|
8840
|
+
[options]="jobOptions()" [loading]="jobLoading()" [noResultsText]="labels.t('messagingSendMessagePanel.noJobsFound')" [minChars]="2" [debounce]="300"
|
|
8752
8841
|
[value]="jobValue()"
|
|
8753
8842
|
(searchChange)="jobSearch$.next($event)" (valueChange)="onJobPick($event)" />
|
|
8754
8843
|
</div>
|
|
@@ -9117,8 +9206,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9117
9206
|
[open]="open()"
|
|
9118
9207
|
[title]="title()"
|
|
9119
9208
|
[wide]="wide()"
|
|
9120
|
-
cancelLabel="
|
|
9121
|
-
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? '
|
|
9209
|
+
[cancelLabel]="labels.t('common.cancel')"
|
|
9210
|
+
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? labels.t('messagingSendMessagePanel.sendMessage') : channel() === 'email' ? labels.t('messagingSendMessagePanel.sendEmail') : labels.t('messagingSendMessagePanel.sendText'))) : ''"
|
|
9122
9211
|
primaryVariant="warning"
|
|
9123
9212
|
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
9124
9213
|
(closed)="onClose()"
|
|
@@ -9135,25 +9224,25 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9135
9224
|
@if (!loading() && !hasTarget() && !inApp()) {
|
|
9136
9225
|
<div class="msg-step">
|
|
9137
9226
|
<span class="msg-step-badge">1</span>
|
|
9138
|
-
<span class="msg-step-text">
|
|
9227
|
+
<span class="msg-step-text">{{ labels.t('messagingSendMessagePanel.whoWouldYouLikeTo') }}</span>
|
|
9139
9228
|
</div>
|
|
9140
9229
|
<ui-contact-picker
|
|
9141
|
-
placeholder="
|
|
9230
|
+
[placeholder]="labels.t('messagingSendMessagePanel.searchByContactName')"
|
|
9142
9231
|
(contactSelected)="onContactSelected($event)" />
|
|
9143
9232
|
}
|
|
9144
9233
|
|
|
9145
9234
|
@if (!loading() && hasTarget()) {
|
|
9146
9235
|
@if (bulkMode()) {
|
|
9147
|
-
<div class="msg-bulk" role="group" aria-label="
|
|
9148
|
-
<p class="msg-bulk-to" data-testid="bulk-to">
|
|
9236
|
+
<div class="msg-bulk" role="group" [attr.aria-label]="labels.t('messagingSendMessagePanel.recipients')" data-testid="bulk-summary">
|
|
9237
|
+
<p class="msg-bulk-to" data-testid="bulk-to">{{ labels.t('messagingSendMessagePanel.toLabel') }} {{ bulkList().length }} {{ recipientWord() }}</p>
|
|
9149
9238
|
<div class="msg-bulk-counts">
|
|
9150
|
-
<ui-badge [label]="emailRecipients().length
|
|
9239
|
+
<ui-badge [label]="labels.t(emailRecipients().length === 1 ? 'messagingSendMessagePanel.canReceiveEmail_one' : 'messagingSendMessagePanel.canReceiveEmail_other', { count: emailRecipients().length })" [variant]="emailRecipients().length ? 'blue' : 'gray'" />
|
|
9151
9240
|
@if (textEnabled()) {
|
|
9152
|
-
<ui-badge [label]="textRecipients().length
|
|
9241
|
+
<ui-badge [label]="labels.t(textRecipients().length === 1 ? 'messagingSendMessagePanel.canReceiveText_one' : 'messagingSendMessagePanel.canReceiveText_other', { count: textRecipients().length })" [variant]="textRecipients().length ? 'blue' : 'gray'" />
|
|
9153
9242
|
}
|
|
9154
9243
|
</div>
|
|
9155
9244
|
@if (!textEnabled()) {
|
|
9156
|
-
<ui-hint>
|
|
9245
|
+
<ui-hint>{{ labels.t('messagingSendMessagePanel.textMessagingIsNotEnabled') }}</ui-hint>
|
|
9157
9246
|
}
|
|
9158
9247
|
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
9159
9248
|
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
@@ -9163,7 +9252,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9163
9252
|
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
9164
9253
|
}
|
|
9165
9254
|
@if (bulkMissingSend()) {
|
|
9166
|
-
<ui-alert variant="danger" data-testid="bulk-no-send">{{
|
|
9255
|
+
<ui-alert variant="danger" data-testid="bulk-no-send">{{ labels.t('messagingSendMessagePanel.bulkNoSend') }}</ui-alert>
|
|
9167
9256
|
}
|
|
9168
9257
|
@if (!bulkNoneEligible()) {
|
|
9169
9258
|
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
@@ -9173,23 +9262,19 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9173
9262
|
|
|
9174
9263
|
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
9175
9264
|
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
9176
|
-
<label class="form-label msg-via-label">
|
|
9265
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
9177
9266
|
@if (sending()) {
|
|
9178
9267
|
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
9179
9268
|
<div class="msg-via-tabs">
|
|
9180
|
-
<ui-badge [label]="channel() === 'email' ? '
|
|
9181
|
-
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">
|
|
9269
|
+
<ui-badge [label]="channel() === 'email' ? labels.t('common.email') : labels.t('common.text')" variant="blue" />
|
|
9270
|
+
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">{{ labels.t('messagingSendMessagePanel.channelLockedWhileSending') }}</span>
|
|
9182
9271
|
</div>
|
|
9183
9272
|
} @else {
|
|
9184
9273
|
<div class="msg-via-tabs">
|
|
9185
9274
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
9186
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
|
9187
|
-
Email
|
|
9188
|
-
</ui-toggle-badge>
|
|
9275
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>{{ labels.t('common.email') }}</ui-toggle-badge>
|
|
9189
9276
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
9190
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
9191
|
-
Text
|
|
9192
|
-
</ui-toggle-badge>
|
|
9277
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('common.text') }}</ui-toggle-badge>
|
|
9193
9278
|
</div>
|
|
9194
9279
|
}
|
|
9195
9280
|
</div>
|
|
@@ -9197,16 +9282,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9197
9282
|
|
|
9198
9283
|
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
9199
9284
|
<div class="msg-channel-row">
|
|
9200
|
-
<label class="form-label msg-via-label">
|
|
9285
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
9201
9286
|
<div class="msg-via-tabs">
|
|
9202
9287
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
9203
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
|
|
9204
|
-
Email
|
|
9205
|
-
</ui-toggle-badge>
|
|
9288
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>{{ labels.t('common.email') }}</ui-toggle-badge>
|
|
9206
9289
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
9207
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
9208
|
-
Text
|
|
9209
|
-
</ui-toggle-badge>
|
|
9290
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>{{ labels.t('common.text') }}</ui-toggle-badge>
|
|
9210
9291
|
</div>
|
|
9211
9292
|
</div>
|
|
9212
9293
|
}
|
|
@@ -9223,8 +9304,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9223
9304
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
9224
9305
|
<div class="msg-job">
|
|
9225
9306
|
<ui-combobox
|
|
9226
|
-
[label]="jobLabel()" placeholder="
|
|
9227
|
-
[options]="jobOptions()" [loading]="jobLoading()" noResultsText="
|
|
9307
|
+
[label]="jobLabel()" [placeholder]="labels.t('messagingSendMessagePanel.searchByJobName')" [hint]="jobHint()"
|
|
9308
|
+
[options]="jobOptions()" [loading]="jobLoading()" [noResultsText]="labels.t('messagingSendMessagePanel.noJobsFound')" [minChars]="2" [debounce]="300"
|
|
9228
9309
|
[value]="jobValue()"
|
|
9229
9310
|
(searchChange)="jobSearch$.next($event)" (valueChange)="onJobPick($event)" />
|
|
9230
9311
|
</div>
|
|
@@ -9402,7 +9483,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9402
9483
|
required: false
|
|
9403
9484
|
}]
|
|
9404
9485
|
}],
|
|
9405
|
-
|
|
9486
|
+
titleInput: [{
|
|
9406
9487
|
type: i0.Input,
|
|
9407
9488
|
args: [{
|
|
9408
9489
|
isSignal: true,
|
|
@@ -9466,7 +9547,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9466
9547
|
required: false
|
|
9467
9548
|
}]
|
|
9468
9549
|
}],
|
|
9469
|
-
|
|
9550
|
+
receiptLabelInput: [{
|
|
9470
9551
|
type: i0.Input,
|
|
9471
9552
|
args: [{
|
|
9472
9553
|
isSignal: true,
|
|
@@ -9722,7 +9803,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9722
9803
|
required: false
|
|
9723
9804
|
}]
|
|
9724
9805
|
}],
|
|
9725
|
-
|
|
9806
|
+
jobLabelInput: [{
|
|
9726
9807
|
type: i0.Input,
|
|
9727
9808
|
args: [{
|
|
9728
9809
|
isSignal: true,
|