# Navigation

### <mark style="color:red;">Overview</mark>

This enables clients to redirect users to different pages within the shell application without direct access to the shell's router.

{% hint style="info" %}
Navigation helpers are router-agnostic. You implement them using your preferred routing library (React Router, Next.js Router, etc.).
{% endhint %}

### <mark style="color:red;">How It Works</mark>

1. Shell defines a `navigate` function and passes it to `AppShellProvider`
2. Client calls `navigation.navigate({ path: '/some-path' })`
3. Shell receives the navigation request via framebus
4. Shell executes the navigation using its router

### <mark style="color:red;">Usage</mark>

Pass the `navigation` prop to `AppShellProvider`:

```tsx
import { AppShellProvider, type ShellNavigation } from '@akinon/app-shell';
import { useNavigate } from 'react-router';

const App = () => {
  const routerNavigate = useNavigate();

  const navigation: ShellNavigation = {
    navigate: (payload) => {
      routerNavigate(payload.path);
    }
  };

  return (
    <AppShellProvider
      apps={registeredApps}
      data={sharedData}
      navigation={navigation}
      actions={shellActions}
    >
      {/* Your shell application */}
    </AppShellProvider>
  );
};
```

### <mark style="color:red;">ShellNavigation Type</mark>

```typescript
interface ShellNavigation {
  navigate: (payload: NavigationPayload) => void;
}

interface NavigationPayload {
  path: string;
  id?: number;
}
```

| Property | Type     | Description                          |
| -------- | -------- | ------------------------------------ |
| `path`   | `string` | The target path to navigate to       |
| `id`     | `number` | Optional. Application ID for context |

### <mark style="color:red;">Implementation Examples</mark>

#### React Router

```tsx
import { useNavigate } from 'react-router';
import { AppShellProvider, type ShellNavigation } from '@akinon/app-shell';

const App = () => {
  const navigate = useNavigate();

  const navigation: ShellNavigation = {
    navigate: ({ path }) => {
      navigate(path);
    }
  };

  return (
    <AppShellProvider navigation={navigation} {...otherProps}>
      {children}
    </AppShellProvider>
  );
};
```

#### TanStack Router

```tsx
import { useNavigate } from '@tanstack/react-router';
import { AppShellProvider, type ShellNavigation } from '@akinon/app-shell';

const App = () => {
  const navigate = useNavigate();

  const navigation: ShellNavigation = {
    navigate: ({ path }) => {
      navigate({ to: path });
    }
  };

  return (
    <AppShellProvider navigation={navigation} {...otherProps}>
      {children}
    </AppShellProvider>
  );
};
```

#### With Application ID

You can use the optional `id` parameter to handle navigation with application context:

```tsx
const navigation: ShellNavigation = {
  navigate: ({ path, id }) => {
    if (id) {
      // Navigate to app-specific route
      navigate(`/apps/${id}${path}`);
    } else {
      navigate(path);
    }
  }
};
```

### <mark style="color:red;">Using Navigation (Client Side)</mark>

Clients trigger navigation via the `useAppClient` hook:

```tsx
// In the client application
import { useAppClient } from '@akinon/app-client';

const ClientComponent = () => {
  const { navigation } = useAppClient();

  const handleViewOrder = (orderId: string) => {
    navigation.navigate({ path: `/orders/${orderId}` });
  };

  const handleGoBack = () => {
    navigation.navigate({ path: '/dashboard' });
  };

  return (
    <div>
      <button onClick={() => handleViewOrder('123')}>
        View Order
      </button>
      <button onClick={handleGoBack}>
        Back to Dashboard
      </button>
    </div>
  );
};
```

{% hint style="info" %}
For detailed information about using navigation on the client side, see the Client Application documentation.
{% endhint %}

### <mark style="color:red;">Advanced Usage</mark>

#### Handling External Navigation

You may want to handle external URLs differently:

```tsx
const navigation: ShellNavigation = {
  navigate: ({ path }) => {
    if (path.startsWith('http://') || path.startsWith('https://')) {
      // External URL - open in new tab
      window.open(path, '_blank');
    } else {
      // Internal path - use router
      routerNavigate(path);
    }
  }
};
```

#### Navigation with Query Parameters

Query parameters can be included in the path:

```tsx
// Client
navigation.navigate({ path: '/products?category=electronics&page=2' });

// Shell handles it naturally
const navigation: ShellNavigation = {
  navigate: ({ path }) => {
    routerNavigate(path); // Includes query params
  }
};
```

#### Navigation with State

If you need to pass state data during navigation, use a combination of navigation and actions:

```tsx
// Shell
const actions = {
  navigateWithState: (path: string, state: any) => {
    routerNavigate(path, { state });
  }
};

// Client
actions.actions.navigateWithState('/details', { fromPage: 'list' });
```

### <mark style="color:red;">Best Practices</mark>

#### 1. Keep Navigation Logic Simple

The navigation handler should focus on routing. Complex logic should be in actions.

```typescript
// ❌ Bad - Too much logic in navigation
navigate: ({ path }) => {
  logAnalytics(path);
  saveToHistory(path);
  checkPermissions(path);
  routerNavigate(path);
}

// ✅ Good - Simple navigation, side effects in actions
navigate: ({ path }) => {
  routerNavigate(path);
}
```

#### 2. Handle Unknown Paths Gracefully

Consider what happens when a client requests an invalid path:

```typescript
navigate: ({ path }) => {
  const validRoutes = ['/dashboard', '/orders', '/products'];
  const isValidPrefix = validRoutes.some(route => path.startsWith(route));
  
  if (isValidPrefix) {
    routerNavigate(path);
  } else {
    routerNavigate('/404');
  }
}
```

#### 3. Consider Navigation Timing

If clients navigate immediately on mount, ensure the shell is ready:

```tsx
// Shell - wrap navigation in a safe check
navigate: ({ path }) => {
  if (isAppReady) {
    routerNavigate(path);
  } else {
    pendingNavigation.current = path;
  }
}
```

### <mark style="color:red;">Next Steps</mark>

* [Data Sharing](/akinon-ui/ui-protocol/shell-application/configuration/data-sharing.md) - Share data with clients
* [Actions](/akinon-ui/ui-protocol/shell-application/configuration/actions.md) - Define custom actions


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akinon.com/akinon-ui/ui-protocol/shell-application/configuration/navigation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
