@forgeroute/ui 0.4.77 → 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 +629 -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 +14021 -5678
- 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 +3299 -338
|
@@ -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
|
`,
|
|
@@ -2025,6 +2065,7 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
2025
2065
|
"legend",
|
|
2026
2066
|
"orientation",
|
|
2027
2067
|
"values",
|
|
2068
|
+
"labelLinks",
|
|
2028
2069
|
"description",
|
|
2029
2070
|
"indent",
|
|
2030
2071
|
"required",
|
|
@@ -2156,35 +2197,34 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2156
2197
|
<div class="dso" role="group" [attr.aria-label]="label()">
|
|
2157
2198
|
@if (available()) {
|
|
2158
2199
|
@if (locked()) {
|
|
2159
|
-
<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>
|
|
2160
2201
|
@if (envelopeStatus() === 'loading') {
|
|
2161
2202
|
<div role="status"><ui-hint data-testid="envelope-loading">{{ envelopeReadMessage() }}</ui-hint></div>
|
|
2162
2203
|
} @else if (envelopeStatus() === 'error') {
|
|
2163
2204
|
<div class="dso-retry">
|
|
2164
2205
|
<ui-error errorId="dso-envelope-error" [message]="envelopeReadMessage()" />
|
|
2165
|
-
<ui-button variant="secondary" size="sm" (click)="retryEnvelope()">
|
|
2206
|
+
<ui-button variant="secondary" size="sm" (click)="retryEnvelope()">{{ labels.t('common.retry') }}</ui-button>
|
|
2166
2207
|
</div>
|
|
2167
2208
|
}
|
|
2168
2209
|
} @else {
|
|
2169
2210
|
<ui-combobox
|
|
2170
2211
|
[label]="label()"
|
|
2171
2212
|
[required]="required()"
|
|
2172
|
-
placeholder="
|
|
2213
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchYourDocumentsByName')"
|
|
2173
2214
|
[options]="options()"
|
|
2174
2215
|
[loading]="loading()"
|
|
2175
2216
|
[minChars]="2"
|
|
2176
|
-
[noResultsText]="searchFailed() ? '
|
|
2177
|
-
[hint]="channel() === 'text' ? '
|
|
2217
|
+
[noResultsText]="searchFailed() ? labels.t('messagingDocumentSendOptions.searchFailed') : labels.t('messagingDocumentSendOptions.noMatchingDocuments')"
|
|
2218
|
+
[hint]="channel() === 'text' ? labels.t('messagingDocumentSendOptions.textedAsLink') : ''"
|
|
2178
2219
|
[error]="searchFailed() ? searchFailedMessage : ''"
|
|
2179
2220
|
[showErrors]="searchFailed()"
|
|
2180
2221
|
(searchChange)="search$.next($event)"
|
|
2181
2222
|
(valueChange)="onPick($event)" />
|
|
2182
|
-
<ui-error errorId="dso-search-error" [message]="searchFailed() ? 'Couldn\\'t search your documents. Check your connection and try again.' : ''" />
|
|
2183
2223
|
}
|
|
2184
2224
|
|
|
2185
2225
|
@if (selected().length > 0) {
|
|
2186
2226
|
<!-- One row per document: the chip (or the plain title when the list is fixed) and, beside it, its small Preview button. -->
|
|
2187
|
-
<div class="dso-docs" role="group" aria-label="
|
|
2227
|
+
<div class="dso-docs" role="group" [attr.aria-label]="labels.t('messagingDocumentSendOptions.chosenDocuments')">
|
|
2188
2228
|
@for (d of selected(); track d.id) {
|
|
2189
2229
|
<div class="dso-doc">
|
|
2190
2230
|
@if (locked()) {
|
|
@@ -2196,8 +2236,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2196
2236
|
@if (documentPreview()) {
|
|
2197
2237
|
<ui-button
|
|
2198
2238
|
variant="secondary" size="sm"
|
|
2199
|
-
[ariaLabel]="selected().length === 1 ? undefined : '
|
|
2200
|
-
(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>
|
|
2201
2241
|
}
|
|
2202
2242
|
</div>
|
|
2203
2243
|
}
|
|
@@ -2212,30 +2252,30 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2212
2252
|
} @else if (signerInfo()?.status === 'error') {
|
|
2213
2253
|
<div class="dso-retry">
|
|
2214
2254
|
<ui-error errorId="dso-roles-error" [message]="signerReadMessage()" />
|
|
2215
|
-
<ui-button variant="secondary" size="sm" (click)="retryRoles()">
|
|
2255
|
+
<ui-button variant="secondary" size="sm" (click)="retryRoles()">{{ labels.t('common.retry') }}</ui-button>
|
|
2216
2256
|
</div>
|
|
2217
2257
|
}
|
|
2218
2258
|
|
|
2219
2259
|
@if (providerChoiceShown()) {
|
|
2220
2260
|
<ui-radio-group
|
|
2221
|
-
label="
|
|
2261
|
+
[label]="labels.t('messagingDocumentSendOptions.signatureProvider')"
|
|
2222
2262
|
orientation="horizontal"
|
|
2223
|
-
[options]="providerOptions"
|
|
2263
|
+
[options]="providerOptions()"
|
|
2224
2264
|
[ngModel]="provider()"
|
|
2225
2265
|
(ngModelChange)="setProvider($event)" />
|
|
2226
2266
|
}
|
|
2227
2267
|
|
|
2228
2268
|
@if (provider() === 'DOCUSIGN') {
|
|
2229
|
-
<ui-hint>
|
|
2269
|
+
<ui-hint>{{ labels.t('messagingDocumentSendOptions.docusignEmailsTheDocumentTo') }}</ui-hint>
|
|
2230
2270
|
@if (showCountersign()) {
|
|
2231
2271
|
<ui-checkbox
|
|
2232
|
-
label="
|
|
2272
|
+
[label]="labels.t('messagingDocumentSendOptions.requireMyCountersignatureAfterClient')"
|
|
2233
2273
|
[ngModel]="countersignChoice()"
|
|
2234
2274
|
(ngModelChange)="countersignChoice.set(!!$event)" />
|
|
2235
2275
|
}
|
|
2236
2276
|
} @else if (channel() === 'email' && selected().length > 0 && purposeOptions().length > 1) {
|
|
2237
2277
|
<ui-select
|
|
2238
|
-
label="
|
|
2278
|
+
[label]="labels.t('messagingDocumentSendOptions.whatShouldTheRecipientDo')"
|
|
2239
2279
|
[options]="purposeOptions()"
|
|
2240
2280
|
[ngModel]="purpose()"
|
|
2241
2281
|
(ngModelChange)="setPurpose($event)" />
|
|
@@ -2251,21 +2291,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2251
2291
|
<ui-button
|
|
2252
2292
|
variant="ghost" size="xs"
|
|
2253
2293
|
[ariaExpanded]="signingExpanded()"
|
|
2254
|
-
[ariaLabel]="signingExpanded() ? '
|
|
2255
|
-
(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>
|
|
2256
2296
|
</div>
|
|
2257
2297
|
@if (signingExpanded()) {
|
|
2258
2298
|
<ui-form-section>
|
|
2259
2299
|
<!-- One column: three labelled number fields do not fit side by side in a 480px panel or on a phone. -->
|
|
2260
2300
|
<ui-form-row [cols]="1">
|
|
2261
2301
|
<ui-text-input
|
|
2262
|
-
label="
|
|
2302
|
+
[label]="labels.t('messagingDocumentSendOptions.expiryDays')" type="number" [required]="true" [min]="1" [max]="90" [maxDecimals]="0"
|
|
2263
2303
|
[showErrors]="showErrors()" [ngModel]="expiryDays()" (ngModelChange)="expiryDays.set(asText($event))" />
|
|
2264
2304
|
<ui-text-input
|
|
2265
|
-
label="
|
|
2305
|
+
[label]="labels.t('messagingDocumentSendOptions.reminderIntervalDays')" type="number" [required]="true" [min]="1" [max]="30" [maxDecimals]="0"
|
|
2266
2306
|
[showErrors]="showErrors()" [ngModel]="reminderIntervalDays()" (ngModelChange)="reminderIntervalDays.set(asText($event))" />
|
|
2267
2307
|
<ui-text-input
|
|
2268
|
-
label="
|
|
2308
|
+
[label]="labels.t('messagingDocumentSendOptions.maxReminders')" type="number" [required]="true" [min]="0" [max]="10" [maxDecimals]="0"
|
|
2269
2309
|
[showErrors]="showErrors()" [ngModel]="maxReminders()" (ngModelChange)="maxReminders.set(asText($event))" />
|
|
2270
2310
|
</ui-form-row>
|
|
2271
2311
|
</ui-form-section>
|
|
@@ -2273,7 +2313,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2273
2313
|
</div>
|
|
2274
2314
|
}
|
|
2275
2315
|
} @else {
|
|
2276
|
-
<p class="dso-unavailable" role="note">
|
|
2316
|
+
<p class="dso-unavailable" role="note">{{ labels.t('messagingDocumentSendOptions.documentsCanOnlyBeTexted') }}</p>
|
|
2277
2317
|
}
|
|
2278
2318
|
</div>
|
|
2279
2319
|
`,
|
|
@@ -2290,7 +2330,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2290
2330
|
required: false
|
|
2291
2331
|
}]
|
|
2292
2332
|
}],
|
|
2293
|
-
|
|
2333
|
+
labelInput: [{
|
|
2294
2334
|
type: i0.Input,
|
|
2295
2335
|
args: [{
|
|
2296
2336
|
isSignal: true,
|
|
@@ -2402,6 +2442,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2402
2442
|
});
|
|
2403
2443
|
var DocumentSignersComponent = class DocumentSignersComponent {
|
|
2404
2444
|
constructor() {
|
|
2445
|
+
this.labels = inject(UiLabelsService);
|
|
2405
2446
|
this.info = input(null, ...ngDevMode ? [{ debugName: "info" }] : /* istanbul ignore next */ []);
|
|
2406
2447
|
this.config = input(null, ...ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []);
|
|
2407
2448
|
this.recipient = input({
|
|
@@ -2442,7 +2483,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2442
2483
|
return countersignPlaceLabel(title);
|
|
2443
2484
|
}
|
|
2444
2485
|
placeText(title) {
|
|
2445
|
-
return this.placeDocs().length > 1 ? countersignPlaceLabel(title) : "
|
|
2486
|
+
return this.placeDocs().length > 1 ? countersignPlaceLabel(title) : this.labels.t("messagingDocumentSendOptions.placeCountersign");
|
|
2446
2487
|
}
|
|
2447
2488
|
label(role) {
|
|
2448
2489
|
return signerRoleLabel(role, this.config());
|
|
@@ -2523,7 +2564,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2523
2564
|
ngImport: i0,
|
|
2524
2565
|
template: `
|
|
2525
2566
|
@if (rowsShown()) {
|
|
2526
|
-
<ui-form-section label="
|
|
2567
|
+
<ui-form-section [label]="labels.t('messagingDocumentSendOptions.signers')" data-testid="signers-section">
|
|
2527
2568
|
@for (role of info()!.roles; track role) {
|
|
2528
2569
|
@if (role === 'signer1') {
|
|
2529
2570
|
<div class="ds-row" [attr.data-testid]="'signer-row-' + role">
|
|
@@ -2538,7 +2579,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2538
2579
|
[required]="true"
|
|
2539
2580
|
[showErrors]="showErrors()"
|
|
2540
2581
|
[errorId]="'ds-error-' + role"
|
|
2541
|
-
placeholder="
|
|
2582
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchForAContact')"
|
|
2542
2583
|
(contactSelected)="pick(role, $event)" />
|
|
2543
2584
|
<!-- The picker's own "<Role> is required." (shown after blur or with showErrors), else the contact problem (no email / twice). -->
|
|
2544
2585
|
<div class="ds-error" [attr.id]="'ds-error-' + role">
|
|
@@ -2547,7 +2588,7 @@ var DocumentSignersComponent = class DocumentSignersComponent {
|
|
|
2547
2588
|
</div>
|
|
2548
2589
|
}
|
|
2549
2590
|
}
|
|
2550
|
-
<ui-hint data-testid="signers-order-hint">
|
|
2591
|
+
<ui-hint data-testid="signers-order-hint">{{ labels.t('messagingDocumentSendOptions.signersAreEmailedOneAfter') }}</ui-hint>
|
|
2551
2592
|
</ui-form-section>
|
|
2552
2593
|
}
|
|
2553
2594
|
@if (line()) {
|
|
@@ -2672,7 +2713,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2672
2713
|
}],
|
|
2673
2714
|
template: `
|
|
2674
2715
|
@if (rowsShown()) {
|
|
2675
|
-
<ui-form-section label="
|
|
2716
|
+
<ui-form-section [label]="labels.t('messagingDocumentSendOptions.signers')" data-testid="signers-section">
|
|
2676
2717
|
@for (role of info()!.roles; track role) {
|
|
2677
2718
|
@if (role === 'signer1') {
|
|
2678
2719
|
<div class="ds-row" [attr.data-testid]="'signer-row-' + role">
|
|
@@ -2687,7 +2728,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2687
2728
|
[required]="true"
|
|
2688
2729
|
[showErrors]="showErrors()"
|
|
2689
2730
|
[errorId]="'ds-error-' + role"
|
|
2690
|
-
placeholder="
|
|
2731
|
+
[placeholder]="labels.t('messagingDocumentSendOptions.searchForAContact')"
|
|
2691
2732
|
(contactSelected)="pick(role, $event)" />
|
|
2692
2733
|
<!-- The picker's own "<Role> is required." (shown after blur or with showErrors), else the contact problem (no email / twice). -->
|
|
2693
2734
|
<div class="ds-error" [attr.id]="'ds-error-' + role">
|
|
@@ -2696,7 +2737,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2696
2737
|
</div>
|
|
2697
2738
|
}
|
|
2698
2739
|
}
|
|
2699
|
-
<ui-hint data-testid="signers-order-hint">
|
|
2740
|
+
<ui-hint data-testid="signers-order-hint">{{ labels.t('messagingDocumentSendOptions.signersAreEmailedOneAfter') }}</ui-hint>
|
|
2700
2741
|
</ui-form-section>
|
|
2701
2742
|
}
|
|
2702
2743
|
@if (line()) {
|
|
@@ -2941,6 +2982,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2941
2982
|
}]
|
|
2942
2983
|
}
|
|
2943
2984
|
});
|
|
2985
|
+
const SPANISH_VIDEO_LINK_WORDS = {
|
|
2986
|
+
watchVideo: "Ver video",
|
|
2987
|
+
watchNamed: "Ver \"{{ title }}\": {{ link }}"
|
|
2988
|
+
};
|
|
2944
2989
|
function buildVideoLink(baseLink, options = {}) {
|
|
2945
2990
|
const params = [];
|
|
2946
2991
|
if (options.autoplay) params.push("autoplay=1");
|
|
@@ -2961,63 +3006,110 @@ function videoLinkWithDefaults(baseLink, defaults = {}, contactId = "") {
|
|
|
2961
3006
|
hideReactions: !!defaults.hideReactions
|
|
2962
3007
|
});
|
|
2963
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
|
+
}
|
|
2964
3019
|
function stripVideoLink(text) {
|
|
2965
|
-
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();
|
|
2966
3021
|
}
|
|
2967
3022
|
function appendVideoLink(text, link) {
|
|
2968
3023
|
const base = stripVideoLink(text);
|
|
2969
|
-
|
|
3024
|
+
const line = `🎬 ${uiText("messagingVideoLink.watchVideo")}: ${link}`;
|
|
3025
|
+
return base ? `${base}\n\n${line}` : line;
|
|
2970
3026
|
}
|
|
2971
3027
|
function videoMessageLine(title, link) {
|
|
2972
|
-
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));
|
|
2973
3065
|
}
|
|
2974
3066
|
function applyVideoLine(body, prev, next) {
|
|
2975
3067
|
if (!prev) {
|
|
2976
3068
|
if (!next) return body;
|
|
2977
3069
|
return body.trim() ? `${body}\n\n${next}` : next;
|
|
2978
3070
|
}
|
|
2979
|
-
const
|
|
2980
|
-
if (
|
|
2981
|
-
|
|
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);
|
|
2982
3075
|
const before = body.slice(0, at);
|
|
2983
|
-
const after = body.slice(at +
|
|
3076
|
+
const after = body.slice(at + found.length);
|
|
2984
3077
|
const trimmedBefore = before.replace(/\n{1,2}$/, "");
|
|
2985
3078
|
return (trimmedBefore + after).trim() === "" ? "" : trimmedBefore + after;
|
|
2986
3079
|
}
|
|
2987
|
-
const VIDEO_PLAYBACK_OPTIONS = [{
|
|
2988
|
-
value: "click",
|
|
2989
|
-
label: "Click to Play"
|
|
2990
|
-
}, {
|
|
2991
|
-
value: "autoplay",
|
|
2992
|
-
label: "Autoplay"
|
|
2993
|
-
}];
|
|
2994
|
-
const VIDEO_CTA_OPTIONS = [
|
|
2995
|
-
{
|
|
2996
|
-
value: "",
|
|
2997
|
-
label: "None (use video default)"
|
|
2998
|
-
},
|
|
2999
|
-
{
|
|
3000
|
-
value: "schedule",
|
|
3001
|
-
label: "Schedule a Call"
|
|
3002
|
-
},
|
|
3003
|
-
{
|
|
3004
|
-
value: "contact",
|
|
3005
|
-
label: "Contact Me"
|
|
3006
|
-
},
|
|
3007
|
-
{
|
|
3008
|
-
value: "custom",
|
|
3009
|
-
label: "Custom"
|
|
3010
|
-
}
|
|
3011
|
-
];
|
|
3012
3080
|
var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
3013
3081
|
constructor() {
|
|
3082
|
+
this.labels = inject(UiLabelsService);
|
|
3014
3083
|
this.video = input(null, ...ngDevMode ? [{ debugName: "video" }] : /* istanbul ignore next */ []);
|
|
3015
3084
|
this.defaults = input({}, ...ngDevMode ? [{ debugName: "defaults" }] : /* istanbul ignore next */ []);
|
|
3016
3085
|
this.contactId = input("", ...ngDevMode ? [{ debugName: "contactId" }] : /* istanbul ignore next */ []);
|
|
3017
3086
|
this.linkChange = output();
|
|
3018
3087
|
this.removed = output();
|
|
3019
|
-
this.playbackOptions =
|
|
3020
|
-
|
|
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 */ []);
|
|
3021
3113
|
this.autoplay = signal("click", ...ngDevMode ? [{ debugName: "autoplay" }] : /* istanbul ignore next */ []);
|
|
3022
3114
|
this.ctaType = signal("", ...ngDevMode ? [{ debugName: "ctaType" }] : /* istanbul ignore next */ []);
|
|
3023
3115
|
this.ctaUrl = signal("", ...ngDevMode ? [{ debugName: "ctaUrl" }] : /* istanbul ignore next */ []);
|
|
@@ -3126,40 +3218,40 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3126
3218
|
<ui-form-section class="vls">
|
|
3127
3219
|
<div class="vls-bar">
|
|
3128
3220
|
@if (v.shareLink) {
|
|
3129
|
-
<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>
|
|
3130
3222
|
}
|
|
3131
|
-
<ui-button variant="ghost" size="xs" [ariaExpanded]="settingsOpen()" (click)="toggleSettings()">
|
|
3132
|
-
<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>
|
|
3133
3225
|
</div>
|
|
3134
3226
|
<!-- Collapsed by default: the defaults from Communication settings are already applied. -->
|
|
3135
3227
|
@if (settingsOpen()) {
|
|
3136
3228
|
<ui-radio-group
|
|
3137
|
-
label="
|
|
3229
|
+
[label]="labels.t('messagingVideoLinkSettings.playback')"
|
|
3138
3230
|
orientation="horizontal"
|
|
3139
|
-
[options]="playbackOptions"
|
|
3231
|
+
[options]="playbackOptions()"
|
|
3140
3232
|
[ngModel]="autoplay()"
|
|
3141
3233
|
(ngModelChange)="setAutoplay($event)" />
|
|
3142
3234
|
<ui-select
|
|
3143
|
-
label="
|
|
3144
|
-
[options]="ctaOptions"
|
|
3235
|
+
[label]="labels.t('messagingVideoLinkSettings.callToAction')"
|
|
3236
|
+
[options]="ctaOptions()"
|
|
3145
3237
|
[ngModel]="ctaType()"
|
|
3146
3238
|
(ngModelChange)="setCtaType($event)" />
|
|
3147
3239
|
@if (ctaType()) {
|
|
3148
3240
|
<ui-text-input
|
|
3149
|
-
label="
|
|
3241
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionUrl')"
|
|
3150
3242
|
type="url"
|
|
3151
3243
|
placeholder="https://..."
|
|
3152
3244
|
[maxlength]="500"
|
|
3153
3245
|
[ngModel]="ctaUrl()"
|
|
3154
3246
|
(ngModelChange)="setCtaUrl($event)" />
|
|
3155
3247
|
<ui-text-input
|
|
3156
|
-
label="
|
|
3157
|
-
placeholder="
|
|
3248
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionLabel')"
|
|
3249
|
+
[placeholder]="labels.t('messagingVideoLinkSettings.buttonLabelEGBook')"
|
|
3158
3250
|
[maxlength]="100"
|
|
3159
3251
|
[ngModel]="ctaLabel()"
|
|
3160
3252
|
(ngModelChange)="setCtaLabel($event)" />
|
|
3161
3253
|
}
|
|
3162
|
-
<ui-checkbox label="
|
|
3254
|
+
<ui-checkbox [label]="labels.t('messagingVideoLinkSettings.hideReactions')" [ngModel]="hideReactions()" (ngModelChange)="setHideReactions($event)" />
|
|
3163
3255
|
}
|
|
3164
3256
|
</ui-form-section>
|
|
3165
3257
|
}
|
|
@@ -3241,6 +3333,7 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3241
3333
|
"legend",
|
|
3242
3334
|
"orientation",
|
|
3243
3335
|
"values",
|
|
3336
|
+
"labelLinks",
|
|
3244
3337
|
"description",
|
|
3245
3338
|
"indent",
|
|
3246
3339
|
"required",
|
|
@@ -3379,40 +3472,40 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
3379
3472
|
<ui-form-section class="vls">
|
|
3380
3473
|
<div class="vls-bar">
|
|
3381
3474
|
@if (v.shareLink) {
|
|
3382
|
-
<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>
|
|
3383
3476
|
}
|
|
3384
|
-
<ui-button variant="ghost" size="xs" [ariaExpanded]="settingsOpen()" (click)="toggleSettings()">
|
|
3385
|
-
<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>
|
|
3386
3479
|
</div>
|
|
3387
3480
|
<!-- Collapsed by default: the defaults from Communication settings are already applied. -->
|
|
3388
3481
|
@if (settingsOpen()) {
|
|
3389
3482
|
<ui-radio-group
|
|
3390
|
-
label="
|
|
3483
|
+
[label]="labels.t('messagingVideoLinkSettings.playback')"
|
|
3391
3484
|
orientation="horizontal"
|
|
3392
|
-
[options]="playbackOptions"
|
|
3485
|
+
[options]="playbackOptions()"
|
|
3393
3486
|
[ngModel]="autoplay()"
|
|
3394
3487
|
(ngModelChange)="setAutoplay($event)" />
|
|
3395
3488
|
<ui-select
|
|
3396
|
-
label="
|
|
3397
|
-
[options]="ctaOptions"
|
|
3489
|
+
[label]="labels.t('messagingVideoLinkSettings.callToAction')"
|
|
3490
|
+
[options]="ctaOptions()"
|
|
3398
3491
|
[ngModel]="ctaType()"
|
|
3399
3492
|
(ngModelChange)="setCtaType($event)" />
|
|
3400
3493
|
@if (ctaType()) {
|
|
3401
3494
|
<ui-text-input
|
|
3402
|
-
label="
|
|
3495
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionUrl')"
|
|
3403
3496
|
type="url"
|
|
3404
3497
|
placeholder="https://..."
|
|
3405
3498
|
[maxlength]="500"
|
|
3406
3499
|
[ngModel]="ctaUrl()"
|
|
3407
3500
|
(ngModelChange)="setCtaUrl($event)" />
|
|
3408
3501
|
<ui-text-input
|
|
3409
|
-
label="
|
|
3410
|
-
placeholder="
|
|
3502
|
+
[label]="labels.t('messagingVideoLinkSettings.callToActionLabel')"
|
|
3503
|
+
[placeholder]="labels.t('messagingVideoLinkSettings.buttonLabelEGBook')"
|
|
3411
3504
|
[maxlength]="100"
|
|
3412
3505
|
[ngModel]="ctaLabel()"
|
|
3413
3506
|
(ngModelChange)="setCtaLabel($event)" />
|
|
3414
3507
|
}
|
|
3415
|
-
<ui-checkbox label="
|
|
3508
|
+
<ui-checkbox [label]="labels.t('messagingVideoLinkSettings.hideReactions')" [ngModel]="hideReactions()" (ngModelChange)="setHideReactions($event)" />
|
|
3416
3509
|
}
|
|
3417
3510
|
</ui-form-section>
|
|
3418
3511
|
}
|
|
@@ -3476,10 +3569,16 @@ function buildDocumentsPayload(v, delivery, purpose = v.purpose, extras = {}) {
|
|
|
3476
3569
|
const DEFAULT_DOCUMENT_SUBJECT = "Document Signature Required";
|
|
3477
3570
|
function suggestDocumentSubject(titles, purpose, informational = false) {
|
|
3478
3571
|
if (titles.length === 0) return "";
|
|
3479
|
-
if (informational && purpose !== "ATTACH") return titles.length === 1 ?
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
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
|
+
});
|
|
3483
3582
|
}
|
|
3484
3583
|
const MAX_CC = 10;
|
|
3485
3584
|
function parseCcList(raw) {
|
|
@@ -3496,9 +3595,9 @@ function parseCcList(raw) {
|
|
|
3496
3595
|
const CC_EMAIL_RE = /^[^\s@,;<>"]+@[^\s@,;<>"]+\.[^\s@,;<>"]+$/;
|
|
3497
3596
|
function ccError(list) {
|
|
3498
3597
|
const bad = list.find((a) => a.length > 254 || !CC_EMAIL_RE.test(a));
|
|
3499
|
-
if (bad) return
|
|
3500
|
-
if (list.length > 10) return
|
|
3501
|
-
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");
|
|
3502
3601
|
return "";
|
|
3503
3602
|
}
|
|
3504
3603
|
function signingBodyFields(d) {
|
|
@@ -3553,13 +3652,14 @@ function nonBlankValues(...sources) {
|
|
|
3553
3652
|
return out;
|
|
3554
3653
|
}
|
|
3555
3654
|
function dateVars(now = /* @__PURE__ */ new Date()) {
|
|
3556
|
-
const
|
|
3655
|
+
const locale = uiLocale();
|
|
3656
|
+
const long = now.toLocaleDateString(locale, {
|
|
3557
3657
|
month: "long",
|
|
3558
3658
|
day: "numeric",
|
|
3559
3659
|
year: "numeric"
|
|
3560
3660
|
});
|
|
3561
3661
|
return {
|
|
3562
|
-
month: now.toLocaleString(
|
|
3662
|
+
month: now.toLocaleString(locale, { month: "long" }),
|
|
3563
3663
|
year: now.getFullYear().toString(),
|
|
3564
3664
|
date: long,
|
|
3565
3665
|
today: long
|
|
@@ -3591,6 +3691,9 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3591
3691
|
get deferredKeys() {
|
|
3592
3692
|
return this.bulk() ? PERSONAL_TAG_KEYS : [];
|
|
3593
3693
|
}
|
|
3694
|
+
get EMAIL_DISABLED_MESSAGE() {
|
|
3695
|
+
return this.labels.t("messagingSendMessagePanel.emailDisabled");
|
|
3696
|
+
}
|
|
3594
3697
|
ngOnInit() {
|
|
3595
3698
|
this.includeReceipt = this.receiptDefault();
|
|
3596
3699
|
this.http.get(`${this.apiBase}/service-areas?size=100`).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ next: (resp) => {
|
|
@@ -3599,6 +3702,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3599
3702
|
} });
|
|
3600
3703
|
}
|
|
3601
3704
|
constructor() {
|
|
3705
|
+
this.labels = inject(UiLabelsService);
|
|
3602
3706
|
this.destroyRef = inject(DestroyRef);
|
|
3603
3707
|
this.http = inject(HttpClient);
|
|
3604
3708
|
this.apiBase = inject(FORGEROUTE_CONFIG, { optional: true })?.baseUrl ?? "/api";
|
|
@@ -3615,7 +3719,11 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3615
3719
|
this.context = input({}, ...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
3616
3720
|
this.sendFn = input(null, ...ngDevMode ? [{ debugName: "sendFn" }] : /* istanbul ignore next */ []);
|
|
3617
3721
|
this.showReceiptOption = input(false, ...ngDevMode ? [{ debugName: "showReceiptOption" }] : /* istanbul ignore next */ []);
|
|
3618
|
-
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 */ []);
|
|
3619
3727
|
this.receiptDefault = input(false, ...ngDevMode ? [{ debugName: "receiptDefault" }] : /* istanbul ignore next */ []);
|
|
3620
3728
|
this.documents = input(false, ...ngDevMode ? [{ debugName: "documents" }] : /* istanbul ignore next */ []);
|
|
3621
3729
|
this.documentPurposes = input([
|
|
@@ -3660,7 +3768,6 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3660
3768
|
this.validChange = output();
|
|
3661
3769
|
this.rejected = output();
|
|
3662
3770
|
this.mapFieldsClick = output();
|
|
3663
|
-
this.EMAIL_DISABLED_MESSAGE = "Email sending is disabled, so this can't be sent. Enable it in Communication Settings.";
|
|
3664
3771
|
this.mode = "compose";
|
|
3665
3772
|
this.subject = "";
|
|
3666
3773
|
this.body = "";
|
|
@@ -3683,13 +3790,13 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3683
3790
|
this.signersInvalid = false;
|
|
3684
3791
|
this.mergeWarnings = [];
|
|
3685
3792
|
this.savingEmail = signal(false, ...ngDevMode ? [{ debugName: "savingEmail" }] : /* istanbul ignore next */ []);
|
|
3686
|
-
this.modeTabs = [{
|
|
3793
|
+
this.modeTabs = computed(() => [{
|
|
3687
3794
|
key: "compose",
|
|
3688
|
-
label: "
|
|
3795
|
+
label: this.labels.t("messagingSendMessagePanel.tabCompose")
|
|
3689
3796
|
}, {
|
|
3690
3797
|
key: "template",
|
|
3691
|
-
label: "
|
|
3692
|
-
}];
|
|
3798
|
+
label: this.labels.t("messagingSendMessagePanel.tabTemplate")
|
|
3799
|
+
}], ...ngDevMode ? [{ debugName: "modeTabs" }] : /* istanbul ignore next */ []);
|
|
3693
3800
|
this.marketVars = {};
|
|
3694
3801
|
this._appliedDefaults = {
|
|
3695
3802
|
subject: "",
|
|
@@ -3803,7 +3910,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3803
3910
|
});
|
|
3804
3911
|
if (this.hasDocuments && this.signerInfo?.multiDocumentNote) out.push({
|
|
3805
3912
|
key: "multi",
|
|
3806
|
-
text: "
|
|
3913
|
+
text: this.labels.t("messagingSendMessagePanel.multiSignerOneAtATime"),
|
|
3807
3914
|
testId: "documents-multi-signer-note"
|
|
3808
3915
|
});
|
|
3809
3916
|
if (this.hasDocuments) this.mergeWarnings.forEach((text, i) => out.push({
|
|
@@ -3827,8 +3934,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3827
3934
|
}
|
|
3828
3935
|
this.syncSuggestedSubject();
|
|
3829
3936
|
if (this.hasDocuments) {
|
|
3830
|
-
const removed = [this.attachments.length > 0 ? "
|
|
3831
|
-
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")} `) });
|
|
3832
3939
|
this.attachments = [];
|
|
3833
3940
|
this.showSchedule = false;
|
|
3834
3941
|
this.scheduledAt = "";
|
|
@@ -3840,10 +3947,16 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3840
3947
|
this.notifyValid();
|
|
3841
3948
|
}
|
|
3842
3949
|
get bodyLengthError() {
|
|
3843
|
-
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
|
+
}) : "";
|
|
3844
3954
|
}
|
|
3845
3955
|
get subjectLengthError() {
|
|
3846
|
-
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
|
+
}) : "";
|
|
3847
3960
|
}
|
|
3848
3961
|
get sendLengthError() {
|
|
3849
3962
|
return this.subjectLengthError || (this.mode === "compose" ? "" : this.bodyLengthError);
|
|
@@ -3905,7 +4018,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3905
4018
|
}
|
|
3906
4019
|
get composeTagError() {
|
|
3907
4020
|
if (this.mode !== "compose") return "";
|
|
3908
|
-
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") : "";
|
|
3909
4022
|
}
|
|
3910
4023
|
get unresolvedVars() {
|
|
3911
4024
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -4005,7 +4118,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4005
4118
|
const reader = new FileReader();
|
|
4006
4119
|
reader.onload = () => {
|
|
4007
4120
|
const base64 = reader.result.split(",")[1];
|
|
4008
|
-
const sizeLabel =
|
|
4121
|
+
const sizeLabel = formatAttachmentSize(file.size);
|
|
4009
4122
|
this.attachments = [...this.attachments, {
|
|
4010
4123
|
filename: file.name,
|
|
4011
4124
|
content: base64,
|
|
@@ -4024,7 +4137,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4024
4137
|
insertVideo(v) {
|
|
4025
4138
|
if (!v.shareLink) return;
|
|
4026
4139
|
const sep = this.body.trim() ? "\n\n" : "";
|
|
4027
|
-
this.body = this.body + sep +
|
|
4140
|
+
this.body = this.body + sep + videoMessageLine(v.title, v.shareLink);
|
|
4028
4141
|
this.notifyValid();
|
|
4029
4142
|
}
|
|
4030
4143
|
docuSignBody(docs, payload) {
|
|
@@ -4069,7 +4182,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4069
4182
|
submit() {
|
|
4070
4183
|
if (!this.canSend || this.loading || !this.bulk() && !this.contactEmail()) return;
|
|
4071
4184
|
if (this.bulk() && !this.sendFn()) {
|
|
4072
|
-
this.toast.error(
|
|
4185
|
+
this.toast.error(this.labels.t("messagingSendMessagePanel.bulkNoSend"));
|
|
4073
4186
|
return;
|
|
4074
4187
|
}
|
|
4075
4188
|
if (this.mode === "template") this.applyPendingVars();
|
|
@@ -4146,7 +4259,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4146
4259
|
});
|
|
4147
4260
|
const onError = (err) => {
|
|
4148
4261
|
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
4149
|
-
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"));
|
|
4150
4263
|
this.loading = false;
|
|
4151
4264
|
this.cdr.markForCheck();
|
|
4152
4265
|
if (this.bulk()) this.bulkSending.emit(null);
|
|
@@ -4162,7 +4275,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4162
4275
|
provider: docs.provider,
|
|
4163
4276
|
informational: docs.signerInfo?.informational === true
|
|
4164
4277
|
}) : void 0;
|
|
4165
|
-
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")));
|
|
4166
4279
|
this.loading = false;
|
|
4167
4280
|
this.attachments = [];
|
|
4168
4281
|
this.includeReceipt = this.receiptDefault();
|
|
@@ -4267,8 +4380,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4267
4380
|
isRequired: false,
|
|
4268
4381
|
transformFunction: null
|
|
4269
4382
|
},
|
|
4270
|
-
|
|
4271
|
-
classPropertyName: "
|
|
4383
|
+
receiptLabelInput: {
|
|
4384
|
+
classPropertyName: "receiptLabelInput",
|
|
4272
4385
|
publicName: "receiptLabel",
|
|
4273
4386
|
isSignal: true,
|
|
4274
4387
|
isRequired: false,
|
|
@@ -4443,25 +4556,21 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4443
4556
|
<!-- Missing email guard -->
|
|
4444
4557
|
@if (!bulk() && !contactEmail()) {
|
|
4445
4558
|
<div class="sm-missing-banner">
|
|
4446
|
-
<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>
|
|
4447
|
-
No email address on file for this contact.
|
|
4448
|
-
</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>
|
|
4449
4560
|
<ui-text-input
|
|
4450
|
-
label="
|
|
4561
|
+
[label]="labels.t('messagingSendMessagePanel.addEmailAddress')"
|
|
4451
4562
|
type="email"
|
|
4452
4563
|
[required]="true"
|
|
4453
4564
|
placeholder="email@example.com"
|
|
4454
4565
|
[(ngModel)]="pendingEmail"
|
|
4455
4566
|
(ngModelChange)="notifyValid()"
|
|
4456
|
-
[error]="pendingEmail && !pendingEmailValid ? '
|
|
4457
|
-
<ui-button variant="primary" [disabled]="!pendingEmailValid || savingEmail()" [loading]="savingEmail()" (click)="saveEmail()">
|
|
4458
|
-
Save & Continue
|
|
4459
|
-
</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>
|
|
4460
4569
|
} @else {
|
|
4461
4570
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
4462
4571
|
@if (!bulk()) {
|
|
4463
4572
|
<div class="sm-group">
|
|
4464
|
-
<span class="sm-group-label">
|
|
4573
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
4465
4574
|
<div class="sm-to-card">
|
|
4466
4575
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
4467
4576
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
@@ -4489,7 +4598,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4489
4598
|
<ui-text-input
|
|
4490
4599
|
label="CC"
|
|
4491
4600
|
placeholder="name@example.com, other@example.com"
|
|
4492
|
-
hint="
|
|
4601
|
+
[hint]="labels.t('messagingSendMessagePanel.separateAddressesWithCommasEveryone')"
|
|
4493
4602
|
[(ngModel)]="ccText"
|
|
4494
4603
|
[error]="ccError"
|
|
4495
4604
|
(ngModelChange)="notifyValid()" />
|
|
@@ -4498,24 +4607,24 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4498
4607
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
4499
4608
|
@if (showTemplates()) {
|
|
4500
4609
|
<div class="sm-mode-row">
|
|
4501
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
4610
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
4502
4611
|
</div>
|
|
4503
4612
|
}
|
|
4504
4613
|
|
|
4505
4614
|
@if (mode === 'compose') {
|
|
4506
4615
|
@if (showSubject()) {
|
|
4507
4616
|
<ui-text-input
|
|
4508
|
-
label="
|
|
4617
|
+
[label]="labels.t('common.subject')"
|
|
4509
4618
|
[required]="!viaDocuSign"
|
|
4510
|
-
placeholder="
|
|
4619
|
+
[placeholder]="labels.t('messagingSendMessagePanel.emailSubject')"
|
|
4511
4620
|
[maxlength]="MAX_SUBJECT"
|
|
4512
4621
|
[(ngModel)]="subject"
|
|
4513
4622
|
(ngModelChange)="notifyValid()" />
|
|
4514
4623
|
}
|
|
4515
4624
|
<ui-textarea-input
|
|
4516
|
-
label="
|
|
4625
|
+
[label]="labels.t('common.message')"
|
|
4517
4626
|
[required]="!viaDocuSign"
|
|
4518
|
-
placeholder="
|
|
4627
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
4519
4628
|
[rows]="8"
|
|
4520
4629
|
[(ngModel)]="body"
|
|
4521
4630
|
[error]="composeTagError || bodyLengthError"
|
|
@@ -4523,7 +4632,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4523
4632
|
|
|
4524
4633
|
@if (!hasDocuments && showAttachments()) {
|
|
4525
4634
|
<div class="sm-field">
|
|
4526
|
-
<label class="sm-field-label">
|
|
4635
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</label>
|
|
4527
4636
|
@if (attachments.length > 0) {
|
|
4528
4637
|
<div class="attach-chips">
|
|
4529
4638
|
@for (a of attachments; track a.filename; let i = $index) {
|
|
@@ -4531,25 +4640,23 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4531
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>
|
|
4532
4641
|
<span class="attach-name">{{ a.filename }}</span>
|
|
4533
4642
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
4534
|
-
<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>
|
|
4535
4644
|
</div>
|
|
4536
4645
|
}
|
|
4537
4646
|
</div>
|
|
4538
4647
|
}
|
|
4539
4648
|
<input #emailFileInput type="file" multiple hidden (change)="onFilesSelected($event)" />
|
|
4540
4649
|
<button type="button" class="attach-add-btn" (click)="emailFileInput.click()">
|
|
4541
|
-
<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>
|
|
4542
|
-
Attach Files
|
|
4543
|
-
</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>
|
|
4544
4651
|
</div>
|
|
4545
4652
|
|
|
4546
4653
|
}
|
|
4547
4654
|
|
|
4548
4655
|
@if (!hasDocuments && showScheduling()) {
|
|
4549
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
4656
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
4550
4657
|
@if (showSchedule) {
|
|
4551
4658
|
<ui-datetime-input
|
|
4552
|
-
label="
|
|
4659
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
4553
4660
|
[min]="minScheduleTime"
|
|
4554
4661
|
[(ngModel)]="scheduledAt"
|
|
4555
4662
|
(ngModelChange)="notifyValid()" />
|
|
@@ -4559,14 +4666,12 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4559
4666
|
@if (missingVars.length > 0) {
|
|
4560
4667
|
<div class="mv-section">
|
|
4561
4668
|
<p class="mv-hint">
|
|
4562
|
-
<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>
|
|
4563
|
-
This template has fields that need values before sending.
|
|
4564
|
-
</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>
|
|
4565
4670
|
@for (key of missingVars; track key) {
|
|
4566
4671
|
<div class="mv-row">
|
|
4567
4672
|
<div class="mv-input-wrap">
|
|
4568
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
4569
|
-
<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')">
|
|
4570
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>
|
|
4571
4676
|
</ui-button>
|
|
4572
4677
|
</div>
|
|
@@ -4577,22 +4682,18 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4577
4682
|
|
|
4578
4683
|
<div class="tpl-preview-header">
|
|
4579
4684
|
<ui-button variant="ghost" size="sm" (click)="clearTemplate()">
|
|
4580
|
-
<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>
|
|
4581
|
-
Back to templates
|
|
4582
|
-
</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>
|
|
4583
4686
|
<div class="tpl-view-toggle">
|
|
4584
|
-
<ui-button variant="tab" size="sm" [active]="previewFormat === 'preview'" [ariaPressed]="previewFormat === 'preview'" (click)="setPreviewFormat('preview')">
|
|
4585
|
-
<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>
|
|
4586
4689
|
</div>
|
|
4587
4690
|
</div>
|
|
4588
4691
|
|
|
4589
4692
|
<div class="tpl-subject-card">
|
|
4590
4693
|
<div class="tpl-subject-card-top">
|
|
4591
|
-
<span class="tpl-subject-label">
|
|
4694
|
+
<span class="tpl-subject-label">{{ labels.t('messagingSendMessagePanel.subject') }}</span>
|
|
4592
4695
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
4593
|
-
<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>
|
|
4594
|
-
View Send Preview
|
|
4595
|
-
</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>
|
|
4596
4697
|
</div>
|
|
4597
4698
|
<span class="tpl-subject-text">{{ resolvedSubject }}</span>
|
|
4598
4699
|
</div>
|
|
@@ -4600,9 +4701,9 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4600
4701
|
<div class="tpl-body-preview" [innerHTML]="previewBodyHtml"></div>
|
|
4601
4702
|
} @else {
|
|
4602
4703
|
<!-- Raw: the template source exactly as written, {{tags}} included — subject first, then the body. -->
|
|
4603
|
-
<div class="tpl-raw-label">
|
|
4704
|
+
<div class="tpl-raw-label">{{ labels.t('common.subject') }}</div>
|
|
4604
4705
|
<pre class="tpl-subject-raw">{{ subject }}</pre>
|
|
4605
|
-
<div class="tpl-raw-label">
|
|
4706
|
+
<div class="tpl-raw-label">{{ labels.t('messagingSendMessagePanel.body') }}</div>
|
|
4606
4707
|
<pre class="tpl-body-raw">{{ body }}</pre>
|
|
4607
4708
|
}
|
|
4608
4709
|
} @else {
|
|
@@ -4639,10 +4740,10 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4639
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. -->
|
|
4640
4741
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
4641
4742
|
@if (hasDocuments) {
|
|
4642
|
-
<p class="sm-docs-note">
|
|
4743
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.yourMessageGoesOutWith') }}</p>
|
|
4643
4744
|
}
|
|
4644
4745
|
@if (warningLines.length > 0) {
|
|
4645
|
-
<ui-alert variant="warning" title="
|
|
4746
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
4646
4747
|
<ul class="sm-warn-list">
|
|
4647
4748
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
4648
4749
|
</ul>
|
|
@@ -4665,7 +4766,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4665
4766
|
|
|
4666
4767
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
4667
4768
|
@if (mode === 'compose' && showVideo()) {
|
|
4668
|
-
<ui-form-section label="
|
|
4769
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
4669
4770
|
@for (k of [videoPickerKey]; track k) {
|
|
4670
4771
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
4671
4772
|
}
|
|
@@ -4687,20 +4788,18 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4687
4788
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
4688
4789
|
<div class="sp-modal-header">
|
|
4689
4790
|
<div class="sp-modal-title">
|
|
4690
|
-
<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>
|
|
4691
|
-
|
|
4692
|
-
</div>
|
|
4693
|
-
<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')">
|
|
4694
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>
|
|
4695
4794
|
</ui-button>
|
|
4696
4795
|
</div>
|
|
4697
4796
|
<div class="sp-email-meta">
|
|
4698
4797
|
<div class="sp-meta-row">
|
|
4699
|
-
<span class="sp-meta-label">
|
|
4700
|
-
<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>
|
|
4701
4800
|
</div>
|
|
4702
4801
|
<div class="sp-meta-row">
|
|
4703
|
-
<span class="sp-meta-label">
|
|
4802
|
+
<span class="sp-meta-label">{{ labels.t('common.subject') }}</span>
|
|
4704
4803
|
<span class="sp-meta-value sp-meta-subject">{{ sendPreviewSubject }}</span>
|
|
4705
4804
|
</div>
|
|
4706
4805
|
</div>
|
|
@@ -4792,6 +4891,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4792
4891
|
"legend",
|
|
4793
4892
|
"orientation",
|
|
4794
4893
|
"values",
|
|
4894
|
+
"labelLinks",
|
|
4795
4895
|
"description",
|
|
4796
4896
|
"indent",
|
|
4797
4897
|
"required",
|
|
@@ -5065,25 +5165,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5065
5165
|
<!-- Missing email guard -->
|
|
5066
5166
|
@if (!bulk() && !contactEmail()) {
|
|
5067
5167
|
<div class="sm-missing-banner">
|
|
5068
|
-
<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>
|
|
5069
|
-
No email address on file for this contact.
|
|
5070
|
-
</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>
|
|
5071
5169
|
<ui-text-input
|
|
5072
|
-
label="
|
|
5170
|
+
[label]="labels.t('messagingSendMessagePanel.addEmailAddress')"
|
|
5073
5171
|
type="email"
|
|
5074
5172
|
[required]="true"
|
|
5075
5173
|
placeholder="email@example.com"
|
|
5076
5174
|
[(ngModel)]="pendingEmail"
|
|
5077
5175
|
(ngModelChange)="notifyValid()"
|
|
5078
|
-
[error]="pendingEmail && !pendingEmailValid ? '
|
|
5079
|
-
<ui-button variant="primary" [disabled]="!pendingEmailValid || savingEmail()" [loading]="savingEmail()" (click)="saveEmail()">
|
|
5080
|
-
Save & Continue
|
|
5081
|
-
</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>
|
|
5082
5178
|
} @else {
|
|
5083
5179
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
5084
5180
|
@if (!bulk()) {
|
|
5085
5181
|
<div class="sm-group">
|
|
5086
|
-
<span class="sm-group-label">
|
|
5182
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
5087
5183
|
<div class="sm-to-card">
|
|
5088
5184
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
5089
5185
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
@@ -5111,7 +5207,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5111
5207
|
<ui-text-input
|
|
5112
5208
|
label="CC"
|
|
5113
5209
|
placeholder="name@example.com, other@example.com"
|
|
5114
|
-
hint="
|
|
5210
|
+
[hint]="labels.t('messagingSendMessagePanel.separateAddressesWithCommasEveryone')"
|
|
5115
5211
|
[(ngModel)]="ccText"
|
|
5116
5212
|
[error]="ccError"
|
|
5117
5213
|
(ngModelChange)="notifyValid()" />
|
|
@@ -5120,24 +5216,24 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5120
5216
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
5121
5217
|
@if (showTemplates()) {
|
|
5122
5218
|
<div class="sm-mode-row">
|
|
5123
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
5219
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
5124
5220
|
</div>
|
|
5125
5221
|
}
|
|
5126
5222
|
|
|
5127
5223
|
@if (mode === 'compose') {
|
|
5128
5224
|
@if (showSubject()) {
|
|
5129
5225
|
<ui-text-input
|
|
5130
|
-
label="
|
|
5226
|
+
[label]="labels.t('common.subject')"
|
|
5131
5227
|
[required]="!viaDocuSign"
|
|
5132
|
-
placeholder="
|
|
5228
|
+
[placeholder]="labels.t('messagingSendMessagePanel.emailSubject')"
|
|
5133
5229
|
[maxlength]="MAX_SUBJECT"
|
|
5134
5230
|
[(ngModel)]="subject"
|
|
5135
5231
|
(ngModelChange)="notifyValid()" />
|
|
5136
5232
|
}
|
|
5137
5233
|
<ui-textarea-input
|
|
5138
|
-
label="
|
|
5234
|
+
[label]="labels.t('common.message')"
|
|
5139
5235
|
[required]="!viaDocuSign"
|
|
5140
|
-
placeholder="
|
|
5236
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5141
5237
|
[rows]="8"
|
|
5142
5238
|
[(ngModel)]="body"
|
|
5143
5239
|
[error]="composeTagError || bodyLengthError"
|
|
@@ -5145,7 +5241,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5145
5241
|
|
|
5146
5242
|
@if (!hasDocuments && showAttachments()) {
|
|
5147
5243
|
<div class="sm-field">
|
|
5148
|
-
<label class="sm-field-label">
|
|
5244
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</label>
|
|
5149
5245
|
@if (attachments.length > 0) {
|
|
5150
5246
|
<div class="attach-chips">
|
|
5151
5247
|
@for (a of attachments; track a.filename; let i = $index) {
|
|
@@ -5153,25 +5249,23 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5153
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>
|
|
5154
5250
|
<span class="attach-name">{{ a.filename }}</span>
|
|
5155
5251
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
5156
|
-
<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>
|
|
5157
5253
|
</div>
|
|
5158
5254
|
}
|
|
5159
5255
|
</div>
|
|
5160
5256
|
}
|
|
5161
5257
|
<input #emailFileInput type="file" multiple hidden (change)="onFilesSelected($event)" />
|
|
5162
5258
|
<button type="button" class="attach-add-btn" (click)="emailFileInput.click()">
|
|
5163
|
-
<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>
|
|
5164
|
-
Attach Files
|
|
5165
|
-
</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>
|
|
5166
5260
|
</div>
|
|
5167
5261
|
|
|
5168
5262
|
}
|
|
5169
5263
|
|
|
5170
5264
|
@if (!hasDocuments && showScheduling()) {
|
|
5171
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
5265
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
5172
5266
|
@if (showSchedule) {
|
|
5173
5267
|
<ui-datetime-input
|
|
5174
|
-
label="
|
|
5268
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
5175
5269
|
[min]="minScheduleTime"
|
|
5176
5270
|
[(ngModel)]="scheduledAt"
|
|
5177
5271
|
(ngModelChange)="notifyValid()" />
|
|
@@ -5181,14 +5275,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5181
5275
|
@if (missingVars.length > 0) {
|
|
5182
5276
|
<div class="mv-section">
|
|
5183
5277
|
<p class="mv-hint">
|
|
5184
|
-
<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>
|
|
5185
|
-
This template has fields that need values before sending.
|
|
5186
|
-
</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>
|
|
5187
5279
|
@for (key of missingVars; track key) {
|
|
5188
5280
|
<div class="mv-row">
|
|
5189
5281
|
<div class="mv-input-wrap">
|
|
5190
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
5191
|
-
<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')">
|
|
5192
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>
|
|
5193
5285
|
</ui-button>
|
|
5194
5286
|
</div>
|
|
@@ -5199,22 +5291,18 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5199
5291
|
|
|
5200
5292
|
<div class="tpl-preview-header">
|
|
5201
5293
|
<ui-button variant="ghost" size="sm" (click)="clearTemplate()">
|
|
5202
|
-
<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>
|
|
5203
|
-
Back to templates
|
|
5204
|
-
</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>
|
|
5205
5295
|
<div class="tpl-view-toggle">
|
|
5206
|
-
<ui-button variant="tab" size="sm" [active]="previewFormat === 'preview'" [ariaPressed]="previewFormat === 'preview'" (click)="setPreviewFormat('preview')">
|
|
5207
|
-
<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>
|
|
5208
5298
|
</div>
|
|
5209
5299
|
</div>
|
|
5210
5300
|
|
|
5211
5301
|
<div class="tpl-subject-card">
|
|
5212
5302
|
<div class="tpl-subject-card-top">
|
|
5213
|
-
<span class="tpl-subject-label">
|
|
5303
|
+
<span class="tpl-subject-label">{{ labels.t('messagingSendMessagePanel.subject') }}</span>
|
|
5214
5304
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
5215
|
-
<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>
|
|
5216
|
-
View Send Preview
|
|
5217
|
-
</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>
|
|
5218
5306
|
</div>
|
|
5219
5307
|
<span class="tpl-subject-text">{{ resolvedSubject }}</span>
|
|
5220
5308
|
</div>
|
|
@@ -5222,9 +5310,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5222
5310
|
<div class="tpl-body-preview" [innerHTML]="previewBodyHtml"></div>
|
|
5223
5311
|
} @else {
|
|
5224
5312
|
<!-- Raw: the template source exactly as written, {{tags}} included — subject first, then the body. -->
|
|
5225
|
-
<div class="tpl-raw-label">
|
|
5313
|
+
<div class="tpl-raw-label">{{ labels.t('common.subject') }}</div>
|
|
5226
5314
|
<pre class="tpl-subject-raw">{{ subject }}</pre>
|
|
5227
|
-
<div class="tpl-raw-label">
|
|
5315
|
+
<div class="tpl-raw-label">{{ labels.t('messagingSendMessagePanel.body') }}</div>
|
|
5228
5316
|
<pre class="tpl-body-raw">{{ body }}</pre>
|
|
5229
5317
|
}
|
|
5230
5318
|
} @else {
|
|
@@ -5261,10 +5349,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5261
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. -->
|
|
5262
5350
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
5263
5351
|
@if (hasDocuments) {
|
|
5264
|
-
<p class="sm-docs-note">
|
|
5352
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.yourMessageGoesOutWith') }}</p>
|
|
5265
5353
|
}
|
|
5266
5354
|
@if (warningLines.length > 0) {
|
|
5267
|
-
<ui-alert variant="warning" title="
|
|
5355
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
5268
5356
|
<ul class="sm-warn-list">
|
|
5269
5357
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
5270
5358
|
</ul>
|
|
@@ -5287,7 +5375,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5287
5375
|
|
|
5288
5376
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
5289
5377
|
@if (mode === 'compose' && showVideo()) {
|
|
5290
|
-
<ui-form-section label="
|
|
5378
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
5291
5379
|
@for (k of [videoPickerKey]; track k) {
|
|
5292
5380
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
5293
5381
|
}
|
|
@@ -5309,20 +5397,18 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5309
5397
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
5310
5398
|
<div class="sp-modal-header">
|
|
5311
5399
|
<div class="sp-modal-title">
|
|
5312
|
-
<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>
|
|
5313
|
-
|
|
5314
|
-
</div>
|
|
5315
|
-
<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')">
|
|
5316
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>
|
|
5317
5403
|
</ui-button>
|
|
5318
5404
|
</div>
|
|
5319
5405
|
<div class="sp-email-meta">
|
|
5320
5406
|
<div class="sp-meta-row">
|
|
5321
|
-
<span class="sp-meta-label">
|
|
5322
|
-
<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>
|
|
5323
5409
|
</div>
|
|
5324
5410
|
<div class="sp-meta-row">
|
|
5325
|
-
<span class="sp-meta-label">
|
|
5411
|
+
<span class="sp-meta-label">{{ labels.t('common.subject') }}</span>
|
|
5326
5412
|
<span class="sp-meta-value sp-meta-subject">{{ sendPreviewSubject }}</span>
|
|
5327
5413
|
</div>
|
|
5328
5414
|
</div>
|
|
@@ -5416,7 +5502,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5416
5502
|
required: false
|
|
5417
5503
|
}]
|
|
5418
5504
|
}],
|
|
5419
|
-
|
|
5505
|
+
receiptLabelInput: [{
|
|
5420
5506
|
type: i0.Input,
|
|
5421
5507
|
args: [{
|
|
5422
5508
|
isSignal: true,
|
|
@@ -5633,6 +5719,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5633
5719
|
const MAX_SUBJECT = 255;
|
|
5634
5720
|
var SendInAppComponent = class SendInAppComponent {
|
|
5635
5721
|
constructor() {
|
|
5722
|
+
this.labels = inject(UiLabelsService);
|
|
5636
5723
|
this.destroyRef = inject(DestroyRef);
|
|
5637
5724
|
this.toast = inject(ToastService);
|
|
5638
5725
|
this.cdr = inject(ChangeDetectorRef);
|
|
@@ -5681,7 +5768,7 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5681
5768
|
const reader = new FileReader();
|
|
5682
5769
|
reader.onload = () => {
|
|
5683
5770
|
const base64 = String(reader.result).split(",")[1] ?? "";
|
|
5684
|
-
const sizeLabel =
|
|
5771
|
+
const sizeLabel = formatAttachmentSize(file.size);
|
|
5685
5772
|
this.attachments = [...this.attachments, {
|
|
5686
5773
|
filename: file.name,
|
|
5687
5774
|
content: base64,
|
|
@@ -5719,13 +5806,13 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5719
5806
|
if (this.showSubject()) payload.subject = this.subject.trim();
|
|
5720
5807
|
send(payload).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
5721
5808
|
next: () => {
|
|
5722
|
-
this.toast.show("
|
|
5809
|
+
this.toast.show(this.labels.t("messagingSendMessagePanel.messageSent"));
|
|
5723
5810
|
this.sending.set(false);
|
|
5724
5811
|
this.attachments = [];
|
|
5725
5812
|
this.sent.emit();
|
|
5726
5813
|
},
|
|
5727
5814
|
error: (err) => {
|
|
5728
|
-
this.toast.error(serverMessage(err) || "
|
|
5815
|
+
this.toast.error(serverMessage(err) || this.labels.t("messagingSendMessagePanel.failedSendMessage"));
|
|
5729
5816
|
this.sending.set(false);
|
|
5730
5817
|
this.notifyValid();
|
|
5731
5818
|
}
|
|
@@ -5827,7 +5914,7 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5827
5914
|
ngImport: i0,
|
|
5828
5915
|
template: `
|
|
5829
5916
|
<div class="sm-group">
|
|
5830
|
-
<span class="sm-group-label">
|
|
5917
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
5831
5918
|
<div class="sm-to-card">
|
|
5832
5919
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
5833
5920
|
@if (contactEmail()) { <span class="sm-to-email">{{ contactEmail() }}</span> }
|
|
@@ -5835,56 +5922,56 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5835
5922
|
</div>
|
|
5836
5923
|
@if (showSubject()) {
|
|
5837
5924
|
<ui-text-input
|
|
5838
|
-
label="
|
|
5925
|
+
[label]="labels.t('common.subject')"
|
|
5839
5926
|
[required]="true"
|
|
5840
|
-
placeholder="
|
|
5927
|
+
[placeholder]="labels.t('messagingSendMessagePanel.subject2')"
|
|
5841
5928
|
[maxlength]="MAX_SUBJECT"
|
|
5842
5929
|
[(ngModel)]="subject"
|
|
5843
5930
|
(ngModelChange)="notifyValid()" />
|
|
5844
5931
|
}
|
|
5845
5932
|
@if (richText()) {
|
|
5846
5933
|
<ui-rich-text-editor
|
|
5847
|
-
label="
|
|
5934
|
+
[label]="labels.t('common.message')"
|
|
5848
5935
|
[required]="true"
|
|
5849
|
-
placeholder="
|
|
5936
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5850
5937
|
[minHeight]="180"
|
|
5851
|
-
[error]="richTooLong() ? '
|
|
5938
|
+
[error]="richTooLong() ? labels.t('validation.tooLong', { max: limit() }) : ''"
|
|
5852
5939
|
[(ngModel)]="body"
|
|
5853
5940
|
(ngModelChange)="notifyValid()" />
|
|
5854
5941
|
} @else if (limit(); as max) {
|
|
5855
5942
|
<ui-textarea-input
|
|
5856
|
-
label="
|
|
5943
|
+
[label]="labels.t('common.message')"
|
|
5857
5944
|
[required]="true"
|
|
5858
|
-
placeholder="
|
|
5945
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5859
5946
|
[rows]="8"
|
|
5860
5947
|
[maxlength]="max"
|
|
5861
5948
|
[(ngModel)]="body"
|
|
5862
5949
|
(ngModelChange)="notifyValid()" />
|
|
5863
5950
|
} @else {
|
|
5864
5951
|
<ui-textarea-input
|
|
5865
|
-
label="
|
|
5952
|
+
[label]="labels.t('common.message')"
|
|
5866
5953
|
[required]="true"
|
|
5867
|
-
placeholder="
|
|
5954
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
5868
5955
|
[rows]="8"
|
|
5869
5956
|
[(ngModel)]="body"
|
|
5870
5957
|
(ngModelChange)="notifyValid()" />
|
|
5871
5958
|
}
|
|
5872
5959
|
@if (allowAttachments()) {
|
|
5873
5960
|
<div class="sm-group" data-testid="in-app-attachments">
|
|
5874
|
-
<span class="sm-group-label">
|
|
5961
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</span>
|
|
5875
5962
|
@if (attachments.length > 0) {
|
|
5876
5963
|
<div class="attach-chips">
|
|
5877
5964
|
@for (a of attachments; track $index; let i = $index) {
|
|
5878
5965
|
<div class="attach-chip">
|
|
5879
5966
|
<span class="attach-name">{{ a.filename }}</span>
|
|
5880
5967
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
5881
|
-
<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>
|
|
5882
5969
|
</div>
|
|
5883
5970
|
}
|
|
5884
5971
|
</div>
|
|
5885
5972
|
}
|
|
5886
5973
|
<input #fileInput type="file" multiple hidden data-testid="in-app-file-input" (change)="onFilesSelected($event)" />
|
|
5887
|
-
<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>
|
|
5888
5975
|
</div>
|
|
5889
5976
|
}
|
|
5890
5977
|
`,
|
|
@@ -6035,7 +6122,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6035
6122
|
],
|
|
6036
6123
|
template: `
|
|
6037
6124
|
<div class="sm-group">
|
|
6038
|
-
<span class="sm-group-label">
|
|
6125
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
6039
6126
|
<div class="sm-to-card">
|
|
6040
6127
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
6041
6128
|
@if (contactEmail()) { <span class="sm-to-email">{{ contactEmail() }}</span> }
|
|
@@ -6043,56 +6130,56 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6043
6130
|
</div>
|
|
6044
6131
|
@if (showSubject()) {
|
|
6045
6132
|
<ui-text-input
|
|
6046
|
-
label="
|
|
6133
|
+
[label]="labels.t('common.subject')"
|
|
6047
6134
|
[required]="true"
|
|
6048
|
-
placeholder="
|
|
6135
|
+
[placeholder]="labels.t('messagingSendMessagePanel.subject2')"
|
|
6049
6136
|
[maxlength]="MAX_SUBJECT"
|
|
6050
6137
|
[(ngModel)]="subject"
|
|
6051
6138
|
(ngModelChange)="notifyValid()" />
|
|
6052
6139
|
}
|
|
6053
6140
|
@if (richText()) {
|
|
6054
6141
|
<ui-rich-text-editor
|
|
6055
|
-
label="
|
|
6142
|
+
[label]="labels.t('common.message')"
|
|
6056
6143
|
[required]="true"
|
|
6057
|
-
placeholder="
|
|
6144
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6058
6145
|
[minHeight]="180"
|
|
6059
|
-
[error]="richTooLong() ? '
|
|
6146
|
+
[error]="richTooLong() ? labels.t('validation.tooLong', { max: limit() }) : ''"
|
|
6060
6147
|
[(ngModel)]="body"
|
|
6061
6148
|
(ngModelChange)="notifyValid()" />
|
|
6062
6149
|
} @else if (limit(); as max) {
|
|
6063
6150
|
<ui-textarea-input
|
|
6064
|
-
label="
|
|
6151
|
+
[label]="labels.t('common.message')"
|
|
6065
6152
|
[required]="true"
|
|
6066
|
-
placeholder="
|
|
6153
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6067
6154
|
[rows]="8"
|
|
6068
6155
|
[maxlength]="max"
|
|
6069
6156
|
[(ngModel)]="body"
|
|
6070
6157
|
(ngModelChange)="notifyValid()" />
|
|
6071
6158
|
} @else {
|
|
6072
6159
|
<ui-textarea-input
|
|
6073
|
-
label="
|
|
6160
|
+
[label]="labels.t('common.message')"
|
|
6074
6161
|
[required]="true"
|
|
6075
|
-
placeholder="
|
|
6162
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6076
6163
|
[rows]="8"
|
|
6077
6164
|
[(ngModel)]="body"
|
|
6078
6165
|
(ngModelChange)="notifyValid()" />
|
|
6079
6166
|
}
|
|
6080
6167
|
@if (allowAttachments()) {
|
|
6081
6168
|
<div class="sm-group" data-testid="in-app-attachments">
|
|
6082
|
-
<span class="sm-group-label">
|
|
6169
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.attachments') }}</span>
|
|
6083
6170
|
@if (attachments.length > 0) {
|
|
6084
6171
|
<div class="attach-chips">
|
|
6085
6172
|
@for (a of attachments; track $index; let i = $index) {
|
|
6086
6173
|
<div class="attach-chip">
|
|
6087
6174
|
<span class="attach-name">{{ a.filename }}</span>
|
|
6088
6175
|
<span class="attach-size">{{ a.sizeLabel }}</span>
|
|
6089
|
-
<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>
|
|
6090
6177
|
</div>
|
|
6091
6178
|
}
|
|
6092
6179
|
</div>
|
|
6093
6180
|
}
|
|
6094
6181
|
<input #fileInput type="file" multiple hidden data-testid="in-app-file-input" (change)="onFilesSelected($event)" />
|
|
6095
|
-
<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>
|
|
6096
6183
|
</div>
|
|
6097
6184
|
}
|
|
6098
6185
|
`,
|
|
@@ -6214,6 +6301,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6214
6301
|
} });
|
|
6215
6302
|
}
|
|
6216
6303
|
constructor() {
|
|
6304
|
+
this.labels = inject(UiLabelsService);
|
|
6217
6305
|
this.formatPhone = formatPhone;
|
|
6218
6306
|
this.destroyRef = inject(DestroyRef);
|
|
6219
6307
|
this.http = inject(HttpClient);
|
|
@@ -6287,13 +6375,13 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6287
6375
|
this.mediaAttachment = signal(null, ...ngDevMode ? [{ debugName: "mediaAttachment" }] : /* istanbul ignore next */ []);
|
|
6288
6376
|
this.mediaUploading = signal(false, ...ngDevMode ? [{ debugName: "mediaUploading" }] : /* istanbul ignore next */ []);
|
|
6289
6377
|
this.savingPhone = signal(false, ...ngDevMode ? [{ debugName: "savingPhone" }] : /* istanbul ignore next */ []);
|
|
6290
|
-
this.modeTabs = [{
|
|
6378
|
+
this.modeTabs = computed(() => [{
|
|
6291
6379
|
key: "compose",
|
|
6292
|
-
label: "
|
|
6380
|
+
label: this.labels.t("messagingSendMessagePanel.tabCompose")
|
|
6293
6381
|
}, {
|
|
6294
6382
|
key: "template",
|
|
6295
|
-
label: "
|
|
6296
|
-
}];
|
|
6383
|
+
label: this.labels.t("messagingSendMessagePanel.tabTemplate")
|
|
6384
|
+
}], ...ngDevMode ? [{ debugName: "modeTabs" }] : /* istanbul ignore next */ []);
|
|
6297
6385
|
this.marketVars = {};
|
|
6298
6386
|
this._appliedDefaultBody = "";
|
|
6299
6387
|
this.forwardedContext = computed(() => forwardContext(this.sendContext(), this.documentContextTypes()).context, ...ngDevMode ? [{ debugName: "forwardedContext" }] : /* istanbul ignore next */ []);
|
|
@@ -6356,8 +6444,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6356
6444
|
onDocumentsChange(v) {
|
|
6357
6445
|
this.documentsValue = v;
|
|
6358
6446
|
if (this.hasDocuments) {
|
|
6359
|
-
const removed = [this.mediaAttachment() ? "
|
|
6360
|
-
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")} `) });
|
|
6361
6449
|
this.showSchedule = false;
|
|
6362
6450
|
this.scheduledAt = "";
|
|
6363
6451
|
this.mediaAttachment.set(null);
|
|
@@ -6409,10 +6497,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6409
6497
|
return mergeTagKeys(this.body).filter((k) => !known[k] && !this.deferredKeys.includes(k));
|
|
6410
6498
|
}
|
|
6411
6499
|
get videoLengthError() {
|
|
6412
|
-
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 }) : "";
|
|
6413
6501
|
}
|
|
6414
6502
|
get composeTagError() {
|
|
6415
|
-
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "
|
|
6503
|
+
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? this.labels.t("messagingSendMessagePanel.leftoverTags") : "";
|
|
6416
6504
|
}
|
|
6417
6505
|
get unresolvedVars() {
|
|
6418
6506
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -6494,7 +6582,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6494
6582
|
onFileSelected(event) {
|
|
6495
6583
|
const file = event.target.files?.[0];
|
|
6496
6584
|
if (!file) return;
|
|
6497
|
-
const sizeLabel =
|
|
6585
|
+
const sizeLabel = formatAttachmentSize(file.size);
|
|
6498
6586
|
this.mediaUploading.set(true);
|
|
6499
6587
|
this.cdr.detectChanges();
|
|
6500
6588
|
const form = new FormData();
|
|
@@ -6511,7 +6599,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6511
6599
|
this.cdr.detectChanges();
|
|
6512
6600
|
},
|
|
6513
6601
|
error: () => {
|
|
6514
|
-
this.toast.error("
|
|
6602
|
+
this.toast.error(this.labels.t("messagingSendMessagePanel.failedUpload"));
|
|
6515
6603
|
this.mediaUploading.set(false);
|
|
6516
6604
|
this.cdr.detectChanges();
|
|
6517
6605
|
}
|
|
@@ -6524,7 +6612,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6524
6612
|
insertVideo(v) {
|
|
6525
6613
|
if (!v.shareLink) return;
|
|
6526
6614
|
const sep = this.body.trim() ? "\n\n" : "";
|
|
6527
|
-
this.body = (this.body + sep +
|
|
6615
|
+
this.body = (this.body + sep + videoMessageLine(v.title, v.shareLink)).slice(0, this.MAX_LENGTH);
|
|
6528
6616
|
this.notifyValid();
|
|
6529
6617
|
}
|
|
6530
6618
|
onVideoSelected(v) {
|
|
@@ -6559,7 +6647,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6559
6647
|
submit() {
|
|
6560
6648
|
if (!this.canSend || this.loading || !this.bulk() && !this.contactPhone()) return;
|
|
6561
6649
|
if (this.bulk() && !this.sendFn()) {
|
|
6562
|
-
this.toast.error(
|
|
6650
|
+
this.toast.error(this.labels.t("messagingSendMessagePanel.bulkNoSend"));
|
|
6563
6651
|
return;
|
|
6564
6652
|
}
|
|
6565
6653
|
if (this.mode === "template") this.applyPendingVars();
|
|
@@ -6631,7 +6719,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6631
6719
|
});
|
|
6632
6720
|
const onError = (err) => {
|
|
6633
6721
|
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
6634
|
-
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"));
|
|
6635
6723
|
this.loading = false;
|
|
6636
6724
|
this.cdr.detectChanges();
|
|
6637
6725
|
if (this.bulk()) this.bulkSending.emit(null);
|
|
@@ -6646,7 +6734,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6646
6734
|
channel: "text",
|
|
6647
6735
|
informational: docs.signerInfo?.informational === true
|
|
6648
6736
|
}) : void 0;
|
|
6649
|
-
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")));
|
|
6650
6738
|
this.loading = false;
|
|
6651
6739
|
this.mediaAttachment.set(null);
|
|
6652
6740
|
if (this.bulk()) this.bulkResult.emit({
|
|
@@ -6869,25 +6957,21 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6869
6957
|
<!-- Missing phone guard -->
|
|
6870
6958
|
@if (!bulk() && !contactPhone()) {
|
|
6871
6959
|
<div class="sm-missing-banner">
|
|
6872
|
-
<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>
|
|
6873
|
-
No phone number on file for this contact.
|
|
6874
|
-
</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>
|
|
6875
6961
|
<ui-text-input
|
|
6876
|
-
label="
|
|
6962
|
+
[label]="labels.t('messagingSendMessagePanel.addPhoneNumber')"
|
|
6877
6963
|
type="tel"
|
|
6878
6964
|
[required]="true"
|
|
6879
6965
|
placeholder="(555) 000-0000"
|
|
6880
6966
|
[(ngModel)]="pendingPhone"
|
|
6881
6967
|
(ngModelChange)="notifyValid()"
|
|
6882
|
-
[error]="pendingPhone && !pendingPhoneValid ? '
|
|
6883
|
-
<ui-button variant="primary" [disabled]="!pendingPhoneValid || savingPhone()" [loading]="savingPhone()" (click)="savePhone()">
|
|
6884
|
-
Save & Continue
|
|
6885
|
-
</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>
|
|
6886
6970
|
} @else {
|
|
6887
6971
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
6888
6972
|
@if (!bulk()) {
|
|
6889
6973
|
<div class="sm-group">
|
|
6890
|
-
<span class="sm-group-label">
|
|
6974
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
6891
6975
|
<div class="sm-to-card">
|
|
6892
6976
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
6893
6977
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
@@ -6898,23 +6982,23 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6898
6982
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
6899
6983
|
@if (showTemplates()) {
|
|
6900
6984
|
<div class="sm-mode-row">
|
|
6901
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
6985
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
6902
6986
|
</div>
|
|
6903
6987
|
}
|
|
6904
6988
|
|
|
6905
6989
|
@if (mode === 'compose') {
|
|
6906
6990
|
<div class="sm-field">
|
|
6907
6991
|
<ui-textarea-input
|
|
6908
|
-
label="
|
|
6992
|
+
[label]="labels.t('common.message')"
|
|
6909
6993
|
[required]="true"
|
|
6910
|
-
placeholder="
|
|
6994
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
6911
6995
|
[rows]="8"
|
|
6912
6996
|
[maxlength]="MAX_LENGTH"
|
|
6913
6997
|
[(ngModel)]="body"
|
|
6914
6998
|
[error]="composeTagError || videoLengthError"
|
|
6915
6999
|
(ngModelChange)="notifyValid()" />
|
|
6916
7000
|
<div class="sm-char-row">
|
|
6917
|
-
<span class="sm-hint">
|
|
7001
|
+
<span class="sm-hint">{{ labels.t('messagingSendMessagePanel.sentAsSmsKeepMessages') }}</span>
|
|
6918
7002
|
<span class="sm-char-count" [class.sm-char-warn]="body.length > MAX_LENGTH * 0.9">
|
|
6919
7003
|
{{ body.length }} / {{ MAX_LENGTH }}
|
|
6920
7004
|
</span>
|
|
@@ -6923,14 +7007,14 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6923
7007
|
|
|
6924
7008
|
@if (!hasDocuments && showAttachments()) {
|
|
6925
7009
|
<div class="sm-field">
|
|
6926
|
-
<label class="sm-field-label">
|
|
7010
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.addImageMediaMms') }}</label>
|
|
6927
7011
|
@if (mediaAttachment()) {
|
|
6928
7012
|
<div class="attach-chips">
|
|
6929
7013
|
<div class="attach-chip">
|
|
6930
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>
|
|
6931
7015
|
<span class="attach-name">{{ mediaAttachment()!.mediaFileName }}</span>
|
|
6932
7016
|
<span class="attach-size">{{ mediaAttachment()!.sizeLabel }}</span>
|
|
6933
|
-
<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>
|
|
6934
7018
|
</div>
|
|
6935
7019
|
</div>
|
|
6936
7020
|
}
|
|
@@ -6938,10 +7022,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6938
7022
|
<input #smsFileInput type="file" accept="image/*,video/*,application/pdf" hidden (change)="onFileSelected($event)" />
|
|
6939
7023
|
<button type="button" class="attach-add-btn" [disabled]="mediaUploading()" (click)="smsFileInput.click()">
|
|
6940
7024
|
@if (mediaUploading()) {
|
|
6941
|
-
<span class="attach-spinner"></span>
|
|
7025
|
+
<span class="attach-spinner"></span> {{ labels.t('messagingSendText.uploading') }}
|
|
6942
7026
|
} @else {
|
|
6943
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>
|
|
6944
|
-
|
|
7028
|
+
{{ labels.t('messagingSendMessagePanel.attachImage') }}
|
|
6945
7029
|
}
|
|
6946
7030
|
</button>
|
|
6947
7031
|
}
|
|
@@ -6950,10 +7034,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6950
7034
|
}
|
|
6951
7035
|
|
|
6952
7036
|
@if (!hasDocuments && showScheduling()) {
|
|
6953
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
7037
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
6954
7038
|
@if (showSchedule) {
|
|
6955
7039
|
<ui-datetime-input
|
|
6956
|
-
label="
|
|
7040
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
6957
7041
|
[min]="minScheduleTime"
|
|
6958
7042
|
[(ngModel)]="scheduledAt"
|
|
6959
7043
|
(ngModelChange)="notifyValid()" />
|
|
@@ -6963,14 +7047,12 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6963
7047
|
@if (missingVars.length > 0) {
|
|
6964
7048
|
<div class="mv-section">
|
|
6965
7049
|
<p class="mv-hint">
|
|
6966
|
-
<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>
|
|
6967
|
-
This template has fields that need values before sending.
|
|
6968
|
-
</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>
|
|
6969
7051
|
@for (key of missingVars; track key) {
|
|
6970
7052
|
<div class="mv-row">
|
|
6971
7053
|
<div class="mv-input-wrap">
|
|
6972
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
6973
|
-
<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')">
|
|
6974
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>
|
|
6975
7057
|
</button>
|
|
6976
7058
|
</div>
|
|
@@ -6981,20 +7063,16 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6981
7063
|
|
|
6982
7064
|
<div class="tpl-preview-header">
|
|
6983
7065
|
<button class="tpl-back-btn" type="button" (click)="clearTemplate()">
|
|
6984
|
-
<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>
|
|
6985
|
-
Back to templates
|
|
6986
|
-
</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>
|
|
6987
7067
|
<div class="tpl-view-toggle">
|
|
6988
|
-
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'preview'" [attr.aria-pressed]="previewFormat === 'preview'" type="button" (click)="setPreviewFormat('preview')">
|
|
6989
|
-
<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>
|
|
6990
7070
|
</div>
|
|
6991
7071
|
</div>
|
|
6992
7072
|
|
|
6993
7073
|
<div class="tpl-send-preview-row">
|
|
6994
7074
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
6995
|
-
<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>
|
|
6996
|
-
View Send Preview
|
|
6997
|
-
</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>
|
|
6998
7076
|
</div>
|
|
6999
7077
|
|
|
7000
7078
|
@if (previewFormat === 'preview') {
|
|
@@ -7034,10 +7112,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7034
7112
|
<!-- One live region, at most ONE warning banner (every current non-blocking warning is a line in it). -->
|
|
7035
7113
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
7036
7114
|
@if (hasDocuments) {
|
|
7037
|
-
<p class="sm-docs-note">
|
|
7115
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.theDocumentsAreTextedAs') }}</p>
|
|
7038
7116
|
}
|
|
7039
7117
|
@if (warningLines.length > 0) {
|
|
7040
|
-
<ui-alert variant="warning" title="
|
|
7118
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
7041
7119
|
<ul class="sm-warn-list">
|
|
7042
7120
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
7043
7121
|
</ul>
|
|
@@ -7048,7 +7126,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7048
7126
|
|
|
7049
7127
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
7050
7128
|
@if (mode === 'compose' && showVideo()) {
|
|
7051
|
-
<ui-form-section label="
|
|
7129
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
7052
7130
|
@for (k of [videoPickerKey]; track k) {
|
|
7053
7131
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
7054
7132
|
}
|
|
@@ -7070,17 +7148,15 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7070
7148
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7071
7149
|
<div class="sp-modal-header">
|
|
7072
7150
|
<div class="sp-modal-title">
|
|
7073
|
-
<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>
|
|
7074
|
-
|
|
7075
|
-
</div>
|
|
7076
|
-
<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')">
|
|
7077
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>
|
|
7078
7154
|
</button>
|
|
7079
7155
|
</div>
|
|
7080
7156
|
<div class="sp-text-meta">
|
|
7081
7157
|
<div class="sp-meta-row">
|
|
7082
|
-
<span class="sp-meta-label">
|
|
7083
|
-
<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>
|
|
7084
7160
|
</div>
|
|
7085
7161
|
</div>
|
|
7086
7162
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7094,10 +7170,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7094
7170
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7095
7171
|
<div class="sp-modal-header">
|
|
7096
7172
|
<div class="sp-modal-title">
|
|
7097
|
-
<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>
|
|
7098
|
-
|
|
7099
|
-
</div>
|
|
7100
|
-
<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')">
|
|
7101
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>
|
|
7102
7176
|
</button>
|
|
7103
7177
|
</div>
|
|
@@ -7189,6 +7263,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7189
7263
|
"legend",
|
|
7190
7264
|
"orientation",
|
|
7191
7265
|
"values",
|
|
7266
|
+
"labelLinks",
|
|
7192
7267
|
"description",
|
|
7193
7268
|
"indent",
|
|
7194
7269
|
"required",
|
|
@@ -7437,25 +7512,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7437
7512
|
<!-- Missing phone guard -->
|
|
7438
7513
|
@if (!bulk() && !contactPhone()) {
|
|
7439
7514
|
<div class="sm-missing-banner">
|
|
7440
|
-
<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>
|
|
7441
|
-
No phone number on file for this contact.
|
|
7442
|
-
</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>
|
|
7443
7516
|
<ui-text-input
|
|
7444
|
-
label="
|
|
7517
|
+
[label]="labels.t('messagingSendMessagePanel.addPhoneNumber')"
|
|
7445
7518
|
type="tel"
|
|
7446
7519
|
[required]="true"
|
|
7447
7520
|
placeholder="(555) 000-0000"
|
|
7448
7521
|
[(ngModel)]="pendingPhone"
|
|
7449
7522
|
(ngModelChange)="notifyValid()"
|
|
7450
|
-
[error]="pendingPhone && !pendingPhoneValid ? '
|
|
7451
|
-
<ui-button variant="primary" [disabled]="!pendingPhoneValid || savingPhone()" [loading]="savingPhone()" (click)="savePhone()">
|
|
7452
|
-
Save & Continue
|
|
7453
|
-
</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>
|
|
7454
7525
|
} @else {
|
|
7455
7526
|
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
7456
7527
|
@if (!bulk()) {
|
|
7457
7528
|
<div class="sm-group">
|
|
7458
|
-
<span class="sm-group-label">
|
|
7529
|
+
<span class="sm-group-label">{{ labels.t('messagingSendMessagePanel.to') }}</span>
|
|
7459
7530
|
<div class="sm-to-card">
|
|
7460
7531
|
<span class="sm-to-name">{{ contactName() }}</span>
|
|
7461
7532
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
@@ -7466,23 +7537,23 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7466
7537
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
7467
7538
|
@if (showTemplates()) {
|
|
7468
7539
|
<div class="sm-mode-row">
|
|
7469
|
-
<ui-pill-tabs [tabs]="modeTabs" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
7540
|
+
<ui-pill-tabs [tabs]="modeTabs()" [activeKey]="mode" (tabChange)="setMode($event)" />
|
|
7470
7541
|
</div>
|
|
7471
7542
|
}
|
|
7472
7543
|
|
|
7473
7544
|
@if (mode === 'compose') {
|
|
7474
7545
|
<div class="sm-field">
|
|
7475
7546
|
<ui-textarea-input
|
|
7476
|
-
label="
|
|
7547
|
+
[label]="labels.t('common.message')"
|
|
7477
7548
|
[required]="true"
|
|
7478
|
-
placeholder="
|
|
7549
|
+
[placeholder]="labels.t('messagingSendMessagePanel.writeYourMessage')"
|
|
7479
7550
|
[rows]="8"
|
|
7480
7551
|
[maxlength]="MAX_LENGTH"
|
|
7481
7552
|
[(ngModel)]="body"
|
|
7482
7553
|
[error]="composeTagError || videoLengthError"
|
|
7483
7554
|
(ngModelChange)="notifyValid()" />
|
|
7484
7555
|
<div class="sm-char-row">
|
|
7485
|
-
<span class="sm-hint">
|
|
7556
|
+
<span class="sm-hint">{{ labels.t('messagingSendMessagePanel.sentAsSmsKeepMessages') }}</span>
|
|
7486
7557
|
<span class="sm-char-count" [class.sm-char-warn]="body.length > MAX_LENGTH * 0.9">
|
|
7487
7558
|
{{ body.length }} / {{ MAX_LENGTH }}
|
|
7488
7559
|
</span>
|
|
@@ -7491,14 +7562,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7491
7562
|
|
|
7492
7563
|
@if (!hasDocuments && showAttachments()) {
|
|
7493
7564
|
<div class="sm-field">
|
|
7494
|
-
<label class="sm-field-label">
|
|
7565
|
+
<label class="sm-field-label">{{ labels.t('messagingSendMessagePanel.addImageMediaMms') }}</label>
|
|
7495
7566
|
@if (mediaAttachment()) {
|
|
7496
7567
|
<div class="attach-chips">
|
|
7497
7568
|
<div class="attach-chip">
|
|
7498
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>
|
|
7499
7570
|
<span class="attach-name">{{ mediaAttachment()!.mediaFileName }}</span>
|
|
7500
7571
|
<span class="attach-size">{{ mediaAttachment()!.sizeLabel }}</span>
|
|
7501
|
-
<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>
|
|
7502
7573
|
</div>
|
|
7503
7574
|
</div>
|
|
7504
7575
|
}
|
|
@@ -7506,10 +7577,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7506
7577
|
<input #smsFileInput type="file" accept="image/*,video/*,application/pdf" hidden (change)="onFileSelected($event)" />
|
|
7507
7578
|
<button type="button" class="attach-add-btn" [disabled]="mediaUploading()" (click)="smsFileInput.click()">
|
|
7508
7579
|
@if (mediaUploading()) {
|
|
7509
|
-
<span class="attach-spinner"></span>
|
|
7580
|
+
<span class="attach-spinner"></span> {{ labels.t('messagingSendText.uploading') }}
|
|
7510
7581
|
} @else {
|
|
7511
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>
|
|
7512
|
-
|
|
7583
|
+
{{ labels.t('messagingSendMessagePanel.attachImage') }}
|
|
7513
7584
|
}
|
|
7514
7585
|
</button>
|
|
7515
7586
|
}
|
|
@@ -7518,10 +7589,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7518
7589
|
}
|
|
7519
7590
|
|
|
7520
7591
|
@if (!hasDocuments && showScheduling()) {
|
|
7521
|
-
<ui-checkbox [checked]="showSchedule" label="
|
|
7592
|
+
<ui-checkbox [checked]="showSchedule" [label]="labels.t('messagingSendMessagePanel.scheduleForLater')" (checkedChange)="showSchedule = $event; notifyValid()" />
|
|
7522
7593
|
@if (showSchedule) {
|
|
7523
7594
|
<ui-datetime-input
|
|
7524
|
-
label="
|
|
7595
|
+
[label]="labels.t('messagingSendMessagePanel.sendAt')"
|
|
7525
7596
|
[min]="minScheduleTime"
|
|
7526
7597
|
[(ngModel)]="scheduledAt"
|
|
7527
7598
|
(ngModelChange)="notifyValid()" />
|
|
@@ -7531,14 +7602,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7531
7602
|
@if (missingVars.length > 0) {
|
|
7532
7603
|
<div class="mv-section">
|
|
7533
7604
|
<p class="mv-hint">
|
|
7534
|
-
<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>
|
|
7535
|
-
This template has fields that need values before sending.
|
|
7536
|
-
</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>
|
|
7537
7606
|
@for (key of missingVars; track key) {
|
|
7538
7607
|
<div class="mv-row">
|
|
7539
7608
|
<div class="mv-input-wrap">
|
|
7540
|
-
<ui-text-input class="mv-text-input" [label]="formatVarLabel(key)" [required]="true" [placeholder]="'
|
|
7541
|
-
<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')">
|
|
7542
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>
|
|
7543
7612
|
</button>
|
|
7544
7613
|
</div>
|
|
@@ -7549,20 +7618,16 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7549
7618
|
|
|
7550
7619
|
<div class="tpl-preview-header">
|
|
7551
7620
|
<button class="tpl-back-btn" type="button" (click)="clearTemplate()">
|
|
7552
|
-
<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>
|
|
7553
|
-
Back to templates
|
|
7554
|
-
</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>
|
|
7555
7622
|
<div class="tpl-view-toggle">
|
|
7556
|
-
<button class="tpl-toggle-btn" [class.active]="previewFormat === 'preview'" [attr.aria-pressed]="previewFormat === 'preview'" type="button" (click)="setPreviewFormat('preview')">
|
|
7557
|
-
<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>
|
|
7558
7625
|
</div>
|
|
7559
7626
|
</div>
|
|
7560
7627
|
|
|
7561
7628
|
<div class="tpl-send-preview-row">
|
|
7562
7629
|
<ui-button variant="secondary" size="sm" (click)="openSendPreview()">
|
|
7563
|
-
<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>
|
|
7564
|
-
View Send Preview
|
|
7565
|
-
</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>
|
|
7566
7631
|
</div>
|
|
7567
7632
|
|
|
7568
7633
|
@if (previewFormat === 'preview') {
|
|
@@ -7602,10 +7667,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7602
7667
|
<!-- One live region, at most ONE warning banner (every current non-blocking warning is a line in it). -->
|
|
7603
7668
|
<div class="sm-docs-live" role="status" aria-live="polite">
|
|
7604
7669
|
@if (hasDocuments) {
|
|
7605
|
-
<p class="sm-docs-note">
|
|
7670
|
+
<p class="sm-docs-note">{{ labels.t('messagingSendMessagePanel.theDocumentsAreTextedAs') }}</p>
|
|
7606
7671
|
}
|
|
7607
7672
|
@if (warningLines.length > 0) {
|
|
7608
|
-
<ui-alert variant="warning" title="
|
|
7673
|
+
<ui-alert variant="warning" [title]="labels.t('messagingSendMessagePanel.headsUp')" data-testid="send-warnings">
|
|
7609
7674
|
<ul class="sm-warn-list">
|
|
7610
7675
|
@for (w of warningLines; track w.key) { <li [attr.data-testid]="w.testId">{{ w.text }}</li> }
|
|
7611
7676
|
</ul>
|
|
@@ -7616,7 +7681,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7616
7681
|
|
|
7617
7682
|
<!-- Video: the LAST section. The picker, and once a video is attached its settings, Watch Preview and Remove Video. -->
|
|
7618
7683
|
@if (mode === 'compose' && showVideo()) {
|
|
7619
|
-
<ui-form-section label="
|
|
7684
|
+
<ui-form-section [label]="labels.t('common.video')" [divider]="true">
|
|
7620
7685
|
@for (k of [videoPickerKey]; track k) {
|
|
7621
7686
|
<ui-video-picker (videoSelected)="onVideoSelected($event)" />
|
|
7622
7687
|
}
|
|
@@ -7638,17 +7703,15 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7638
7703
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7639
7704
|
<div class="sp-modal-header">
|
|
7640
7705
|
<div class="sp-modal-title">
|
|
7641
|
-
<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>
|
|
7642
|
-
|
|
7643
|
-
</div>
|
|
7644
|
-
<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')">
|
|
7645
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>
|
|
7646
7709
|
</button>
|
|
7647
7710
|
</div>
|
|
7648
7711
|
<div class="sp-text-meta">
|
|
7649
7712
|
<div class="sp-meta-row">
|
|
7650
|
-
<span class="sp-meta-label">
|
|
7651
|
-
<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>
|
|
7652
7715
|
</div>
|
|
7653
7716
|
</div>
|
|
7654
7717
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7662,10 +7725,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7662
7725
|
<div class="sp-modal" (click)="$event.stopPropagation()">
|
|
7663
7726
|
<div class="sp-modal-header">
|
|
7664
7727
|
<div class="sp-modal-title">
|
|
7665
|
-
<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>
|
|
7666
|
-
|
|
7667
|
-
</div>
|
|
7668
|
-
<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')">
|
|
7669
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>
|
|
7670
7731
|
</button>
|
|
7671
7732
|
</div>
|
|
@@ -7908,13 +7969,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7908
7969
|
const BULK_MERGE_TAG_HINT = "Personal details such as {{first_name}} are filled in for each recipient when sent.";
|
|
7909
7970
|
const SKIPPED_NAMES_SHOWN = 5;
|
|
7910
7971
|
var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
7911
|
-
|
|
7912
|
-
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");
|
|
7913
7979
|
}
|
|
7914
7980
|
skippedNames() {
|
|
7915
|
-
const names = this.skippedRecipients().map((r) => r.name || "
|
|
7981
|
+
const names = this.skippedRecipients().map((r) => r.name || this.labels.t("messagingSendMessagePanel.unnamed"));
|
|
7916
7982
|
const shown = names.slice(0, SKIPPED_NAMES_SHOWN).join(", ");
|
|
7917
|
-
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;
|
|
7918
7987
|
}
|
|
7919
7988
|
bulkRecipientsFor(ch) {
|
|
7920
7989
|
if (!this.bulkMode()) return null;
|
|
@@ -7962,15 +8031,20 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7962
8031
|
this.jobOptions.set([]);
|
|
7963
8032
|
}
|
|
7964
8033
|
constructor() {
|
|
8034
|
+
this.labels = inject(UiLabelsService);
|
|
7965
8035
|
this.open = input(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
|
|
7966
8036
|
this.contact = input(null, ...ngDevMode ? [{ debugName: "contact" }] : /* istanbul ignore next */ []);
|
|
7967
8037
|
this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
7968
8038
|
this.recipients = input(null, ...ngDevMode ? [{ debugName: "recipients" }] : /* istanbul ignore next */ []);
|
|
7969
8039
|
this.initialChannel = input(null, ...ngDevMode ? [{ debugName: "initialChannel" }] : /* istanbul ignore next */ []);
|
|
7970
|
-
this.recipientNoun = input("
|
|
8040
|
+
this.recipientNoun = input("", ...ngDevMode ? [{ debugName: "recipientNoun" }] : /* istanbul ignore next */ []);
|
|
7971
8041
|
this.recipientNounSingular = input("", ...ngDevMode ? [{ debugName: "recipientNounSingular" }] : /* istanbul ignore next */ []);
|
|
7972
8042
|
this.textEnabled = input(false, ...ngDevMode ? [{ debugName: "textEnabled" }] : /* istanbul ignore next */ []);
|
|
7973
|
-
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 */ []);
|
|
7974
8048
|
this.defaultSubject = input("", ...ngDevMode ? [{ debugName: "defaultSubject" }] : /* istanbul ignore next */ []);
|
|
7975
8049
|
this.defaultBody = input("", ...ngDevMode ? [{ debugName: "defaultBody" }] : /* istanbul ignore next */ []);
|
|
7976
8050
|
this.defaultMessage = input("", ...ngDevMode ? [{ debugName: "defaultMessage" }] : /* istanbul ignore next */ []);
|
|
@@ -7978,7 +8052,11 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7978
8052
|
this.sendEmail = input(null, ...ngDevMode ? [{ debugName: "sendEmail" }] : /* istanbul ignore next */ []);
|
|
7979
8053
|
this.sendText = input(null, ...ngDevMode ? [{ debugName: "sendText" }] : /* istanbul ignore next */ []);
|
|
7980
8054
|
this.showReceiptOption = input(false, ...ngDevMode ? [{ debugName: "showReceiptOption" }] : /* istanbul ignore next */ []);
|
|
7981
|
-
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 */ []);
|
|
7982
8060
|
this.receiptDefault = input(false, ...ngDevMode ? [{ debugName: "receiptDefault" }] : /* istanbul ignore next */ []);
|
|
7983
8061
|
this.documents = input(false, ...ngDevMode ? [{ debugName: "documents" }] : /* istanbul ignore next */ []);
|
|
7984
8062
|
this.documentsEnabled = input(true, ...ngDevMode ? [{ debugName: "documentsEnabled" }] : /* istanbul ignore next */ []);
|
|
@@ -7992,8 +8070,6 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7992
8070
|
this.showTemplates = input(true, ...ngDevMode ? [{ debugName: "showTemplates" }] : /* istanbul ignore next */ []);
|
|
7993
8071
|
this.showVideo = input(true, ...ngDevMode ? [{ debugName: "showVideo" }] : /* istanbul ignore next */ []);
|
|
7994
8072
|
this.inApp = computed(() => this.recipientMode() === "in-app" && !this.bulkMode(), ...ngDevMode ? [{ debugName: "inApp" }] : /* istanbul ignore next */ []);
|
|
7995
|
-
this.BULK_NO_SEND_MESSAGE = BULK_NO_SEND_MESSAGE;
|
|
7996
|
-
this.BULK_MERGE_TAG_HINT = BULK_MERGE_TAG_HINT;
|
|
7997
8073
|
this.attachmentsAndScheduling = input(true, ...ngDevMode ? [{ debugName: "attachmentsAndScheduling" }] : /* istanbul ignore next */ []);
|
|
7998
8074
|
this.allowAttachments = input(null, ...ngDevMode ? [{ debugName: "allowAttachments" }] : /* istanbul ignore next */ []);
|
|
7999
8075
|
this.allowScheduling = input(null, ...ngDevMode ? [{ debugName: "allowScheduling" }] : /* istanbul ignore next */ []);
|
|
@@ -8037,31 +8113,56 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8037
8113
|
this.submitSnapshot = null;
|
|
8038
8114
|
this.recipientWord = computed(() => {
|
|
8039
8115
|
const n = this.bulkList().length;
|
|
8040
|
-
const plural = this.recipientNoun() || "
|
|
8116
|
+
const plural = this.recipientNoun() || this.labels.t("messagingSendMessagePanel.recipientsWord");
|
|
8041
8117
|
if (n !== 1) return plural;
|
|
8042
8118
|
return this.recipientNounSingular() || (plural.endsWith("s") ? plural.slice(0, -1) : plural);
|
|
8043
8119
|
}, ...ngDevMode ? [{ debugName: "recipientWord" }] : /* istanbul ignore next */ []);
|
|
8044
8120
|
this.skippedText = computed(() => {
|
|
8045
8121
|
const n = this.skippedRecipients().length;
|
|
8046
8122
|
if (n === 0) return "";
|
|
8047
|
-
const what = this.channel() === "email" ? "
|
|
8048
|
-
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
|
+
});
|
|
8049
8130
|
}, ...ngDevMode ? [{ debugName: "skippedText" }] : /* istanbul ignore next */ []);
|
|
8050
8131
|
this.noneEligibleText = computed(() => {
|
|
8051
|
-
|
|
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
|
+
});
|
|
8052
8139
|
}, ...ngDevMode ? [{ debugName: "noneEligibleText" }] : /* istanbul ignore next */ []);
|
|
8053
8140
|
this.bulkAnnouncement = computed(() => {
|
|
8054
8141
|
if (!this.bulkMode()) return "";
|
|
8055
8142
|
const n = this.bulkList().length;
|
|
8056
8143
|
const ok = this.activeRecipients().length;
|
|
8057
|
-
const ch = this.channel() === "email" ? "
|
|
8058
|
-
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
|
+
});
|
|
8059
8150
|
const skipped = this.skippedRecipients().length;
|
|
8060
|
-
|
|
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 }) : "");
|
|
8061
8158
|
}, ...ngDevMode ? [{ debugName: "bulkAnnouncement" }] : /* istanbul ignore next */ []);
|
|
8062
8159
|
this.lastBulkResult = void 0;
|
|
8063
8160
|
this.showJobPicker = input(false, ...ngDevMode ? [{ debugName: "showJobPicker" }] : /* istanbul ignore next */ []);
|
|
8064
|
-
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 */ []);
|
|
8065
8166
|
this.jobHint = input("", ...ngDevMode ? [{ debugName: "jobHint" }] : /* istanbul ignore next */ []);
|
|
8066
8167
|
this.jobSearch = input(null, ...ngDevMode ? [{ debugName: "jobSearch" }] : /* istanbul ignore next */ []);
|
|
8067
8168
|
this.jobSelected = output();
|
|
@@ -8093,10 +8194,10 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8093
8194
|
if (!c || this.inApp()) return [];
|
|
8094
8195
|
const notices = [];
|
|
8095
8196
|
const hasEmail = !!c.email, hasPhone = !!c.phone;
|
|
8096
|
-
if (!this.textEnabled()) notices.push(
|
|
8097
|
-
else if (!c.smsOptedIn) notices.push(
|
|
8098
|
-
else if (!hasPhone) notices.push(
|
|
8099
|
-
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 }));
|
|
8100
8201
|
return notices;
|
|
8101
8202
|
}, ...ngDevMode ? [{ debugName: "contactNotices" }] : /* istanbul ignore next */ []);
|
|
8102
8203
|
this.channel = signal("email", ...ngDevMode ? [{ debugName: "channel" }] : /* istanbul ignore next */ []);
|
|
@@ -8296,8 +8397,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8296
8397
|
isRequired: false,
|
|
8297
8398
|
transformFunction: null
|
|
8298
8399
|
},
|
|
8299
|
-
|
|
8300
|
-
classPropertyName: "
|
|
8400
|
+
titleInput: {
|
|
8401
|
+
classPropertyName: "titleInput",
|
|
8301
8402
|
publicName: "title",
|
|
8302
8403
|
isSignal: true,
|
|
8303
8404
|
isRequired: false,
|
|
@@ -8352,8 +8453,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8352
8453
|
isRequired: false,
|
|
8353
8454
|
transformFunction: null
|
|
8354
8455
|
},
|
|
8355
|
-
|
|
8356
|
-
classPropertyName: "
|
|
8456
|
+
receiptLabelInput: {
|
|
8457
|
+
classPropertyName: "receiptLabelInput",
|
|
8357
8458
|
publicName: "receiptLabel",
|
|
8358
8459
|
isSignal: true,
|
|
8359
8460
|
isRequired: false,
|
|
@@ -8576,8 +8677,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8576
8677
|
isRequired: false,
|
|
8577
8678
|
transformFunction: null
|
|
8578
8679
|
},
|
|
8579
|
-
|
|
8580
|
-
classPropertyName: "
|
|
8680
|
+
jobLabelInput: {
|
|
8681
|
+
classPropertyName: "jobLabelInput",
|
|
8581
8682
|
publicName: "jobLabel",
|
|
8582
8683
|
isSignal: true,
|
|
8583
8684
|
isRequired: false,
|
|
@@ -8637,8 +8738,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8637
8738
|
[open]="open()"
|
|
8638
8739
|
[title]="title()"
|
|
8639
8740
|
[wide]="wide()"
|
|
8640
|
-
cancelLabel="
|
|
8641
|
-
[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'))) : ''"
|
|
8642
8743
|
primaryVariant="warning"
|
|
8643
8744
|
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
8644
8745
|
(closed)="onClose()"
|
|
@@ -8655,25 +8756,25 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8655
8756
|
@if (!loading() && !hasTarget() && !inApp()) {
|
|
8656
8757
|
<div class="msg-step">
|
|
8657
8758
|
<span class="msg-step-badge">1</span>
|
|
8658
|
-
<span class="msg-step-text">
|
|
8759
|
+
<span class="msg-step-text">{{ labels.t('messagingSendMessagePanel.whoWouldYouLikeTo') }}</span>
|
|
8659
8760
|
</div>
|
|
8660
8761
|
<ui-contact-picker
|
|
8661
|
-
placeholder="
|
|
8762
|
+
[placeholder]="labels.t('messagingSendMessagePanel.searchByContactName')"
|
|
8662
8763
|
(contactSelected)="onContactSelected($event)" />
|
|
8663
8764
|
}
|
|
8664
8765
|
|
|
8665
8766
|
@if (!loading() && hasTarget()) {
|
|
8666
8767
|
@if (bulkMode()) {
|
|
8667
|
-
<div class="msg-bulk" role="group" aria-label="
|
|
8668
|
-
<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>
|
|
8669
8770
|
<div class="msg-bulk-counts">
|
|
8670
|
-
<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'" />
|
|
8671
8772
|
@if (textEnabled()) {
|
|
8672
|
-
<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'" />
|
|
8673
8774
|
}
|
|
8674
8775
|
</div>
|
|
8675
8776
|
@if (!textEnabled()) {
|
|
8676
|
-
<ui-hint>
|
|
8777
|
+
<ui-hint>{{ labels.t('messagingSendMessagePanel.textMessagingIsNotEnabled') }}</ui-hint>
|
|
8677
8778
|
}
|
|
8678
8779
|
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
8679
8780
|
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
@@ -8683,7 +8784,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8683
8784
|
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
8684
8785
|
}
|
|
8685
8786
|
@if (bulkMissingSend()) {
|
|
8686
|
-
<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>
|
|
8687
8788
|
}
|
|
8688
8789
|
@if (!bulkNoneEligible()) {
|
|
8689
8790
|
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
@@ -8693,23 +8794,19 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8693
8794
|
|
|
8694
8795
|
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
8695
8796
|
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
8696
|
-
<label class="form-label msg-via-label">
|
|
8797
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
8697
8798
|
@if (sending()) {
|
|
8698
8799
|
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
8699
8800
|
<div class="msg-via-tabs">
|
|
8700
|
-
<ui-badge [label]="channel() === 'email' ? '
|
|
8701
|
-
<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>
|
|
8702
8803
|
</div>
|
|
8703
8804
|
} @else {
|
|
8704
8805
|
<div class="msg-via-tabs">
|
|
8705
8806
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
8706
|
-
<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>
|
|
8707
|
-
Email
|
|
8708
|
-
</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>
|
|
8709
8808
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
8710
|
-
<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>
|
|
8711
|
-
Text
|
|
8712
|
-
</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>
|
|
8713
8810
|
</div>
|
|
8714
8811
|
}
|
|
8715
8812
|
</div>
|
|
@@ -8717,16 +8814,12 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8717
8814
|
|
|
8718
8815
|
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
8719
8816
|
<div class="msg-channel-row">
|
|
8720
|
-
<label class="form-label msg-via-label">
|
|
8817
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
8721
8818
|
<div class="msg-via-tabs">
|
|
8722
8819
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
8723
|
-
<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>
|
|
8724
|
-
Email
|
|
8725
|
-
</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>
|
|
8726
8821
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
8727
|
-
<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>
|
|
8728
|
-
Text
|
|
8729
|
-
</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>
|
|
8730
8823
|
</div>
|
|
8731
8824
|
</div>
|
|
8732
8825
|
}
|
|
@@ -8743,8 +8836,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8743
8836
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8744
8837
|
<div class="msg-job">
|
|
8745
8838
|
<ui-combobox
|
|
8746
|
-
[label]="jobLabel()" placeholder="
|
|
8747
|
-
[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"
|
|
8748
8841
|
[value]="jobValue()"
|
|
8749
8842
|
(searchChange)="jobSearch$.next($event)" (valueChange)="onJobPick($event)" />
|
|
8750
8843
|
</div>
|
|
@@ -9113,8 +9206,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9113
9206
|
[open]="open()"
|
|
9114
9207
|
[title]="title()"
|
|
9115
9208
|
[wide]="wide()"
|
|
9116
|
-
cancelLabel="
|
|
9117
|
-
[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'))) : ''"
|
|
9118
9211
|
primaryVariant="warning"
|
|
9119
9212
|
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
9120
9213
|
(closed)="onClose()"
|
|
@@ -9131,25 +9224,25 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9131
9224
|
@if (!loading() && !hasTarget() && !inApp()) {
|
|
9132
9225
|
<div class="msg-step">
|
|
9133
9226
|
<span class="msg-step-badge">1</span>
|
|
9134
|
-
<span class="msg-step-text">
|
|
9227
|
+
<span class="msg-step-text">{{ labels.t('messagingSendMessagePanel.whoWouldYouLikeTo') }}</span>
|
|
9135
9228
|
</div>
|
|
9136
9229
|
<ui-contact-picker
|
|
9137
|
-
placeholder="
|
|
9230
|
+
[placeholder]="labels.t('messagingSendMessagePanel.searchByContactName')"
|
|
9138
9231
|
(contactSelected)="onContactSelected($event)" />
|
|
9139
9232
|
}
|
|
9140
9233
|
|
|
9141
9234
|
@if (!loading() && hasTarget()) {
|
|
9142
9235
|
@if (bulkMode()) {
|
|
9143
|
-
<div class="msg-bulk" role="group" aria-label="
|
|
9144
|
-
<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>
|
|
9145
9238
|
<div class="msg-bulk-counts">
|
|
9146
|
-
<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'" />
|
|
9147
9240
|
@if (textEnabled()) {
|
|
9148
|
-
<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'" />
|
|
9149
9242
|
}
|
|
9150
9243
|
</div>
|
|
9151
9244
|
@if (!textEnabled()) {
|
|
9152
|
-
<ui-hint>
|
|
9245
|
+
<ui-hint>{{ labels.t('messagingSendMessagePanel.textMessagingIsNotEnabled') }}</ui-hint>
|
|
9153
9246
|
}
|
|
9154
9247
|
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
9155
9248
|
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
@@ -9159,7 +9252,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9159
9252
|
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
9160
9253
|
}
|
|
9161
9254
|
@if (bulkMissingSend()) {
|
|
9162
|
-
<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>
|
|
9163
9256
|
}
|
|
9164
9257
|
@if (!bulkNoneEligible()) {
|
|
9165
9258
|
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
@@ -9169,23 +9262,19 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9169
9262
|
|
|
9170
9263
|
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
9171
9264
|
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
9172
|
-
<label class="form-label msg-via-label">
|
|
9265
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
9173
9266
|
@if (sending()) {
|
|
9174
9267
|
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
9175
9268
|
<div class="msg-via-tabs">
|
|
9176
|
-
<ui-badge [label]="channel() === 'email' ? '
|
|
9177
|
-
<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>
|
|
9178
9271
|
</div>
|
|
9179
9272
|
} @else {
|
|
9180
9273
|
<div class="msg-via-tabs">
|
|
9181
9274
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
9182
|
-
<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>
|
|
9183
|
-
Email
|
|
9184
|
-
</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>
|
|
9185
9276
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
9186
|
-
<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>
|
|
9187
|
-
Text
|
|
9188
|
-
</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>
|
|
9189
9278
|
</div>
|
|
9190
9279
|
}
|
|
9191
9280
|
</div>
|
|
@@ -9193,16 +9282,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9193
9282
|
|
|
9194
9283
|
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
9195
9284
|
<div class="msg-channel-row">
|
|
9196
|
-
<label class="form-label msg-via-label">
|
|
9285
|
+
<label class="form-label msg-via-label">{{ labels.t('messagingSendMessagePanel.sendVia') }}</label>
|
|
9197
9286
|
<div class="msg-via-tabs">
|
|
9198
9287
|
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
9199
|
-
<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>
|
|
9200
|
-
Email
|
|
9201
|
-
</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>
|
|
9202
9289
|
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
9203
|
-
<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>
|
|
9204
|
-
Text
|
|
9205
|
-
</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>
|
|
9206
9291
|
</div>
|
|
9207
9292
|
</div>
|
|
9208
9293
|
}
|
|
@@ -9219,8 +9304,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9219
9304
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
9220
9305
|
<div class="msg-job">
|
|
9221
9306
|
<ui-combobox
|
|
9222
|
-
[label]="jobLabel()" placeholder="
|
|
9223
|
-
[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"
|
|
9224
9309
|
[value]="jobValue()"
|
|
9225
9310
|
(searchChange)="jobSearch$.next($event)" (valueChange)="onJobPick($event)" />
|
|
9226
9311
|
</div>
|
|
@@ -9398,7 +9483,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9398
9483
|
required: false
|
|
9399
9484
|
}]
|
|
9400
9485
|
}],
|
|
9401
|
-
|
|
9486
|
+
titleInput: [{
|
|
9402
9487
|
type: i0.Input,
|
|
9403
9488
|
args: [{
|
|
9404
9489
|
isSignal: true,
|
|
@@ -9462,7 +9547,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9462
9547
|
required: false
|
|
9463
9548
|
}]
|
|
9464
9549
|
}],
|
|
9465
|
-
|
|
9550
|
+
receiptLabelInput: [{
|
|
9466
9551
|
type: i0.Input,
|
|
9467
9552
|
args: [{
|
|
9468
9553
|
isSignal: true,
|
|
@@ -9718,7 +9803,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9718
9803
|
required: false
|
|
9719
9804
|
}]
|
|
9720
9805
|
}],
|
|
9721
|
-
|
|
9806
|
+
jobLabelInput: [{
|
|
9722
9807
|
type: i0.Input,
|
|
9723
9808
|
args: [{
|
|
9724
9809
|
isSignal: true,
|