src/app/features/email-client/email-template-selection-dialog/email-template-selection-dialog.component.ts

Implements

OnInit

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods
Accessors

Methods

Async confirmSelectedTemplate
confirmSelectedTemplate()
Returns : any

Properties

createNoteControl
Type : unknown
Default value : new FormControl<boolean>(true)
emailContentForm
Type : unknown
Default value : new FormGroup({ subject: new FormControl<string>("", { validators: [Validators.required] }), body: new FormControl<string>(""), })
EmailTemplate
Type : unknown
Default value : EmailTemplate
Protected Readonly emailTemplateRoute
Type : unknown
Default value : getEntityRuntimeRoute(EmailTemplate)
emailTemplateSelectionForm
Type : FormControl
Default value : new FormControl()
excludedEntitiesCount
Type : number
Default value : 0
filteredTemplate
Type : unknown
Default value : () => {...}

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).

isBulkEmail
Type : boolean
Default value : false
sendAsBCC
Type : unknown
Default value : new FormControl<boolean>(true)
sendSemicolonSeparated
Type : unknown
Default value : new FormControl<boolean>(false)

Accessors

entity
getentity()
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>
        &nbsp;
        <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>
        &nbsp;
        <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>

./email-template-selection-dialog.component.scss

.warning-message {
  color: red;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""