src/app/features/coming-soon/coming-soon/coming-soon.component.ts
Placeholder page to announce that a feature is not available yet.
This integrates with analytics and allows user to explicitly request the feature.
| changeDetection | ChangeDetectionStrategy.OnPush |
| selector | app-coming-soon |
| standalone | true |
| imports |
MatDialogModule
MatButtonModule
FontAwesomeModule
|
| styleUrls | ./coming-soon.component.scss |
| templateUrl | ./coming-soon.component.html |
No results matching.
DialogCloseComponent
MatDialogModule
MatButtonModule
FontAwesomeModule
Properties |
|
Methods |
Inputs |
constructor()
|
| featureId | |
Type : string
|
|
|
the identifier for the specific feature this page serves as a placeholder for |
|
| reportFeatureRequest |
reportFeatureRequest()
|
|
Report an explicit user request for the feature through the analytics plugin.
Returns :
void
|
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;
}