@forgeroute/ui 0.4.71 → 0.4.73
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-messaging.mjs +614 -100
- package/fesm2022/forgeroute-ui-messaging.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-pdf.mjs +3 -0
- package/fesm2022/forgeroute-ui-pdf.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-stripe.mjs +895 -3
- package/fesm2022/forgeroute-ui-stripe.mjs.map +1 -1
- package/fesm2022/forgeroute-ui.mjs +5987 -1848
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/forgeroute-ui-messaging.d.ts +191 -1
- package/types/forgeroute-ui-stripe.d.ts +162 -3
- package/types/forgeroute-ui.d.ts +1403 -28
|
@@ -4,8 +4,8 @@ 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, 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";
|
|
8
|
-
import { Subject, catchError, debounceTime, defer, distinctUntilChanged, map, of, switchMap, take } from "rxjs";
|
|
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";
|
|
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 {
|
|
11
11
|
optionId(i) {
|
|
@@ -1958,6 +1958,8 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1958
1958
|
inputs: [
|
|
1959
1959
|
"label",
|
|
1960
1960
|
"ariaLabel",
|
|
1961
|
+
"labelHidden",
|
|
1962
|
+
"inputName",
|
|
1961
1963
|
"placeholder",
|
|
1962
1964
|
"options",
|
|
1963
1965
|
"valueType",
|
|
@@ -2080,8 +2082,10 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
2080
2082
|
"label",
|
|
2081
2083
|
"ariaLabel",
|
|
2082
2084
|
"inputTestId",
|
|
2085
|
+
"inputName",
|
|
2083
2086
|
"placeholder",
|
|
2084
2087
|
"prefix",
|
|
2088
|
+
"leadingIcon",
|
|
2085
2089
|
"revealable",
|
|
2086
2090
|
"passwordRequirements",
|
|
2087
2091
|
"passwordRules",
|
|
@@ -3287,6 +3291,8 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3287
3291
|
inputs: [
|
|
3288
3292
|
"label",
|
|
3289
3293
|
"ariaLabel",
|
|
3294
|
+
"labelHidden",
|
|
3295
|
+
"inputName",
|
|
3290
3296
|
"placeholder",
|
|
3291
3297
|
"options",
|
|
3292
3298
|
"valueType",
|
|
@@ -3308,8 +3314,10 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3308
3314
|
"label",
|
|
3309
3315
|
"ariaLabel",
|
|
3310
3316
|
"inputTestId",
|
|
3317
|
+
"inputName",
|
|
3311
3318
|
"placeholder",
|
|
3312
3319
|
"prefix",
|
|
3320
|
+
"leadingIcon",
|
|
3313
3321
|
"revealable",
|
|
3314
3322
|
"passwordRequirements",
|
|
3315
3323
|
"passwordRules",
|
|
@@ -3526,8 +3534,18 @@ function applyMergeTags(text, values) {
|
|
|
3526
3534
|
return v != null && String(v).trim() !== "" ? String(v) : whole;
|
|
3527
3535
|
});
|
|
3528
3536
|
}
|
|
3529
|
-
|
|
3530
|
-
|
|
3537
|
+
const PERSONAL_TAG_KEYS = [
|
|
3538
|
+
"first_name",
|
|
3539
|
+
"last_name",
|
|
3540
|
+
"full_name",
|
|
3541
|
+
"name",
|
|
3542
|
+
"email",
|
|
3543
|
+
"phone"
|
|
3544
|
+
];
|
|
3545
|
+
function hasLeftoverTags(text, ignoreKeys = []) {
|
|
3546
|
+
const t = text ?? "";
|
|
3547
|
+
if (ignoreKeys.length === 0) return ANY_TAG_RE.test(t);
|
|
3548
|
+
return ANY_TAG_RE.test(t.replace(TAG_RE, (whole, k) => ignoreKeys.includes(k) ? "" : whole));
|
|
3531
3549
|
}
|
|
3532
3550
|
function nonBlankValues(...sources) {
|
|
3533
3551
|
const out = {};
|
|
@@ -3561,6 +3579,7 @@ function marketVarsFrom(resp) {
|
|
|
3561
3579
|
function formatVarLabel(key) {
|
|
3562
3580
|
return key.replace(/[_.]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3563
3581
|
}
|
|
3582
|
+
const BULK_NO_SEND_MESSAGE = "Sending to several recipients is not set up for this page, so nothing was sent.";
|
|
3564
3583
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3565
3584
|
function messagePreviewHtml(body) {
|
|
3566
3585
|
if (!body) return "";
|
|
@@ -3569,6 +3588,9 @@ function messagePreviewHtml(body) {
|
|
|
3569
3588
|
}
|
|
3570
3589
|
const NO_DOCUMENTS$1 = [];
|
|
3571
3590
|
var SendEmailComponent = class SendEmailComponent {
|
|
3591
|
+
get deferredKeys() {
|
|
3592
|
+
return this.bulk() ? PERSONAL_TAG_KEYS : [];
|
|
3593
|
+
}
|
|
3572
3594
|
ngOnInit() {
|
|
3573
3595
|
this.includeReceipt = this.receiptDefault();
|
|
3574
3596
|
this.http.get(`${this.apiBase}/service-areas?size=100`).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ next: (resp) => {
|
|
@@ -3586,6 +3608,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3586
3608
|
this.contactEmail = input("", ...ngDevMode ? [{ debugName: "contactEmail" }] : /* istanbul ignore next */ []);
|
|
3587
3609
|
this.contactPhone = input("", ...ngDevMode ? [{ debugName: "contactPhone" }] : /* istanbul ignore next */ []);
|
|
3588
3610
|
this.contactId = input("", ...ngDevMode ? [{ debugName: "contactId" }] : /* istanbul ignore next */ []);
|
|
3611
|
+
this.bulkRecipients = input(null, ...ngDevMode ? [{ debugName: "bulkRecipients" }] : /* istanbul ignore next */ []);
|
|
3612
|
+
this.bulk = computed(() => this.bulkRecipients() !== null, ...ngDevMode ? [{ debugName: "bulk" }] : /* istanbul ignore next */ []);
|
|
3589
3613
|
this.defaultSubject = input("", ...ngDevMode ? [{ debugName: "defaultSubject" }] : /* istanbul ignore next */ []);
|
|
3590
3614
|
this.defaultBody = input("", ...ngDevMode ? [{ debugName: "defaultBody" }] : /* istanbul ignore next */ []);
|
|
3591
3615
|
this.context = input({}, ...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
@@ -3626,6 +3650,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3626
3650
|
this.showTemplates = input(true, ...ngDevMode ? [{ debugName: "showTemplates" }] : /* istanbul ignore next */ []);
|
|
3627
3651
|
this.showVideo = input(true, ...ngDevMode ? [{ debugName: "showVideo" }] : /* istanbul ignore next */ []);
|
|
3628
3652
|
this.sent = output();
|
|
3653
|
+
this.bulkResult = output();
|
|
3654
|
+
this.bulkSending = output();
|
|
3629
3655
|
this.emailAdded = output();
|
|
3630
3656
|
this.validChange = output();
|
|
3631
3657
|
this.rejected = output();
|
|
@@ -3684,6 +3710,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3684
3710
|
this.contactEmail();
|
|
3685
3711
|
this.contactId();
|
|
3686
3712
|
this.context();
|
|
3713
|
+
this.bulkRecipients();
|
|
3687
3714
|
untracked(() => this.notifyValid());
|
|
3688
3715
|
});
|
|
3689
3716
|
effect(() => {
|
|
@@ -3823,7 +3850,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3823
3850
|
if (this.ccError || this.documents() && this.documentsInvalid) return false;
|
|
3824
3851
|
if (this.signersActive && (this.signersInvalid || !this.signersValue)) return false;
|
|
3825
3852
|
if (this.viaDocuSign && !this.contactId()) return false;
|
|
3826
|
-
const hasContent = (this.viaDocuSign || (!this.showSubject() || !!this.subject.trim()) && !!this.body.trim()) && this.unresolvedVars.length === 0 && !hasLeftoverTags(this.resolvedSubject) && !hasLeftoverTags(this.resolvedBody);
|
|
3853
|
+
const hasContent = (this.viaDocuSign || (!this.showSubject() || !!this.subject.trim()) && !!this.body.trim()) && this.unresolvedVars.length === 0 && !hasLeftoverTags(this.resolvedSubject, this.deferredKeys) && !hasLeftoverTags(this.resolvedBody, this.deferredKeys);
|
|
3827
3854
|
if (this.showSchedule) return hasContent && !!this.scheduledAt && new Date(this.scheduledAt).getTime() > Date.now();
|
|
3828
3855
|
return hasContent;
|
|
3829
3856
|
}
|
|
@@ -3833,7 +3860,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3833
3860
|
get knownVars() {
|
|
3834
3861
|
const name = this.contactName().trim();
|
|
3835
3862
|
const parts = name.split(/\s+/);
|
|
3836
|
-
return nonBlankValues({
|
|
3863
|
+
return nonBlankValues(this.bulk() ? {} : {
|
|
3837
3864
|
first_name: parts[0] ?? "",
|
|
3838
3865
|
last_name: parts.slice(1).join(" "),
|
|
3839
3866
|
full_name: name,
|
|
@@ -3870,11 +3897,11 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3870
3897
|
}
|
|
3871
3898
|
get missingVars() {
|
|
3872
3899
|
const known = this.knownVars;
|
|
3873
|
-
return mergeTagKeys(this.subject + " " + this.body).filter((k) => !known[k]);
|
|
3900
|
+
return mergeTagKeys(this.subject + " " + this.body).filter((k) => !known[k] && !this.deferredKeys.includes(k));
|
|
3874
3901
|
}
|
|
3875
3902
|
get composeTagError() {
|
|
3876
3903
|
if (this.mode !== "compose") return "";
|
|
3877
|
-
return hasLeftoverTags(this.resolvedSubject) || hasLeftoverTags(this.resolvedBody) ? "Replace every {{…}} field with text before sending." : "";
|
|
3904
|
+
return hasLeftoverTags(this.resolvedSubject, this.deferredKeys) || hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "Replace every {{…}} field with text before sending." : "";
|
|
3878
3905
|
}
|
|
3879
3906
|
get unresolvedVars() {
|
|
3880
3907
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -3916,7 +3943,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3916
3943
|
this.cdr.markForCheck();
|
|
3917
3944
|
}
|
|
3918
3945
|
notifyValid() {
|
|
3919
|
-
this.validChange.emit(!!this.contactEmail() && this.canSend);
|
|
3946
|
+
this.validChange.emit((this.bulk() || !!this.contactEmail()) && this.canSend);
|
|
3920
3947
|
this.cdr.markForCheck();
|
|
3921
3948
|
}
|
|
3922
3949
|
setMode(key) {
|
|
@@ -4036,7 +4063,11 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4036
4063
|
this.videoPickerKey++;
|
|
4037
4064
|
}
|
|
4038
4065
|
submit() {
|
|
4039
|
-
if (!this.canSend || this.loading || !this.contactEmail()) return;
|
|
4066
|
+
if (!this.canSend || this.loading || !this.bulk() && !this.contactEmail()) return;
|
|
4067
|
+
if (this.bulk() && !this.sendFn()) {
|
|
4068
|
+
this.toast.error(BULK_NO_SEND_MESSAGE);
|
|
4069
|
+
return;
|
|
4070
|
+
}
|
|
4040
4071
|
if (this.mode === "template") this.applyPendingVars();
|
|
4041
4072
|
this.loading = true;
|
|
4042
4073
|
this.cdr.markForCheck();
|
|
@@ -4054,6 +4085,10 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4054
4085
|
scheduledAt: this.showSchedule && this.scheduledAt ? new Date(this.scheduledAt).toISOString() : void 0,
|
|
4055
4086
|
attachments: attachments.length ? attachments : void 0
|
|
4056
4087
|
};
|
|
4088
|
+
if (this.bulk()) {
|
|
4089
|
+
payload.recipients = [...this.bulkRecipients()];
|
|
4090
|
+
this.bulkSending.emit(payload.recipients);
|
|
4091
|
+
}
|
|
4057
4092
|
if (this.showReceiptOption() === true) payload.includeReceipt = this.includeReceipt;
|
|
4058
4093
|
if (this.mode === "template" && this.templateId) payload.templateId = this.templateId;
|
|
4059
4094
|
const cc = this.ccList;
|
|
@@ -4069,7 +4104,14 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4069
4104
|
payload.scheduledAt = void 0;
|
|
4070
4105
|
}
|
|
4071
4106
|
const custom = this.sendFn();
|
|
4072
|
-
|
|
4107
|
+
const safeHostCall = () => {
|
|
4108
|
+
try {
|
|
4109
|
+
return custom(payload);
|
|
4110
|
+
} catch (e) {
|
|
4111
|
+
return throwError(() => e);
|
|
4112
|
+
}
|
|
4113
|
+
};
|
|
4114
|
+
const req$ = custom && this.bulk() ? safeHostCall() : custom ? custom(payload) : docs?.provider === "DOCUSIGN" ? sendDocuSignRequest(this.http, this.apiBase, this.docuSignBody(docs, payload)) : docs && this.documentEnvelope() ? sendExistingEnvelope(this.http, this.apiBase, this.documentEnvelope().id, {
|
|
4073
4115
|
subject: payload.subject || "Document Signature Required",
|
|
4074
4116
|
message: payload.body,
|
|
4075
4117
|
customerId: payload.contactId,
|
|
@@ -4093,8 +4135,22 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4093
4135
|
...cc.length ? { ccEmails: cc } : {},
|
|
4094
4136
|
...signingBodyFields(payload.documents),
|
|
4095
4137
|
...signersContextBodyFields(payload.documents)
|
|
4096
|
-
}, payload.templateId) : this.http.post(`${this.apiBase}/email-messages`, payload)
|
|
4097
|
-
|
|
4138
|
+
}, payload.templateId) : this.http.post(`${this.apiBase}/email-messages`, payload);
|
|
4139
|
+
let destroyed = false;
|
|
4140
|
+
this.destroyRef.onDestroy(() => {
|
|
4141
|
+
destroyed = true;
|
|
4142
|
+
});
|
|
4143
|
+
const onError = (err) => {
|
|
4144
|
+
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
4145
|
+
this.toast.error(custom || docs ? getErrorMessage(err, "email", "send") : serverMessage(err) || "Failed to send email");
|
|
4146
|
+
this.loading = false;
|
|
4147
|
+
this.cdr.markForCheck();
|
|
4148
|
+
if (this.bulk()) this.bulkSending.emit(null);
|
|
4149
|
+
const status = err?.status;
|
|
4150
|
+
if (docs && (status === 404 || status === 409)) this.rejected.emit();
|
|
4151
|
+
};
|
|
4152
|
+
req$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
4153
|
+
next: (result) => {
|
|
4098
4154
|
const sentText = docs ? this.documentSentMessage()?.({
|
|
4099
4155
|
titles: docs.documents.map((d) => d.title),
|
|
4100
4156
|
envelopeName: this.documentEnvelope()?.name,
|
|
@@ -4106,15 +4162,16 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4106
4162
|
this.loading = false;
|
|
4107
4163
|
this.attachments = [];
|
|
4108
4164
|
this.includeReceipt = this.receiptDefault();
|
|
4165
|
+
if (this.bulk()) this.bulkResult.emit({
|
|
4166
|
+
result,
|
|
4167
|
+
recipients: payload.recipients ?? []
|
|
4168
|
+
});
|
|
4109
4169
|
this.sent.emit();
|
|
4110
4170
|
this.cdr.markForCheck();
|
|
4111
4171
|
},
|
|
4112
|
-
error:
|
|
4113
|
-
|
|
4114
|
-
this.loading
|
|
4115
|
-
this.cdr.markForCheck();
|
|
4116
|
-
const status = err?.status;
|
|
4117
|
-
if (docs && (status === 404 || status === 409)) this.rejected.emit();
|
|
4172
|
+
error: onError,
|
|
4173
|
+
complete: () => {
|
|
4174
|
+
if (!destroyed && this.bulk() && this.loading) onError(null);
|
|
4118
4175
|
}
|
|
4119
4176
|
});
|
|
4120
4177
|
}
|
|
@@ -4164,6 +4221,13 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4164
4221
|
isRequired: false,
|
|
4165
4222
|
transformFunction: null
|
|
4166
4223
|
},
|
|
4224
|
+
bulkRecipients: {
|
|
4225
|
+
classPropertyName: "bulkRecipients",
|
|
4226
|
+
publicName: "bulkRecipients",
|
|
4227
|
+
isSignal: true,
|
|
4228
|
+
isRequired: false,
|
|
4229
|
+
transformFunction: null
|
|
4230
|
+
},
|
|
4167
4231
|
defaultSubject: {
|
|
4168
4232
|
classPropertyName: "defaultSubject",
|
|
4169
4233
|
publicName: "defaultSubject",
|
|
@@ -4349,6 +4413,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4349
4413
|
},
|
|
4350
4414
|
outputs: {
|
|
4351
4415
|
sent: "sent",
|
|
4416
|
+
bulkResult: "bulkResult",
|
|
4417
|
+
bulkSending: "bulkSending",
|
|
4352
4418
|
emailAdded: "emailAdded",
|
|
4353
4419
|
validChange: "validChange",
|
|
4354
4420
|
rejected: "rejected",
|
|
@@ -4357,7 +4423,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4357
4423
|
ngImport: i0,
|
|
4358
4424
|
template: `
|
|
4359
4425
|
<!-- Missing email guard -->
|
|
4360
|
-
@if (!contactEmail()) {
|
|
4426
|
+
@if (!bulk() && !contactEmail()) {
|
|
4361
4427
|
<div class="sm-missing-banner">
|
|
4362
4428
|
<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>
|
|
4363
4429
|
No email address on file for this contact.
|
|
@@ -4374,7 +4440,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4374
4440
|
Save & Continue
|
|
4375
4441
|
</ui-button>
|
|
4376
4442
|
} @else {
|
|
4377
|
-
<!-- To -->
|
|
4443
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
4444
|
+
@if (!bulk()) {
|
|
4378
4445
|
<div class="sm-group">
|
|
4379
4446
|
<span class="sm-group-label">To</span>
|
|
4380
4447
|
<div class="sm-to-card">
|
|
@@ -4382,6 +4449,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4382
4449
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
4383
4450
|
</div>
|
|
4384
4451
|
</div>
|
|
4452
|
+
}
|
|
4385
4453
|
|
|
4386
4454
|
<ui-error errorId="sm-email-disabled" [message]="emailEnabled() ? '' : EMAIL_DISABLED_MESSAGE" />
|
|
4387
4455
|
|
|
@@ -4608,7 +4676,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4608
4676
|
<div class="sp-email-meta">
|
|
4609
4677
|
<div class="sp-meta-row">
|
|
4610
4678
|
<span class="sp-meta-label">To</span>
|
|
4611
|
-
<span class="sp-meta-value"
|
|
4679
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} <{{ contactEmail() }}> }</span>
|
|
4612
4680
|
</div>
|
|
4613
4681
|
<div class="sp-meta-row">
|
|
4614
4682
|
<span class="sp-meta-label">Subject</span>
|
|
@@ -4728,7 +4796,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4728
4796
|
"ariaLabel",
|
|
4729
4797
|
"name",
|
|
4730
4798
|
"noWrap",
|
|
4731
|
-
"orientation"
|
|
4799
|
+
"orientation",
|
|
4800
|
+
"controlsPanels"
|
|
4732
4801
|
],
|
|
4733
4802
|
outputs: ["tabChange"]
|
|
4734
4803
|
},
|
|
@@ -4768,8 +4837,10 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4768
4837
|
"label",
|
|
4769
4838
|
"ariaLabel",
|
|
4770
4839
|
"inputTestId",
|
|
4840
|
+
"inputName",
|
|
4771
4841
|
"placeholder",
|
|
4772
4842
|
"prefix",
|
|
4843
|
+
"leadingIcon",
|
|
4773
4844
|
"revealable",
|
|
4774
4845
|
"passwordRequirements",
|
|
4775
4846
|
"passwordRules",
|
|
@@ -4965,7 +5036,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4965
5036
|
],
|
|
4966
5037
|
template: `
|
|
4967
5038
|
<!-- Missing email guard -->
|
|
4968
|
-
@if (!contactEmail()) {
|
|
5039
|
+
@if (!bulk() && !contactEmail()) {
|
|
4969
5040
|
<div class="sm-missing-banner">
|
|
4970
5041
|
<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>
|
|
4971
5042
|
No email address on file for this contact.
|
|
@@ -4982,7 +5053,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4982
5053
|
Save & Continue
|
|
4983
5054
|
</ui-button>
|
|
4984
5055
|
} @else {
|
|
4985
|
-
<!-- To -->
|
|
5056
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
5057
|
+
@if (!bulk()) {
|
|
4986
5058
|
<div class="sm-group">
|
|
4987
5059
|
<span class="sm-group-label">To</span>
|
|
4988
5060
|
<div class="sm-to-card">
|
|
@@ -4990,6 +5062,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4990
5062
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
4991
5063
|
</div>
|
|
4992
5064
|
</div>
|
|
5065
|
+
}
|
|
4993
5066
|
|
|
4994
5067
|
<ui-error errorId="sm-email-disabled" [message]="emailEnabled() ? '' : EMAIL_DISABLED_MESSAGE" />
|
|
4995
5068
|
|
|
@@ -5216,7 +5289,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5216
5289
|
<div class="sp-email-meta">
|
|
5217
5290
|
<div class="sp-meta-row">
|
|
5218
5291
|
<span class="sp-meta-label">To</span>
|
|
5219
|
-
<span class="sp-meta-value"
|
|
5292
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} <{{ contactEmail() }}> }</span>
|
|
5220
5293
|
</div>
|
|
5221
5294
|
<div class="sp-meta-row">
|
|
5222
5295
|
<span class="sp-meta-label">Subject</span>
|
|
@@ -5265,6 +5338,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5265
5338
|
required: false
|
|
5266
5339
|
}]
|
|
5267
5340
|
}],
|
|
5341
|
+
bulkRecipients: [{
|
|
5342
|
+
type: i0.Input,
|
|
5343
|
+
args: [{
|
|
5344
|
+
isSignal: true,
|
|
5345
|
+
alias: "bulkRecipients",
|
|
5346
|
+
required: false
|
|
5347
|
+
}]
|
|
5348
|
+
}],
|
|
5268
5349
|
defaultSubject: [{
|
|
5269
5350
|
type: i0.Input,
|
|
5270
5351
|
args: [{
|
|
@@ -5477,6 +5558,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5477
5558
|
type: i0.Output,
|
|
5478
5559
|
args: ["sent"]
|
|
5479
5560
|
}],
|
|
5561
|
+
bulkResult: [{
|
|
5562
|
+
type: i0.Output,
|
|
5563
|
+
args: ["bulkResult"]
|
|
5564
|
+
}],
|
|
5565
|
+
bulkSending: [{
|
|
5566
|
+
type: i0.Output,
|
|
5567
|
+
args: ["bulkSending"]
|
|
5568
|
+
}],
|
|
5480
5569
|
emailAdded: [{
|
|
5481
5570
|
type: i0.Output,
|
|
5482
5571
|
args: ["emailAdded"]
|
|
@@ -5798,8 +5887,10 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5798
5887
|
"label",
|
|
5799
5888
|
"ariaLabel",
|
|
5800
5889
|
"inputTestId",
|
|
5890
|
+
"inputName",
|
|
5801
5891
|
"placeholder",
|
|
5802
5892
|
"prefix",
|
|
5893
|
+
"leadingIcon",
|
|
5803
5894
|
"revealable",
|
|
5804
5895
|
"passwordRequirements",
|
|
5805
5896
|
"passwordRules",
|
|
@@ -6063,6 +6154,9 @@ function formatPhone(raw) {
|
|
|
6063
6154
|
}
|
|
6064
6155
|
const NO_DOCUMENTS = [];
|
|
6065
6156
|
var SendTextComponent = class SendTextComponent {
|
|
6157
|
+
get deferredKeys() {
|
|
6158
|
+
return this.bulk() ? PERSONAL_TAG_KEYS : [];
|
|
6159
|
+
}
|
|
6066
6160
|
ngOnInit() {
|
|
6067
6161
|
this.http.get(`${this.apiBase}/service-areas?size=100`).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ next: (resp) => {
|
|
6068
6162
|
this.marketVars = marketVarsFrom(resp);
|
|
@@ -6080,6 +6174,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6080
6174
|
this.contactPhone = input("", ...ngDevMode ? [{ debugName: "contactPhone" }] : /* istanbul ignore next */ []);
|
|
6081
6175
|
this.contactEmail = input("", ...ngDevMode ? [{ debugName: "contactEmail" }] : /* istanbul ignore next */ []);
|
|
6082
6176
|
this.contactId = input("", ...ngDevMode ? [{ debugName: "contactId" }] : /* istanbul ignore next */ []);
|
|
6177
|
+
this.bulkRecipients = input(null, ...ngDevMode ? [{ debugName: "bulkRecipients" }] : /* istanbul ignore next */ []);
|
|
6178
|
+
this.bulk = computed(() => this.bulkRecipients() !== null, ...ngDevMode ? [{ debugName: "bulk" }] : /* istanbul ignore next */ []);
|
|
6083
6179
|
this.defaultBody = input("", ...ngDevMode ? [{ debugName: "defaultBody" }] : /* istanbul ignore next */ []);
|
|
6084
6180
|
this.context = input({}, ...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
6085
6181
|
this.sendFn = input(null, ...ngDevMode ? [{ debugName: "sendFn" }] : /* istanbul ignore next */ []);
|
|
@@ -6112,6 +6208,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6112
6208
|
}, ...ngDevMode ? [{ debugName: "previewContact" }] : /* istanbul ignore next */ []);
|
|
6113
6209
|
this.videoDefaults = input(null, ...ngDevMode ? [{ debugName: "videoDefaults" }] : /* istanbul ignore next */ []);
|
|
6114
6210
|
this.sent = output();
|
|
6211
|
+
this.bulkResult = output();
|
|
6212
|
+
this.bulkSending = output();
|
|
6115
6213
|
this.phoneAdded = output();
|
|
6116
6214
|
this.validChange = output();
|
|
6117
6215
|
this.rejected = output();
|
|
@@ -6158,6 +6256,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6158
6256
|
this.contactPhone();
|
|
6159
6257
|
this.contactId();
|
|
6160
6258
|
this.context();
|
|
6259
|
+
this.bulkRecipients();
|
|
6161
6260
|
untracked(() => this.notifyValid());
|
|
6162
6261
|
});
|
|
6163
6262
|
effect(() => {
|
|
@@ -6218,7 +6317,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6218
6317
|
get canSend() {
|
|
6219
6318
|
if (this.documents() && this.documentsInvalid) return false;
|
|
6220
6319
|
if (this._videoLine && this.body.length > this.MAX_LENGTH) return false;
|
|
6221
|
-
const hasBody = this.body.trim().length > 0 && this.unresolvedVars.length === 0 && !hasLeftoverTags(this.resolvedBody);
|
|
6320
|
+
const hasBody = this.body.trim().length > 0 && this.unresolvedVars.length === 0 && !hasLeftoverTags(this.resolvedBody, this.deferredKeys);
|
|
6222
6321
|
if (this.showSchedule) return hasBody && !!this.scheduledAt && new Date(this.scheduledAt).getTime() > Date.now();
|
|
6223
6322
|
return hasBody;
|
|
6224
6323
|
}
|
|
@@ -6228,7 +6327,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6228
6327
|
get knownVars() {
|
|
6229
6328
|
const name = this.contactName().trim();
|
|
6230
6329
|
const parts = name.split(/\s+/);
|
|
6231
|
-
return nonBlankValues({
|
|
6330
|
+
return nonBlankValues(this.bulk() ? {} : {
|
|
6232
6331
|
first_name: parts[0] ?? "",
|
|
6233
6332
|
last_name: parts.slice(1).join(" "),
|
|
6234
6333
|
full_name: name,
|
|
@@ -6253,13 +6352,13 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6253
6352
|
}
|
|
6254
6353
|
get missingVars() {
|
|
6255
6354
|
const known = this.knownVars;
|
|
6256
|
-
return mergeTagKeys(this.body).filter((k) => !known[k]);
|
|
6355
|
+
return mergeTagKeys(this.body).filter((k) => !known[k] && !this.deferredKeys.includes(k));
|
|
6257
6356
|
}
|
|
6258
6357
|
get videoLengthError() {
|
|
6259
6358
|
return this._videoLine && this.body.length > this.MAX_LENGTH ? `The video link makes this text longer than ${this.MAX_LENGTH} characters. Shorten the message or remove the video.` : "";
|
|
6260
6359
|
}
|
|
6261
6360
|
get composeTagError() {
|
|
6262
|
-
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody) ? "Replace every {{…}} field with text before sending." : "";
|
|
6361
|
+
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "Replace every {{…}} field with text before sending." : "";
|
|
6263
6362
|
}
|
|
6264
6363
|
get unresolvedVars() {
|
|
6265
6364
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -6303,7 +6402,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6303
6402
|
this.notifyValid();
|
|
6304
6403
|
}
|
|
6305
6404
|
notifyValid() {
|
|
6306
|
-
this.validChange.emit(!!this.contactPhone() && this.canSend);
|
|
6405
|
+
this.validChange.emit((this.bulk() || !!this.contactPhone()) && this.canSend);
|
|
6307
6406
|
this.cdr.detectChanges();
|
|
6308
6407
|
}
|
|
6309
6408
|
setMode(key) {
|
|
@@ -6404,7 +6503,11 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6404
6503
|
this.videoPickerKey++;
|
|
6405
6504
|
}
|
|
6406
6505
|
submit() {
|
|
6407
|
-
if (!this.canSend || this.loading || !this.contactPhone()) return;
|
|
6506
|
+
if (!this.canSend || this.loading || !this.bulk() && !this.contactPhone()) return;
|
|
6507
|
+
if (this.bulk() && !this.sendFn()) {
|
|
6508
|
+
this.toast.error(BULK_NO_SEND_MESSAGE);
|
|
6509
|
+
return;
|
|
6510
|
+
}
|
|
6408
6511
|
if (this.mode === "template") this.applyPendingVars();
|
|
6409
6512
|
this.loading = true;
|
|
6410
6513
|
this.cdr.detectChanges();
|
|
@@ -6419,6 +6522,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6419
6522
|
mediaType: media?.mediaType ?? void 0,
|
|
6420
6523
|
mediaFileName: media?.mediaFileName ?? void 0
|
|
6421
6524
|
};
|
|
6525
|
+
if (this.bulk()) {
|
|
6526
|
+
payload.recipients = [...this.bulkRecipients()];
|
|
6527
|
+
this.bulkSending.emit(payload.recipients);
|
|
6528
|
+
}
|
|
6422
6529
|
if (this.mode === "template" && this.templateId) payload.templateId = this.templateId;
|
|
6423
6530
|
const docs = this.hasDocuments ? this.documentsValue : null;
|
|
6424
6531
|
if (docs) {
|
|
@@ -6432,7 +6539,14 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6432
6539
|
payload.scheduledAt = void 0;
|
|
6433
6540
|
}
|
|
6434
6541
|
const custom = this.sendFn();
|
|
6435
|
-
|
|
6542
|
+
const safeHostCall = () => {
|
|
6543
|
+
try {
|
|
6544
|
+
return custom(payload);
|
|
6545
|
+
} catch (e) {
|
|
6546
|
+
return throwError(() => e);
|
|
6547
|
+
}
|
|
6548
|
+
};
|
|
6549
|
+
const req$ = custom && this.bulk() ? safeHostCall() : custom ? custom(payload) : docs && this.documentEnvelope() ? sendExistingEnvelope(this.http, this.apiBase, this.documentEnvelope().id, {
|
|
6436
6550
|
subject: DEFAULT_DOCUMENT_SUBJECT,
|
|
6437
6551
|
message: payload.body,
|
|
6438
6552
|
customerId: payload.contactId,
|
|
@@ -6456,8 +6570,22 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6456
6570
|
delivery: "TEXT",
|
|
6457
6571
|
...signingBodyFields(payload.documents),
|
|
6458
6572
|
...signersContextBodyFields(payload.documents)
|
|
6459
|
-
}, payload.templateId) : this.http.post(`${this.apiBase}/text-messages`, payload)
|
|
6460
|
-
|
|
6573
|
+
}, payload.templateId) : this.http.post(`${this.apiBase}/text-messages`, payload);
|
|
6574
|
+
let destroyed = false;
|
|
6575
|
+
this.destroyRef.onDestroy(() => {
|
|
6576
|
+
destroyed = true;
|
|
6577
|
+
});
|
|
6578
|
+
const onError = (err) => {
|
|
6579
|
+
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
6580
|
+
this.toast.error(custom || docs ? getErrorMessage(err, "text message", "send") : serverMessage(err) || "Failed to send text message");
|
|
6581
|
+
this.loading = false;
|
|
6582
|
+
this.cdr.detectChanges();
|
|
6583
|
+
if (this.bulk()) this.bulkSending.emit(null);
|
|
6584
|
+
const status = err?.status;
|
|
6585
|
+
if (docs && (status === 404 || status === 409)) this.rejected.emit();
|
|
6586
|
+
};
|
|
6587
|
+
req$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
6588
|
+
next: (result) => {
|
|
6461
6589
|
const sentText = docs ? this.documentSentMessage()?.({
|
|
6462
6590
|
titles: docs.documents.map((d) => d.title),
|
|
6463
6591
|
envelopeName: this.documentEnvelope()?.name,
|
|
@@ -6467,15 +6595,16 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6467
6595
|
this.toast.show(sentText ?? (docs && this.documentEnvelope() ? `Envelope "${this.documentEnvelope().name}" sent` : this.showSchedule ? "Message scheduled" : "Text message sent"));
|
|
6468
6596
|
this.loading = false;
|
|
6469
6597
|
this.mediaAttachment.set(null);
|
|
6598
|
+
if (this.bulk()) this.bulkResult.emit({
|
|
6599
|
+
result,
|
|
6600
|
+
recipients: payload.recipients ?? []
|
|
6601
|
+
});
|
|
6470
6602
|
this.sent.emit();
|
|
6471
6603
|
this.cdr.detectChanges();
|
|
6472
6604
|
},
|
|
6473
|
-
error:
|
|
6474
|
-
|
|
6475
|
-
this.loading
|
|
6476
|
-
this.cdr.detectChanges();
|
|
6477
|
-
const status = err?.status;
|
|
6478
|
-
if (docs && (status === 404 || status === 409)) this.rejected.emit();
|
|
6605
|
+
error: onError,
|
|
6606
|
+
complete: () => {
|
|
6607
|
+
if (!destroyed && this.bulk() && this.loading) onError(null);
|
|
6479
6608
|
}
|
|
6480
6609
|
});
|
|
6481
6610
|
}
|
|
@@ -6525,6 +6654,13 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6525
6654
|
isRequired: false,
|
|
6526
6655
|
transformFunction: null
|
|
6527
6656
|
},
|
|
6657
|
+
bulkRecipients: {
|
|
6658
|
+
classPropertyName: "bulkRecipients",
|
|
6659
|
+
publicName: "bulkRecipients",
|
|
6660
|
+
isSignal: true,
|
|
6661
|
+
isRequired: false,
|
|
6662
|
+
transformFunction: null
|
|
6663
|
+
},
|
|
6528
6664
|
defaultBody: {
|
|
6529
6665
|
classPropertyName: "defaultBody",
|
|
6530
6666
|
publicName: "defaultBody",
|
|
@@ -6654,6 +6790,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6654
6790
|
},
|
|
6655
6791
|
outputs: {
|
|
6656
6792
|
sent: "sent",
|
|
6793
|
+
bulkResult: "bulkResult",
|
|
6794
|
+
bulkSending: "bulkSending",
|
|
6657
6795
|
phoneAdded: "phoneAdded",
|
|
6658
6796
|
validChange: "validChange",
|
|
6659
6797
|
rejected: "rejected"
|
|
@@ -6661,7 +6799,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6661
6799
|
ngImport: i0,
|
|
6662
6800
|
template: `
|
|
6663
6801
|
<!-- Missing phone guard -->
|
|
6664
|
-
@if (!contactPhone()) {
|
|
6802
|
+
@if (!bulk() && !contactPhone()) {
|
|
6665
6803
|
<div class="sm-missing-banner">
|
|
6666
6804
|
<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>
|
|
6667
6805
|
No phone number on file for this contact.
|
|
@@ -6678,7 +6816,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6678
6816
|
Save & Continue
|
|
6679
6817
|
</ui-button>
|
|
6680
6818
|
} @else {
|
|
6681
|
-
<!-- To -->
|
|
6819
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
6820
|
+
@if (!bulk()) {
|
|
6682
6821
|
<div class="sm-group">
|
|
6683
6822
|
<span class="sm-group-label">To</span>
|
|
6684
6823
|
<div class="sm-to-card">
|
|
@@ -6686,6 +6825,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6686
6825
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
6687
6826
|
</div>
|
|
6688
6827
|
</div>
|
|
6828
|
+
}
|
|
6689
6829
|
|
|
6690
6830
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
6691
6831
|
@if (showTemplates()) {
|
|
@@ -6869,7 +7009,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6869
7009
|
<div class="sp-text-meta">
|
|
6870
7010
|
<div class="sp-meta-row">
|
|
6871
7011
|
<span class="sp-meta-label">To</span>
|
|
6872
|
-
<span class="sp-meta-value"
|
|
7012
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} {{ formatPhone(contactPhone()) }} }</span>
|
|
6873
7013
|
</div>
|
|
6874
7014
|
</div>
|
|
6875
7015
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7003,7 +7143,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7003
7143
|
"ariaLabel",
|
|
7004
7144
|
"name",
|
|
7005
7145
|
"noWrap",
|
|
7006
|
-
"orientation"
|
|
7146
|
+
"orientation",
|
|
7147
|
+
"controlsPanels"
|
|
7007
7148
|
],
|
|
7008
7149
|
outputs: ["tabChange"]
|
|
7009
7150
|
},
|
|
@@ -7043,8 +7184,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7043
7184
|
"label",
|
|
7044
7185
|
"ariaLabel",
|
|
7045
7186
|
"inputTestId",
|
|
7187
|
+
"inputName",
|
|
7046
7188
|
"placeholder",
|
|
7047
7189
|
"prefix",
|
|
7190
|
+
"leadingIcon",
|
|
7048
7191
|
"revealable",
|
|
7049
7192
|
"passwordRequirements",
|
|
7050
7193
|
"passwordRules",
|
|
@@ -7215,7 +7358,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7215
7358
|
],
|
|
7216
7359
|
template: `
|
|
7217
7360
|
<!-- Missing phone guard -->
|
|
7218
|
-
@if (!contactPhone()) {
|
|
7361
|
+
@if (!bulk() && !contactPhone()) {
|
|
7219
7362
|
<div class="sm-missing-banner">
|
|
7220
7363
|
<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>
|
|
7221
7364
|
No phone number on file for this contact.
|
|
@@ -7232,7 +7375,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7232
7375
|
Save & Continue
|
|
7233
7376
|
</ui-button>
|
|
7234
7377
|
} @else {
|
|
7235
|
-
<!-- To -->
|
|
7378
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
7379
|
+
@if (!bulk()) {
|
|
7236
7380
|
<div class="sm-group">
|
|
7237
7381
|
<span class="sm-group-label">To</span>
|
|
7238
7382
|
<div class="sm-to-card">
|
|
@@ -7240,6 +7384,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7240
7384
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
7241
7385
|
</div>
|
|
7242
7386
|
</div>
|
|
7387
|
+
}
|
|
7243
7388
|
|
|
7244
7389
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
7245
7390
|
@if (showTemplates()) {
|
|
@@ -7423,7 +7568,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7423
7568
|
<div class="sp-text-meta">
|
|
7424
7569
|
<div class="sp-meta-row">
|
|
7425
7570
|
<span class="sp-meta-label">To</span>
|
|
7426
|
-
<span class="sp-meta-value"
|
|
7571
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} {{ formatPhone(contactPhone()) }} }</span>
|
|
7427
7572
|
</div>
|
|
7428
7573
|
</div>
|
|
7429
7574
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7486,6 +7631,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7486
7631
|
required: false
|
|
7487
7632
|
}]
|
|
7488
7633
|
}],
|
|
7634
|
+
bulkRecipients: [{
|
|
7635
|
+
type: i0.Input,
|
|
7636
|
+
args: [{
|
|
7637
|
+
isSignal: true,
|
|
7638
|
+
alias: "bulkRecipients",
|
|
7639
|
+
required: false
|
|
7640
|
+
}]
|
|
7641
|
+
}],
|
|
7489
7642
|
defaultBody: [{
|
|
7490
7643
|
type: i0.Input,
|
|
7491
7644
|
args: [{
|
|
@@ -7634,6 +7787,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7634
7787
|
type: i0.Output,
|
|
7635
7788
|
args: ["sent"]
|
|
7636
7789
|
}],
|
|
7790
|
+
bulkResult: [{
|
|
7791
|
+
type: i0.Output,
|
|
7792
|
+
args: ["bulkResult"]
|
|
7793
|
+
}],
|
|
7794
|
+
bulkSending: [{
|
|
7795
|
+
type: i0.Output,
|
|
7796
|
+
args: ["bulkSending"]
|
|
7797
|
+
}],
|
|
7637
7798
|
phoneAdded: [{
|
|
7638
7799
|
type: i0.Output,
|
|
7639
7800
|
args: ["phoneAdded"]
|
|
@@ -7648,7 +7809,46 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7648
7809
|
}]
|
|
7649
7810
|
}
|
|
7650
7811
|
});
|
|
7812
|
+
const BULK_MERGE_TAG_HINT = "Personal details such as {{first_name}} are filled in for each recipient when sent.";
|
|
7813
|
+
const SKIPPED_NAMES_SHOWN = 5;
|
|
7651
7814
|
var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
7815
|
+
skippedReason() {
|
|
7816
|
+
return this.channel() === "email" ? "no email address" : "no phone number or no opt-in to texts";
|
|
7817
|
+
}
|
|
7818
|
+
skippedNames() {
|
|
7819
|
+
const names = this.skippedRecipients().map((r) => r.name || "Unnamed");
|
|
7820
|
+
const shown = names.slice(0, SKIPPED_NAMES_SHOWN).join(", ");
|
|
7821
|
+
return names.length > SKIPPED_NAMES_SHOWN ? `${shown} and ${names.length - SKIPPED_NAMES_SHOWN} more` : shown;
|
|
7822
|
+
}
|
|
7823
|
+
bulkRecipientsFor(ch) {
|
|
7824
|
+
if (!this.bulkMode()) return null;
|
|
7825
|
+
return ch === "email" ? this.emailRecipients() : this.textRecipients();
|
|
7826
|
+
}
|
|
7827
|
+
onBulkSending(sent) {
|
|
7828
|
+
if (sent) {
|
|
7829
|
+
this.submitSnapshot = {
|
|
7830
|
+
channel: this.channel(),
|
|
7831
|
+
selected: [...this.bulkList()],
|
|
7832
|
+
sent: [...sent]
|
|
7833
|
+
};
|
|
7834
|
+
this.sending.set(true);
|
|
7835
|
+
} else {
|
|
7836
|
+
this.submitSnapshot = null;
|
|
7837
|
+
this.sending.set(false);
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7840
|
+
resetBulkSend() {
|
|
7841
|
+
this.submitSnapshot = null;
|
|
7842
|
+
this.lastBulkResult = void 0;
|
|
7843
|
+
this.sending.set(false);
|
|
7844
|
+
}
|
|
7845
|
+
onBulkResult(e) {
|
|
7846
|
+
this.lastBulkResult = e.result;
|
|
7847
|
+
if (this.submitSnapshot) this.submitSnapshot = {
|
|
7848
|
+
...this.submitSnapshot,
|
|
7849
|
+
sent: [...e.recipients]
|
|
7850
|
+
};
|
|
7851
|
+
}
|
|
7652
7852
|
onJobPick(o) {
|
|
7653
7853
|
const job = o ? {
|
|
7654
7854
|
id: o.value,
|
|
@@ -7669,6 +7869,10 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7669
7869
|
this.open = input(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
|
|
7670
7870
|
this.contact = input(null, ...ngDevMode ? [{ debugName: "contact" }] : /* istanbul ignore next */ []);
|
|
7671
7871
|
this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
7872
|
+
this.recipients = input(null, ...ngDevMode ? [{ debugName: "recipients" }] : /* istanbul ignore next */ []);
|
|
7873
|
+
this.initialChannel = input(null, ...ngDevMode ? [{ debugName: "initialChannel" }] : /* istanbul ignore next */ []);
|
|
7874
|
+
this.recipientNoun = input("recipients", ...ngDevMode ? [{ debugName: "recipientNoun" }] : /* istanbul ignore next */ []);
|
|
7875
|
+
this.recipientNounSingular = input("", ...ngDevMode ? [{ debugName: "recipientNounSingular" }] : /* istanbul ignore next */ []);
|
|
7672
7876
|
this.textEnabled = input(false, ...ngDevMode ? [{ debugName: "textEnabled" }] : /* istanbul ignore next */ []);
|
|
7673
7877
|
this.title = input("Send Message", ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
|
|
7674
7878
|
this.defaultSubject = input("", ...ngDevMode ? [{ debugName: "defaultSubject" }] : /* istanbul ignore next */ []);
|
|
@@ -7691,7 +7895,9 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7691
7895
|
this.showSubject = input(true, ...ngDevMode ? [{ debugName: "showSubject" }] : /* istanbul ignore next */ []);
|
|
7692
7896
|
this.showTemplates = input(true, ...ngDevMode ? [{ debugName: "showTemplates" }] : /* istanbul ignore next */ []);
|
|
7693
7897
|
this.showVideo = input(true, ...ngDevMode ? [{ debugName: "showVideo" }] : /* istanbul ignore next */ []);
|
|
7694
|
-
this.inApp = computed(() => this.recipientMode() === "in-app", ...ngDevMode ? [{ debugName: "inApp" }] : /* istanbul ignore next */ []);
|
|
7898
|
+
this.inApp = computed(() => this.recipientMode() === "in-app" && !this.bulkMode(), ...ngDevMode ? [{ debugName: "inApp" }] : /* istanbul ignore next */ []);
|
|
7899
|
+
this.BULK_NO_SEND_MESSAGE = BULK_NO_SEND_MESSAGE;
|
|
7900
|
+
this.BULK_MERGE_TAG_HINT = BULK_MERGE_TAG_HINT;
|
|
7695
7901
|
this.attachmentsAndScheduling = input(true, ...ngDevMode ? [{ debugName: "attachmentsAndScheduling" }] : /* istanbul ignore next */ []);
|
|
7696
7902
|
this.documentPurposes = input([
|
|
7697
7903
|
"ESIGN",
|
|
@@ -7712,7 +7918,50 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7712
7918
|
this.docuSignConnected = input(false, ...ngDevMode ? [{ debugName: "docuSignConnected" }] : /* istanbul ignore next */ []);
|
|
7713
7919
|
this.documentPreview = input(null, ...ngDevMode ? [{ debugName: "documentPreview" }] : /* istanbul ignore next */ []);
|
|
7714
7920
|
this.videoDefaults = input(null, ...ngDevMode ? [{ debugName: "videoDefaults" }] : /* istanbul ignore next */ []);
|
|
7715
|
-
this.documentsOn = computed(() => (this.documents() || !!this.documentEnvelope()) && this.documentsEnabled(), ...ngDevMode ? [{ debugName: "documentsOn" }] : /* istanbul ignore next */ []);
|
|
7921
|
+
this.documentsOn = computed(() => (this.documents() || !!this.documentEnvelope()) && this.documentsEnabled() && !this.bulkMode(), ...ngDevMode ? [{ debugName: "documentsOn" }] : /* istanbul ignore next */ []);
|
|
7922
|
+
this.bulkList = computed(() => {
|
|
7923
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7924
|
+
return (this.recipients() ?? []).filter((r) => !seen.has(r.id) && !!seen.add(r.id));
|
|
7925
|
+
}, ...ngDevMode ? [{ debugName: "bulkList" }] : /* istanbul ignore next */ []);
|
|
7926
|
+
this.bulkMode = computed(() => this.bulkList().length > 0, ...ngDevMode ? [{ debugName: "bulkMode" }] : /* istanbul ignore next */ []);
|
|
7927
|
+
this.emailRecipients = computed(() => this.bulkList().filter((r) => !!r.email?.trim()), ...ngDevMode ? [{ debugName: "emailRecipients" }] : /* istanbul ignore next */ []);
|
|
7928
|
+
this.textRecipients = computed(() => this.textEnabled() ? this.bulkList().filter((r) => !!r.phone?.trim() && r.smsOptedIn === true) : [], ...ngDevMode ? [{ debugName: "textRecipients" }] : /* istanbul ignore next */ []);
|
|
7929
|
+
this.activeRecipients = computed(() => this.channel() === "email" ? this.emailRecipients() : this.textRecipients(), ...ngDevMode ? [{ debugName: "activeRecipients" }] : /* istanbul ignore next */ []);
|
|
7930
|
+
this.skippedRecipients = computed(() => {
|
|
7931
|
+
const ok = new Set(this.activeRecipients());
|
|
7932
|
+
return this.bulkList().filter((r) => !ok.has(r));
|
|
7933
|
+
}, ...ngDevMode ? [{ debugName: "skippedRecipients" }] : /* istanbul ignore next */ []);
|
|
7934
|
+
this.bulkNoneEligible = computed(() => this.bulkMode() && this.activeRecipients().length === 0, ...ngDevMode ? [{ debugName: "bulkNoneEligible" }] : /* istanbul ignore next */ []);
|
|
7935
|
+
this.bulkMissingSend = computed(() => this.bulkMode() && !(this.channel() === "email" ? this.sendEmail() : this.sendText()), ...ngDevMode ? [{ debugName: "bulkMissingSend" }] : /* istanbul ignore next */ []);
|
|
7936
|
+
this.bulkBlocked = computed(() => this.bulkMode() && (this.bulkNoneEligible() || this.bulkMissingSend()), ...ngDevMode ? [{ debugName: "bulkBlocked" }] : /* istanbul ignore next */ []);
|
|
7937
|
+
this.hasTarget = computed(() => this.bulkMode() || !!this.activeContact(), ...ngDevMode ? [{ debugName: "hasTarget" }] : /* istanbul ignore next */ []);
|
|
7938
|
+
this.sending = signal(false, ...ngDevMode ? [{ debugName: "sending" }] : /* istanbul ignore next */ []);
|
|
7939
|
+
this.submitSnapshot = null;
|
|
7940
|
+
this.recipientWord = computed(() => {
|
|
7941
|
+
const n = this.bulkList().length;
|
|
7942
|
+
const plural = this.recipientNoun() || "recipients";
|
|
7943
|
+
if (n !== 1) return plural;
|
|
7944
|
+
return this.recipientNounSingular() || (plural.endsWith("s") ? plural.slice(0, -1) : plural);
|
|
7945
|
+
}, ...ngDevMode ? [{ debugName: "recipientWord" }] : /* istanbul ignore next */ []);
|
|
7946
|
+
this.skippedText = computed(() => {
|
|
7947
|
+
const n = this.skippedRecipients().length;
|
|
7948
|
+
if (n === 0) return "";
|
|
7949
|
+
const what = this.channel() === "email" ? "email" : "text";
|
|
7950
|
+
return `${n} ${n === 1 ? "has" : "have"} ${this.skippedReason()} and will be skipped (${this.skippedNames()}). Only the others get this ${what}.`;
|
|
7951
|
+
}, ...ngDevMode ? [{ debugName: "skippedText" }] : /* istanbul ignore next */ []);
|
|
7952
|
+
this.noneEligibleText = computed(() => {
|
|
7953
|
+
return `None of the ${this.bulkList().length} selected can receive this ${this.channel() === "email" ? "email" : "text message"} (${this.skippedReason()}), so there is nothing to send.`;
|
|
7954
|
+
}, ...ngDevMode ? [{ debugName: "noneEligibleText" }] : /* istanbul ignore next */ []);
|
|
7955
|
+
this.bulkAnnouncement = computed(() => {
|
|
7956
|
+
if (!this.bulkMode()) return "";
|
|
7957
|
+
const n = this.bulkList().length;
|
|
7958
|
+
const ok = this.activeRecipients().length;
|
|
7959
|
+
const ch = this.channel() === "email" ? "email" : "text";
|
|
7960
|
+
if (ok === 0) return `${n} ${this.recipientWord()} selected. None can receive the ${ch}.`;
|
|
7961
|
+
const skipped = this.skippedRecipients().length;
|
|
7962
|
+
return `${n} ${this.recipientWord()} selected. ${ok} can receive the ${ch}.${skipped ? ` ${skipped} will be skipped.` : ""}`;
|
|
7963
|
+
}, ...ngDevMode ? [{ debugName: "bulkAnnouncement" }] : /* istanbul ignore next */ []);
|
|
7964
|
+
this.lastBulkResult = void 0;
|
|
7716
7965
|
this.showJobPicker = input(false, ...ngDevMode ? [{ debugName: "showJobPicker" }] : /* istanbul ignore next */ []);
|
|
7717
7966
|
this.jobLabel = input("Job", ...ngDevMode ? [{ debugName: "jobLabel" }] : /* istanbul ignore next */ []);
|
|
7718
7967
|
this.jobHint = input("", ...ngDevMode ? [{ debugName: "jobHint" }] : /* istanbul ignore next */ []);
|
|
@@ -7720,6 +7969,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7720
7969
|
this.jobSelected = output();
|
|
7721
7970
|
this.closed = output();
|
|
7722
7971
|
this.sent = output();
|
|
7972
|
+
this.sentBulk = output();
|
|
7723
7973
|
this.emailAdded = output();
|
|
7724
7974
|
this.rejected = output();
|
|
7725
7975
|
this.mapFieldsClick = output();
|
|
@@ -7777,6 +8027,31 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7777
8027
|
const loadingVal = this.loading();
|
|
7778
8028
|
const openedNow = openVal && !this._prevOpen;
|
|
7779
8029
|
this._prevOpen = openVal;
|
|
8030
|
+
if (this.bulkMode()) {
|
|
8031
|
+
const emailCount = this.emailRecipients().length;
|
|
8032
|
+
const textCount = this.textRecipients().length;
|
|
8033
|
+
untracked(() => {
|
|
8034
|
+
const wasSingle = !!this.activeContact();
|
|
8035
|
+
const ch = this.channel();
|
|
8036
|
+
const activeCount = ch === "email" ? emailCount : textCount;
|
|
8037
|
+
const otherCount = ch === "email" ? textCount : emailCount;
|
|
8038
|
+
const pref = this.initialChannel();
|
|
8039
|
+
const defaultCh = pref === "text" && textCount > 0 ? "text" : pref === "email" && emailCount > 0 ? "email" : emailCount > 0 || textCount === 0 ? "email" : "text";
|
|
8040
|
+
if (openedNow || wasSingle) {
|
|
8041
|
+
this.activeContact.set(null);
|
|
8042
|
+
this.channel.set(defaultCh);
|
|
8043
|
+
} else if (openVal && activeCount === 0 && otherCount > 0 && !this.sending()) this.channel.set(ch === "email" ? "text" : "email");
|
|
8044
|
+
else return;
|
|
8045
|
+
this.resetBulkSend();
|
|
8046
|
+
this.valid.set(false);
|
|
8047
|
+
this.resetJob();
|
|
8048
|
+
this.formEpoch.update((n) => n + 1);
|
|
8049
|
+
});
|
|
8050
|
+
return;
|
|
8051
|
+
}
|
|
8052
|
+
untracked(() => {
|
|
8053
|
+
if (openedNow || this.sending() || this.submitSnapshot) this.resetBulkSend();
|
|
8054
|
+
});
|
|
7780
8055
|
if (!openedNow && !(openVal && !loadingVal && !!contactVal)) return;
|
|
7781
8056
|
const c = contactVal ?? null;
|
|
7782
8057
|
const active = untracked(() => this.activeContact());
|
|
@@ -7800,6 +8075,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7800
8075
|
this.formEpoch.update((n) => n + 1);
|
|
7801
8076
|
}
|
|
7802
8077
|
onChannelChange(ch) {
|
|
8078
|
+
if (this.sending()) return;
|
|
7803
8079
|
this.channel.set(ch);
|
|
7804
8080
|
this.valid.set(false);
|
|
7805
8081
|
}
|
|
@@ -7820,12 +8096,29 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7820
8096
|
this.phoneAdded.emit(phone);
|
|
7821
8097
|
}
|
|
7822
8098
|
submit() {
|
|
8099
|
+
if (this.bulkBlocked()) return;
|
|
7823
8100
|
if (this.inApp()) this.sendInAppRef()?.submit();
|
|
7824
8101
|
else if (this.channel() === "email") this.sendEmailRef()?.submit();
|
|
7825
8102
|
else this.sendTextRef()?.submit();
|
|
7826
8103
|
}
|
|
7827
8104
|
onSent() {
|
|
8105
|
+
const snap = this.submitSnapshot;
|
|
8106
|
+
const bulk = !!snap || this.bulkMode();
|
|
8107
|
+
const channel = snap?.channel ?? this.channel();
|
|
8108
|
+
const selected = snap?.selected ?? [...this.bulkList()];
|
|
8109
|
+
const sentList = snap?.sent ?? [...this.activeRecipients()];
|
|
8110
|
+
const sentIds = new Set(sentList.map((r) => r.id));
|
|
8111
|
+
const event = bulk ? {
|
|
8112
|
+
channel,
|
|
8113
|
+
recipients: sentList,
|
|
8114
|
+
skipped: selected.filter((r) => !sentIds.has(r.id)),
|
|
8115
|
+
result: this.lastBulkResult
|
|
8116
|
+
} : null;
|
|
8117
|
+
this.lastBulkResult = void 0;
|
|
8118
|
+
this.submitSnapshot = null;
|
|
8119
|
+
this.sending.set(false);
|
|
7828
8120
|
this.sent.emit();
|
|
8121
|
+
if (event) this.sentBulk.emit(event);
|
|
7829
8122
|
this.closed.emit();
|
|
7830
8123
|
}
|
|
7831
8124
|
onClose() {
|
|
@@ -7870,6 +8163,34 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7870
8163
|
isRequired: false,
|
|
7871
8164
|
transformFunction: null
|
|
7872
8165
|
},
|
|
8166
|
+
recipients: {
|
|
8167
|
+
classPropertyName: "recipients",
|
|
8168
|
+
publicName: "recipients",
|
|
8169
|
+
isSignal: true,
|
|
8170
|
+
isRequired: false,
|
|
8171
|
+
transformFunction: null
|
|
8172
|
+
},
|
|
8173
|
+
initialChannel: {
|
|
8174
|
+
classPropertyName: "initialChannel",
|
|
8175
|
+
publicName: "initialChannel",
|
|
8176
|
+
isSignal: true,
|
|
8177
|
+
isRequired: false,
|
|
8178
|
+
transformFunction: null
|
|
8179
|
+
},
|
|
8180
|
+
recipientNoun: {
|
|
8181
|
+
classPropertyName: "recipientNoun",
|
|
8182
|
+
publicName: "recipientNoun",
|
|
8183
|
+
isSignal: true,
|
|
8184
|
+
isRequired: false,
|
|
8185
|
+
transformFunction: null
|
|
8186
|
+
},
|
|
8187
|
+
recipientNounSingular: {
|
|
8188
|
+
classPropertyName: "recipientNounSingular",
|
|
8189
|
+
publicName: "recipientNounSingular",
|
|
8190
|
+
isSignal: true,
|
|
8191
|
+
isRequired: false,
|
|
8192
|
+
transformFunction: null
|
|
8193
|
+
},
|
|
7873
8194
|
textEnabled: {
|
|
7874
8195
|
classPropertyName: "textEnabled",
|
|
7875
8196
|
publicName: "textEnabled",
|
|
@@ -8169,6 +8490,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8169
8490
|
jobSelected: "jobSelected",
|
|
8170
8491
|
closed: "closed",
|
|
8171
8492
|
sent: "sent",
|
|
8493
|
+
sentBulk: "sentBulk",
|
|
8172
8494
|
emailAdded: "emailAdded",
|
|
8173
8495
|
rejected: "rejected",
|
|
8174
8496
|
mapFieldsClick: "mapFieldsClick",
|
|
@@ -8204,9 +8526,9 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8204
8526
|
[title]="title()"
|
|
8205
8527
|
[wide]="wide()"
|
|
8206
8528
|
cancelLabel="Cancel"
|
|
8207
|
-
[primaryLabel]="!loading() &&
|
|
8529
|
+
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? 'Send Message' : channel() === 'email' ? 'Send Email' : 'Send Text')) : ''"
|
|
8208
8530
|
primaryVariant="warning"
|
|
8209
|
-
[primaryDisabled]="!valid()"
|
|
8531
|
+
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
8210
8532
|
(closed)="onClose()"
|
|
8211
8533
|
(primaryClick)="submit()">
|
|
8212
8534
|
|
|
@@ -8218,7 +8540,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8218
8540
|
</div>
|
|
8219
8541
|
}
|
|
8220
8542
|
|
|
8221
|
-
@if (!loading() && !
|
|
8543
|
+
@if (!loading() && !hasTarget() && !inApp()) {
|
|
8222
8544
|
<div class="msg-step">
|
|
8223
8545
|
<span class="msg-step-badge">1</span>
|
|
8224
8546
|
<span class="msg-step-text">Who would you like to message?</span>
|
|
@@ -8228,8 +8550,60 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8228
8550
|
(contactSelected)="onContactSelected($event)" />
|
|
8229
8551
|
}
|
|
8230
8552
|
|
|
8231
|
-
@if (!loading() &&
|
|
8232
|
-
@if (
|
|
8553
|
+
@if (!loading() && hasTarget()) {
|
|
8554
|
+
@if (bulkMode()) {
|
|
8555
|
+
<div class="msg-bulk" role="group" aria-label="Recipients" data-testid="bulk-summary">
|
|
8556
|
+
<p class="msg-bulk-to" data-testid="bulk-to">To: {{ bulkList().length }} {{ recipientWord() }}</p>
|
|
8557
|
+
<div class="msg-bulk-counts">
|
|
8558
|
+
<ui-badge [label]="emailRecipients().length + ' can receive email'" [variant]="emailRecipients().length ? 'blue' : 'gray'" />
|
|
8559
|
+
@if (textEnabled()) {
|
|
8560
|
+
<ui-badge [label]="textRecipients().length + ' can receive text'" [variant]="textRecipients().length ? 'blue' : 'gray'" />
|
|
8561
|
+
}
|
|
8562
|
+
</div>
|
|
8563
|
+
@if (!textEnabled()) {
|
|
8564
|
+
<ui-hint>Text messaging is not enabled. Connect Twilio in Comm Settings to send texts.</ui-hint>
|
|
8565
|
+
}
|
|
8566
|
+
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
8567
|
+
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
8568
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-skipped">{{ skippedText() }}</ui-alert>
|
|
8569
|
+
}
|
|
8570
|
+
@if (bulkNoneEligible()) {
|
|
8571
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
8572
|
+
}
|
|
8573
|
+
@if (bulkMissingSend()) {
|
|
8574
|
+
<ui-alert variant="danger" data-testid="bulk-no-send">{{ BULK_NO_SEND_MESSAGE }}</ui-alert>
|
|
8575
|
+
}
|
|
8576
|
+
@if (!bulkNoneEligible()) {
|
|
8577
|
+
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
8578
|
+
}
|
|
8579
|
+
</div>
|
|
8580
|
+
}
|
|
8581
|
+
|
|
8582
|
+
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
8583
|
+
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
8584
|
+
<label class="form-label msg-via-label">Send via</label>
|
|
8585
|
+
@if (sending()) {
|
|
8586
|
+
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
8587
|
+
<div class="msg-via-tabs">
|
|
8588
|
+
<ui-badge [label]="channel() === 'email' ? 'Email' : 'Text'" variant="blue" />
|
|
8589
|
+
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">Channel locked while sending.</span>
|
|
8590
|
+
</div>
|
|
8591
|
+
} @else {
|
|
8592
|
+
<div class="msg-via-tabs">
|
|
8593
|
+
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
8594
|
+
<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>
|
|
8595
|
+
Email
|
|
8596
|
+
</ui-toggle-badge>
|
|
8597
|
+
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
8598
|
+
<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>
|
|
8599
|
+
Text
|
|
8600
|
+
</ui-toggle-badge>
|
|
8601
|
+
</div>
|
|
8602
|
+
}
|
|
8603
|
+
</div>
|
|
8604
|
+
}
|
|
8605
|
+
|
|
8606
|
+
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
8233
8607
|
<div class="msg-channel-row">
|
|
8234
8608
|
<label class="form-label msg-via-label">Send via</label>
|
|
8235
8609
|
<div class="msg-via-tabs">
|
|
@@ -8253,7 +8627,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8253
8627
|
}
|
|
8254
8628
|
|
|
8255
8629
|
<!-- Optional job link (hidden unless the host turns it on). -->
|
|
8256
|
-
@if (showJobPicker()) {
|
|
8630
|
+
@if (showJobPicker() && !bulkMode()) {
|
|
8257
8631
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8258
8632
|
<div class="msg-job">
|
|
8259
8633
|
<ui-combobox
|
|
@@ -8266,13 +8640,14 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8266
8640
|
}
|
|
8267
8641
|
|
|
8268
8642
|
<!-- Keyed on formEpoch: a fresh open or another contact gets brand-new forms (no stale draft / template). -->
|
|
8643
|
+
<div [hidden]="bulkNoneEligible()" data-testid="msg-forms">
|
|
8269
8644
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8270
8645
|
@if (inApp()) {
|
|
8271
8646
|
<ui-send-in-app
|
|
8272
8647
|
#sendInAppRef
|
|
8273
|
-
[contactName]="activeContact()
|
|
8274
|
-
[contactId]="activeContact()
|
|
8275
|
-
[contactEmail]="activeContact()
|
|
8648
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
8649
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
8650
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8276
8651
|
[allowAttachments]="inAppAttachments()"
|
|
8277
8652
|
[richText]="inAppRichText()"
|
|
8278
8653
|
[defaultSubject]="defaultSubject()"
|
|
@@ -8285,10 +8660,11 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8285
8660
|
} @else if (channel() === 'email') {
|
|
8286
8661
|
<ui-send-email
|
|
8287
8662
|
#sendEmailRef
|
|
8288
|
-
[contactName]="activeContact()
|
|
8289
|
-
[contactEmail]="activeContact()
|
|
8290
|
-
[contactPhone]="activeContact()
|
|
8291
|
-
[contactId]="activeContact()
|
|
8663
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
8664
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8665
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
8666
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
8667
|
+
[bulkRecipients]="bulkRecipientsFor('email')"
|
|
8292
8668
|
[defaultSubject]="defaultSubject()"
|
|
8293
8669
|
[defaultBody]="defaultBody()"
|
|
8294
8670
|
[context]="context()"
|
|
@@ -8298,13 +8674,13 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8298
8674
|
[receiptDefault]="receiptDefault()"
|
|
8299
8675
|
[documents]="documentsOn()"
|
|
8300
8676
|
[documentPurposes]="documentPurposes()"
|
|
8301
|
-
[initialDocuments]="initialDocuments()"
|
|
8677
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8302
8678
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8303
|
-
[documentSigners]="documentSigners()"
|
|
8679
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8304
8680
|
[sendContext]="sendContext()"
|
|
8305
8681
|
[documentContextTypes]="documentContextTypes()"
|
|
8306
8682
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8307
|
-
[documentEnvelope]="documentEnvelope()"
|
|
8683
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8308
8684
|
[emailEnabled]="emailEnabled()"
|
|
8309
8685
|
[documentSentMessage]="documentSentMessage()"
|
|
8310
8686
|
(rejected)="rejected.emit()"
|
|
@@ -8317,46 +8693,52 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8317
8693
|
[showSubject]="showSubject()"
|
|
8318
8694
|
[showTemplates]="showTemplates()"
|
|
8319
8695
|
[showVideo]="showVideo()"
|
|
8696
|
+
(bulkSending)="onBulkSending($event)"
|
|
8697
|
+
(bulkResult)="onBulkResult($event)"
|
|
8320
8698
|
(sent)="onSent()"
|
|
8321
8699
|
(emailAdded)="onEmailAdded($event)"
|
|
8322
8700
|
(validChange)="valid.set($event)" />
|
|
8323
8701
|
} @else {
|
|
8324
8702
|
<ui-send-text
|
|
8325
8703
|
#sendTextRef
|
|
8326
|
-
[contactName]="activeContact()
|
|
8327
|
-
[contactPhone]="activeContact()
|
|
8328
|
-
[contactEmail]="activeContact()
|
|
8329
|
-
[contactId]="activeContact()
|
|
8704
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
8705
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
8706
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8707
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
8708
|
+
[bulkRecipients]="bulkRecipientsFor('text')"
|
|
8330
8709
|
[defaultBody]="defaultMessage()"
|
|
8331
8710
|
[context]="context()"
|
|
8332
8711
|
[sendFn]="sendText()"
|
|
8333
8712
|
[attachmentsAndScheduling]="attachmentsAndScheduling()"
|
|
8334
8713
|
[documents]="documentsOn()"
|
|
8335
8714
|
[documentPurposes]="documentPurposes()"
|
|
8336
|
-
[initialDocuments]="initialDocuments()"
|
|
8715
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8337
8716
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8338
|
-
[documentSigners]="documentSigners()"
|
|
8717
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8339
8718
|
[sendContext]="sendContext()"
|
|
8340
8719
|
[documentContextTypes]="documentContextTypes()"
|
|
8341
8720
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8342
|
-
[documentEnvelope]="documentEnvelope()"
|
|
8721
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8343
8722
|
[documentSentMessage]="documentSentMessage()"
|
|
8344
8723
|
(rejected)="rejected.emit()"
|
|
8345
8724
|
[documentPreview]="documentPreview()"
|
|
8346
8725
|
[videoDefaults]="videoDefaults()"
|
|
8347
8726
|
[showTemplates]="showTemplates()"
|
|
8348
8727
|
[showVideo]="showVideo()"
|
|
8728
|
+
(bulkSending)="onBulkSending($event)"
|
|
8729
|
+
(bulkResult)="onBulkResult($event)"
|
|
8349
8730
|
(sent)="onSent()"
|
|
8350
8731
|
(phoneAdded)="onPhoneAdded($event)"
|
|
8351
8732
|
(validChange)="valid.set($event)" />
|
|
8352
8733
|
}
|
|
8353
8734
|
}
|
|
8735
|
+
</div>
|
|
8354
8736
|
}
|
|
8355
8737
|
|
|
8356
8738
|
</ui-side-panel>
|
|
8357
8739
|
`,
|
|
8358
8740
|
isInline: true,
|
|
8359
|
-
styles: [".msg-step{display:flex;align-items:center;gap:10px;margin-bottom:14px}.msg-step-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0;border-radius:50%;background:#1e293b;color:#fff;font-size:.75rem;font-weight:700}.msg-step-text{font-size:.9375rem;font-weight:600;color:#1e293b}.msg-channel-row{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}.msg-sms-notice{display:flex;align-items:center;gap:8px;margin-bottom:16px;padding:10px 12px;border-radius:8px;background:#f8fafc;border:1px solid #e2e8f0;font-size:.8125rem;color:#64748b}.msg-job{margin-bottom:16px}.msg-via-tabs{display:flex;gap:6px;flex-wrap:wrap}.msg-skeleton{display:flex;flex-direction:column;gap:12px;padding:4px 0}.skeleton-line{height:14px;border-radius:6px;background:linear-gradient(90deg,#e2e8f0 25%,#f1f5f9,#e2e8f0 75%);background-size:200% 100%;animation:skeleton-shimmer 1.4s infinite}.skeleton-line--wide{width:100%}.skeleton-line--medium{width:70%}.skeleton-line--narrow{width:45%}@keyframes skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"],
|
|
8741
|
+
styles: [".msg-step{display:flex;align-items:center;gap:10px;margin-bottom:14px}.msg-step-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0;border-radius:50%;background:#1e293b;color:#fff;font-size:.75rem;font-weight:700}.msg-step-text{font-size:.9375rem;font-weight:600;color:#1e293b}.msg-channel-row{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}.msg-sms-notice{display:flex;align-items:center;gap:8px;margin-bottom:16px;padding:10px 12px;border-radius:8px;background:#f8fafc;border:1px solid #e2e8f0;font-size:.8125rem;color:#64748b}.msg-job{margin-bottom:16px}.msg-locked-note{font-size:.75rem;color:#64748b}.msg-bulk{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}.msg-bulk-to{margin:0;font-size:.9375rem;font-weight:600;color:var(--shell-text, #1e293b)}.msg-bulk-counts{display:flex;flex-wrap:wrap;gap:6px}.msg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.msg-via-tabs{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.msg-skeleton{display:flex;flex-direction:column;gap:12px;padding:4px 0}.skeleton-line{height:14px;border-radius:6px;background:linear-gradient(90deg,#e2e8f0 25%,#f1f5f9,#e2e8f0 75%);background-size:200% 100%;animation:skeleton-shimmer 1.4s infinite}.skeleton-line--wide{width:100%}.skeleton-line--medium{width:70%}.skeleton-line--narrow{width:45%}@keyframes skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"],
|
|
8360
8742
|
dependencies: [
|
|
8361
8743
|
{
|
|
8362
8744
|
kind: "component",
|
|
@@ -8400,6 +8782,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8400
8782
|
"contactEmail",
|
|
8401
8783
|
"contactPhone",
|
|
8402
8784
|
"contactId",
|
|
8785
|
+
"bulkRecipients",
|
|
8403
8786
|
"defaultSubject",
|
|
8404
8787
|
"defaultBody",
|
|
8405
8788
|
"context",
|
|
@@ -8429,6 +8812,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8429
8812
|
],
|
|
8430
8813
|
outputs: [
|
|
8431
8814
|
"sent",
|
|
8815
|
+
"bulkResult",
|
|
8816
|
+
"bulkSending",
|
|
8432
8817
|
"emailAdded",
|
|
8433
8818
|
"validChange",
|
|
8434
8819
|
"rejected",
|
|
@@ -8462,6 +8847,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8462
8847
|
"contactPhone",
|
|
8463
8848
|
"contactEmail",
|
|
8464
8849
|
"contactId",
|
|
8850
|
+
"bulkRecipients",
|
|
8465
8851
|
"defaultBody",
|
|
8466
8852
|
"context",
|
|
8467
8853
|
"sendFn",
|
|
@@ -8483,6 +8869,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8483
8869
|
],
|
|
8484
8870
|
outputs: [
|
|
8485
8871
|
"sent",
|
|
8872
|
+
"bulkResult",
|
|
8873
|
+
"bulkSending",
|
|
8486
8874
|
"phoneAdded",
|
|
8487
8875
|
"validChange",
|
|
8488
8876
|
"rejected"
|
|
@@ -8540,6 +8928,33 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8540
8928
|
"focused",
|
|
8541
8929
|
"blurred"
|
|
8542
8930
|
]
|
|
8931
|
+
},
|
|
8932
|
+
{
|
|
8933
|
+
kind: "component",
|
|
8934
|
+
type: AlertComponent,
|
|
8935
|
+
selector: "ui-alert",
|
|
8936
|
+
inputs: [
|
|
8937
|
+
"variant",
|
|
8938
|
+
"title",
|
|
8939
|
+
"dismissible",
|
|
8940
|
+
"dismissAriaLabel",
|
|
8941
|
+
"quiet",
|
|
8942
|
+
"compact",
|
|
8943
|
+
"inline",
|
|
8944
|
+
"fill"
|
|
8945
|
+
],
|
|
8946
|
+
outputs: ["dismissed"]
|
|
8947
|
+
},
|
|
8948
|
+
{
|
|
8949
|
+
kind: "component",
|
|
8950
|
+
type: BadgeComponent,
|
|
8951
|
+
selector: "ui-badge",
|
|
8952
|
+
inputs: ["label", "variant"]
|
|
8953
|
+
},
|
|
8954
|
+
{
|
|
8955
|
+
kind: "component",
|
|
8956
|
+
type: HintComponent,
|
|
8957
|
+
selector: "ui-hint"
|
|
8543
8958
|
}
|
|
8544
8959
|
],
|
|
8545
8960
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
@@ -8564,7 +8979,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8564
8979
|
SendInAppComponent,
|
|
8565
8980
|
SendTextComponent,
|
|
8566
8981
|
ContactPickerComponent,
|
|
8567
|
-
ComboboxComponent
|
|
8982
|
+
ComboboxComponent,
|
|
8983
|
+
AlertComponent,
|
|
8984
|
+
BadgeComponent,
|
|
8985
|
+
HintComponent
|
|
8568
8986
|
],
|
|
8569
8987
|
template: `
|
|
8570
8988
|
<ui-side-panel
|
|
@@ -8572,9 +8990,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8572
8990
|
[title]="title()"
|
|
8573
8991
|
[wide]="wide()"
|
|
8574
8992
|
cancelLabel="Cancel"
|
|
8575
|
-
[primaryLabel]="!loading() &&
|
|
8993
|
+
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? 'Send Message' : channel() === 'email' ? 'Send Email' : 'Send Text')) : ''"
|
|
8576
8994
|
primaryVariant="warning"
|
|
8577
|
-
[primaryDisabled]="!valid()"
|
|
8995
|
+
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
8578
8996
|
(closed)="onClose()"
|
|
8579
8997
|
(primaryClick)="submit()">
|
|
8580
8998
|
|
|
@@ -8586,7 +9004,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8586
9004
|
</div>
|
|
8587
9005
|
}
|
|
8588
9006
|
|
|
8589
|
-
@if (!loading() && !
|
|
9007
|
+
@if (!loading() && !hasTarget() && !inApp()) {
|
|
8590
9008
|
<div class="msg-step">
|
|
8591
9009
|
<span class="msg-step-badge">1</span>
|
|
8592
9010
|
<span class="msg-step-text">Who would you like to message?</span>
|
|
@@ -8596,8 +9014,60 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8596
9014
|
(contactSelected)="onContactSelected($event)" />
|
|
8597
9015
|
}
|
|
8598
9016
|
|
|
8599
|
-
@if (!loading() &&
|
|
8600
|
-
@if (
|
|
9017
|
+
@if (!loading() && hasTarget()) {
|
|
9018
|
+
@if (bulkMode()) {
|
|
9019
|
+
<div class="msg-bulk" role="group" aria-label="Recipients" data-testid="bulk-summary">
|
|
9020
|
+
<p class="msg-bulk-to" data-testid="bulk-to">To: {{ bulkList().length }} {{ recipientWord() }}</p>
|
|
9021
|
+
<div class="msg-bulk-counts">
|
|
9022
|
+
<ui-badge [label]="emailRecipients().length + ' can receive email'" [variant]="emailRecipients().length ? 'blue' : 'gray'" />
|
|
9023
|
+
@if (textEnabled()) {
|
|
9024
|
+
<ui-badge [label]="textRecipients().length + ' can receive text'" [variant]="textRecipients().length ? 'blue' : 'gray'" />
|
|
9025
|
+
}
|
|
9026
|
+
</div>
|
|
9027
|
+
@if (!textEnabled()) {
|
|
9028
|
+
<ui-hint>Text messaging is not enabled. Connect Twilio in Comm Settings to send texts.</ui-hint>
|
|
9029
|
+
}
|
|
9030
|
+
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
9031
|
+
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
9032
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-skipped">{{ skippedText() }}</ui-alert>
|
|
9033
|
+
}
|
|
9034
|
+
@if (bulkNoneEligible()) {
|
|
9035
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
9036
|
+
}
|
|
9037
|
+
@if (bulkMissingSend()) {
|
|
9038
|
+
<ui-alert variant="danger" data-testid="bulk-no-send">{{ BULK_NO_SEND_MESSAGE }}</ui-alert>
|
|
9039
|
+
}
|
|
9040
|
+
@if (!bulkNoneEligible()) {
|
|
9041
|
+
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
9042
|
+
}
|
|
9043
|
+
</div>
|
|
9044
|
+
}
|
|
9045
|
+
|
|
9046
|
+
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
9047
|
+
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
9048
|
+
<label class="form-label msg-via-label">Send via</label>
|
|
9049
|
+
@if (sending()) {
|
|
9050
|
+
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
9051
|
+
<div class="msg-via-tabs">
|
|
9052
|
+
<ui-badge [label]="channel() === 'email' ? 'Email' : 'Text'" variant="blue" />
|
|
9053
|
+
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">Channel locked while sending.</span>
|
|
9054
|
+
</div>
|
|
9055
|
+
} @else {
|
|
9056
|
+
<div class="msg-via-tabs">
|
|
9057
|
+
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
9058
|
+
<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>
|
|
9059
|
+
Email
|
|
9060
|
+
</ui-toggle-badge>
|
|
9061
|
+
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
9062
|
+
<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>
|
|
9063
|
+
Text
|
|
9064
|
+
</ui-toggle-badge>
|
|
9065
|
+
</div>
|
|
9066
|
+
}
|
|
9067
|
+
</div>
|
|
9068
|
+
}
|
|
9069
|
+
|
|
9070
|
+
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
8601
9071
|
<div class="msg-channel-row">
|
|
8602
9072
|
<label class="form-label msg-via-label">Send via</label>
|
|
8603
9073
|
<div class="msg-via-tabs">
|
|
@@ -8621,7 +9091,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8621
9091
|
}
|
|
8622
9092
|
|
|
8623
9093
|
<!-- Optional job link (hidden unless the host turns it on). -->
|
|
8624
|
-
@if (showJobPicker()) {
|
|
9094
|
+
@if (showJobPicker() && !bulkMode()) {
|
|
8625
9095
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8626
9096
|
<div class="msg-job">
|
|
8627
9097
|
<ui-combobox
|
|
@@ -8634,13 +9104,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8634
9104
|
}
|
|
8635
9105
|
|
|
8636
9106
|
<!-- Keyed on formEpoch: a fresh open or another contact gets brand-new forms (no stale draft / template). -->
|
|
9107
|
+
<div [hidden]="bulkNoneEligible()" data-testid="msg-forms">
|
|
8637
9108
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8638
9109
|
@if (inApp()) {
|
|
8639
9110
|
<ui-send-in-app
|
|
8640
9111
|
#sendInAppRef
|
|
8641
|
-
[contactName]="activeContact()
|
|
8642
|
-
[contactId]="activeContact()
|
|
8643
|
-
[contactEmail]="activeContact()
|
|
9112
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
9113
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
9114
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8644
9115
|
[allowAttachments]="inAppAttachments()"
|
|
8645
9116
|
[richText]="inAppRichText()"
|
|
8646
9117
|
[defaultSubject]="defaultSubject()"
|
|
@@ -8653,10 +9124,11 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8653
9124
|
} @else if (channel() === 'email') {
|
|
8654
9125
|
<ui-send-email
|
|
8655
9126
|
#sendEmailRef
|
|
8656
|
-
[contactName]="activeContact()
|
|
8657
|
-
[contactEmail]="activeContact()
|
|
8658
|
-
[contactPhone]="activeContact()
|
|
8659
|
-
[contactId]="activeContact()
|
|
9127
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
9128
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
9129
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
9130
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
9131
|
+
[bulkRecipients]="bulkRecipientsFor('email')"
|
|
8660
9132
|
[defaultSubject]="defaultSubject()"
|
|
8661
9133
|
[defaultBody]="defaultBody()"
|
|
8662
9134
|
[context]="context()"
|
|
@@ -8666,13 +9138,13 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8666
9138
|
[receiptDefault]="receiptDefault()"
|
|
8667
9139
|
[documents]="documentsOn()"
|
|
8668
9140
|
[documentPurposes]="documentPurposes()"
|
|
8669
|
-
[initialDocuments]="initialDocuments()"
|
|
9141
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8670
9142
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8671
|
-
[documentSigners]="documentSigners()"
|
|
9143
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8672
9144
|
[sendContext]="sendContext()"
|
|
8673
9145
|
[documentContextTypes]="documentContextTypes()"
|
|
8674
9146
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8675
|
-
[documentEnvelope]="documentEnvelope()"
|
|
9147
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8676
9148
|
[emailEnabled]="emailEnabled()"
|
|
8677
9149
|
[documentSentMessage]="documentSentMessage()"
|
|
8678
9150
|
(rejected)="rejected.emit()"
|
|
@@ -8685,45 +9157,51 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8685
9157
|
[showSubject]="showSubject()"
|
|
8686
9158
|
[showTemplates]="showTemplates()"
|
|
8687
9159
|
[showVideo]="showVideo()"
|
|
9160
|
+
(bulkSending)="onBulkSending($event)"
|
|
9161
|
+
(bulkResult)="onBulkResult($event)"
|
|
8688
9162
|
(sent)="onSent()"
|
|
8689
9163
|
(emailAdded)="onEmailAdded($event)"
|
|
8690
9164
|
(validChange)="valid.set($event)" />
|
|
8691
9165
|
} @else {
|
|
8692
9166
|
<ui-send-text
|
|
8693
9167
|
#sendTextRef
|
|
8694
|
-
[contactName]="activeContact()
|
|
8695
|
-
[contactPhone]="activeContact()
|
|
8696
|
-
[contactEmail]="activeContact()
|
|
8697
|
-
[contactId]="activeContact()
|
|
9168
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
9169
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
9170
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
9171
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
9172
|
+
[bulkRecipients]="bulkRecipientsFor('text')"
|
|
8698
9173
|
[defaultBody]="defaultMessage()"
|
|
8699
9174
|
[context]="context()"
|
|
8700
9175
|
[sendFn]="sendText()"
|
|
8701
9176
|
[attachmentsAndScheduling]="attachmentsAndScheduling()"
|
|
8702
9177
|
[documents]="documentsOn()"
|
|
8703
9178
|
[documentPurposes]="documentPurposes()"
|
|
8704
|
-
[initialDocuments]="initialDocuments()"
|
|
9179
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8705
9180
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8706
|
-
[documentSigners]="documentSigners()"
|
|
9181
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8707
9182
|
[sendContext]="sendContext()"
|
|
8708
9183
|
[documentContextTypes]="documentContextTypes()"
|
|
8709
9184
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8710
|
-
[documentEnvelope]="documentEnvelope()"
|
|
9185
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8711
9186
|
[documentSentMessage]="documentSentMessage()"
|
|
8712
9187
|
(rejected)="rejected.emit()"
|
|
8713
9188
|
[documentPreview]="documentPreview()"
|
|
8714
9189
|
[videoDefaults]="videoDefaults()"
|
|
8715
9190
|
[showTemplates]="showTemplates()"
|
|
8716
9191
|
[showVideo]="showVideo()"
|
|
9192
|
+
(bulkSending)="onBulkSending($event)"
|
|
9193
|
+
(bulkResult)="onBulkResult($event)"
|
|
8717
9194
|
(sent)="onSent()"
|
|
8718
9195
|
(phoneAdded)="onPhoneAdded($event)"
|
|
8719
9196
|
(validChange)="valid.set($event)" />
|
|
8720
9197
|
}
|
|
8721
9198
|
}
|
|
9199
|
+
</div>
|
|
8722
9200
|
}
|
|
8723
9201
|
|
|
8724
9202
|
</ui-side-panel>
|
|
8725
9203
|
`,
|
|
8726
|
-
styles: [".msg-step{display:flex;align-items:center;gap:10px;margin-bottom:14px}.msg-step-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0;border-radius:50%;background:#1e293b;color:#fff;font-size:.75rem;font-weight:700}.msg-step-text{font-size:.9375rem;font-weight:600;color:#1e293b}.msg-channel-row{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}.msg-sms-notice{display:flex;align-items:center;gap:8px;margin-bottom:16px;padding:10px 12px;border-radius:8px;background:#f8fafc;border:1px solid #e2e8f0;font-size:.8125rem;color:#64748b}.msg-job{margin-bottom:16px}.msg-via-tabs{display:flex;gap:6px;flex-wrap:wrap}.msg-skeleton{display:flex;flex-direction:column;gap:12px;padding:4px 0}.skeleton-line{height:14px;border-radius:6px;background:linear-gradient(90deg,#e2e8f0 25%,#f1f5f9,#e2e8f0 75%);background-size:200% 100%;animation:skeleton-shimmer 1.4s infinite}.skeleton-line--wide{width:100%}.skeleton-line--medium{width:70%}.skeleton-line--narrow{width:45%}@keyframes skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"]
|
|
9204
|
+
styles: [".msg-step{display:flex;align-items:center;gap:10px;margin-bottom:14px}.msg-step-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0;border-radius:50%;background:#1e293b;color:#fff;font-size:.75rem;font-weight:700}.msg-step-text{font-size:.9375rem;font-weight:600;color:#1e293b}.msg-channel-row{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}.msg-sms-notice{display:flex;align-items:center;gap:8px;margin-bottom:16px;padding:10px 12px;border-radius:8px;background:#f8fafc;border:1px solid #e2e8f0;font-size:.8125rem;color:#64748b}.msg-job{margin-bottom:16px}.msg-locked-note{font-size:.75rem;color:#64748b}.msg-bulk{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}.msg-bulk-to{margin:0;font-size:.9375rem;font-weight:600;color:var(--shell-text, #1e293b)}.msg-bulk-counts{display:flex;flex-wrap:wrap;gap:6px}.msg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.msg-via-tabs{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.msg-skeleton{display:flex;flex-direction:column;gap:12px;padding:4px 0}.skeleton-line{height:14px;border-radius:6px;background:linear-gradient(90deg,#e2e8f0 25%,#f1f5f9,#e2e8f0 75%);background-size:200% 100%;animation:skeleton-shimmer 1.4s infinite}.skeleton-line--wide{width:100%}.skeleton-line--medium{width:70%}.skeleton-line--narrow{width:45%}@keyframes skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"]
|
|
8727
9205
|
}]
|
|
8728
9206
|
}],
|
|
8729
9207
|
ctorParameters: () => [],
|
|
@@ -8752,6 +9230,38 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8752
9230
|
required: false
|
|
8753
9231
|
}]
|
|
8754
9232
|
}],
|
|
9233
|
+
recipients: [{
|
|
9234
|
+
type: i0.Input,
|
|
9235
|
+
args: [{
|
|
9236
|
+
isSignal: true,
|
|
9237
|
+
alias: "recipients",
|
|
9238
|
+
required: false
|
|
9239
|
+
}]
|
|
9240
|
+
}],
|
|
9241
|
+
initialChannel: [{
|
|
9242
|
+
type: i0.Input,
|
|
9243
|
+
args: [{
|
|
9244
|
+
isSignal: true,
|
|
9245
|
+
alias: "initialChannel",
|
|
9246
|
+
required: false
|
|
9247
|
+
}]
|
|
9248
|
+
}],
|
|
9249
|
+
recipientNoun: [{
|
|
9250
|
+
type: i0.Input,
|
|
9251
|
+
args: [{
|
|
9252
|
+
isSignal: true,
|
|
9253
|
+
alias: "recipientNoun",
|
|
9254
|
+
required: false
|
|
9255
|
+
}]
|
|
9256
|
+
}],
|
|
9257
|
+
recipientNounSingular: [{
|
|
9258
|
+
type: i0.Input,
|
|
9259
|
+
args: [{
|
|
9260
|
+
isSignal: true,
|
|
9261
|
+
alias: "recipientNounSingular",
|
|
9262
|
+
required: false
|
|
9263
|
+
}]
|
|
9264
|
+
}],
|
|
8755
9265
|
textEnabled: [{
|
|
8756
9266
|
type: i0.Input,
|
|
8757
9267
|
args: [{
|
|
@@ -9100,6 +9610,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9100
9610
|
type: i0.Output,
|
|
9101
9611
|
args: ["sent"]
|
|
9102
9612
|
}],
|
|
9613
|
+
sentBulk: [{
|
|
9614
|
+
type: i0.Output,
|
|
9615
|
+
args: ["sentBulk"]
|
|
9616
|
+
}],
|
|
9103
9617
|
emailAdded: [{
|
|
9104
9618
|
type: i0.Output,
|
|
9105
9619
|
args: ["emailAdded"]
|
|
@@ -9130,6 +9644,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9130
9644
|
}]
|
|
9131
9645
|
}
|
|
9132
9646
|
});
|
|
9133
|
-
export { DEFAULT_DOCUMENT_SUBJECT, DEFAULT_SIGNING_OPTIONS, DOCUMENT_PROVIDER_OPTIONS, DOCUMENT_PURPOSE_OPTIONS, DocumentMergeCheckComponent, DocumentSendOptionsComponent, DocumentSignersComponent, MAX_CC, MERGE_CHECK_DEBOUNCE_MS, SIGNER_ROLES, SIGNER_ROLE_LABEL_DEFAULT, SIGNING_LIMITS, SendMessagePanelComponent, TemplatePickerComponent, VideoPickerComponent, appendVideoLink, applyVideoLine, buildSigners, buildVideoLink, countersignLine, countersignPlaceLabel, describeDocumentSigners, effectiveRoles, forwardContext, hasMappedDataFields, mergeFieldText, mergeWarningLines, messagePreviewHtml, normalizeRoles, parseCcList, roleNumber, sendExistingEnvelope, signerProblems, signerRoleLabel, stripVideoLink, suggestDocumentSubject, videoMessageLine };
|
|
9647
|
+
export { BULK_MERGE_TAG_HINT, BULK_NO_SEND_MESSAGE, DEFAULT_DOCUMENT_SUBJECT, DEFAULT_SIGNING_OPTIONS, DOCUMENT_PROVIDER_OPTIONS, DOCUMENT_PURPOSE_OPTIONS, DocumentMergeCheckComponent, DocumentSendOptionsComponent, DocumentSignersComponent, MAX_CC, MERGE_CHECK_DEBOUNCE_MS, PERSONAL_TAG_KEYS, SIGNER_ROLES, SIGNER_ROLE_LABEL_DEFAULT, SIGNING_LIMITS, SendMessagePanelComponent, TemplatePickerComponent, VideoPickerComponent, appendVideoLink, applyVideoLine, buildSigners, buildVideoLink, countersignLine, countersignPlaceLabel, describeDocumentSigners, effectiveRoles, forwardContext, hasMappedDataFields, mergeFieldText, mergeWarningLines, messagePreviewHtml, normalizeRoles, parseCcList, roleNumber, sendExistingEnvelope, signerProblems, signerRoleLabel, stripVideoLink, suggestDocumentSubject, videoMessageLine };
|
|
9134
9648
|
|
|
9135
9649
|
//# sourceMappingURL=forgeroute-ui-messaging.mjs.map
|