import { EditEntityComponent } from "#src/app/core/basic-datatypes/entity/edit-entity/edit-entity.component";
import { EntityMapperService } from "#src/app/core/entity/entity-mapper/entity-mapper.service";
import { Entity } from "#src/app/core/entity/model/entity";
import { DisableEntityOperationDirective } from "#src/app/core/permissions/permission-directive/disable-entity-operation.directive";
import {
Component,
inject,
OnInit,
ChangeDetectionStrategy,
} from "@angular/core";
import {
FormControl,
FormGroup,
ReactiveFormsModule,
Validators,
} from "@angular/forms";
import { MatButton } from "@angular/material/button";
import { MatCheckbox } from "@angular/material/checkbox";
import {
MAT_DIALOG_DATA,
MatDialogActions,
MatDialogClose,
MatDialogContent,
MatDialogRef,
} from "@angular/material/dialog";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatInputModule } from "@angular/material/input";
import { MatTooltipModule } from "@angular/material/tooltip";
import { RouterLink } from "@angular/router";
import { EmailTemplate } from "../email-template.entity";
import { getEntityRuntimeRoute } from "#src/app/core/entity/entity-config.service";
import { HelpButtonComponent } from "#src/app/core/common-components/help-button/help-button.component";
import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
import { switchMap, distinctUntilChanged } from "rxjs/operators";
import { from, of } from "rxjs";
/**
* Input to prefill the email template selection dialog
* with the relevant context.
*/
export interface EmailTemplateSelectionDialogData {
entity: Entity;
excludedEntitiesCount: number;
isBulk: boolean;
}
/**
* Output of the email template selection dialog
* when the user selects and confirms.
*/
export interface EmailTemplateSelectionResult {
template: EmailTemplate;
createNote: boolean;
sendAsBCC: boolean;
sendSemicolonSeparated: boolean;
}
@UntilDestroy()
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-email-template-selection-dialog",
imports: [
MatDialogContent,
MatDialogActions,
MatButton,
EditEntityComponent,
MatDialogClose,
MatInputModule,
RouterLink,
DisableEntityOperationDirective,
MatCheckbox,
ReactiveFormsModule,
MatTooltipModule,
MatFormFieldModule,
HelpButtonComponent,
],
templateUrl: "./email-template-selection-dialog.component.html",
styleUrl: "./email-template-selection-dialog.component.scss",
})
export class EmailTemplateSelectionDialogComponent implements OnInit {
protected readonly emailTemplateRoute = getEntityRuntimeRoute(EmailTemplate);
emailTemplateSelectionForm: FormControl = new FormControl();
emailContentForm = new FormGroup({
subject: new FormControl<string>("", { validators: [Validators.required] }),
body: new FormControl<string>(""),
});
createNoteControl = new FormControl<boolean>(true);
sendAsBCC = new FormControl<boolean>(true);
sendSemicolonSeparated = new FormControl<boolean>(false);
EmailTemplate = EmailTemplate;
excludedEntitiesCount: number = 0;
isBulkEmail: boolean = false;
private selectedTemplate: EmailTemplate | null = null;
private readonly dialogRef = inject(
MatDialogRef<EmailTemplateSelectionDialogComponent>,
);
private readonly entityMapper = inject(EntityMapperService);
private readonly dialogData: EmailTemplateSelectionDialogData =
inject(MAT_DIALOG_DATA);
get entity(): Entity {
return this.dialogData.entity;
}
async ngOnInit() {
this.excludedEntitiesCount = this.dialogData.excludedEntitiesCount ?? 0;
this.isBulkEmail = this.dialogData.isBulk;
// Listen to template selection changes and prefill subject/body
this.emailTemplateSelectionForm.valueChanges
.pipe(
distinctUntilChanged(),
switchMap((templateId: string) => {
if (!templateId) {
return of(null);
}
return from(this.entityMapper.load(EmailTemplate, templateId));
}),
untilDestroyed(this),
)
.subscribe((template: EmailTemplate | null) => {
this.selectedTemplate = template;
if (template) {
this.emailContentForm.patchValue({
subject: template.subject,
body: template.body,
});
} else {
this.emailContentForm.patchValue({
subject: "",
body: "",
});
}
});
}
/**
* Filter email templates to show based on current entity type.
* Shows only templates explicitly matching the entity type if any exist,
* otherwise shows templates with no restrictions (null or empty availableForEntityTypes).
*/
filteredTemplate = (e: EmailTemplate): boolean => {
return (
!e.availableForEntityTypes ||
e.availableForEntityTypes.length === 0 ||
e.availableForEntityTypes.includes(this.entity.getType())
);
};
async confirmSelectedTemplate() {
const template = new EmailTemplate();
template.subject = this.emailContentForm.value.subject;
template.body = this.emailContentForm.value.body;
if (this.selectedTemplate) {
template.category = this.selectedTemplate.category;
}
this.dialogRef.close({
template,
createNote: !!this.createNoteControl.value,
sendAsBCC: this.isBulkEmail ? !!this.sendAsBCC.value : false,
sendSemicolonSeparated: !!this.sendSemicolonSeparated.value,
} as EmailTemplateSelectionResult);
}
}
<mat-dialog-content>
<h2 i18n>Prepare Email</h2>
@if (excludedEntitiesCount > 0) {
<p class="warning-message" i18n>
{{ excludedEntitiesCount }} records were excluded due to missing email
address.
</p>
}
<p>
<span i18n>
Note: "Sending" mail will open the email application on your device. If
nothing happens you may have to set up a default email client.
</span>
</p>
<mat-form-field class="full-width" floatLabel="always">
<mat-label i18n>Message Template</mat-label>
<app-edit-entity
[formControl]="emailTemplateSelectionForm"
[entityType]="EmailTemplate.ENTITY_TYPE"
[additionalFilter]="filteredTemplate"
[disableCreateNew]="true"
placeholder="Select a template to prefill email content"
i18n-placeholder
></app-edit-entity>
<mat-hint>
<span i18n>
Select the template to prefill email content to this record. If you want
to create a new template, you can do so from -
</span>
<a
[routerLink]="emailTemplateRoute"
*appDisabledEntityOperation="{
entity: EmailTemplate,
operation: 'update',
}"
matDialogClose
i18n
>configure available Email templates</a
></mat-hint
>
</mat-form-field>
<h3 i18n>Email Content</h3>
<mat-form-field class="full-width">
<mat-label i18n>Subject</mat-label>
<input
matInput
[formControl]="emailContentForm.controls.subject"
placeholder="Enter email subject"
i18n-placeholder
/>
</mat-form-field>
<mat-form-field class="full-width">
<mat-label i18n>Body</mat-label>
<textarea
matInput
[formControl]="emailContentForm.controls.body"
placeholder="Enter email body"
i18n-placeholder
rows="5"
></textarea>
</mat-form-field>
<div class="flex-column">
<mat-checkbox [formControl]="createNoteControl" i18n>
Create a note to document message
</mat-checkbox>
@if (isBulkEmail) {
<mat-checkbox [formControl]="sendAsBCC">
<span i18n>Send as BCC</span>
<app-help-button
text="If you send an email to multiple people they can see each others email IDs. Unless they know each other you should avoid this. Therefore, you can instead send the email to yourself and add all recipients as 'blind copy' (BCC)."
i18n-text
></app-help-button>
</mat-checkbox>
<mat-checkbox [formControl]="sendSemicolonSeparated">
<span i18n>Microsoft Outlook compatibility</span>
<app-help-button
text="Check this if email ids are not separated correctly. If you use Microsoft Outlook, you may need to separate email addresses with semicolons instead of commas for compatibility."
i18n-text
></app-help-button>
</mat-checkbox>
}
</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-raised-button color="accent" (click)="confirmSelectedTemplate()">
<span i18n>Send Email</span>
</button>
<button mat-stroked-button i18n [matDialogClose]="false">Cancel</button>
</mat-dialog-actions>