src/app/features/coming-soon/coming-soon/coming-soon.component.ts

Description

Placeholder page to announce that a feature is not available yet.

This integrates with analytics and allows user to explicitly request the feature.

Example

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods
Inputs

Constructor

constructor()

Inputs

featureId
Type : string

the identifier for the specific feature this page serves as a placeholder for

Methods

reportFeatureRequest
reportFeatureRequest()

Report an explicit user request for the feature through the analytics plugin.

Returns : void

Properties

Static featuresRequested
Type : []
Default value : []

An array of featureIds that the user has already requested during the current session.

Users cannot request the same feature twice and see that they have already requested the feature. This information is not persisted across sessions however. So after reloading the page this history is gone.

requested
Type : unknown
Default value : linkedSignal<boolean>( () => !!this.currentFeatureId() && ComingSoonComponent.featuresRequested.includes(this.currentFeatureId()), )

whether user has already requested the feature

import {
  Component,
  effect,
  input,
  linkedSignal,
  inject,
  ChangeDetectionStrategy,
} from "@angular/core";
import { AlertService } from "../../../core/alerts/alert.service";
import { ActivatedRoute } from "@angular/router";
import { AnalyticsService } from "../../../core/analytics/analytics.service";
import { MAT_DIALOG_DATA, MatDialogModule } from "@angular/material/dialog";
import { DialogCloseComponent } from "../../../core/common-components/dialog-close/dialog-close.component";
import { MatButtonModule } from "@angular/material/button";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";

import { RouteTarget } from "../../../route-target";

/**
 * Placeholder page to announce that a feature is not available yet.
 *
 * This integrates with analytics and allows user to explicitly request the feature.
 */
@RouteTarget("ComingSoon")
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-coming-soon",
  templateUrl: "./coming-soon.component.html",
  styleUrls: ["./coming-soon.component.scss"],
  imports: [
    DialogCloseComponent,
    MatDialogModule,
    MatButtonModule,
    FontAwesomeModule,
  ],
})
export class ComingSoonComponent {
  private alertService = inject(AlertService);
  private analyticsService = inject(AnalyticsService);
  private activatedRoute = inject(ActivatedRoute);

  /**
   * An array of featureIds that the user has already requested during the current session.
   *
   * Users cannot request the same feature twice and see that they have already requested the feature.
   * This information is not persisted across sessions however. So after reloading the page this history is gone.
   */
  static featuresRequested = [];

  /**
   * the identifier for the specific feature this page serves as a placeholder for
   */
  featureId = input<string>();
  private readonly currentFeatureId = linkedSignal<string | undefined>(() =>
    this.featureId(),
  );

  /**
   * whether user has already requested the feature
   */
  requested = linkedSignal<boolean>(
    () =>
      !!this.currentFeatureId() &&
      ComingSoonComponent.featuresRequested.includes(this.currentFeatureId()),
  );

  constructor() {
    const dialogData = inject<{
      featureId: string;
    }>(MAT_DIALOG_DATA, { optional: true });

    if (dialogData?.featureId) {
      this.init(dialogData.featureId);
    }
    this.activatedRoute.paramMap.subscribe((params) => {
      if (params.has("feature")) {
        this.init(params.get("feature") ?? undefined);
      }
    });

    effect(() => {
      if (this.featureId()) {
        this.track("visit");
      }
    });
  }

  private init(newFeatureId: string | undefined) {
    if (!newFeatureId) {
      return;
    }
    this.currentFeatureId.set(newFeatureId);

    this.track("visit");
  }

  private track(action: string) {
    const featureId = this.currentFeatureId();
    if (!featureId) {
      return;
    }
    this.analyticsService.eventTrack(featureId, {
      category: "feature_request",
      label: action,
    });
  }

  /**
   * Report an explicit user request for the feature through the analytics plugin.
   */
  reportFeatureRequest() {
    const featureId = this.currentFeatureId();
    if (!featureId) {
      return;
    }
    this.track("request");

    this.requested.set(true);
    ComingSoonComponent.featuresRequested.push(featureId);
    this.alertService.addInfo(
      $localize`:Sent after the user has sent a feature-request:Thank you for letting us know.`,
    );
  }
}
<app-dialog-close mat-dialog-close></app-dialog-close>
<mat-dialog-content>
  <h1 i18n="Coming Soon header">Coming Soon</h1>
  <h3 i18n="Coming Soon description">
    Sorry, this feature isn't quite ready yet. We are working hard to make this
    available for you. Let us know below if you need this functionality.
  </h3>

  <div class="feedback-section margin-bottom-regular">
    <button
      mat-raised-button
      color="primary"
      class="full-width"
      (click)="reportFeatureRequest()"
      [disabled]="requested()"
    >
      @if (requested()) {
        <fa-icon i18n-aria-label aria-label="requested" icon="check"></fa-icon>
      }
      <span
        i18n="
          Feature Button|Indicates that the user needs this feature and can send
          a feature-request
        "
        >I need this feature</span
      >
    </button>

    <a
      i18n
      mat-stroked-button
      class="full-width"
      target="_blank"
      rel="noopener"
      [href]="
        'mailto:info@aam-digital.com?subject=Feature-Request%20' + featureId()
      "
    >
      I can tell you about my use case
    </a>
  </div>

  <img src="../../../../assets/canvas-stand.png" alt="" class="illustration" />
</mat-dialog-content>

./coming-soon.component.scss

@use "variables/sizes";
@use "mixins/grid-layout";

.illustration {
  width: 70%;
}

.feedback-section {
  width: 70%;
  @include grid-layout.adaptive(
    $min-block-width: 250px,
    $max-screen-width: 414px
  );
}

mat-dialog-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: sizes.$max-text-width;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""