fix(crm-customer-card): Refresh after Lock, Unlock or Add Cards correctly, Adjusted Placeholder Text, Show Transactions based on first Card instead of first active card

Ref: #5503
This commit is contained in:
Nino
2025-11-21 17:10:12 +01:00
parent df1fe540d0
commit 4c306a213d
11 changed files with 81 additions and 48 deletions

View File

@@ -10,7 +10,7 @@
[ngModel]="store.bonNumber()"
(ngModelChange)="onBonNumberChange($event)"
required
placeholder="Bon Nummer / Rechnungs-Nummer (HUG.de)*"
placeholder="Bon Nummer"
data-what="bon-number-input"
data-which="customer-loyalty"
aria-label="Bon Nummer eingeben"

View File

@@ -2,8 +2,7 @@ import {
ChangeDetectionStrategy,
Component,
inject,
input,
OnDestroy,
output,
} from '@angular/core';
import { Validators } from '@angular/forms';
import { logger } from '@isa/core/logging';
@@ -22,8 +21,7 @@ import { firstValueFrom } from 'rxjs';
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TextButtonComponent],
})
export class AddCustomerCardComponent implements OnDestroy {
#reloadTimeoutId?: ReturnType<typeof setTimeout>;
export class AddCustomerCardComponent {
#logger = logger(() => ({
component: 'AddCustomerCardComponent',
}));
@@ -34,6 +32,12 @@ export class AddCustomerCardComponent implements OnDestroy {
#textDialog = injectTextInputDialog();
#feedbackDialog = injectFeedbackDialog();
/**
* Event emitted when a card has been successfully added.
* Parent should reload cards and transactions.
*/
readonly cardAdded = output<void>();
async addCardDialog() {
this.#logger.debug('Opening add card dialog');
const dialogRef = this.#textDialog({
@@ -52,7 +56,6 @@ export class AddCustomerCardComponent implements OnDestroy {
],
onConfirm: async (cardCode: string) => {
await this.addCard(cardCode);
this.reloadCards();
},
},
width: '30rem',
@@ -62,6 +65,7 @@ export class AddCustomerCardComponent implements OnDestroy {
if (dialogResult?.inputValue) {
this.feedback();
this.cardAdded.emit();
}
}
@@ -90,16 +94,4 @@ export class AddCustomerCardComponent implements OnDestroy {
});
this.#logger.info('Adding customer card complete', () => ({ cardCode }));
}
reloadCards() {
this.#reloadTimeoutId = setTimeout(() => {
this.#bonusCardsResource.resource.reload();
}, 500);
}
ngOnDestroy(): void {
if (this.#reloadTimeoutId) {
clearTimeout(this.#reloadTimeoutId);
}
}
}

View File

@@ -48,6 +48,7 @@
<crm-lock-customer-card
[isActive]="card().isActive"
[cardCode]="card().code"
(cardLocked)="cardLocked.emit()"
></crm-lock-customer-card>
</div>
</div>

View File

@@ -1,4 +1,9 @@
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
input,
output,
} from '@angular/core';
import { BonusCardInfo } from '@isa/crm/data-access';
import { BarcodeComponent } from '@isa/shared/barcode';
import { LockCustomerCardComponent } from '../lock-customer-card/lock-customer-card.component';
@@ -35,6 +40,12 @@ export class CustomerCardComponent {
*/
readonly card = input.required<BonusCardInfo>();
/**
* Event emitted when a card has been successfully locked or unlocked.
* Parent should reload cards and transactions.
*/
readonly cardLocked = output<void>();
/**
* Barcode dimensions in rem, converted to pixels for JsBarcode.
* Base: 1rem = 16px

View File

@@ -6,7 +6,7 @@
[padding]="'0.75rem 0.5rem'"
>
@for (card of sortedCards(); track card.code) {
<crm-customer-card [card]="card" />
<crm-customer-card [card]="card" (cardLocked)="cardLocked.emit()" />
}
</ui-carousel>
</div>

View File

@@ -33,6 +33,12 @@ export class CustomerCardsCarouselComponent {
*/
readonly cards = input.required<BonusCardInfo[]>();
/**
* Event emitted when a card has been successfully locked or unlocked.
* Parent should reload cards and transactions.
*/
readonly cardLocked = output<void>();
/**
* Cards sorted with blocked cards at the end.
* Per Figma annotation: "gesperrte Karte immer nach hinten"

View File

@@ -3,7 +3,7 @@ import {
Component,
inject,
input,
OnDestroy,
output,
signal,
} from '@angular/core';
import { logger } from '@isa/core/logging';
@@ -24,8 +24,7 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TextButtonComponent],
})
export class LockCustomerCardComponent implements OnDestroy {
#reloadTimeoutId?: ReturnType<typeof setTimeout>;
export class LockCustomerCardComponent {
#logger = logger(() => ({
component: 'LockCustomerCardComponent',
}));
@@ -41,6 +40,12 @@ export class LockCustomerCardComponent implements OnDestroy {
readonly #customerId = this.#bonusCardsResource.customerId;
/**
* Event emitted when a card has been successfully locked or unlocked.
* Parent should reload cards and transactions.
*/
readonly cardLocked = output<void>();
loading = signal(false);
async lockCard() {
@@ -55,7 +60,7 @@ export class LockCustomerCardComponent implements OnDestroy {
message: 'Karte gesperrt',
},
});
this.reloadCards();
this.cardLocked.emit();
} catch (error: unknown) {
this.#logger.error('Error locking card', error as Error, () => ({
cardCode,
@@ -90,7 +95,7 @@ export class LockCustomerCardComponent implements OnDestroy {
message: 'Karte entsperrt',
},
});
this.reloadCards();
this.cardLocked.emit();
} catch (error: unknown) {
this.#logger.error('Error unlocking card', error as Error, () => ({
cardCode,
@@ -104,16 +109,4 @@ export class LockCustomerCardComponent implements OnDestroy {
this.loading.set(false);
}
}
reloadCards() {
this.#reloadTimeoutId = setTimeout(() => {
this.#bonusCardsResource.resource.reload();
}, 500);
}
ngOnDestroy(): void {
if (this.#reloadTimeoutId) {
clearTimeout(this.#reloadTimeoutId);
}
}
}

View File

@@ -28,8 +28,12 @@
/>
<!-- Cards carousel -->
<crm-customer-cards-carousel [cards]="cardList" class="w-full" />
<crm-customer-cards-carousel
[cards]="cardList"
class="w-full"
(cardLocked)="onCardUpdated()"
/>
<crm-add-customer-card />
<crm-add-customer-card (cardAdded)="onCardUpdated()" />
}
</div>

View File

@@ -62,6 +62,12 @@ export class CustomerLoyaltyCardsComponent {
*/
readonly navigateToPraemienshop = output<void>();
/**
* Event emitted when a card has been added, locked, or unlocked.
* Parent should reload cards and transactions.
*/
readonly cardUpdated = output<void>();
/**
* All bonus cards for the selected customer.
*/
@@ -96,4 +102,13 @@ export class CustomerLoyaltyCardsComponent {
this.#logger.info('Emit navigate to Prämienshop event');
this.navigateToPraemienshop.emit();
}
/**
* Handle card update events from child components.
* Forwards the event to parent for reload coordination.
*/
onCardUpdated(): void {
this.#logger.debug('Card updated, forwarding event to parent');
this.cardUpdated.emit();
}
}