mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1973: feat(customer-search): use navigation state for reward customer selection
feat(customer-search): use navigation state for reward customer selection Replace tab metadata context flag with NavigationStateService for tracking reward flow customer selection. Store return URL in preserved navigation context instead of tab metadata 'context' field. Benefits: - Clean separation: tab metadata no longer polluted with flow state - Automatic cleanup when tabs close (no manual cleanup needed) - Survives intermediate navigations (e.g., address edit) - Tab-scoped automatically via TabService integration Changes: - Remove `isRewardTab()` linkedSignal and tab metadata 'context' check - Add NavigationStateService with 'select-customer' scope - Store returnUrl in preserved context before navigation - Restore context and navigate back on customer selection - Update reward-start-card to preserve context on button click - Remove reward-catalog context initialization (no longer needed) Technical Details: - Context stored in tab.metadata['navigation-contexts']['select-customer'] - Uses async methods: preserveContext(), restoreAndClearContext() - Signal-based hasReturnUrl() for template reactivity - Maintains existing button flow (checks hasReturnUrl signal) Ref: #5368
This commit is contained in:
committed by
Lorenz Hilpert
parent
b96d889da5
commit
f549c59bc8
@@ -184,7 +184,7 @@
|
||||
>Auswählen</shared-loader
|
||||
>
|
||||
</button>
|
||||
} @else if (!isRewardTab()) {
|
||||
} @else {
|
||||
@if (shoppingCartHasNoItems$ | async) {
|
||||
<button
|
||||
type="button"
|
||||
@@ -210,15 +210,4 @@
|
||||
>
|
||||
</button>
|
||||
}
|
||||
} @else {
|
||||
<button
|
||||
type="button"
|
||||
(click)="continueReward()"
|
||||
class="w-60 text-white text-lg bg-brand rounded-full px-5 py-3 absolute top-[calc(100vh-19.375rem)] left-1/2 -translate-x-1/2 font-bold disabled:bg-inactive-branch"
|
||||
[disabled]="!(hasKundenkarte$ | async)"
|
||||
>
|
||||
<shared-loader [loading]="showLoader$ | async" spinnerSize="32"
|
||||
>Auswählen</shared-loader
|
||||
>
|
||||
</button>
|
||||
}
|
||||
|
||||
@@ -80,10 +80,9 @@ export class CustomerDetailsViewMainComponent
|
||||
customerService = inject(CrmCustomerService);
|
||||
crmTabMetadataService = inject(CrmTabMetadataService);
|
||||
private _rewardSelectionPopUpService = inject(RewardSelectionPopUpService);
|
||||
tab = injectTab();
|
||||
|
||||
// Signal to track if return URL exists
|
||||
hasReturnUrlSignal = signal(false);
|
||||
// Signal to track if return URL exists (used directly in template)
|
||||
readonly hasReturnUrl = signal(false);
|
||||
|
||||
fetching$ = combineLatest([
|
||||
this._store.fetchingCustomer$,
|
||||
@@ -104,11 +103,7 @@ export class CustomerDetailsViewMainComponent
|
||||
async checkHasReturnUrl(): Promise<void> {
|
||||
const hasContext =
|
||||
await this._navigationState.hasPreservedContext('select-customer');
|
||||
this.hasReturnUrlSignal.set(hasContext);
|
||||
}
|
||||
|
||||
hasReturnUrl(): boolean {
|
||||
return this.hasReturnUrlSignal();
|
||||
this.hasReturnUrl.set(hasContext);
|
||||
}
|
||||
|
||||
isBusy$ = this.select((s) => s.isBusy);
|
||||
@@ -318,11 +313,6 @@ export class CustomerDetailsViewMainComponent
|
||||
this.patchState({ payer });
|
||||
}
|
||||
|
||||
isRewardTab = linkedSignal(() => {
|
||||
const tab = this.tab();
|
||||
return tab?.metadata?.['context'] === 'reward';
|
||||
});
|
||||
|
||||
ngOnInit() {
|
||||
// Check if we have a return URL context
|
||||
this.checkHasReturnUrl();
|
||||
@@ -367,7 +357,7 @@ export class CustomerDetailsViewMainComponent
|
||||
@logAsync
|
||||
// #5262 Für die Auswahl des Kunden im "Prämienshop-Modus" (Getrennt vom regulären Checkout-Prozess)
|
||||
async continueReward() {
|
||||
if (this.isRewardTab()) {
|
||||
if (this.hasReturnUrl()) {
|
||||
this._setSelectedCustomerIdInTab();
|
||||
|
||||
// Restore from preserved context (auto-scoped to current tab) and clean up
|
||||
|
||||
@@ -17,7 +17,6 @@ import { RewardHeaderComponent } from './reward-header/reward-header.component';
|
||||
import { RewardListComponent } from './reward-list/reward-list.component';
|
||||
import { injectRestoreScrollPosition } from '@isa/utils/scroll-position';
|
||||
import { RewardActionComponent } from './reward-action/reward-action.component';
|
||||
import { TabService } from '@isa/core/tabs';
|
||||
import { SelectedRewardShoppingCartResource } from '@isa/checkout/data-access';
|
||||
import { SelectedCustomerBonusCardsResource } from '@isa/crm/data-access';
|
||||
|
||||
@@ -54,28 +53,14 @@ function querySettingsFactory() {
|
||||
},
|
||||
})
|
||||
export class RewardCatalogComponent {
|
||||
#tabService = inject(TabService);
|
||||
|
||||
restoreScrollPosition = injectRestoreScrollPosition();
|
||||
|
||||
searchTrigger = signal<SearchTrigger | 'reload' | 'initial'>('initial');
|
||||
|
||||
#filterService = inject(FilterService);
|
||||
|
||||
constructor() {
|
||||
this.initRewardContext();
|
||||
}
|
||||
|
||||
search(trigger: SearchTrigger): void {
|
||||
this.searchTrigger.set(trigger); // Ist entweder 'scan', 'input', 'filter' oder 'orderBy'
|
||||
this.#filterService.commit();
|
||||
}
|
||||
|
||||
// Wichtig damit Kundensuche weiß, dass wir im Reward Kontext sind - Über Header CTA oder Kaufoptionen gelangt man zur Kundensuche
|
||||
initRewardContext() {
|
||||
const tabId = this.#tabService.activatedTabId();
|
||||
if (tabId) {
|
||||
this.#tabService.patchTabMetadata(tabId, { context: 'reward' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<a
|
||||
<button
|
||||
class="reward-start-card__select-cta"
|
||||
data-which="select-customer"
|
||||
data-what="select-customer"
|
||||
uiButton
|
||||
color="tertiary"
|
||||
size="large"
|
||||
[routerLink]="route().path"
|
||||
[queryParams]="route().queryParams"
|
||||
type="button"
|
||||
(click)="onSelectCustomer()"
|
||||
>
|
||||
Kund*in auswählen
|
||||
</a>
|
||||
</button>
|
||||
|
||||
@@ -1,16 +1,41 @@
|
||||
import { ChangeDetectionStrategy, Component, computed } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { ButtonComponent } from '@isa/ui/buttons';
|
||||
import { injectTabId } from '@isa/core/tabs';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
import { getRouteToCustomer } from '../../helpers';
|
||||
import { NavigationStateService } from '@isa/core/navigation';
|
||||
|
||||
@Component({
|
||||
selector: 'reward-start-card',
|
||||
templateUrl: './reward-start-card.component.html',
|
||||
styleUrl: './reward-start-card.component.css',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [ButtonComponent, RouterLink],
|
||||
imports: [ButtonComponent],
|
||||
})
|
||||
export class RewardStartCardComponent {
|
||||
readonly #navigationState = inject(NavigationStateService);
|
||||
readonly #router = inject(Router);
|
||||
|
||||
tabId = injectTabId();
|
||||
route = computed(() => getRouteToCustomer(this.tabId()));
|
||||
|
||||
/**
|
||||
* Called when "Kund*in auswählen" button is clicked.
|
||||
* Preserves the current URL as returnUrl before navigating to customer search.
|
||||
*/
|
||||
async onSelectCustomer() {
|
||||
const customerRoute = getRouteToCustomer(this.tabId());
|
||||
|
||||
// Preserve context: Store current reward page URL to return to after customer selection
|
||||
await this.#navigationState.preserveContext(
|
||||
{
|
||||
returnUrl: this.#router.url,
|
||||
},
|
||||
'select-customer',
|
||||
);
|
||||
|
||||
// Navigate to customer search
|
||||
await this.#router.navigate(customerRoute.path, {
|
||||
queryParams: customerRoute.queryParams,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
507
package-lock.json
generated
507
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user