Files
Portfolio/src/app/features/services/service-page-view/service-page-view.ts
Antonio Ledebuhr 1de146c650 integration: name case metrics, split delivered offerings from offers, and frame the stack honestly
Give every metrics list a localized heading, keep delivered Rösterei tools out of the offer boundary, and describe the skills grid as a familiarity overview with an evidence note instead of claiming public-case backing for every item.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 19:32:18 +02:00

67 lines
2.6 KiB
TypeScript

import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';
import {
type OfferingCopy,
type ProcessStepCopy,
type ServicePageId,
type ServiceSequenceCopy,
} from '../../../core/content/content.contracts';
import { ContentService } from '../../../core/content/content.service';
import { CaseCard } from '../../../shared/case-card/case-card';
import { ContentSection } from '../../../shared/content-section/content-section';
import { CtaRow } from '../../../shared/cta-row/cta-row';
import { PageHero } from '../../../shared/page-hero/page-hero';
import { ProcessSteps } from '../../../shared/process-steps/process-steps';
function sequenceSteps(sequence: ServiceSequenceCopy): readonly ProcessStepCopy[] {
return [sequence.situation, sequence.diagnosis, sequence.implementation, sequence.operation].map(
(section) => ({
id: section.id,
title: section.headline,
body: (section.body ?? []).join(' '),
}),
);
}
@Component({
selector: 'app-service-page-view',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [PageHero, ContentSection, ProcessSteps, CaseCard, CtaRow],
templateUrl: './service-page-view.html',
styleUrl: './service-page-view.scss',
})
export class ServicePageView {
readonly routeId = input.required<ServicePageId>();
private readonly content = inject(ContentService);
protected readonly page = computed(() => this.content.service(this.routeId())());
protected readonly steps = computed(() => sequenceSteps(this.page().sequence));
protected readonly referenceCase = computed(() =>
this.content.caseStudy(this.page().sequence.referenceCaseId)(),
);
protected readonly sequenceHeadingId = computed(() => {
const section = this.page().sections.find((item) => item.id === 'sequence');
return section ? `section-${section.id}` : null;
});
protected readonly deliveredOfferings = computed(() =>
this.page().offerings.filter((offering) => offering.status === 'delivered'),
);
protected readonly offerOfferings = computed(() =>
this.page().offerings.filter((offering) => offering.status === 'offer'),
);
protected readonly deliveredHeadingId = computed(() => `offerings-delivered-${this.routeId()}`);
protected readonly offerHeadingId = computed(() => `offerings-offer-${this.routeId()}`);
protected caseBackedNote(offering: OfferingCopy): string | null {
const caseId = offering.referenceCaseId;
if (!caseId) {
return null;
}
return this.page().offeringCaseBackedLabel.replace(
'{case}',
this.content.caseStudy(caseId)().client,
);
}
}