Merge branch 'release/4.5' into develop

This commit is contained in:
Nino
2025-12-03 16:00:41 +01:00
4 changed files with 19 additions and 14 deletions

3
.gitignore vendored
View File

@@ -80,3 +80,6 @@ CLAUDE.md
*.pyc
.vite
reports/
# Local iPad dev setup (proxy)
/local-dev/

View File

@@ -51,7 +51,7 @@ describe('CustomerCardPointsSummaryComponent', () => {
});
describe('formattedPoints computed signal', () => {
it('should display points from primary card', () => {
it('should display points from first card', () => {
fixture.componentRef.setInput('cards', mockCards);
fixture.detectChanges();
@@ -77,7 +77,7 @@ describe('CustomerCardPointsSummaryComponent', () => {
expect(component.formattedPoints()).toBe('123.456');
});
it('should display 0 when no primary card exists', () => {
it('should display points from first card regardless of isPrimary flag', () => {
const cardsWithoutPrimary: BonusCardInfo[] = [
{
code: 'CARD-1',
@@ -93,7 +93,7 @@ describe('CustomerCardPointsSummaryComponent', () => {
fixture.componentRef.setInput('cards', cardsWithoutPrimary);
fixture.detectChanges();
expect(component.formattedPoints()).toBe('0');
expect(component.formattedPoints()).toBe('1.500');
});
it('should display 0 when cards array is empty', () => {
@@ -122,14 +122,14 @@ describe('CustomerCardPointsSummaryComponent', () => {
expect(component.formattedPoints()).toBe('0');
});
it('should only use primary card points, not sum of all cards', () => {
it('should only use first card points, not sum of all cards', () => {
const multipleCards: BonusCardInfo[] = [
{
code: 'CARD-1',
firstName: 'John',
lastName: 'Doe',
isActive: true,
isPrimary: true,
isPrimary: false,
totalPoints: 1000,
cardNumber: '1234-5678-9012-3456',
} as BonusCardInfo,
@@ -138,7 +138,7 @@ describe('CustomerCardPointsSummaryComponent', () => {
firstName: 'John',
lastName: 'Doe',
isActive: true,
isPrimary: false,
isPrimary: true,
totalPoints: 500,
cardNumber: '9876-5432-1098-7654',
} as BonusCardInfo,
@@ -147,7 +147,7 @@ describe('CustomerCardPointsSummaryComponent', () => {
fixture.componentRef.setInput('cards', multipleCards);
fixture.detectChanges();
// Should be 1000, not 1500
// Should be 1000 (first card), not 500 (primary) or 1500 (sum)
expect(component.formattedPoints()).toBe('1.000');
});
});

View File

@@ -36,12 +36,11 @@ export class CustomerCardPointsSummaryComponent {
readonly navigateToPraemienshop = output<void>();
/**
* Total points from primary card, formatted with thousands separator.
* Total points from first card, formatted with thousands separator.
*/
readonly formattedPoints = computed(() => {
const cards = this.cards();
const primaryCard = cards.find((c) => c.isPrimary);
const points = primaryCard?.totalPoints ?? 0;
const points = cards?.[0]?.totalPoints ?? 0;
// Format with German thousands separator (dot)
return points.toLocaleString('de-DE');

View File

@@ -84,8 +84,11 @@ export class CloseOnScrollDirective implements OnDestroy {
}
this.#isActive = true;
// Delay listener registration to next frame to skip any stale scroll events
this.#pendingActivation = requestAnimationFrame(() => {
// Delay listener registration to skip scroll events caused by:
// 1. Stale scroll events from before activation
// 2. iOS Safari's automatic "scroll into view" when focusing elements
// Using setTimeout with 100ms to ensure iOS scroll-into-view completes
this.#pendingActivation = window.setTimeout(() => {
this.#scrollListener = (event: Event) => {
const excludeElement = this.closeOnScrollExclude();
if (excludeElement?.contains(event.target as HTMLElement)) {
@@ -101,12 +104,12 @@ export class CloseOnScrollDirective implements OnDestroy {
{ capture: true, passive: true },
);
this.#logger.debug('Activated scroll listener');
});
}, 100);
}
#deactivate(): void {
if (this.#pendingActivation) {
cancelAnimationFrame(this.#pendingActivation);
clearTimeout(this.#pendingActivation);
this.#pendingActivation = undefined;
}