diff --git a/apps/isa-app/src/page/customer/customer-search/details-main-view/details-main-view.component.ts b/apps/isa-app/src/page/customer/customer-search/details-main-view/details-main-view.component.ts index 3b0a30103..26c462147 100644 --- a/apps/isa-app/src/page/customer/customer-search/details-main-view/details-main-view.component.ts +++ b/apps/isa-app/src/page/customer/customer-search/details-main-view/details-main-view.component.ts @@ -329,6 +329,12 @@ export class CustomerDetailsViewMainComponent }>('select-customer'); if (context?.autoTriggerContinueFn) { + // Clear the autoTriggerContinueFn flag immediately (preserves returnUrl automatically) + await this._navigationState.patchContext( + { autoTriggerContinueFn: undefined }, + 'select-customer', + ); + // Auto-trigger continue() ONLY when coming from Kundenkarte this.continue(); } diff --git a/libs/core/navigation/README.md b/libs/core/navigation/README.md index 2ac555732..c85cbedac 100644 --- a/libs/core/navigation/README.md +++ b/libs/core/navigation/README.md @@ -146,6 +146,68 @@ navState.preserveContext( --- +#### `patchContext(partialState, customScope?)` + +Partially update preserved context without replacing the entire context. + +This method merges partial state with the existing context, preserving properties you don't specify. Properties explicitly set to `undefined` will be removed from the context. + +```typescript +// Existing context: { returnUrl: '/cart', autoTriggerContinueFn: true, customerId: 123 } + +// Clear one property while preserving others +await navState.patchContext( + { autoTriggerContinueFn: undefined }, + 'select-customer' +); +// Result: { returnUrl: '/cart', customerId: 123 } + +// Update one property while preserving others +await navState.patchContext( + { customerId: 456 }, + 'select-customer' +); +// Result: { returnUrl: '/cart', customerId: 456 } + +// Add new property to existing context +await navState.patchContext( + { selectedTab: 'details' }, + 'select-customer' +); +// Result: { returnUrl: '/cart', customerId: 456, selectedTab: 'details' } +``` + +**Parameters:** +- `partialState`: Partial state object to merge (set properties to `undefined` to remove them) +- `customScope` (optional): Custom scope within the tab + +**Use Cases:** +- Clear trigger flags while preserving flow data +- Update specific properties without affecting others +- Remove properties from context +- Add properties to existing context + +**Comparison with `preserveContext`:** +- `preserveContext`: Replaces entire context (overwrites all properties) +- `patchContext`: Merges with existing context (updates only specified properties) + +```typescript +// ❌ preserveContext - must manually preserve existing properties +const context = await navState.restoreContext(); +await navState.preserveContext({ + returnUrl: context?.returnUrl, // Must specify + customerId: context?.customerId, // Must specify + autoTriggerContinueFn: undefined, // Clear this +}); + +// ✅ patchContext - automatically preserves unspecified properties +await navState.patchContext({ + autoTriggerContinueFn: undefined, // Only specify what changes +}); +``` + +--- + #### `restoreContext(customScope?)` Retrieve preserved context **without** removing it. @@ -710,6 +772,7 @@ export const NAVIGATION_CONTEXT_METADATA_KEY = 'navigation-contexts'; | Method | Parameters | Returns | Purpose | |--------|-----------|---------|---------| | `preserveContext(state, customScope?)` | state: T, customScope?: string | void | Save context | +| `patchContext(partialState, customScope?)` | partialState: Partial, customScope?: string | void | Merge partial updates | | `restoreContext(customScope?)` | customScope?: string | T \| null | Get context (keep) | | `restoreAndClearContext(customScope?)` | customScope?: string | T \| null | Get + remove | | `clearPreservedContext(customScope?)` | customScope?: string | boolean | Remove context | diff --git a/libs/core/navigation/src/lib/navigation-context.service.ts b/libs/core/navigation/src/lib/navigation-context.service.ts index 4ee947cf8..170b58bf0 100644 --- a/libs/core/navigation/src/lib/navigation-context.service.ts +++ b/libs/core/navigation/src/lib/navigation-context.service.ts @@ -143,6 +143,75 @@ export class NavigationContextService { })); } + /** + * Patch a context in the active tab's metadata. + * + * Merges partial data with the existing context, preserving unspecified properties. + * Properties explicitly set to `undefined` will be removed from the context. + * If the context doesn't exist, creates a new one (behaves like setContext). + * + * @template T The type of data being patched + * @param partialData The partial navigation data to merge + * @param customScope Optional custom scope (defaults to 'default') + * + * @example + * ```typescript + * // Clear one property while preserving others + * contextService.patchContext({ autoTriggerContinueFn: undefined }, 'select-customer'); + * + * // Update one property while preserving others + * contextService.patchContext({ selectedTab: 'details' }, 'customer-flow'); + * ``` + */ + async patchContext( + partialData: Partial, + customScope?: string, + ): Promise { + const tabId = this.#tabService.activatedTabId(); + if (tabId === null) { + throw new Error('No active tab - cannot patch navigation context'); + } + + const scopeKey = customScope || 'default'; + const existingContext = await this.getContext(customScope); + + const mergedData = { + ...(existingContext ?? {}), + ...partialData, + }; + + // Remove properties explicitly set to undefined + const removedKeys: string[] = []; + Object.keys(mergedData).forEach((key) => { + if (mergedData[key] === undefined) { + removedKeys.push(key); + delete mergedData[key]; + } + }); + + const contextsMap = this.#getContextsMap(tabId); + const context: NavigationContext = { + data: mergedData, + createdAt: + existingContext && contextsMap[scopeKey] + ? contextsMap[scopeKey].createdAt + : Date.now(), + }; + + contextsMap[scopeKey] = context; + this.#saveContextsMap(tabId, contextsMap); + + this.#log.debug('Context patched in tab metadata', () => ({ + tabId, + scopeKey, + patchedKeys: Object.keys(partialData), + removedKeys, + totalDataKeys: Object.keys(mergedData), + wasUpdate: existingContext !== null, + totalContexts: Object.keys(contextsMap).length, + })); + } + /** * Get a context from the active tab's metadata without removing it. * diff --git a/libs/core/navigation/src/lib/navigation-state.service.ts b/libs/core/navigation/src/lib/navigation-state.service.ts index e25bc34d0..4983e0127 100644 --- a/libs/core/navigation/src/lib/navigation-state.service.ts +++ b/libs/core/navigation/src/lib/navigation-state.service.ts @@ -112,6 +112,50 @@ export class NavigationStateService { await this.#contextService.setContext(state, customScope); } + /** + * Patch preserved navigation state. + * + * Merges partial state with existing preserved context, keeping unspecified properties intact. + * This is useful when you need to update or clear specific properties without replacing + * the entire context. Properties set to `undefined` will be removed. + * + * Use cases: + * - Clear a trigger flag while preserving return URL + * - Update one property in a multi-property context + * - Remove specific properties from context + * + * @template T The type of state data being patched + * @param partialState The partial state to merge (properties set to undefined will be removed) + * @param customScope Optional custom scope within the tab + * + * @example + * ```typescript + * // Clear the autoTriggerContinueFn flag while preserving returnUrl + * await navigationStateService.patchContext( + * { autoTriggerContinueFn: undefined }, + * 'select-customer' + * ); + * + * // Update selectedTab while keeping other properties + * await navigationStateService.patchContext( + * { selectedTab: 'rewards' }, + * 'customer-flow' + * ); + * + * // Add a new property to existing context + * await navigationStateService.patchContext( + * { shippingAddressId: 123 }, + * 'checkout-flow' + * ); + * ``` + */ + async patchContext( + partialState: Partial, + customScope?: string, + ): Promise { + await this.#contextService.patchContext(partialState, customScope); + } + /** * Restore preserved navigation state. *