Browse Source

feat(client): implement computed signal for product2

pull/7099/head
KenTandrian 3 weeks ago
parent
commit
017d42965b
  1. 39
      apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts
  2. 70
      apps/client/src/app/pages/resources/personal-finance-tools/product-page.html

39
apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts

@ -47,42 +47,45 @@ export class GfProductPageComponent implements OnInit {
useAnonymously: true
}));
protected product2: Product;
protected readonly routerLinkAbout = publicRoutes.about.routerLink;
protected readonly routerLinkFeatures = publicRoutes.features.routerLink;
protected readonly routerLinkResourcesPersonalFinanceTools =
publicRoutes.resources.subRoutes.personalFinanceTools.routerLink;
protected tags: string[];
private readonly dataService = inject(DataService);
private readonly route = inject(ActivatedRoute);
public ngOnInit() {
protected readonly product2 = computed<Product>(() => {
const product = personalFinanceTools.find(({ key }) => {
return key === this.route.snapshot.data['key'];
});
this.product2 = {
const mappedProduct = {
key: product?.key ?? '',
name: product?.name ?? '',
...product
};
if (this.product2.origin) {
this.product2.origin = getCountryName({ code: this.product2.origin });
if (mappedProduct.origin) {
mappedProduct.origin = getCountryName({ code: mappedProduct.origin });
}
if (this.product2.regions) {
this.product2.regions = this.product2.regions.map((region) => {
if (mappedProduct.regions) {
mappedProduct.regions = mappedProduct.regions.map((region) => {
return translate(region);
});
}
return mappedProduct;
});
protected readonly routerLinkAbout = publicRoutes.about.routerLink;
protected readonly routerLinkFeatures = publicRoutes.features.routerLink;
protected readonly routerLinkResourcesPersonalFinanceTools =
publicRoutes.resources.subRoutes.personalFinanceTools.routerLink;
protected tags: string[];
private readonly dataService = inject(DataService);
private readonly route = inject(ActivatedRoute);
public ngOnInit() {
this.tags = [
this.product1().name,
this.product1().origin,
this.product2.name,
this.product2.origin,
this.product2().name,
this.product2().origin,
$localize`Alternative`,
$localize`App`,
$localize`Budgeting`,

70
apps/client/src/app/pages/resources/personal-finance-tools/product-page.html

@ -6,10 +6,10 @@
<h1 class="mb-1">
<strong>Ghostfolio</strong>:
<ng-container i18n>The Open Source Alternative to</ng-container
>&nbsp;<strong>{{ product2.name }}</strong>
>&nbsp;<strong>{{ product2().name }}</strong>
</h1>
</div>
@if (product2.isArchived) {
@if (product2().isArchived) {
<div class="info-container my-4 p-2 rounded text-center text-muted">
<ng-container i18n>This page has been archived.</ng-container>
</div>
@ -17,7 +17,7 @@
<section class="mb-4">
<p i18n>
Are you looking for an open source alternative to
{{ product2.name }}?
{{ product2().name }}?
<a [routerLink]="routerLinkAbout">Ghostfolio</a> is a powerful
portfolio management tool that provides individuals with a
comprehensive platform to track, analyze, and optimize their
@ -31,7 +31,7 @@
</p>
<p i18n>
Ghostfolio is an open source software (OSS), providing a
cost-effective alternative to {{ product2.name }} making it
cost-effective alternative to {{ product2().name }} making it
particularly suitable for individuals on a tight budget, such as
those
<a href="../en/blog/2023/07/exploring-the-path-to-fire"
@ -42,9 +42,9 @@
</p>
<p i18n>
Let’s dive deeper into the detailed Ghostfolio vs
{{ product2.name }} comparison table below to gain a thorough
{{ product2().name }} comparison table below to gain a thorough
understanding of how Ghostfolio positions itself relative to
{{ product2.name }}. We will explore various aspects such as
{{ product2().name }}. We will explore various aspects such as
features, data privacy, pricing, and more, allowing you to make a
well-informed choice for your personal requirements.
</p>
@ -54,7 +54,7 @@
<caption class="text-center" i18n>
Ghostfolio vs
{{
product2.name
product2().name
}}
comparison table
</caption>
@ -63,7 +63,7 @@
<th class="mat-mdc-header-cell px-1 py-2"></th>
<th class="mat-mdc-header-cell px-1 py-2">Ghostfolio</th>
<th class="mat-mdc-header-cell px-1 py-2">
{{ product2.name }}
{{ product2().name }}
</th>
</tr>
</thead>
@ -71,17 +71,17 @@
<tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right"></td>
<td class="mat-mdc-cell px-1 py-2">{{ product1().slogan }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2.slogan }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2().slogan }}</td>
</tr>
<tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right" i18n>Founded</td>
<td class="mat-mdc-cell px-1 py-2">{{ product1().founded }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2.founded }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2().founded }}</td>
</tr>
<tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right" i18n>Origin</td>
<td class="mat-mdc-cell px-1 py-2">{{ product1().origin }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2.origin }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2().origin }}</td>
</tr>
<tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right" i18n>Region</td>
@ -96,7 +96,7 @@
</td>
<td class="mat-mdc-cell px-1 py-2">
@for (
region of product2.regions;
region of product2().regions;
track region;
let isLast = $last
) {
@ -119,7 +119,7 @@
</td>
<td class="mat-mdc-cell px-1 py-2">
@for (
language of product2.languages;
language of product2().languages;
track language;
let isLast = $last
) {
@ -149,18 +149,18 @@
}
</td>
<td class="mat-mdc-cell px-1 py-2">
@if (product2.isOpenSource) {
@if (product2().isOpenSource) {
<span
i18n
i18n-title
title="{{ product2.name }} is Open Source Software"
title="{{ product2().name }} is Open Source Software"
>✅ Yes</span
>
} @else {
<span
i18n
i18n-title
title="{{ product2.name }} is not Open Source Software"
title="{{ product2().name }} is not Open Source Software"
>❌ No</span
>
}
@ -188,18 +188,18 @@
}
</td>
<td class="mat-mdc-cell px-1 py-2">
@if (product2.hasSelfHostingAbility === true) {
@if (product2().hasSelfHostingAbility === true) {
<span
i18n
i18n-title
title="{{ product2.name }} can be self-hosted"
title="{{ product2().name }} can be self-hosted"
>✅ Yes</span
>
} @else if (product2.hasSelfHostingAbility === false) {
} @else if (product2().hasSelfHostingAbility === false) {
<span
i18n
i18n-title
title="{{ product2.name }} cannot be self-hosted"
title="{{ product2().name }} cannot be self-hosted"
>❌ No</span
>
}
@ -227,18 +227,18 @@
}
</td>
<td class="mat-mdc-cell px-1 py-2">
@if (product2.useAnonymously === true) {
@if (product2().useAnonymously === true) {
<span
i18n
i18n-title
title="{{ product2.name }} can be used anonymously"
title="{{ product2().name }} can be used anonymously"
>✅ Yes</span
>
} @else if (product2.useAnonymously === false) {
} @else if (product2().useAnonymously === false) {
<span
i18n
i18n-title
title="{{ product2.name }} cannot be used anonymously"
title="{{ product2().name }} cannot be used anonymously"
>❌ No</span
>
}
@ -266,18 +266,18 @@
}
</td>
<td class="mat-mdc-cell px-1 py-2">
@if (product2.hasFreePlan === true) {
@if (product2().hasFreePlan === true) {
<span
i18n
i18n-title
title="{{ product2.name }} offers a free plan"
title="{{ product2().name }} offers a free plan"
>✅ Yes</span
>
} @else if (product2.hasFreePlan === false) {
} @else if (product2().hasFreePlan === false) {
<span
i18n
i18n-title
title="{{ product2.name }} does not offer a free plan"
title="{{ product2().name }} does not offer a free plan"
>❌ No</span
>
}
@ -290,18 +290,18 @@
<span i18n>year</span>
</td>
<td class="mat-mdc-cell px-1 py-2">
@if (product2.pricingPerYear) {
@if (product2().pricingPerYear) {
<span i18n>Starting from</span>
{{ product2.pricingPerYear }} /
{{ product2().pricingPerYear }} /
<span i18n>year</span>
}
</td>
</tr>
@if (product1().note || product2.note) {
@if (product1().note || product2().note) {
<tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right" i18n>Notes</td>
<td class="mat-mdc-cell px-1 py-2">{{ product1().note }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2.note }}</td>
<td class="mat-mdc-cell px-1 py-2">{{ product2().note }}</td>
</tr>
}
</tbody>
@ -310,9 +310,9 @@
<section class="mb-4">
<p i18n>
Please note that the information provided in the Ghostfolio vs
{{ product2.name }} comparison table is based on our independent
{{ product2().name }} comparison table is based on our independent
research and analysis. This website is not affiliated with
{{ product2.name }} or any other product mentioned in the
{{ product2().name }} or any other product mentioned in the
comparison. As the landscape of personal finance tools evolves, it
is essential to verify any specific details or changes directly from
the respective product page. Data needs a refresh? Help us maintain
@ -355,7 +355,7 @@
aria-current="page"
class="active breadcrumb-item text-truncate"
>
Ghostfolio vs {{ product2.name }}
Ghostfolio vs {{ product2().name }}
</li>
</ol>
</nav>

Loading…
Cancel
Save