# State Management

## Local State

- Use Signals for component-level state
- Keep state close to where it's used
- Document state management decisions

## Global State (NgRx)

- Use for complex application state
- Follow feature-based store organization
- Implement proper error handling

## Navigation State

Navigation state refers to temporary data preserved between routes during navigation flows. Unlike global state or local component state, navigation state is transient and tied to a specific navigation flow within a tab.

### Storage Architecture

Navigation contexts are stored in **tab metadata** using `@isa/core/navigation`:

```typescript
// Context stored in tab metadata:
tab.metadata['navigation-contexts'] = {
  'default': {
    data: { returnUrl: '/cart', customerId: 123 },
    createdAt: 1234567890
  },
  'customer-flow': {
    data: { step: 2, selectedOptions: ['A', 'B'] },
    createdAt: 1234567895
  }
}
```

**Benefits:**
- ✅ **Automatic cleanup** when tabs close (no manual cleanup needed)
- ✅ **Tab isolation** (contexts don't leak between tabs)
- ✅ **Persistence** across page refresh (via TabService UserStorage)
- ✅ **Integration** with tab lifecycle management

### When to Use Navigation State

Use `@isa/core/navigation` for:

- **Return URLs**: Storing the previous route to navigate back to
- **Wizard/Multi-step Forms**: Passing context between wizard steps
- **Context Preservation**: Maintaining search queries, filters, or selections when drilling into details
- **Temporary Data**: Any data needed only for the current navigation flow within a tab

### When NOT to Use Navigation State

Avoid using navigation state for:

- **Persistent Data**: Use NgRx stores or services instead
- **Shareable URLs**: Use route parameters or query parameters if the URL should be bookmarkable
- **Long-lived State**: Use session storage or NgRx with persistence
- **Cross-tab Communication**: Use services with proper state management

### Best Practices

#### ✅ Do Use Navigation Context (Tab Metadata)

```typescript
// Good: Clean URLs, automatic cleanup, tab-scoped
navState.preserveContext({
  returnUrl: '/customer-list',
  searchQuery: 'John Doe',
  context: 'reward-selection'
});

await router.navigate(['/customer', customerId]);

// Later (after intermediate navigations):
const context = navState.restoreAndClearContext<{ returnUrl: string }>();
await router.navigateByUrl(context.returnUrl);
```

#### ❌ Don't Use Query Parameters for Temporary State

```typescript
// Bad: URL pollution, can be overwritten, visible in browser bar
await router.navigate(['/customer', customerId], {
  queryParams: {
    returnUrl: '/customer-list',
    searchQuery: 'John Doe'
  }
});
// URL becomes: /customer/123?returnUrl=%2Fcustomer-list&searchQuery=John%20Doe
```

#### ❌ Don't Use Router State for Multi-Step Flows

```typescript
// Bad: Lost after intermediate navigations
await router.navigate(['/customer/search'], {
  state: { returnUrl: '/reward/cart' }  // Lost after next navigation!
});
```

### Integration with TabService

Navigation context relies on `TabService` for automatic tab scoping:

```typescript
// Context automatically scoped to active tab
const tabId = tabService.activatedTabId();  // e.g., 123

// When you preserve context:
navState.preserveContext({ returnUrl: '/cart' });
// Stored in: tab[123].metadata['navigation-contexts']['default']

// When you preserve with custom scope:
navState.preserveContext({ step: 2 }, 'wizard-flow');
// Stored in: tab[123].metadata['navigation-contexts']['wizard-flow']
```

**Automatic Cleanup:**
When the tab closes, all contexts stored in that tab's metadata are automatically removed. No manual cleanup required!

### Usage Example: Multi-Step Flow

**Start of Flow (preserving context):**
```typescript
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { NavigationStateService } from '@isa/core/navigation';

export class CustomerListComponent {
  private router = inject(Router);
  private navState = inject(NavigationStateService);

  async viewCustomerDetails(customerId: number) {
    // Preserve context before navigating
    this.navState.preserveContext({
      returnUrl: this.router.url,
      searchQuery: this.searchForm.value.query
    });

    await this.router.navigate(['/customer', customerId]);
  }
}
```

**Intermediate Navigation (context persists):**
```typescript
export class CustomerDetailsComponent {
  private router = inject(Router);

  async editAddress(addressId: number) {
    // Context still preserved through intermediate navigations
    await this.router.navigate(['/address/edit', addressId]);
  }
}
```

**End of Flow (restoring context):**
```typescript
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { NavigationStateService } from '@isa/core/navigation';

interface CustomerNavigationContext {
  returnUrl: string;
  searchQuery?: string;
}

export class AddressEditComponent {
  private router = inject(Router);
  private navState = inject(NavigationStateService);

  async complete() {
    // Restore and clear context
    const context = this.navState.restoreAndClearContext<CustomerNavigationContext>();

    if (context?.returnUrl) {
      await this.router.navigateByUrl(context.returnUrl);
    } else {
      // Fallback navigation
      await this.router.navigate(['/customers']);
    }
  }

  // For template usage
  hasReturnUrl(): boolean {
    return this.navState.hasPreservedContext();
  }
}
```

**Template:**
```html
@if (hasReturnUrl()) {
  <button (click)="complete()">Zurück</button>
}
```

### Advanced: Multiple Concurrent Flows

Use custom scopes to manage multiple flows in the same tab:

```typescript
export class DashboardComponent {
  private navState = inject(NavigationStateService);
  private router = inject(Router);

  async startCustomerFlow() {
    // Save context for customer flow
    this.navState.preserveContext(
      { returnUrl: '/dashboard', flowType: 'customer' },
      'customer-flow'
    );

    await this.router.navigate(['/customer/search']);
  }

  async startProductFlow() {
    // Save context for product flow (different scope)
    this.navState.preserveContext(
      { returnUrl: '/dashboard', flowType: 'product' },
      'product-flow'
    );

    await this.router.navigate(['/product/search']);
  }

  async completeCustomerFlow() {
    // Restore customer flow context
    const context = this.navState.restoreAndClearContext('customer-flow');
    if (context?.returnUrl) {
      await this.router.navigateByUrl(context.returnUrl);
    }
  }

  async completeProductFlow() {
    // Restore product flow context
    const context = this.navState.restoreAndClearContext('product-flow');
    if (context?.returnUrl) {
      await this.router.navigateByUrl(context.returnUrl);
    }
  }
}
```

### Architecture Decision

**Why Tab Metadata instead of SessionStorage?**

Tab metadata provides several advantages over SessionStorage:

- **Automatic Cleanup**: Contexts are automatically removed when tabs close (no manual cleanup or TTL management needed)
- **Better Integration**: Seamlessly integrated with tab lifecycle and TabService
- **Tab Isolation**: Impossible to leak contexts between tabs (scoped by tab ID)
- **Simpler Mental Model**: Contexts are "owned" by tabs, not stored globally
- **Persistence**: Tab metadata persists across page refresh via UserStorage

**Why not Query Parameters?**

Query parameters were traditionally used for passing state, but they have significant drawbacks:

- **URL Pollution**: Makes URLs long, ugly, and non-bookmarkable
- **Overwritable**: Intermediate navigations can overwrite query parameters
- **Security**: Sensitive data visible in browser URL bar
- **User Experience**: Affects URL sharing and bookmarking

**Why not Router State?**

Angular's Router state mechanism has limitations:

- **Lost After Navigation**: State is lost after the immediate navigation (doesn't survive intermediate navigations)
- **Not Persistent**: Doesn't survive page refresh
- **No Tab Scoping**: Can't isolate state by tab

**Why Tab Metadata is Better:**

Navigation context using tab metadata provides:

- **Survives Intermediate Navigations**: State persists across multiple navigation steps
- **Clean URLs**: No visible state in the URL bar
- **Reliable**: State survives page refresh (via TabService UserStorage)
- **Type-safe**: Full TypeScript support with generics
- **Platform-agnostic**: Works with SSR/Angular Universal
- **Automatic Cleanup**: No manual cleanup needed when tabs close
- **Tab Isolation**: Contexts automatically scoped to tabs

### Comparison with Other State Solutions

| Feature | Navigation Context | NgRx Store | Service State | Query Params | Router State |
|---------|-------------------|------------|---------------|--------------|--------------|
| **Scope** | Tab-scoped flow | Application-wide | Feature-specific | URL-based | Single navigation |
| **Persistence** | Until tab closes | Configurable | Component lifetime | URL lifetime | Lost after nav |
| **Survives Refresh** | ✅ Yes | ⚠️ Optional | ❌ No | ✅ Yes | ❌ No |
| **Survives Intermediate Navs** | ✅ Yes | ✅ Yes | ✅ Yes | ⚠️ Sometimes | ❌ No |
| **Automatic Cleanup** | ✅ Yes (tab close) | ❌ Manual | ❌ Manual | N/A | ✅ Yes |
| **Tab Isolation** | ✅ Yes | ❌ No | ❌ No | ❌ No | ❌ No |
| **Clean URLs** | ✅ Yes | N/A | N/A | ❌ No | ✅ Yes |
| **Shareability** | ❌ No | ❌ No | ❌ No | ✅ Yes | ❌ No |
| **Type Safety** | ✅ Yes | ✅ Yes | ✅ Yes | ⚠️ Limited | ✅ Yes |
| **Use Case** | Multi-step flow | Global state | Feature state | Bookmarkable state | Simple navigation |

### Best Practices for Navigation Context

#### ✅ Do

- **Use for temporary flow context** (return URLs, wizard state, search filters)
- **Use custom scopes** for multiple concurrent flows in the same tab
- **Always use type safety** with TypeScript generics
- **Trust automatic cleanup** - no need to manually clear contexts in `ngOnDestroy`
- **Check for null** when restoring contexts (they may not exist)

#### ❌ Don't

- **Don't store large objects** - keep contexts lean (URLs, IDs, simple flags)
- **Don't use for persistent data** - use NgRx or services for long-lived state
- **Don't store sensitive data** - contexts may be visible in browser dev tools
- **Don't manually clear in ngOnDestroy** - tab lifecycle handles cleanup automatically
- **Don't use for cross-tab communication** - use services or BroadcastChannel

### Cleanup Behavior

**Automatic Cleanup (Recommended):**
```typescript
// ✅ No manual cleanup needed - tab lifecycle handles it!
export class CustomerFlowComponent {
  navState = inject(NavigationStateService);

  async startFlow() {
    this.navState.preserveContext({ returnUrl: '/home' });
    // Context automatically cleaned up when tab closes
  }

  // No ngOnDestroy needed!
}
```

**Manual Cleanup (Rarely Needed):**
```typescript
// Use only if you need to explicitly clear contexts during tab lifecycle
export class ComplexFlowComponent {
  navState = inject(NavigationStateService);

  async cancelFlow() {
    // Explicitly clear all contexts for this tab
    const cleared = this.navState.clearScopeContexts();
    console.log(`Cleared ${cleared} contexts`);
  }
}
```

### Related Documentation

- **Full API Reference**: See [libs/core/navigation/README.md](../../libs/core/navigation/README.md) for complete documentation
- **Usage Patterns**: Detailed examples and patterns in the library README
- **Testing Guide**: Full testing guide included in the library documentation
- **Migration Guide**: Instructions for migrating from SessionStorage approach in the library README
