@forgeroute/ui 0.4.71 → 0.4.72
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 +603 -98
- package/fesm2022/forgeroute-ui-messaging.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-pdf.mjs +1 -0
- package/fesm2022/forgeroute-ui-pdf.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-stripe.mjs +891 -3
- package/fesm2022/forgeroute-ui-stripe.mjs.map +1 -1
- package/fesm2022/forgeroute-ui.mjs +4091 -665
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/forgeroute-ui-messaging.d.ts +190 -0
- package/types/forgeroute-ui-stripe.d.ts +161 -2
- package/types/forgeroute-ui.d.ts +1031 -16
|
@@ -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,7 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
1958
1958
|
inputs: [
|
|
1959
1959
|
"label",
|
|
1960
1960
|
"ariaLabel",
|
|
1961
|
+
"inputName",
|
|
1961
1962
|
"placeholder",
|
|
1962
1963
|
"options",
|
|
1963
1964
|
"valueType",
|
|
@@ -2080,6 +2081,7 @@ var DocumentSendOptionsComponent = class DocumentSendOptionsComponent {
|
|
|
2080
2081
|
"label",
|
|
2081
2082
|
"ariaLabel",
|
|
2082
2083
|
"inputTestId",
|
|
2084
|
+
"inputName",
|
|
2083
2085
|
"placeholder",
|
|
2084
2086
|
"prefix",
|
|
2085
2087
|
"revealable",
|
|
@@ -3287,6 +3289,7 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3287
3289
|
inputs: [
|
|
3288
3290
|
"label",
|
|
3289
3291
|
"ariaLabel",
|
|
3292
|
+
"inputName",
|
|
3290
3293
|
"placeholder",
|
|
3291
3294
|
"options",
|
|
3292
3295
|
"valueType",
|
|
@@ -3308,6 +3311,7 @@ var VideoLinkSettingsComponent = class VideoLinkSettingsComponent {
|
|
|
3308
3311
|
"label",
|
|
3309
3312
|
"ariaLabel",
|
|
3310
3313
|
"inputTestId",
|
|
3314
|
+
"inputName",
|
|
3311
3315
|
"placeholder",
|
|
3312
3316
|
"prefix",
|
|
3313
3317
|
"revealable",
|
|
@@ -3526,8 +3530,18 @@ function applyMergeTags(text, values) {
|
|
|
3526
3530
|
return v != null && String(v).trim() !== "" ? String(v) : whole;
|
|
3527
3531
|
});
|
|
3528
3532
|
}
|
|
3529
|
-
|
|
3530
|
-
|
|
3533
|
+
const PERSONAL_TAG_KEYS = [
|
|
3534
|
+
"first_name",
|
|
3535
|
+
"last_name",
|
|
3536
|
+
"full_name",
|
|
3537
|
+
"name",
|
|
3538
|
+
"email",
|
|
3539
|
+
"phone"
|
|
3540
|
+
];
|
|
3541
|
+
function hasLeftoverTags(text, ignoreKeys = []) {
|
|
3542
|
+
const t = text ?? "";
|
|
3543
|
+
if (ignoreKeys.length === 0) return ANY_TAG_RE.test(t);
|
|
3544
|
+
return ANY_TAG_RE.test(t.replace(TAG_RE, (whole, k) => ignoreKeys.includes(k) ? "" : whole));
|
|
3531
3545
|
}
|
|
3532
3546
|
function nonBlankValues(...sources) {
|
|
3533
3547
|
const out = {};
|
|
@@ -3561,6 +3575,7 @@ function marketVarsFrom(resp) {
|
|
|
3561
3575
|
function formatVarLabel(key) {
|
|
3562
3576
|
return key.replace(/[_.]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3563
3577
|
}
|
|
3578
|
+
const BULK_NO_SEND_MESSAGE = "Sending to several recipients is not set up for this page, so nothing was sent.";
|
|
3564
3579
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3565
3580
|
function messagePreviewHtml(body) {
|
|
3566
3581
|
if (!body) return "";
|
|
@@ -3569,6 +3584,9 @@ function messagePreviewHtml(body) {
|
|
|
3569
3584
|
}
|
|
3570
3585
|
const NO_DOCUMENTS$1 = [];
|
|
3571
3586
|
var SendEmailComponent = class SendEmailComponent {
|
|
3587
|
+
get deferredKeys() {
|
|
3588
|
+
return this.bulk() ? PERSONAL_TAG_KEYS : [];
|
|
3589
|
+
}
|
|
3572
3590
|
ngOnInit() {
|
|
3573
3591
|
this.includeReceipt = this.receiptDefault();
|
|
3574
3592
|
this.http.get(`${this.apiBase}/service-areas?size=100`).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ next: (resp) => {
|
|
@@ -3586,6 +3604,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3586
3604
|
this.contactEmail = input("", ...ngDevMode ? [{ debugName: "contactEmail" }] : /* istanbul ignore next */ []);
|
|
3587
3605
|
this.contactPhone = input("", ...ngDevMode ? [{ debugName: "contactPhone" }] : /* istanbul ignore next */ []);
|
|
3588
3606
|
this.contactId = input("", ...ngDevMode ? [{ debugName: "contactId" }] : /* istanbul ignore next */ []);
|
|
3607
|
+
this.bulkRecipients = input(null, ...ngDevMode ? [{ debugName: "bulkRecipients" }] : /* istanbul ignore next */ []);
|
|
3608
|
+
this.bulk = computed(() => this.bulkRecipients() !== null, ...ngDevMode ? [{ debugName: "bulk" }] : /* istanbul ignore next */ []);
|
|
3589
3609
|
this.defaultSubject = input("", ...ngDevMode ? [{ debugName: "defaultSubject" }] : /* istanbul ignore next */ []);
|
|
3590
3610
|
this.defaultBody = input("", ...ngDevMode ? [{ debugName: "defaultBody" }] : /* istanbul ignore next */ []);
|
|
3591
3611
|
this.context = input({}, ...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
@@ -3626,6 +3646,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3626
3646
|
this.showTemplates = input(true, ...ngDevMode ? [{ debugName: "showTemplates" }] : /* istanbul ignore next */ []);
|
|
3627
3647
|
this.showVideo = input(true, ...ngDevMode ? [{ debugName: "showVideo" }] : /* istanbul ignore next */ []);
|
|
3628
3648
|
this.sent = output();
|
|
3649
|
+
this.bulkResult = output();
|
|
3650
|
+
this.bulkSending = output();
|
|
3629
3651
|
this.emailAdded = output();
|
|
3630
3652
|
this.validChange = output();
|
|
3631
3653
|
this.rejected = output();
|
|
@@ -3684,6 +3706,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3684
3706
|
this.contactEmail();
|
|
3685
3707
|
this.contactId();
|
|
3686
3708
|
this.context();
|
|
3709
|
+
this.bulkRecipients();
|
|
3687
3710
|
untracked(() => this.notifyValid());
|
|
3688
3711
|
});
|
|
3689
3712
|
effect(() => {
|
|
@@ -3823,7 +3846,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3823
3846
|
if (this.ccError || this.documents() && this.documentsInvalid) return false;
|
|
3824
3847
|
if (this.signersActive && (this.signersInvalid || !this.signersValue)) return false;
|
|
3825
3848
|
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);
|
|
3849
|
+
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
3850
|
if (this.showSchedule) return hasContent && !!this.scheduledAt && new Date(this.scheduledAt).getTime() > Date.now();
|
|
3828
3851
|
return hasContent;
|
|
3829
3852
|
}
|
|
@@ -3833,7 +3856,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3833
3856
|
get knownVars() {
|
|
3834
3857
|
const name = this.contactName().trim();
|
|
3835
3858
|
const parts = name.split(/\s+/);
|
|
3836
|
-
return nonBlankValues({
|
|
3859
|
+
return nonBlankValues(this.bulk() ? {} : {
|
|
3837
3860
|
first_name: parts[0] ?? "",
|
|
3838
3861
|
last_name: parts.slice(1).join(" "),
|
|
3839
3862
|
full_name: name,
|
|
@@ -3870,11 +3893,11 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3870
3893
|
}
|
|
3871
3894
|
get missingVars() {
|
|
3872
3895
|
const known = this.knownVars;
|
|
3873
|
-
return mergeTagKeys(this.subject + " " + this.body).filter((k) => !known[k]);
|
|
3896
|
+
return mergeTagKeys(this.subject + " " + this.body).filter((k) => !known[k] && !this.deferredKeys.includes(k));
|
|
3874
3897
|
}
|
|
3875
3898
|
get composeTagError() {
|
|
3876
3899
|
if (this.mode !== "compose") return "";
|
|
3877
|
-
return hasLeftoverTags(this.resolvedSubject) || hasLeftoverTags(this.resolvedBody) ? "Replace every {{…}} field with text before sending." : "";
|
|
3900
|
+
return hasLeftoverTags(this.resolvedSubject, this.deferredKeys) || hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "Replace every {{…}} field with text before sending." : "";
|
|
3878
3901
|
}
|
|
3879
3902
|
get unresolvedVars() {
|
|
3880
3903
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -3916,7 +3939,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
3916
3939
|
this.cdr.markForCheck();
|
|
3917
3940
|
}
|
|
3918
3941
|
notifyValid() {
|
|
3919
|
-
this.validChange.emit(!!this.contactEmail() && this.canSend);
|
|
3942
|
+
this.validChange.emit((this.bulk() || !!this.contactEmail()) && this.canSend);
|
|
3920
3943
|
this.cdr.markForCheck();
|
|
3921
3944
|
}
|
|
3922
3945
|
setMode(key) {
|
|
@@ -4036,7 +4059,11 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4036
4059
|
this.videoPickerKey++;
|
|
4037
4060
|
}
|
|
4038
4061
|
submit() {
|
|
4039
|
-
if (!this.canSend || this.loading || !this.contactEmail()) return;
|
|
4062
|
+
if (!this.canSend || this.loading || !this.bulk() && !this.contactEmail()) return;
|
|
4063
|
+
if (this.bulk() && !this.sendFn()) {
|
|
4064
|
+
this.toast.error(BULK_NO_SEND_MESSAGE);
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4040
4067
|
if (this.mode === "template") this.applyPendingVars();
|
|
4041
4068
|
this.loading = true;
|
|
4042
4069
|
this.cdr.markForCheck();
|
|
@@ -4054,6 +4081,10 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4054
4081
|
scheduledAt: this.showSchedule && this.scheduledAt ? new Date(this.scheduledAt).toISOString() : void 0,
|
|
4055
4082
|
attachments: attachments.length ? attachments : void 0
|
|
4056
4083
|
};
|
|
4084
|
+
if (this.bulk()) {
|
|
4085
|
+
payload.recipients = [...this.bulkRecipients()];
|
|
4086
|
+
this.bulkSending.emit(payload.recipients);
|
|
4087
|
+
}
|
|
4057
4088
|
if (this.showReceiptOption() === true) payload.includeReceipt = this.includeReceipt;
|
|
4058
4089
|
if (this.mode === "template" && this.templateId) payload.templateId = this.templateId;
|
|
4059
4090
|
const cc = this.ccList;
|
|
@@ -4069,7 +4100,14 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4069
4100
|
payload.scheduledAt = void 0;
|
|
4070
4101
|
}
|
|
4071
4102
|
const custom = this.sendFn();
|
|
4072
|
-
|
|
4103
|
+
const safeHostCall = () => {
|
|
4104
|
+
try {
|
|
4105
|
+
return custom(payload);
|
|
4106
|
+
} catch (e) {
|
|
4107
|
+
return throwError(() => e);
|
|
4108
|
+
}
|
|
4109
|
+
};
|
|
4110
|
+
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
4111
|
subject: payload.subject || "Document Signature Required",
|
|
4074
4112
|
message: payload.body,
|
|
4075
4113
|
customerId: payload.contactId,
|
|
@@ -4093,8 +4131,22 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4093
4131
|
...cc.length ? { ccEmails: cc } : {},
|
|
4094
4132
|
...signingBodyFields(payload.documents),
|
|
4095
4133
|
...signersContextBodyFields(payload.documents)
|
|
4096
|
-
}, payload.templateId) : this.http.post(`${this.apiBase}/email-messages`, payload)
|
|
4097
|
-
|
|
4134
|
+
}, payload.templateId) : this.http.post(`${this.apiBase}/email-messages`, payload);
|
|
4135
|
+
let destroyed = false;
|
|
4136
|
+
this.destroyRef.onDestroy(() => {
|
|
4137
|
+
destroyed = true;
|
|
4138
|
+
});
|
|
4139
|
+
const onError = (err) => {
|
|
4140
|
+
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
4141
|
+
this.toast.error(custom || docs ? getErrorMessage(err, "email", "send") : serverMessage(err) || "Failed to send email");
|
|
4142
|
+
this.loading = false;
|
|
4143
|
+
this.cdr.markForCheck();
|
|
4144
|
+
if (this.bulk()) this.bulkSending.emit(null);
|
|
4145
|
+
const status = err?.status;
|
|
4146
|
+
if (docs && (status === 404 || status === 409)) this.rejected.emit();
|
|
4147
|
+
};
|
|
4148
|
+
req$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
4149
|
+
next: (result) => {
|
|
4098
4150
|
const sentText = docs ? this.documentSentMessage()?.({
|
|
4099
4151
|
titles: docs.documents.map((d) => d.title),
|
|
4100
4152
|
envelopeName: this.documentEnvelope()?.name,
|
|
@@ -4106,15 +4158,16 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4106
4158
|
this.loading = false;
|
|
4107
4159
|
this.attachments = [];
|
|
4108
4160
|
this.includeReceipt = this.receiptDefault();
|
|
4161
|
+
if (this.bulk()) this.bulkResult.emit({
|
|
4162
|
+
result,
|
|
4163
|
+
recipients: payload.recipients ?? []
|
|
4164
|
+
});
|
|
4109
4165
|
this.sent.emit();
|
|
4110
4166
|
this.cdr.markForCheck();
|
|
4111
4167
|
},
|
|
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();
|
|
4168
|
+
error: onError,
|
|
4169
|
+
complete: () => {
|
|
4170
|
+
if (!destroyed && this.bulk() && this.loading) onError(null);
|
|
4118
4171
|
}
|
|
4119
4172
|
});
|
|
4120
4173
|
}
|
|
@@ -4164,6 +4217,13 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4164
4217
|
isRequired: false,
|
|
4165
4218
|
transformFunction: null
|
|
4166
4219
|
},
|
|
4220
|
+
bulkRecipients: {
|
|
4221
|
+
classPropertyName: "bulkRecipients",
|
|
4222
|
+
publicName: "bulkRecipients",
|
|
4223
|
+
isSignal: true,
|
|
4224
|
+
isRequired: false,
|
|
4225
|
+
transformFunction: null
|
|
4226
|
+
},
|
|
4167
4227
|
defaultSubject: {
|
|
4168
4228
|
classPropertyName: "defaultSubject",
|
|
4169
4229
|
publicName: "defaultSubject",
|
|
@@ -4349,6 +4409,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4349
4409
|
},
|
|
4350
4410
|
outputs: {
|
|
4351
4411
|
sent: "sent",
|
|
4412
|
+
bulkResult: "bulkResult",
|
|
4413
|
+
bulkSending: "bulkSending",
|
|
4352
4414
|
emailAdded: "emailAdded",
|
|
4353
4415
|
validChange: "validChange",
|
|
4354
4416
|
rejected: "rejected",
|
|
@@ -4357,7 +4419,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4357
4419
|
ngImport: i0,
|
|
4358
4420
|
template: `
|
|
4359
4421
|
<!-- Missing email guard -->
|
|
4360
|
-
@if (!contactEmail()) {
|
|
4422
|
+
@if (!bulk() && !contactEmail()) {
|
|
4361
4423
|
<div class="sm-missing-banner">
|
|
4362
4424
|
<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
4425
|
No email address on file for this contact.
|
|
@@ -4374,7 +4436,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4374
4436
|
Save & Continue
|
|
4375
4437
|
</ui-button>
|
|
4376
4438
|
} @else {
|
|
4377
|
-
<!-- To -->
|
|
4439
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
4440
|
+
@if (!bulk()) {
|
|
4378
4441
|
<div class="sm-group">
|
|
4379
4442
|
<span class="sm-group-label">To</span>
|
|
4380
4443
|
<div class="sm-to-card">
|
|
@@ -4382,6 +4445,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4382
4445
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
4383
4446
|
</div>
|
|
4384
4447
|
</div>
|
|
4448
|
+
}
|
|
4385
4449
|
|
|
4386
4450
|
<ui-error errorId="sm-email-disabled" [message]="emailEnabled() ? '' : EMAIL_DISABLED_MESSAGE" />
|
|
4387
4451
|
|
|
@@ -4608,7 +4672,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4608
4672
|
<div class="sp-email-meta">
|
|
4609
4673
|
<div class="sp-meta-row">
|
|
4610
4674
|
<span class="sp-meta-label">To</span>
|
|
4611
|
-
<span class="sp-meta-value"
|
|
4675
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} <{{ contactEmail() }}> }</span>
|
|
4612
4676
|
</div>
|
|
4613
4677
|
<div class="sp-meta-row">
|
|
4614
4678
|
<span class="sp-meta-label">Subject</span>
|
|
@@ -4768,6 +4832,7 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4768
4832
|
"label",
|
|
4769
4833
|
"ariaLabel",
|
|
4770
4834
|
"inputTestId",
|
|
4835
|
+
"inputName",
|
|
4771
4836
|
"placeholder",
|
|
4772
4837
|
"prefix",
|
|
4773
4838
|
"revealable",
|
|
@@ -4965,7 +5030,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4965
5030
|
],
|
|
4966
5031
|
template: `
|
|
4967
5032
|
<!-- Missing email guard -->
|
|
4968
|
-
@if (!contactEmail()) {
|
|
5033
|
+
@if (!bulk() && !contactEmail()) {
|
|
4969
5034
|
<div class="sm-missing-banner">
|
|
4970
5035
|
<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
5036
|
No email address on file for this contact.
|
|
@@ -4982,7 +5047,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4982
5047
|
Save & Continue
|
|
4983
5048
|
</ui-button>
|
|
4984
5049
|
} @else {
|
|
4985
|
-
<!-- To -->
|
|
5050
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
5051
|
+
@if (!bulk()) {
|
|
4986
5052
|
<div class="sm-group">
|
|
4987
5053
|
<span class="sm-group-label">To</span>
|
|
4988
5054
|
<div class="sm-to-card">
|
|
@@ -4990,6 +5056,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4990
5056
|
<span class="sm-to-detail">{{ contactEmail() }}</span>
|
|
4991
5057
|
</div>
|
|
4992
5058
|
</div>
|
|
5059
|
+
}
|
|
4993
5060
|
|
|
4994
5061
|
<ui-error errorId="sm-email-disabled" [message]="emailEnabled() ? '' : EMAIL_DISABLED_MESSAGE" />
|
|
4995
5062
|
|
|
@@ -5216,7 +5283,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5216
5283
|
<div class="sp-email-meta">
|
|
5217
5284
|
<div class="sp-meta-row">
|
|
5218
5285
|
<span class="sp-meta-label">To</span>
|
|
5219
|
-
<span class="sp-meta-value"
|
|
5286
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} <{{ contactEmail() }}> }</span>
|
|
5220
5287
|
</div>
|
|
5221
5288
|
<div class="sp-meta-row">
|
|
5222
5289
|
<span class="sp-meta-label">Subject</span>
|
|
@@ -5265,6 +5332,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5265
5332
|
required: false
|
|
5266
5333
|
}]
|
|
5267
5334
|
}],
|
|
5335
|
+
bulkRecipients: [{
|
|
5336
|
+
type: i0.Input,
|
|
5337
|
+
args: [{
|
|
5338
|
+
isSignal: true,
|
|
5339
|
+
alias: "bulkRecipients",
|
|
5340
|
+
required: false
|
|
5341
|
+
}]
|
|
5342
|
+
}],
|
|
5268
5343
|
defaultSubject: [{
|
|
5269
5344
|
type: i0.Input,
|
|
5270
5345
|
args: [{
|
|
@@ -5477,6 +5552,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5477
5552
|
type: i0.Output,
|
|
5478
5553
|
args: ["sent"]
|
|
5479
5554
|
}],
|
|
5555
|
+
bulkResult: [{
|
|
5556
|
+
type: i0.Output,
|
|
5557
|
+
args: ["bulkResult"]
|
|
5558
|
+
}],
|
|
5559
|
+
bulkSending: [{
|
|
5560
|
+
type: i0.Output,
|
|
5561
|
+
args: ["bulkSending"]
|
|
5562
|
+
}],
|
|
5480
5563
|
emailAdded: [{
|
|
5481
5564
|
type: i0.Output,
|
|
5482
5565
|
args: ["emailAdded"]
|
|
@@ -5798,6 +5881,7 @@ var SendInAppComponent = class SendInAppComponent {
|
|
|
5798
5881
|
"label",
|
|
5799
5882
|
"ariaLabel",
|
|
5800
5883
|
"inputTestId",
|
|
5884
|
+
"inputName",
|
|
5801
5885
|
"placeholder",
|
|
5802
5886
|
"prefix",
|
|
5803
5887
|
"revealable",
|
|
@@ -6063,6 +6147,9 @@ function formatPhone(raw) {
|
|
|
6063
6147
|
}
|
|
6064
6148
|
const NO_DOCUMENTS = [];
|
|
6065
6149
|
var SendTextComponent = class SendTextComponent {
|
|
6150
|
+
get deferredKeys() {
|
|
6151
|
+
return this.bulk() ? PERSONAL_TAG_KEYS : [];
|
|
6152
|
+
}
|
|
6066
6153
|
ngOnInit() {
|
|
6067
6154
|
this.http.get(`${this.apiBase}/service-areas?size=100`).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ next: (resp) => {
|
|
6068
6155
|
this.marketVars = marketVarsFrom(resp);
|
|
@@ -6080,6 +6167,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6080
6167
|
this.contactPhone = input("", ...ngDevMode ? [{ debugName: "contactPhone" }] : /* istanbul ignore next */ []);
|
|
6081
6168
|
this.contactEmail = input("", ...ngDevMode ? [{ debugName: "contactEmail" }] : /* istanbul ignore next */ []);
|
|
6082
6169
|
this.contactId = input("", ...ngDevMode ? [{ debugName: "contactId" }] : /* istanbul ignore next */ []);
|
|
6170
|
+
this.bulkRecipients = input(null, ...ngDevMode ? [{ debugName: "bulkRecipients" }] : /* istanbul ignore next */ []);
|
|
6171
|
+
this.bulk = computed(() => this.bulkRecipients() !== null, ...ngDevMode ? [{ debugName: "bulk" }] : /* istanbul ignore next */ []);
|
|
6083
6172
|
this.defaultBody = input("", ...ngDevMode ? [{ debugName: "defaultBody" }] : /* istanbul ignore next */ []);
|
|
6084
6173
|
this.context = input({}, ...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
6085
6174
|
this.sendFn = input(null, ...ngDevMode ? [{ debugName: "sendFn" }] : /* istanbul ignore next */ []);
|
|
@@ -6112,6 +6201,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6112
6201
|
}, ...ngDevMode ? [{ debugName: "previewContact" }] : /* istanbul ignore next */ []);
|
|
6113
6202
|
this.videoDefaults = input(null, ...ngDevMode ? [{ debugName: "videoDefaults" }] : /* istanbul ignore next */ []);
|
|
6114
6203
|
this.sent = output();
|
|
6204
|
+
this.bulkResult = output();
|
|
6205
|
+
this.bulkSending = output();
|
|
6115
6206
|
this.phoneAdded = output();
|
|
6116
6207
|
this.validChange = output();
|
|
6117
6208
|
this.rejected = output();
|
|
@@ -6158,6 +6249,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6158
6249
|
this.contactPhone();
|
|
6159
6250
|
this.contactId();
|
|
6160
6251
|
this.context();
|
|
6252
|
+
this.bulkRecipients();
|
|
6161
6253
|
untracked(() => this.notifyValid());
|
|
6162
6254
|
});
|
|
6163
6255
|
effect(() => {
|
|
@@ -6218,7 +6310,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6218
6310
|
get canSend() {
|
|
6219
6311
|
if (this.documents() && this.documentsInvalid) return false;
|
|
6220
6312
|
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);
|
|
6313
|
+
const hasBody = this.body.trim().length > 0 && this.unresolvedVars.length === 0 && !hasLeftoverTags(this.resolvedBody, this.deferredKeys);
|
|
6222
6314
|
if (this.showSchedule) return hasBody && !!this.scheduledAt && new Date(this.scheduledAt).getTime() > Date.now();
|
|
6223
6315
|
return hasBody;
|
|
6224
6316
|
}
|
|
@@ -6228,7 +6320,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6228
6320
|
get knownVars() {
|
|
6229
6321
|
const name = this.contactName().trim();
|
|
6230
6322
|
const parts = name.split(/\s+/);
|
|
6231
|
-
return nonBlankValues({
|
|
6323
|
+
return nonBlankValues(this.bulk() ? {} : {
|
|
6232
6324
|
first_name: parts[0] ?? "",
|
|
6233
6325
|
last_name: parts.slice(1).join(" "),
|
|
6234
6326
|
full_name: name,
|
|
@@ -6253,13 +6345,13 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6253
6345
|
}
|
|
6254
6346
|
get missingVars() {
|
|
6255
6347
|
const known = this.knownVars;
|
|
6256
|
-
return mergeTagKeys(this.body).filter((k) => !known[k]);
|
|
6348
|
+
return mergeTagKeys(this.body).filter((k) => !known[k] && !this.deferredKeys.includes(k));
|
|
6257
6349
|
}
|
|
6258
6350
|
get videoLengthError() {
|
|
6259
6351
|
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
6352
|
}
|
|
6261
6353
|
get composeTagError() {
|
|
6262
|
-
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody) ? "Replace every {{…}} field with text before sending." : "";
|
|
6354
|
+
return this.mode === "compose" && hasLeftoverTags(this.resolvedBody, this.deferredKeys) ? "Replace every {{…}} field with text before sending." : "";
|
|
6263
6355
|
}
|
|
6264
6356
|
get unresolvedVars() {
|
|
6265
6357
|
return this.missingVars.filter((k) => !(this.pendingInputs[k] ?? "").trim());
|
|
@@ -6303,7 +6395,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6303
6395
|
this.notifyValid();
|
|
6304
6396
|
}
|
|
6305
6397
|
notifyValid() {
|
|
6306
|
-
this.validChange.emit(!!this.contactPhone() && this.canSend);
|
|
6398
|
+
this.validChange.emit((this.bulk() || !!this.contactPhone()) && this.canSend);
|
|
6307
6399
|
this.cdr.detectChanges();
|
|
6308
6400
|
}
|
|
6309
6401
|
setMode(key) {
|
|
@@ -6404,7 +6496,11 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6404
6496
|
this.videoPickerKey++;
|
|
6405
6497
|
}
|
|
6406
6498
|
submit() {
|
|
6407
|
-
if (!this.canSend || this.loading || !this.contactPhone()) return;
|
|
6499
|
+
if (!this.canSend || this.loading || !this.bulk() && !this.contactPhone()) return;
|
|
6500
|
+
if (this.bulk() && !this.sendFn()) {
|
|
6501
|
+
this.toast.error(BULK_NO_SEND_MESSAGE);
|
|
6502
|
+
return;
|
|
6503
|
+
}
|
|
6408
6504
|
if (this.mode === "template") this.applyPendingVars();
|
|
6409
6505
|
this.loading = true;
|
|
6410
6506
|
this.cdr.detectChanges();
|
|
@@ -6419,6 +6515,10 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6419
6515
|
mediaType: media?.mediaType ?? void 0,
|
|
6420
6516
|
mediaFileName: media?.mediaFileName ?? void 0
|
|
6421
6517
|
};
|
|
6518
|
+
if (this.bulk()) {
|
|
6519
|
+
payload.recipients = [...this.bulkRecipients()];
|
|
6520
|
+
this.bulkSending.emit(payload.recipients);
|
|
6521
|
+
}
|
|
6422
6522
|
if (this.mode === "template" && this.templateId) payload.templateId = this.templateId;
|
|
6423
6523
|
const docs = this.hasDocuments ? this.documentsValue : null;
|
|
6424
6524
|
if (docs) {
|
|
@@ -6432,7 +6532,14 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6432
6532
|
payload.scheduledAt = void 0;
|
|
6433
6533
|
}
|
|
6434
6534
|
const custom = this.sendFn();
|
|
6435
|
-
|
|
6535
|
+
const safeHostCall = () => {
|
|
6536
|
+
try {
|
|
6537
|
+
return custom(payload);
|
|
6538
|
+
} catch (e) {
|
|
6539
|
+
return throwError(() => e);
|
|
6540
|
+
}
|
|
6541
|
+
};
|
|
6542
|
+
const req$ = custom && this.bulk() ? safeHostCall() : custom ? custom(payload) : docs && this.documentEnvelope() ? sendExistingEnvelope(this.http, this.apiBase, this.documentEnvelope().id, {
|
|
6436
6543
|
subject: DEFAULT_DOCUMENT_SUBJECT,
|
|
6437
6544
|
message: payload.body,
|
|
6438
6545
|
customerId: payload.contactId,
|
|
@@ -6456,8 +6563,22 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6456
6563
|
delivery: "TEXT",
|
|
6457
6564
|
...signingBodyFields(payload.documents),
|
|
6458
6565
|
...signersContextBodyFields(payload.documents)
|
|
6459
|
-
}, payload.templateId) : this.http.post(`${this.apiBase}/text-messages`, payload)
|
|
6460
|
-
|
|
6566
|
+
}, payload.templateId) : this.http.post(`${this.apiBase}/text-messages`, payload);
|
|
6567
|
+
let destroyed = false;
|
|
6568
|
+
this.destroyRef.onDestroy(() => {
|
|
6569
|
+
destroyed = true;
|
|
6570
|
+
});
|
|
6571
|
+
const onError = (err) => {
|
|
6572
|
+
if (this.bulk() && (destroyed || !this.loading)) return;
|
|
6573
|
+
this.toast.error(custom || docs ? getErrorMessage(err, "text message", "send") : serverMessage(err) || "Failed to send text message");
|
|
6574
|
+
this.loading = false;
|
|
6575
|
+
this.cdr.detectChanges();
|
|
6576
|
+
if (this.bulk()) this.bulkSending.emit(null);
|
|
6577
|
+
const status = err?.status;
|
|
6578
|
+
if (docs && (status === 404 || status === 409)) this.rejected.emit();
|
|
6579
|
+
};
|
|
6580
|
+
req$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
6581
|
+
next: (result) => {
|
|
6461
6582
|
const sentText = docs ? this.documentSentMessage()?.({
|
|
6462
6583
|
titles: docs.documents.map((d) => d.title),
|
|
6463
6584
|
envelopeName: this.documentEnvelope()?.name,
|
|
@@ -6467,15 +6588,16 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6467
6588
|
this.toast.show(sentText ?? (docs && this.documentEnvelope() ? `Envelope "${this.documentEnvelope().name}" sent` : this.showSchedule ? "Message scheduled" : "Text message sent"));
|
|
6468
6589
|
this.loading = false;
|
|
6469
6590
|
this.mediaAttachment.set(null);
|
|
6591
|
+
if (this.bulk()) this.bulkResult.emit({
|
|
6592
|
+
result,
|
|
6593
|
+
recipients: payload.recipients ?? []
|
|
6594
|
+
});
|
|
6470
6595
|
this.sent.emit();
|
|
6471
6596
|
this.cdr.detectChanges();
|
|
6472
6597
|
},
|
|
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();
|
|
6598
|
+
error: onError,
|
|
6599
|
+
complete: () => {
|
|
6600
|
+
if (!destroyed && this.bulk() && this.loading) onError(null);
|
|
6479
6601
|
}
|
|
6480
6602
|
});
|
|
6481
6603
|
}
|
|
@@ -6525,6 +6647,13 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6525
6647
|
isRequired: false,
|
|
6526
6648
|
transformFunction: null
|
|
6527
6649
|
},
|
|
6650
|
+
bulkRecipients: {
|
|
6651
|
+
classPropertyName: "bulkRecipients",
|
|
6652
|
+
publicName: "bulkRecipients",
|
|
6653
|
+
isSignal: true,
|
|
6654
|
+
isRequired: false,
|
|
6655
|
+
transformFunction: null
|
|
6656
|
+
},
|
|
6528
6657
|
defaultBody: {
|
|
6529
6658
|
classPropertyName: "defaultBody",
|
|
6530
6659
|
publicName: "defaultBody",
|
|
@@ -6654,6 +6783,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6654
6783
|
},
|
|
6655
6784
|
outputs: {
|
|
6656
6785
|
sent: "sent",
|
|
6786
|
+
bulkResult: "bulkResult",
|
|
6787
|
+
bulkSending: "bulkSending",
|
|
6657
6788
|
phoneAdded: "phoneAdded",
|
|
6658
6789
|
validChange: "validChange",
|
|
6659
6790
|
rejected: "rejected"
|
|
@@ -6661,7 +6792,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6661
6792
|
ngImport: i0,
|
|
6662
6793
|
template: `
|
|
6663
6794
|
<!-- Missing phone guard -->
|
|
6664
|
-
@if (!contactPhone()) {
|
|
6795
|
+
@if (!bulk() && !contactPhone()) {
|
|
6665
6796
|
<div class="sm-missing-banner">
|
|
6666
6797
|
<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
6798
|
No phone number on file for this contact.
|
|
@@ -6678,7 +6809,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6678
6809
|
Save & Continue
|
|
6679
6810
|
</ui-button>
|
|
6680
6811
|
} @else {
|
|
6681
|
-
<!-- To -->
|
|
6812
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
6813
|
+
@if (!bulk()) {
|
|
6682
6814
|
<div class="sm-group">
|
|
6683
6815
|
<span class="sm-group-label">To</span>
|
|
6684
6816
|
<div class="sm-to-card">
|
|
@@ -6686,6 +6818,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6686
6818
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
6687
6819
|
</div>
|
|
6688
6820
|
</div>
|
|
6821
|
+
}
|
|
6689
6822
|
|
|
6690
6823
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
6691
6824
|
@if (showTemplates()) {
|
|
@@ -6869,7 +7002,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6869
7002
|
<div class="sp-text-meta">
|
|
6870
7003
|
<div class="sp-meta-row">
|
|
6871
7004
|
<span class="sp-meta-label">To</span>
|
|
6872
|
-
<span class="sp-meta-value"
|
|
7005
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} {{ formatPhone(contactPhone()) }} }</span>
|
|
6873
7006
|
</div>
|
|
6874
7007
|
</div>
|
|
6875
7008
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7043,6 +7176,7 @@ var SendTextComponent = class SendTextComponent {
|
|
|
7043
7176
|
"label",
|
|
7044
7177
|
"ariaLabel",
|
|
7045
7178
|
"inputTestId",
|
|
7179
|
+
"inputName",
|
|
7046
7180
|
"placeholder",
|
|
7047
7181
|
"prefix",
|
|
7048
7182
|
"revealable",
|
|
@@ -7215,7 +7349,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7215
7349
|
],
|
|
7216
7350
|
template: `
|
|
7217
7351
|
<!-- Missing phone guard -->
|
|
7218
|
-
@if (!contactPhone()) {
|
|
7352
|
+
@if (!bulk() && !contactPhone()) {
|
|
7219
7353
|
<div class="sm-missing-banner">
|
|
7220
7354
|
<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
7355
|
No phone number on file for this contact.
|
|
@@ -7232,7 +7366,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7232
7366
|
Save & Continue
|
|
7233
7367
|
</ui-button>
|
|
7234
7368
|
} @else {
|
|
7235
|
-
<!-- To -->
|
|
7369
|
+
<!-- To (bulk mode: the panel shows the recipient summary instead) -->
|
|
7370
|
+
@if (!bulk()) {
|
|
7236
7371
|
<div class="sm-group">
|
|
7237
7372
|
<span class="sm-group-label">To</span>
|
|
7238
7373
|
<div class="sm-to-card">
|
|
@@ -7240,6 +7375,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7240
7375
|
<span class="sm-to-detail">{{ formatPhone(contactPhone()) }}</span>
|
|
7241
7376
|
</div>
|
|
7242
7377
|
</div>
|
|
7378
|
+
}
|
|
7243
7379
|
|
|
7244
7380
|
<!-- Mode (hidden with [showTemplates]="false": the form is Create Message only) -->
|
|
7245
7381
|
@if (showTemplates()) {
|
|
@@ -7423,7 +7559,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7423
7559
|
<div class="sp-text-meta">
|
|
7424
7560
|
<div class="sp-meta-row">
|
|
7425
7561
|
<span class="sp-meta-label">To</span>
|
|
7426
|
-
<span class="sp-meta-value"
|
|
7562
|
+
<span class="sp-meta-value">@if (bulk()) { {{ bulkRecipients()!.length }} recipient{{ bulkRecipients()!.length === 1 ? '' : 's' }} } @else { {{ contactName() }} {{ formatPhone(contactPhone()) }} }</span>
|
|
7427
7563
|
</div>
|
|
7428
7564
|
</div>
|
|
7429
7565
|
<div class="sp-text-body">{{ resolvedBody }}</div>
|
|
@@ -7486,6 +7622,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7486
7622
|
required: false
|
|
7487
7623
|
}]
|
|
7488
7624
|
}],
|
|
7625
|
+
bulkRecipients: [{
|
|
7626
|
+
type: i0.Input,
|
|
7627
|
+
args: [{
|
|
7628
|
+
isSignal: true,
|
|
7629
|
+
alias: "bulkRecipients",
|
|
7630
|
+
required: false
|
|
7631
|
+
}]
|
|
7632
|
+
}],
|
|
7489
7633
|
defaultBody: [{
|
|
7490
7634
|
type: i0.Input,
|
|
7491
7635
|
args: [{
|
|
@@ -7634,6 +7778,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7634
7778
|
type: i0.Output,
|
|
7635
7779
|
args: ["sent"]
|
|
7636
7780
|
}],
|
|
7781
|
+
bulkResult: [{
|
|
7782
|
+
type: i0.Output,
|
|
7783
|
+
args: ["bulkResult"]
|
|
7784
|
+
}],
|
|
7785
|
+
bulkSending: [{
|
|
7786
|
+
type: i0.Output,
|
|
7787
|
+
args: ["bulkSending"]
|
|
7788
|
+
}],
|
|
7637
7789
|
phoneAdded: [{
|
|
7638
7790
|
type: i0.Output,
|
|
7639
7791
|
args: ["phoneAdded"]
|
|
@@ -7648,7 +7800,46 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7648
7800
|
}]
|
|
7649
7801
|
}
|
|
7650
7802
|
});
|
|
7803
|
+
const BULK_MERGE_TAG_HINT = "Personal details such as {{first_name}} are filled in for each recipient when sent.";
|
|
7804
|
+
const SKIPPED_NAMES_SHOWN = 5;
|
|
7651
7805
|
var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
7806
|
+
skippedReason() {
|
|
7807
|
+
return this.channel() === "email" ? "no email address" : "no phone number or no opt-in to texts";
|
|
7808
|
+
}
|
|
7809
|
+
skippedNames() {
|
|
7810
|
+
const names = this.skippedRecipients().map((r) => r.name || "Unnamed");
|
|
7811
|
+
const shown = names.slice(0, SKIPPED_NAMES_SHOWN).join(", ");
|
|
7812
|
+
return names.length > SKIPPED_NAMES_SHOWN ? `${shown} and ${names.length - SKIPPED_NAMES_SHOWN} more` : shown;
|
|
7813
|
+
}
|
|
7814
|
+
bulkRecipientsFor(ch) {
|
|
7815
|
+
if (!this.bulkMode()) return null;
|
|
7816
|
+
return ch === "email" ? this.emailRecipients() : this.textRecipients();
|
|
7817
|
+
}
|
|
7818
|
+
onBulkSending(sent) {
|
|
7819
|
+
if (sent) {
|
|
7820
|
+
this.submitSnapshot = {
|
|
7821
|
+
channel: this.channel(),
|
|
7822
|
+
selected: [...this.bulkList()],
|
|
7823
|
+
sent: [...sent]
|
|
7824
|
+
};
|
|
7825
|
+
this.sending.set(true);
|
|
7826
|
+
} else {
|
|
7827
|
+
this.submitSnapshot = null;
|
|
7828
|
+
this.sending.set(false);
|
|
7829
|
+
}
|
|
7830
|
+
}
|
|
7831
|
+
resetBulkSend() {
|
|
7832
|
+
this.submitSnapshot = null;
|
|
7833
|
+
this.lastBulkResult = void 0;
|
|
7834
|
+
this.sending.set(false);
|
|
7835
|
+
}
|
|
7836
|
+
onBulkResult(e) {
|
|
7837
|
+
this.lastBulkResult = e.result;
|
|
7838
|
+
if (this.submitSnapshot) this.submitSnapshot = {
|
|
7839
|
+
...this.submitSnapshot,
|
|
7840
|
+
sent: [...e.recipients]
|
|
7841
|
+
};
|
|
7842
|
+
}
|
|
7652
7843
|
onJobPick(o) {
|
|
7653
7844
|
const job = o ? {
|
|
7654
7845
|
id: o.value,
|
|
@@ -7669,6 +7860,10 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7669
7860
|
this.open = input(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
|
|
7670
7861
|
this.contact = input(null, ...ngDevMode ? [{ debugName: "contact" }] : /* istanbul ignore next */ []);
|
|
7671
7862
|
this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
7863
|
+
this.recipients = input(null, ...ngDevMode ? [{ debugName: "recipients" }] : /* istanbul ignore next */ []);
|
|
7864
|
+
this.initialChannel = input(null, ...ngDevMode ? [{ debugName: "initialChannel" }] : /* istanbul ignore next */ []);
|
|
7865
|
+
this.recipientNoun = input("recipients", ...ngDevMode ? [{ debugName: "recipientNoun" }] : /* istanbul ignore next */ []);
|
|
7866
|
+
this.recipientNounSingular = input("", ...ngDevMode ? [{ debugName: "recipientNounSingular" }] : /* istanbul ignore next */ []);
|
|
7672
7867
|
this.textEnabled = input(false, ...ngDevMode ? [{ debugName: "textEnabled" }] : /* istanbul ignore next */ []);
|
|
7673
7868
|
this.title = input("Send Message", ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
|
|
7674
7869
|
this.defaultSubject = input("", ...ngDevMode ? [{ debugName: "defaultSubject" }] : /* istanbul ignore next */ []);
|
|
@@ -7691,7 +7886,9 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7691
7886
|
this.showSubject = input(true, ...ngDevMode ? [{ debugName: "showSubject" }] : /* istanbul ignore next */ []);
|
|
7692
7887
|
this.showTemplates = input(true, ...ngDevMode ? [{ debugName: "showTemplates" }] : /* istanbul ignore next */ []);
|
|
7693
7888
|
this.showVideo = input(true, ...ngDevMode ? [{ debugName: "showVideo" }] : /* istanbul ignore next */ []);
|
|
7694
|
-
this.inApp = computed(() => this.recipientMode() === "in-app", ...ngDevMode ? [{ debugName: "inApp" }] : /* istanbul ignore next */ []);
|
|
7889
|
+
this.inApp = computed(() => this.recipientMode() === "in-app" && !this.bulkMode(), ...ngDevMode ? [{ debugName: "inApp" }] : /* istanbul ignore next */ []);
|
|
7890
|
+
this.BULK_NO_SEND_MESSAGE = BULK_NO_SEND_MESSAGE;
|
|
7891
|
+
this.BULK_MERGE_TAG_HINT = BULK_MERGE_TAG_HINT;
|
|
7695
7892
|
this.attachmentsAndScheduling = input(true, ...ngDevMode ? [{ debugName: "attachmentsAndScheduling" }] : /* istanbul ignore next */ []);
|
|
7696
7893
|
this.documentPurposes = input([
|
|
7697
7894
|
"ESIGN",
|
|
@@ -7712,7 +7909,50 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7712
7909
|
this.docuSignConnected = input(false, ...ngDevMode ? [{ debugName: "docuSignConnected" }] : /* istanbul ignore next */ []);
|
|
7713
7910
|
this.documentPreview = input(null, ...ngDevMode ? [{ debugName: "documentPreview" }] : /* istanbul ignore next */ []);
|
|
7714
7911
|
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 */ []);
|
|
7912
|
+
this.documentsOn = computed(() => (this.documents() || !!this.documentEnvelope()) && this.documentsEnabled() && !this.bulkMode(), ...ngDevMode ? [{ debugName: "documentsOn" }] : /* istanbul ignore next */ []);
|
|
7913
|
+
this.bulkList = computed(() => {
|
|
7914
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7915
|
+
return (this.recipients() ?? []).filter((r) => !seen.has(r.id) && !!seen.add(r.id));
|
|
7916
|
+
}, ...ngDevMode ? [{ debugName: "bulkList" }] : /* istanbul ignore next */ []);
|
|
7917
|
+
this.bulkMode = computed(() => this.bulkList().length > 0, ...ngDevMode ? [{ debugName: "bulkMode" }] : /* istanbul ignore next */ []);
|
|
7918
|
+
this.emailRecipients = computed(() => this.bulkList().filter((r) => !!r.email?.trim()), ...ngDevMode ? [{ debugName: "emailRecipients" }] : /* istanbul ignore next */ []);
|
|
7919
|
+
this.textRecipients = computed(() => this.textEnabled() ? this.bulkList().filter((r) => !!r.phone?.trim() && r.smsOptedIn === true) : [], ...ngDevMode ? [{ debugName: "textRecipients" }] : /* istanbul ignore next */ []);
|
|
7920
|
+
this.activeRecipients = computed(() => this.channel() === "email" ? this.emailRecipients() : this.textRecipients(), ...ngDevMode ? [{ debugName: "activeRecipients" }] : /* istanbul ignore next */ []);
|
|
7921
|
+
this.skippedRecipients = computed(() => {
|
|
7922
|
+
const ok = new Set(this.activeRecipients());
|
|
7923
|
+
return this.bulkList().filter((r) => !ok.has(r));
|
|
7924
|
+
}, ...ngDevMode ? [{ debugName: "skippedRecipients" }] : /* istanbul ignore next */ []);
|
|
7925
|
+
this.bulkNoneEligible = computed(() => this.bulkMode() && this.activeRecipients().length === 0, ...ngDevMode ? [{ debugName: "bulkNoneEligible" }] : /* istanbul ignore next */ []);
|
|
7926
|
+
this.bulkMissingSend = computed(() => this.bulkMode() && !(this.channel() === "email" ? this.sendEmail() : this.sendText()), ...ngDevMode ? [{ debugName: "bulkMissingSend" }] : /* istanbul ignore next */ []);
|
|
7927
|
+
this.bulkBlocked = computed(() => this.bulkMode() && (this.bulkNoneEligible() || this.bulkMissingSend()), ...ngDevMode ? [{ debugName: "bulkBlocked" }] : /* istanbul ignore next */ []);
|
|
7928
|
+
this.hasTarget = computed(() => this.bulkMode() || !!this.activeContact(), ...ngDevMode ? [{ debugName: "hasTarget" }] : /* istanbul ignore next */ []);
|
|
7929
|
+
this.sending = signal(false, ...ngDevMode ? [{ debugName: "sending" }] : /* istanbul ignore next */ []);
|
|
7930
|
+
this.submitSnapshot = null;
|
|
7931
|
+
this.recipientWord = computed(() => {
|
|
7932
|
+
const n = this.bulkList().length;
|
|
7933
|
+
const plural = this.recipientNoun() || "recipients";
|
|
7934
|
+
if (n !== 1) return plural;
|
|
7935
|
+
return this.recipientNounSingular() || (plural.endsWith("s") ? plural.slice(0, -1) : plural);
|
|
7936
|
+
}, ...ngDevMode ? [{ debugName: "recipientWord" }] : /* istanbul ignore next */ []);
|
|
7937
|
+
this.skippedText = computed(() => {
|
|
7938
|
+
const n = this.skippedRecipients().length;
|
|
7939
|
+
if (n === 0) return "";
|
|
7940
|
+
const what = this.channel() === "email" ? "email" : "text";
|
|
7941
|
+
return `${n} ${n === 1 ? "has" : "have"} ${this.skippedReason()} and will be skipped (${this.skippedNames()}). Only the others get this ${what}.`;
|
|
7942
|
+
}, ...ngDevMode ? [{ debugName: "skippedText" }] : /* istanbul ignore next */ []);
|
|
7943
|
+
this.noneEligibleText = computed(() => {
|
|
7944
|
+
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.`;
|
|
7945
|
+
}, ...ngDevMode ? [{ debugName: "noneEligibleText" }] : /* istanbul ignore next */ []);
|
|
7946
|
+
this.bulkAnnouncement = computed(() => {
|
|
7947
|
+
if (!this.bulkMode()) return "";
|
|
7948
|
+
const n = this.bulkList().length;
|
|
7949
|
+
const ok = this.activeRecipients().length;
|
|
7950
|
+
const ch = this.channel() === "email" ? "email" : "text";
|
|
7951
|
+
if (ok === 0) return `${n} ${this.recipientWord()} selected. None can receive the ${ch}.`;
|
|
7952
|
+
const skipped = this.skippedRecipients().length;
|
|
7953
|
+
return `${n} ${this.recipientWord()} selected. ${ok} can receive the ${ch}.${skipped ? ` ${skipped} will be skipped.` : ""}`;
|
|
7954
|
+
}, ...ngDevMode ? [{ debugName: "bulkAnnouncement" }] : /* istanbul ignore next */ []);
|
|
7955
|
+
this.lastBulkResult = void 0;
|
|
7716
7956
|
this.showJobPicker = input(false, ...ngDevMode ? [{ debugName: "showJobPicker" }] : /* istanbul ignore next */ []);
|
|
7717
7957
|
this.jobLabel = input("Job", ...ngDevMode ? [{ debugName: "jobLabel" }] : /* istanbul ignore next */ []);
|
|
7718
7958
|
this.jobHint = input("", ...ngDevMode ? [{ debugName: "jobHint" }] : /* istanbul ignore next */ []);
|
|
@@ -7720,6 +7960,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7720
7960
|
this.jobSelected = output();
|
|
7721
7961
|
this.closed = output();
|
|
7722
7962
|
this.sent = output();
|
|
7963
|
+
this.sentBulk = output();
|
|
7723
7964
|
this.emailAdded = output();
|
|
7724
7965
|
this.rejected = output();
|
|
7725
7966
|
this.mapFieldsClick = output();
|
|
@@ -7777,6 +8018,31 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7777
8018
|
const loadingVal = this.loading();
|
|
7778
8019
|
const openedNow = openVal && !this._prevOpen;
|
|
7779
8020
|
this._prevOpen = openVal;
|
|
8021
|
+
if (this.bulkMode()) {
|
|
8022
|
+
const emailCount = this.emailRecipients().length;
|
|
8023
|
+
const textCount = this.textRecipients().length;
|
|
8024
|
+
untracked(() => {
|
|
8025
|
+
const wasSingle = !!this.activeContact();
|
|
8026
|
+
const ch = this.channel();
|
|
8027
|
+
const activeCount = ch === "email" ? emailCount : textCount;
|
|
8028
|
+
const otherCount = ch === "email" ? textCount : emailCount;
|
|
8029
|
+
const pref = this.initialChannel();
|
|
8030
|
+
const defaultCh = pref === "text" && textCount > 0 ? "text" : pref === "email" && emailCount > 0 ? "email" : emailCount > 0 || textCount === 0 ? "email" : "text";
|
|
8031
|
+
if (openedNow || wasSingle) {
|
|
8032
|
+
this.activeContact.set(null);
|
|
8033
|
+
this.channel.set(defaultCh);
|
|
8034
|
+
} else if (openVal && activeCount === 0 && otherCount > 0 && !this.sending()) this.channel.set(ch === "email" ? "text" : "email");
|
|
8035
|
+
else return;
|
|
8036
|
+
this.resetBulkSend();
|
|
8037
|
+
this.valid.set(false);
|
|
8038
|
+
this.resetJob();
|
|
8039
|
+
this.formEpoch.update((n) => n + 1);
|
|
8040
|
+
});
|
|
8041
|
+
return;
|
|
8042
|
+
}
|
|
8043
|
+
untracked(() => {
|
|
8044
|
+
if (openedNow || this.sending() || this.submitSnapshot) this.resetBulkSend();
|
|
8045
|
+
});
|
|
7780
8046
|
if (!openedNow && !(openVal && !loadingVal && !!contactVal)) return;
|
|
7781
8047
|
const c = contactVal ?? null;
|
|
7782
8048
|
const active = untracked(() => this.activeContact());
|
|
@@ -7800,6 +8066,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7800
8066
|
this.formEpoch.update((n) => n + 1);
|
|
7801
8067
|
}
|
|
7802
8068
|
onChannelChange(ch) {
|
|
8069
|
+
if (this.sending()) return;
|
|
7803
8070
|
this.channel.set(ch);
|
|
7804
8071
|
this.valid.set(false);
|
|
7805
8072
|
}
|
|
@@ -7820,12 +8087,29 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7820
8087
|
this.phoneAdded.emit(phone);
|
|
7821
8088
|
}
|
|
7822
8089
|
submit() {
|
|
8090
|
+
if (this.bulkBlocked()) return;
|
|
7823
8091
|
if (this.inApp()) this.sendInAppRef()?.submit();
|
|
7824
8092
|
else if (this.channel() === "email") this.sendEmailRef()?.submit();
|
|
7825
8093
|
else this.sendTextRef()?.submit();
|
|
7826
8094
|
}
|
|
7827
8095
|
onSent() {
|
|
8096
|
+
const snap = this.submitSnapshot;
|
|
8097
|
+
const bulk = !!snap || this.bulkMode();
|
|
8098
|
+
const channel = snap?.channel ?? this.channel();
|
|
8099
|
+
const selected = snap?.selected ?? [...this.bulkList()];
|
|
8100
|
+
const sentList = snap?.sent ?? [...this.activeRecipients()];
|
|
8101
|
+
const sentIds = new Set(sentList.map((r) => r.id));
|
|
8102
|
+
const event = bulk ? {
|
|
8103
|
+
channel,
|
|
8104
|
+
recipients: sentList,
|
|
8105
|
+
skipped: selected.filter((r) => !sentIds.has(r.id)),
|
|
8106
|
+
result: this.lastBulkResult
|
|
8107
|
+
} : null;
|
|
8108
|
+
this.lastBulkResult = void 0;
|
|
8109
|
+
this.submitSnapshot = null;
|
|
8110
|
+
this.sending.set(false);
|
|
7828
8111
|
this.sent.emit();
|
|
8112
|
+
if (event) this.sentBulk.emit(event);
|
|
7829
8113
|
this.closed.emit();
|
|
7830
8114
|
}
|
|
7831
8115
|
onClose() {
|
|
@@ -7870,6 +8154,34 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
7870
8154
|
isRequired: false,
|
|
7871
8155
|
transformFunction: null
|
|
7872
8156
|
},
|
|
8157
|
+
recipients: {
|
|
8158
|
+
classPropertyName: "recipients",
|
|
8159
|
+
publicName: "recipients",
|
|
8160
|
+
isSignal: true,
|
|
8161
|
+
isRequired: false,
|
|
8162
|
+
transformFunction: null
|
|
8163
|
+
},
|
|
8164
|
+
initialChannel: {
|
|
8165
|
+
classPropertyName: "initialChannel",
|
|
8166
|
+
publicName: "initialChannel",
|
|
8167
|
+
isSignal: true,
|
|
8168
|
+
isRequired: false,
|
|
8169
|
+
transformFunction: null
|
|
8170
|
+
},
|
|
8171
|
+
recipientNoun: {
|
|
8172
|
+
classPropertyName: "recipientNoun",
|
|
8173
|
+
publicName: "recipientNoun",
|
|
8174
|
+
isSignal: true,
|
|
8175
|
+
isRequired: false,
|
|
8176
|
+
transformFunction: null
|
|
8177
|
+
},
|
|
8178
|
+
recipientNounSingular: {
|
|
8179
|
+
classPropertyName: "recipientNounSingular",
|
|
8180
|
+
publicName: "recipientNounSingular",
|
|
8181
|
+
isSignal: true,
|
|
8182
|
+
isRequired: false,
|
|
8183
|
+
transformFunction: null
|
|
8184
|
+
},
|
|
7873
8185
|
textEnabled: {
|
|
7874
8186
|
classPropertyName: "textEnabled",
|
|
7875
8187
|
publicName: "textEnabled",
|
|
@@ -8169,6 +8481,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8169
8481
|
jobSelected: "jobSelected",
|
|
8170
8482
|
closed: "closed",
|
|
8171
8483
|
sent: "sent",
|
|
8484
|
+
sentBulk: "sentBulk",
|
|
8172
8485
|
emailAdded: "emailAdded",
|
|
8173
8486
|
rejected: "rejected",
|
|
8174
8487
|
mapFieldsClick: "mapFieldsClick",
|
|
@@ -8204,9 +8517,9 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8204
8517
|
[title]="title()"
|
|
8205
8518
|
[wide]="wide()"
|
|
8206
8519
|
cancelLabel="Cancel"
|
|
8207
|
-
[primaryLabel]="!loading() &&
|
|
8520
|
+
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? 'Send Message' : channel() === 'email' ? 'Send Email' : 'Send Text')) : ''"
|
|
8208
8521
|
primaryVariant="warning"
|
|
8209
|
-
[primaryDisabled]="!valid()"
|
|
8522
|
+
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
8210
8523
|
(closed)="onClose()"
|
|
8211
8524
|
(primaryClick)="submit()">
|
|
8212
8525
|
|
|
@@ -8218,7 +8531,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8218
8531
|
</div>
|
|
8219
8532
|
}
|
|
8220
8533
|
|
|
8221
|
-
@if (!loading() && !
|
|
8534
|
+
@if (!loading() && !hasTarget() && !inApp()) {
|
|
8222
8535
|
<div class="msg-step">
|
|
8223
8536
|
<span class="msg-step-badge">1</span>
|
|
8224
8537
|
<span class="msg-step-text">Who would you like to message?</span>
|
|
@@ -8228,8 +8541,60 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8228
8541
|
(contactSelected)="onContactSelected($event)" />
|
|
8229
8542
|
}
|
|
8230
8543
|
|
|
8231
|
-
@if (!loading() &&
|
|
8232
|
-
@if (
|
|
8544
|
+
@if (!loading() && hasTarget()) {
|
|
8545
|
+
@if (bulkMode()) {
|
|
8546
|
+
<div class="msg-bulk" role="group" aria-label="Recipients" data-testid="bulk-summary">
|
|
8547
|
+
<p class="msg-bulk-to" data-testid="bulk-to">To: {{ bulkList().length }} {{ recipientWord() }}</p>
|
|
8548
|
+
<div class="msg-bulk-counts">
|
|
8549
|
+
<ui-badge [label]="emailRecipients().length + ' can receive email'" [variant]="emailRecipients().length ? 'blue' : 'gray'" />
|
|
8550
|
+
@if (textEnabled()) {
|
|
8551
|
+
<ui-badge [label]="textRecipients().length + ' can receive text'" [variant]="textRecipients().length ? 'blue' : 'gray'" />
|
|
8552
|
+
}
|
|
8553
|
+
</div>
|
|
8554
|
+
@if (!textEnabled()) {
|
|
8555
|
+
<ui-hint>Text messaging is not enabled. Connect Twilio in Comm Settings to send texts.</ui-hint>
|
|
8556
|
+
}
|
|
8557
|
+
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
8558
|
+
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
8559
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-skipped">{{ skippedText() }}</ui-alert>
|
|
8560
|
+
}
|
|
8561
|
+
@if (bulkNoneEligible()) {
|
|
8562
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
8563
|
+
}
|
|
8564
|
+
@if (bulkMissingSend()) {
|
|
8565
|
+
<ui-alert variant="danger" data-testid="bulk-no-send">{{ BULK_NO_SEND_MESSAGE }}</ui-alert>
|
|
8566
|
+
}
|
|
8567
|
+
@if (!bulkNoneEligible()) {
|
|
8568
|
+
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
8569
|
+
}
|
|
8570
|
+
</div>
|
|
8571
|
+
}
|
|
8572
|
+
|
|
8573
|
+
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
8574
|
+
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
8575
|
+
<label class="form-label msg-via-label">Send via</label>
|
|
8576
|
+
@if (sending()) {
|
|
8577
|
+
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
8578
|
+
<div class="msg-via-tabs">
|
|
8579
|
+
<ui-badge [label]="channel() === 'email' ? 'Email' : 'Text'" variant="blue" />
|
|
8580
|
+
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">Channel locked while sending.</span>
|
|
8581
|
+
</div>
|
|
8582
|
+
} @else {
|
|
8583
|
+
<div class="msg-via-tabs">
|
|
8584
|
+
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
8585
|
+
<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>
|
|
8586
|
+
Email
|
|
8587
|
+
</ui-toggle-badge>
|
|
8588
|
+
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
8589
|
+
<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>
|
|
8590
|
+
Text
|
|
8591
|
+
</ui-toggle-badge>
|
|
8592
|
+
</div>
|
|
8593
|
+
}
|
|
8594
|
+
</div>
|
|
8595
|
+
}
|
|
8596
|
+
|
|
8597
|
+
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
8233
8598
|
<div class="msg-channel-row">
|
|
8234
8599
|
<label class="form-label msg-via-label">Send via</label>
|
|
8235
8600
|
<div class="msg-via-tabs">
|
|
@@ -8253,7 +8618,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8253
8618
|
}
|
|
8254
8619
|
|
|
8255
8620
|
<!-- Optional job link (hidden unless the host turns it on). -->
|
|
8256
|
-
@if (showJobPicker()) {
|
|
8621
|
+
@if (showJobPicker() && !bulkMode()) {
|
|
8257
8622
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8258
8623
|
<div class="msg-job">
|
|
8259
8624
|
<ui-combobox
|
|
@@ -8266,13 +8631,14 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8266
8631
|
}
|
|
8267
8632
|
|
|
8268
8633
|
<!-- Keyed on formEpoch: a fresh open or another contact gets brand-new forms (no stale draft / template). -->
|
|
8634
|
+
<div [hidden]="bulkNoneEligible()" data-testid="msg-forms">
|
|
8269
8635
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8270
8636
|
@if (inApp()) {
|
|
8271
8637
|
<ui-send-in-app
|
|
8272
8638
|
#sendInAppRef
|
|
8273
|
-
[contactName]="activeContact()
|
|
8274
|
-
[contactId]="activeContact()
|
|
8275
|
-
[contactEmail]="activeContact()
|
|
8639
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
8640
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
8641
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8276
8642
|
[allowAttachments]="inAppAttachments()"
|
|
8277
8643
|
[richText]="inAppRichText()"
|
|
8278
8644
|
[defaultSubject]="defaultSubject()"
|
|
@@ -8285,10 +8651,11 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8285
8651
|
} @else if (channel() === 'email') {
|
|
8286
8652
|
<ui-send-email
|
|
8287
8653
|
#sendEmailRef
|
|
8288
|
-
[contactName]="activeContact()
|
|
8289
|
-
[contactEmail]="activeContact()
|
|
8290
|
-
[contactPhone]="activeContact()
|
|
8291
|
-
[contactId]="activeContact()
|
|
8654
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
8655
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8656
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
8657
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
8658
|
+
[bulkRecipients]="bulkRecipientsFor('email')"
|
|
8292
8659
|
[defaultSubject]="defaultSubject()"
|
|
8293
8660
|
[defaultBody]="defaultBody()"
|
|
8294
8661
|
[context]="context()"
|
|
@@ -8298,13 +8665,13 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8298
8665
|
[receiptDefault]="receiptDefault()"
|
|
8299
8666
|
[documents]="documentsOn()"
|
|
8300
8667
|
[documentPurposes]="documentPurposes()"
|
|
8301
|
-
[initialDocuments]="initialDocuments()"
|
|
8668
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8302
8669
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8303
|
-
[documentSigners]="documentSigners()"
|
|
8670
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8304
8671
|
[sendContext]="sendContext()"
|
|
8305
8672
|
[documentContextTypes]="documentContextTypes()"
|
|
8306
8673
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8307
|
-
[documentEnvelope]="documentEnvelope()"
|
|
8674
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8308
8675
|
[emailEnabled]="emailEnabled()"
|
|
8309
8676
|
[documentSentMessage]="documentSentMessage()"
|
|
8310
8677
|
(rejected)="rejected.emit()"
|
|
@@ -8317,46 +8684,52 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8317
8684
|
[showSubject]="showSubject()"
|
|
8318
8685
|
[showTemplates]="showTemplates()"
|
|
8319
8686
|
[showVideo]="showVideo()"
|
|
8687
|
+
(bulkSending)="onBulkSending($event)"
|
|
8688
|
+
(bulkResult)="onBulkResult($event)"
|
|
8320
8689
|
(sent)="onSent()"
|
|
8321
8690
|
(emailAdded)="onEmailAdded($event)"
|
|
8322
8691
|
(validChange)="valid.set($event)" />
|
|
8323
8692
|
} @else {
|
|
8324
8693
|
<ui-send-text
|
|
8325
8694
|
#sendTextRef
|
|
8326
|
-
[contactName]="activeContact()
|
|
8327
|
-
[contactPhone]="activeContact()
|
|
8328
|
-
[contactEmail]="activeContact()
|
|
8329
|
-
[contactId]="activeContact()
|
|
8695
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
8696
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
8697
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8698
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
8699
|
+
[bulkRecipients]="bulkRecipientsFor('text')"
|
|
8330
8700
|
[defaultBody]="defaultMessage()"
|
|
8331
8701
|
[context]="context()"
|
|
8332
8702
|
[sendFn]="sendText()"
|
|
8333
8703
|
[attachmentsAndScheduling]="attachmentsAndScheduling()"
|
|
8334
8704
|
[documents]="documentsOn()"
|
|
8335
8705
|
[documentPurposes]="documentPurposes()"
|
|
8336
|
-
[initialDocuments]="initialDocuments()"
|
|
8706
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8337
8707
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8338
|
-
[documentSigners]="documentSigners()"
|
|
8708
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8339
8709
|
[sendContext]="sendContext()"
|
|
8340
8710
|
[documentContextTypes]="documentContextTypes()"
|
|
8341
8711
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8342
|
-
[documentEnvelope]="documentEnvelope()"
|
|
8712
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8343
8713
|
[documentSentMessage]="documentSentMessage()"
|
|
8344
8714
|
(rejected)="rejected.emit()"
|
|
8345
8715
|
[documentPreview]="documentPreview()"
|
|
8346
8716
|
[videoDefaults]="videoDefaults()"
|
|
8347
8717
|
[showTemplates]="showTemplates()"
|
|
8348
8718
|
[showVideo]="showVideo()"
|
|
8719
|
+
(bulkSending)="onBulkSending($event)"
|
|
8720
|
+
(bulkResult)="onBulkResult($event)"
|
|
8349
8721
|
(sent)="onSent()"
|
|
8350
8722
|
(phoneAdded)="onPhoneAdded($event)"
|
|
8351
8723
|
(validChange)="valid.set($event)" />
|
|
8352
8724
|
}
|
|
8353
8725
|
}
|
|
8726
|
+
</div>
|
|
8354
8727
|
}
|
|
8355
8728
|
|
|
8356
8729
|
</ui-side-panel>
|
|
8357
8730
|
`,
|
|
8358
8731
|
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"],
|
|
8732
|
+
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
8733
|
dependencies: [
|
|
8361
8734
|
{
|
|
8362
8735
|
kind: "component",
|
|
@@ -8400,6 +8773,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8400
8773
|
"contactEmail",
|
|
8401
8774
|
"contactPhone",
|
|
8402
8775
|
"contactId",
|
|
8776
|
+
"bulkRecipients",
|
|
8403
8777
|
"defaultSubject",
|
|
8404
8778
|
"defaultBody",
|
|
8405
8779
|
"context",
|
|
@@ -8429,6 +8803,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8429
8803
|
],
|
|
8430
8804
|
outputs: [
|
|
8431
8805
|
"sent",
|
|
8806
|
+
"bulkResult",
|
|
8807
|
+
"bulkSending",
|
|
8432
8808
|
"emailAdded",
|
|
8433
8809
|
"validChange",
|
|
8434
8810
|
"rejected",
|
|
@@ -8462,6 +8838,7 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8462
8838
|
"contactPhone",
|
|
8463
8839
|
"contactEmail",
|
|
8464
8840
|
"contactId",
|
|
8841
|
+
"bulkRecipients",
|
|
8465
8842
|
"defaultBody",
|
|
8466
8843
|
"context",
|
|
8467
8844
|
"sendFn",
|
|
@@ -8483,6 +8860,8 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8483
8860
|
],
|
|
8484
8861
|
outputs: [
|
|
8485
8862
|
"sent",
|
|
8863
|
+
"bulkResult",
|
|
8864
|
+
"bulkSending",
|
|
8486
8865
|
"phoneAdded",
|
|
8487
8866
|
"validChange",
|
|
8488
8867
|
"rejected"
|
|
@@ -8540,6 +8919,33 @@ var SendMessagePanelComponent = class SendMessagePanelComponent {
|
|
|
8540
8919
|
"focused",
|
|
8541
8920
|
"blurred"
|
|
8542
8921
|
]
|
|
8922
|
+
},
|
|
8923
|
+
{
|
|
8924
|
+
kind: "component",
|
|
8925
|
+
type: AlertComponent,
|
|
8926
|
+
selector: "ui-alert",
|
|
8927
|
+
inputs: [
|
|
8928
|
+
"variant",
|
|
8929
|
+
"title",
|
|
8930
|
+
"dismissible",
|
|
8931
|
+
"dismissAriaLabel",
|
|
8932
|
+
"quiet",
|
|
8933
|
+
"compact",
|
|
8934
|
+
"inline",
|
|
8935
|
+
"fill"
|
|
8936
|
+
],
|
|
8937
|
+
outputs: ["dismissed"]
|
|
8938
|
+
},
|
|
8939
|
+
{
|
|
8940
|
+
kind: "component",
|
|
8941
|
+
type: BadgeComponent,
|
|
8942
|
+
selector: "ui-badge",
|
|
8943
|
+
inputs: ["label", "variant"]
|
|
8944
|
+
},
|
|
8945
|
+
{
|
|
8946
|
+
kind: "component",
|
|
8947
|
+
type: HintComponent,
|
|
8948
|
+
selector: "ui-hint"
|
|
8543
8949
|
}
|
|
8544
8950
|
],
|
|
8545
8951
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
@@ -8564,7 +8970,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8564
8970
|
SendInAppComponent,
|
|
8565
8971
|
SendTextComponent,
|
|
8566
8972
|
ContactPickerComponent,
|
|
8567
|
-
ComboboxComponent
|
|
8973
|
+
ComboboxComponent,
|
|
8974
|
+
AlertComponent,
|
|
8975
|
+
BadgeComponent,
|
|
8976
|
+
HintComponent
|
|
8568
8977
|
],
|
|
8569
8978
|
template: `
|
|
8570
8979
|
<ui-side-panel
|
|
@@ -8572,9 +8981,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8572
8981
|
[title]="title()"
|
|
8573
8982
|
[wide]="wide()"
|
|
8574
8983
|
cancelLabel="Cancel"
|
|
8575
|
-
[primaryLabel]="!loading() &&
|
|
8984
|
+
[primaryLabel]="!loading() && hasTarget() ? (sendLabel() || (inApp() ? 'Send Message' : channel() === 'email' ? 'Send Email' : 'Send Text')) : ''"
|
|
8576
8985
|
primaryVariant="warning"
|
|
8577
|
-
[primaryDisabled]="!valid()"
|
|
8986
|
+
[primaryDisabled]="!valid() || bulkBlocked()"
|
|
8578
8987
|
(closed)="onClose()"
|
|
8579
8988
|
(primaryClick)="submit()">
|
|
8580
8989
|
|
|
@@ -8586,7 +8995,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8586
8995
|
</div>
|
|
8587
8996
|
}
|
|
8588
8997
|
|
|
8589
|
-
@if (!loading() && !
|
|
8998
|
+
@if (!loading() && !hasTarget() && !inApp()) {
|
|
8590
8999
|
<div class="msg-step">
|
|
8591
9000
|
<span class="msg-step-badge">1</span>
|
|
8592
9001
|
<span class="msg-step-text">Who would you like to message?</span>
|
|
@@ -8596,8 +9005,60 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8596
9005
|
(contactSelected)="onContactSelected($event)" />
|
|
8597
9006
|
}
|
|
8598
9007
|
|
|
8599
|
-
@if (!loading() &&
|
|
8600
|
-
@if (
|
|
9008
|
+
@if (!loading() && hasTarget()) {
|
|
9009
|
+
@if (bulkMode()) {
|
|
9010
|
+
<div class="msg-bulk" role="group" aria-label="Recipients" data-testid="bulk-summary">
|
|
9011
|
+
<p class="msg-bulk-to" data-testid="bulk-to">To: {{ bulkList().length }} {{ recipientWord() }}</p>
|
|
9012
|
+
<div class="msg-bulk-counts">
|
|
9013
|
+
<ui-badge [label]="emailRecipients().length + ' can receive email'" [variant]="emailRecipients().length ? 'blue' : 'gray'" />
|
|
9014
|
+
@if (textEnabled()) {
|
|
9015
|
+
<ui-badge [label]="textRecipients().length + ' can receive text'" [variant]="textRecipients().length ? 'blue' : 'gray'" />
|
|
9016
|
+
}
|
|
9017
|
+
</div>
|
|
9018
|
+
@if (!textEnabled()) {
|
|
9019
|
+
<ui-hint>Text messaging is not enabled. Connect Twilio in Comm Settings to send texts.</ui-hint>
|
|
9020
|
+
}
|
|
9021
|
+
<span class="msg-sr" role="status" data-testid="bulk-live">{{ bulkAnnouncement() }}</span>
|
|
9022
|
+
@if (skippedRecipients().length > 0 && !bulkNoneEligible()) {
|
|
9023
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-skipped">{{ skippedText() }}</ui-alert>
|
|
9024
|
+
}
|
|
9025
|
+
@if (bulkNoneEligible()) {
|
|
9026
|
+
<ui-alert variant="warning" [quiet]="true" data-testid="bulk-none-eligible">{{ noneEligibleText() }}</ui-alert>
|
|
9027
|
+
}
|
|
9028
|
+
@if (bulkMissingSend()) {
|
|
9029
|
+
<ui-alert variant="danger" data-testid="bulk-no-send">{{ BULK_NO_SEND_MESSAGE }}</ui-alert>
|
|
9030
|
+
}
|
|
9031
|
+
@if (!bulkNoneEligible()) {
|
|
9032
|
+
<ui-hint data-testid="bulk-merge-hint">{{ BULK_MERGE_TAG_HINT }}</ui-hint>
|
|
9033
|
+
}
|
|
9034
|
+
</div>
|
|
9035
|
+
}
|
|
9036
|
+
|
|
9037
|
+
@if (bulkMode() && textEnabled() && emailRecipients().length > 0 && textRecipients().length > 0) {
|
|
9038
|
+
<div class="msg-channel-row" data-testid="bulk-channel-row">
|
|
9039
|
+
<label class="form-label msg-via-label">Send via</label>
|
|
9040
|
+
@if (sending()) {
|
|
9041
|
+
<!-- A send is in flight: the toggle is replaced by plain text (ui-toggle-badge has no disabled state), so nothing pressable remains. -->
|
|
9042
|
+
<div class="msg-via-tabs">
|
|
9043
|
+
<ui-badge [label]="channel() === 'email' ? 'Email' : 'Text'" variant="blue" />
|
|
9044
|
+
<span class="msg-locked-note" role="status" data-testid="bulk-channel-locked">Channel locked while sending.</span>
|
|
9045
|
+
</div>
|
|
9046
|
+
} @else {
|
|
9047
|
+
<div class="msg-via-tabs">
|
|
9048
|
+
<ui-toggle-badge [active]="channel() === 'email'" (toggle)="onChannelChange('email')">
|
|
9049
|
+
<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>
|
|
9050
|
+
Email
|
|
9051
|
+
</ui-toggle-badge>
|
|
9052
|
+
<ui-toggle-badge [active]="channel() === 'text'" (toggle)="onChannelChange('text')">
|
|
9053
|
+
<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>
|
|
9054
|
+
Text
|
|
9055
|
+
</ui-toggle-badge>
|
|
9056
|
+
</div>
|
|
9057
|
+
}
|
|
9058
|
+
</div>
|
|
9059
|
+
}
|
|
9060
|
+
|
|
9061
|
+
@if (!bulkMode() && !inApp() && textEnabled() && activeContact()?.smsOptedIn) {
|
|
8601
9062
|
<div class="msg-channel-row">
|
|
8602
9063
|
<label class="form-label msg-via-label">Send via</label>
|
|
8603
9064
|
<div class="msg-via-tabs">
|
|
@@ -8621,7 +9082,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8621
9082
|
}
|
|
8622
9083
|
|
|
8623
9084
|
<!-- Optional job link (hidden unless the host turns it on). -->
|
|
8624
|
-
@if (showJobPicker()) {
|
|
9085
|
+
@if (showJobPicker() && !bulkMode()) {
|
|
8625
9086
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8626
9087
|
<div class="msg-job">
|
|
8627
9088
|
<ui-combobox
|
|
@@ -8634,13 +9095,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8634
9095
|
}
|
|
8635
9096
|
|
|
8636
9097
|
<!-- Keyed on formEpoch: a fresh open or another contact gets brand-new forms (no stale draft / template). -->
|
|
9098
|
+
<div [hidden]="bulkNoneEligible()" data-testid="msg-forms">
|
|
8637
9099
|
@for (epoch of [formEpoch()]; track epoch) {
|
|
8638
9100
|
@if (inApp()) {
|
|
8639
9101
|
<ui-send-in-app
|
|
8640
9102
|
#sendInAppRef
|
|
8641
|
-
[contactName]="activeContact()
|
|
8642
|
-
[contactId]="activeContact()
|
|
8643
|
-
[contactEmail]="activeContact()
|
|
9103
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
9104
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
9105
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
8644
9106
|
[allowAttachments]="inAppAttachments()"
|
|
8645
9107
|
[richText]="inAppRichText()"
|
|
8646
9108
|
[defaultSubject]="defaultSubject()"
|
|
@@ -8653,10 +9115,11 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8653
9115
|
} @else if (channel() === 'email') {
|
|
8654
9116
|
<ui-send-email
|
|
8655
9117
|
#sendEmailRef
|
|
8656
|
-
[contactName]="activeContact()
|
|
8657
|
-
[contactEmail]="activeContact()
|
|
8658
|
-
[contactPhone]="activeContact()
|
|
8659
|
-
[contactId]="activeContact()
|
|
9118
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
9119
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
9120
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
9121
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
9122
|
+
[bulkRecipients]="bulkRecipientsFor('email')"
|
|
8660
9123
|
[defaultSubject]="defaultSubject()"
|
|
8661
9124
|
[defaultBody]="defaultBody()"
|
|
8662
9125
|
[context]="context()"
|
|
@@ -8666,13 +9129,13 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8666
9129
|
[receiptDefault]="receiptDefault()"
|
|
8667
9130
|
[documents]="documentsOn()"
|
|
8668
9131
|
[documentPurposes]="documentPurposes()"
|
|
8669
|
-
[initialDocuments]="initialDocuments()"
|
|
9132
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8670
9133
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8671
|
-
[documentSigners]="documentSigners()"
|
|
9134
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8672
9135
|
[sendContext]="sendContext()"
|
|
8673
9136
|
[documentContextTypes]="documentContextTypes()"
|
|
8674
9137
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8675
|
-
[documentEnvelope]="documentEnvelope()"
|
|
9138
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8676
9139
|
[emailEnabled]="emailEnabled()"
|
|
8677
9140
|
[documentSentMessage]="documentSentMessage()"
|
|
8678
9141
|
(rejected)="rejected.emit()"
|
|
@@ -8685,45 +9148,51 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8685
9148
|
[showSubject]="showSubject()"
|
|
8686
9149
|
[showTemplates]="showTemplates()"
|
|
8687
9150
|
[showVideo]="showVideo()"
|
|
9151
|
+
(bulkSending)="onBulkSending($event)"
|
|
9152
|
+
(bulkResult)="onBulkResult($event)"
|
|
8688
9153
|
(sent)="onSent()"
|
|
8689
9154
|
(emailAdded)="onEmailAdded($event)"
|
|
8690
9155
|
(validChange)="valid.set($event)" />
|
|
8691
9156
|
} @else {
|
|
8692
9157
|
<ui-send-text
|
|
8693
9158
|
#sendTextRef
|
|
8694
|
-
[contactName]="activeContact()
|
|
8695
|
-
[contactPhone]="activeContact()
|
|
8696
|
-
[contactEmail]="activeContact()
|
|
8697
|
-
[contactId]="activeContact()
|
|
9159
|
+
[contactName]="(activeContact()?.name ?? '')"
|
|
9160
|
+
[contactPhone]="activeContact()?.phone ?? ''"
|
|
9161
|
+
[contactEmail]="activeContact()?.email ?? ''"
|
|
9162
|
+
[contactId]="(activeContact()?.id ?? '')"
|
|
9163
|
+
[bulkRecipients]="bulkRecipientsFor('text')"
|
|
8698
9164
|
[defaultBody]="defaultMessage()"
|
|
8699
9165
|
[context]="context()"
|
|
8700
9166
|
[sendFn]="sendText()"
|
|
8701
9167
|
[attachmentsAndScheduling]="attachmentsAndScheduling()"
|
|
8702
9168
|
[documents]="documentsOn()"
|
|
8703
9169
|
[documentPurposes]="documentPurposes()"
|
|
8704
|
-
[initialDocuments]="initialDocuments()"
|
|
9170
|
+
[initialDocuments]="bulkMode() ? [] : initialDocuments()"
|
|
8705
9171
|
[documentSigningOptions]="documentSigningOptions()"
|
|
8706
|
-
[documentSigners]="documentSigners()"
|
|
9172
|
+
[documentSigners]="bulkMode() ? null : documentSigners()"
|
|
8707
9173
|
[sendContext]="sendContext()"
|
|
8708
9174
|
[documentContextTypes]="documentContextTypes()"
|
|
8709
9175
|
[documentMergeCheck]="documentMergeCheck()"
|
|
8710
|
-
[documentEnvelope]="documentEnvelope()"
|
|
9176
|
+
[documentEnvelope]="bulkMode() ? null : documentEnvelope()"
|
|
8711
9177
|
[documentSentMessage]="documentSentMessage()"
|
|
8712
9178
|
(rejected)="rejected.emit()"
|
|
8713
9179
|
[documentPreview]="documentPreview()"
|
|
8714
9180
|
[videoDefaults]="videoDefaults()"
|
|
8715
9181
|
[showTemplates]="showTemplates()"
|
|
8716
9182
|
[showVideo]="showVideo()"
|
|
9183
|
+
(bulkSending)="onBulkSending($event)"
|
|
9184
|
+
(bulkResult)="onBulkResult($event)"
|
|
8717
9185
|
(sent)="onSent()"
|
|
8718
9186
|
(phoneAdded)="onPhoneAdded($event)"
|
|
8719
9187
|
(validChange)="valid.set($event)" />
|
|
8720
9188
|
}
|
|
8721
9189
|
}
|
|
9190
|
+
</div>
|
|
8722
9191
|
}
|
|
8723
9192
|
|
|
8724
9193
|
</ui-side-panel>
|
|
8725
9194
|
`,
|
|
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"]
|
|
9195
|
+
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
9196
|
}]
|
|
8728
9197
|
}],
|
|
8729
9198
|
ctorParameters: () => [],
|
|
@@ -8752,6 +9221,38 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8752
9221
|
required: false
|
|
8753
9222
|
}]
|
|
8754
9223
|
}],
|
|
9224
|
+
recipients: [{
|
|
9225
|
+
type: i0.Input,
|
|
9226
|
+
args: [{
|
|
9227
|
+
isSignal: true,
|
|
9228
|
+
alias: "recipients",
|
|
9229
|
+
required: false
|
|
9230
|
+
}]
|
|
9231
|
+
}],
|
|
9232
|
+
initialChannel: [{
|
|
9233
|
+
type: i0.Input,
|
|
9234
|
+
args: [{
|
|
9235
|
+
isSignal: true,
|
|
9236
|
+
alias: "initialChannel",
|
|
9237
|
+
required: false
|
|
9238
|
+
}]
|
|
9239
|
+
}],
|
|
9240
|
+
recipientNoun: [{
|
|
9241
|
+
type: i0.Input,
|
|
9242
|
+
args: [{
|
|
9243
|
+
isSignal: true,
|
|
9244
|
+
alias: "recipientNoun",
|
|
9245
|
+
required: false
|
|
9246
|
+
}]
|
|
9247
|
+
}],
|
|
9248
|
+
recipientNounSingular: [{
|
|
9249
|
+
type: i0.Input,
|
|
9250
|
+
args: [{
|
|
9251
|
+
isSignal: true,
|
|
9252
|
+
alias: "recipientNounSingular",
|
|
9253
|
+
required: false
|
|
9254
|
+
}]
|
|
9255
|
+
}],
|
|
8755
9256
|
textEnabled: [{
|
|
8756
9257
|
type: i0.Input,
|
|
8757
9258
|
args: [{
|
|
@@ -9100,6 +9601,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9100
9601
|
type: i0.Output,
|
|
9101
9602
|
args: ["sent"]
|
|
9102
9603
|
}],
|
|
9604
|
+
sentBulk: [{
|
|
9605
|
+
type: i0.Output,
|
|
9606
|
+
args: ["sentBulk"]
|
|
9607
|
+
}],
|
|
9103
9608
|
emailAdded: [{
|
|
9104
9609
|
type: i0.Output,
|
|
9105
9610
|
args: ["emailAdded"]
|
|
@@ -9130,6 +9635,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
9130
9635
|
}]
|
|
9131
9636
|
}
|
|
9132
9637
|
});
|
|
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 };
|
|
9638
|
+
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
9639
|
|
|
9135
9640
|
//# sourceMappingURL=forgeroute-ui-messaging.mjs.map
|